Redesign output flags for rustc

This commit removes the -c, --emit-llvm, -s, --rlib, --dylib, --staticlib,
--lib, and --bin flags from rustc, adding the following flags:

* --emit=[asm,ir,bc,obj,link]
* --crate-type=[dylib,rlib,staticlib,bin,lib]

The -o option has also been redefined to be used for *all* flavors of outputs.
This means that we no longer ignore it for libraries. The --out-dir remains the
same as before.

The new logic for files that rustc emits is as follows:

1. Output types are dictated by the --emit flag. The default value is
   --emit=link, and this option can be passed multiple times and have all
   options stacked on one another.
2. Crate types are dictated by the --crate-type flag and the #[crate_type]
   attribute. The flags can be passed many times and stack with the crate
   attribute.
3. If the -o flag is specified, and only one output type is specified, the
   output will be emitted at this location. If more than one output type is
   specified, then the filename of -o is ignored, and all output goes in the
   directory that -o specifies. The -o option always ignores the --out-dir
   option.
4. If the --out-dir flag is specified, all output goes in this directory.
5. If -o and --out-dir are both not present, all output goes in the current
   directory of the process.
6. When multiple output types are specified, the filestem of all output is the
   same as the name of the CrateId (derived from a crate attribute or from the
   filestem of the crate file).

Closes #7791
Closes #11056
Closes #11667
This commit is contained in:
Alex Crichton 2014-02-03 15:27:54 -08:00
parent f039d10cf7
commit 6e7968b10a
30 changed files with 415 additions and 356 deletions

View File

@ -12,17 +12,14 @@ This program is a compiler for the Rust language, available at
.SH OPTIONS .SH OPTIONS
.TP .TP
\fB\-\-bin\fR \fB\-\-crate-type=[bin|lib|dylib|rlib|staticlib]\fR
Compile an executable crate (default) Configure the flavor of rust crate that is generated (default `bin`)
.TP
\fB\-c\fR
Compile and assemble, but do not link
.TP .TP
\fB\-\-cfg\fR SPEC \fB\-\-cfg\fR SPEC
Configure the compilation environment Configure the compilation environment
.TP .TP
\fB\-\-emit\-llvm\fR \fB\-\-emit=[asm,ir,bc,obj,link]\fR
Produce an LLVM bitcode file Configure the output that rustc will produce
.TP .TP
\fB\-h\fR, \fB\-\-help\fR \fB\-h\fR, \fB\-\-help\fR
Display this message Display this message
@ -30,9 +27,6 @@ Display this message
\fB\-L\fR PATH \fB\-L\fR PATH
Add a directory to the library search path Add a directory to the library search path
.TP .TP
\fB\-\-lib\fR
Compile a library crate
.TP
\fB\-\-linker\fR LINKER \fB\-\-linker\fR LINKER
Program to use for linking instead of the default Program to use for linking instead of the default
.TP .TP
@ -49,7 +43,7 @@ Run all passes except translation; no output
Equivalent to \fI\-\-opt\-level=2\fR Equivalent to \fI\-\-opt\-level=2\fR
.TP .TP
\fB\-o\fR FILENAME \fB\-o\fR FILENAME
Write output to <filename> Write output to <filename>. Ignored if more than one --emit is specified.
.TP .TP
\fB\-\-opt\-level\fR LEVEL \fB\-\-opt\-level\fR LEVEL
Optimize with possible levels 0-3 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. will list the available passes.
.TP .TP
\fB\-\-out\-dir\fR DIR \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 .TP
\fB\-\-parse\-only\fR \fB\-\-parse\-only\fR
Parse only; do not compile, assemble, or link 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, expanded, with type annotations), or identified (fully parenthesized,
AST nodes and blocks with IDs) AST nodes and blocks with IDs)
.TP .TP
\fB\-S\fR
Compile only; do not assemble or link
.TP
\fB\-\-save\-temps\fR \fB\-\-save\-temps\fR
Write intermediate files (.bc, .opt.bc, .o) in addition to normal output Write intermediate files (.bc, .opt.bc, .o) in addition to normal output
.TP .TP
@ -120,7 +112,7 @@ To build an executable from a source file with a main function:
$ rustc -o hello hello.rs $ rustc -o hello hello.rs
To build a library from a source file: 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: To build either with a crate (.rs) file:
$ rustc hello.rs $ rustc hello.rs

View File

