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 }));
73 }
74
75 if let Some(guar) = guar {
76 guar.raise_fatal();
77 }
78}
79
80pub fn filename_for_metadata(sess: &Session, outputs: &OutputFilenames) -> OutFileName {
81 let out_filename = outputs.path(OutputType::Metadata);
82 if let OutFileName::Real(ref path) = out_filename {
83 check_file_is_writeable(path, sess);
84 }
85 out_filename
86}
87
88pub fn filename_for_input(
89 sess: &Session,
90 crate_type: CrateType,
91 crate_name: Symbol,
92 outputs: &OutputFilenames,
93) -> OutFileName {
94 let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
95
96 match crate_type {
97 CrateType::Rlib => {
98 OutFileName::Real(outputs.out_directory.join(&format!("lib{libname}.rlib")))
99 }
100 CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib | CrateType::Sdylib => {
101 let (prefix, suffix) = (&sess.target.dll_prefix, &sess.target.dll_suffix);
102 OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}")))
103 }
104 CrateType::Staticlib => {
105 let (prefix, suffix) = sess.staticlib_components(false);
106 OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}")))
107 }
108 CrateType::Executable => {
109 let suffix = &sess.target.exe_suffix;
110 let out_filename = outputs.path(OutputType::Exe);
111 if let OutFileName::Real(ref path) = out_filename {
112 if suffix.is_empty() {
113 out_filename
114 } else {
115 OutFileName::Real(path.with_extension(&suffix[1..]))
116 }
117 } else {
118 out_filename
119 }
120 }
121 }
122}
123
124pub fn default_output_for_target(sess: &Session) -> CrateType {
134 if !sess.target.executables { CrateType::Staticlib } else { CrateType::Executable }
135}
136
137pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool {
139 if let CrateType::Cdylib | CrateType::Dylib | CrateType::ProcMacro = crate_type {
140 if !sess.target.dynamic_linking {
141 return true;
142 }
143 if sess.crt_static(Some(crate_type)) && !sess.target.crt_static_allows_dylibs {
144 return true;
145 }
146 }
147 if let CrateType::ProcMacro | CrateType::Dylib = crate_type
148 && sess.target.only_cdylib
149 {
150 return true;
151 }
152 if let CrateType::Executable = crate_type
153 && !sess.target.executables
154 {
155 return true;
156 }
157
158 false
159}
160
161pub const CRATE_TYPES: &[(Symbol, CrateType)] = &[
162 (sym::rlib, CrateType::Rlib),
163 (sym::dylib, CrateType::Dylib),
164 (sym::cdylib, CrateType::Cdylib),
165 (sym::lib, config::default_lib_output()),
166 (sym::staticlib, CrateType::Staticlib),
167 (sym::proc_dash_macro, CrateType::ProcMacro),
168 (sym::bin, CrateType::Executable),
169 (sym::sdylib, CrateType::Sdylib),
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(
177 session: &Session,
178 backend_crate_types: &[CrateType],
179 codegen_backend_name: &'static str,
180 attrs: &[ast::Attribute],
181) -> Vec<CrateType> {
182 if session.opts.test {
185 if !session.target.executables {
186 session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget {
187 crate_type: CrateType::Executable,
188 target_triple: &session.opts.target_triple,
189 });
190 return Vec::new();
191 }
192 return vec![CrateType::Executable];
193 }
194
195 if session.opts.unstable_opts.build_sdylib_interface {
197 return vec![CrateType::Rlib];
198 }
199
200 #[allow(rustc::bad_opt_access)]
205 let mut base = session.opts.crate_types.clone();
206 if base.is_empty() {
207 let attr_types = attrs.iter().filter_map(|a| {
208 if a.has_name(sym::crate_type)
209 && let Some(s) = a.value_str()
210 {
211 categorize_crate_type(s)
212 } else {
213 None
214 }
215 });
216 base.extend(attr_types);
217 if base.is_empty() {
218 base.push(default_output_for_target(session));
219 } else {
220 base.sort();
221 base.dedup();
222 }
223 }
224
225 base.retain(|crate_type| {
226 if invalid_output_for_target(session, *crate_type) {
227 session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget {
228 crate_type: *crate_type,
229 target_triple: &session.opts.target_triple,
230 });
231 false
232 } else if !backend_crate_types.contains(crate_type) {
233 session.dcx().emit_warn(errors::UnsupportedCrateTypeForCodegenBackend {
234 crate_type: *crate_type,
235 codegen_backend: codegen_backend_name,
236 });
237 false
238 } else {
239 true
240 }
241 });
242
243 base
244}