diff --git a/src/comp/README b/src/comp/README index 974511a8c0a6e..3598a221b999e 100644 --- a/src/comp/README +++ b/src/comp/README @@ -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. diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index 373027daf1e1a..1652863de9784 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -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)); diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 6effc44f69416..279f69ac61686 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -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: