1+ pub mod run;
2+
13use std:: env;
24use std:: path:: { Path , PathBuf } ;
35use std:: process:: { Command , Output } ;
46
57pub use wasmparser;
68
9+ pub use run:: { run, run_fail} ;
10+
711pub fn out_dir ( ) -> PathBuf {
812 env:: var_os ( "TMPDIR" ) . unwrap ( ) . into ( )
913}
@@ -24,65 +28,148 @@ fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> !
2428 std:: process:: exit ( 1 )
2529}
2630
27- pub fn rustc ( ) -> RustcInvocationBuilder {
28- RustcInvocationBuilder :: new ( )
29- }
30-
31- pub fn aux_build ( ) -> AuxBuildInvocationBuilder {
32- AuxBuildInvocationBuilder :: new ( )
33- }
34-
31+ /// A `rustc` invocation builder.
3532#[ derive( Debug ) ]
36- pub struct RustcInvocationBuilder {
33+ pub struct Rustc {
3734 cmd : Command ,
3835}
3936
40- impl RustcInvocationBuilder {
41- fn new ( ) -> Self {
37+ impl Rustc {
38+ // `rustc` invocation constructor methods
39+
40+ /// Construct a new `rustc` invocation.
41+ pub fn new ( ) -> Self {
4242 let cmd = setup_common_build_cmd ( ) ;
4343 Self { cmd }
4444 }
4545
46- pub fn arg ( & mut self , arg : & str ) -> & mut RustcInvocationBuilder {
47- self . cmd . arg ( arg) ;
46+ /// Construct a new `rustc` invocation with `aux_build` preset (setting `--crate-type=lib`).
47+ pub fn new_aux_build ( ) -> Self {
48+ let mut cmd = setup_common_build_cmd ( ) ;
49+ cmd. arg ( "--crate-type=lib" ) ;
50+ Self { cmd }
51+ }
52+
53+ // Argument provider methods
54+
55+ /// Configure the compilation environment.
56+ pub fn cfg ( & mut self , s : & str ) -> & mut Self {
57+ self . cmd . arg ( "--cfg" ) ;
58+ self . cmd . arg ( s) ;
4859 self
4960 }
5061
51- pub fn args ( & mut self , args : & [ & str ] ) -> & mut RustcInvocationBuilder {
52- self . cmd . args ( args) ;
62+ /// Configure codegen options.
63+ pub fn codegen_opt ( & mut self , c : CodegenOpt ) -> & mut Self {
64+ self . cmd . arg ( "-C" ) ;
65+
66+ match c {
67+ CodegenOpt :: PreferDynamic => self . cmd . arg ( "prefer-dynamic=true" ) ,
68+ CodegenOpt :: SymbolManglingVersion ( v) => match v {
69+ SymbolManglingVersion :: Legacy => self . cmd . arg ( "symbol-mangling-version=legacy" ) ,
70+ SymbolManglingVersion :: V0 => self . cmd . arg ( "symbol-mangling-version=v0" ) ,
71+ } ,
72+ CodegenOpt :: Lto ( kind) => match kind {
73+ LtoKind :: Fat => self . cmd . arg ( "lto=fat" ) ,
74+ LtoKind :: Thin => self . cmd . arg ( "lto=thin" ) ,
75+ LtoKind :: None => self . cmd . arg ( "lto=false" ) ,
76+ } ,
77+ CodegenOpt :: OptLevel ( level) => match level {
78+ OptLevel :: O0 => self . cmd . arg ( "opt-level=0" ) ,
79+ OptLevel :: O1 => self . cmd . arg ( "opt-level=1" ) ,
80+ OptLevel :: O2 => self . cmd . arg ( "opt-level=2" ) ,
81+ OptLevel :: O3 => self . cmd . arg ( "opt-level=3" ) ,
82+ OptLevel :: Os => self . cmd . arg ( "opt-level=s" ) ,
83+ OptLevel :: Oz => self . cmd . arg ( "opt-level=z" ) ,
84+ } ,
85+ CodegenOpt :: OverflowChecks => self . cmd . arg ( "overflow-checks=true" ) ,
86+ CodegenOpt :: Panic ( strat) => match strat {
87+ PanicStrategy :: Abort => self . cmd . arg ( "panic=abort" ) ,
88+ PanicStrategy :: Unwind => self . cmd . arg ( "panic=unwind" ) ,
89+ } ,
90+ } ;
91+
5392 self
5493 }
5594
56- #[ track_caller]
57- pub fn run ( & mut self ) -> Output {
58- let caller_location = std:: panic:: Location :: caller ( ) ;
59- let caller_line_number = caller_location. line ( ) ;
95+ /// Specify default optimization level `-O` (alias for `-C opt-level=2`).
96+ pub fn default_opt ( & mut self ) -> & mut Self {
97+ self . cmd . arg ( "-O" ) ;
98+ self
99+ }
60100
61- let output = self . cmd . output ( ) . unwrap ( ) ;
62- if !output. status . success ( ) {
63- handle_failed_output ( & format ! ( "{:#?}" , self . cmd) , output, caller_line_number) ;
64- }
65- output
101+ /// Specify types of output files to generate. See [`EmitKind`] for kinds.
102+ pub fn emit ( & mut self , kinds : & [ EmitKind ] ) -> & mut Self {
103+ let kinds = kinds
104+ . iter ( )
105+ . map ( |kind| match kind {
106+ EmitKind :: Metadata => "metadata" ,
107+ } )
108+ . collect :: < Vec < _ > > ( ) ;
109+ let kinds_str: String = kinds. join ( "," ) ;
110+ self . cmd . arg ( format ! ( "--emit={kinds_str}" ) ) ;
111+ self
66112 }
67- }
68113
69- #[ derive( Debug ) ]
70- pub struct AuxBuildInvocationBuilder {
71- cmd : Command ,
72- }
114+ /// Set `-Z unstable-options`
115+ pub fn enable_unstable_options ( & mut self ) -> & mut Self {
116+ self . cmd . arg ( "-Z" ) ;
117+ self . cmd . arg ( "unstable-options" ) ;
118+ self
119+ }
73120
74- impl AuxBuildInvocationBuilder {
75- fn new ( ) -> Self {
76- let mut cmd = setup_common_build_cmd ( ) ;
77- cmd. arg ( "--crate-type=lib" ) ;
78- Self { cmd }
121+ /// Specify where an external library is located.
122+ pub fn extern_ < P : AsRef < Path > > ( & mut self , crate_name : & str , path : P ) -> & mut Self {
123+ assert ! (
124+ !crate_name. contains( |c: char | c. is_whitespace( ) || c == '\\' || c == '/' ) ,
125+ "crate name cannot contain whitespace or path separators"
126+ ) ;
127+
128+ let path = path. as_ref ( ) . to_string_lossy ( ) ;
129+
130+ self . cmd . arg ( "--extern" ) ;
131+ self . cmd . arg ( format ! ( "{crate_name}={path}" ) ) ;
132+
133+ self
79134 }
80135
81- pub fn arg ( & mut self , arg : & str ) -> & mut AuxBuildInvocationBuilder {
136+ /// Specify path to the input file.
137+ pub fn input_file < P : AsRef < Path > > ( & mut self , path : P ) -> & mut Self {
138+ self . cmd . arg ( path. as_ref ( ) ) ;
139+ self
140+ }
141+
142+ /// Specify target triple.
143+ pub fn target ( & mut self , target : & str ) -> & mut Self {
144+ assert ! ( !target. contains( char :: is_whitespace) , "target triple cannot contain spaces" ) ;
145+ self . cmd . arg ( format ! ( "--target={target}" ) ) ;
146+ self
147+ }
148+
149+ // Last-resort builder methods
150+
151+ /// Fallback command argument provider. Prefer using semantically meaningful builder methods
152+ /// (add them if they don't exist) whenever possible.
153+ pub fn arg ( & mut self , arg : & str ) -> & mut Self {
82154 self . cmd . arg ( arg) ;
83155 self
84156 }
85157
158+ /// Fallback command arguments provider. Prefer using semantically meaningful builder methods
159+ /// (add them if they don't exist) whenever possible.
160+ pub fn args ( & mut self , args : & [ & str ] ) -> & mut Self {
161+ self . cmd . args ( args) ;
162+ self
163+ }
164+
165+ // Command inspection, output and running helper methods
166+
167+ /// Get the [`Output`][std::process::Output] of the finished `rustc` process.
168+ pub fn output ( & mut self ) -> Output {
169+ self . cmd . output ( ) . unwrap ( )
170+ }
171+
172+ /// Run the constructed `rustc` command and assert that it is successfully run.
86173 #[ track_caller]
87174 pub fn run ( & mut self ) -> Output {
88175 let caller_location = std:: panic:: Location :: caller ( ) ;
@@ -94,66 +181,81 @@ impl AuxBuildInvocationBuilder {
94181 }
95182 output
96183 }
97- }
98184
99- fn run_common ( bin_name : & str ) -> ( Command , Output ) {
100- let target = env:: var ( "TARGET" ) . unwrap ( ) ;
101-
102- let bin_name =
103- if target. contains ( "windows" ) { format ! ( "{}.exe" , bin_name) } else { bin_name. to_owned ( ) } ;
104-
105- let mut bin_path = PathBuf :: new ( ) ;
106- bin_path. push ( env:: var ( "TMPDIR" ) . unwrap ( ) ) ;
107- bin_path. push ( & bin_name) ;
108- let ld_lib_path_envvar = env:: var ( "LD_LIB_PATH_ENVVAR" ) . unwrap ( ) ;
109- let mut cmd = Command :: new ( bin_path) ;
110- cmd. env ( & ld_lib_path_envvar, {
111- let mut paths = vec ! [ ] ;
112- paths. push ( PathBuf :: from ( env:: var ( "TMPDIR" ) . unwrap ( ) ) ) ;
113- for p in env:: split_paths ( & env:: var ( "TARGET_RPATH_ENV" ) . unwrap ( ) ) {
114- paths. push ( p. to_path_buf ( ) ) ;
115- }
116- for p in env:: split_paths ( & env:: var ( & ld_lib_path_envvar) . unwrap ( ) ) {
117- paths. push ( p. to_path_buf ( ) ) ;
118- }
119- env:: join_paths ( paths. iter ( ) ) . unwrap ( )
120- } ) ;
121-
122- if target. contains ( "windows" ) {
123- let mut paths = vec ! [ ] ;
124- for p in env:: split_paths ( & std:: env:: var ( "PATH" ) . unwrap_or ( String :: new ( ) ) ) {
125- paths. push ( p. to_path_buf ( ) ) ;
126- }
127- paths. push ( Path :: new ( & std:: env:: var ( "TARGET_RPATH_DIR" ) . unwrap ( ) ) . to_path_buf ( ) ) ;
128- cmd. env ( "PATH" , env:: join_paths ( paths. iter ( ) ) . unwrap ( ) ) ;
185+ /// Inspect what the underlying [`Command`] is up to the current construction.
186+ pub fn inspect ( & mut self , f : impl FnOnce ( & Command ) ) -> & mut Self {
187+ f ( & self . cmd ) ;
188+ self
129189 }
190+ }
130191
131- let output = cmd. output ( ) . unwrap ( ) ;
132- ( cmd, output)
192+ /// Specifies the types of output files to generate.
193+ pub enum EmitKind {
194+ /// Generates a file containing metadata about the crate. The default output filename is
195+ /// `libCRATE_NAME.rmeta`.
196+ Metadata ,
133197}
134198
135- /// Run a built binary and make sure it succeeds.
136- #[ track_caller]
137- pub fn run ( bin_name : & str ) -> Output {
138- let caller_location = std:: panic:: Location :: caller ( ) ;
139- let caller_line_number = caller_location. line ( ) ;
199+ /// Specifies codegen options.
200+ pub enum CodegenOpt {
201+ /// By default, rustc prefers to statically link dependencies. This option will indicate that
202+ /// dynamic linking should be used if possible if both a static and dynamic versions of a
203+ /// library are available.
204+ PreferDynamic ,
205+ /// Controls the name mangling format for encoding Rust item names for the purpose of generating
206+ /// object code and linking.
207+ SymbolManglingVersion ( SymbolManglingVersion ) ,
208+ /// Controls whether LLVM uses link time optimizations to produce better optimized code, using
209+ /// whole-program analysis, at the cost of longer linking time.
210+ Lto ( LtoKind ) ,
211+ ///
212+ OptLevel ( OptLevel ) ,
213+ /// Control the behavior of runtime integer overflow. When `overflow-checks` are enabled, a
214+ /// panic will occur on overflow.
215+ OverflowChecks ,
216+ /// Control what happens when the code panics.
217+ Panic ( PanicStrategy ) ,
218+ }
140219
141- let ( cmd , output ) = run_common ( bin_name ) ;
142- if !output . status . success ( ) {
143- handle_failed_output ( & format ! ( "{:#?}" , cmd ) , output , caller_line_number ) ;
144- }
145- output
220+ /// The name mangling format for encoding Rust item names for the purpose of generating object code
221+ /// and linking.
222+ pub enum SymbolManglingVersion {
223+ Legacy ,
224+ V0 ,
146225}
147226
148- /// Run a built binary and make sure it fails.
149- #[ track_caller]
150- pub fn run_fail ( bin_name : & str ) -> Output {
151- let caller_location = std:: panic:: Location :: caller ( ) ;
152- let caller_line_number = caller_location. line ( ) ;
227+ /// Kind of LTO to perform.
228+ pub enum LtoKind {
229+ /// Perform "fat" LTO which attempts to perform optimizations across all crates within the
230+ /// dependency graph.
231+ Fat ,
232+ /// Similar to "fat", but takes substantially less time to run while still achieving performance
233+ /// gains similar to "fat".
234+ Thin ,
235+ /// Disable LTO.
236+ None ,
237+ }
153238
154- let ( cmd, output) = run_common ( bin_name) ;
155- if output. status . success ( ) {
156- handle_failed_output ( & format ! ( "{:#?}" , cmd) , output, caller_line_number) ;
157- }
158- output
239+ /// Optimization level.
240+ pub enum OptLevel {
241+ /// No optimizations, also turns on `cfg(debug_assertions)` (the default).
242+ O0 ,
243+ /// Basic optimizations.
244+ O1 ,
245+ /// Some optimizations.
246+ O2 ,
247+ /// All optimizations.
248+ O3 ,
249+ /// Optimize for binary size.
250+ Os ,
251+ /// Optimize for binary size, but also turn off loop vectorization.
252+ Oz ,
253+ }
254+
255+ /// What happens when the code panics.
256+ pub enum PanicStrategy {
257+ /// Terminate the process upon panic.
258+ Abort ,
259+ /// Unwind the stack upon panic.
260+ Unwind ,
159261}
0 commit comments