rustc_session/
output.rs
1use std::path::Path;
4
5use rustc_ast as ast;
6use rustc_span::{Span, Symbol, sym};
7
8use crate::Session;
9use crate::config::{self, CrateType, OutFileName, OutputFilenames, OutputType};
10use crate::errors::{self, CrateNameEmpty, FileIsNotWriteable, InvalidCharacterInCrateName};
11
12pub fn out_filename(
13 sess: &Session,
14 crate_type: CrateType,
15 outputs: &OutputFilenames,
16 crate_name: Symbol,
17) -> OutFileName {
18 let default_filename = filename_for_input(sess, crate_type, crate_name, outputs);
19 let out_filename = outputs
20 .outputs
21 .get(&OutputType::Exe)
22 .and_then(|s| s.to_owned())
23 .or_else(|| outputs.single_output_file.clone())
24 .unwrap_or(default_filename);
25
26 if let OutFileName::Real(ref path) = out_filename {
27 check_file_is_writeable(path, sess);
28 }
29
30 out_filename
31}
32
33pub fn check_file_is_writeable(file: &Path, sess: &Session) {
37 if !is_writeable(file) {
38 sess.dcx().emit_fatal(FileIsNotWriteable { file });
39 }
40}
41
42fn is_writeable(p: &Path) -> bool {
43 match p.metadata() {
44 Err(..) => true,
45 Ok(m) => !m.permissions().readonly(),
46 }
47}
48
49pub fn validate_crate_name(sess: &Session, crate_name: Symbol, span: Option<Span>) {
58 let mut guar = None;
59
60 if crate_name.is_empty() {
61 guar = Some(sess.dcx().emit_err(CrateNameEmpty { span }));
62 }
63
64 for c in crate_name.as_str().chars() {
65 if c.is_alphanumeric() || c == '_' {
66 continue;
67 }
68 guar = Some(sess.dcx().emit_err(InvalidCharacterInCrateName {
69 span,
70 character: c,
71 crate_name,
72 help: span.is_none().then_some(()),
73 }));
74 }
75
76 if let Some(guar) = guar {
77 guar.raise_fatal();
78 }
79}
80
81pub fn filename_for_metadata(sess: &Session, outputs: &OutputFilenames) -> OutFileName {
82 let out_filename = outputs.path(OutputType::Metadata);
83 if let OutFileName::Real(ref path) = out_filename {
84 check_file_is_writeable(path, sess);
85 }
86 out_filename
87}
88
89pub fn filename_for_input(
90 sess: &Session,
91 crate_type: CrateType,
92 crate_name: Symbol,
93 outputs: &OutputFilenames,
94) -> OutFileName {
95 let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
96
97 match crate_type {
98 CrateType::Rlib => {
99 OutFileName::Real(outputs.out_directory.join(&format!("lib{libname}.rlib")))
100 }
101 CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib => {
102 let (prefix, suffix) = (&sess.target.dll_prefix, &sess.target.dll_suffix);
103 OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}")))
104 }
105 CrateType::Staticlib => {
106 let (prefix, suffix) = sess.staticlib_components(false);
107 OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}")))
108 }
109 CrateType::Executable => {
110 let suffix = &sess.target.exe_suffix;
111 let out_filename = outputs.path(OutputType::Exe);
112 if let OutFileName::Real(ref path) = out_filename {
113 if suffix.is_empty() {
114 out_filename
115 } else {
116 OutFileName::Real(path.with_extension(&suffix[1..]))
117 }
118 } else {
119 out_filename
120 }
121 }
122 }
123}
124
125pub fn default_output_for_target(sess: &Session) -> CrateType {
135 if !sess.target.executables { CrateType::Staticlib } else { CrateType::Executable }
136}
137
138pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool {
140 if let CrateType::Cdylib | CrateType::Dylib | CrateType::ProcMacro = crate_type {
141 if !sess.target.dynamic_linking {
142 return true;
143 }
144 if sess.crt_static(Some(crate_type)) && !sess.target.crt_static_allows_dylibs {
145 return true;
146 }
147 }
148 if let CrateType::ProcMacro | CrateType::Dylib = crate_type
149 && sess.target.only_cdylib
150 {
151 return true;
152 }
153 if let CrateType::Executable = crate_type
154 && !sess.target.executables
155 {
156 return true;
157 }
158
159 false
160}
161
162pub const CRATE_TYPES: &[(Symbol, CrateType)] = &[
163 (sym::rlib, CrateType::Rlib),
164 (sym::dylib, CrateType::Dylib),
165 (sym::cdylib, CrateType::Cdylib),
166 (sym::lib, config::default_lib_output()),
167 (sym::staticlib, CrateType::Staticlib),
168 (sym::proc_dash_macro, CrateType::ProcMacro),
169 (sym::bin, CrateType::Executable),
170];
171
172pub fn categorize_crate_type(s: Symbol) -> Option<CrateType> {
173 Some(CRATE_TYPES.iter().find(|(key, _)| *key == s)?.1)
174}
175
176pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<CrateType> {
177 if session.opts.test {
180 return vec![CrateType::Executable];
181 }
182
183 #[allow(rustc::bad_opt_access)]
188 let mut base = session.opts.crate_types.clone();
189 if base.is_empty() {
190 let attr_types = attrs.iter().filter_map(|a| {
191 if a.has_name(sym::crate_type)
192 && let Some(s) = a.value_str()
193 {
194 categorize_crate_type(s)
195 } else {
196 None
197 }
198 });
199 base.extend(attr_types);
200 if base.is_empty() {
201 base.push(default_output_for_target(session));
202 } else {
203 base.sort();
204 base.dedup();
205 }
206 }
207
208 base.retain(|crate_type| {
209 if invalid_output_for_target(session, *crate_type) {
210 session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget {
211 crate_type: *crate_type,
212 target_triple: &session.opts.target_triple,
213 });
214 false
215 } else {
216 true
217 }
218 });
219
220 base
221}