]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_session/src/output.rs
New upstream version 1.67.1+dfsg1
[rustc.git] / compiler / rustc_session / src / output.rs
CommitLineData
ba9703b0 1//! Related to out filenames of compilation (e.g. save analysis, binaries).
f9f354fc 2use crate::config::{CrateType, Input, OutputFilenames, OutputType};
f2b60f7d
FG
3use crate::errors::{
4 CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable,
5 InvalidCharacterInCrateName,
6};
ba9703b0 7use crate::Session;
3dfed10e 8use rustc_ast as ast;
dfeec247 9use rustc_span::symbol::sym;
487cf647 10use rustc_span::{Span, Symbol};
ea8adc8c 11use std::path::{Path, PathBuf};
dfeec247
XL
12
13pub fn out_filename(
14 sess: &Session,
f9f354fc 15 crate_type: CrateType,
dfeec247 16 outputs: &OutputFilenames,
487cf647 17 crate_name: Symbol,
dfeec247 18) -> PathBuf {
ea8adc8c 19 let default_filename = filename_for_input(sess, crate_type, crate_name, outputs);
dfeec247
XL
20 let out_filename = outputs
21 .outputs
22 .get(&OutputType::Exe)
23 .and_then(|s| s.to_owned())
24 .or_else(|| outputs.single_output_file.clone())
25 .unwrap_or(default_filename);
ea8adc8c
XL
26
27 check_file_is_writeable(&out_filename, sess);
28
29 out_filename
30}
31
ba9703b0
XL
32/// Make sure files are writeable. Mac, FreeBSD, and Windows system linkers
33/// check this already -- however, the Linux linker will happily overwrite a
34/// read-only file. We should be consistent.
ea8adc8c
XL
35pub fn check_file_is_writeable(file: &Path, sess: &Session) {
36 if !is_writeable(file) {
f2b60f7d 37 sess.emit_fatal(FileIsNotWriteable { file });
ea8adc8c
XL
38 }
39}
40
41fn is_writeable(p: &Path) -> bool {
42 match p.metadata() {
43 Err(..) => true,
dfeec247 44 Ok(m) => !m.permissions().readonly(),
ea8adc8c
XL
45 }
46}
47
487cf647
FG
48pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) -> Symbol {
49 let validate = |s: Symbol, span: Option<Span>| {
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 61 if let Some(ref s) = sess.opts.crate_name {
487cf647 62 let s = Symbol::intern(s);
3dfed10e 63 if let Some((attr, name)) = attr_crate_name {
487cf647 64 if name != s {
f2b60f7d 65 sess.emit_err(CrateNameDoesNotMatch { span: attr.span, s, name });
3b2f2976 66 }
3b2f2976 67 }
487cf647 68 return validate(s, None);
3b2f2976
XL
69 }
70
71 if let Some((attr, s)) = attr_crate_name {
487cf647 72 return validate(s, Some(attr.span));
3b2f2976
XL
73 }
74 if let Input::File(ref path) = *input {
75 if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
74b04a01 76 if s.starts_with('-') {
f2b60f7d 77 sess.emit_err(CrateNameInvalid { s });
3b2f2976 78 } else {
487cf647 79 return validate(Symbol::intern(&s.replace('-', "_")), None);
3b2f2976
XL
80 }
81 }
82 }
83
487cf647 84 Symbol::intern("rust_out")
3b2f2976
XL
85}
86
487cf647 87pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option<Span>) {
ba9703b0
XL
88 let mut err_count = 0;
89 {
ba9703b0 90 if s.is_empty() {
f2b60f7d
FG
91 err_count += 1;
92 sess.emit_err(CrateNameEmpty { span: sp });
ba9703b0 93 }
487cf647 94 for c in s.as_str().chars() {
ba9703b0
XL
95 if c.is_alphanumeric() {
96 continue;
97 }
98 if c == '_' {
99 continue;
100 }
f2b60f7d
FG
101 err_count += 1;
102 sess.emit_err(InvalidCharacterInCrateName { span: sp, character: c, crate_name: s });
ba9703b0
XL
103 }
104 }
105
106 if err_count > 0 {
3dfed10e 107 sess.abort_if_errors();
ba9703b0
XL
108 }
109}
110
dfeec247
XL
111pub fn filename_for_metadata(
112 sess: &Session,
487cf647 113 crate_name: Symbol,
dfeec247
XL
114 outputs: &OutputFilenames,
115) -> PathBuf {
17df50a5
XL
116 // If the command-line specified the path, use that directly.
117 if let Some(Some(out_filename)) = sess.opts.output_types.get(&OutputType::Metadata) {
118 return out_filename.clone();
119 }
120
0bf4aa26
XL
121 let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
122
dfeec247
XL
123 let out_filename = outputs
124 .single_output_file
125 .clone()
5e7ed085 126 .unwrap_or_else(|| outputs.out_directory.join(&format!("lib{libname}.rmeta")));
0bf4aa26
XL
127
128 check_file_is_writeable(&out_filename, sess);
129
130 out_filename
131}
132
dfeec247
XL
133pub fn filename_for_input(
134 sess: &Session,
f9f354fc 135 crate_type: CrateType,
487cf647 136 crate_name: Symbol,
dfeec247
XL
137 outputs: &OutputFilenames,
138) -> PathBuf {
3b2f2976
XL
139 let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
140
141 match crate_type {
5e7ed085 142 CrateType::Rlib => outputs.out_directory.join(&format!("lib{libname}.rlib")),
f9f354fc 143 CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib => {
29967ef6 144 let (prefix, suffix) = (&sess.target.dll_prefix, &sess.target.dll_suffix);
5e7ed085 145 outputs.out_directory.join(&format!("{prefix}{libname}{suffix}"))
3b2f2976 146 }
f9f354fc 147 CrateType::Staticlib => {
29967ef6 148 let (prefix, suffix) = (&sess.target.staticlib_prefix, &sess.target.staticlib_suffix);
5e7ed085 149 outputs.out_directory.join(&format!("{prefix}{libname}{suffix}"))
3b2f2976 150 }
f9f354fc 151 CrateType::Executable => {
29967ef6 152 let suffix = &sess.target.exe_suffix;
3b2f2976 153 let out_filename = outputs.path(OutputType::Exe);
dfeec247 154 if suffix.is_empty() { out_filename } else { out_filename.with_extension(&suffix[1..]) }
3b2f2976
XL
155 }
156 }
157}
158
159/// Returns default crate type for target
160///
161/// Default crate type is used when crate type isn't provided neither
162/// through cmd line arguments nor through crate attributes
163///
b7449926 164/// It is CrateType::Executable for all platforms but iOS as there is no
3b2f2976
XL
165/// way to run iOS binaries anyway without jailbreaking and
166/// interaction with Rust code through static library is the only
167/// option for now
f9f354fc 168pub fn default_output_for_target(sess: &Session) -> CrateType {
29967ef6 169 if !sess.target.executables { CrateType::Staticlib } else { CrateType::Executable }
3b2f2976
XL
170}
171
172/// Checks if target supports crate_type as output
f9f354fc 173pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool {
5e7ed085
FG
174 if let CrateType::Cdylib | CrateType::Dylib | CrateType::ProcMacro = crate_type {
175 if !sess.target.dynamic_linking {
176 return true;
abe05a73 177 }
5e7ed085
FG
178 if sess.crt_static(Some(crate_type)) && !sess.target.crt_static_allows_dylibs {
179 return true;
abe05a73
XL
180 }
181 }
5e7ed085
FG
182 if let CrateType::ProcMacro | CrateType::Dylib = crate_type && sess.target.only_cdylib {
183 return true;
184 }
185 if let CrateType::Executable = crate_type && !sess.target.executables {
29967ef6 186 return true;
abe05a73
XL
187 }
188
189 false
3b2f2976 190}