]>
Commit | Line | Data |
---|---|---|
ba9703b0 | 1 | //! Related to out filenames of compilation (e.g. save analysis, binaries). |
f9f354fc | 2 | use crate::config::{CrateType, Input, OutputFilenames, OutputType}; |
ba9703b0 | 3 | use crate::Session; |
3dfed10e | 4 | use rustc_ast as ast; |
dfeec247 XL |
5 | use rustc_span::symbol::sym; |
6 | use rustc_span::Span; | |
ea8adc8c | 7 | use std::path::{Path, PathBuf}; |
dfeec247 XL |
8 | |
9 | pub fn out_filename( | |
10 | sess: &Session, | |
f9f354fc | 11 | crate_type: CrateType, |
dfeec247 XL |
12 | outputs: &OutputFilenames, |
13 | crate_name: &str, | |
14 | ) -> PathBuf { | |
ea8adc8c | 15 | let default_filename = filename_for_input(sess, crate_type, crate_name, outputs); |
dfeec247 XL |
16 | let out_filename = outputs |
17 | .outputs | |
18 | .get(&OutputType::Exe) | |
19 | .and_then(|s| s.to_owned()) | |
20 | .or_else(|| outputs.single_output_file.clone()) | |
21 | .unwrap_or(default_filename); | |
ea8adc8c XL |
22 | |
23 | check_file_is_writeable(&out_filename, sess); | |
24 | ||
25 | out_filename | |
26 | } | |
27 | ||
ba9703b0 XL |
28 | /// Make sure files are writeable. Mac, FreeBSD, and Windows system linkers |
29 | /// check this already -- however, the Linux linker will happily overwrite a | |
30 | /// read-only file. We should be consistent. | |
ea8adc8c XL |
31 | pub fn check_file_is_writeable(file: &Path, sess: &Session) { |
32 | if !is_writeable(file) { | |
dfeec247 XL |
33 | sess.fatal(&format!( |
34 | "output file {} is not writeable -- check its \ | |
35 | permissions", | |
36 | file.display() | |
37 | )); | |
ea8adc8c XL |
38 | } |
39 | } | |
40 | ||
41 | fn is_writeable(p: &Path) -> bool { | |
42 | match p.metadata() { | |
43 | Err(..) => true, | |
dfeec247 | 44 | Ok(m) => !m.permissions().readonly(), |
ea8adc8c XL |
45 | } |
46 | } | |
47 | ||
3dfed10e | 48 | pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) -> String { |
3b2f2976 | 49 | let validate = |s: String, span: Option<Span>| { |
ba9703b0 | 50 | validate_crate_name(sess, &s, span); |
3b2f2976 XL |
51 | s |
52 | }; | |
53 | ||
54 | // Look in attributes 100% of the time to make sure the attribute is marked | |
55 | // as used. After doing this, however, we still prioritize a crate name from | |
56 | // the command line over one found in the #[crate_name] attribute. If we | |
57 | // find both we ensure that they're the same later on as well. | |
dfeec247 | 58 | let attr_crate_name = |
3dfed10e | 59 | sess.find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s))); |
3b2f2976 | 60 | |
3dfed10e XL |
61 | if let Some(ref s) = sess.opts.crate_name { |
62 | if let Some((attr, name)) = attr_crate_name { | |
a2a8927a | 63 | if name.as_str() != s { |
3dfed10e XL |
64 | let msg = format!( |
65 | "`--crate-name` and `#[crate_name]` are \ | |
ee023bcb | 66 | required to match, but `{s}` != `{name}`" |
3dfed10e XL |
67 | ); |
68 | sess.span_err(attr.span, &msg); | |
3b2f2976 | 69 | } |
3b2f2976 | 70 | } |
3dfed10e | 71 | return validate(s.clone(), None); |
3b2f2976 XL |
72 | } |
73 | ||
74 | if let Some((attr, s)) = attr_crate_name { | |
75 | return validate(s.to_string(), Some(attr.span)); | |
76 | } | |
77 | if let Input::File(ref path) = *input { | |
78 | if let Some(s) = path.file_stem().and_then(|s| s.to_str()) { | |
74b04a01 | 79 | if s.starts_with('-') { |
dfeec247 XL |
80 | let msg = format!( |
81 | "crate names cannot start with a `-`, but \ | |
ee023bcb | 82 | `{s}` has a leading hyphen" |
dfeec247 | 83 | ); |
3dfed10e | 84 | sess.err(&msg); |
3b2f2976 | 85 | } else { |
a2a8927a | 86 | return validate(s.replace('-', "_"), None); |
3b2f2976 XL |
87 | } |
88 | } | |
89 | } | |
90 | ||
91 | "rust_out".to_string() | |
92 | } | |
93 | ||
3dfed10e | 94 | pub fn validate_crate_name(sess: &Session, s: &str, sp: Option<Span>) { |
ba9703b0 XL |
95 | let mut err_count = 0; |
96 | { | |
97 | let mut say = |s: &str| { | |
3dfed10e XL |
98 | match sp { |
99 | Some(sp) => sess.span_err(sp, s), | |
100 | None => sess.err(s), | |
ee023bcb | 101 | }; |
ba9703b0 XL |
102 | err_count += 1; |
103 | }; | |
104 | if s.is_empty() { | |
105 | say("crate name must not be empty"); | |
106 | } | |
107 | for c in s.chars() { | |
108 | if c.is_alphanumeric() { | |
109 | continue; | |
110 | } | |
111 | if c == '_' { | |
112 | continue; | |
113 | } | |
ee023bcb | 114 | say(&format!("invalid character `{c}` in crate name: `{s}`")); |
ba9703b0 XL |
115 | } |
116 | } | |
117 | ||
118 | if err_count > 0 { | |
3dfed10e | 119 | sess.abort_if_errors(); |
ba9703b0 XL |
120 | } |
121 | } | |
122 | ||
dfeec247 XL |
123 | pub fn filename_for_metadata( |
124 | sess: &Session, | |
125 | crate_name: &str, | |
126 | outputs: &OutputFilenames, | |
127 | ) -> PathBuf { | |
17df50a5 XL |
128 | // If the command-line specified the path, use that directly. |
129 | if let Some(Some(out_filename)) = sess.opts.output_types.get(&OutputType::Metadata) { | |
130 | return out_filename.clone(); | |
131 | } | |
132 | ||
0bf4aa26 XL |
133 | let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename); |
134 | ||
dfeec247 XL |
135 | let out_filename = outputs |
136 | .single_output_file | |
137 | .clone() | |
ee023bcb | 138 | .unwrap_or_else(|| outputs.out_directory.join(&format!("lib{libname}.rmeta"))); |
0bf4aa26 XL |
139 | |
140 | check_file_is_writeable(&out_filename, sess); | |
141 | ||
142 | out_filename | |
143 | } | |
144 | ||
dfeec247 XL |
145 | pub fn filename_for_input( |
146 | sess: &Session, | |
f9f354fc | 147 | crate_type: CrateType, |
dfeec247 XL |
148 | crate_name: &str, |
149 | outputs: &OutputFilenames, | |
150 | ) -> PathBuf { | |
3b2f2976 XL |
151 | let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename); |
152 | ||
153 | match crate_type { | |
ee023bcb | 154 | CrateType::Rlib => outputs.out_directory.join(&format!("lib{libname}.rlib")), |
f9f354fc | 155 | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib => { |
29967ef6 | 156 | let (prefix, suffix) = (&sess.target.dll_prefix, &sess.target.dll_suffix); |
ee023bcb | 157 | outputs.out_directory.join(&format!("{prefix}{libname}{suffix}")) |
3b2f2976 | 158 | } |
f9f354fc | 159 | CrateType::Staticlib => { |
29967ef6 | 160 | let (prefix, suffix) = (&sess.target.staticlib_prefix, &sess.target.staticlib_suffix); |
ee023bcb | 161 | outputs.out_directory.join(&format!("{prefix}{libname}{suffix}")) |
3b2f2976 | 162 | } |
f9f354fc | 163 | CrateType::Executable => { |
29967ef6 | 164 | let suffix = &sess.target.exe_suffix; |
3b2f2976 | 165 | let out_filename = outputs.path(OutputType::Exe); |
dfeec247 | 166 | if suffix.is_empty() { out_filename } else { out_filename.with_extension(&suffix[1..]) } |
3b2f2976 XL |
167 | } |
168 | } | |
169 | } | |
170 | ||
171 | /// Returns default crate type for target | |
172 | /// | |
173 | /// Default crate type is used when crate type isn't provided neither | |
174 | /// through cmd line arguments nor through crate attributes | |
175 | /// | |
b7449926 | 176 | /// It is CrateType::Executable for all platforms but iOS as there is no |
3b2f2976 XL |
177 | /// way to run iOS binaries anyway without jailbreaking and |
178 | /// interaction with Rust code through static library is the only | |
179 | /// option for now | |
f9f354fc | 180 | pub fn default_output_for_target(sess: &Session) -> CrateType { |
29967ef6 | 181 | if !sess.target.executables { CrateType::Staticlib } else { CrateType::Executable } |
3b2f2976 XL |
182 | } |
183 | ||
184 | /// Checks if target supports crate_type as output | |
f9f354fc | 185 | pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool { |
ee023bcb FG |
186 | if let CrateType::Cdylib | CrateType::Dylib | CrateType::ProcMacro = crate_type { |
187 | if !sess.target.dynamic_linking { | |
188 | return true; | |
abe05a73 | 189 | } |
ee023bcb FG |
190 | if sess.crt_static(Some(crate_type)) && !sess.target.crt_static_allows_dylibs { |
191 | return true; | |
abe05a73 XL |
192 | } |
193 | } | |
ee023bcb FG |
194 | if let CrateType::ProcMacro | CrateType::Dylib = crate_type && sess.target.only_cdylib { |
195 | return true; | |
196 | } | |
197 | if let CrateType::Executable = crate_type && !sess.target.executables { | |
29967ef6 | 198 | return true; |
abe05a73 XL |
199 | } |
200 | ||
201 | false | |
3b2f2976 | 202 | } |