From 6e7968b10a32cbef810dcb9e3d5bc736dbf61d1f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 3 Feb 2014 15:27:54 -0800 Subject: [PATCH] Redesign output flags for rustc This commit removes the -c, --emit-llvm, -s, --rlib, --dylib, --staticlib, --lib, and --bin flags from rustc, adding the following flags: * --emit=[asm,ir,bc,obj,link] * --crate-type=[dylib,rlib,staticlib,bin,lib] The -o option has also been redefined to be used for *all* flavors of outputs. This means that we no longer ignore it for libraries. The --out-dir remains the same as before. The new logic for files that rustc emits is as follows: 1. Output types are dictated by the --emit flag. The default value is --emit=link, and this option can be passed multiple times and have all options stacked on one another. 2. Crate types are dictated by the --crate-type flag and the #[crate_type] attribute. The flags can be passed many times and stack with the crate attribute. 3. If the -o flag is specified, and only one output type is specified, the output will be emitted at this location. If more than one output type is specified, then the filename of -o is ignored, and all output goes in the directory that -o specifies. The -o option always ignores the --out-dir option. 4. If the --out-dir flag is specified, all output goes in this directory. 5. If -o and --out-dir are both not present, all output goes in the current directory of the process. 6. When multiple output types are specified, the filestem of all output is the same as the name of the CrateId (derived from a crate attribute or from the filestem of the crate file). Closes #7791 Closes #11056 Closes #11667 --- man/rustc.1 | 24 +- mk/crates.mk | 2 +- mk/tests.mk | 2 +- src/compiletest/runtest.rs | 29 +- src/doc/rust.md | 64 ++-- src/doc/tutorial.md | 4 +- src/etc/zsh/_rust | 8 +- src/librustc/back/link.rs | 174 +++++----- src/librustc/back/lto.rs | 8 +- src/librustc/driver/driver.rs | 309 +++++++++--------- src/librustc/driver/session.rs | 49 ++- src/librustc/lib.rs | 8 +- src/librustc/middle/trans/base.rs | 5 +- src/librustdoc/core.rs | 2 +- src/librustdoc/test.rs | 6 +- src/test/run-make/crate-data-smoke/Makefile | 2 +- src/test/run-make/dep-info-custom/Makefile | 2 +- .../run-make/dep-info-custom/Makefile.foo | 4 +- src/test/run-make/dep-info/Makefile | 2 +- src/test/run-make/dep-info/Makefile.foo | 6 +- .../duplicate-output-flavors/Makefile | 2 +- src/test/run-make/mixing-libs/Makefile | 2 +- .../run-make/no-intermediate-extras/Makefile | 2 +- .../output-type-permutations/Makefile | 42 +++ .../run-make/output-type-permutations/foo.rs | 3 + src/test/run-make/prefer-dylib/Makefile | 2 +- src/test/run-make/prefer-rlib/Makefile | 2 +- src/test/run-make/simple-dylib/Makefile | 2 +- src/test/run-make/simple-rlib/Makefile | 2 +- .../run-make/volatile-intrinsics/Makefile | 2 +- 30 files changed, 415 insertions(+), 356 deletions(-) create mode 100644 src/test/run-make/output-type-permutations/Makefile create mode 100644 src/test/run-make/output-type-permutations/foo.rs diff --git a/man/rustc.1 b/man/rustc.1 index 885ec37f374..0f84c26df2b 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -12,17 +12,14 @@ This program is a compiler for the Rust language, available at .SH OPTIONS .TP -\fB\-\-bin\fR -Compile an executable crate (default) -.TP -\fB\-c\fR -Compile and assemble, but do not link +\fB\-\-crate-type=[bin|lib|dylib|rlib|staticlib]\fR +Configure the flavor of rust crate that is generated (default `bin`) .TP \fB\-\-cfg\fR SPEC Configure the compilation environment .TP -\fB\-\-emit\-llvm\fR -Produce an LLVM bitcode file +\fB\-\-emit=[asm,ir,bc,obj,link]\fR +Configure the output that rustc will produce .TP \fB\-h\fR, \fB\-\-help\fR Display this message @@ -30,9 +27,6 @@ Display this message \fB\-L\fR PATH Add a directory to the library search path .TP -\fB\-\-lib\fR -Compile a library crate -.TP \fB\-\-linker\fR LINKER Program to use for linking instead of the default .TP @@ -49,7 +43,7 @@ Run all passes except translation; no output Equivalent to \fI\-\-opt\-level=2\fR .TP \fB\-o\fR FILENAME -Write output to +Write output to . Ignored if more than one --emit is specified. .TP \fB\-\-opt\-level\fR LEVEL Optimize with possible levels 0-3 @@ -60,7 +54,8 @@ the default passes for the optimization level. A value of 'list' will list the available passes. .TP \fB\-\-out\-dir\fR DIR -Write output to compiler-chosen filename in +Write output to compiler-chosen filename in . Ignored if -o is specified. +(default the current directory) .TP \fB\-\-parse\-only\fR Parse only; do not compile, assemble, or link @@ -71,9 +66,6 @@ Pretty-print the input instead of compiling; valid types are: normal expanded, with type annotations), or identified (fully parenthesized, AST nodes and blocks with IDs) .TP -\fB\-S\fR -Compile only; do not assemble or link -.TP \fB\-\-save\-temps\fR Write intermediate files (.bc, .opt.bc, .o) in addition to normal output .TP @@ -120,7 +112,7 @@ To build an executable from a source file with a main function: $ rustc -o hello hello.rs To build a library from a source file: - $ rustc --lib hello-lib.rs + $ rustc --crate-type=lib hello-lib.rs To build either with a crate (.rs) file: $ rustc hello.rs diff --git a/mk/crates.mk b/mk/crates.mk index ea573b9db8d..652d7629bda 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -102,7 +102,7 @@ $(foreach crate,$(CRATES),$(eval $(call RUST_CRATE,$(crate)))) # # $(1) is the crate to generate variables for define RUST_TOOL -TOOL_INPUTS_$(1) := $$(wildcard $$(addprefix $(S)$$(dir $$(TOOL_SOURCE_$(1))), \ +TOOL_INPUTS_$(1) := $$(wildcard $$(addprefix $$(dir $$(TOOL_SOURCE_$(1))), \ *.rs */*.rs */*/*.rs */*/*/*.rs)) endef diff --git a/mk/tests.mk b/mk/tests.mk index 85c63acb0f1..f8898ee8d06 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -835,7 +835,7 @@ $$(TLIB2_T_$(2)_H_$(3))/$$(FT_LIB): \ tmp/$$(FT).rc \ $$(SREQ2_T_$(2)_H_$(3)) @$$(call E, compile_and_link: $$@) - $$(STAGE2_T_$(2)_H_$(3)) --lib -o $$@ $$< \ + $$(STAGE2_T_$(2)_H_$(3)) --crate-type=dylib --out-dir $$(@D) $$< \ -L "$$(RT_OUTPUT_DIR_$(2))" $(3)/test/$$(FT_DRIVER)-$(2)$$(X_$(2)): \ diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 0503790ae94..adb81803ab0 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -245,7 +245,7 @@ actual:\n\ }; // FIXME (#9639): This needs to handle non-utf8 paths let mut args = ~[~"-", - ~"--no-trans", ~"--lib", + ~"--no-trans", ~"--crate-type=lib", ~"--target=" + target, ~"-L", config.build_base.as_str().unwrap().to_owned(), ~"-L", @@ -659,7 +659,7 @@ fn compile_test_(config: &config, props: &TestProps, // FIXME (#9639): This needs to handle non-utf8 paths let link_args = ~[~"-L", aux_dir.as_str().unwrap().to_owned()]; let args = make_compile_args(config, props, link_args + extra_args, - make_exe_name, testfile); + |a, b| ThisFile(make_exe_name(a, b)), testfile); compose_and_run_compiler(config, props, testfile, args, None) } @@ -702,8 +702,12 @@ fn compose_and_run_compiler( let abs_ab = config.aux_base.join(rel_ab.as_slice()); let aux_props = load_props(&abs_ab); let aux_args = - make_compile_args(config, &aux_props, ~[~"--dylib"] + extra_link_args, - |a,b| make_lib_name(a, b, testfile), &abs_ab); + make_compile_args(config, &aux_props, ~[~"--crate-type=dylib"] + + extra_link_args, + |a,b| { + let f = make_lib_name(a, b, testfile); + ThisDirectory(f.dir_path()) + }, &abs_ab); let auxres = compose_and_run(config, &abs_ab, aux_args, ~[], config.compile_lib_path, None); if !auxres.status.success() { @@ -741,10 +745,15 @@ fn compose_and_run(config: &config, testfile: &Path, prog, args, procenv, input); } +enum TargetLocation { + ThisFile(Path), + ThisDirectory(Path), +} + fn make_compile_args(config: &config, props: &TestProps, extras: ~[~str], - xform: |&config, &Path| -> Path, + xform: |&config, &Path| -> TargetLocation, testfile: &Path) -> ProcArgs { let xform_file = xform(config, testfile); @@ -755,10 +764,14 @@ fn make_compile_args(config: &config, }; // FIXME (#9639): This needs to handle non-utf8 paths let mut args = ~[testfile.as_str().unwrap().to_owned(), - ~"-o", xform_file.as_str().unwrap().to_owned(), ~"-L", config.build_base.as_str().unwrap().to_owned(), ~"--target=" + target] + extras; + let path = match xform_file { + ThisFile(path) => { args.push(~"-o"); path } + ThisDirectory(path) => { args.push(~"--out-dir"); path } + }; + args.push(path.as_str().unwrap().to_owned()); args.push_all_move(split_maybe_args(&config.rustcflags)); args.push_all_move(split_maybe_args(&props.compile_flags)); return ProcArgs {prog: config.rustc_path.as_str().unwrap().to_owned(), args: args}; @@ -1043,10 +1056,10 @@ fn compile_test_and_save_bitcode(config: &config, props: &TestProps, let aux_dir = aux_output_dir_name(config, testfile); // FIXME (#9639): This needs to handle non-utf8 paths let link_args = ~[~"-L", aux_dir.as_str().unwrap().to_owned()]; - let llvm_args = ~[~"-c", ~"--lib", ~"--save-temps"]; + let llvm_args = ~[~"--emit=obj", ~"--crate-type=lib", ~"--save-temps"]; let args = make_compile_args(config, props, link_args + llvm_args, - make_o_name, testfile); + |a, b| ThisFile(make_o_name(a, b)), testfile); compose_and_run_compiler(config, props, testfile, args, None) } diff --git a/src/doc/rust.md b/src/doc/rust.md index c95bfee4ace..b412fa4967d 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -3678,43 +3678,43 @@ found in the [ffi tutorial][ffi]. In one session of compilation, the compiler can generate multiple artifacts through the usage of command line flags and the `crate_type` attribute. -* `--bin`, `#[crate_type = "bin"]` - A runnable executable will be produced. - This requires that there is a `main` function in the crate which will be run - when the program begins executing. This will link in all Rust and native - dependencies, producing a distributable binary. +* `--crate-type=bin`, `#[crate_type = "bin"]` - A runnable executable will be + produced. This requires that there is a `main` function in the crate which + will be run when the program begins executing. This will link in all Rust and + native dependencies, producing a distributable binary. -* `--lib`, `#[crate_type = "lib"]` - A Rust library will be produced. This is - an ambiguous concept as to what exactly is produced because a library can - manifest itself in several forms. The purpose of this generic `lib` option is - to generate the "compiler recommended" style of library. The output library - will always be usable by rustc, but the actual type of library may change - from time-to-time. The remaining output types are all different flavors of - libraries, and the `lib` type can be seen as an alias for one of them (but - the actual one is compiler-defined). +* `--crate-type=lib`, `#[crate_type = "lib"]` - A Rust library will be produced. + This is an ambiguous concept as to what exactly is produced because a library + can manifest itself in several forms. The purpose of this generic `lib` option + is to generate the "compiler recommended" style of library. The output library + will always be usable by rustc, but the actual type of library may change from + time-to-time. The remaining output types are all different flavors of + libraries, and the `lib` type can be seen as an alias for one of them (but the + actual one is compiler-defined). -* `--dylib`, `#[crate_type = "dylib"]` - A dynamic Rust library will be - produced. This is different from the `lib` output type in that this forces +* `--crate-type=dylib`, `#[crate_type = "dylib"]` - A dynamic Rust library will + be produced. This is different from the `lib` output type in that this forces dynamic library generation. The resulting dynamic library can be used as a dependency for other libraries and/or executables. This output type will create `*.so` files on linux, `*.dylib` files on osx, and `*.dll` files on windows. -* `--staticlib`, `#[crate_type = "staticlib"]` - A static system library will - be produced. This is different from other library outputs in that the Rust - compiler will never attempt to link to `staticlib` outputs. The purpose of - this output type is to create a static library containing all of the local - crate's code along with all upstream dependencies. The static library is - actually a `*.a` archive on linux and osx and a `*.lib` file on windows. This - format is recommended for use in situtations such as linking Rust code into an - existing non-Rust application because it will not have dynamic dependencies on - other Rust code. +* `--crate-type=staticlib`, `#[crate_type = "staticlib"]` - A static system + library will be produced. This is different from other library outputs in that + the Rust compiler will never attempt to link to `staticlib` outputs. The + purpose of this output type is to create a static library containing all of + the local crate's code along with all upstream dependencies. The static + library is actually a `*.a` archive on linux and osx and a `*.lib` file on + windows. This format is recommended for use in situtations such as linking + Rust code into an existing non-Rust application because it will not have + dynamic dependencies on other Rust code. -* `--rlib`, `#[crate_type = "rlib"]` - A "Rust library" file will be produced. - This is used as an intermediate artifact and can be thought of as a "static - Rust library". These `rlib` files, unlike `staticlib` files, are interpreted - by the Rust compiler in future linkage. This essentially means that `rustc` - will look for metadata in `rlib` files like it looks for metadata in dynamic - libraries. This form of output is used to produce statically linked +* `--crate-type=rlib`, `#[crate_type = "rlib"]` - A "Rust library" file will be + produced. This is used as an intermediate artifact and can be thought of as a + "static Rust library". These `rlib` files, unlike `staticlib` files, are + interpreted by the Rust compiler in future linkage. This essentially means + that `rustc` will look for metadata in `rlib` files like it looks for metadata + in dynamic libraries. This form of output is used to produce statically linked executables as well as `staticlib` outputs. Note that these outputs are stackable in the sense that if multiple are @@ -3769,9 +3769,9 @@ dependencies will be used: then the compiler will force all dependencies to be dynamic and will generate errors if dynamic versions could not be found. -In general, `--bin` or `--lib` should be sufficient for all compilation needs, -and the other options are just available if more fine-grained control is desired -over the output format of a Rust crate. +In general, `--crate-type=bin` or `--crate-type=lib` should be sufficient for +all compilation needs, and the other options are just available if more +fine-grained control is desired over the output format of a Rust crate. ### Logging system diff --git a/src/doc/tutorial.md b/src/doc/tutorial.md index 75a5840a1ef..7010eb4e48d 100644 --- a/src/doc/tutorial.md +++ b/src/doc/tutorial.md @@ -3162,8 +3162,8 @@ fn main() { println!("hello {}", world::explore()); } Now compile and run like this (adjust to your platform if necessary): ~~~~ {.notrust} -> rustc --lib world.rs # compiles libworld--0.42.so -> rustc main.rs -L . # compiles main +> rustc --crate-type=lib world.rs # compiles libworld--0.42.so +> rustc main.rs -L . # compiles main > ./main "hello world" ~~~~ diff --git a/src/etc/zsh/_rust b/src/etc/zsh/_rust index 03a8712283c..f1f9e88f7c9 100644 --- a/src/etc/zsh/_rust +++ b/src/etc/zsh/_rust @@ -7,18 +7,15 @@ typeset -A opt_args _rustc_opts_switches=( --android-cross-path'[The path to the Android NDK]' --ar'[Program to use for managing archives instead of the default.]' - --bin'[Compile an executable crate (default)]' -c'[Compile and assemble, but do not link]' --cfg'[Configure the compilation environment]' --crate-id'[Output the crate id and exit]' --crate-file-name'[Output the file(s) that would be written if compilation continued and exit]' --crate-name'[Output the crate name and exit]' --dep-info'[Output dependency info to after compiling]' - --dylib'[Compile a dynamic library crate]' - --emit-llvm'[Produce an LLVM bitcode file]' + --crate-type'[Specify the type of crate to crate]' {-h,--help}'[Display this message]' -L'[Add a directory to the library search path]' - --lib'[Compile a library crate]' --linker'[Program to use for linking instead of the default.]' --link-args'[FLAGS is a space-separated list of flags passed to the linker]' --llvm-args'[A list of arguments to pass to llvm, comma separated]' @@ -33,10 +30,7 @@ _rustc_opts_switches=( --parse-only'[Parse only; do not compile, assemble, or link]' --passes'[Comma or space separated list of pass names to use]' --pretty'[Pretty-print the input instead of compiling]' - --rlib'[Compile a rust library crate as an rlib file]' - -S'[Compile only; do not assemble or link]' --save-temps'[Write intermediate files (.bc, .opt.bc, .o) in addition to normal output]' - --staticlib'[Compile a static library crate]' --sysroot'[Override the system root]' --test'[Build a test harness]' --target'[Target triple cpu-manufacturer-kernel\[-os\] to compile]' diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index aea9b65087d..62fdff49168 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -11,7 +11,7 @@ use back::archive::{Archive, METADATA_FILENAME}; use back::rpath; -use driver::driver::CrateTranslation; +use driver::driver::{CrateTranslation, OutputFilenames}; use driver::session::Session; use driver::session; use lib::llvm::llvm; @@ -44,9 +44,8 @@ use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::crateid::CrateId; -#[deriving(Clone, Eq)] +#[deriving(Clone, Eq, TotalOrd, TotalEq)] pub enum OutputType { - OutputTypeNone, OutputTypeBitcode, OutputTypeAssembly, OutputTypeLlvmAssembly, @@ -90,7 +89,7 @@ pub mod write { use back::link::{OutputTypeAssembly, OutputTypeBitcode}; use back::link::{OutputTypeExe, OutputTypeLlvmAssembly}; use back::link::{OutputTypeObject}; - use driver::driver::CrateTranslation; + use driver::driver::{CrateTranslation, OutputFilenames}; use driver::session::Session; use driver::session; use lib::llvm::llvm; @@ -101,7 +100,6 @@ pub mod write { use std::c_str::ToCStr; use std::libc::{c_uint, c_int}; - use std::path::Path; use std::run; use std::str; @@ -125,8 +123,8 @@ pub mod write { pub fn run_passes(sess: Session, trans: &CrateTranslation, - output_type: OutputType, - output: &Path) { + output_types: &[OutputType], + output: &OutputFilenames) { let llmod = trans.module; let llcx = trans.context; unsafe { @@ -209,10 +207,11 @@ pub mod write { // Emit the bytecode if we're either saving our temporaries or // emitting an rlib. Whenever an rlib is created, the bytecode is // inserted into the archive in order to allow LTO against it. - let outputs = sess.outputs.borrow(); + let crate_types = sess.crate_types.borrow(); if sess.opts.save_temps || - outputs.get().iter().any(|&o| o == session::OutputRlib) { - output.with_extension("bc").with_c_str(|buf| { + (crate_types.get().contains(&session::CrateTypeRlib) && + sess.opts.output_types.contains(&OutputTypeExe)) { + output.temp_path(OutputTypeBitcode).with_c_str(|buf| { llvm::LLVMWriteBitcodeToFile(llmod, buf); }) } @@ -247,52 +246,68 @@ pub mod write { } } - time(sess.time_passes(), "codegen passes", (), |()| { - match output_type { - OutputTypeNone => {} + let mut object_file = None; + let mut needs_metadata = false; + for output_type in output_types.iter() { + let path = output.path(*output_type); + match *output_type { OutputTypeBitcode => { - output.with_c_str(|buf| { + path.with_c_str(|buf| { llvm::LLVMWriteBitcodeToFile(llmod, buf); }) } OutputTypeLlvmAssembly => { - output.with_c_str(|output| { + path.with_c_str(|output| { with_codegen(tm, llmod, |cpm| { llvm::LLVMRustPrintModule(cpm, llmod, output); }) }) } OutputTypeAssembly => { - with_codegen(tm, llmod, |cpm| { - WriteOutputFile(sess, tm, cpm, llmod, output, - lib::llvm::AssemblyFile); - }); - // If we're not using the LLVM assembler, this function // could be invoked specially with output_type_assembly, // so in this case we still want the metadata object // file. - if sess.opts.output_type != OutputTypeAssembly { - with_codegen(tm, trans.metadata_module, |cpm| { - let out = output.with_extension("metadata.o"); - WriteOutputFile(sess, tm, cpm, - trans.metadata_module, &out, - lib::llvm::ObjectFile); - }) - } - } - OutputTypeExe | OutputTypeObject => { + let ty = OutputTypeAssembly; + let path = if sess.opts.output_types.contains(&ty) { + path + } else { + needs_metadata = true; + output.temp_path(OutputTypeAssembly) + }; with_codegen(tm, llmod, |cpm| { - WriteOutputFile(sess, tm, cpm, llmod, output, + WriteOutputFile(sess, tm, cpm, llmod, &path, + lib::llvm::AssemblyFile); + }); + } + OutputTypeObject => { + object_file = Some(path); + } + OutputTypeExe => { + object_file = Some(output.temp_path(OutputTypeObject)); + needs_metadata = true; + } + } + } + + time(sess.time_passes(), "codegen passes", (), |()| { + match object_file { + Some(ref path) => { + with_codegen(tm, llmod, |cpm| { + WriteOutputFile(sess, tm, cpm, llmod, path, lib::llvm::ObjectFile); }); - with_codegen(tm, trans.metadata_module, |cpm| { - let out = output.with_extension("metadata.o"); - WriteOutputFile(sess, tm, cpm, - trans.metadata_module, &out, - lib::llvm::ObjectFile); - }) } + None => {} + } + if needs_metadata { + with_codegen(tm, trans.metadata_module, |cpm| { + let out = output.temp_path(OutputTypeObject) + .with_extension("metadata.o"); + WriteOutputFile(sess, tm, cpm, + trans.metadata_module, &out, + lib::llvm::ObjectFile); + }) } }); @@ -304,8 +319,10 @@ pub mod write { } } - pub fn run_assembler(sess: Session, assembly: &Path, object: &Path) { + pub fn run_assembler(sess: Session, outputs: &OutputFilenames) { let cc = super::get_cc_prog(sess); + let assembly = outputs.temp_path(OutputTypeAssembly); + let object = outputs.path(OutputTypeObject); // FIXME (#9639): This needs to handle non-utf8 paths let args = [ @@ -480,9 +497,8 @@ pub mod write { * system linkers understand. */ -pub fn build_link_meta(sess: Session, - attrs: &[ast::Attribute], - output: &Path, +pub fn build_link_meta(attrs: &[ast::Attribute], + output: &OutputFilenames, symbol_hasher: &mut Sha256) -> LinkMeta { // This calculates CMH as defined above @@ -493,14 +509,7 @@ pub fn build_link_meta(sess: Session, } let crateid = match attr::find_crateid(attrs) { - None => { - let stem = session::expect( - sess, - output.filestem_str(), - || format!("output file name '{}' doesn't appear to have a stem", - output.display())); - from_str(stem).unwrap() - } + None => from_str(output.out_filestem).unwrap(), Some(s) => s, }; @@ -794,20 +803,21 @@ fn remove(sess: Session, path: &Path) { /// of the requested outputs for this compilation session. pub fn link_binary(sess: Session, trans: &CrateTranslation, - obj_filename: &Path, - out_filename: &Path, + outputs: &OutputFilenames, lm: &LinkMeta) -> ~[Path] { let mut out_filenames = ~[]; - let outputs = sess.outputs.borrow(); - for &output in outputs.get().iter() { - let out_file = link_binary_output(sess, trans, output, obj_filename, - out_filename, lm); + let crate_types = sess.crate_types.borrow(); + for &crate_type in crate_types.get().iter() { + let out_file = link_binary_output(sess, trans, crate_type, outputs, lm); out_filenames.push(out_file); } // Remove the temporary object file and metadata if we aren't saving temps if !sess.opts.save_temps { - remove(sess, obj_filename); + let obj_filename = outputs.temp_path(OutputTypeObject); + if !sess.opts.output_types.contains(&OutputTypeObject) { + remove(sess, &obj_filename); + } remove(sess, &obj_filename.with_extension("metadata.o")); } @@ -821,14 +831,14 @@ fn is_writeable(p: &Path) -> bool { } } -pub fn filename_for_input(sess: &Session, output: session::OutputStyle, lm: &LinkMeta, - out_filename: &Path) -> Path { +pub fn filename_for_input(sess: &Session, crate_type: session::CrateType, + lm: &LinkMeta, out_filename: &Path) -> Path { let libname = output_lib_filename(lm); - match output { - session::OutputRlib => { + match crate_type { + session::CrateTypeRlib => { out_filename.with_filename(format!("lib{}.rlib", libname)) } - session::OutputDylib => { + session::CrateTypeDylib => { let (prefix, suffix) = match sess.targ_cfg.os { abi::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX), abi::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX), @@ -838,27 +848,32 @@ pub fn filename_for_input(sess: &Session, output: session::OutputStyle, lm: &Lin }; out_filename.with_filename(format!("{}{}{}", prefix, libname, suffix)) } - session::OutputStaticlib => { + session::CrateTypeStaticlib => { out_filename.with_filename(format!("lib{}.a", libname)) } - session::OutputExecutable => out_filename.clone(), + session::CrateTypeExecutable => out_filename.clone(), } - } fn link_binary_output(sess: Session, trans: &CrateTranslation, - output: session::OutputStyle, - obj_filename: &Path, - out_filename: &Path, + crate_type: session::CrateType, + outputs: &OutputFilenames, lm: &LinkMeta) -> Path { - let out_filename = filename_for_input(&sess, output, lm, out_filename); + let obj_filename = outputs.temp_path(OutputTypeObject); + let out_filename = match outputs.single_output_file { + Some(ref file) => file.clone(), + None => { + let out_filename = outputs.path(OutputTypeExe); + filename_for_input(&sess, crate_type, lm, &out_filename) + } + }; // Make sure the output and obj_filename are both writeable. // Mac, FreeBSD, and Windows system linkers check this already -- // however, the Linux linker will happily overwrite a read-only file. // We should be consistent. - let obj_is_writeable = is_writeable(obj_filename); + let obj_is_writeable = is_writeable(&obj_filename); let out_is_writeable = is_writeable(&out_filename); if !out_is_writeable { sess.fatal(format!("Output file {} is not writeable -- check its permissions.", @@ -869,18 +884,18 @@ fn link_binary_output(sess: Session, obj_filename.display())); } - match output { - session::OutputRlib => { - link_rlib(sess, Some(trans), obj_filename, &out_filename); + match crate_type { + session::CrateTypeRlib => { + link_rlib(sess, Some(trans), &obj_filename, &out_filename); } - session::OutputStaticlib => { - link_staticlib(sess, obj_filename, &out_filename); + session::CrateTypeStaticlib => { + link_staticlib(sess, &obj_filename, &out_filename); } - session::OutputExecutable => { - link_natively(sess, false, obj_filename, &out_filename); + session::CrateTypeExecutable => { + link_natively(sess, false, &obj_filename, &out_filename); } - session::OutputDylib => { - link_natively(sess, true, obj_filename, &out_filename); + session::CrateTypeDylib => { + link_natively(sess, true, &obj_filename, &out_filename); } } @@ -954,7 +969,8 @@ fn link_rlib(sess: Session, // into the archive. let bc = obj_filename.with_extension("bc"); a.add_file(&bc, false); - if !sess.opts.save_temps { + if !sess.opts.save_temps && + !sess.opts.output_types.contains(&OutputTypeBitcode) { remove(sess, &bc); } diff --git a/src/librustc/back/lto.rs b/src/librustc/back/lto.rs index 3fbcd377b8b..3c7d804435f 100644 --- a/src/librustc/back/lto.rs +++ b/src/librustc/back/lto.rs @@ -26,10 +26,10 @@ pub fn run(sess: session::Session, llmod: ModuleRef, } // Make sure we actually can run LTO - let outputs = sess.outputs.borrow(); - for output in outputs.get().iter() { - match *output { - session::OutputExecutable | session::OutputStaticlib => {} + let crate_types = sess.crate_types.borrow(); + for crate_type in crate_types.get().iter() { + match *crate_type { + session::CrateTypeExecutable | session::CrateTypeStaticlib => {} _ => { sess.fatal("lto can only be run for executables and \ static library outputs"); diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index c3b851b76ac..9d03fbb6061 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -11,7 +11,7 @@ use back::link; use back::{arm, x86, x86_64, mips}; -use driver::session::{Aggressive, OutputExecutable}; +use driver::session::{Aggressive, CrateTypeExecutable}; use driver::session::{Session, Session_, No, Less, Default}; use driver::session; use front; @@ -182,7 +182,7 @@ pub fn phase_2_configure_and_expand(sess: Session, let time_passes = sess.time_passes(); sess.building_library.set(session::building_library(sess.opts, &crate)); - sess.outputs.set(session::collect_outputs(&sess, crate.attrs)); + sess.crate_types.set(session::collect_crate_types(&sess, crate.attrs)); time(time_passes, "gated feature checking", (), |_| front::feature_gate::check_crate(sess, &crate)); @@ -373,8 +373,7 @@ pub fn phase_4_translate_to_llvm(sess: Session, analysis: &CrateAnalysis, outputs: &OutputFilenames) -> CrateTranslation { time(sess.time_passes(), "translation", crate, |crate| - trans::base::trans_crate(sess, crate, analysis, - &outputs.obj_filename)) + trans::base::trans_crate(sess, crate, analysis, outputs)) } /// Run LLVM itself, producing a bitcode file, assembly file or object file @@ -382,29 +381,24 @@ pub fn phase_4_translate_to_llvm(sess: Session, pub fn phase_5_run_llvm_passes(sess: Session, trans: &CrateTranslation, outputs: &OutputFilenames) { - if sess.no_integrated_as() { let output_type = link::OutputTypeAssembly; - let asm_filename = outputs.obj_filename.with_extension("s"); time(sess.time_passes(), "LLVM passes", (), |_| - link::write::run_passes(sess, - trans, - output_type, - &asm_filename)); + link::write::run_passes(sess, trans, [output_type], outputs)); - link::write::run_assembler(sess, &asm_filename, &outputs.obj_filename); + link::write::run_assembler(sess, outputs); // Remove assembly source, unless --save-temps was specified if !sess.opts.save_temps { - fs::unlink(&asm_filename).unwrap(); + fs::unlink(&outputs.temp_path(link::OutputTypeAssembly)).unwrap(); } } else { time(sess.time_passes(), "LLVM passes", (), |_| link::write::run_passes(sess, trans, - sess.opts.output_type, - &outputs.obj_filename)); + sess.opts.output_types, + outputs)); } } @@ -416,8 +410,7 @@ pub fn phase_6_link_output(sess: Session, time(sess.time_passes(), "linking", (), |_| link::link_binary(sess, trans, - &outputs.obj_filename, - &outputs.out_filename, + outputs, &trans.link)); } @@ -446,24 +439,34 @@ pub fn stop_after_phase_2(sess: Session) -> bool { } pub fn stop_after_phase_5(sess: Session) -> bool { - if sess.opts.output_type != link::OutputTypeExe { + if !sess.opts.output_types.iter().any(|&i| i == link::OutputTypeExe) { debug!("not building executable, returning early from compile_input"); return true; } return false; } -fn write_out_deps(sess: Session, input: &Input, outputs: &OutputFilenames, - crate: &ast::Crate) -> io::IoResult<()> -{ - let lm = link::build_link_meta(sess, crate.attrs, &outputs.obj_filename, +fn write_out_deps(sess: Session, + input: &Input, + outputs: &OutputFilenames, + crate: &ast::Crate) -> io::IoResult<()> { + let lm = link::build_link_meta(crate.attrs, outputs, &mut ::util::sha2::Sha256::new()); - let sess_outputs = sess.outputs.borrow(); - let out_filenames = sess_outputs.get().iter() - .map(|&output| link::filename_for_input(&sess, output, &lm, - &outputs.out_filename)) - .to_owned_vec(); + let mut out_filenames = ~[]; + for output_type in sess.opts.output_types.iter() { + let file = outputs.path(*output_type); + match *output_type { + link::OutputTypeExe => { + let crate_types = sess.crate_types.borrow(); + for output in crate_types.get().iter() { + let p = link::filename_for_input(&sess, *output, &lm, &file); + out_filenames.push(p); + } + } + _ => { out_filenames.push(file); } + } + } // Write out dependency rules to the dep-info file if requested with // --dep-info @@ -473,12 +476,7 @@ fn write_out_deps(sess: Session, input: &Input, outputs: &OutputFilenames, // Use default filename: crate source filename with extension replaced // by ".d" (true, None) => match *input { - FileInput(ref input_path) => { - let filestem = input_path.filestem().expect("input file must \ - have stem"); - let filename = out_filenames[0].dir_path().join(filestem); - filename.with_extension("d") - }, + FileInput(..) => outputs.with_extension("d"), StrInput(..) => { sess.warn("can not write --dep-info without a filename \ when compiling stdin."); @@ -526,19 +524,19 @@ pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &Input, let outputs = build_output_filenames(input, outdir, output, expanded_crate.attrs, sess); - write_out_deps(sess, input, outputs, &expanded_crate).unwrap(); + write_out_deps(sess, input, &outputs, &expanded_crate).unwrap(); if stop_after_phase_2(sess) { return; } let analysis = phase_3_run_analysis_passes(sess, &expanded_crate, ast_map); if stop_after_phase_3(sess) { return; } let trans = phase_4_translate_to_llvm(sess, expanded_crate, - &analysis, outputs); + &analysis, &outputs); (outputs, trans) }; - phase_5_run_llvm_passes(sess, &trans, outputs); + phase_5_run_llvm_passes(sess, &trans, &outputs); if stop_after_phase_5(sess) { return; } - phase_6_link_output(sess, &trans, outputs); + phase_6_link_output(sess, &trans, &outputs); } struct IdentifiedAnnotation { @@ -735,22 +733,19 @@ pub fn build_session_options(binary: ~str, matches: &getopts::Matches, demitter: @diagnostic::Emitter) -> @session::Options { - let mut outputs = ~[]; - if matches.opt_present("lib") { - outputs.push(session::default_lib_output()); - } - if matches.opt_present("rlib") { - outputs.push(session::OutputRlib) - } - if matches.opt_present("staticlib") { - outputs.push(session::OutputStaticlib) - } - if matches.opt_present("dylib") { - outputs.push(session::OutputDylib) - } - if matches.opt_present("bin") { - outputs.push(session::OutputExecutable) - } + let crate_types = matches.opt_strs("crate-type").flat_map(|s| { + s.split(',').map(|part| { + match part { + "lib" => session::default_lib_output(), + "rlib" => session::CrateTypeRlib, + "staticlib" => session::CrateTypeStaticlib, + "dylib" => session::CrateTypeDylib, + "bin" => session::CrateTypeExecutable, + _ => early_error(demitter, + format!("unknown crate type: `{}`", part)) + } + }).collect() + }); let parse_only = matches.opt_present("parse-only"); let no_trans = matches.opt_present("no-trans"); @@ -801,19 +796,30 @@ pub fn build_session_options(binary: ~str, unsafe { llvm::LLVMSetDebug(1); } } - let output_type = - if parse_only || no_trans { - link::OutputTypeNone - } else if matches.opt_present("S") && - matches.opt_present("emit-llvm") { - link::OutputTypeLlvmAssembly - } else if matches.opt_present("S") { - link::OutputTypeAssembly - } else if matches.opt_present("c") { - link::OutputTypeObject - } else if matches.opt_present("emit-llvm") { - link::OutputTypeBitcode - } else { link::OutputTypeExe }; + let mut output_types = if parse_only || no_trans { + ~[] + } else { + matches.opt_strs("emit").flat_map(|s| { + s.split(',').map(|part| { + match part.as_slice() { + "asm" => link::OutputTypeAssembly, + "ir" => link::OutputTypeLlvmAssembly, + "bc" => link::OutputTypeBitcode, + "obj" => link::OutputTypeObject, + "link" => link::OutputTypeExe, + _ => early_error(demitter, + format!("unknown emission type: `{}`", + part)) + } + }).collect() + }) + }; + output_types.sort(); + output_types.dedup(); + if output_types.len() == 0 { + output_types.push(link::OutputTypeExe); + } + let sysroot_opt = matches.opt_str("sysroot").map(|m| @Path::new(m)); let target = matches.opt_str("target").unwrap_or(host_triple()); let target_cpu = matches.opt_str("target-cpu").unwrap_or(~"generic"); @@ -886,7 +892,7 @@ pub fn build_session_options(binary: ~str, matches.opt_present("crate-file-name")); let sopts = @session::Options { - outputs: outputs, + crate_types: crate_types, gc: gc, optimize: opt_level, custom_passes: custom_passes, @@ -895,7 +901,7 @@ pub fn build_session_options(binary: ~str, extra_debuginfo: extra_debuginfo, lint_opts: lint_opts, save_temps: save_temps, - output_type: output_type, + output_types: output_types, addl_lib_search_paths: @RefCell::new(addl_lib_search_paths), ar: ar, linker: linker, @@ -972,7 +978,7 @@ pub fn build_session_(sopts: @session::Options, working_dir: os::getcwd(), lints: RefCell::new(HashMap::new()), node_id: Cell::new(1), - outputs: @RefCell::new(~[]), + crate_types: @RefCell::new(~[]), } } @@ -994,20 +1000,15 @@ pub fn parse_pretty(sess: Session, name: &str) -> PpMode { // rustc command line options pub fn optgroups() -> ~[getopts::groups::OptGroup] { ~[ - optflag("c", "", "Compile and assemble, but do not link"), - optmulti("", "cfg", "Configure the compilation - environment", "SPEC"), - optflag("", "emit-llvm", - "Produce an LLVM assembly file if used with -S option; - produce an LLVM bitcode file otherwise"), - optflag("h", "help","Display this message"), - optmulti("L", "", "Add a directory to the library search path", - "PATH"), - optflag("", "bin", "Compile an executable crate (default)"), - optflag("", "lib", "Compile a rust library crate using the compiler's default"), - optflag("", "rlib", "Compile a rust library crate as an rlib file"), - optflag("", "staticlib", "Compile a static library crate"), - optflag("", "dylib", "Compile a dynamic library crate"), + optflag("h", "help", "Display this message"), + optmulti("", "cfg", "Configure the compilation environment", "SPEC"), + optmulti("L", "", "Add a directory to the library search path", "PATH"), + optmulti("", "crate-type", "Comma separated list of types of crates for the \ + compiler to emit", + "[bin|lib|rlib|dylib|staticlib]"), + optmulti("", "emit", "Comma separated list of types of output for the compiler + to emit", + "[asm|bc|ir|obj|link]"), optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"), optopt("", "ar", "Program to use for managing archives instead of the default.", "AR"), optflag("", "crate-id", "Output the crate id and exit"), @@ -1045,7 +1046,6 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] { typed (crates expanded, with type annotations), or identified (fully parenthesized, AST nodes and blocks with IDs)", "TYPE"), - optflag("S", "", "Compile only; do not assemble or link"), optflagopt("", "dep-info", "Output dependency info to after compiling", "FILENAME"), optflag("", "save-temps", @@ -1081,8 +1081,35 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] { } pub struct OutputFilenames { - out_filename: Path, - obj_filename: Path + out_directory: Path, + out_filestem: ~str, + single_output_file: Option, +} + +impl OutputFilenames { + pub fn path(&self, flavor: link::OutputType) -> Path { + match self.single_output_file { + Some(ref path) => return path.clone(), + None => {} + } + self.temp_path(flavor) + } + + pub fn temp_path(&self, flavor: link::OutputType) -> Path { + let base = self.out_directory.join(self.out_filestem.as_slice()); + match flavor { + link::OutputTypeBitcode => base.with_extension("bc"), + link::OutputTypeAssembly => base.with_extension("s"), + link::OutputTypeLlvmAssembly => base.with_extension("ll"), + link::OutputTypeObject => base.with_extension("o"), + link::OutputTypeExe => base, + } + } + + pub fn with_extension(&self, extension: &str) -> Path { + let stem = self.out_filestem.as_slice(); + self.out_directory.join(stem).with_extension(extension) + } } pub fn build_output_filenames(input: &Input, @@ -1090,83 +1117,53 @@ pub fn build_output_filenames(input: &Input, ofile: &Option, attrs: &[ast::Attribute], sess: Session) - -> ~OutputFilenames { - let obj_path; - let out_path; - let sopts = sess.opts; - let stop_after_codegen = sopts.output_type != link::OutputTypeExe; - - let obj_suffix = match sopts.output_type { - link::OutputTypeNone => ~"none", - link::OutputTypeBitcode => ~"bc", - link::OutputTypeAssembly => ~"s", - link::OutputTypeLlvmAssembly => ~"ll", - // Object and exe output both use the '.o' extension here - link::OutputTypeObject | link::OutputTypeExe => ~"o" - }; - + -> OutputFilenames { match *ofile { - None => { - // "-" as input file will cause the parser to read from stdin so we - // have to make up a name - // We want to toss everything after the final '.' - let dirpath = match *odir { - Some(ref d) => (*d).clone(), - None => match *input { - StrInput(_) => os::getcwd(), - FileInput(ref ifile) => (*ifile).dir_path() - } - }; + None => { + // "-" as input file will cause the parser to read from stdin so we + // have to make up a name + // We want to toss everything after the final '.' + let dirpath = match *odir { + Some(ref d) => d.clone(), + None => os::getcwd(), + }; - let mut stem = match *input { - // FIXME (#9639): This needs to handle non-utf8 paths - FileInput(ref ifile) => { - (*ifile).filestem_str().unwrap().to_str() - } - StrInput(_) => ~"rust_out" - }; + let mut stem = match *input { + // FIXME (#9639): This needs to handle non-utf8 paths + FileInput(ref ifile) => ifile.filestem_str().unwrap().to_str(), + StrInput(_) => ~"rust_out" + }; - // If a crateid is present, we use it as the link name - let crateid = attr::find_crateid(attrs); - match crateid { - None => {} - Some(crateid) => stem = crateid.name.to_str(), - } - - if sess.building_library.get() { - out_path = dirpath.join(os::dll_filename(stem)); - obj_path = { - let mut p = dirpath.join(stem); - p.set_extension(obj_suffix); - p - }; - } else { - out_path = dirpath.join(stem); - obj_path = out_path.with_extension(obj_suffix); - } - } - - Some(ref out_file) => { - out_path = out_file.clone(); - obj_path = if stop_after_codegen { - out_file.clone() - } else { - out_file.with_extension(obj_suffix) - }; - - if sess.building_library.get() { - sess.warn("ignoring specified output filename for library."); + // If a crateid is present, we use it as the link name + let crateid = attr::find_crateid(attrs); + match crateid { + None => {} + Some(crateid) => stem = crateid.name.to_str(), + } + OutputFilenames { + out_directory: dirpath, + out_filestem: stem, + single_output_file: None, + } } - if *odir != None { - sess.warn("ignoring --out-dir flag due to -o flag."); + Some(ref out_file) => { + let ofile = if sess.opts.output_types.len() > 1 { + sess.warn("ignoring specified output filename because multiple \ + outputs were requested"); + None + } else { + Some(out_file.clone()) + }; + if *odir != None { + sess.warn("ignoring --out-dir flag due to -o flag."); + } + OutputFilenames { + out_directory: out_file.dir_path(), + out_filestem: out_file.filestem_str().unwrap().to_str(), + single_output_file: ofile, + } } - } - } - - ~OutputFilenames { - out_filename: out_path, - obj_filename: obj_path } } diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 4ef97e9234a..859d09b5962 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -9,7 +9,6 @@ // except according to those terms. -use back::link; use back::target_strs; use back; use driver::driver::host_triple; @@ -139,7 +138,7 @@ pub enum OptLevel { pub struct Options { // The crate config requested for the session, which may be combined // with additional crate configurations during the compile process - outputs: ~[OutputStyle], + crate_types: ~[CrateType], gc: bool, optimize: OptLevel, @@ -149,7 +148,7 @@ pub struct Options { extra_debuginfo: bool, lint_opts: ~[(lint::Lint, lint::level)], save_temps: bool, - output_type: back::link::OutputType, + output_types: ~[back::link::OutputType], // This was mutable for rustpkg, which updates search paths based on the // parsed code. It remains mutable in case its replacements wants to use // this. @@ -192,11 +191,11 @@ pub enum EntryFnType { } #[deriving(Eq, Clone, TotalOrd, TotalEq)] -pub enum OutputStyle { - OutputExecutable, - OutputDylib, - OutputRlib, - OutputStaticlib, +pub enum CrateType { + CrateTypeExecutable, + CrateTypeDylib, + CrateTypeRlib, + CrateTypeStaticlib, } pub struct Session_ { @@ -219,7 +218,7 @@ pub struct Session_ { lints: RefCell>, node_id: Cell, - outputs: @RefCell<~[OutputStyle]>, + crate_types: @RefCell<~[CrateType]>, } pub type Session = @Session_; @@ -374,7 +373,7 @@ impl Session_ { /// Some reasonable defaults pub fn basic_options() -> @Options { @Options { - outputs: ~[], + crate_types: ~[], gc: false, optimize: No, custom_passes: ~[], @@ -383,7 +382,7 @@ pub fn basic_options() -> @Options { extra_debuginfo: false, lint_opts: ~[], save_temps: false, - output_type: link::OutputTypeExe, + output_types: ~[], addl_lib_search_paths: @RefCell::new(HashSet::new()), ar: None, linker: None, @@ -413,10 +412,10 @@ pub fn expect(sess: Session, opt: Option, msg: || -> ~str) -> T { pub fn building_library(options: &Options, crate: &ast::Crate) -> bool { if options.test { return false } - for output in options.outputs.iter() { + for output in options.crate_types.iter() { match *output { - OutputExecutable => {} - OutputStaticlib | OutputDylib | OutputRlib => return true + CrateTypeExecutable => {} + CrateTypeStaticlib | CrateTypeDylib | CrateTypeRlib => return true } } match syntax::attr::first_attr_value_str_by_name(crate.attrs, "crate_type") { @@ -430,30 +429,30 @@ pub fn building_library(options: &Options, crate: &ast::Crate) -> bool { } } -pub fn default_lib_output() -> OutputStyle { - OutputRlib +pub fn default_lib_output() -> CrateType { + CrateTypeRlib } -pub fn collect_outputs(session: &Session, - attrs: &[ast::Attribute]) -> ~[OutputStyle] { +pub fn collect_crate_types(session: &Session, + attrs: &[ast::Attribute]) -> ~[CrateType] { // If we're generating a test executable, then ignore all other output // styles at all other locations if session.opts.test { - return ~[OutputExecutable]; + return ~[CrateTypeExecutable]; } - let mut base = session.opts.outputs.clone(); + let mut base = session.opts.crate_types.clone(); let mut iter = attrs.iter().filter_map(|a| { if a.name().equiv(&("crate_type")) { match a.value_str() { - Some(ref n) if n.equiv(&("rlib")) => Some(OutputRlib), - Some(ref n) if n.equiv(&("dylib")) => Some(OutputDylib), + Some(ref n) if n.equiv(&("rlib")) => Some(CrateTypeRlib), + Some(ref n) if n.equiv(&("dylib")) => Some(CrateTypeDylib), Some(ref n) if n.equiv(&("lib")) => { Some(default_lib_output()) } Some(ref n) if n.equiv(&("staticlib")) => { - Some(OutputStaticlib) + Some(CrateTypeStaticlib) } - Some(ref n) if n.equiv(&("bin")) => Some(OutputExecutable), + Some(ref n) if n.equiv(&("bin")) => Some(CrateTypeExecutable), Some(_) => { session.add_lint(lint::UnknownCrateType, ast::CRATE_NODE_ID, @@ -473,7 +472,7 @@ pub fn collect_outputs(session: &Session, }); base.extend(&mut iter); if base.len() == 0 { - base.push(OutputExecutable); + base.push(CrateTypeExecutable); } base.sort(); base.dedup(); diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 52ddc8c8108..13b38d2e2bc 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -302,12 +302,12 @@ pub fn run_compiler(args: &[~str], demitter: @diagnostic::Emitter) { } if crate_file_name { - let lm = link::build_link_meta(sess, attrs, &t_outputs.obj_filename, + let lm = link::build_link_meta(attrs, &t_outputs, &mut ::util::sha2::Sha256::new()); - let outputs = session::collect_outputs(&sess, attrs); - for &style in outputs.iter() { + let crate_types = session::collect_crate_types(&sess, attrs); + for &style in crate_types.iter() { let fname = link::filename_for_input(&sess, style, &lm, - &t_outputs.out_filename); + &t_outputs.with_extension("")); println!("{}", fname.filename_display()); } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 5b4a9617612..485daf3d387 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -28,6 +28,7 @@ use back::link::{mangle_exported_name}; use back::{link, abi}; use driver::session; use driver::session::Session; +use driver::driver::OutputFilenames; use driver::driver::{CrateAnalysis, CrateTranslation}; use lib::llvm::{ModuleRef, ValueRef, BasicBlockRef}; use lib::llvm::{llvm, True, Vector}; @@ -2657,7 +2658,7 @@ pub fn write_metadata(cx: &CrateContext, crate: &ast::Crate) -> ~[u8] { pub fn trans_crate(sess: session::Session, crate: ast::Crate, analysis: &CrateAnalysis, - output: &Path) -> CrateTranslation { + output: &OutputFilenames) -> CrateTranslation { // Before we touch LLVM, make sure that multithreading is enabled. unsafe { use sync::one::{Once, ONCE_INIT}; @@ -2677,7 +2678,7 @@ pub fn trans_crate(sess: session::Session, } let mut symbol_hasher = Sha256::new(); - let link_meta = link::build_link_meta(sess, crate.attrs, output, + let link_meta = link::build_link_meta(crate.attrs, output, &mut symbol_hasher); // Append ".rs" to crate name as LLVM module identifier. diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 1ad60960de6..174841f282a 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -55,7 +55,7 @@ fn get_ast_and_resolve(cpath: &Path, binary: ~"rustdoc", maybe_sysroot: Some(@os::self_exe_path().unwrap().dir_path()), addl_lib_search_paths: @RefCell::new(libs), - outputs: ~[driver::session::OutputDylib], + crate_types: ~[driver::session::CrateTypeDylib], .. (*rustc::driver::session::basic_options()).clone() }; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 28e62f8fb29..153ab8afaa8 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -18,6 +18,7 @@ use std::str; use extra::tempfile::TempDir; use extra::getopts; use extra::test; +use rustc::back::link; use rustc::driver::driver; use rustc::driver::session; use rustc::metadata::creader::Loader; @@ -43,7 +44,7 @@ pub fn run(input: &str, matches: &getopts::Matches) -> int { binary: ~"rustdoc", maybe_sysroot: Some(@os::self_exe_path().unwrap().dir_path()), addl_lib_search_paths: libs, - outputs: ~[session::OutputDylib], + crate_types: ~[session::CrateTypeDylib], .. (*session::basic_options()).clone() }; @@ -104,8 +105,9 @@ fn runtest(test: &str, cratename: &str, libs: HashSet) { binary: ~"rustdoctest", maybe_sysroot: Some(@os::self_exe_path().unwrap().dir_path()), addl_lib_search_paths: @RefCell::new(libs), - outputs: ~[session::OutputExecutable], + crate_types: ~[session::CrateTypeExecutable], debugging_opts: session::PREFER_DYNAMIC, + output_types: ~[link::OutputTypeExe], .. (*session::basic_options()).clone() }; diff --git a/src/test/run-make/crate-data-smoke/Makefile b/src/test/run-make/crate-data-smoke/Makefile index 09ae0998202..5009ed15ee6 100644 --- a/src/test/run-make/crate-data-smoke/Makefile +++ b/src/test/run-make/crate-data-smoke/Makefile @@ -4,7 +4,7 @@ all: [ `$(RUSTC) --crate-id crate.rs` = "foo#0.10-pre" ] [ `$(RUSTC) --crate-name crate.rs` = "foo" ] [ `$(RUSTC) --crate-file-name crate.rs` = "foo" ] - [ `$(RUSTC) --crate-file-name --lib --test crate.rs` = "foo" ] + [ `$(RUSTC) --crate-file-name --crate-type=lib --test crate.rs` = "foo" ] [ `$(RUSTC) --crate-file-name --test lib.rs` = "mylib" ] $(RUSTC) --crate-file-name lib.rs $(RUSTC) --crate-file-name rlib.rs diff --git a/src/test/run-make/dep-info-custom/Makefile b/src/test/run-make/dep-info-custom/Makefile index 7a1f99ac2d5..72ce26ee6c6 100644 --- a/src/test/run-make/dep-info-custom/Makefile +++ b/src/test/run-make/dep-info-custom/Makefile @@ -1,7 +1,7 @@ -include ../tools.mk all: - $(RUSTC) --dep-info $(TMPDIR)/custom-deps-file.d --lib lib.rs + $(RUSTC) --dep-info $(TMPDIR)/custom-deps-file.d --crate-type=lib lib.rs sleep 1 touch foo.rs -rm -f $(TMPDIR)/done diff --git a/src/test/run-make/dep-info-custom/Makefile.foo b/src/test/run-make/dep-info-custom/Makefile.foo index 95e736deb41..302bb84908b 100644 --- a/src/test/run-make/dep-info-custom/Makefile.foo +++ b/src/test/run-make/dep-info-custom/Makefile.foo @@ -1,7 +1,7 @@ -LIB := $(shell $(RUSTC) --crate-file-name --lib lib.rs) +LIB := $(shell $(RUSTC) --crate-file-name --crate-type=lib lib.rs) $(TMPDIR)/$(LIB): - $(RUSTC) --dep-info $(TMPDIR)/custom-deps-file.d --lib lib.rs + $(RUSTC) --dep-info $(TMPDIR)/custom-deps-file.d --crate-type=lib lib.rs touch $(TMPDIR)/done -include $(TMPDIR)/custom-deps-file.d diff --git a/src/test/run-make/dep-info/Makefile b/src/test/run-make/dep-info/Makefile index 36a43b4c455..00a59383176 100644 --- a/src/test/run-make/dep-info/Makefile +++ b/src/test/run-make/dep-info/Makefile @@ -1,7 +1,7 @@ -include ../tools.mk all: - $(RUSTC) --dep-info --lib lib.rs + $(RUSTC) --dep-info --crate-type=lib lib.rs sleep 1 touch foo.rs -rm -f $(TMPDIR)/done diff --git a/src/test/run-make/dep-info/Makefile.foo b/src/test/run-make/dep-info/Makefile.foo index 2a1ce715e28..2b43dd0ec70 100644 --- a/src/test/run-make/dep-info/Makefile.foo +++ b/src/test/run-make/dep-info/Makefile.foo @@ -1,7 +1,7 @@ -LIB := $(shell $(RUSTC) --crate-file-name --lib lib.rs) +LIB := $(shell $(RUSTC) --crate-file-name --crate-type=lib lib.rs) $(TMPDIR)/$(LIB): - $(RUSTC) --dep-info --lib lib.rs + $(RUSTC) --dep-info --crate-type=lib lib.rs touch $(TMPDIR)/done --include $(TMPDIR)/lib.d +-include $(TMPDIR)/foo.d diff --git a/src/test/run-make/duplicate-output-flavors/Makefile b/src/test/run-make/duplicate-output-flavors/Makefile index a93a7ce8448..d40b6862a01 100644 --- a/src/test/run-make/duplicate-output-flavors/Makefile +++ b/src/test/run-make/duplicate-output-flavors/Makefile @@ -1,4 +1,4 @@ include ../tools.mk all: - $(RUSTC) --rlib foo.rs + $(RUSTC) --crate-type=rlib foo.rs diff --git a/src/test/run-make/mixing-libs/Makefile b/src/test/run-make/mixing-libs/Makefile index eb00c801390..533a6933a6d 100644 --- a/src/test/run-make/mixing-libs/Makefile +++ b/src/test/run-make/mixing-libs/Makefile @@ -3,7 +3,7 @@ all: $(RUSTC) rlib.rs $(RUSTC) dylib.rs && exit 1 || exit 0 - $(RUSTC) rlib.rs --dylib + $(RUSTC) rlib.rs --crate-type=dylib $(RUSTC) dylib.rs rm $(call DYLIB,rlib-*) $(RUSTC) prog.rs && exit 1 || exit 0 diff --git a/src/test/run-make/no-intermediate-extras/Makefile b/src/test/run-make/no-intermediate-extras/Makefile index 89186b2ad4d..258cbf04c61 100644 --- a/src/test/run-make/no-intermediate-extras/Makefile +++ b/src/test/run-make/no-intermediate-extras/Makefile @@ -3,5 +3,5 @@ -include ../tools.mk all: - $(RUSTC) --rlib --test foo.rs + $(RUSTC) --crate-type=rlib --test foo.rs rm $(TMPDIR)/foo.bc && exit 1 || exit 0 diff --git a/src/test/run-make/output-type-permutations/Makefile b/src/test/run-make/output-type-permutations/Makefile new file mode 100644 index 00000000000..72f96b21fa8 --- /dev/null +++ b/src/test/run-make/output-type-permutations/Makefile @@ -0,0 +1,42 @@ +-include ../tools.mk + +all: + $(RUSTC) foo.rs --crate-type=rlib,dylib,staticlib + rm $(TMPDIR)/$(call RLIB_GLOB,bar) + rm $(TMPDIR)/$(call DYLIB_GLOB,bar) + rm $(TMPDIR)/$(call STATICLIB_GLOB,bar) + $(RUSTC) foo.rs --crate-type=bin + rm $(TMPDIR)/bar + $(RUSTC) foo.rs --emit=asm,ir,bc,obj,link + rm $(TMPDIR)/bar.ll + rm $(TMPDIR)/bar.bc + rm $(TMPDIR)/bar.s + rm $(TMPDIR)/bar.o + rm $(TMPDIR)/bar + $(RUSTC) foo.rs --emit=asm,ir,bc,obj,link --crate-type=staticlib + rm $(TMPDIR)/bar.ll + rm $(TMPDIR)/bar.bc + rm $(TMPDIR)/bar.s + rm $(TMPDIR)/bar.o + rm $(TMPDIR)/$(call STATICLIB_GLOB,bar) + $(RUSTC) foo.rs --emit=asm -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --emit=bc -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --emit=ir -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --emit=obj -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --emit=link -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --crate-type=rlib -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --crate-type=dylib -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --crate-type=staticlib -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --crate-type=bin -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --emit=bc,link --crate-type=rlib + rm $(TMPDIR)/bar.bc + rm $(TMPDIR)/$(call RLIB_GLOB,bar) diff --git a/src/test/run-make/output-type-permutations/foo.rs b/src/test/run-make/output-type-permutations/foo.rs new file mode 100644 index 00000000000..3d944fd7a58 --- /dev/null +++ b/src/test/run-make/output-type-permutations/foo.rs @@ -0,0 +1,3 @@ +#[crate_id = "bar"]; + +fn main() {} diff --git a/src/test/run-make/prefer-dylib/Makefile b/src/test/run-make/prefer-dylib/Makefile index 8229547176a..6fb7434e68a 100644 --- a/src/test/run-make/prefer-dylib/Makefile +++ b/src/test/run-make/prefer-dylib/Makefile @@ -1,7 +1,7 @@ -include ../tools.mk all: - $(RUSTC) bar.rs --dylib --rlib + $(RUSTC) bar.rs --crate-type=dylib --crate-type=rlib $(RUSTC) foo.rs -Z prefer-dynamic $(call RUN,foo) rm $(TMPDIR)/*bar* diff --git a/src/test/run-make/prefer-rlib/Makefile b/src/test/run-make/prefer-rlib/Makefile index eedb70c4efd..c6a239eef08 100644 --- a/src/test/run-make/prefer-rlib/Makefile +++ b/src/test/run-make/prefer-rlib/Makefile @@ -1,7 +1,7 @@ -include ../tools.mk all: - $(RUSTC) bar.rs --dylib --rlib + $(RUSTC) bar.rs --crate-type=dylib --crate-type=rlib ls $(TMPDIR)/$(call RLIB_GLOB,bar) $(RUSTC) foo.rs rm $(TMPDIR)/*bar* diff --git a/src/test/run-make/simple-dylib/Makefile b/src/test/run-make/simple-dylib/Makefile index d4f215c69f0..84e6e079e6f 100644 --- a/src/test/run-make/simple-dylib/Makefile +++ b/src/test/run-make/simple-dylib/Makefile @@ -1,5 +1,5 @@ -include ../tools.mk all: - $(RUSTC) bar.rs --dylib + $(RUSTC) bar.rs --crate-type=dylib $(RUSTC) foo.rs $(call RUN,foo) diff --git a/src/test/run-make/simple-rlib/Makefile b/src/test/run-make/simple-rlib/Makefile index e8909ef134b..7b156cb8748 100644 --- a/src/test/run-make/simple-rlib/Makefile +++ b/src/test/run-make/simple-rlib/Makefile @@ -1,5 +1,5 @@ -include ../tools.mk all: - $(RUSTC) bar.rs --rlib + $(RUSTC) bar.rs --crate-type=rlib $(RUSTC) foo.rs $(call RUN,foo) diff --git a/src/test/run-make/volatile-intrinsics/Makefile b/src/test/run-make/volatile-intrinsics/Makefile index fc19412e2ef..bf79ca68c94 100644 --- a/src/test/run-make/volatile-intrinsics/Makefile +++ b/src/test/run-make/volatile-intrinsics/Makefile @@ -5,6 +5,6 @@ all: $(RUSTC) main.rs $(call RUN,main) # ... and the loads/stores must not be optimized out. - $(RUSTC) main.rs --emit-llvm -S + $(RUSTC) main.rs --emit=ir grep "load volatile" $(TMPDIR)/main.ll grep "store volatile" $(TMPDIR)/main.ll