Skip to content

Commit

Permalink
Add automatic exe generation capabilities. Add --bitcode flag to gene…
Browse files Browse the repository at this point in the history
…rate only an LLVM bitcode file.
  • Loading branch information
wilsonk authored and graydon committed May 16, 2011
1 parent 32b8dcb commit 196351a
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 26 deletions.
4 changes: 2 additions & 2 deletions src/comp/README
Expand Up @@ -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.
62 changes: 40 additions & 22 deletions src/comp/back/link.rs
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -143,44 +143,62 @@ 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;
}

// 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();
}
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));
Expand Down
70 changes: 68 additions & 2 deletions src/comp/driver/rustc.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"),
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);
Expand All @@ -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:
Expand Down

0 comments on commit 196351a

Please sign in to comment.