Add automatic exe generation capabilities. Add --bitcode flag to generate only an LLVM bitcode file.

This commit is contained in:
Kelly Wilson 2011-05-16 09:01:36 -06:00 committed by Graydon Hoare
parent 32b8dcb97c
commit 196351aa44
3 changed files with 110 additions and 26 deletions

View file

@ -73,5 +73,5 @@ Control and information flow within the compiler:
- Finally middle/trans.rs is applied to the AST, which performs a
type-directed translation to LLVM-ese. When it's finished synthesizing LLVM
values, rustc asks LLVM to write them out as a bitcode file, on which you
can run the normal LLVM pipeline (opt, llc, as) to get an executable.
values, rustc asks LLVM to write them out as an executable, on which the
normal LLVM pipeline (opt, llc, as) was run.

View file

@ -17,6 +17,7 @@ tag output_type {
output_type_bitcode;
output_type_assembly;
output_type_object;
output_type_exe;
}
fn llvm_err(session::session sess, str msg) {
@ -56,11 +57,10 @@ fn link_intrinsics(session::session sess, ModuleRef llmod) {
}
mod write {
fn is_object_or_assembly(output_type ot) -> bool {
if (ot == output_type_assembly) {
ret true;
}
if (ot == output_type_object) {
fn is_object_or_assembly_or_exe(output_type ot) -> bool {
if ( (ot == output_type_assembly) ||
(ot == output_type_object) ||
(ot == output_type_exe) ) {
ret true;
}
ret false;
@ -143,13 +143,13 @@ mod write {
llvm::LLVMAddVerifierPass(pm.llpm);
}
// TODO: Write .s if -c was specified and -save-temps was on.
if (is_object_or_assembly(opts.output_type)) {
if (is_object_or_assembly_or_exe(opts.output_type)) {
let int LLVMAssemblyFile = 0;
let int LLVMObjectFile = 1;
let int LLVMNullFile = 2;
auto FileType;
if (opts.output_type == output_type_object) {
if ((opts.output_type == output_type_object) ||
(opts.output_type == output_type_exe)) {
FileType = LLVMObjectFile;
} else {
FileType = LLVMAssemblyFile;
@ -157,23 +157,39 @@ mod write {
// Write optimized bitcode if --save-temps was on.
if (opts.save_temps) {
alt (opts.output_type) {
case (output_type_bitcode) { /* nothing to do */ }
case (_) {
auto filename = mk_intermediate_name(output,
"opt.bc");
llvm::LLVMRunPassManager(pm.llpm, llmod);
llvm::LLVMWriteBitcodeToFile(llmod,
_str::buf(filename));
pm = mk_pass_manager();
}
// Always output the bitcode file with --save-temps
auto filename = mk_intermediate_name(output, "opt.bc");
llvm::LLVMRunPassManager(pm.llpm, llmod);
llvm::LLVMWriteBitcodeToFile(llmod, _str::buf(output));
pm = mk_pass_manager();
// Save the assembly file if -S is used
if (opts.output_type == output_type_assembly) {
llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
_str::buf(x86::get_target_triple()),
_str::buf(output), LLVMAssemblyFile);
}
// Save the object file for -c or only --save-temps
// is used and an exe is built
if ((opts.output_type == output_type_object) ||
(opts.output_type == output_type_exe)) {
llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
_str::buf(x86::get_target_triple()),
_str::buf(output), LLVMObjectFile);
}
} else {
// If we aren't saving temps then just output the file
// type corresponding to the '-c' or '-S' flag used
llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
_str::buf(x86::get_target_triple()),
_str::buf(output),
FileType);
}
llvm::LLVMRustWriteOutputFile(pm.llpm, llmod,
_str::buf(x86::get_target_triple()),
_str::buf(output),
FileType);
// Clean up and return
llvm::LLVMDisposeModule(llmod);
if (opts.time_llvm_passes) {
llvm::LLVMRustPrintPassTimings();
@ -181,6 +197,8 @@ mod write {
ret;
}
// If only a bitcode file is asked for by using the '--bitcode'
// flag, then output it here
llvm::LLVMRunPassManager(pm.llpm, llmod);
llvm::LLVMWriteBitcodeToFile(llmod, _str::buf(output));

View file

@ -22,6 +22,7 @@ import std::option::none;
import std::_str;
import std::_vec;
import std::io;
import std::run;
import std::getopts;
import std::getopts::optopt;
@ -154,6 +155,7 @@ options:
-O optimize
-S compile only; do not assemble or link
-c compile and assemble, but do not link
--bitcode produce an LLVM bitcode file
--save-temps write intermediate files in addition to normal output
--stats gather and report various compilation statistics
--time-passes time the individual phases of the compiler
@ -205,7 +207,7 @@ fn main(vec[str] args) {
auto opts = vec(optflag("h"), optflag("help"),
optflag("v"), optflag("version"),
optflag("glue"),
optflag("glue"), optflag("bitcode"),
optflag("pretty"), optflag("ls"), optflag("parse-only"),
optflag("O"), optflag("shared"), optmulti("L"),
optflag("S"), optflag("c"), optopt("o"), optflag("g"),
@ -241,13 +243,15 @@ fn main(vec[str] args) {
auto output_file = getopts::opt_maybe_str(match, "o");
auto library_search_paths = getopts::opt_strs(match, "L");
auto output_type = link::output_type_bitcode;
auto output_type = link::output_type_exe;
if (opt_present(match, "parse-only")) {
output_type = link::output_type_none;
} else if (opt_present(match, "S")) {
output_type = link::output_type_assembly;
} else if (opt_present(match, "c")) {
output_type = link::output_type_object;
} else if (opt_present(match, "bitcode")) {
output_type = link::output_type_bitcode;
}
auto verify = !opt_present(match, "noverify");
@ -306,6 +310,7 @@ fn main(vec[str] args) {
}
auto ifile = match.free.(0);
let str saved_out_filename = "";
auto env = default_environment(sess, args.(0), ifile);
if (pretty) {
pretty_print_input(sess, env, ifile);
@ -316,20 +321,81 @@ fn main(vec[str] args) {
case (none[str]) {
let vec[str] parts = _str::split(ifile, '.' as u8);
_vec::pop[str](parts);
saved_out_filename = parts.(0);
alt (output_type) {
case (link::output_type_none) { parts += vec("pp"); }
case (link::output_type_bitcode) { parts += vec("bc"); }
case (link::output_type_assembly) { parts += vec("s"); }
// Object and exe output both use the '.o' extension here
case (link::output_type_object) { parts += vec("o"); }
case (link::output_type_exe) { parts += vec("o"); }
}
auto ofile = _str::connect(parts, ".");
compile_input(sess, env, ifile, ofile);
}
case (some[str](?ofile)) {
saved_out_filename = ofile;
compile_input(sess, env, ifile, ofile);
}
}
}
// If the user wants an exe generated we need to invoke
// gcc to link the object file with some libs
if (output_type == link::output_type_exe) {
//FIXME: Should we make the 'stage3's variable here?
let str glu = "stage3/glue.o";
let str stage = "-Lstage3";
let vec[str] gcc_args;
let str prog = "gcc";
let str exe_suffix = "";
// The invocations of gcc share some flags across platforms
let vec[str] common_cflags = vec("-fno-strict-aliasing", "-fPIC",
"-Wall", "-fno-rtti", "-fno-exceptions", "-g");
let vec[str] common_libs = vec(stage, "-Lrustllvm", "-Lrt",
"-lrustrt", "-lrustllvm", "-lstd", "-lm");
alt (sess.get_targ_cfg().os) {
case (session::os_win32) {
exe_suffix = ".exe";
gcc_args = common_cflags + vec(
"-march=i686", "-O2",
glu, "-o",
saved_out_filename + exe_suffix,
saved_out_filename + ".o") + common_libs;
}
case (session::os_macos) {
gcc_args = common_cflags + vec(
"-arch i386", "-O0", "-m32",
glu, "-o",
saved_out_filename + exe_suffix,
saved_out_filename + ".o") + common_libs;
}
case (session::os_linux) {
gcc_args = common_cflags + vec(
"-march=i686", "-O2", "-m32",
glu, "-o",
saved_out_filename + exe_suffix,
saved_out_filename + ".o") + common_libs;
}
}
// We run 'gcc' here
run::run_program(prog, gcc_args);
// Clean up on Darwin
if (sess.get_targ_cfg().os == session::os_macos) {
run::run_program("dsymutil", vec(saved_out_filename));
}
// Remove the temporary object file if we aren't saving temps
if (!save_temps) {
run::run_program("rm", vec(saved_out_filename + ".o"));
}
}
}
// Local Variables: