about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--man/rustc.124
-rw-r--r--mk/crates.mk2
-rw-r--r--mk/tests.mk2
-rw-r--r--src/compiletest/runtest.rs29
-rw-r--r--src/doc/rust.md70
-rw-r--r--src/doc/tutorial.md4
-rw-r--r--src/etc/zsh/_rust8
-rw-r--r--src/librustc/back/link.rs172
-rw-r--r--src/librustc/back/lto.rs8
-rw-r--r--src/librustc/driver/driver.rs309
-rw-r--r--src/librustc/driver/session.rs49
-rw-r--r--src/librustc/lib.rs8
-rw-r--r--src/librustc/middle/trans/base.rs5
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/librustdoc/test.rs6
-rw-r--r--src/test/run-make/crate-data-smoke/Makefile2
-rw-r--r--src/test/run-make/dep-info-custom/Makefile2
-rw-r--r--src/test/run-make/dep-info-custom/Makefile.foo4
-rw-r--r--src/test/run-make/dep-info/Makefile2
-rw-r--r--src/test/run-make/dep-info/Makefile.foo6
-rw-r--r--src/test/run-make/duplicate-output-flavors/Makefile2
-rw-r--r--src/test/run-make/mixing-libs/Makefile2
-rw-r--r--src/test/run-make/no-intermediate-extras/Makefile2
-rw-r--r--src/test/run-make/output-type-permutations/Makefile42
-rw-r--r--src/test/run-make/output-type-permutations/foo.rs3
-rw-r--r--src/test/run-make/prefer-dylib/Makefile2
-rw-r--r--src/test/run-make/prefer-rlib/Makefile2
-rw-r--r--src/test/run-make/simple-dylib/Makefile2
-rw-r--r--src/test/run-make/simple-rlib/Makefile2
-rw-r--r--src/test/run-make/volatile-intrinsics/Makefile2
30 files changed, 417 insertions, 358 deletions
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 <filename>
+Write output to <filename>. 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 <dir>
+Write output to compiler-chosen filename in <dir>. 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.
-
-* `--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=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=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=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.
-
-* `--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=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=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-<HASH>-0.42.so
-> rustc main.rs -L .    # compiles main
+> rustc --crate-type=lib world.rs  # compiles libworld-<HASH>-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 <filename> 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);
-                            })
-                        }
+                        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, &path,
+                                            lib::llvm::AssemblyFile);
+                        });
+                    }
+                    OutputTypeObject => {
+                        object_file = Some(path);
                     }
-                    OutputTypeExe | OutputTypeObject => {
+                    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, output,
+                            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 <filename> 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<Path>,
+}
+
+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<Path>,
                               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()
-              }
-          };
-
-          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);
-          }
-      }
+        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(),
+            };
 
-      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)
-        };
+            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 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<HashMap<ast::NodeId,
                            ~[(lint::Lint, codemap::Span, ~str)]>>,
     node_id: Cell<ast::NodeId>,
-    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<T:Clone>(sess: Session, opt: Option<T>, 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<Path>) {
         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