Add automatic exe generation capabilities. Add --bitcode flag to generate only an LLVM bitcode file.
This commit is contained in:
parent
32b8dcb97c
commit
196351aa44
3 changed files with 110 additions and 26 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue