]> git.lizzy.rs Git - rust.git/commitdiff
Redesign output flags for rustc
authorAlex Crichton <alex@alexcrichton.com>
Mon, 3 Feb 2014 23:27:54 +0000 (15:27 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Thu, 6 Feb 2014 19:14:13 +0000 (11:14 -0800)
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

30 files changed:
man/rustc.1
mk/crates.mk
mk/tests.mk
src/compiletest/runtest.rs
src/doc/rust.md
src/doc/tutorial.md
src/etc/zsh/_rust
src/librustc/back/link.rs
src/librustc/back/lto.rs
src/librustc/driver/driver.rs
src/librustc/driver/session.rs
src/librustc/lib.rs
src/librustc/middle/trans/base.rs
src/librustdoc/core.rs
src/librustdoc/test.rs
src/test/run-make/crate-data-smoke/Makefile
src/test/run-make/dep-info-custom/Makefile
src/test/run-make/dep-info-custom/Makefile.foo
src/test/run-make/dep-info/Makefile
src/test/run-make/dep-info/Makefile.foo
src/test/run-make/duplicate-output-flavors/Makefile
src/test/run-make/mixing-libs/Makefile
src/test/run-make/no-intermediate-extras/Makefile
src/test/run-make/output-type-permutations/Makefile [new file with mode: 0644]
src/test/run-make/output-type-permutations/foo.rs [new file with mode: 0644]
src/test/run-make/prefer-dylib/Makefile
src/test/run-make/prefer-rlib/Makefile
src/test/run-make/simple-dylib/Makefile
src/test/run-make/simple-rlib/Makefile
src/test/run-make/volatile-intrinsics/Makefile

index 885ec37f37486cbeabe5e4b2cb5b1be7bf1c30d5..0f84c26df2b02c5090859d235aed122ed1d0a271 100644 (file)
@@ -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
index ea573b9db8d21c21cedf0e2b41d3b56ab7c463a1..652d7629bda3033a40f146748bca86d0f7e8e464 100644 (file)
@@ -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
 
index 85c63acb0f1f29930c773d69aa559c31bdbc94f8..f8898ee8d0602cd3c554a5f5988f55825a01b4ef 100644 (file)
@@ -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)): \
index 0503790ae943c964002a3d906e96ff1d14929654..adb81803ab09501c370c3220f7688fde498462f5 100644 (file)
@@ -245,7 +245,7 @@ fn make_typecheck_args(config: &config, props: &TestProps, testfile: &Path) -> P
         };
         // 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)
 }
 
index c95bfee4ace1f926036b750c50aa38c9e2b4b851..b412fa4967df0861656c57a14c1224ce5fc50325 100644 (file)
@@ -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
 
index 75a5840a1ef6935ef370cc04f6409f45bee6b4ca..7010eb4e48d8b27a09b3dd0f05e8ea460f0fcd57 100644 (file)
@@ -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"
 ~~~~
index 03a8712283cd79e501b074298089dbf2f038b0ac..f1f9e88f7c92643c270b217f514dbff6dfdc8674 100644 (file)
@@ -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]'
index aea9b65087dc68b4a0cc76fb3260cee5a2602f10..62fdff49168aaff3d985f726bb6a2df800a3f102 100644 (file)
@@ -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::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 @@ fn target_feature<'a>(sess: &'a Session) -> &'a str {
 
     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 fn run_passes(sess: Session,
             // 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 @@ fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
                 }
             }
 
-            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 @@ fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
         }
     }
 
-    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 @@ unsafe fn populate_llvm_passes(fpm: lib::llvm::PassManagerRef,
  *    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 @@ fn crate_hash(symbol_hasher: &mut Sha256, crateid: &CrateId) -> ~str {
     }
 
     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);
             }
 
index 3fbcd377b8b1cdd9b6203a749d82421680213285..3c7d804435f2fdb2d76bf8a6f26cdd8ba0275175 100644 (file)
@@ -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");
index c3b851b76ac04168eeff0e7fea32989eb4f9275d..9d03fbb60619dccd56e2a909a6c2168771c0ac26 100644 (file)
@@ -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
     }
 }
 
