Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

rustc subcommand #1568

Merged
merged 12 commits into from
May 7, 2015
1 change: 1 addition & 0 deletions src/bin/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
&options.flag_test,
&options.flag_example,
&options.flag_bench),
target_rustc_args: None,
},
};

Expand Down
1 change: 1 addition & 0 deletions src/bin/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
&options.flag_test,
&options.flag_example,
&options.flag_bench),
target_rustc_args: None,
};

ops::compile(&root, &opts).map(|_| None).map_err(|err| {
Expand Down
1 change: 1 addition & 0 deletions src/bin/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ macro_rules! each_subcommand{ ($mac:ident) => ({
$mac!(publish);
$mac!(read_manifest);
$mac!(run);
$mac!(rustc);
$mac!(search);
$mac!(test);
$mac!(update);
Expand Down
1 change: 1 addition & 0 deletions src/bin/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
mode: ops::CompileMode::Doc {
deps: !options.flag_no_deps,
},
target_rustc_args: None,
},
};

Expand Down
1 change: 1 addition & 0 deletions src/bin/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
bins: &bins, examples: &examples,
}
},
target_rustc_args: None,
};

let err = try!(ops::run(&root,
Expand Down
96 changes: 96 additions & 0 deletions src/bin/rustc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use std::env;

use cargo::ops::CompileOptions;
use cargo::ops;
use cargo::util::important_paths::{find_root_manifest_for_cwd};
use cargo::util::{CliResult, CliError, Config};

#[derive(RustcDecodable)]
struct Options {
arg_pkgid: Option<String>,
arg_opts: Option<Vec<String>>,
flag_profile: Option<String>,
flag_jobs: Option<u32>,
flag_features: Vec<String>,
flag_no_default_features: bool,
flag_target: Option<String>,
flag_manifest_path: Option<String>,
flag_verbose: bool,
flag_release: bool,
flag_lib: bool,
flag_bin: Vec<String>,
flag_example: Vec<String>,
flag_test: Vec<String>,
flag_bench: Vec<String>,
}

pub const USAGE: &'static str = "
Compile a package and all of its dependencies

Usage:
cargo rustc [options] [<pkgid>] [--] [<opts>...]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah when I originally wrote this spec we didn't have a -p argument, but nowadays this <pkgid> argument should be specified through -p, --package instead.


Options:
-h, --help Print this message
-p, --profile PROFILE The profile to compile for
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I think that this flag (although I spec'd it originally) can just be removed

-j N, --jobs N The number of jobs to run in parallel
--lib Build only this package's library
--bin NAME Build only the specified binary
--example NAME Build only the specified example
--test NAME Build only the specified test
--bench NAME Build only the specified benchmark
--release Build artifacts in release mode, with optimizations
--features FEATURES Features to compile for the package
--no-default-features Do not compile default features for the package
--target TRIPLE Target triple which compiles will be for
--manifest-path PATH Path to the manifest to fetch depednencies for
-v, --verbose Use verbose output

The <pkgid> specified (defaults to the current package) will have all of its
dependencies compiled, and then the package itself will be compiled. This
command requires that a lockfile is available and dependencies have been
fetched.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this documentation may want to be touched up a bit, perhaps something along the lines of:

The specified target for the current package (or package specified by SPEC if provided) will be compiled along with all of its dependencies. The specified <opts>... will all be passed to the final compiler invocation, not any of the dependencies. Note that the compiler will still unconditionally receive arguments such as -L, --extern, and --crate-type, and the specified <opts>... will simply be added to the compiler invocation.

This command requires that only one target is being compiled. If more than one target is available for the current package the filters of --lib, --bin, etc, must be used to select which target is compiled.


All of the trailing arguments are passed through to the *final* rustc
invocation, not any of the dependencies.

Dependencies will not be recompiled if they do not need to be, but the package
specified will always be compiled. The compiler will receive a number of
arguments unconditionally such as --extern, -L, etc. Note that dependencies are
recompiled when the flags they're compiled with change, so it is not allowed to
manually compile a package's dependencies and then compile the package against
the artifacts just generated.
";

pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
debug!("executing; cmd=cargo-rustc; args={:?}",
env::args().collect::<Vec<_>>());
config.shell().set_verbose(options.flag_verbose);

let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
let spec = options.arg_pkgid.as_ref().map(|s| &s[..]);

let opts = CompileOptions {
config: config,
jobs: options.flag_jobs,
target: options.flag_target.as_ref().map(|t| &t[..]),
features: &options.flag_features,
no_default_features: options.flag_no_default_features,
spec: spec,
exec_engine: None,
mode: ops::CompileMode::Build,
release: options.flag_release,
filter: ops::CompileFilter::new(options.flag_lib,
&options.flag_bin,
&options.flag_test,
&options.flag_example,
&options.flag_bench),
target_rustc_args: options.arg_opts.as_ref().map(|a| &a[..]),
};

ops::compile(&root, &opts).map(|_| None).map_err(|err| {
CliError::from_boxed(err, 101)
})
}


1 change: 1 addition & 0 deletions src/bin/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
&options.flag_test,
&options.flag_example,
&options.flag_bench),
target_rustc_args: None,
},
};

Expand Down
7 changes: 6 additions & 1 deletion src/cargo/ops/cargo_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ pub struct CompileOptions<'a, 'b: 'a> {
pub release: bool,
/// Mode for this compile.
pub mode: CompileMode,
/// The specified target will be compiled with all the available arguments,
/// note that this only accounts for the *final* invocation of rustc
pub target_rustc_args: Option<&'a [String]>,
}

