@@ -7,8 +7,6 @@ pub struct CompilationCommandBuilder {
7
7
optimization : String ,
8
8
include_paths : Vec < String > ,
9
9
project_root : Option < String > ,
10
- output : String ,
11
- input : String ,
12
10
linker : Option < String > ,
13
11
extra_flags : Vec < String > ,
14
12
}
@@ -23,8 +21,6 @@ impl CompilationCommandBuilder {
23
21
optimization : "2" . to_string ( ) ,
24
22
include_paths : Vec :: new ( ) ,
25
23
project_root : None ,
26
- output : String :: new ( ) ,
27
- input : String :: new ( ) ,
28
24
linker : None ,
29
25
extra_flags : Vec :: new ( ) ,
30
26
}
@@ -71,18 +67,6 @@ impl CompilationCommandBuilder {
71
67
self
72
68
}
73
69
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
-
86
70
pub fn set_linker ( mut self , linker : String ) -> Self {
87
71
self . linker = Some ( linker) ;
88
72
self
@@ -100,55 +84,122 @@ impl CompilationCommandBuilder {
100
84
}
101
85
102
86
impl 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
+
105
94
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 ) ;
121
102
122
103
if let Some ( target) = & self . target {
123
- command = command + " --target=" + target;
104
+ cpp_compiler . arg ( format ! ( " --target={ target}" ) ) ;
124
105
}
125
106
126
107
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
+ }
151
203
}
152
- command
153
204
}
154
205
}
0 commit comments