index 4ef97e9234a9e8ec0148655177a353d42135f75a..859d09b59627c91465613d5aa1f0ff3f1f3c5a5d 100644 (file)
@@ -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 @@ pub fn intr(&self) -> @syntax::parse::token::IdentInterner {
 /// 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();
index 52ddc8c810888e980073b1b1c4fc45009f1b24c8..13b38d2e2bcb6f25e85091680c3ef406844f8341 100644 (file)
@@ -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());
             }
         }
index 5b4a961761277273ecb7a055e97acf11bd1b63da..485daf3d387fce3d704ca2ea409e7750978884a4 100644 (file)
@@ -28,6 +28,7 @@
 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.
index 1ad60960de63fedcfad64e76c8ec95a8386eda9a..174841f282a5bdd05d73bebf570f4f55c428d101 100644 (file)
@@ -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()
     };
 
index 28e62f8fb299aba1939bf533dabb1ab7c6d38dc0..153ab8afaa8801b1b9dcd3ae0c056ebef84db3b0 100644 (file)
@@ -18,6 +18,7 @@
 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()
     };
 
index 09ae09982028fc3f42ba6e491d5889b6a370ffa1..5009ed15ee6c02dacc0f64389840b67a42a59f02 100644 (file)
@@ -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
index 7a1f99ac2d5928c3869b736d455b58876a916518..72ce26ee6c638f7513f78ed1bbfe911b8beb6d07 100644 (file)
@@ -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
index 95e736deb41a189ee740a9148b7987132665e1b2..302bb84908b66caf9ade6c81429ace97b4341803 100644 (file)
@@ -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
index 36a43b4c45560e39098e281e54ede83860218974..00a59383176df4354ebb4a1d0d933748fa7ab517 100644 (file)
@@ -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
index 2a1ce715e280ae49fe76e39027756cb9b6461008..2b43dd0ec7095fbde0af1a498e01a0619628d8bf 100644 (file)
@@ -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
index a93a7ce84484bf1cefce18a071e274b30ce507e5..d40b6862a0143dbfe2c5f2b3178700e118fa5e91 100644 (file)
@@ -1,4 +1,4 @@
 include ../tools.mk
 
 all:
-       $(RUSTC) --rlib foo.rs
+       $(RUSTC) --crate-type=rlib foo.rs
index eb00c80139092eb7fb7e6d1ce9c28d694bc639d7..533a6933a6dbc247de548d4c919f005923072dee 100644 (file)
@@ -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
index 89186b2ad4da2e3d62fd81093f939bcac338de78..258cbf04c611dba792f65b70a9461958b02c4e26 100644 (file)
@@ -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 (file)
index 0000000..72f96b2
--- /dev/null
@@ -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 (file)
index 0000000..3d944fd
--- /dev/null
@@ -0,0 +1,3 @@
+#[crate_id = "bar"];
+
+fn main() {}
index 8229547176a48be7750e24778e2dd4489a73a046..6fb7434e68ab3a43c10b0163223da9886fbab8e2 100644 (file)
@@ -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*
index eedb70c4efdf025b8e81eea6aeaf1838ed9d041e..c6a239eef08e287577e068e8e95e098f80e35bf2 100644 (file)
@@ -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*
index d4f215c69f07e50a058d66d07997ccbbd0d4c411..84e6e079e6f06bea606c775438de005fc6a3fa2d 100644 (file)
@@ -1,5 +1,5 @@
 -include ../tools.mk
 all:
-       $(RUSTC) bar.rs --dylib
+       $(RUSTC) bar.rs --crate-type=dylib
        $(RUSTC) foo.rs
        $(call RUN,foo)
index e8909ef134bf5a6952ec8e999abca84e5cf8e5f8..7b156cb87488065d8949d79447fa610eb597e446 100644 (file)
@@ -1,5 +1,5 @@
 -include ../tools.mk
 all:
-       $(RUSTC) bar.rs --rlib
+       $(RUSTC) bar.rs --crate-type=rlib
        $(RUSTC) foo.rs
        $(call RUN,foo)
index fc19412e2ef54a2788f33b28a174763e7ea90b8d..bf79ca68c9461ac8d6fe57a456a7d8ad1f39038c 100644 (file)
@@ -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