#[derive(Clone, Copy, PartialEq)]
Expand Down Expand Up @@ -102,7 +105,8 @@ pub fn compile_pkg(package: &Package, options: &CompileOptions)
-> CargoResult<ops::Compilation> {
let CompileOptions { config, jobs, target, spec, features,
no_default_features, release, mode,
ref filter, ref exec_engine } = *options;
ref filter, ref exec_engine,
ref target_rustc_args } = *options;

let target = target.map(|s| s.to_string());
let features = features.iter().flat_map(|s| {
Expand Down Expand Up @@ -168,6 +172,7 @@ pub fn compile_pkg(package: &Package, options: &CompileOptions)
let mut build_config = try!(scrape_build_config(config, jobs, target));
build_config.exec_engine = exec_engine.clone();
build_config.release = release;
build_config.target_rustc_args = target_rustc_args.map(|a| a.to_vec());
if let CompileMode::Doc { deps } = mode {
build_config.doc_all = deps;
}
Expand Down
1 change: 1 addition & 0 deletions src/cargo/ops/cargo_package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ fn run_verify(config: &Config, pkg: &Package, tar: &Path)
exec_engine: None,
release: false,
mode: ops::CompileMode::Build,
target_rustc_args: None,
}));

Ok(())
Expand Down
5 changes: 5 additions & 0 deletions src/cargo/ops/cargo_rustc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub struct BuildConfig {
pub exec_engine: Option<Arc<Box<ExecEngine>>>,
pub release: bool,
pub doc_all: bool,
pub target_rustc_args: Option<Vec<String>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it may be best to add this option to a Profile instead of the build configuration here (reflecting on this). Right now the custom arguments are passed to all crates in the dependency graph, but the command is tasked with only passing the arguments to the top-level command.

By using a Profile you can automatically set the extra arguments to an empty list for all profiles generated for dependencies, but the top-level profiles (generated in cargo_compile.rs) can have the arguments listed.

}

#[derive(Clone, Default)]
Expand Down Expand Up @@ -664,6 +665,10 @@ fn build_base_args(cx: &Context,
cmd.arg("-g");
}

if let Some(ref args) = cx.build_config.target_rustc_args {
cmd.args(args);
}

if debug_assertions && opt_level > 0 {
cmd.args(&["-C", "debug-assertions=on"]);
} else if !debug_assertions && opt_level == 0 {
Expand Down
93 changes: 93 additions & 0 deletions tests/test_cargo_rustc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use std::path::MAIN_SEPARATOR as SEP;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice suite of tests!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, what I would have liked is the ability to check the cargo ouput for not matches, e.g. modify the support::lines_match to also accept a [!..] wildcard, or something similar. By doing this we could check for [..] <opts>... [..] occurrences where we want the args to through, and make sure that the other compilations does not contain the extra args like [!..] <opts>... [!..].

use support::{execs, project, ProjectBuilder};
use support::{COMPILING, RUNNING};
use hamcrest::{assert_that};

fn setup() {
}

fn verbose_output_for_target(lib: bool, p: &ProjectBuilder) -> String {
let (target, kind) = match lib {
true => ("lib", "lib"),
false => ("main", "bin"),
};
format!("\
{compiling} {name} v{version} ({url})
{running} `rustc src{sep}{target}.rs --crate-name {name} --crate-type {kind} -g \
--out-dir {dir}{sep}target{sep}debug \
--emit=dep-info,link \
-L dependency={dir}{sep}target{sep}debug \
-L dependency={dir}{sep}target{sep}debug{sep}deps`
",
running = RUNNING, compiling = COMPILING, sep = SEP,
dir = p.root().display(), url = p.url(),
target = target, kind = kind,
name = "foo", version = "0.0.1")
}

fn verbose_output_for_target_with_args(lib: bool, p: &ProjectBuilder, args: &str) -> String {
verbose_output_for_target(lib, p).replace(" -g ", &format!(" -g {} ", args))
}

test!(build_lib_for_foo {
let p = project("foo")
.file("Cargo.toml", r#"
[package]

name = "foo"
version = "0.0.1"
authors = ["wycats@example.com"]
"#)
.file("src/main.rs", r#"
fn main() {}
"#)
.file("src/lib.rs", r#" "#);

assert_that(p.cargo_process("rustc").arg("--lib").arg("-v").arg("foo"),
execs()
.with_status(0)
.with_stdout(verbose_output_for_target(true, &p)));
});

test!(build_lib_and_allow_unstable_options {
let p = project("foo")
.file("Cargo.toml", r#"
[package]

name = "foo"
version = "0.0.1"
authors = ["wycats@example.com"]
"#)
.file("src/main.rs", r#"
fn main() {}
"#)
.file("src/lib.rs", r#" "#);

assert_that(p.cargo_process("rustc").arg("--lib").arg("-v").arg("foo")
.arg("--").arg("-Z").arg("unstable-options"),
execs()
.with_status(0)
.with_stdout(verbose_output_for_target_with_args(true, &p,
"-Z unstable-options")));
});

test!(build_main_and_allow_unstable_options {
let p = project("foo")
.file("Cargo.toml", r#"
[package]

name = "foo"
version = "0.0.1"
authors = ["wycats@example.com"]
"#)
.file("src/main.rs", r#"
fn main() {}
"#);

assert_that(p.cargo_process("rustc").arg("-v").arg("foo")
.arg("--").arg("-Z").arg("unstable-options"),
execs()
.with_status(0)
.with_stdout(verbose_output_for_target_with_args(false, &p,
"-Z unstable-options")));
});
1 change: 1 addition & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ mod test_cargo_profiles;
mod test_cargo_publish;
mod test_cargo_registry;
mod test_cargo_run;
mod test_cargo_rustc;
mod test_cargo_search;
mod test_cargo_test;
mod test_cargo_version;
Expand Down