@@ -7,8 +7,6 @@ pub struct CompilationCommandBuilder {
77 optimization : String ,
88 include_paths : Vec < String > ,
99 project_root : Option < String > ,
10- output : String ,
11- input : String ,
1210 linker : Option < String > ,
1311 extra_flags : Vec < String > ,
1412}
@@ -23,8 +21,6 @@ impl CompilationCommandBuilder {
2321 optimization : "2" . to_string ( ) ,
2422 include_paths : Vec :: new ( ) ,
2523 project_root : None ,
26- output : String :: new ( ) ,
27- input : String :: new ( ) ,
2824 linker : None ,
2925 extra_flags : Vec :: new ( ) ,
3026 }
@@ -71,18 +67,6 @@ impl CompilationCommandBuilder {
7167 self
7268 }
7369
74- /// The name of the output executable, without any suffixes
75- pub fn set_output_name ( mut self , path : & str ) -> Self {
76- self . output = path. to_string ( ) ;
77- self
78- }
79-
80- /// The name of the input C file, without any suffixes
81- pub fn set_input_name ( mut self , path : & str ) -> Self {
82- self . input = path. to_string ( ) ;
83- self
84- }
85-
8670 pub fn set_linker ( mut self , linker : String ) -> Self {
8771 self . linker = Some ( linker) ;
8872 self
@@ -100,55 +84,122 @@ impl CompilationCommandBuilder {
10084}
10185
10286impl CompilationCommandBuilder {
103- pub fn make_string ( self ) -> String {
104- let arch_flags = self . arch_flags . join ( "+" ) ;
87+ pub fn into_cpp_compilation ( self ) -> CppCompilation {
88+ let mut cpp_compiler = std:: process:: Command :: new ( self . compiler ) ;
89+
90+ if let Some ( project_root) = self . project_root {
91+ cpp_compiler. current_dir ( project_root) ;
92+ }
93+
10594 let flags = std:: env:: var ( "CPPFLAGS" ) . unwrap_or ( "" . into ( ) ) ;
106- let project_root = self . project_root . unwrap_or_default ( ) ;
107- let project_root_str = project_root. as_str ( ) ;
108- let mut output = self . output . clone ( ) ;
109- if self . linker . is_some ( ) {
110- output += ".o"
111- } ;
112- let mut command = format ! (
113- "{} {flags} -march={arch_flags} \
114- -O{} \
115- -o {project_root}/{} \
116- {project_root}/{}.cpp",
117- self . compiler, self . optimization, output, self . input,
118- ) ;
119-
120- command = command + " " + self . extra_flags . join ( " " ) . as_str ( ) ;
95+ cpp_compiler. args ( flags. split_whitespace ( ) ) ;
96+
97+ cpp_compiler. arg ( format ! ( "-march={}" , self . arch_flags. join( "+" ) ) ) ;
98+
99+ cpp_compiler. arg ( format ! ( "-O{}" , self . optimization) ) ;
100+
101+ cpp_compiler. args ( self . extra_flags ) ;
121102
122103 if let Some ( target) = & self . target {
123- command = command + " --target=" + target;
104+ cpp_compiler . arg ( format ! ( " --target={ target}" ) ) ;
124105 }
125106
126107 if let ( Some ( linker) , Some ( cxx_toolchain_dir) ) = ( & self . linker , & self . cxx_toolchain_dir ) {
127- let include_args = self
128- . include_paths
129- . iter ( )
130- . map ( |path| "--include-directory=" . to_string ( ) + cxx_toolchain_dir + path)
131- . collect :: < Vec < _ > > ( )
132- . join ( " " ) ;
133-
134- command = command
135- + " -c "
136- + include_args. as_str ( )
137- + " && "
138- + linker
139- + " "
140- + project_root_str
141- + "/"
142- + & output
143- + " -o "
144- + project_root_str
145- + "/"
146- + & self . output
147- + " && rm "
148- + project_root_str
149- + "/"
150- + & output;
108+ cpp_compiler. args (
109+ self . include_paths
110+ . iter ( )
111+ . map ( |path| "--include-directory=" . to_string ( ) + cxx_toolchain_dir + path) ,
112+ ) ;
113+
114+ CppCompilation :: CustomLinker {
115+ cpp_compiler,
116+ linker : linker. to_owned ( ) ,
117+ }
118+ } else {
119+ CppCompilation :: Simple ( cpp_compiler)
120+ }
121+ }
122+ }
123+
124+ pub enum CppCompilation {
125+ Simple ( std:: process:: Command ) ,
126+ CustomLinker {
127+ cpp_compiler : std:: process:: Command ,
128+ linker : String ,
129+ } ,
130+ }
131+
132+ fn clone_command ( command : & std:: process:: Command ) -> std:: process:: Command {
133+ let mut cmd = std:: process:: Command :: new ( command. get_program ( ) ) ;
134+ if let Some ( current_dir) = command. get_current_dir ( ) {
135+ cmd. current_dir ( current_dir) ;
136+ }
137+ cmd. args ( command. get_args ( ) ) ;
138+
139+ for ( key, val) in command. get_envs ( ) {
140+ cmd. env ( key, val. unwrap_or_default ( ) ) ;
141+ }
142+
143+ cmd
144+ }
145+
146+ impl CppCompilation {
147+ pub fn run ( & self , inputs : & [ String ] , output : & str ) -> std:: io:: Result < std:: process:: Output > {
148+ match self {
149+ CppCompilation :: Simple ( command) => {
150+ let mut cmd = clone_command ( command) ;
151+ cmd. args ( inputs) ;
152+ cmd. args ( [ "-o" , output] ) ;
153+
154+ cmd. output ( )
155+ }
156+ CppCompilation :: CustomLinker {
157+ cpp_compiler,
158+ linker,
159+ } => {
160+ let object_file = & format ! ( "{output}.o" ) ;
161+
162+ // Build an object file using the cpp compiler.
163+ let mut cmd = clone_command ( cpp_compiler) ;
164+ cmd. args ( inputs) ;
165+ cmd. args ( [ "-c" , "-o" , object_file] ) ;
166+
167+ let cpp_output = cmd. output ( ) ?;
168+ if !cpp_output. status . success ( ) {
169+ error ! ( "c++ compilaton failed" ) ;
170+ return Ok ( cpp_output) ;
171+ }
172+
173+ trace ! ( "using custom linker" ) ;
174+
175+ // Use the custom linker to turn the object file into an executable.
176+ let mut cmd = std:: process:: Command :: new ( linker) ;
177+ cmd. args ( [ object_file, "-o" , output] ) ;
178+
179+ if let Some ( current_dir) = cpp_compiler. get_current_dir ( ) {
180+ cmd. current_dir ( current_dir) ;
181+ }
182+
183+ for ( key, val) in cpp_compiler. get_envs ( ) {
184+ cmd. env ( key, val. unwrap_or_default ( ) ) ;
185+ }
186+
187+ let linker_output = cmd. output ( ) ?;
188+ if !linker_output. status . success ( ) {
189+ error ! ( "custom linker failed" ) ;
190+ return Ok ( linker_output) ;
191+ }
192+
193+ trace ! ( "removing {object_file}" ) ;
194+ let object_file_path = match cpp_compiler. get_current_dir ( ) {
195+ Some ( current_dir) => & format ! ( "{}/{object_file}" , current_dir. display( ) ) ,
196+ None => object_file,
197+ } ;
198+
199+ std:: fs:: remove_file ( object_file_path) ?;
200+
201+ Ok ( cpp_output)
202+ }
151203 }
152- command
153204 }
154205}
0 commit comments