@ -102,7 +102,7 @@ $(foreach crate,$(CRATES),$(eval $(call RUST_CRATE,$(crate))))
# #
# $(1) is the crate to generate variables for # $(1) is the crate to generate variables for
define RUST_TOOL 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)) *.rs */*.rs */*/*.rs */*/*/*.rs))
endef endef

View File

@ -835,7 +835,7 @@ $$(TLIB2_T_$(2)_H_$(3))/$$(FT_LIB): \
tmp/$$(FT).rc \ tmp/$$(FT).rc \
$$(SREQ2_T_$(2)_H_$(3)) $$(SREQ2_T_$(2)_H_$(3))
@$$(call E, compile_and_link: $$@) @$$(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))" -L "$$(RT_OUTPUT_DIR_$(2))"
$(3)/test/$$(FT_DRIVER)-$(2)$$(X_$(2)): \ $(3)/test/$$(FT_DRIVER)-$(2)$$(X_$(2)): \

View File

@ -245,7 +245,7 @@ actual:\n\
}; };
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
let mut args = ~[~"-", let mut args = ~[~"-",
~"--no-trans", ~"--lib", ~"--no-trans", ~"--crate-type=lib",
~"--target=" + target, ~"--target=" + target,
~"-L", config.build_base.as_str().unwrap().to_owned(), ~"-L", config.build_base.as_str().unwrap().to_owned(),
~"-L", ~"-L",
@ -659,7 +659,7 @@ fn compile_test_(config: &config, props: &TestProps,
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
let link_args = ~[~"-L", aux_dir.as_str().unwrap().to_owned()]; let link_args = ~[~"-L", aux_dir.as_str().unwrap().to_owned()];
let args = make_compile_args(config, props, link_args + extra_args, 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) 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 abs_ab = config.aux_base.join(rel_ab.as_slice());
let aux_props = load_props(&abs_ab); let aux_props = load_props(&abs_ab);
let aux_args = let aux_args =
make_compile_args(config, &aux_props, ~[~"--dylib"] + extra_link_args, make_compile_args(config, &aux_props, ~[~"--crate-type=dylib"]
|a,b| make_lib_name(a, b, testfile), &abs_ab); + 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, ~[], let auxres = compose_and_run(config, &abs_ab, aux_args, ~[],
config.compile_lib_path, None); config.compile_lib_path, None);
if !auxres.status.success() { if !auxres.status.success() {
@ -741,10 +745,15 @@ fn compose_and_run(config: &config, testfile: &Path,
prog, args, procenv, input); prog, args, procenv, input);
} }
enum TargetLocation {
ThisFile(Path),
ThisDirectory(Path),
}
fn make_compile_args(config: &config, fn make_compile_args(config: &config,
props: &TestProps, props: &TestProps,
extras: ~[~str], extras: ~[~str],
xform: |&config, &Path| -> Path, xform: |&config, &Path| -> TargetLocation,
testfile: &Path) testfile: &Path)
-> ProcArgs { -> ProcArgs {
let xform_file = xform(config, testfile); 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 // FIXME (#9639): This needs to handle non-utf8 paths
let mut args = ~[testfile.as_str().unwrap().to_owned(), 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(), ~"-L", config.build_base.as_str().unwrap().to_owned(),
~"--target=" + target] ~"--target=" + target]
+ extras; + 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(&config.rustcflags));
args.push_all_move(split_maybe_args(&props.compile_flags)); args.push_all_move(split_maybe_args(&props.compile_flags));
return ProcArgs {prog: config.rustc_path.as_str().unwrap().to_owned(), args: args}; 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); let aux_dir = aux_output_dir_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
let link_args = ~[~"-L", aux_dir.as_str().unwrap().to_owned()]; 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, let args = make_compile_args(config, props,
link_args + llvm_args, 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) compose_and_run_compiler(config, props, testfile, args, None)
} }

View File

@ -3678,43 +3678,43 @@ found in the [ffi tutorial][ffi].
In one session of compilation, the compiler can generate multiple artifacts In one session of compilation, the compiler can generate multiple artifacts
through the usage of command line flags and the `crate_type` attribute. through the usage of command line flags and the `crate_type` attribute.
* `--bin`, `#[crate_type = "bin"]` - A runnable executable will be produced. * `--crate-type=bin`, `#[crate_type = "bin"]` - A runnable executable will be
This requires that there is a `main` function in the crate which will be run produced. This requires that there is a `main` function in the crate which
when the program begins executing. This will link in all Rust and native will be run when the program begins executing. This will link in all Rust and
dependencies, producing a distributable binary. native dependencies, producing a distributable binary.
* `--lib`, `#[crate_type = "lib"]` - A Rust library will be produced. This is * `--crate-type=lib`, `#[crate_type = "lib"]` - A Rust library will be produced.
an ambiguous concept as to what exactly is produced because a library can This is an ambiguous concept as to what exactly is produced because a library
manifest itself in several forms. The purpose of this generic `lib` option is can manifest itself in several forms. The purpose of this generic `lib` option
to generate the "compiler recommended" style of library. The output library 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 will always be usable by rustc, but the actual type of library may change from
from time-to-time. The remaining output types are all different flavors of 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 libraries, and the `lib` type can be seen as an alias for one of them (but the
the actual one is compiler-defined). actual one is compiler-defined).
* `--dylib`, `#[crate_type = "dylib"]` - A dynamic Rust library will be * `--crate-type=dylib`, `#[crate_type = "dylib"]` - A dynamic Rust library will
produced. This is different from the `lib` output type in that this forces 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 dynamic library generation. The resulting dynamic library can be used as a
dependency for other libraries and/or executables. This output type will dependency for other libraries and/or executables. This output type will
create `*.so` files on linux, `*.dylib` files on osx, and `*.dll` files on create `*.so` files on linux, `*.dylib` files on osx, and `*.dll` files on
windows. windows.
* `--staticlib`, `#[crate_type = "staticlib"]` - A static system library will * `--crate-type=staticlib`, `#[crate_type = "staticlib"]` - A static system
be produced. This is different from other library outputs in that the Rust library will be produced. This is different from other library outputs in that
compiler will never attempt to link to `staticlib` outputs. The purpose of the Rust compiler will never attempt to link to `staticlib` outputs. The
this output type is to create a static library containing all of the local purpose of this output type is to create a static library containing all of
crate's code along with all upstream dependencies. The static library is the local crate's code along with all upstream dependencies. The static
actually a `*.a` archive on linux and osx and a `*.lib` file on windows. This library is actually a `*.a` archive on linux and osx and a `*.lib` file on
format is recommended for use in situtations such as linking Rust code into an windows. This format is recommended for use in situtations such as linking
existing non-Rust application because it will not have dynamic dependencies on Rust code into an existing non-Rust application because it will not have
other Rust code. dynamic dependencies on other Rust code.
* `--rlib`, `#[crate_type = "rlib"]` - A "Rust library" file will be produced. * `--crate-type=rlib`, `#[crate_type = "rlib"]` - A "Rust library" file will be
This is used as an intermediate artifact and can be thought of as a "static produced. This is used as an intermediate artifact and can be thought of as a
Rust library". These `rlib` files, unlike `staticlib` files, are interpreted "static Rust library". These `rlib` files, unlike `staticlib` files, are
by the Rust compiler in future linkage. This essentially means that `rustc` interpreted by the Rust compiler in future linkage. This essentially means
will look for metadata in `rlib` files like it looks for metadata in dynamic that `rustc` will look for metadata in `rlib` files like it looks for metadata
libraries. This form of output is used to produce statically linked in dynamic libraries. This form of output is used to produce statically linked
executables as well as `staticlib` outputs. executables as well as `staticlib` outputs.
Note that these outputs are stackable in the sense that if multiple are 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 then the compiler will force all dependencies to be dynamic and will generate
errors if dynamic versions could not be found. errors if dynamic versions could not be found.
In general, `--bin` or `--lib` should be sufficient for all compilation needs, In general, `--crate-type=bin` or `--crate-type=lib` should be sufficient for
and the other options are just available if more fine-grained control is desired all compilation needs, and the other options are just available if more
over the output format of a Rust crate. fine-grained control is desired over the output format of a Rust crate.
### Logging system ### Logging system

View File

@ -3162,8 +3162,8 @@ fn main() { println!("hello {}", world::explore()); }
Now compile and run like this (adjust to your platform if necessary): Now compile and run like this (adjust to your platform if necessary):
~~~~ {.notrust} ~~~~ {.notrust}
> rustc --lib world.rs # compiles libworld-<HASH>-0.42.so > rustc --crate-type=lib world.rs # compiles libworld-<HASH>-0.42.so
> rustc main.rs -L . # compiles main > rustc main.rs -L . # compiles main
> ./main > ./main
"hello world" "hello world"
~~~~ ~~~~

View File

@ -7,18 +7,15 @@ typeset -A opt_args
_rustc_opts_switches=( _rustc_opts_switches=(
--android-cross-path'[The path to the Android NDK]' --android-cross-path'[The path to the Android NDK]'
--ar'[Program to use for managing archives instead of the default.]' --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]' -c'[Compile and assemble, but do not link]'
--cfg'[Configure the compilation environment]' --cfg'[Configure the compilation environment]'
--crate-id'[Output the crate id and exit]' --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-file-name'[Output the file(s) that would be written if compilation continued and exit]'
--crate-name'[Output the crate name and exit]' --crate-name'[Output the crate name and exit]'
--dep-info'[Output dependency info to <filename> after compiling]' --dep-info'[Output dependency info to <filename> after compiling]'
--dylib'[Compile a dynamic library crate]' --crate-type'[Specify the type of crate to crate]'
--emit-llvm'[Produce an LLVM bitcode file]'
{-h,--help}'[Display this message]' {-h,--help}'[Display this message]'
-L'[Add a directory to the library search path]' -L'[Add a directory to the library search path]'
--lib'[Compile a library crate]'
--linker'[Program to use for linking instead of the default.]' --linker'[Program to use for linking instead of the default.]'
--link-args'[FLAGS is a space-separated list of flags passed to the linker]' --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]' --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]' --parse-only'[Parse only; do not compile, assemble, or link]'
--passes'[Comma or space separated list of pass names to use]' --passes'[Comma or space separated list of pass names to use]'
--pretty'[Pretty-print the input instead of compiling]' --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]' --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]' --sysroot'[Override the system root]'
--test'[Build a test harness]' --test'[Build a test harness]'
--target'[Target triple cpu-manufacturer-kernel\[-os\] to compile]' --target'[Target triple cpu-manufacturer-kernel\[-os\] to compile]'

View File

@ -11,7 +11,7 @@
use back::archive::{Archive, METADATA_FILENAME}; use back::archive::{Archive, METADATA_FILENAME};
use back::rpath; use back::rpath;
use driver::driver::CrateTranslation; use driver::driver::{CrateTranslation, OutputFilenames};
use driver::session::Session; use driver::session::Session;
use driver::session; use driver::session;
use lib::llvm::llvm; use lib::llvm::llvm;
@ -44,9 +44,8 @@ use syntax::attr;
use syntax::attr::AttrMetaMethods; use syntax::attr::AttrMetaMethods;
use syntax::crateid::CrateId; use syntax::crateid::CrateId;
#[deriving(Clone, Eq)] #[deriving(Clone, Eq, TotalOrd, TotalEq)]
pub enum OutputType { pub enum OutputType {
OutputTypeNone,
OutputTypeBitcode, OutputTypeBitcode,
OutputTypeAssembly, OutputTypeAssembly,
OutputTypeLlvmAssembly, OutputTypeLlvmAssembly,
@ -90,7 +89,7 @@ pub mod write {
use back::link::{OutputTypeAssembly, OutputTypeBitcode}; use back::link::{OutputTypeAssembly, OutputTypeBitcode};
use back::link::{OutputTypeExe, OutputTypeLlvmAssembly}; use back::link::{OutputTypeExe, OutputTypeLlvmAssembly};
use back::link::{OutputTypeObject}; use back::link::{OutputTypeObject};
use driver::driver::CrateTranslation; use driver::driver::{CrateTranslation, OutputFilenames};
use driver::session::Session; use driver::session::Session;
use driver::session; use driver::session;
use lib::llvm::llvm; use lib::llvm::llvm;
@ -101,7 +100,6 @@ pub mod write {
use std::c_str::ToCStr; use std::c_str::ToCStr;
use std::libc::{c_uint, c_int}; use std::libc::{c_uint, c_int};
use std::path::Path;
use std::run; use std::run;
use std::str; use std::str;
@ -125,8 +123,8 @@ pub mod write {
pub fn run_passes(sess: Session, pub fn run_passes(sess: Session,
trans: &CrateTranslation, trans: &CrateTranslation,
output_type: OutputType, output_types: &[OutputType],
output: &Path) { output: &OutputFilenames) {
let llmod = trans.module; let llmod = trans.module;
let llcx = trans.context; let llcx = trans.context;
unsafe { unsafe {
@ -209,10 +207,11 @@ pub mod write {
// Emit the bytecode if we're either saving our temporaries or // Emit the bytecode if we're either saving our temporaries or
// emitting an rlib. Whenever an rlib is created, the bytecode is // emitting an rlib. Whenever an rlib is created, the bytecode is
// inserted into the archive in order to allow LTO against it. // 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 || if sess.opts.save_temps ||
outputs.get().iter().any(|&o| o == session::OutputRlib) { (crate_types.get().contains(&session::CrateTypeRlib) &&
output.with_extension("bc").with_c_str(|buf| { sess.opts.output_types.contains(&OutputTypeExe)) {
output.temp_path(OutputTypeBitcode).with_c_str(|buf| {
llvm::LLVMWriteBitcodeToFile(llmod, buf); llvm::LLVMWriteBitcodeToFile(llmod, buf);
}) })
} }
@ -247,52 +246,68 @@ pub mod write {
} }
} }
time(sess.time_passes(), "codegen passes", (), |()| { let mut object_file = None;
match output_type { let mut needs_metadata = false;
OutputTypeNone => {} for output_type in output_types.iter() {
let path = output.path(*output_type);
match *output_type {
OutputTypeBitcode => { OutputTypeBitcode => {
output.with_c_str(|buf| { path.with_c_str(|buf| {
llvm::LLVMWriteBitcodeToFile(llmod, buf); llvm::LLVMWriteBitcodeToFile(llmod, buf);
}) })
} }
OutputTypeLlvmAssembly => { OutputTypeLlvmAssembly => {
output.with_c_str(|output| { path.with_c_str(|output| {
with_codegen(tm, llmod, |cpm| { with_codegen(tm, llmod, |cpm| {
llvm::LLVMRustPrintModule(cpm, llmod, output); llvm::LLVMRustPrintModule(cpm, llmod, output);
}) })
}) })
} }
OutputTypeAssembly => { 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 // If we're not using the LLVM assembler, this function
// could be invoked specially with output_type_assembly, // could be invoked specially with output_type_assembly,
// so in this case we still want the metadata object // so in this case we still want the metadata object
// file. // file.
if sess.opts.output_type != OutputTypeAssembly { let ty = OutputTypeAssembly;
with_codegen(tm, trans.metadata_module, |cpm| { let path = if sess.opts.output_types.contains(&ty) {
let out = output.with_extension("metadata.o"); path
WriteOutputFile(sess, tm, cpm, } else {
trans.metadata_module, &out, needs_metadata = true;
lib::llvm::ObjectFile); output.temp_path(OutputTypeAssembly)
}) };
}
}
OutputTypeExe | OutputTypeObject => {
with_codegen(tm, llmod, |cpm| { with_codegen(tm, llmod, |cpm| {
WriteOutputFile(sess, tm, cpm, llmod, output, WriteOutputFile(sess, tm, cpm, llmod, &path,
lib::llvm::AssemblyFile);
});
}
OutputTypeObject => {
object_file = Some(path);
}
OutputTypeExe => {
object_file = Some(output.temp_path(OutputTypeObject));
needs_metadata = true;
}
}
}
time(sess.time_passes(), "codegen passes", (), |()| {
match object_file {
Some(ref path) => {
with_codegen(tm, llmod, |cpm| {
WriteOutputFile(sess, tm, cpm, llmod, path,
lib::llvm::ObjectFile); 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 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 // FIXME (#9639): This needs to handle non-utf8 paths
let args = [ let args = [
@ -480,9 +497,8 @@ pub mod write {
* system linkers understand. * system linkers understand.
*/ */
pub fn build_link_meta(sess: Session, pub fn build_link_meta(attrs: &[ast::Attribute],
attrs: &[ast::Attribute], output: &OutputFilenames,
output: &Path,
symbol_hasher: &mut Sha256) symbol_hasher: &mut Sha256)
-> LinkMeta { -> LinkMeta {
// This calculates CMH as defined above // This calculates CMH as defined above
@ -493,14 +509,7 @@ pub fn build_link_meta(sess: Session,
} }
let crateid = match attr::find_crateid(attrs) { let crateid = match attr::find_crateid(attrs) {
None => { None => from_str(output.out_filestem).unwrap(),
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()
}
Some(s) => s, Some(s) => s,
}; };
@ -794,20 +803,21 @@ fn remove(sess: Session, path: &Path) {
/// of the requested outputs for this compilation session. /// of the requested outputs for this compilation session.
pub fn link_binary(sess: Session, pub fn link_binary(sess: Session,
trans: &CrateTranslation, trans: &CrateTranslation,
obj_filename: &Path, outputs: &OutputFilenames,
out_filename: &Path,
lm: &LinkMeta) -> ~[Path] { lm: &LinkMeta) -> ~[Path] {
let mut out_filenames = ~[]; let mut out_filenames = ~[];
let outputs = sess.outputs.borrow(); let crate_types = sess.crate_types.borrow();
for &output in outputs.get().iter() { for &crate_type in crate_types.get().iter() {
let out_file = link_binary_output(sess, trans, output, obj_filename, let out_file = link_binary_output(sess, trans, crate_type, outputs, lm);
out_filename, lm);
out_filenames.push(out_file); out_filenames.push(out_file);
} }
// Remove the temporary object file and metadata if we aren't saving temps // Remove the temporary object file and metadata if we aren't saving temps
if !sess.opts.save_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")); 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, pub fn filename_for_input(sess: &Session, crate_type: session::CrateType,
out_filename: &Path) -> Path { lm: &LinkMeta, out_filename: &Path) -> Path {
let libname = output_lib_filename(lm); let libname = output_lib_filename(lm);
match output { match crate_type {
session::OutputRlib => { session::CrateTypeRlib => {
out_filename.with_filename(format!("lib{}.rlib", libname)) out_filename.with_filename(format!("lib{}.rlib", libname))
} }
session::OutputDylib => { session::CrateTypeDylib => {
let (prefix, suffix) = match sess.targ_cfg.os { let (prefix, suffix) = match sess.targ_cfg.os {
abi::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX), abi::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
abi::OsMacos => (macos::DLL_PREFIX, macos::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)) out_filename.with_filename(format!("{}{}{}", prefix, libname, suffix))
} }
session::OutputStaticlib => { session::CrateTypeStaticlib => {
out_filename.with_filename(format!("lib{}.a", libname)) out_filename.with_filename(format!("lib{}.a", libname))
} }
session::OutputExecutable => out_filename.clone(), session::CrateTypeExecutable => out_filename.clone(),
} }
} }
fn link_binary_output(sess: Session, fn link_binary_output(sess: Session,
trans: &CrateTranslation, trans: &CrateTranslation,
output: session::OutputStyle, crate_type: session::CrateType,
obj_filename: &Path, outputs: &OutputFilenames,
out_filename: &Path,
lm: &LinkMeta) -> Path { 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. // Make sure the output and obj_filename are both writeable.
// Mac, FreeBSD, and Windows system linkers check this already -- // Mac, FreeBSD, and Windows system linkers check this already --
// however, the Linux linker will happily overwrite a read-only file. // however, the Linux linker will happily overwrite a read-only file.
// We should be consistent. // 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); let out_is_writeable = is_writeable(&out_filename);
if !out_is_writeable { if !out_is_writeable {
sess.fatal(format!("Output file {} is not writeable -- check its permissions.", sess.fatal(format!("Output file {} is not writeable -- check its permissions.",
@ -869,18 +884,18 @@ fn link_binary_output(sess: Session,
obj_filename.display())); obj_filename.display()));
} }
match output { match crate_type {
session::OutputRlib => { session::CrateTypeRlib => {
link_rlib(sess, Some(trans), obj_filename, &out_filename); link_rlib(sess, Some(trans), &obj_filename, &out_filename);
} }
session::OutputStaticlib => { session::CrateTypeStaticlib => {
link_staticlib(sess, obj_filename, &out_filename); link_staticlib(sess, &obj_filename, &out_filename);
} }
session::OutputExecutable => { session::CrateTypeExecutable => {
link_natively(sess, false, obj_filename, &out_filename); link_natively(sess, false, &obj_filename, &out_filename);
} }
session::OutputDylib => { session::CrateTypeDylib => {
link_natively(sess, true, obj_filename, &out_filename); link_natively(sess, true, &obj_filename, &out_filename);
} }
} }
@ -954,7 +969,8 @@ fn link_rlib(sess: Session,
// into the archive. // into the archive.
let bc = obj_filename.with_extension("bc"); let bc = obj_filename.with_extension("bc");
a.add_file(&bc, false); a.add_file(&bc, false);
if !sess.opts.save_temps { if !sess.opts.save_temps &&
!sess.opts.output_types.contains(&OutputTypeBitcode) {
remove(sess, &bc); remove(sess, &bc);
} }

View File

@ -26,10 +26,10 @@ pub fn run(sess: session::Session, llmod: ModuleRef,
} }
// Make sure we actually can run LTO // Make sure we actually can run LTO
let outputs = sess.outputs.borrow(); let crate_types = sess.crate_types.borrow();
for output in outputs.get().iter() { for crate_type in crate_types.get().iter() {
match *output { match *crate_type {
session::OutputExecutable | session::OutputStaticlib => {} session::CrateTypeExecutable | session::CrateTypeStaticlib => {}
_ => { _ => {
sess.fatal("lto can only be run for executables and \ sess.fatal("lto can only be run for executables and \
static library outputs"); static library outputs");

View File

@ -11,7 +11,7 @@
use back::link; use back::link;
use back::{arm, x86, x86_64, mips}; 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::{Session, Session_, No, Less, Default};
use driver::session; use driver::session;
use front; use front;
@ -182,7 +182,7 @@ pub fn phase_2_configure_and_expand(sess: Session,
let time_passes = sess.time_passes(); let time_passes = sess.time_passes();
sess.building_library.set(session::building_library(sess.opts, &crate)); 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", (), |_| time(time_passes, "gated feature checking", (), |_|
front::feature_gate::check_crate(sess, &crate)); front::feature_gate::check_crate(sess, &crate));
@ -373,8 +373,7 @@ pub fn phase_4_translate_to_llvm(sess: Session,
analysis: &CrateAnalysis, analysis: &CrateAnalysis,
outputs: &OutputFilenames) -> CrateTranslation { outputs: &OutputFilenames) -> CrateTranslation {
time(sess.time_passes(), "translation", crate, |crate| time(sess.time_passes(), "translation", crate, |crate|
trans::base::trans_crate(sess, crate, analysis, trans::base::trans_crate(sess, crate, analysis, outputs))
&outputs.obj_filename))
} }
/// Run LLVM itself, producing a bitcode file, assembly file or object file /// 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, pub fn phase_5_run_llvm_passes(sess: Session,
trans: &CrateTranslation, trans: &CrateTranslation,
outputs: &OutputFilenames) { outputs: &OutputFilenames) {
if sess.no_integrated_as() { if sess.no_integrated_as() {
let output_type = link::OutputTypeAssembly; let output_type = link::OutputTypeAssembly;
let asm_filename = outputs.obj_filename.with_extension("s");
time(sess.time_passes(), "LLVM passes", (), |_| time(sess.time_passes(), "LLVM passes", (), |_|
link::write::run_passes(sess, link::write::run_passes(sess, trans, [output_type], outputs));
trans,
output_type,
&asm_filename));
link::write::run_assembler(sess, &asm_filename, &outputs.obj_filename); link::write::run_assembler(sess, outputs);
// Remove assembly source, unless --save-temps was specified // Remove assembly source, unless --save-temps was specified
if !sess.opts.save_temps { if !sess.opts.save_temps {
fs::unlink(&asm_filename).unwrap(); fs::unlink(&outputs.temp_path(link::OutputTypeAssembly)).unwrap();
} }
} else { } else {
time(sess.time_passes(), "LLVM passes", (), |_| time(sess.time_passes(), "LLVM passes", (), |_|
link::write::run_passes(sess, link::write::run_passes(sess,
trans, trans,
sess.opts.output_type, sess.opts.output_types,
&outputs.obj_filename)); outputs));
} }
} }
@ -416,8 +410,7 @@ pub fn phase_6_link_output(sess: Session,
time(sess.time_passes(), "linking", (), |_| time(sess.time_passes(), "linking", (), |_|
link::link_binary(sess, link::link_binary(sess,
trans, trans,
&outputs.obj_filename, outputs,
&outputs.out_filename,
&trans.link)); &trans.link));
} }
@ -446,24 +439,34 @@ pub fn stop_after_phase_2(sess: Session) -> bool {
} }
pub fn stop_after_phase_5(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"); debug!("not building executable, returning early from compile_input");
return true; return true;
} }
return false; return false;
} }
fn write_out_deps(sess: Session, input: &Input, outputs: &OutputFilenames, fn write_out_deps(sess: Session,
crate: &ast::Crate) -> io::IoResult<()> input: &Input,
{ outputs: &OutputFilenames,
let lm = link::build_link_meta(sess, crate.attrs, &outputs.obj_filename, crate: &ast::Crate) -> io::IoResult<()> {
let lm = link::build_link_meta(crate.attrs, outputs,
&mut ::util::sha2::Sha256::new()); &mut ::util::sha2::Sha256::new());
let sess_outputs = sess.outputs.borrow(); let mut out_filenames = ~[];
let out_filenames = sess_outputs.get().iter() for output_type in sess.opts.output_types.iter() {
.map(|&output| link::filename_for_input(&sess, output, &lm, let file = outputs.path(*output_type);
&outputs.out_filename)) match *output_type {
.to_owned_vec(); 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 // Write out dependency rules to the dep-info file if requested with
// --dep-info // --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 // Use default filename: crate source filename with extension replaced
// by ".d" // by ".d"
(true, None) => match *input { (true, None) => match *input {
FileInput(ref input_path) => { FileInput(..) => outputs.with_extension("d"),
let filestem = input_path.filestem().expect("input file must \
have stem");
let filename = out_filenames[0].dir_path().join(filestem);
filename.with_extension("d")
},
StrInput(..) => { StrInput(..) => {
sess.warn("can not write --dep-info without a filename \ sess.warn("can not write --dep-info without a filename \
when compiling stdin."); 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, let outputs = build_output_filenames(input, outdir, output,
expanded_crate.attrs, sess); 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; } if stop_after_phase_2(sess) { return; }
let analysis = phase_3_run_analysis_passes(sess, &expanded_crate, ast_map); let analysis = phase_3_run_analysis_passes(sess, &expanded_crate, ast_map);
if stop_after_phase_3(sess) { return; } if stop_after_phase_3(sess) { return; }
let trans = phase_4_translate_to_llvm(sess, expanded_crate, let trans = phase_4_translate_to_llvm(sess, expanded_crate,
&analysis, outputs); &analysis, &outputs);
(outputs, trans) (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; } if stop_after_phase_5(sess) { return; }
phase_6_link_output(sess, &trans, outputs); phase_6_link_output(sess, &trans, &outputs);
} }
struct IdentifiedAnnotation { struct IdentifiedAnnotation {
@ -735,22 +733,19 @@ pub fn build_session_options(binary: ~str,
matches: &getopts::Matches, matches: &getopts::Matches,
demitter: @diagnostic::Emitter) demitter: @diagnostic::Emitter)
-> @session::Options { -> @session::Options {
let mut outputs = ~[]; let crate_types = matches.opt_strs("crate-type").flat_map(|s| {
if matches.opt_present("lib") { s.split(',').map(|part| {
outputs.push(session::default_lib_output()); match part {
} "lib" => session::default_lib_output(),
if matches.opt_present("rlib") { "rlib" => session::CrateTypeRlib,
outputs.push(session::OutputRlib) "staticlib" => session::CrateTypeStaticlib,
} "dylib" => session::CrateTypeDylib,
if matches.opt_present("staticlib") { "bin" => session::CrateTypeExecutable,
outputs.push(session::OutputStaticlib) _ => early_error(demitter,
} format!("unknown crate type: `{}`", part))
if matches.opt_present("dylib") { }
outputs.push(session::OutputDylib) }).collect()
} });
if matches.opt_present("bin") {
outputs.push(session::OutputExecutable)
}
let parse_only = matches.opt_present("parse-only"); let parse_only = matches.opt_present("parse-only");
let no_trans = matches.opt_present("no-trans"); let no_trans = matches.opt_present("no-trans");
@ -801,19 +796,30 @@ pub fn build_session_options(binary: ~str,
unsafe { llvm::LLVMSetDebug(1); } unsafe { llvm::LLVMSetDebug(1); }
} }
let output_type = let mut output_types = if parse_only || no_trans {
if parse_only || no_trans { ~[]
link::OutputTypeNone } else {
} else if matches.opt_present("S") && matches.opt_strs("emit").flat_map(|s| {
matches.opt_present("emit-llvm") { s.split(',').map(|part| {
link::OutputTypeLlvmAssembly match part.as_slice() {
} else if matches.opt_present("S") { "asm" => link::OutputTypeAssembly,
link::OutputTypeAssembly "ir" => link::OutputTypeLlvmAssembly,
} else if matches.opt_present("c") { "bc" => link::OutputTypeBitcode,
link::OutputTypeObject "obj" => link::OutputTypeObject,
} else if matches.opt_present("emit-llvm") { "link" => link::OutputTypeExe,
link::OutputTypeBitcode _ => early_error(demitter,
} else { link::OutputTypeExe }; 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 sysroot_opt = matches.opt_str("sysroot").map(|m| @Path::new(m));
let target = matches.opt_str("target").unwrap_or(host_triple()); let target = matches.opt_str("target").unwrap_or(host_triple());
let target_cpu = matches.opt_str("target-cpu").unwrap_or(~"generic"); 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")); matches.opt_present("crate-file-name"));
let sopts = @session::Options { let sopts = @session::Options {
outputs: outputs, crate_types: crate_types,
gc: gc, gc: gc,
optimize: opt_level, optimize: opt_level,
custom_passes: custom_passes, custom_passes: custom_passes,
@ -895,7 +901,7 @@ pub fn build_session_options(binary: ~str,
extra_debuginfo: extra_debuginfo, extra_debuginfo: extra_debuginfo,
lint_opts: lint_opts, lint_opts: lint_opts,
save_temps: save_temps, save_temps: save_temps,
output_type: output_type, output_types: output_types,
addl_lib_search_paths: @RefCell::new(addl_lib_search_paths), addl_lib_search_paths: @RefCell::new(addl_lib_search_paths),
ar: ar, ar: ar,
linker: linker, linker: linker,
@ -972,7 +978,7 @@ pub fn build_session_(sopts: @session::Options,
working_dir: os::getcwd(), working_dir: os::getcwd(),
lints: RefCell::new(HashMap::new()), lints: RefCell::new(HashMap::new()),
node_id: Cell::new(1), 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 // rustc command line options
pub fn optgroups() -> ~[getopts::groups::OptGroup] { pub fn optgroups() -> ~[getopts::groups::OptGroup] {
~[ ~[
optflag("c", "", "Compile and assemble, but do not link"), optflag("h", "help", "Display this message"),
optmulti("", "cfg", "Configure the compilation optmulti("", "cfg", "Configure the compilation environment", "SPEC"),
environment", "SPEC"), optmulti("L", "", "Add a directory to the library search path", "PATH"),
optflag("", "emit-llvm", optmulti("", "crate-type", "Comma separated list of types of crates for the \
"Produce an LLVM assembly file if used with -S option; compiler to emit",
produce an LLVM bitcode file otherwise"), "[bin|lib|rlib|dylib|staticlib]"),
optflag("h", "help","Display this message"), optmulti("", "emit", "Comma separated list of types of output for the compiler
optmulti("L", "", "Add a directory to the library search path", to emit",
"PATH"), "[asm|bc|ir|obj|link]"),
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"),
optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"), 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"), optopt("", "ar", "Program to use for managing archives instead of the default.", "AR"),
optflag("", "crate-id", "Output the crate id and exit"), 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), typed (crates expanded, with type annotations),
or identified (fully parenthesized, or identified (fully parenthesized,
AST nodes and blocks with IDs)", "TYPE"), AST nodes and blocks with IDs)", "TYPE"),
optflag("S", "", "Compile only; do not assemble or link"),
optflagopt("", "dep-info", optflagopt("", "dep-info",
"Output dependency info to <filename> after compiling", "FILENAME"), "Output dependency info to <filename> after compiling", "FILENAME"),
optflag("", "save-temps", optflag("", "save-temps",
@ -1081,8 +1081,35 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] {
} }
pub struct OutputFilenames { pub struct OutputFilenames {
out_filename: Path, out_directory: Path,
obj_filename: 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, pub fn build_output_filenames(input: &Input,
@ -1090,83 +1117,53 @@ pub fn build_output_filenames(input: &Input,
ofile: &Option<Path>, ofile: &Option<Path>,
attrs: &[ast::Attribute], attrs: &[ast::Attribute],
sess: Session) sess: Session)
-> ~OutputFilenames { -> 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"
};
match *ofile { match *ofile {
None => { None => {
// "-" as input file will cause the parser to read from stdin so we // "-" as input file will cause the parser to read from stdin so we
// have to make up a name // have to make up a name
// We want to toss everything after the final '.' // We want to toss everything after the final '.'
let dirpath = match *odir { let dirpath = match *odir {
Some(ref d) => (*d).clone(), Some(ref d) => d.clone(),
None => match *input { None => os::getcwd(),
StrInput(_) => os::getcwd(), };
FileInput(ref ifile) => (*ifile).dir_path()
}
};
let mut stem = match *input { let mut stem = match *input {
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
FileInput(ref ifile) => { FileInput(ref ifile) => ifile.filestem_str().unwrap().to_str(),
(*ifile).filestem_str().unwrap().to_str() StrInput(_) => ~"rust_out"
} };
StrInput(_) => ~"rust_out"
};
// If a crateid is present, we use it as the link name // If a crateid is present, we use it as the link name
let crateid = attr::find_crateid(attrs); let crateid = attr::find_crateid(attrs);
match crateid { match crateid {
None => {} None => {}
Some(crateid) => stem = crateid.name.to_str(), Some(crateid) => stem = crateid.name.to_str(),
} }
OutputFilenames {
if sess.building_library.get() { out_directory: dirpath,
out_path = dirpath.join(os::dll_filename(stem)); out_filestem: stem,
obj_path = { single_output_file: None,
let mut p = dirpath.join(stem); }
p.set_extension(obj_suffix);
p
};
} else {
out_path = dirpath.join(stem);
obj_path = out_path.with_extension(obj_suffix);
}
}
Some(ref out_file) => {
out_path = out_file.clone();
obj_path = if stop_after_codegen {
out_file.clone()
} else {
out_file.with_extension(obj_suffix)
};
if sess.building_library.get() {
sess.warn("ignoring specified output filename for library.");
} }
if *odir != None { Some(ref out_file) => {
sess.warn("ignoring --out-dir flag due to -o flag."); 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
} }
} }

View File

@ -9,7 +9,6 @@
// except according to those terms. // except according to those terms.
use back::link;
use back::target_strs; use back::target_strs;
use back; use back;
use driver::driver::host_triple; use driver::driver::host_triple;
@ -139,7 +138,7 @@ pub enum OptLevel {
pub struct Options { pub struct Options {
// The crate config requested for the session, which may be combined // The crate config requested for the session, which may be combined
// with additional crate configurations during the compile process // with additional crate configurations during the compile process
outputs: ~[OutputStyle], crate_types: ~[CrateType],
gc: bool, gc: bool,
optimize: OptLevel, optimize: OptLevel,
@ -149,7 +148,7 @@ pub struct Options {
extra_debuginfo: bool, extra_debuginfo: bool,
lint_opts: ~[(lint::Lint, lint::level)], lint_opts: ~[(lint::Lint, lint::level)],
save_temps: bool, 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 // This was mutable for rustpkg, which updates search paths based on the
// parsed code. It remains mutable in case its replacements wants to use // parsed code. It remains mutable in case its replacements wants to use
// this. // this.
@ -192,11 +191,11 @@ pub enum EntryFnType {
} }
#[deriving(Eq, Clone, TotalOrd, TotalEq)] #[deriving(Eq, Clone, TotalOrd, TotalEq)]
pub enum OutputStyle { pub enum CrateType {
OutputExecutable, CrateTypeExecutable,
OutputDylib, CrateTypeDylib,
OutputRlib, CrateTypeRlib,
OutputStaticlib, CrateTypeStaticlib,
} }
pub struct Session_ { pub struct Session_ {
@ -219,7 +218,7 @@ pub struct Session_ {
lints: RefCell<HashMap<ast::NodeId, lints: RefCell<HashMap<ast::NodeId,
~[(lint::Lint, codemap::Span, ~str)]>>, ~[(lint::Lint, codemap::Span, ~str)]>>,
node_id: Cell<ast::NodeId>, node_id: Cell<ast::NodeId>,
outputs: @RefCell<~[OutputStyle]>, crate_types: @RefCell<~[CrateType]>,
} }
pub type Session = @Session_; pub type Session = @Session_;
@ -374,7 +373,7 @@ impl Session_ {
/// Some reasonable defaults /// Some reasonable defaults
pub fn basic_options() -> @Options { pub fn basic_options() -> @Options {
@Options { @Options {
outputs: ~[], crate_types: ~[],
gc: false, gc: false,
optimize: No, optimize: No,
custom_passes: ~[], custom_passes: ~[],
@ -383,7 +382,7 @@ pub fn basic_options() -> @Options {
extra_debuginfo: false, extra_debuginfo: false,
lint_opts: ~[], lint_opts: ~[],
save_temps: false, save_temps: false,
output_type: link::OutputTypeExe, output_types: ~[],
addl_lib_search_paths: @RefCell::new(HashSet::new()), addl_lib_search_paths: @RefCell::new(HashSet::new()),
ar: None, ar: None,
linker: 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 { pub fn building_library(options: &Options, crate: &ast::Crate) -> bool {
if options.test { return false } if options.test { return false }
for output in options.outputs.iter() { for output in options.crate_types.iter() {
match *output { match *output {
OutputExecutable => {} CrateTypeExecutable => {}
OutputStaticlib | OutputDylib | OutputRlib => return true CrateTypeStaticlib | CrateTypeDylib | CrateTypeRlib => return true
} }
} }
match syntax::attr::first_attr_value_str_by_name(crate.attrs, "crate_type") { 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 { pub fn default_lib_output() -> CrateType {
OutputRlib CrateTypeRlib
} }
pub fn collect_outputs(session: &Session, pub fn collect_crate_types(session: &Session,
attrs: &[ast::Attribute]) -> ~[OutputStyle] { attrs: &[ast::Attribute]) -> ~[CrateType] {
// If we're generating a test executable, then ignore all other output // If we're generating a test executable, then ignore all other output
// styles at all other locations // styles at all other locations
if session.opts.test { 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| { let mut iter = attrs.iter().filter_map(|a| {
if a.name().equiv(&("crate_type")) { if a.name().equiv(&("crate_type")) {
match a.value_str() { match a.value_str() {
Some(ref n) if n.equiv(&("rlib")) => Some(OutputRlib), Some(ref n) if n.equiv(&("rlib")) => Some(CrateTypeRlib),
Some(ref n) if n.equiv(&("dylib")) => Some(OutputDylib), Some(ref n) if n.equiv(&("dylib")) => Some(CrateTypeDylib),
Some(ref n) if n.equiv(&("lib")) => { Some(ref n) if n.equiv(&("lib")) => {
Some(default_lib_output()) Some(default_lib_output())
} }
Some(ref n) if n.equiv(&("staticlib")) => { 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(_) => { Some(_) => {
session.add_lint(lint::UnknownCrateType, session.add_lint(lint::UnknownCrateType,
ast::CRATE_NODE_ID, ast::CRATE_NODE_ID,
@ -473,7 +472,7 @@ pub fn collect_outputs(session: &Session,
}); });
base.extend(&mut iter); base.extend(&mut iter);
if base.len() == 0 { if base.len() == 0 {
base.push(OutputExecutable); base.push(CrateTypeExecutable);
} }
base.sort(); base.sort();
base.dedup(); base.dedup();

View File

@ -302,12 +302,12 @@ pub fn run_compiler(args: &[~str], demitter: @diagnostic::Emitter) {
} }
if crate_file_name { 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()); &mut ::util::sha2::Sha256::new());
let outputs = session::collect_outputs(&sess, attrs); let crate_types = session::collect_crate_types(&sess, attrs);
for &style in outputs.iter() { for &style in crate_types.iter() {
let fname = link::filename_for_input(&sess, style, &lm, let fname = link::filename_for_input(&sess, style, &lm,
&t_outputs.out_filename); &t_outputs.with_extension(""));
println!("{}", fname.filename_display()); println!("{}", fname.filename_display());
} }
} }

View File

@ -28,6 +28,7 @@ use back::link::{mangle_exported_name};
use back::{link, abi}; use back::{link, abi};
use driver::session; use driver::session;
use driver::session::Session; use driver::session::Session;
use driver::driver::OutputFilenames;
use driver::driver::{CrateAnalysis, CrateTranslation}; use driver::driver::{CrateAnalysis, CrateTranslation};
use lib::llvm::{ModuleRef, ValueRef, BasicBlockRef}; use lib::llvm::{ModuleRef, ValueRef, BasicBlockRef};
use lib::llvm::{llvm, True, Vector}; 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, pub fn trans_crate(sess: session::Session,
crate: ast::Crate, crate: ast::Crate,
analysis: &CrateAnalysis, analysis: &CrateAnalysis,
output: &Path) -> CrateTranslation { output: &OutputFilenames) -> CrateTranslation {
// Before we touch LLVM, make sure that multithreading is enabled. // Before we touch LLVM, make sure that multithreading is enabled.
unsafe { unsafe {
use sync::one::{Once, ONCE_INIT}; use sync::one::{Once, ONCE_INIT};
@ -2677,7 +2678,7 @@ pub fn trans_crate(sess: session::Session,
} }
let mut symbol_hasher = Sha256::new(); 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); &mut symbol_hasher);
// Append ".rs" to crate name as LLVM module identifier. // Append ".rs" to crate name as LLVM module identifier.

View File

@ -55,7 +55,7 @@ fn get_ast_and_resolve(cpath: &Path,
binary: ~"rustdoc", binary: ~"rustdoc",
maybe_sysroot: Some(@os::self_exe_path().unwrap().dir_path()), maybe_sysroot: Some(@os::self_exe_path().unwrap().dir_path()),
addl_lib_search_paths: @RefCell::new(libs), addl_lib_search_paths: @RefCell::new(libs),
outputs: ~[driver::session::OutputDylib], crate_types: ~[driver::session::CrateTypeDylib],
.. (*rustc::driver::session::basic_options()).clone() .. (*rustc::driver::session::basic_options()).clone()
}; };

View File

@ -18,6 +18,7 @@ use std::str;
use extra::tempfile::TempDir; use extra::tempfile::TempDir;
use extra::getopts; use extra::getopts;
use extra::test; use extra::test;
use rustc::back::link;
use rustc::driver::driver; use rustc::driver::driver;
use rustc::driver::session; use rustc::driver::session;
use rustc::metadata::creader::Loader; use rustc::metadata::creader::Loader;
@ -43,7 +44,7 @@ pub fn run(input: &str, matches: &getopts::Matches) -> int {
binary: ~"rustdoc", binary: ~"rustdoc",
maybe_sysroot: Some(@os::self_exe_path().unwrap().dir_path()), maybe_sysroot: Some(@os::self_exe_path().unwrap().dir_path()),
addl_lib_search_paths: libs, addl_lib_search_paths: libs,
outputs: ~[session::OutputDylib], crate_types: ~[session::CrateTypeDylib],
.. (*session::basic_options()).clone() .. (*session::basic_options()).clone()
}; };
@ -104,8 +105,9 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>) {
binary: ~"rustdoctest", binary: ~"rustdoctest",
maybe_sysroot: Some(@os::self_exe_path().unwrap().dir_path()), maybe_sysroot: Some(@os::self_exe_path().unwrap().dir_path()),
addl_lib_search_paths: @RefCell::new(libs), addl_lib_search_paths: @RefCell::new(libs),
outputs: ~[session::OutputExecutable], crate_types: ~[session::CrateTypeExecutable],
debugging_opts: session::PREFER_DYNAMIC, debugging_opts: session::PREFER_DYNAMIC,
output_types: ~[link::OutputTypeExe],
.. (*session::basic_options()).clone() .. (*session::basic_options()).clone()
}; };

View File

@ -4,7 +4,7 @@ all:
[ `$(RUSTC) --crate-id crate.rs` = "foo#0.10-pre" ] [ `$(RUSTC) --crate-id crate.rs` = "foo#0.10-pre" ]
[ `$(RUSTC) --crate-name crate.rs` = "foo" ] [ `$(RUSTC) --crate-name crate.rs` = "foo" ]
[ `$(RUSTC) --crate-file-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 --test lib.rs` = "mylib" ]
$(RUSTC) --crate-file-name lib.rs $(RUSTC) --crate-file-name lib.rs
$(RUSTC) --crate-file-name rlib.rs $(RUSTC) --crate-file-name rlib.rs

View File

@ -1,7 +1,7 @@
-include ../tools.mk -include ../tools.mk
all: 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 sleep 1
touch foo.rs touch foo.rs
-rm -f $(TMPDIR)/done -rm -f $(TMPDIR)/done

View 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): $(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 touch $(TMPDIR)/done
-include $(TMPDIR)/custom-deps-file.d -include $(TMPDIR)/custom-deps-file.d

View File

@ -1,7 +1,7 @@
-include ../tools.mk -include ../tools.mk
all: all:
$(RUSTC) --dep-info --lib lib.rs $(RUSTC) --dep-info --crate-type=lib lib.rs
sleep 1 sleep 1
touch foo.rs touch foo.rs
-rm -f $(TMPDIR)/done -rm -f $(TMPDIR)/done

View 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): $(TMPDIR)/$(LIB):
$(RUSTC) --dep-info --lib lib.rs $(RUSTC) --dep-info --crate-type=lib lib.rs
touch $(TMPDIR)/done touch $(TMPDIR)/done
-include $(TMPDIR)/lib.d -include $(TMPDIR)/foo.d

View File

@ -1,4 +1,4 @@
include ../tools.mk include ../tools.mk
all: all:
$(RUSTC) --rlib foo.rs $(RUSTC) --crate-type=rlib foo.rs

View File

@ -3,7 +3,7 @@
all: all:
$(RUSTC) rlib.rs $(RUSTC) rlib.rs
$(RUSTC) dylib.rs && exit 1 || exit 0 $(RUSTC) dylib.rs && exit 1 || exit 0
$(RUSTC) rlib.rs --dylib $(RUSTC) rlib.rs --crate-type=dylib
$(RUSTC) dylib.rs $(RUSTC) dylib.rs
rm $(call DYLIB,rlib-*) rm $(call DYLIB,rlib-*)
$(RUSTC) prog.rs && exit 1 || exit 0 $(RUSTC) prog.rs && exit 1 || exit 0

View File

@ -3,5 +3,5 @@
-include ../tools.mk -include ../tools.mk
all: all:
$(RUSTC) --rlib --test foo.rs $(RUSTC) --crate-type=rlib --test foo.rs
rm $(TMPDIR)/foo.bc && exit 1 || exit 0 rm $(TMPDIR)/foo.bc && exit 1 || exit 0

View File

@ -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)

View File

@ -0,0 +1,3 @@
#[crate_id = "bar"];
fn main() {}

View File

@ -1,7 +1,7 @@
-include ../tools.mk -include ../tools.mk
all: all:
$(RUSTC) bar.rs --dylib --rlib $(RUSTC) bar.rs --crate-type=dylib --crate-type=rlib
$(RUSTC) foo.rs -Z prefer-dynamic $(RUSTC) foo.rs -Z prefer-dynamic
$(call RUN,foo) $(call RUN,foo)
rm $(TMPDIR)/*bar* rm $(TMPDIR)/*bar*

View File

@ -1,7 +1,7 @@
-include ../tools.mk -include ../tools.mk
all: all:
$(RUSTC) bar.rs --dylib --rlib $(RUSTC) bar.rs --crate-type=dylib --crate-type=rlib
ls $(TMPDIR)/$(call RLIB_GLOB,bar) ls $(TMPDIR)/$(call RLIB_GLOB,bar)
$(RUSTC) foo.rs $(RUSTC) foo.rs
rm $(TMPDIR)/*bar* rm $(TMPDIR)/*bar*

View File

@ -1,5 +1,5 @@
-include ../tools.mk -include ../tools.mk
all: all:
$(RUSTC) bar.rs --dylib $(RUSTC) bar.rs --crate-type=dylib
$(RUSTC) foo.rs $(RUSTC) foo.rs
$(call RUN,foo) $(call RUN,foo)

View File

@ -1,5 +1,5 @@
-include ../tools.mk -include ../tools.mk
all: all:
$(RUSTC) bar.rs --rlib $(RUSTC) bar.rs --crate-type=rlib
$(RUSTC) foo.rs $(RUSTC) foo.rs
$(call RUN,foo) $(call RUN,foo)

View File

@ -5,6 +5,6 @@ all:
$(RUSTC) main.rs $(RUSTC) main.rs
$(call RUN,main) $(call RUN,main)
# ... and the loads/stores must not be optimized out. # ... 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 "load volatile" $(TMPDIR)/main.ll
grep "store volatile" $(TMPDIR)/main.ll grep "store volatile" $(TMPDIR)/main.ll