Skip to content

Auto link #378

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/comp/README
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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 --save-temps alone
// This .o is needed when 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 '--emit-llvm'
// 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
Original file line number Diff line number Diff line change
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
--emit-llvm 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("emit-llvm"),
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, "emit-llvm")) {
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