Skip to content

Commit 196351a

Browse files
wilsonkgraydon
authored andcommitted
Add automatic exe generation capabilities. Add --bitcode flag to generate only an LLVM bitcode file.
1 parent 32b8dcb commit 196351a

File tree

3 files changed

+110
-26
lines changed

3 files changed

+110
-26
lines changed

src/comp/README

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,5 +73,5 @@ Control and information flow within the compiler:
7373

7474
- Finally middle/trans.rs is applied to the AST, which performs a
7575
type-directed translation to LLVM-ese. When it's finished synthesizing LLVM
76-
values, rustc asks LLVM to write them out as a bitcode file, on which you
77-
can run the normal LLVM pipeline (opt, llc, as) to get an executable.
76+
values, rustc asks LLVM to write them out as an executable, on which the
77+
normal LLVM pipeline (opt, llc, as) was run.

src/comp/back/link.rs

+40-22
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ tag output_type {
1717
output_type_bitcode;
1818
output_type_assembly;
1919
output_type_object;
20+
output_type_exe;
2021
}
2122

2223
fn llvm_err(session::session sess, str msg) {
@@ -56,11 +57,10 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) {
5657
}
5758

5859
mod write {
59-
fn is_object_or_assembly(output_type ot) -> bool {
60-
if (ot == output_type_assembly) {
61-
ret true;
62-
}
63-
if (ot == output_type_object) {
60+
fn is_object_or_assembly_or_exe(output_type ot) -> bool {
61+
if ( (ot == output_type_assembly) ||
62+
(ot == output_type_object) ||
63+
(ot == output_type_exe) ) {
6464
ret true;
6565
}
6666
ret false;
@@ -143,44 +143,62 @@ mod write {
143143
llvm::LLVMAddVerifierPass(pm.llpm);
144144
}
145145

146-
// TODO: Write .s if -c was specified and -save-temps was on.
147-
if (is_object_or_assembly(opts.output_type)) {
146+
if (is_object_or_assembly_or_exe(opts.output_type)) {
148147
let int LLVMAssemblyFile = 0;
149148
let int LLVMObjectFile = 1;
150149
let int LLVMNullFile = 2;
151150
auto FileType;
152-
if (opts.output_type == output_type_object) {
151+
if ((opts.output_type == output_type_object) ||
152+
(opts.output_type == output_type_exe)) {
153153
FileType = LLVMObjectFile;
154154
} else {
155155
FileType = LLVMAssemblyFile;
156156
}
157157

158158
// Write optimized bitcode if --save-temps was on.
159159
if (opts.save_temps) {
160-
alt (opts.output_type) {
161-
case (output_type_bitcode) { /* nothing to do */ }
162-
case (_) {
163-
auto filename = mk_intermediate_name(output,
164-
"opt.bc");
165-
llvm::LLVMRunPassManager(pm.llpm, llmod);
166-
llvm::LLVMWriteBitcodeToFile(llmod,
167-
_str::buf(filename));
168-
pm = mk_pass_manager();
169-
}
160+
161+
// Always output the bitcode file with --save-temps
162+
auto filename = mk_intermediate_name(output, "opt.bc");
163+
llvm::LLVMRunPassManager(pm.llpm, llmod);
164+
llvm::LLVMWriteBitcodeToFile(llmod, _str::buf(output));
165+
pm = mk_pass_manager();
166+
167+
// Save the assembly file if -S is used
168+
if (opts.output_type == output_type_assembly) {
169+
llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
170+
_str::buf(x86::get_target_triple()),
171+
_str::buf(output), LLVMAssemblyFile);
170172
}
173+
174+
// Save the object file for -c or only --save-temps
175+
// is used and an exe is built
176+
if ((opts.output_type == output_type_object) ||
177+
(opts.output_type == output_type_exe)) {
178+
llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
179+
_str::buf(x86::get_target_triple()),
180+
_str::buf(output), LLVMObjectFile);
181+
}
182+
} else {
183+
184+
// If we aren't saving temps then just output the file
185+
// type corresponding to the '-c' or '-S' flag used
186+
llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
187+
_str::buf(x86::get_target_triple()),
188+
_str::buf(output),
189+
FileType);
171190
}
172191

173-
llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
174-
_str::buf(x86::get_target_triple()),
175-
_str::buf(output),
176-
FileType);
192+
// Clean up and return
177193
llvm::LLVMDisposeModule(llmod);
178194
if (opts.time_llvm_passes) {
179195
llvm::LLVMRustPrintPassTimings();
180196
}
181197
ret;
182198
}
183199

200+
// If only a bitcode file is asked for by using the '--bitcode'
201+
// flag, then output it here
184202
llvm::LLVMRunPassManager(pm.llpm, llmod);
185203

186204
llvm::LLVMWriteBitcodeToFile(llmod, _str::buf(output));

src/comp/driver/rustc.rs

+68-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import std::option::none;
2222
import std::_str;
2323
import std::_vec;
2424
import std::io;
25+
import std::run;
2526

2627
import std::getopts;
2728
import std::getopts::optopt;
@@ -154,6 +155,7 @@ options:
154155
-O optimize
155156
-S compile only; do not assemble or link
156157
-c compile and assemble, but do not link
158+
--bitcode produce an LLVM bitcode file
157159
--save-temps write intermediate files in addition to normal output
158160
--stats gather and report various compilation statistics
159161
--time-passes time the individual phases of the compiler
@@ -205,7 +207,7 @@ fn main(vec[str] args) {
205207

206208
auto opts = vec(optflag("h"), optflag("help"),
207209
optflag("v"), optflag("version"),
208-
optflag("glue"),
210+
optflag("glue"), optflag("bitcode"),
209211
optflag("pretty"), optflag("ls"), optflag("parse-only"),
210212
optflag("O"), optflag("shared"), optmulti("L"),
211213
optflag("S"), optflag("c"), optopt("o"), optflag("g"),
@@ -241,13 +243,15 @@ fn main(vec[str] args) {
241243
auto output_file = getopts::opt_maybe_str(match, "o");
242244
auto library_search_paths = getopts::opt_strs(match, "L");
243245

244-
auto output_type = link::output_type_bitcode;
246+
auto output_type = link::output_type_exe;
245247
if (opt_present(match, "parse-only")) {
246248
output_type = link::output_type_none;
247249
} else if (opt_present(match, "S")) {
248250
output_type = link::output_type_assembly;
249251
} else if (opt_present(match, "c")) {
250252
output_type = link::output_type_object;
253+
} else if (opt_present(match, "bitcode")) {
254+
output_type = link::output_type_bitcode;
251255
}
252256

253257
auto verify = !opt_present(match, "noverify");
@@ -306,6 +310,7 @@ fn main(vec[str] args) {
306310
}
307311

308312
auto ifile = match.free.(0);
313+
let str saved_out_filename = "";
309314
auto env = default_environment(sess, args.(0), ifile);
310315
if (pretty) {
311316
pretty_print_input(sess, env, ifile);
@@ -316,20 +321,81 @@ fn main(vec[str] args) {
316321
case (none[str]) {
317322
let vec[str] parts = _str::split(ifile, '.' as u8);
318323
_vec::pop[str](parts);
324+
saved_out_filename = parts.(0);
319325
alt (output_type) {
320326
case (link::output_type_none) { parts += vec("pp"); }
321327
case (link::output_type_bitcode) { parts += vec("bc"); }
322328
case (link::output_type_assembly) { parts += vec("s"); }
329+
330+
// Object and exe output both use the '.o' extension here
323331
case (link::output_type_object) { parts += vec("o"); }
332+
case (link::output_type_exe) { parts += vec("o"); }
324333
}
325334
auto ofile = _str::connect(parts, ".");
326335
compile_input(sess, env, ifile, ofile);
327336
}
328337
case (some[str](?ofile)) {
338+
saved_out_filename = ofile;
329339
compile_input(sess, env, ifile, ofile);
330340
}
331341
}
332342
}
343+
344+
// If the user wants an exe generated we need to invoke
345+
// gcc to link the object file with some libs
346+
if (output_type == link::output_type_exe) {
347+
348+
//FIXME: Should we make the 'stage3's variable here?
349+
let str glu = "stage3/glue.o";
350+
let str stage = "-Lstage3";
351+
let vec[str] gcc_args;
352+
let str prog = "gcc";
353+
let str exe_suffix = "";
354+
355+
// The invocations of gcc share some flags across platforms
356+
let vec[str] common_cflags = vec("-fno-strict-aliasing", "-fPIC",
357+
"-Wall", "-fno-rtti", "-fno-exceptions", "-g");
358+
let vec[str] common_libs = vec(stage, "-Lrustllvm", "-Lrt",
359+
"-lrustrt", "-lrustllvm", "-lstd", "-lm");
360+
361+
alt (sess.get_targ_cfg().os) {
362+
case (session::os_win32) {
363+
exe_suffix = ".exe";
364+
gcc_args = common_cflags + vec(
365+
"-march=i686", "-O2",
366+
glu, "-o",
367+
saved_out_filename + exe_suffix,
368+
saved_out_filename + ".o") + common_libs;
369+
}
370+
case (session::os_macos) {
371+
gcc_args = common_cflags + vec(
372+
"-arch i386", "-O0", "-m32",
373+
glu, "-o",
374+
saved_out_filename + exe_suffix,
375+
saved_out_filename + ".o") + common_libs;
376+
}
377+
case (session::os_linux) {
378+
gcc_args = common_cflags + vec(
379+
"-march=i686", "-O2", "-m32",
380+
glu, "-o",
381+
saved_out_filename + exe_suffix,
382+
saved_out_filename + ".o") + common_libs;
383+
}
384+
}
385+
386+
// We run 'gcc' here
387+
run::run_program(prog, gcc_args);
388+
389+
// Clean up on Darwin
390+
if (sess.get_targ_cfg().os == session::os_macos) {
391+
run::run_program("dsymutil", vec(saved_out_filename));
392+
}
393+
394+
// Remove the temporary object file if we aren't saving temps
395+
if (!save_temps) {
396+
run::run_program("rm", vec(saved_out_filename + ".o"));
397+
}
398+
}
333399
}
334400

335401
// Local Variables:

0 commit comments

Comments
 (0)