cargo/tests/testsuite/build.rs

4762 lines
118 KiB
Rust
Raw Normal View History

2019-11-25 02:42:45 +00:00
//! Tests for the `cargo build` command.
2019-09-12 19:52:46 +00:00
use cargo::util::paths::dylib_path_envvar;
use cargo_test_support::paths::{root, CargoPathExt};
use cargo_test_support::registry::Package;
use cargo_test_support::{
basic_bin_manifest, basic_lib_manifest, basic_manifest, main_file, project, rustc_host,
2019-09-12 19:52:46 +00:00
sleep_ms, symlink_supported, t, Execs, ProjectBuilder,
};
2019-09-12 19:52:46 +00:00
use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
#[cargo_test]
fn cargo_compile_simple() {
let p = project()
2015-03-26 18:17:44 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
.build();
p.cargo("build").run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo").is_file());
2014-05-09 00:50:28 +00:00
p.process(&p.bin("foo")).with_stdout("i am foo\n").run();
}
#[cargo_test]
fn cargo_fail_with_no_stderr() {
let p = project()
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", &String::from("refusal"))
.build();
p.cargo("build --message-format=json")
.with_status(101)
.with_stderr_does_not_contain("--- stderr")
.run();
}
2019-02-03 04:01:23 +00:00
/// Checks that the `CARGO_INCREMENTAL` environment variable results in
2019-02-20 17:12:27 +00:00
/// `rustc` getting `-C incremental` passed to it.
#[cargo_test]
fn cargo_compile_incremental() {
let p = project()
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
.build();
p.cargo("build -v")
.env("CARGO_INCREMENTAL", "1")
.with_stderr_contains(
"[RUNNING] `rustc [..] -C incremental=[..]/target/debug/incremental[..]`\n",
2018-12-08 11:19:47 +00:00
)
.run();
2017-01-11 16:30:12 +00:00
p.cargo("test -v")
.env("CARGO_INCREMENTAL", "1")
.with_stderr_contains(
"[RUNNING] `rustc [..] -C incremental=[..]/target/debug/incremental[..]`\n",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn incremental_profile() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
[profile.dev]
incremental = false
[profile.release]
incremental = true
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("build -v")
.env_remove("CARGO_INCREMENTAL")
.with_stderr_does_not_contain("[..]C incremental=[..]")
.run();
p.cargo("build -v")
.env("CARGO_INCREMENTAL", "1")
.with_stderr_contains("[..]C incremental=[..]")
.run();
p.cargo("build --release -v")
.env_remove("CARGO_INCREMENTAL")
.with_stderr_contains("[..]C incremental=[..]")
.run();
p.cargo("build --release -v")
.env("CARGO_INCREMENTAL", "0")
.with_stderr_does_not_contain("[..]C incremental=[..]")
.run();
}
#[cargo_test]
fn incremental_config() {
let p = project()
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
".cargo/config",
r#"
[build]
incremental = false
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
p.cargo("build -v")
.env_remove("CARGO_INCREMENTAL")
.with_stderr_does_not_contain("[..]C incremental=[..]")
.run();
p.cargo("build -v")
.env("CARGO_INCREMENTAL", "1")
.with_stderr_contains("[..]C incremental=[..]")
.run();
}
#[cargo_test]
fn cargo_compile_with_workspace_excluded() {
let p = project().file("src/main.rs", "fn main() {}").build();
2019-08-12 12:31:20 +00:00
p.cargo("build --workspace --exclude foo")
.with_stderr_does_not_contain("[..]virtual[..]")
.with_stderr_contains("[..]no packages to compile")
.with_status(101)
.run();
}
#[cargo_test]
fn cargo_compile_manifest_path() {
let p = project()
2015-03-26 18:17:44 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
.build();
p.cargo("build --manifest-path foo/Cargo.toml")
.cwd(p.root().parent().unwrap())
.run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo").is_file());
}
#[cargo_test]
fn cargo_compile_with_invalid_manifest() {
let p = project().file("Cargo.toml", "").build();
2014-05-09 00:50:28 +00:00
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
virtual manifests must be configured with [workspace]
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn cargo_compile_with_invalid_manifest2() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r"
[project]
foo = bar
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
could not parse input as TOML
Caused by:
2019-08-13 17:37:40 +00:00
invalid number at line 3 column 19
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
}
2014-05-09 00:50:28 +00:00
#[cargo_test]
fn cargo_compile_with_invalid_manifest3() {
let p = project().file("src/Cargo.toml", "a = bar").build();
p.cargo("build --manifest-path src/Cargo.toml")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
could not parse input as TOML
Caused by:
2019-08-13 17:37:40 +00:00
invalid number at line 1 column 5
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
2016-07-10 17:29:31 +00:00
fn cargo_compile_duplicate_build_targets() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2016-07-10 17:29:31 +00:00
[package]
name = "foo"
version = "0.0.1"
authors = []
[lib]
name = "main"
2017-07-09 10:03:22 +00:00
path = "src/main.rs"
2016-07-10 17:29:31 +00:00
crate-type = ["dylib"]
[dependencies]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "#![allow(warnings)] fn main() {}")
.build();
2016-07-10 17:29:31 +00:00
p.cargo("build")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
warning: file found to be present in multiple build targets: [..]main.rs
[COMPILING] foo v0.0.1 ([..])
[FINISHED] [..]
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
2016-07-10 17:29:31 +00:00
}
#[cargo_test]
fn cargo_compile_with_invalid_version() {
let p = project()
2018-07-24 22:35:01 +00:00
.file("Cargo.toml", &basic_manifest("foo", "1.0"))
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
2018-07-24 22:35:01 +00:00
Expected dot for key `package.version`
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn cargo_compile_with_empty_package_name() {
let p = project()
2018-07-24 22:35:01 +00:00
.file("Cargo.toml", &basic_manifest("", "0.0.0"))
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
package name cannot be an empty string
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn cargo_compile_with_invalid_package_name() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo::bar", "0.0.0"))
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
invalid character `:` in package name: `foo::bar`, [..]
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn cargo_compile_with_invalid_bin_target_name() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
authors = []
version = "0.0.0"
[[bin]]
name = ""
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
2017-07-08 21:59:31 +00:00
binary target names cannot be empty
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn cargo_compile_with_forbidden_bin_target_name() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
authors = []
version = "0.0.0"
[[bin]]
name = "build"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
the binary target name `build` is forbidden
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn cargo_compile_with_bin_and_crate_type() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
authors = []
version = "0.0.0"
[[bin]]
name = "the_foo_bin"
path = "src/foo.rs"
crate-type = ["cdylib", "rlib"]
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/foo.rs", "fn main() {}")
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
the target `the_foo_bin` is a binary and can't have any crate-types set \
(currently \"cdylib, rlib\")",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn cargo_compile_with_bin_and_proc() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
authors = []
version = "0.0.0"
[[bin]]
name = "the_foo_bin"
path = "src/foo.rs"
proc-macro = true
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/foo.rs", "fn main() {}")
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
the target `the_foo_bin` is a binary and can't have `proc-macro` set `true`",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn cargo_compile_with_invalid_lib_target_name() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
authors = []
version = "0.0.0"
[lib]
name = ""
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
2017-07-08 21:59:31 +00:00
library target names cannot be empty
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn cargo_compile_with_invalid_non_numeric_dep_version() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
[dependencies]
crossbeam = "y"
"#,
2018-12-08 11:19:47 +00:00
)
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
"\
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
Caused by:
failed to parse the version requirement `y` for dependency `crossbeam`
Caused by:
the given version requirement is invalid
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn cargo_compile_without_manifest() {
let p = project().no_manifest().build();
2014-05-09 00:50:28 +00:00
p.cargo("build")
.with_status(101)
.with_stderr("[ERROR] could not find `Cargo.toml` in `[..]` or any parent directory")
.run();
}
#[cargo_test]
fn cargo_compile_with_invalid_code() {
let p = project()
2015-03-26 18:17:44 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", "invalid rust code!")
.build();
p.cargo("build")
.with_status(101)
.with_stderr_contains(
2018-03-14 15:17:44 +00:00
"\
[ERROR] could not compile `foo`.
2018-03-14 15:17:44 +00:00
To learn more, run the command again with --verbose.\n",
2018-12-08 11:19:47 +00:00
)
.run();
2018-08-29 06:11:10 +00:00
assert!(p.root().join("Cargo.lock").is_file());
}
#[cargo_test]
fn cargo_compile_with_invalid_code_in_deps() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "../bar"
[dependencies.baz]
path = "../baz"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "invalid rust code!")
.build();
let _bar = project()
.at("bar")
.file("Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("src/lib.rs", "invalid rust code!")
.build();
let _baz = project()
.at("baz")
.file("Cargo.toml", &basic_manifest("baz", "0.1.0"))
.file("src/lib.rs", "invalid rust code!")
.build();
p.cargo("build")
.with_status(101)
.with_stderr_contains("[..]invalid rust code[..]")
.with_stderr_contains("[ERROR] could not compile [..]")
.run();
}
#[cargo_test]
fn cargo_compile_with_warnings_in_the_root_package() {
let p = project()
2015-03-26 18:17:44 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", "fn main() {} fn dead() {}")
.build();
p.cargo("build")
.with_stderr_contains("[..]function is never used: `dead`[..]")
.run();
}
#[cargo_test]
fn cargo_compile_with_warnings_in_a_dep_package() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.bar]
path = "bar"
[[bin]]
name = "foo"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/foo.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"]))
2018-07-24 22:35:01 +00:00
.file("bar/Cargo.toml", &basic_lib_manifest("bar"))
2018-03-14 15:17:44 +00:00
.file(
"bar/src/bar.rs",
r#"
2015-01-13 16:41:04 +00:00
pub fn gimme() -> &'static str {
"test passed"
}
fn dead() {}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
p.cargo("build")
.with_stderr_contains("[..]function is never used: `dead`[..]")
.run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo").is_file());
p.process(&p.bin("foo")).with_stdout("test passed\n").run();
}
2014-05-09 00:50:28 +00:00
#[cargo_test]
fn cargo_compile_with_nested_deps_inferred() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2014-07-08 00:59:18 +00:00
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.bar]
path = 'bar'
2014-07-08 00:59:18 +00:00
[[bin]]
name = "foo"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/foo.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"]))
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
2014-07-08 00:59:18 +00:00
[project]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.baz]
path = "../baz"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"bar/src/lib.rs",
r#"
2014-07-08 00:59:18 +00:00
extern crate baz;
pub fn gimme() -> String {
baz::gimme()
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("baz/Cargo.toml", &basic_manifest("baz", "0.5.0"))
2018-03-14 15:17:44 +00:00
.file(
"baz/src/lib.rs",
r#"
2014-07-08 00:59:18 +00:00
pub fn gimme() -> String {
"test passed".to_string()
2014-07-08 00:59:18 +00:00
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
2014-07-08 00:59:18 +00:00
p.cargo("build").run();
2014-07-08 00:59:18 +00:00
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo").is_file());
assert!(!p.bin("libbar.rlib").is_file());
assert!(!p.bin("libbaz.rlib").is_file());
2014-07-08 00:59:18 +00:00
p.process(&p.bin("foo")).with_stdout("test passed\n").run();
}
2014-07-08 00:59:18 +00:00
#[cargo_test]
fn cargo_compile_with_nested_deps_correct_bin() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2014-07-08 00:59:18 +00:00
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.bar]
path = "bar"
2014-07-08 00:59:18 +00:00
[[bin]]
name = "foo"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"]))
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
2014-07-08 00:59:18 +00:00
[project]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.baz]
path = "../baz"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"bar/src/lib.rs",
r#"
2014-07-08 00:59:18 +00:00
extern crate baz;
pub fn gimme() -> String {
baz::gimme()
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("baz/Cargo.toml", &basic_manifest("baz", "0.5.0"))
2018-03-14 15:17:44 +00:00
.file(
"baz/src/lib.rs",
r#"
2014-07-08 00:59:18 +00:00
pub fn gimme() -> String {
"test passed".to_string()
2014-07-08 00:59:18 +00:00
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
2014-07-08 00:59:18 +00:00
p.cargo("build").run();
2014-07-08 00:59:18 +00:00
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo").is_file());
assert!(!p.bin("libbar.rlib").is_file());
assert!(!p.bin("libbaz.rlib").is_file());
2014-07-08 00:59:18 +00:00
p.process(&p.bin("foo")).with_stdout("test passed\n").run();
}
2014-07-08 00:59:18 +00:00
#[cargo_test]
fn cargo_compile_with_nested_deps_shorthand() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2014-05-08 23:49:58 +00:00
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.bar]
path = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"]))
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
2014-05-08 23:49:58 +00:00
[project]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.baz]
path = "../baz"
2014-05-08 23:49:58 +00:00
2014-08-14 06:08:02 +00:00
[lib]
2014-05-08 23:49:58 +00:00
name = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"bar/src/bar.rs",
r#"
2014-05-08 23:49:58 +00:00
extern crate baz;
2014-05-27 23:14:34 +00:00
pub fn gimme() -> String {
2014-05-08 23:49:58 +00:00
baz::gimme()
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("baz/Cargo.toml", &basic_lib_manifest("baz"))
2018-03-14 15:17:44 +00:00
.file(
"baz/src/baz.rs",
r#"
2014-05-27 23:14:34 +00:00
pub fn gimme() -> String {
"test passed".to_string()
2014-05-08 23:49:58 +00:00
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
2014-05-08 23:49:58 +00:00
p.cargo("build").run();
2014-05-08 23:49:58 +00:00
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo").is_file());
assert!(!p.bin("libbar.rlib").is_file());
assert!(!p.bin("libbaz.rlib").is_file());
2014-05-08 23:49:58 +00:00
p.process(&p.bin("foo")).with_stdout("test passed\n").run();
}
2014-05-08 23:49:58 +00:00
#[cargo_test]
fn cargo_compile_with_nested_deps_longhand() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
[dependencies.bar]
path = "bar"
version = "0.5.0"
[[bin]]
name = "foo"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/foo.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"]))
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.baz]
Implement a registry source # cargo upload The cargo-upload command will take the local package and upload it to the specified registry. The local package is uploaded as a tarball compressed with gzip under maximum compression. Most of this is done by just delegating to `cargo package` The host to upload to is specified, in order of priority, by a command line `--host` flag, the `registry.host` config key, and then the default registry. The default registry is still `example.com` The registry itself is still a work in progress, but the general plumbing for a command such as this would look like: 1. Ensure the local package has been compressed into an archive. 2. Fetch the relevant registry and login token from config files. 3. Ensure all dependencies for a package are listed as coming from the same registry. 4. Upload the archive to the registry with the login token. 5. The registry will verify the package is under 2MB (configurable). 6. The registry will upload the archive to S3, calculating a checksum in the process. 7. The registry will add an entry to the registry's index (a git repository). The entry will include the name of the package, the version uploaded, the checksum of the upload, and then the list of dependencies (name/version req) 8. The local `cargo upload` command will succeed. # cargo login Uploading requires a token from the api server, and this token follows the same config chain for the host except that there is no fallback. To implement login, the `cargo login` command is used. With 0 arguments, the command will request that a site be visited for a login token, and with an argument it will set the argument as the new login token. The `util::config` module was modified to allow writing configuration as well as reading it. The support is a little lacking in that comments are blown away, but the support is there at least. # RegistrySource An implementation of `RegistrySource` has been created (deleting the old `DummyRegistrySource`). This implementation only needs a URL to be constructed, and it is assumed that the URL is running an instance of the cargo registry. ## RegistrySource::update Currently this will unconditionally update the registry's index (a git repository). Tuning is necessary to prevent updating the index each time (more coming soon). ## RegistrySource::query This is called in the resolve phase of cargo. This function is given a dependency to query for, and the source will simply look into the index to see if any package with the name is present. If found, the package's index file will be loaded and parsed into a list of summaries. The main optimization of this function is to not require the entire registry to ever be resident in memory. Instead, only necessary packages are loaded into memory and parsed. ## RegistrySource::download This is also called during the resolve phase of cargo, but only when a package has been selected to be built (actually resolved). This phase of the source will actually download and unpack the tarball for the package. Currently a configuration file is located in the root of a registry's index describing the root url to download packages from. This function is optimized for two different metrics: 1. If a tarball is downloaded, it is not downloaded again. It is assumed that once a tarball is successfully downloaded it will never change. 2. If the unpacking destination has a `.cargo-ok` file, it is assumed that the unpacking has already occurred and does not need to happen again. With these in place, a rebuild should take almost no time at all. ## RegistrySource::get This function is simply implemented in terms of a PathSource's `get` function by creating a `PathSource` for all unpacked tarballs as part of the `download` stage. ## Filesystem layout There are a few new directories as part of the `.cargo` home folder: * `.cargo/registry/index/$hostname-$hash` - This is the directory containing the actual index of the registry. `$hostname` comes from its url, and `$hash` is the hash of the entire url. * `.cargo/registry/cache/$hostname-$hash/$pkg-$vers.tar.gz` - This is a directory used to cache the downloads of packages from the registry. * `.cargo/registry/src/$hostname-$hash/$pkg-$vers` - This is the location of the unpacked packages. They will be compiled from this location. # New Dependencies Cargo has picked up a new dependency on the `curl-rust` package in order to send HTTP requests to the registry as well as send HTTP requests to download tarballs.
2014-07-18 15:40:45 +00:00
path = "../baz"
version = "0.5.0"
2014-08-14 06:08:02 +00:00
[lib]
name = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"bar/src/bar.rs",
r#"
extern crate baz;
pub fn gimme() -> String {
baz::gimme()
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("baz/Cargo.toml", &basic_lib_manifest("baz"))
2018-03-14 15:17:44 +00:00
.file(
"baz/src/baz.rs",
r#"
pub fn gimme() -> String {
"test passed".to_string()
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
p.cargo("build").run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo").is_file());
assert!(!p.bin("libbar.rlib").is_file());
assert!(!p.bin("libbaz.rlib").is_file());
p.process(&p.bin("foo")).with_stdout("test passed\n").run();
}
// Check that Cargo gives a sensible error if a dependency can't be found
// because of a name mismatch.
#[cargo_test]
fn cargo_compile_with_dep_name_mismatch() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = ["wycats@example.com"]
[[bin]]
name = "foo"
[dependencies.notquitebar]
path = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/bin/foo.rs", &main_file(r#""i am foo""#, &["bar"]))
2015-03-26 18:17:44 +00:00
.file("bar/Cargo.toml", &basic_bin_manifest("bar"))
.file("bar/src/bar.rs", &main_file(r#""i am bar""#, &[]))
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
r#"error: no matching package named `notquitebar` found
location searched: [CWD]/bar
required by package `foo v0.0.1 ([CWD])`
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn cargo_compile_with_filename() {
let p = project()
.file("src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"src/bin/a.rs",
r#"
extern crate foo;
fn main() { println!("hello a.rs"); }
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("examples/a.rs", r#"fn main() { println!("example"); }"#)
.build();
p.cargo("build --bin bin.rs")
.with_status(101)
.with_stderr("[ERROR] no bin target named `bin.rs`")
.run();
p.cargo("build --bin a.rs")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] no bin target named `a.rs`
2019-06-21 18:36:53 +00:00
<tab>Did you mean `a`?",
2018-12-08 11:19:47 +00:00
)
.run();
p.cargo("build --example example.rs")
.with_status(101)
.with_stderr("[ERROR] no example target named `example.rs`")
.run();
p.cargo("build --example a.rs")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] no example target named `a.rs`
2019-06-21 18:36:53 +00:00
<tab>Did you mean `a`?",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn incompatible_dependencies() {
Package::new("bad", "0.1.0").publish();
Package::new("bad", "1.0.0").publish();
Package::new("bad", "1.0.1").publish();
Package::new("bad", "1.0.2").publish();
Package::new("bar", "0.1.0").dep("bad", "0.1.0").publish();
Package::new("baz", "0.1.1").dep("bad", "=1.0.0").publish();
Package::new("baz", "0.1.0").dep("bad", "=1.0.0").publish();
Package::new("qux", "0.1.2").dep("bad", ">=1.0.1").publish();
Package::new("qux", "0.1.1").dep("bad", ">=1.0.1").publish();
Package::new("qux", "0.1.0").dep("bad", ">=1.0.1").publish();
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
[dependencies]
bar = "0.1.0"
baz = "0.1.0"
qux = "0.1.0"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "fn main(){}")
.build();
p.cargo("build")
.with_status(101)
.with_stderr_contains(
2018-03-14 15:17:44 +00:00
"\
error: failed to select a version for `bad`.
... required by package `qux v0.1.0`
... which is depended on by `foo v0.0.1 ([..])`
2018-02-15 03:28:59 +00:00
versions that meet the requirements `>= 1.0.1` are: 1.0.2, 1.0.1
all possible versions conflict with previously selected packages.
2018-02-07 16:51:40 +00:00
previously selected package `bad v1.0.0`
... which is depended on by `baz v0.1.0`
... which is depended on by `foo v0.0.1 ([..])`
2018-02-15 03:28:59 +00:00
2018-03-14 15:17:44 +00:00
failed to select a version for `bad` which could resolve this conflict",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn incompatible_dependencies_with_multi_semver() {
Package::new("bad", "1.0.0").publish();
Package::new("bad", "1.0.1").publish();
Package::new("bad", "2.0.0").publish();
Package::new("bad", "2.0.1").publish();
Package::new("bar", "0.1.0").dep("bad", "=1.0.0").publish();
Package::new("baz", "0.1.0").dep("bad", ">=2.0.1").publish();
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
[dependencies]
bar = "0.1.0"
baz = "0.1.0"
bad = ">=1.0.1, <=2.0.0"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "fn main(){}")
.build();
p.cargo("build")
.with_status(101)
.with_stderr_contains(
2018-03-14 15:17:44 +00:00
"\
error: failed to select a version for `bad`.
... required by package `foo v0.0.1 ([..])`
2018-02-15 03:28:59 +00:00
versions that meet the requirements `>= 1.0.1, <= 2.0.0` are: 2.0.0, 1.0.1
all possible versions conflict with previously selected packages.
2018-02-15 03:28:59 +00:00
previously selected package `bad v2.0.1`
... which is depended on by `baz v0.1.0`
... which is depended on by `foo v0.0.1 ([..])`
2018-02-15 03:28:59 +00:00
previously selected package `bad v1.0.0`
... which is depended on by `bar v0.1.0`
... which is depended on by `foo v0.0.1 ([..])`
2018-02-15 03:28:59 +00:00
2018-03-14 15:17:44 +00:00
failed to select a version for `bad` which could resolve this conflict",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn compile_path_dep_then_change_version() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
2018-07-24 22:35:01 +00:00
.file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file("bar/src/lib.rs", "")
.build();
p.cargo("build").run();
2018-03-14 15:17:44 +00:00
File::create(&p.root().join("bar/Cargo.toml"))
.unwrap()
2018-07-24 22:35:01 +00:00
.write_all(basic_manifest("bar", "0.0.2").as_bytes())
2018-03-14 15:17:44 +00:00
.unwrap();
p.cargo("build").run();
}
#[cargo_test]
fn ignores_carriage_return_in_lockfile() {
let p = project()
.file("src/main.rs", r"mod a; fn main() {}")
.file("src/a.rs", "")
.build();
p.cargo("build").run();
let lockfile = p.root().join("Cargo.lock");
let mut lock = String::new();
2018-03-14 15:17:44 +00:00
File::open(&lockfile)
.unwrap()
.read_to_string(&mut lock)
.unwrap();
let lock = lock.replace("\n", "\r\n");
2018-03-14 15:17:44 +00:00
File::create(&lockfile)
.unwrap()
.write_all(lock.as_bytes())
.unwrap();
p.cargo("build").run();
}
#[cargo_test]
fn cargo_default_env_metadata_env_var() {
// Ensure that path dep + dylib + env_var get metadata
// (even though path_dep + dylib should not)
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "// hi")
2018-03-14 15:17:44 +00:00
.file(
"bar/Cargo.toml",
r#"
[package]
name = "bar"
version = "0.0.1"
authors = []
[lib]
name = "bar"
crate_type = ["dylib"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("bar/src/lib.rs", "// hello")
.build();
// No metadata on libbar since it's a dylib path dependency
p.cargo("build -v")
.with_stderr(&format!(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] bar v0.0.1 ([CWD]/bar)
2019-09-25 01:17:36 +00:00
[RUNNING] `rustc --crate-name bar bar/src/lib.rs [..]--crate-type dylib \
--emit=[..]link \
-C prefer-dynamic -C debuginfo=2 \
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps`
[COMPILING] foo v0.0.1 ([CWD])
2019-09-25 01:17:36 +00:00
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
--emit=[..]link -C debuginfo=2 \
-C metadata=[..] \
-C extra-filename=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps \
--extern bar=[CWD]/target/debug/deps/{prefix}bar{suffix}`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
2018-03-14 15:17:44 +00:00
prefix = env::consts::DLL_PREFIX,
suffix = env::consts::DLL_SUFFIX,
2018-12-08 11:19:47 +00:00
))
.run();
p.cargo("clean").run();
// If you set the env-var, then we expect metadata on libbar
p.cargo("build -v")
.env("__CARGO_DEFAULT_LIB_METADATA", "stable")
.with_stderr(&format!(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] bar v0.0.1 ([CWD]/bar)
2019-09-25 01:17:36 +00:00
[RUNNING] `rustc --crate-name bar bar/src/lib.rs [..]--crate-type dylib \
--emit=[..]link \
-C prefer-dynamic -C debuginfo=2 \
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps`
[COMPILING] foo v0.0.1 ([CWD])
2019-09-25 01:17:36 +00:00
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
--emit=[..]link -C debuginfo=2 \
-C metadata=[..] \
-C extra-filename=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps \
--extern bar=[CWD]/target/debug/deps/{prefix}bar-[..]{suffix}`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
2018-03-14 15:17:44 +00:00
prefix = env::consts::DLL_PREFIX,
suffix = env::consts::DLL_SUFFIX,
2018-12-08 11:19:47 +00:00
))
.run();
}
#[cargo_test]
fn crate_env_vars() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.5.1-alpha.1"
description = "This is foo"
2019-01-30 20:34:37 +00:00
homepage = "https://example.com"
repository = "https://example.com/repo.git"
authors = ["wycats@example.com"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"src/main.rs",
r#"
extern crate foo;
2014-07-24 00:57:49 +00:00
static VERSION_MAJOR: &'static str = env!("CARGO_PKG_VERSION_MAJOR");
static VERSION_MINOR: &'static str = env!("CARGO_PKG_VERSION_MINOR");
static VERSION_PATCH: &'static str = env!("CARGO_PKG_VERSION_PATCH");
static VERSION_PRE: &'static str = env!("CARGO_PKG_VERSION_PRE");
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
static CARGO_MANIFEST_DIR: &'static str = env!("CARGO_MANIFEST_DIR");
static PKG_NAME: &'static str = env!("CARGO_PKG_NAME");
static HOMEPAGE: &'static str = env!("CARGO_PKG_HOMEPAGE");
static REPOSITORY: &'static str = env!("CARGO_PKG_REPOSITORY");
static DESCRIPTION: &'static str = env!("CARGO_PKG_DESCRIPTION");
2014-07-24 00:57:49 +00:00
fn main() {
let s = format!("{}-{}-{} @ {} in {}", VERSION_MAJOR,
VERSION_MINOR, VERSION_PATCH, VERSION_PRE,
CARGO_MANIFEST_DIR);
assert_eq!(s, foo::version());
println!("{}", s);
assert_eq!("foo", PKG_NAME);
2019-01-30 20:34:37 +00:00
assert_eq!("https://example.com", HOMEPAGE);
assert_eq!("https://example.com/repo.git", REPOSITORY);
assert_eq!("This is foo", DESCRIPTION);
let s = format!("{}.{}.{}-{}", VERSION_MAJOR,
VERSION_MINOR, VERSION_PATCH, VERSION_PRE);
assert_eq!(s, VERSION);
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"src/lib.rs",
r#"
pub fn version() -> String {
format!("{}-{}-{} @ {} in {}",
env!("CARGO_PKG_VERSION_MAJOR"),
env!("CARGO_PKG_VERSION_MINOR"),
env!("CARGO_PKG_VERSION_PATCH"),
env!("CARGO_PKG_VERSION_PRE"),
env!("CARGO_MANIFEST_DIR"))
2014-07-24 00:57:49 +00:00
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
2014-07-24 00:57:49 +00:00
Overhaul how cargo treats profiles This commit is a complete overhaul of how Cargo handles compilation profiles internally. The external interface of Cargo is not affected by this change. Previously each Target had a Profile embedded within it. Conceptually a Target is an entry in the manifest (a binary, benchmark, etc) and a Profile controlled various flags (e.g. --test, -C opt-level, etc). Each Package then contained many profiles for each possible compilation mode. For example a Package would have one target for testing a library, benchmarking a library, documenting a library, etc. When it came to building these targets, Cargo would filter out the targets listed to determine what needed to be built. This filtering was largely done based off an "environment" represented as a string. Each mode of compilation got a separate environment string like `"test"` or `"bench"`. Altogether, however, this approach had a number of drawbacks: * Examples in release mode do not currently work. This is due to how examples are classified and how release mode is handled (e.g. the "release" environment where examples are meant to be built in the "test" environment). * It is not trivial to implement `cargo test --release` today. * It is not trivial to implement `cargo build --bin foo` where *only* the binary `foo` is built. The same is true for examples. * It is not trivial to add selective building of a number of binaries/examples/etc. * Filtering the list of targets to build has some pretty hokey logic that involves pseudo-environments like "doc-all" vs "doc". This logic is duplicated in a few places and in general is quite brittle. * The TOML parser greatly affects compilation due to the time at which profiles are generated, which seems somewhat backwards. * Profiles must be overridden, but only partially, at compile time becuase only the top-level package's profile is applied. In general, this system just needed an overhaul. This commit made a single change of separating `Profile` from `Target` and then basically hit `make` until all the tests passed again. The other large architectural changes are: * Environment strings are now entirely gone. * Filters are implemented in a much more robust fashion. * Release mode is now handled much more gracefully. * The unit of compilation in the backend is no longer (package, target) but rather (package, target, profile). This change had to be propagated many location in the `cargo_rustc` module. * The backend does not filter targets to build *at all*. All filtering now happens entirely in the frontend. I'll test issues after this change lands, but the motivation behind this is to open the door to quickly fixing a number of outstanding issues against Cargo. This change itself is not intended to close many bugs.
2015-02-19 19:30:35 +00:00
println!("build");
p.cargo("build -v").run();
2014-07-24 00:57:49 +00:00
Overhaul how cargo treats profiles This commit is a complete overhaul of how Cargo handles compilation profiles internally. The external interface of Cargo is not affected by this change. Previously each Target had a Profile embedded within it. Conceptually a Target is an entry in the manifest (a binary, benchmark, etc) and a Profile controlled various flags (e.g. --test, -C opt-level, etc). Each Package then contained many profiles for each possible compilation mode. For example a Package would have one target for testing a library, benchmarking a library, documenting a library, etc. When it came to building these targets, Cargo would filter out the targets listed to determine what needed to be built. This filtering was largely done based off an "environment" represented as a string. Each mode of compilation got a separate environment string like `"test"` or `"bench"`. Altogether, however, this approach had a number of drawbacks: * Examples in release mode do not currently work. This is due to how examples are classified and how release mode is handled (e.g. the "release" environment where examples are meant to be built in the "test" environment). * It is not trivial to implement `cargo test --release` today. * It is not trivial to implement `cargo build --bin foo` where *only* the binary `foo` is built. The same is true for examples. * It is not trivial to add selective building of a number of binaries/examples/etc. * Filtering the list of targets to build has some pretty hokey logic that involves pseudo-environments like "doc-all" vs "doc". This logic is duplicated in a few places and in general is quite brittle. * The TOML parser greatly affects compilation due to the time at which profiles are generated, which seems somewhat backwards. * Profiles must be overridden, but only partially, at compile time becuase only the top-level package's profile is applied. In general, this system just needed an overhaul. This commit made a single change of separating `Profile` from `Target` and then basically hit `make` until all the tests passed again. The other large architectural changes are: * Environment strings are now entirely gone. * Filters are implemented in a much more robust fashion. * Release mode is now handled much more gracefully. * The unit of compilation in the backend is no longer (package, target) but rather (package, target, profile). This change had to be propagated many location in the `cargo_rustc` module. * The backend does not filter targets to build *at all*. All filtering now happens entirely in the frontend. I'll test issues after this change lands, but the motivation behind this is to open the door to quickly fixing a number of outstanding issues against Cargo. This change itself is not intended to close many bugs.
2015-02-19 19:30:35 +00:00
println!("bin");
2018-12-08 11:19:47 +00:00
p.process(&p.bin("foo"))
.with_stdout("0-5-1 @ alpha.1 in [CWD]")
.run();
Overhaul how cargo treats profiles This commit is a complete overhaul of how Cargo handles compilation profiles internally. The external interface of Cargo is not affected by this change. Previously each Target had a Profile embedded within it. Conceptually a Target is an entry in the manifest (a binary, benchmark, etc) and a Profile controlled various flags (e.g. --test, -C opt-level, etc). Each Package then contained many profiles for each possible compilation mode. For example a Package would have one target for testing a library, benchmarking a library, documenting a library, etc. When it came to building these targets, Cargo would filter out the targets listed to determine what needed to be built. This filtering was largely done based off an "environment" represented as a string. Each mode of compilation got a separate environment string like `"test"` or `"bench"`. Altogether, however, this approach had a number of drawbacks: * Examples in release mode do not currently work. This is due to how examples are classified and how release mode is handled (e.g. the "release" environment where examples are meant to be built in the "test" environment). * It is not trivial to implement `cargo test --release` today. * It is not trivial to implement `cargo build --bin foo` where *only* the binary `foo` is built. The same is true for examples. * It is not trivial to add selective building of a number of binaries/examples/etc. * Filtering the list of targets to build has some pretty hokey logic that involves pseudo-environments like "doc-all" vs "doc". This logic is duplicated in a few places and in general is quite brittle. * The TOML parser greatly affects compilation due to the time at which profiles are generated, which seems somewhat backwards. * Profiles must be overridden, but only partially, at compile time becuase only the top-level package's profile is applied. In general, this system just needed an overhaul. This commit made a single change of separating `Profile` from `Target` and then basically hit `make` until all the tests passed again. The other large architectural changes are: * Environment strings are now entirely gone. * Filters are implemented in a much more robust fashion. * Release mode is now handled much more gracefully. * The unit of compilation in the backend is no longer (package, target) but rather (package, target, profile). This change had to be propagated many location in the `cargo_rustc` module. * The backend does not filter targets to build *at all*. All filtering now happens entirely in the frontend. I'll test issues after this change lands, but the motivation behind this is to open the door to quickly fixing a number of outstanding issues against Cargo. This change itself is not intended to close many bugs.
2015-02-19 19:30:35 +00:00
println!("test");
p.cargo("test -v").run();
}
2014-07-24 00:57:49 +00:00
#[cargo_test]
fn crate_authors_env_vars() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.5.1-alpha.1"
authors = ["wycats@example.com", "neikos@example.com"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"src/main.rs",
r#"
extern crate foo;
static AUTHORS: &'static str = env!("CARGO_PKG_AUTHORS");
fn main() {
let s = "wycats@example.com:neikos@example.com";
assert_eq!(AUTHORS, foo::authors());
println!("{}", AUTHORS);
assert_eq!(s, AUTHORS);
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"src/lib.rs",
r#"
pub fn authors() -> String {
format!("{}", env!("CARGO_PKG_AUTHORS"))
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
println!("build");
p.cargo("build -v").run();
println!("bin");
p.process(&p.bin("foo"))
.with_stdout("wycats@example.com:neikos@example.com")
.run();
println!("test");
p.cargo("test -v").run();
}
#[cargo_test]
fn vv_prints_rustc_env_vars() {
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = ["escape='\"@example.com"]
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
let mut b = p.cargo("build -vv");
if cfg!(windows) {
b.with_stderr_contains(
"[RUNNING] `[..]set CARGO_PKG_NAME=foo&& [..]rustc [..]`"
).with_stderr_contains(
r#"[RUNNING] `[..]set CARGO_PKG_AUTHORS="escape='\"@example.com"&& [..]rustc [..]`"#
)
} else {
2019-01-27 13:39:49 +00:00
b.with_stderr_contains("[RUNNING] `[..]CARGO_PKG_NAME=foo [..]rustc [..]`")
.with_stderr_contains(
r#"[RUNNING] `[..]CARGO_PKG_AUTHORS='escape='\''"@example.com' [..]rustc [..]`"#,
)
};
b.run();
}
// The tester may already have LD_LIBRARY_PATH=::/foo/bar which leads to a false positive error
fn setenv_for_removing_empty_component(mut execs: Execs) -> Execs {
let v = dylib_path_envvar();
if let Ok(search_path) = env::var(v) {
let new_search_path =
env::join_paths(env::split_paths(&search_path).filter(|e| !e.as_os_str().is_empty()))
.expect("join_paths");
execs.env(v, new_search_path); // build_command() will override LD_LIBRARY_PATH accordingly
}
execs
}
// Regression test for #4277
#[cargo_test]
fn crate_library_path_env_var() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"src/main.rs",
&format!(
r##"
fn main() {{
let search_path = env!("{}");
let paths = std::env::split_paths(&search_path).collect::<Vec<_>>();
assert!(!paths.contains(&"".into()));
}}
2018-03-14 15:17:44 +00:00
"##,
dylib_path_envvar()
),
2018-12-08 11:19:47 +00:00
)
.build();
setenv_for_removing_empty_component(p.cargo("run")).run();
}
// Regression test for #4277
#[cargo_test]
fn build_with_fake_libc_not_loading() {
let p = project()
.file("src/main.rs", "fn main() {}")
.file("src/lib.rs", r#" "#)
.file("libc.so.6", r#""#)
.build();
setenv_for_removing_empty_component(p.cargo("build")).run();
}
2014-07-08 00:59:18 +00:00
// this is testing that src/<pkg-name>.rs still works (for now)
#[cargo_test]
fn many_crate_types_old_style_lib_location() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
2014-08-14 06:08:02 +00:00
[lib]
name = "foo"
crate_type = ["rlib", "dylib"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/foo.rs", "pub fn foo() {}")
.build();
p.cargo("build")
.with_stderr_contains(
2018-03-14 15:17:44 +00:00
"\
2018-08-02 09:18:48 +00:00
[WARNING] path `[..]src/foo.rs` was erroneously implicitly accepted for library `foo`,
2018-03-14 15:17:44 +00:00
please rename the file to `src/lib.rs` or set lib.path in Cargo.toml",
2018-12-08 11:19:47 +00:00
)
.run();
2018-08-29 06:11:10 +00:00
assert!(p.root().join("target/debug/libfoo.rlib").is_file());
2018-03-14 15:17:44 +00:00
let fname = format!("{}foo{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX);
2018-08-29 06:11:10 +00:00
assert!(p.root().join("target/debug").join(&fname).is_file());
}
2014-07-08 00:59:18 +00:00
#[cargo_test]
fn many_crate_types_correct() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2014-07-08 00:59:18 +00:00
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
2014-08-14 06:08:02 +00:00
[lib]
2014-07-08 00:59:18 +00:00
name = "foo"
crate_type = ["rlib", "dylib"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "pub fn foo() {}")
.build();
p.cargo("build").run();
2018-08-29 06:11:10 +00:00
assert!(p.root().join("target/debug/libfoo.rlib").is_file());
2018-03-14 15:17:44 +00:00
let fname = format!("{}foo{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX);
2018-08-29 06:11:10 +00:00
assert!(p.root().join("target/debug").join(&fname).is_file());
}
2014-06-27 05:53:05 +00:00
#[cargo_test]
fn self_dependency() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "test"
version = "0.0.0"
authors = []
[dependencies.test]
path = "."
2014-08-14 06:08:02 +00:00
[lib]
name = "test"
2017-07-09 10:03:22 +00:00
path = "src/test.rs"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/test.rs", "fn main() {}")
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] cyclic package dependency: package `test v0.0.0 ([CWD])` depends on itself. Cycle:
package `test v0.0.0 ([CWD])`
... which is depended on by `test v0.0.0 ([..])`",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
/// Make sure broken symlinks don't break the build
///
/// This test requires you to be able to make symlinks.
/// For windows, this may require you to enable developer mode.
fn ignore_broken_symlinks() {
if !symlink_supported() {
return;
}
let p = project()
2015-03-26 18:17:44 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
.symlink("Notafile", "bar")
.build();
p.cargo("build").run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo").is_file());
p.process(&p.bin("foo")).with_stdout("i am foo\n").run();
}
#[cargo_test]
fn missing_lib_and_bin() {
2018-07-24 13:01:56 +00:00
let p = project().build();
p.cargo("build")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]Cargo.toml`
Caused by:
no targets specified in the manifest
2018-03-14 15:17:44 +00:00
either src/lib.rs, src/main.rs, a [lib] section, or [[bin]] section must be present\n",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn lto_build() {
// FIXME: currently this hits a linker bug on 32-bit MSVC
if cfg!(all(target_env = "msvc", target_pointer_width = "32")) {
2018-03-14 15:17:44 +00:00
return;
}
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "test"
version = "0.0.0"
authors = []
2014-11-14 16:49:01 +00:00
[profile.release]
lto = true
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("build -v --release")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] test v0.0.0 ([CWD])
2019-09-25 01:17:36 +00:00
[RUNNING] `rustc --crate-name test src/main.rs [..]--crate-type bin \
--emit=[..]link \
2014-12-21 18:45:39 +00:00
-C opt-level=3 \
-C lto \
-C metadata=[..] \
--out-dir [CWD]/target/release/deps \
-L dependency=[CWD]/target/release/deps`
[FINISHED] release [optimized] target(s) in [..]
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn verbose_build() {
let p = project().file("src/lib.rs", "").build();
p.cargo("build -v")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] foo v0.0.1 ([CWD])
2019-09-25 01:17:36 +00:00
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
--emit=[..]link -C debuginfo=2 \
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn verbose_release_build() {
let p = project().file("src/lib.rs", "").build();
p.cargo("build -v --release")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] foo v0.0.1 ([CWD])
2019-09-25 01:17:36 +00:00
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
--emit=[..]link \
2014-12-21 18:45:39 +00:00
-C opt-level=3 \
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/release/deps`
[FINISHED] release [optimized] target(s) in [..]
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn verbose_release_build_deps() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "test"
version = "0.0.0"
authors = []
[dependencies.foo]
path = "foo"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"foo/Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.0"
authors = []
2014-08-14 06:08:02 +00:00
[lib]
name = "foo"
crate_type = ["dylib", "rlib"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("foo/src/lib.rs", "")
.build();
p.cargo("build -v --release")
.with_stderr(&format!(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] foo v0.0.0 ([CWD]/foo)
2019-09-25 01:17:36 +00:00
[RUNNING] `rustc --crate-name foo foo/src/lib.rs [..]\
2017-01-03 21:22:58 +00:00
--crate-type dylib --crate-type rlib \
--emit=[..]link \
2017-01-03 21:22:58 +00:00
-C prefer-dynamic \
2014-12-21 18:45:39 +00:00
-C opt-level=3 \
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/release/deps`
[COMPILING] test v0.0.0 ([CWD])
2019-09-25 01:17:36 +00:00
[RUNNING] `rustc --crate-name test src/lib.rs [..]--crate-type lib \
--emit=[..]link \
2014-12-21 18:45:39 +00:00
-C opt-level=3 \
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/release/deps \
--extern foo=[CWD]/target/release/deps/{prefix}foo{suffix} \
--extern foo=[CWD]/target/release/deps/libfoo.rlib`
[FINISHED] release [optimized] target(s) in [..]
",
2018-03-14 15:17:44 +00:00
prefix = env::consts::DLL_PREFIX,
suffix = env::consts::DLL_SUFFIX
2018-12-08 11:19:47 +00:00
))
.run();
}
2014-07-10 22:13:53 +00:00
#[cargo_test]
fn explicit_examples() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2014-07-10 22:13:53 +00:00
[package]
name = "foo"
2014-07-10 22:13:53 +00:00
version = "1.0.0"
authors = []
2014-08-14 06:08:02 +00:00
[lib]
name = "foo"
2014-07-10 22:13:53 +00:00
path = "src/lib.rs"
[[example]]
name = "hello"
path = "examples/ex-hello.rs"
[[example]]
name = "goodbye"
path = "examples/ex-goodbye.rs"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"src/lib.rs",
r#"
2014-07-10 22:13:53 +00:00
pub fn get_hello() -> &'static str { "Hello" }
pub fn get_goodbye() -> &'static str { "Goodbye" }
pub fn get_world() -> &'static str { "World" }
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"examples/ex-hello.rs",
r#"
extern crate foo;
fn main() { println!("{}, {}!", foo::get_hello(), foo::get_world()); }
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"examples/ex-goodbye.rs",
r#"
extern crate foo;
fn main() { println!("{}, {}!", foo::get_goodbye(), foo::get_world()); }
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
2014-07-10 22:13:53 +00:00
2019-02-19 17:32:07 +00:00
p.cargo("build --examples").run();
p.process(&p.bin("examples/hello"))
.with_stdout("Hello, World!\n")
.run();
p.process(&p.bin("examples/goodbye"))
.with_stdout("Goodbye, World!\n")
.run();
}
2014-07-10 22:13:53 +00:00
#[cargo_test]
fn non_existing_example() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "1.0.0"
authors = []
[lib]
name = "foo"
path = "src/lib.rs"
[[example]]
name = "hello"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.build();
p.cargo("test -v")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
2018-03-14 15:17:44 +00:00
can't find `hello` example, specify example.path",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn non_existing_binary() {
let p = project()
2018-07-24 13:01:56 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/lib.rs", "")
.file("src/bin/ehlo.rs", "")
.build();
p.cargo("build -v")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
2018-07-24 13:01:56 +00:00
can't find `foo` bin, specify bin.path",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
2018-07-24 13:01:56 +00:00
fn legacy_binary_paths_warnings() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "1.0.0"
authors = []
[[bin]]
name = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("build -v")
.with_stderr_contains(
2018-03-14 15:17:44 +00:00
"\
2018-08-02 09:18:48 +00:00
[WARNING] path `[..]src/main.rs` was erroneously implicitly accepted for binary `bar`,
2018-03-14 15:17:44 +00:00
please set bin.path in Cargo.toml",
2018-12-08 11:19:47 +00:00
)
.run();
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "1.0.0"
authors = []
[[bin]]
name = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.file("src/bin/main.rs", "fn main() {}")
.build();
p.cargo("build -v")
.with_stderr_contains(
2018-03-14 15:17:44 +00:00
"\
2018-08-02 09:18:48 +00:00
[WARNING] path `[..]src/bin/main.rs` was erroneously implicitly accepted for binary `bar`,
2018-03-14 15:17:44 +00:00
please set bin.path in Cargo.toml",
2018-12-08 11:19:47 +00:00
)
.run();
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "1.0.0"
authors = []
[[bin]]
name = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/bar.rs", "fn main() {}")
.build();
p.cargo("build -v")
.with_stderr_contains(
2018-03-14 15:17:44 +00:00
"\
2018-08-02 09:18:48 +00:00
[WARNING] path `[..]src/bar.rs` was erroneously implicitly accepted for binary `bar`,
2018-03-14 15:17:44 +00:00
please set bin.path in Cargo.toml",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn implicit_examples() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"src/lib.rs",
r#"
2014-07-10 22:13:53 +00:00
pub fn get_hello() -> &'static str { "Hello" }
pub fn get_goodbye() -> &'static str { "Goodbye" }
pub fn get_world() -> &'static str { "World" }
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"examples/hello.rs",
r#"
extern crate foo;
fn main() {
println!("{}, {}!", foo::get_hello(), foo::get_world());
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"examples/goodbye.rs",
r#"
extern crate foo;
fn main() {
println!("{}, {}!", foo::get_goodbye(), foo::get_world());
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
2014-07-10 22:13:53 +00:00
2019-02-19 17:32:07 +00:00
p.cargo("build --examples").run();
p.process(&p.bin("examples/hello"))
.with_stdout("Hello, World!\n")
.run();
p.process(&p.bin("examples/goodbye"))
.with_stdout("Goodbye, World!\n")
.run();
}
#[cargo_test]
fn standard_build_no_ndebug() {
let p = project()
.file("Cargo.toml", &basic_bin_manifest("foo"))
2018-03-14 15:17:44 +00:00
.file(
"src/foo.rs",
r#"
fn main() {
if cfg!(debug_assertions) {
println!("slow")
} else {
println!("fast")
}
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
p.cargo("build").run();
p.process(&p.bin("foo")).with_stdout("slow\n").run();
}
#[cargo_test]
fn release_build_ndebug() {
let p = project()
.file("Cargo.toml", &basic_bin_manifest("foo"))
2018-03-14 15:17:44 +00:00
.file(
"src/foo.rs",
r#"
fn main() {
if cfg!(debug_assertions) {
println!("slow")
} else {
println!("fast")
}
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.build();
p.cargo("build --release").run();
p.process(&p.release_bin("foo")).with_stdout("fast\n").run();
}
#[cargo_test]
fn inferred_main_bin() {
let p = project().file("src/main.rs", "fn main() {}").build();
p.cargo("build").run();
p.process(&p.bin("foo")).run();
}
#[cargo_test]
fn deletion_causes_failure() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "extern crate bar; fn main() {}")
2018-07-24 22:35:01 +00:00
.file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
.file("bar/src/lib.rs", "")
.build();
p.cargo("build").run();
2018-07-24 22:35:01 +00:00
p.change_file("Cargo.toml", &basic_manifest("foo", "0.0.1"));
p.cargo("build")
.with_status(101)
.with_stderr_contains("[..]can't find crate for `bar`")
.run();
}
#[cargo_test]
fn bad_cargo_toml_in_target_dir() {
let p = project()
.file("src/main.rs", "fn main() {}")
.file("target/Cargo.toml", "bad-toml")
.build();
p.cargo("build").run();
p.process(&p.bin("foo")).run();
}
#[cargo_test]
fn lib_with_standard_name() {
let p = project()
2018-07-24 22:35:01 +00:00
.file("Cargo.toml", &basic_manifest("syntax", "0.0.1"))
.file("src/lib.rs", "pub fn foo() {}")
.file(
"src/main.rs",
"extern crate syntax; fn main() { syntax::foo() }",
2018-12-08 11:19:47 +00:00
)
.build();
p.cargo("build")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] syntax v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn simple_staticlib() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
authors = []
version = "0.0.1"
2014-08-14 06:08:02 +00:00
[lib]
name = "foo"
crate-type = ["staticlib"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "pub fn foo() {}")
.build();
// env var is a test for #1381
p.cargo("build").env("CARGO_LOG", "nekoneko=trace").run();
}
#[cargo_test]
fn staticlib_rlib_and_bin() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
authors = []
version = "0.0.1"
[lib]
name = "foo"
crate-type = ["staticlib", "rlib"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "pub fn foo() {}")
.file("src/main.rs", "extern crate foo; fn main() { foo::foo(); }")
.build();
p.cargo("build -v").run();
}
#[cargo_test]
fn opt_out_of_bin() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
bin = []
[package]
name = "foo"
authors = []
version = "0.0.1"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.file("src/main.rs", "bad syntax")
.build();
p.cargo("build").run();
}
#[cargo_test]
fn single_lib() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
authors = []
version = "0.0.1"
[lib]
name = "foo"
path = "src/bar.rs"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/bar.rs", "")
.build();
p.cargo("build").run();
}
2014-08-14 06:08:02 +00:00
#[cargo_test]
fn freshness_ignores_excluded() {
let foo = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.0"
authors = []
build = "build.rs"
exclude = ["src/b*.rs"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("build.rs", "fn main() {}")
.file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
.build();
foo.root().move_into_the_past();
foo.cargo("build")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] foo v0.0.0 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
// Smoke test to make sure it doesn't compile again
println!("first pass");
foo.cargo("build").with_stdout("").run();
// Modify an ignored file and make sure we don't rebuild
println!("second pass");
File::create(&foo.root().join("src/bar.rs")).unwrap();
foo.cargo("build").with_stdout("").run();
}
#[cargo_test]
fn rebuild_preserves_out_dir() {
let foo = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.0"
authors = []
build = 'build.rs'
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"build.rs",
r#"
2015-02-06 07:27:53 +00:00
use std::env;
2015-03-26 18:17:44 +00:00
use std::fs::File;
use std::path::Path;
fn main() {
2015-03-26 18:17:44 +00:00
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("foo");
2015-02-13 04:10:07 +00:00
if env::var_os("FIRST").is_some() {
File::create(&path).unwrap();
} else {
File::create(&path).unwrap();
}
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
.build();
foo.root().move_into_the_past();
foo.cargo("build")
.env("FIRST", "1")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] foo v0.0.0 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
File::create(&foo.root().join("src/bar.rs")).unwrap();
foo.cargo("build")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] foo v0.0.0 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
}
2014-09-07 18:48:35 +00:00
#[cargo_test]
fn dep_no_libs() {
let foo = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2014-09-07 18:48:35 +00:00
[package]
name = "foo"
version = "0.0.0"
authors = []
[dependencies.bar]
path = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "pub fn bar() -> i32 { 1 }")
2018-07-24 22:35:01 +00:00
.file("bar/Cargo.toml", &basic_manifest("bar", "0.0.0"))
.file("bar/src/main.rs", "")
.build();
foo.cargo("build").run();
}
#[cargo_test]
fn recompile_space_in_name() {
let foo = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.0"
authors = []
[lib]
name = "foo"
path = "src/my lib.rs"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/my lib.rs", "")
.build();
foo.cargo("build").run();
foo.root().move_into_the_past();
foo.cargo("build").with_stdout("").run();
}
#[cfg(unix)]
#[cargo_test]
fn credentials_is_unreadable() {
use cargo_test_support::paths::home;
use std::os::unix::prelude::*;
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/lib.rs", "")
.build();
let credentials = home().join(".cargo/credentials");
t!(fs::create_dir_all(credentials.parent().unwrap()));
t!(t!(File::create(&credentials)).write_all(
br#"
[registry]
token = "api-token"
"#
));
let stat = fs::metadata(credentials.as_path()).unwrap();
let mut perms = stat.permissions();
perms.set_mode(0o000);
2020-01-17 11:19:12 +00:00
fs::set_permissions(credentials, perms).unwrap();
p.cargo("build").run();
}
#[cfg(unix)]
#[cargo_test]
fn ignore_bad_directories() {
use std::os::unix::prelude::*;
let foo = project()
2018-07-24 22:35:01 +00:00
.file("Cargo.toml", &basic_manifest("foo", "0.0.0"))
.file("src/lib.rs", "")
.build();
let dir = foo.root().join("tmp");
fs::create_dir(&dir).unwrap();
let stat = fs::metadata(&dir).unwrap();
let mut perms = stat.permissions();
perms.set_mode(0o644);
fs::set_permissions(&dir, perms.clone()).unwrap();
foo.cargo("build").run();
perms.set_mode(0o755);
fs::set_permissions(&dir, perms).unwrap();
}
#[cargo_test]
fn bad_cargo_config() {
let foo = project()
2018-07-24 22:35:01 +00:00
.file("Cargo.toml", &basic_manifest("foo", "0.0.0"))
.file("src/lib.rs", "")
.file(".cargo/config", "this is not valid toml")
.build();
foo.cargo("build -v")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[ERROR] could not load Cargo configuration
Caused by:
could not parse TOML configuration in `[..]`
Caused by:
could not parse input as TOML
Caused by:
2019-08-13 17:37:40 +00:00
expected an equals, found an identifier at line 1 column 6
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn cargo_platform_specific_dependency() {
let host = rustc_host();
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
&format!(
r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
build = "build.rs"
[target.{host}.dependencies]
dep = {{ path = "dep" }}
[target.{host}.build-dependencies]
build = {{ path = "build" }}
[target.{host}.dev-dependencies]
dev = {{ path = "dev" }}
2018-03-14 15:17:44 +00:00
"#,
host = host
),
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "extern crate dep; fn main() { dep::dep() }")
.file(
"tests/foo.rs",
"extern crate dev; #[test] fn foo() { dev::dev() }",
2018-12-08 11:19:47 +00:00
)
.file(
"build.rs",
"extern crate build; fn main() { build::build(); }",
2018-12-08 11:19:47 +00:00
)
.file("dep/Cargo.toml", &basic_manifest("dep", "0.5.0"))
.file("dep/src/lib.rs", "pub fn dep() {}")
2018-07-24 22:35:01 +00:00
.file("build/Cargo.toml", &basic_manifest("build", "0.5.0"))
.file("build/src/lib.rs", "pub fn build() {}")
2018-07-24 22:35:01 +00:00
.file("dev/Cargo.toml", &basic_manifest("dev", "0.5.0"))
.file("dev/src/lib.rs", "pub fn dev() {}")
.build();
p.cargo("build").run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo").is_file());
p.cargo("test").run();
}
#[cargo_test]
fn bad_platform_specific_dependency() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[target.wrong-target.dependencies.bar]
path = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", &main_file(r#""{}", bar::gimme()"#, &["bar"]))
2018-07-24 22:35:01 +00:00
.file("bar/Cargo.toml", &basic_manifest("bar", "0.5.0"))
.file(
"bar/src/lib.rs",
r#"pub fn gimme() -> String { format!("") }"#,
2018-12-08 11:19:47 +00:00
)
.build();
p.cargo("build")
.with_status(101)
.with_stderr_contains("[..]can't find crate for `bar`")
.run();
}
#[cargo_test]
fn cargo_platform_specific_dependency_wrong_platform() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[target.non-existing-triplet.dependencies.bar]
path = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "fn main() {}")
2018-07-24 22:35:01 +00:00
.file("bar/Cargo.toml", &basic_manifest("bar", "0.5.0"))
.file(
"bar/src/lib.rs",
"invalid rust file, should not be compiled",
2018-12-08 11:19:47 +00:00
)
.build();
p.cargo("build").run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo").is_file());
p.process(&p.bin("foo")).run();
let loc = p.root().join("Cargo.lock");
let mut lockfile = String::new();
2018-03-14 15:17:44 +00:00
File::open(&loc)
.unwrap()
.read_to_string(&mut lockfile)
.unwrap();
assert!(lockfile.contains("bar"));
}
#[cargo_test]
fn example_as_lib() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[[example]]
name = "ex"
crate-type = ["lib"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.file("examples/ex.rs", "")
.build();
p.cargo("build --example=ex").run();
2018-08-29 06:11:10 +00:00
assert!(p.example_lib("ex", "lib").is_file());
}
#[cargo_test]
fn example_as_rlib() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[[example]]
name = "ex"
crate-type = ["rlib"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.file("examples/ex.rs", "")
.build();
p.cargo("build --example=ex").run();
2018-08-29 06:11:10 +00:00
assert!(p.example_lib("ex", "rlib").is_file());
}
#[cargo_test]
fn example_as_dylib() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[[example]]
name = "ex"
crate-type = ["dylib"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.file("examples/ex.rs", "")
.build();
p.cargo("build --example=ex").run();
2018-08-29 06:11:10 +00:00
assert!(p.example_lib("ex", "dylib").is_file());
}
#[cargo_test]
fn example_as_proc_macro() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[[example]]
name = "ex"
crate-type = ["proc-macro"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.file(
"examples/ex.rs",
r#"
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro]
pub fn eat(_item: TokenStream) -> TokenStream {
"".parse().unwrap()
}
"#,
)
.build();
p.cargo("build --example=ex").run();
2018-08-29 06:11:10 +00:00
assert!(p.example_lib("ex", "proc-macro").is_file());
}
#[cargo_test]
fn example_bin_same_name() {
let p = project()
.file("src/main.rs", "fn main() {}")
.file("examples/foo.rs", "fn main() {}")
.build();
2019-02-19 17:32:07 +00:00
p.cargo("build --examples").run();
2018-08-29 06:11:10 +00:00
assert!(!p.bin("foo").is_file());
// We expect a file of the form bin/foo-{metadata_hash}
2018-08-29 06:11:10 +00:00
assert!(p.bin("examples/foo").is_file());
2019-02-19 17:32:07 +00:00
p.cargo("build --examples").run();
2018-08-29 06:11:10 +00:00
assert!(!p.bin("foo").is_file());
// We expect a file of the form bin/foo-{metadata_hash}
2018-08-29 06:11:10 +00:00
assert!(p.bin("examples/foo").is_file());
}
#[cargo_test]
fn compile_then_delete() {
let p = project().file("src/main.rs", "fn main() {}").build();
p.cargo("run -v").run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo").is_file());
if cfg!(windows) {
2015-03-16 13:27:58 +00:00
// On windows unlinking immediately after running often fails, so sleep
sleep_ms(100);
}
fs::remove_file(&p.bin("foo")).unwrap();
p.cargo("run -v").run();
}
#[cargo_test]
fn transitive_dependencies_not_available() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
2015-02-09 16:16:08 +00:00
[dependencies.aaaaa]
path = "a"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"src/main.rs",
"extern crate bbbbb; extern crate aaaaa; fn main() {}",
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"a/Cargo.toml",
r#"
[package]
2015-02-09 16:16:08 +00:00
name = "aaaaa"
version = "0.0.1"
authors = []
2015-02-09 16:16:08 +00:00
[dependencies.bbbbb]
path = "../b"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("a/src/lib.rs", "extern crate bbbbb;")
2018-07-24 22:35:01 +00:00
.file("b/Cargo.toml", &basic_manifest("bbbbb", "0.0.1"))
.file("b/src/lib.rs", "")
.build();
p.cargo("build -v")
.with_status(101)
.with_stderr_contains("[..] can't find crate for `bbbbb`[..]")
.run();
}
#[cargo_test]
fn cyclic_deps_rejected() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.a]
path = "a"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
2018-03-14 15:17:44 +00:00
.file(
"a/Cargo.toml",
r#"
[package]
name = "a"
version = "0.0.1"
authors = []
[dependencies.foo]
path = ".."
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("a/src/lib.rs", "")
.build();
p.cargo("build -v")
.with_status(101)
.with_stderr(
"[ERROR] cyclic package dependency: package `a v0.0.1 ([CWD]/a)` depends on itself. Cycle:
package `a v0.0.1 ([CWD]/a)`
... which is depended on by `foo v0.0.1 ([CWD])`
... which is depended on by `a v0.0.1 ([..])`",
).run();
}
#[cargo_test]
fn predictable_filenames() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[lib]
name = "foo"
crate-type = ["dylib", "rlib"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.build();
p.cargo("build -v").run();
2018-08-29 06:11:10 +00:00
assert!(p.root().join("target/debug/libfoo.rlib").is_file());
2018-03-14 15:17:44 +00:00
let dylib_name = format!("{}foo{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX);
2018-08-29 06:11:10 +00:00
assert!(p.root().join("target/debug").join(dylib_name).is_file());
}
#[cargo_test]
fn dashes_to_underscores() {
let p = project()
2018-07-24 22:35:01 +00:00
.file("Cargo.toml", &basic_manifest("foo-bar", "0.0.1"))
.file("src/lib.rs", "")
.file("src/main.rs", "extern crate foo_bar; fn main() {}")
.build();
p.cargo("build -v").run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo-bar").is_file());
}
#[cargo_test]
fn dashes_in_crate_name_bad() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[lib]
name = "foo-bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.file("src/main.rs", "extern crate foo_bar; fn main() {}")
.build();
p.cargo("build -v")
.with_status(101)
.with_stderr(
"\
[ERROR] failed to parse manifest at `[..]/foo/Cargo.toml`
Caused by:
library target names cannot contain hyphens: foo-bar
",
)
.run();
}
#[cargo_test]
fn rustc_env_var() {
let p = project().file("src/lib.rs", "").build();
p.cargo("build -v")
.env("RUSTC", "rustc-that-does-not-exist")
.with_status(101)
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
2016-09-14 18:10:30 +00:00
[ERROR] could not execute process `rustc-that-does-not-exist -vV` ([..])
Caused by:
[..]
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
2018-08-29 06:11:10 +00:00
assert!(!p.bin("a").is_file());
}
#[cargo_test]
fn filtering() {
let p = project()
.file("src/lib.rs", "")
.file("src/bin/a.rs", "fn main() {}")
.file("src/bin/b.rs", "fn main() {}")
.file("examples/a.rs", "fn main() {}")
.file("examples/b.rs", "fn main() {}")
.build();
p.cargo("build --lib").run();
2018-08-29 06:11:10 +00:00
assert!(!p.bin("a").is_file());
p.cargo("build --bin=a --example=a").run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("a").is_file());
assert!(!p.bin("b").is_file());
assert!(p.bin("examples/a").is_file());
assert!(!p.bin("examples/b").is_file());
}
#[cargo_test]
fn filtering_implicit_bins() {
let p = project()
.file("src/lib.rs", "")
.file("src/bin/a.rs", "fn main() {}")
.file("src/bin/b.rs", "fn main() {}")
.file("examples/a.rs", "fn main() {}")
.file("examples/b.rs", "fn main() {}")
.build();
p.cargo("build --bins").run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("a").is_file());
assert!(p.bin("b").is_file());
assert!(!p.bin("examples/a").is_file());
assert!(!p.bin("examples/b").is_file());
}
#[cargo_test]
fn filtering_implicit_examples() {
let p = project()
.file("src/lib.rs", "")
.file("src/bin/a.rs", "fn main() {}")
.file("src/bin/b.rs", "fn main() {}")
.file("examples/a.rs", "fn main() {}")
.file("examples/b.rs", "fn main() {}")
.build();
p.cargo("build --examples").run();
2018-08-29 06:11:10 +00:00
assert!(!p.bin("a").is_file());
assert!(!p.bin("b").is_file());
assert!(p.bin("examples/a").is_file());
assert!(p.bin("examples/b").is_file());
}
#[cargo_test]
fn ignore_dotfile() {
let p = project()
.file("src/bin/.a.rs", "")
.file("src/bin/a.rs", "fn main() {}")
.build();
p.cargo("build").run();
}
#[cargo_test]
fn ignore_dotdirs() {
let p = project()
.file("src/bin/a.rs", "fn main() {}")
.file(".git/Cargo.toml", "")
.file(".pc/dummy-fix.patch/Cargo.toml", "")
.build();
p.cargo("build").run();
}
#[cargo_test]
fn dotdir_root() {
let p = ProjectBuilder::new(root().join(".foo"))
.file("src/bin/a.rs", "fn main() {}")
.build();
p.cargo("build").run();
}
#[cargo_test]
fn custom_target_dir_env() {
let p = project().file("src/main.rs", "fn main() {}").build();
let exe_name = format!("foo{}", env::consts::EXE_SUFFIX);
p.cargo("build").env("CARGO_TARGET_DIR", "foo/target").run();
2018-08-29 06:11:10 +00:00
assert!(p.root().join("foo/target/debug").join(&exe_name).is_file());
assert!(!p.root().join("target/debug").join(&exe_name).is_file());
p.cargo("build").run();
2018-08-29 06:11:10 +00:00
assert!(p.root().join("foo/target/debug").join(&exe_name).is_file());
assert!(p.root().join("target/debug").join(&exe_name).is_file());
p.cargo("build")
.env("CARGO_BUILD_TARGET_DIR", "foo2/target")
.run();
assert!(p.root().join("foo2/target/debug").join(&exe_name).is_file());
fs::create_dir(p.root().join(".cargo")).unwrap();
2018-03-14 15:17:44 +00:00
File::create(p.root().join(".cargo/config"))
.unwrap()
.write_all(
br#"
[build]
target-dir = "foo/target"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.unwrap();
p.cargo("build").env("CARGO_TARGET_DIR", "bar/target").run();
2018-08-29 06:11:10 +00:00
assert!(p.root().join("bar/target/debug").join(&exe_name).is_file());
assert!(p.root().join("foo/target/debug").join(&exe_name).is_file());
assert!(p.root().join("target/debug").join(&exe_name).is_file());
}
#[cargo_test]
fn custom_target_dir_line_parameter() {
let p = project().file("src/main.rs", "fn main() {}").build();
let exe_name = format!("foo{}", env::consts::EXE_SUFFIX);
p.cargo("build --target-dir foo/target").run();
2018-08-29 06:11:10 +00:00
assert!(p.root().join("foo/target/debug").join(&exe_name).is_file());
assert!(!p.root().join("target/debug").join(&exe_name).is_file());
p.cargo("build").run();
2018-08-29 06:11:10 +00:00
assert!(p.root().join("foo/target/debug").join(&exe_name).is_file());
assert!(p.root().join("target/debug").join(&exe_name).is_file());
fs::create_dir(p.root().join(".cargo")).unwrap();
File::create(p.root().join(".cargo/config"))
.unwrap()
.write_all(
br#"
[build]
target-dir = "foo/target"
"#,
2018-12-08 11:19:47 +00:00
)
.unwrap();
p.cargo("build --target-dir bar/target").run();
2018-08-29 06:11:10 +00:00
assert!(p.root().join("bar/target/debug").join(&exe_name).is_file());
assert!(p.root().join("foo/target/debug").join(&exe_name).is_file());
assert!(p.root().join("target/debug").join(&exe_name).is_file());
p.cargo("build --target-dir foobar/target")
.env("CARGO_TARGET_DIR", "bar/target")
.run();
2018-12-08 11:19:47 +00:00
assert!(p
.root()
.join("foobar/target/debug")
.join(&exe_name)
.is_file());
2018-08-29 06:11:10 +00:00
assert!(p.root().join("bar/target/debug").join(&exe_name).is_file());
assert!(p.root().join("foo/target/debug").join(&exe_name).is_file());
assert!(p.root().join("target/debug").join(&exe_name).is_file());
}
#[cargo_test]
fn build_multiple_packages() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.d1]
path = "d1"
[dependencies.d2]
path = "d2"
[[bin]]
name = "foo"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
2018-07-24 22:35:01 +00:00
.file("d1/Cargo.toml", &basic_bin_manifest("d1"))
.file("d1/src/lib.rs", "")
.file("d1/src/main.rs", "fn main() { println!(\"d1\"); }")
2018-03-14 15:17:44 +00:00
.file(
"d2/Cargo.toml",
r#"
[package]
name = "d2"
version = "0.0.1"
authors = []
[[bin]]
name = "d2"
doctest = false
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("d2/src/main.rs", "fn main() { println!(\"d2\"); }")
.build();
p.cargo("build -p d1 -p d2 -p foo").run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo").is_file());
p.process(&p.bin("foo")).with_stdout("i am foo\n").run();
let d1_path = &p
.build_dir()
2018-03-14 15:17:44 +00:00
.join("debug")
.join(format!("d1{}", env::consts::EXE_SUFFIX));
let d2_path = &p
.build_dir()
2018-03-14 15:17:44 +00:00
.join("debug")
.join(format!("d2{}", env::consts::EXE_SUFFIX));
2018-08-29 06:11:10 +00:00
assert!(d1_path.is_file());
p.process(d1_path).with_stdout("d1").run();
2015-09-24 21:47:50 +00:00
2018-08-29 06:11:10 +00:00
assert!(d2_path.is_file());
p.process(d2_path).with_stdout("d2").run();
}
#[cargo_test]
fn invalid_spec() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.d1]
path = "d1"
[[bin]]
name = "foo"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/bin/foo.rs", &main_file(r#""i am foo""#, &[]))
2018-07-24 22:35:01 +00:00
.file("d1/Cargo.toml", &basic_bin_manifest("d1"))
.file("d1/src/lib.rs", "")
.file("d1/src/main.rs", "fn main() { println!(\"d1\"); }")
.build();
p.cargo("build -p notAValidDep")
.with_status(101)
2019-02-03 04:01:23 +00:00
.with_stderr("[ERROR] package ID specification `notAValidDep` matched no packages")
.run();
p.cargo("build -p d1 -p notAValidDep")
.with_status(101)
2019-02-03 04:01:23 +00:00
.with_stderr("[ERROR] package ID specification `notAValidDep` matched no packages")
.run();
}
#[cargo_test]
fn manifest_with_bom_is_ok() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
"\u{FEFF}
[package]
name = \"foo\"
version = \"0.0.1\"
authors = []
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.build();
p.cargo("build -v").run();
}
#[cargo_test]
fn panic_abort_compiles_with_panic_abort() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[profile.dev]
panic = 'abort'
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.build();
p.cargo("build -v")
.with_stderr_contains("[..] -C panic=abort [..]")
.run();
}
2016-06-09 20:55:17 +00:00
#[cargo_test]
2016-08-11 21:47:49 +00:00
fn compiler_json_error_format() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2016-08-11 21:47:49 +00:00
[project]
name = "foo"
version = "0.5.0"
authors = ["wycats@example.com"]
[dependencies.bar]
path = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
"build.rs",
"fn main() { println!(\"cargo:rustc-cfg=xyz\") }",
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "fn main() { let unused = 92; }")
2018-07-24 22:35:01 +00:00
.file("bar/Cargo.toml", &basic_manifest("bar", "0.5.0"))
.file("bar/src/lib.rs", r#"fn dead() {}"#)
.build();
2016-08-11 21:47:49 +00:00
2019-09-25 01:17:36 +00:00
let output = |fresh| {
r#"
2016-08-11 21:47:49 +00:00
{
"reason":"compiler-artifact",
"package_id":"foo 0.5.0 ([..])",
2017-02-08 15:15:06 +00:00
"target":{
"kind":["custom-build"],
"crate_types":["bin"],
"doctest": false,
"edition": "2015",
"name":"build-script-build",
"src_path":"[..]build.rs"
2017-02-08 15:15:06 +00:00
},
"profile": {
"debug_assertions": true,
"debuginfo": 2,
"opt_level": "0",
"overflow_checks": true,
"test": false
},
2018-11-30 14:31:01 +00:00
"executable": null,
"features": [],
"filenames": "{...}",
2019-09-25 01:17:36 +00:00
"fresh": $FRESH
}
{
"reason":"compiler-message",
"package_id":"bar 0.5.0 ([..])",
2017-02-08 15:15:06 +00:00
"target":{
"kind":["lib"],
"crate_types":["lib"],
"doctest": true,
"edition": "2015",
2017-02-08 15:15:06 +00:00
"name":"bar",
"src_path":"[..]lib.rs"
},
"message":"{...}"
}
{
"reason":"compiler-artifact",
"profile": {
"debug_assertions": true,
"debuginfo": 2,
"opt_level": "0",
"overflow_checks": true,
"test": false
},
2018-11-30 14:31:01 +00:00
"executable": null,
"features": [],
"package_id":"bar 0.5.0 ([..])",
"target":{
"kind":["lib"],
"crate_types":["lib"],
"doctest": true,
"edition": "2015",
"name":"bar",
"src_path":"[..]lib.rs"
},
"filenames":[
"[..].rlib",
"[..].rmeta"
],
2019-09-25 01:17:36 +00:00
"fresh": $FRESH
}
{
"reason":"build-script-executed",
"package_id":"foo 0.5.0 ([..])",
"linked_libs":[],
"linked_paths":[],
"env":[],
"cfgs":["xyz"],
"out_dir": "[..]target/debug/build/foo-[..]/out"
}
2016-08-11 21:47:49 +00:00
{
"reason":"compiler-message",
2016-08-11 21:47:49 +00:00
"package_id":"foo 0.5.0 ([..])",
2017-02-08 15:15:06 +00:00
"target":{
"kind":["bin"],
"crate_types":["bin"],
"doctest": false,
"edition": "2015",
2017-02-08 15:15:06 +00:00
"name":"foo",
"src_path":"[..]main.rs"
},
make build tests not depend on minutiæ of rustc output This little patch arises from the maelstrom of my purity born of pain. It's the pain of seeing rust-lang/rust#38103 in its perfect crystalline beauty waste away on page four of https://github.com/rust-lang/rust/pulls, waiting, ready, itching to land, dying with anticipation to bring the light of clearer lint group error messages to Rust users of all creeds and nations, only for its promise to be cruelly blocked by the fateful, hateful hand of circular dependency. For it is written in src/tools/cargotest/main.rs that the Cargo tests must pass before the PR can receive Appveyor's blessing, but the Cargo tests could not pass (because they depend on fine details of the output that the PR is meant to change), and the Cargo tests could not be changed (because updating the test expectation to match the proposed new compiler output, would fail with the current compiler). The Gordian knot is cut in the bowels of cargotest's very notion of comparison (of JSON objects) itself, by means of introducing a magic string literal `"{...}"`, which can server as a wildcard for any JSON sub-object. And so it will be for the children, and the children's children, and unto the 1.17.0 and 1.18.0 releases, that Cargo's build test expectations will faithfully expect the exact JSON output by Cargo itself, but the string literal `"{...}"` shall be a token upon the JSON output by rustc, and when I see `"{...}"`, I will pass over you, and the failure shall not be upon you. And this day shall be unto you for a memorial.
2017-02-01 04:51:24 +00:00
"message":"{...}"
2016-08-11 21:47:49 +00:00
}
{
"reason":"compiler-artifact",
"package_id":"foo 0.5.0 ([..])",
2017-02-08 15:15:06 +00:00
"target":{
"kind":["bin"],
"crate_types":["bin"],
"doctest": false,
"edition": "2015",
2017-02-08 15:15:06 +00:00
"name":"foo",
"src_path":"[..]main.rs"
},
"profile": {
"debug_assertions": true,
"debuginfo": 2,
"opt_level": "0",
"overflow_checks": true,
"test": false
},
2018-11-30 14:31:01 +00:00
"executable": "[..]/foo/target/debug/foo[EXE]",
"features": [],
"filenames": "{...}",
2019-09-25 01:17:36 +00:00
"fresh": $FRESH
}
2019-09-25 01:17:36 +00:00
"#
.replace("$FRESH", fresh)
};
// Use `jobs=1` to ensure that the order of messages is consistent.
p.cargo("build -v --message-format=json --jobs=1")
.with_json(&output("false"))
2018-12-08 11:19:47 +00:00
.run();
// With fresh build, we should repeat the artifacts,
2019-09-25 01:17:36 +00:00
// and replay the cached compiler warnings.
p.cargo("build -v --message-format=json --jobs=1")
2019-09-25 01:17:36 +00:00
.with_json(&output("true"))
2018-12-08 11:19:47 +00:00
.run();
2016-08-11 21:47:49 +00:00
}
#[cargo_test]
2016-08-11 21:47:49 +00:00
fn wrong_message_format_option() {
let p = project()
2016-08-11 21:47:49 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/main.rs", "fn main() {}")
.build();
2016-08-11 21:47:49 +00:00
p.cargo("build --message-format XML")
Add support for customizing JSON diagnostics from Cargo Cargo has of #7143 enabled pipelined compilation by default which affects how the compiler is invoked, especially with respect to JSON messages. This, in some testing, has proven to cause quite a few issues with rustbuild's current integration with Cargo. This commit is aimed at adding features to Cargo to solve this issue. This commit adds the ability to customize the stream of JSON messages coming from Cargo. The new feature for Cargo is that it now also mirrors rustc in how you can configure the JSON stream. Multiple `--message-format` arguments are now supported and the value specified is a comma-separated list of directives. In addition to the existing `human`, `short`, and `json` directives these new directives have been added: * `json-render-diagnostics` - instructs Cargo to render rustc diagnostics and only print out JSON messages for artifacts and Cargo things. * `json-diagnostic-short` - indicates that the `rendered` field of rustc diagnostics should use the "short" rendering. * `json-diagnostic-rendered-ansi` - indicates that the `rendered` field of rustc diagnostics should embed ansi color codes. The first option here, `json-render-diagnostics`, will be used by rustbuild unconditionally. Additionally `json-diagnostic-short` will be conditionally used based on the input to rustbuild itself. This should be enough for external tools to customize how Cargo is invoked and how all kinds of JSON diagnostics get printed, and it's thought that we can relatively easily tweak this as necessary to extend it and such.
2019-08-05 16:42:28 +00:00
.with_status(101)
.with_stderr_contains(
2018-03-14 15:17:44 +00:00
"\
Add support for customizing JSON diagnostics from Cargo Cargo has of #7143 enabled pipelined compilation by default which affects how the compiler is invoked, especially with respect to JSON messages. This, in some testing, has proven to cause quite a few issues with rustbuild's current integration with Cargo. This commit is aimed at adding features to Cargo to solve this issue. This commit adds the ability to customize the stream of JSON messages coming from Cargo. The new feature for Cargo is that it now also mirrors rustc in how you can configure the JSON stream. Multiple `--message-format` arguments are now supported and the value specified is a comma-separated list of directives. In addition to the existing `human`, `short`, and `json` directives these new directives have been added: * `json-render-diagnostics` - instructs Cargo to render rustc diagnostics and only print out JSON messages for artifacts and Cargo things. * `json-diagnostic-short` - indicates that the `rendered` field of rustc diagnostics should use the "short" rendering. * `json-diagnostic-rendered-ansi` - indicates that the `rendered` field of rustc diagnostics should embed ansi color codes. The first option here, `json-render-diagnostics`, will be used by rustbuild unconditionally. Additionally `json-diagnostic-short` will be conditionally used based on the input to rustbuild itself. This should be enough for external tools to customize how Cargo is invoked and how all kinds of JSON diagnostics get printed, and it's thought that we can relatively easily tweak this as necessary to extend it and such.
2019-08-05 16:42:28 +00:00
error: invalid message format specifier: `xml`
2018-03-14 15:17:44 +00:00
",
2018-12-08 11:19:47 +00:00
)
.run();
2016-08-11 21:47:49 +00:00
}
#[cargo_test]
fn message_format_json_forward_stderr() {
let p = project()
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/main.rs", "fn main() { let unused = 0; }")
.build();
p.cargo("rustc --release --bin foo --message-format JSON")
.with_json(
2018-03-14 15:17:44 +00:00
r#"
{
"reason":"compiler-message",
"package_id":"foo 0.5.0 ([..])",
2017-02-10 09:35:20 +00:00
"target":{
"kind":["bin"],
"crate_types":["bin"],
"doctest": false,
"edition": "2015",
2017-02-10 09:35:20 +00:00
"name":"foo",
"src_path":"[..]"
},
make build tests not depend on minutiæ of rustc output This little patch arises from the maelstrom of my purity born of pain. It's the pain of seeing rust-lang/rust#38103 in its perfect crystalline beauty waste away on page four of https://github.com/rust-lang/rust/pulls, waiting, ready, itching to land, dying with anticipation to bring the light of clearer lint group error messages to Rust users of all creeds and nations, only for its promise to be cruelly blocked by the fateful, hateful hand of circular dependency. For it is written in src/tools/cargotest/main.rs that the Cargo tests must pass before the PR can receive Appveyor's blessing, but the Cargo tests could not pass (because they depend on fine details of the output that the PR is meant to change), and the Cargo tests could not be changed (because updating the test expectation to match the proposed new compiler output, would fail with the current compiler). The Gordian knot is cut in the bowels of cargotest's very notion of comparison (of JSON objects) itself, by means of introducing a magic string literal `"{...}"`, which can server as a wildcard for any JSON sub-object. And so it will be for the children, and the children's children, and unto the 1.17.0 and 1.18.0 releases, that Cargo's build test expectations will faithfully expect the exact JSON output by Cargo itself, but the string literal `"{...}"` shall be a token upon the JSON output by rustc, and when I see `"{...}"`, I will pass over you, and the failure shall not be upon you. And this day shall be unto you for a memorial.
2017-02-01 04:51:24 +00:00
"message":"{...}"
}
{
"reason":"compiler-artifact",
"package_id":"foo 0.5.0 ([..])",
2017-02-10 09:35:20 +00:00
"target":{
"kind":["bin"],
"crate_types":["bin"],
"doctest": false,
"edition": "2015",
2017-02-10 09:35:20 +00:00
"name":"foo",
"src_path":"[..]"
},
"profile":{
2017-10-13 19:13:32 +00:00
"debug_assertions":false,
"debuginfo":null,
"opt_level":"3",
"overflow_checks": false,
"test":false
},
2018-11-30 14:31:01 +00:00
"executable": "{...}",
"features":[],
"filenames": "{...}",
"fresh": false
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn no_warn_about_package_metadata() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[package.metadata]
foo = "bar"
a = true
b = 3
[package.metadata.another]
bar = 3
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.build();
p.cargo("build")
.with_stderr(
2018-03-14 15:17:44 +00:00
"[..] foo v0.0.1 ([..])\n\
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]\n",
2018-12-08 11:19:47 +00:00
)
.run();
}
2016-10-25 18:52:47 +00:00
#[cargo_test]
2016-10-25 18:52:47 +00:00
fn cargo_build_empty_target() {
let p = project()
2016-10-25 18:52:47 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/main.rs", "fn main() {}")
.build();
2016-10-25 18:52:47 +00:00
p.cargo("build --target")
.arg("")
.with_status(101)
.with_stderr_contains("[..] target was empty")
.run();
2016-10-25 18:52:47 +00:00
}
#[cargo_test]
fn build_all_workspace() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
[dependencies]
bar = { path = "bar" }
[workspace]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "fn main() {}")
2018-07-24 22:35:01 +00:00
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "pub fn bar() {}")
.build();
2019-08-12 12:31:20 +00:00
p.cargo("build --workspace")
.with_stderr(
2018-03-14 15:17:44 +00:00
"[..] Compiling bar v0.1.0 ([..])\n\
[..] Compiling foo v0.1.0 ([..])\n\
[..] Finished dev [unoptimized + debuginfo] target(s) in [..]\n",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
2017-05-12 13:44:15 +00:00
fn build_all_exclude() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2017-05-12 13:44:15 +00:00
[project]
name = "foo"
version = "0.1.0"
[workspace]
members = ["bar", "baz"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "fn main() {}")
2018-07-24 22:35:01 +00:00
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "pub fn bar() {}")
2018-07-24 22:35:01 +00:00
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
.file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }")
.build();
2017-05-12 13:44:15 +00:00
2019-08-12 12:31:20 +00:00
p.cargo("build --workspace --exclude baz")
.with_stderr_contains("[..]Compiling foo v0.1.0 [..]")
.with_stderr_contains("[..]Compiling bar v0.1.0 [..]")
.with_stderr_does_not_contain("[..]Compiling baz v0.1.0 [..]")
.run();
2017-05-12 13:44:15 +00:00
}
#[cargo_test]
fn build_all_workspace_implicit_examples() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
[dependencies]
bar = { path = "bar" }
[workspace]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.file("src/bin/a.rs", "fn main() {}")
.file("src/bin/b.rs", "fn main() {}")
.file("examples/c.rs", "fn main() {}")
.file("examples/d.rs", "fn main() {}")
2018-07-24 22:35:01 +00:00
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "")
.file("bar/src/bin/e.rs", "fn main() {}")
.file("bar/src/bin/f.rs", "fn main() {}")
.file("bar/examples/g.rs", "fn main() {}")
.file("bar/examples/h.rs", "fn main() {}")
.build();
2019-08-12 12:31:20 +00:00
p.cargo("build --workspace --examples")
.with_stderr(
2018-03-14 15:17:44 +00:00
"[..] Compiling bar v0.1.0 ([..])\n\
[..] Compiling foo v0.1.0 ([..])\n\
[..] Finished dev [unoptimized + debuginfo] target(s) in [..]\n",
2018-12-08 11:19:47 +00:00
)
.run();
2018-08-29 06:11:10 +00:00
assert!(!p.bin("a").is_file());
assert!(!p.bin("b").is_file());
assert!(p.bin("examples/c").is_file());
assert!(p.bin("examples/d").is_file());
assert!(!p.bin("e").is_file());
assert!(!p.bin("f").is_file());
assert!(p.bin("examples/g").is_file());
assert!(p.bin("examples/h").is_file());
}
#[cargo_test]
fn build_all_virtual_manifest() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
members = ["bar", "baz"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "pub fn bar() {}")
2018-07-24 22:35:01 +00:00
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
.file("baz/src/lib.rs", "pub fn baz() {}")
.build();
// The order in which bar and baz are built is not guaranteed
2019-08-12 12:31:20 +00:00
p.cargo("build --workspace")
.with_stderr_contains("[..] Compiling baz v0.1.0 ([..])")
.with_stderr_contains("[..] Compiling bar v0.1.0 ([..])")
.with_stderr(
"[..] Compiling [..] v0.1.0 ([..])\n\
[..] Compiling [..] v0.1.0 ([..])\n\
[..] Finished dev [unoptimized + debuginfo] target(s) in [..]\n",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
2017-05-26 21:00:45 +00:00
fn build_virtual_manifest_all_implied() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2017-05-26 21:00:45 +00:00
[workspace]
members = ["bar", "baz"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "pub fn bar() {}")
2018-07-24 22:35:01 +00:00
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
.file("baz/src/lib.rs", "pub fn baz() {}")
.build();
2017-05-26 21:00:45 +00:00
2019-02-03 04:01:23 +00:00
// The order in which `bar` and `baz` are built is not guaranteed.
p.cargo("build")
.with_stderr_contains("[..] Compiling baz v0.1.0 ([..])")
.with_stderr_contains("[..] Compiling bar v0.1.0 ([..])")
.with_stderr(
"[..] Compiling [..] v0.1.0 ([..])\n\
[..] Compiling [..] v0.1.0 ([..])\n\
[..] Finished dev [unoptimized + debuginfo] target(s) in [..]\n",
2018-12-08 11:19:47 +00:00
)
.run();
2017-05-26 21:00:45 +00:00
}
#[cargo_test]
fn build_virtual_manifest_one_project() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
members = ["bar", "baz"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "pub fn bar() {}")
2018-07-24 22:35:01 +00:00
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
.file("baz/src/lib.rs", "pub fn baz() {}")
.build();
p.cargo("build -p bar")
.with_stderr_does_not_contain("[..]baz[..]")
.with_stderr_contains("[..] Compiling bar v0.1.0 ([..])")
.with_stderr(
"[..] Compiling [..] v0.1.0 ([..])\n\
[..] Finished dev [unoptimized + debuginfo] target(s) in [..]\n",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn build_all_virtual_manifest_implicit_examples() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
members = ["bar", "baz"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("bar/src/lib.rs", "")
.file("bar/src/bin/a.rs", "fn main() {}")
.file("bar/src/bin/b.rs", "fn main() {}")
.file("bar/examples/c.rs", "fn main() {}")
.file("bar/examples/d.rs", "fn main() {}")
2018-07-24 22:35:01 +00:00
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
.file("baz/src/lib.rs", "")
.file("baz/src/bin/e.rs", "fn main() {}")
.file("baz/src/bin/f.rs", "fn main() {}")
.file("baz/examples/g.rs", "fn main() {}")
.file("baz/examples/h.rs", "fn main() {}")
.build();
// The order in which bar and baz are built is not guaranteed
2019-08-12 12:31:20 +00:00
p.cargo("build --workspace --examples")
.with_stderr_contains("[..] Compiling baz v0.1.0 ([..])")
.with_stderr_contains("[..] Compiling bar v0.1.0 ([..])")
.with_stderr(
"[..] Compiling [..] v0.1.0 ([..])\n\
[..] Compiling [..] v0.1.0 ([..])\n\
[..] Finished dev [unoptimized + debuginfo] target(s) in [..]\n",
2018-12-08 11:19:47 +00:00
)
.run();
2018-08-29 06:11:10 +00:00
assert!(!p.bin("a").is_file());
assert!(!p.bin("b").is_file());
assert!(p.bin("examples/c").is_file());
assert!(p.bin("examples/d").is_file());
assert!(!p.bin("e").is_file());
assert!(!p.bin("f").is_file());
assert!(p.bin("examples/g").is_file());
assert!(p.bin("examples/h").is_file());
}
#[cargo_test]
fn build_all_member_dependency_same_name() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[workspace]
members = ["a"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"a/Cargo.toml",
r#"
[project]
name = "a"
version = "0.1.0"
[dependencies]
a = "0.1.0"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("a/src/lib.rs", "pub fn a() {}")
.build();
Package::new("a", "0.1.0").publish();
2019-08-12 12:31:20 +00:00
p.cargo("build --workspace")
.with_stderr(
2018-09-14 20:33:18 +00:00
"[UPDATING] `[..]` index\n\
[DOWNLOADING] crates ...\n\
[DOWNLOADED] a v0.1.0 ([..])\n\
[COMPILING] a v0.1.0\n\
[COMPILING] a v0.1.0 ([..])\n\
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]\n",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
2017-01-28 23:56:30 +00:00
fn run_proper_binary() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2017-01-28 23:56:30 +00:00
[package]
name = "foo"
authors = []
version = "0.0.0"
[[bin]]
name = "main"
[[bin]]
name = "other"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.file(
"src/bin/main.rs",
r#"fn main() { panic!("This should never be run."); }"#,
2018-12-08 11:19:47 +00:00
)
.file("src/bin/other.rs", "fn main() {}")
.build();
2017-01-28 23:56:30 +00:00
p.cargo("run --bin other").run();
2017-01-28 23:56:30 +00:00
}
#[cargo_test]
fn run_proper_binary_main_rs() {
let p = project()
2018-07-24 22:35:01 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/lib.rs", "")
.file("src/bin/main.rs", "fn main() {}")
.build();
p.cargo("run --bin foo").run();
}
2017-04-04 21:58:31 +00:00
#[cargo_test]
2017-05-14 20:47:24 +00:00
fn run_proper_alias_binary_from_src() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2017-05-14 20:47:24 +00:00
[package]
name = "foo"
authors = []
version = "0.0.0"
[[bin]]
name = "foo"
[[bin]]
name = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/foo.rs", r#"fn main() { println!("foo"); }"#)
.file("src/bar.rs", r#"fn main() { println!("bar"); }"#)
.build();
2017-05-14 20:47:24 +00:00
2019-08-12 12:31:20 +00:00
p.cargo("build --workspace").run();
p.process(&p.bin("foo")).with_stdout("foo\n").run();
p.process(&p.bin("bar")).with_stdout("bar\n").run();
2017-05-14 20:47:24 +00:00
}
#[cargo_test]
2017-05-14 20:47:24 +00:00
fn run_proper_alias_binary_main_rs() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2017-05-14 20:47:24 +00:00
[package]
name = "foo"
authors = []
version = "0.0.0"
[[bin]]
name = "foo"
[[bin]]
name = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", r#"fn main() { println!("main"); }"#)
.build();
2017-05-14 20:47:24 +00:00
2019-08-12 12:31:20 +00:00
p.cargo("build --workspace").run();
p.process(&p.bin("foo")).with_stdout("main\n").run();
p.process(&p.bin("bar")).with_stdout("main\n").run();
2017-05-14 20:47:24 +00:00
}
#[cargo_test]
2017-04-04 21:58:31 +00:00
fn run_proper_binary_main_rs_as_foo() {
let p = project()
2018-07-24 22:35:01 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file(
"src/foo.rs",
r#" fn main() { panic!("This should never be run."); }"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "fn main() {}")
.build();
2017-04-04 21:58:31 +00:00
p.cargo("run --bin foo").run();
2017-04-04 21:58:31 +00:00
}
#[cargo_test]
2019-02-03 04:01:23 +00:00
// NOTE: we don't have `/usr/bin/env` on Windows.
#[cfg(not(windows))]
fn rustc_wrapper() {
let p = project().file("src/lib.rs", "").build();
p.cargo("build -v")
.env("RUSTC_WRAPPER", "/usr/bin/env")
.with_stderr_contains("[RUNNING] `/usr/bin/env rustc --crate-name foo [..]")
.run();
}
#[cargo_test]
#[cfg(not(windows))]
fn rustc_wrapper_relative() {
let p = project().file("src/lib.rs", "").build();
p.cargo("build -v")
.env("RUSTC_WRAPPER", "./sccache")
.with_status(101)
.with_stderr_contains("[..]/foo/./sccache rustc[..]")
.run();
}
#[cargo_test]
#[cfg(not(windows))]
fn rustc_wrapper_from_path() {
let p = project().file("src/lib.rs", "").build();
p.cargo("build -v")
.env("RUSTC_WRAPPER", "wannabe_sccache")
.with_status(101)
.with_stderr_contains("[..]`wannabe_sccache rustc [..]")
.run();
}
#[cargo_test]
fn cdylib_not_lifted() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
authors = []
version = "0.1.0"
[lib]
crate-type = ["cdylib"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.build();
p.cargo("build").run();
let files = if cfg!(windows) {
vec!["foo.dll.lib", "foo.dll.exp", "foo.dll"]
} else if cfg!(target_os = "macos") {
vec!["libfoo.dylib"]
} else {
vec!["libfoo.so"]
};
for file in files {
println!("checking: {}", file);
2018-08-29 06:11:10 +00:00
assert!(p.root().join("target/debug/deps").join(&file).is_file());
}
}
#[cargo_test]
fn cdylib_final_outputs() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo-bar"
authors = []
version = "0.1.0"
[lib]
crate-type = ["cdylib"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.build();
p.cargo("build").run();
let files = if cfg!(windows) {
vec!["foo_bar.dll.lib", "foo_bar.dll"]
} else if cfg!(target_os = "macos") {
vec!["libfoo_bar.dylib"]
} else {
vec!["libfoo_bar.so"]
};
for file in files {
println!("checking: {}", file);
2018-08-29 06:11:10 +00:00
assert!(p.root().join("target/debug").join(&file).is_file());
}
}
#[cargo_test]
fn deterministic_cfg_flags() {
2019-02-03 04:01:23 +00:00
// This bug is non-deterministic.
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
authors = []
build = "build.rs"
[features]
default = ["f_a", "f_b", "f_c", "f_d"]
f_a = []
f_b = []
f_c = []
f_d = []
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file(
2018-03-14 15:17:44 +00:00
"build.rs",
r#"
fn main() {
println!("cargo:rustc-cfg=cfg_a");
println!("cargo:rustc-cfg=cfg_b");
println!("cargo:rustc-cfg=cfg_c");
println!("cargo:rustc-cfg=cfg_d");
println!("cargo:rustc-cfg=cfg_e");
}
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("build -v")
.with_stderr(
2018-03-14 15:17:44 +00:00
"\
[COMPILING] foo v0.1.0 [..]
[RUNNING] [..]
[RUNNING] [..]
[RUNNING] `rustc --crate-name foo [..] \
--cfg[..]default[..]--cfg[..]f_a[..]--cfg[..]f_b[..]\
--cfg[..]f_c[..]--cfg[..]f_d[..] \
--cfg cfg_a --cfg cfg_b --cfg cfg_c --cfg cfg_d --cfg cfg_e`
2018-03-14 15:17:44 +00:00
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
2018-12-08 11:19:47 +00:00
)
.run();
}
2017-06-16 19:41:27 +00:00
#[cargo_test]
2017-06-16 19:41:27 +00:00
fn explicit_bins_without_paths() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
2017-06-16 19:41:27 +00:00
[package]
name = "foo"
version = "0.1.0"
authors = []
[[bin]]
name = "foo"
[[bin]]
name = "bar"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
2017-06-16 19:41:27 +00:00
.file("src/main.rs", "fn main() {}")
.file("src/bin/bar.rs", "fn main() {}")
.build();
2017-06-16 19:41:27 +00:00
p.cargo("build").run();
2017-06-16 19:41:27 +00:00
}
#[cargo_test]
fn no_bin_in_src_with_lib() {
let p = project()
2018-07-24 22:35:01 +00:00
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/lib.rs", "")
.file("src/foo.rs", "fn main() {}")
.build();
p.cargo("build")
.with_status(101)
.with_stderr_contains(
2018-03-14 15:17:44 +00:00
"\
[ERROR] failed to parse manifest at `[..]`
Caused by:
2018-03-14 15:17:44 +00:00
can't find `foo` bin, specify bin.path",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
2017-10-23 09:18:12 +00:00
fn inferred_bins() {
let p = project()
.file("src/main.rs", "fn main() {}")
.file("src/bin/bar.rs", "fn main() {}")
2017-10-23 09:18:12 +00:00
.file("src/bin/baz/main.rs", "fn main() {}")
.build();
p.cargo("build").run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("foo").is_file());
assert!(p.bin("bar").is_file());
assert!(p.bin("baz").is_file());
}
#[cargo_test]
2017-10-23 09:18:12 +00:00
fn inferred_bins_duplicate_name() {
// this should fail, because we have two binaries with the same name
let p = project()
.file("src/main.rs", "fn main() {}")
.file("src/bin/bar.rs", "fn main() {}")
.file("src/bin/bar/main.rs", "fn main() {}")
.build();
p.cargo("build").with_status(101).with_stderr_contains(
"[..]found duplicate binary name bar, but all binary targets must have a unique name[..]",
)
.run();
}
#[cargo_test]
2017-10-23 09:18:12 +00:00
fn inferred_bin_path() {
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
[[bin]]
name = "bar"
# Note, no `path` key!
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/bin/bar/main.rs", "fn main() {}")
.build();
p.cargo("build").run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("bar").is_file());
}
#[cargo_test]
2017-09-15 13:37:34 +00:00
fn inferred_examples() {
let p = project()
2017-09-15 13:37:34 +00:00
.file("src/lib.rs", "fn main() {}")
.file("examples/bar.rs", "fn main() {}")
.file("examples/baz/main.rs", "fn main() {}")
.build();
2017-09-15 13:37:34 +00:00
2019-02-19 17:32:07 +00:00
p.cargo("build --examples").run();
2018-08-29 06:11:10 +00:00
assert!(p.bin("examples/bar").is_file());
assert!(p.bin("examples/baz").is_file());
2017-09-15 13:37:34 +00:00
}
#[cargo_test]
2017-09-15 13:37:34 +00:00
fn inferred_tests() {
let p = project()
2017-09-15 13:37:34 +00:00
.file("src/lib.rs", "fn main() {}")
.file("tests/bar.rs", "fn main() {}")
.file("tests/baz/main.rs", "fn main() {}")
.build();
2017-09-15 13:37:34 +00:00
p.cargo("test --test=bar --test=baz").run();
2017-09-15 13:37:34 +00:00
}
#[cargo_test]
2017-10-23 09:18:12 +00:00
fn inferred_benchmarks() {
let p = project()
2017-09-15 13:37:34 +00:00
.file("src/lib.rs", "fn main() {}")
.file("benches/bar.rs", "fn main() {}")
2017-10-23 09:18:12 +00:00
.file("benches/baz/main.rs", "fn main() {}")
.build();
2017-09-15 13:37:34 +00:00
p.cargo("bench --bench=bar --bench=baz").run();
2017-09-15 13:37:34 +00:00
}
#[cargo_test]
fn target_edition() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
[lib]
edition = "2018"
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.build();
p.cargo("build -v")
2019-02-03 04:01:23 +00:00
// Passes on nightly, fails on stable, since `--edition` is nightly-only.
.without_status()
.with_stderr_contains(
"\
[COMPILING] foo v0.0.1 ([..])
[RUNNING] `rustc [..]--edition=2018 [..]
",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn target_edition_override() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
edition = "2018"
[lib]
edition = "2015"
"#,
2018-12-08 11:19:47 +00:00
)
.file(
"src/lib.rs",
"
pub fn async() {}
pub fn try() {}
pub fn await() {}
2018-12-08 11:19:47 +00:00
",
)
.build();
p.cargo("build -v").run();
}
#[cargo_test]
fn same_metadata_different_directory() {
// A top-level crate built in two different workspaces should have the
// same metadata hash.
let p = project()
.at("foo1")
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
.build();
let output = t!(String::from_utf8(
t!(p.cargo("build -v").exec_with_output()).stderr,
));
let metadata = output
.split_whitespace()
2017-09-24 14:26:37 +00:00
.find(|arg| arg.starts_with("metadata="))
.unwrap();
let p = project()
.at("foo2")
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
.build();
p.cargo("build -v")
.with_stderr_contains(format!("[..]{}[..]", metadata))
.run();
}
#[cargo_test]
fn building_a_dependent_crate_witout_bin_should_fail() {
Package::new("testless", "0.1.0")
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "testless"
version = "0.1.0"
[[bin]]
name = "a_bin"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.publish();
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.1.0"
[dependencies]
testless = "0.1.0"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/lib.rs", "")
.build();
p.cargo("build")
.with_status(101)
.with_stderr_contains("[..]can't find `a_bin` bin, specify bin.path")
.run();
}
2017-10-13 19:13:32 +00:00
#[cargo_test]
#[cfg(any(target_os = "macos", target_os = "ios"))]
2017-10-13 19:13:32 +00:00
fn uplift_dsym_of_bin_on_mac() {
let p = project()
2017-10-13 19:13:32 +00:00
.file("src/main.rs", "fn main() { panic!(); }")
.file("src/bin/b.rs", "fn main() { panic!(); }")
.file("examples/c.rs", "fn main() { panic!(); }")
.file("tests/d.rs", "fn main() { panic!(); }")
.build();
p.cargo("build --bins --examples --tests").run();
assert!(p.target_debug_dir().join("foo.dSYM").is_dir());
assert!(p.target_debug_dir().join("b.dSYM").is_dir());
assert!(p.target_debug_dir().join("b.dSYM").is_symlink());
assert!(p.target_debug_dir().join("examples/c.dSYM").is_symlink());
assert!(!p.target_debug_dir().join("c.dSYM").exists());
assert!(!p.target_debug_dir().join("d.dSYM").exists());
2017-10-13 19:13:32 +00:00
}
Fix dSYM uplifting when symlink is broken We were sporadically but persistently seeing errors like failed to link or copy `.../target/debugs/deps/bin-264030cd6c8a02be.dSYM` to `.../target/debug/bin.dSYM` Caused by: the source path is not an existing regular file while running `cargo build`. Once the error occurs once, `cargo build` will fail forever with the same error until `target/debug/bin.dSYM` is manually unlinked. After some investigation, I've determined that this situation arises when the target of `bin.dSYM` goes missing. For example, if bin.dSYM is pointing at `deps/bin-86908f0fa7f1440e.dSYM`, and `deps/bin-86908f0fa7f1440e.dSYM` does not exist, then this error will occur. I'm still not clear on why the underlying dSYM bundle sporadically goes missing--perhaps it's the result of pressing Ctrl-C at the wrong moment?--but Cargo should at least be able to handle this situation better. It turns out that Cargo was getting confused by the broken symlink. When it goes to install the new `target/debug/bin.dSYM` link, it will remove the existing `target/debug/bin.dSYM` file, if it exists. Unfortunately, Cargo was checking whether the *target* of that symlink existed (e.g., `deps/bin-86908f0fa7f1440e.dSYM`, which in the buggy case would not exist), rather than the symlink itself, deciding that there was no existing symlink to remove, and crashing with EEXIST when trying to install the new symlink. This commit adjusts the existence check to evaluate whether the symlink itself exists, rather than its target. Note that while the symptoms are the same as #4671, the root cause is unrelated.
2019-08-19 20:45:42 +00:00
#[cargo_test]
#[cfg(any(target_os = "macos", target_os = "ios"))]
fn uplift_dsym_of_bin_on_mac_when_broken_link_exists() {
let p = project()
.file("src/main.rs", "fn main() { panic!(); }")
.build();
let dsym = p.target_debug_dir().join("foo.dSYM");
p.cargo("build").run();
assert!(dsym.is_dir());
// Simulate the situation where the underlying dSYM bundle goes missing
// but the uplifted symlink to it remains. This would previously cause
// builds to permanently fail until the bad symlink was manually removed.
dsym.rm_rf();
p.symlink(
p.target_debug_dir()
.join("deps")
.join("foo-baaaaaadbaaaaaad.dSYM"),
&dsym,
);
assert!(dsym.is_symlink());
assert!(!dsym.exists());
p.cargo("build").run();
assert!(dsym.is_dir());
}
#[cargo_test]
#[cfg(all(target_os = "windows", target_env = "msvc"))]
fn uplift_pdb_of_bin_on_windows() {
let p = project()
.file("src/main.rs", "fn main() { panic!(); }")
.file("src/bin/b.rs", "fn main() { panic!(); }")
.file("examples/c.rs", "fn main() { panic!(); }")
.file("tests/d.rs", "fn main() { panic!(); }")
.build();
p.cargo("build --bins --examples --tests").run();
2018-08-29 06:11:10 +00:00
assert!(p.target_debug_dir().join("foo.pdb").is_file());
assert!(p.target_debug_dir().join("b.pdb").is_file());
assert!(p.target_debug_dir().join("examples/c.pdb").exists());
assert!(!p.target_debug_dir().join("c.pdb").exists());
assert!(!p.target_debug_dir().join("d.pdb").exists());
}
2019-02-03 04:01:23 +00:00
// Ensure that `cargo build` chooses the correct profile for building
// targets based on filters (assuming `--profile` is not specified).
#[cargo_test]
fn build_filter_infer_profile() {
let p = project()
.file("src/lib.rs", "")
.file("src/main.rs", "fn main() {}")
.file("tests/t1.rs", "")
.file("benches/b1.rs", "")
.file("examples/ex1.rs", "fn main() {}")
.build();
p.cargo("build -v")
.with_stderr_contains(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
--emit=[..]link[..]",
2018-12-08 11:19:47 +00:00
)
.with_stderr_contains(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--crate-type bin \
--emit=[..]link[..]",
2018-12-08 11:19:47 +00:00
)
.run();
p.root().join("target").rm_rf();
p.cargo("build -v --test=t1")
.with_stderr_contains(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
--emit=[..]link -C debuginfo=2 [..]",
2018-12-08 11:19:47 +00:00
)
.with_stderr_contains(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name t1 tests/t1.rs [..]--emit=[..]link \
2018-12-08 11:19:47 +00:00
-C debuginfo=2 [..]",
)
.with_stderr_contains(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--crate-type bin \
--emit=[..]link -C debuginfo=2 [..]",
2018-12-08 11:19:47 +00:00
)
.run();
p.root().join("target").rm_rf();
// Bench uses test profile without `--release`.
p.cargo("build -v --bench=b1")
.with_stderr_contains(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
--emit=[..]link -C debuginfo=2 [..]",
2018-12-08 11:19:47 +00:00
)
.with_stderr_contains(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name b1 benches/b1.rs [..]--emit=[..]link \
2018-12-08 11:19:47 +00:00
-C debuginfo=2 [..]",
)
.with_stderr_does_not_contain("opt-level")
.with_stderr_contains(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--crate-type bin \
--emit=[..]link -C debuginfo=2 [..]",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn targets_selected_default() {
let p = project().file("src/main.rs", "fn main() {}").build();
p.cargo("build -v")
2019-02-03 04:01:23 +00:00
// Binaries.
2018-12-08 11:19:47 +00:00
.with_stderr_contains(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--crate-type bin \
--emit=[..]link[..]",
2018-12-08 11:19:47 +00:00
)
2019-02-03 04:01:23 +00:00
// Benchmarks.
2018-12-08 11:19:47 +00:00
.with_stderr_does_not_contain(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--emit=[..]link \
2018-12-08 11:19:47 +00:00
-C opt-level=3 --test [..]",
)
2019-02-03 04:01:23 +00:00
// Unit tests.
2018-12-08 11:19:47 +00:00
.with_stderr_does_not_contain(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--emit=[..]link \
2018-12-08 11:19:47 +00:00
-C debuginfo=2 --test [..]",
)
.run();
}
#[cargo_test]
fn targets_selected_all() {
let p = project().file("src/main.rs", "fn main() {}").build();
p.cargo("build -v --all-targets")
2019-02-03 04:01:23 +00:00
// Binaries.
2018-12-08 11:19:47 +00:00
.with_stderr_contains(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--crate-type bin \
--emit=[..]link[..]",
2018-12-08 11:19:47 +00:00
)
2019-02-03 04:01:23 +00:00
// Unit tests.
2018-12-08 11:19:47 +00:00
.with_stderr_contains(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--emit=[..]link \
2018-12-08 11:19:47 +00:00
-C debuginfo=2 --test [..]",
)
.run();
2018-03-15 15:20:15 +00:00
}
#[cargo_test]
fn all_targets_no_lib() {
let p = project().file("src/main.rs", "fn main() {}").build();
p.cargo("build -v --all-targets")
2019-02-03 04:01:23 +00:00
// Binaries.
2018-12-08 11:19:47 +00:00
.with_stderr_contains(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--crate-type bin \
--emit=[..]link[..]",
2018-12-08 11:19:47 +00:00
)
2019-02-03 04:01:23 +00:00
// Unit tests.
2018-12-08 11:19:47 +00:00
.with_stderr_contains(
2019-09-25 01:17:36 +00:00
"[RUNNING] `rustc --crate-name foo src/main.rs [..]--emit=[..]link \
2018-12-08 11:19:47 +00:00
-C debuginfo=2 --test [..]",
)
.run();
}
#[cargo_test]
fn no_linkable_target() {
2019-02-03 04:01:23 +00:00
// Issue 3169: this is currently not an error as per discussion in PR #4797.
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
[dependencies]
the_lib = { path = "the_lib" }
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "fn main() {}")
2018-03-14 15:17:44 +00:00
.file(
"the_lib/Cargo.toml",
r#"
[package]
name = "the_lib"
version = "0.1.0"
[lib]
name = "the_lib"
crate-type = ["staticlib"]
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("the_lib/src/lib.rs", "pub fn foo() {}")
.build();
p.cargo("build")
.with_stderr_contains(
2019-07-13 23:00:47 +00:00
"[WARNING] The package `the_lib` provides no linkable [..] \
2018-03-14 15:17:44 +00:00
while compiling `foo`. [..] in `the_lib`'s Cargo.toml. [..]",
2018-12-08 11:19:47 +00:00
)
.run();
}
#[cargo_test]
fn avoid_dev_deps() {
Package::new("foo", "1.0.0").publish();
let p = project()
2018-03-14 15:17:44 +00:00
.file(
"Cargo.toml",
r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
[dev-dependencies]
baz = "1.0.0"
2018-03-14 15:17:44 +00:00
"#,
2018-12-08 11:19:47 +00:00
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("build")
.with_status(101)
.with_stderr(
"\
[UPDATING] [..]
[ERROR] no matching package named `baz` found
location searched: registry `https://github.com/rust-lang/crates.io-index`
required by package `bar v0.1.0 ([..]/foo)`
",
)
.run();
p.cargo("build -Zavoid-dev-deps")
.masquerade_as_nightly_cargo()
.run();
}
#[cargo_test]
fn default_cargo_config_jobs() {
let p = project()
.file("src/lib.rs", "")
.file(
".cargo/config",
r#"
[build]
jobs = 1
"#,
)
.build();
p.cargo("build -v").run();
}
#[cargo_test]
fn good_cargo_config_jobs() {
let p = project()
.file("src/lib.rs", "")
.file(
".cargo/config",
r#"
[build]
jobs = 4
"#,
)
.build();
p.cargo("build -v").run();
}
#[cargo_test]
fn invalid_jobs() {
let p = project()
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
.build();
p.cargo("build --jobs -1")
.with_status(1)
.with_stderr_contains(
"error: Found argument '-1' which wasn't expected, or isn't valid in this context",
)
.run();
p.cargo("build --jobs over9000")
.with_status(1)
.with_stderr("error: Invalid value: could not parse `over9000` as a number")
.run();
}
#[cargo_test]
fn target_filters_workspace() {
let ws = project()
.at("ws")
.file(
"Cargo.toml",
r#"
[workspace]
members = ["a", "b"]
"#,
2018-12-08 11:19:47 +00:00
)
.file("a/Cargo.toml", &basic_lib_manifest("a"))
.file("a/src/lib.rs", "")
.file("a/examples/ex1.rs", "fn main() {}")
.file("b/Cargo.toml", &basic_bin_manifest("b"))
2018-11-12 15:13:13 +00:00
.file("b/src/lib.rs", "")
.file("b/src/main.rs", "fn main() {}")
.build();
ws.cargo("build -v --example ex")
.with_status(101)
.with_stderr(
"\
[ERROR] no example target named `ex`
2019-06-21 18:36:53 +00:00
<tab>Did you mean `ex1`?",
2018-12-08 11:19:47 +00:00
)
.run();
ws.cargo("build -v --lib")
.with_stderr_contains("[RUNNING] `rustc [..]a/src/lib.rs[..]")
2018-11-12 15:13:13 +00:00
.with_stderr_contains("[RUNNING] `rustc [..]b/src/lib.rs[..]")
.run();
ws.cargo("build -v --example ex1")
.with_stderr_contains("[RUNNING] `rustc [..]a/examples/ex1.rs[..]")
.run();
}
#[cargo_test]
fn target_filters_workspace_not_found() {
let ws = project()
.at("ws")
.file(
"Cargo.toml",
r#"
[workspace]
members = ["a", "b"]
"#,
2018-12-08 11:19:47 +00:00
)
.file("a/Cargo.toml", &basic_bin_manifest("a"))
.file("a/src/main.rs", "fn main() {}")
.file("b/Cargo.toml", &basic_bin_manifest("b"))
.file("b/src/main.rs", "fn main() {}")
.build();
ws.cargo("build -v --lib")
.with_status(101)
.with_stderr("[ERROR] no library targets found in packages: a, b")
.run();
}
#[cfg(unix)]
#[cargo_test]
fn signal_display() {
// Cause the compiler to crash with a signal.
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[dependencies]
pm = { path = "pm" }
"#,
)
.file(
"src/lib.rs",
r#"
#[macro_use]
extern crate pm;
#[derive(Foo)]
pub struct S;
"#,
)
.file(
"pm/Cargo.toml",
r#"
[package]
name = "pm"
version = "0.1.0"
[lib]
proc-macro = true
"#,
)
.file(
"pm/src/lib.rs",
r#"
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_derive(Foo)]
pub fn derive(_input: TokenStream) -> TokenStream {
std::process::abort()
}
"#,
)
.build();
foo.cargo("build")
2018-12-08 11:19:47 +00:00
.with_stderr(
"\
[COMPILING] pm [..]
[COMPILING] foo [..]
[ERROR] could not compile `foo`.
Caused by:
process didn't exit successfully: `rustc [..]` (signal: 6, SIGABRT: process abort signal)
2018-12-08 11:19:47 +00:00
",
)
.with_status(101)
.run();
}
#[cargo_test]
fn tricky_pipelining() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[dependencies]
bar = { path = "bar" }
"#,
)
.file("src/lib.rs", "extern crate bar;")
.file("bar/Cargo.toml", &basic_lib_manifest("bar"))
.file("bar/src/lib.rs", "")
.build();
foo.cargo("build -p bar")
.env("CARGO_BUILD_PIPELINING", "true")
.run();
foo.cargo("build -p foo")
.env("CARGO_BUILD_PIPELINING", "true")
.run();
}
#[cargo_test]
fn pipelining_works() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[dependencies]
bar = { path = "bar" }
"#,
)
.file("src/lib.rs", "extern crate bar;")
.file("bar/Cargo.toml", &basic_lib_manifest("bar"))
.file("bar/src/lib.rs", "")
.build();
foo.cargo("build")
.env("CARGO_BUILD_PIPELINING", "true")
.with_stdout("")
2019-05-20 19:36:59 +00:00
.with_stderr(
"\
[COMPILING] [..]
[COMPILING] [..]
[FINISHED] [..]
2019-05-20 19:36:59 +00:00
",
)
.run();
}
#[cargo_test]
fn pipelining_big_graph() {
2019-07-03 14:11:23 +00:00
// Create a crate graph of the form {a,b}{0..29}, where {a,b}(n) depend on {a,b}(n+1)
// Then have `foo`, a binary crate, depend on the whole thing.
let mut project = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[dependencies]
a1 = { path = "a1" }
b1 = { path = "b1" }
"#,
)
.file("src/main.rs", "fn main(){}");
for n in 0..30 {
for x in &["a", "b"] {
project = project
.file(
&format!("{x}{n}/Cargo.toml", x = x, n = n),
&format!(
r#"
[package]
name = "{x}{n}"
version = "0.1.0"
[dependencies]
a{np1} = {{ path = "../a{np1}" }}
b{np1} = {{ path = "../b{np1}" }}
"#,
x = x,
n = n,
np1 = n + 1
),
)
.file(&format!("{x}{n}/src/lib.rs", x = x, n = n), "");
}
}
let foo = project
.file("a30/Cargo.toml", &basic_lib_manifest("a30"))
.file(
"a30/src/lib.rs",
r#"compile_error!("don't actually build me");"#,
)
.file("b30/Cargo.toml", &basic_lib_manifest("b30"))
.file("b30/src/lib.rs", "")
.build();
foo.cargo("build -p foo")
.env("CARGO_BUILD_PIPELINING", "true")
.with_status(101)
.with_stderr_contains("[ERROR] could not compile `a30`[..]")
.run();
}
#[cargo_test]
fn forward_rustc_output() {
let foo = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = '2018'
[dependencies]
bar = { path = "bar" }
"#,
)
.file("src/lib.rs", "bar::foo!();")
.file(
"bar/Cargo.toml",
r#"
[package]
name = "bar"
version = "0.1.0"
[lib]
proc-macro = true
"#,
)
.file(
"bar/src/lib.rs",
r#"
extern crate proc_macro;
use proc_macro::*;
#[proc_macro]
pub fn foo(input: TokenStream) -> TokenStream {
println!("a");
println!("b");
println!("{{}}");
eprintln!("c");
eprintln!("d");
eprintln!("{{a"); // "malformed json"
input
}
"#,
)
.build();
foo.cargo("build")
.with_stdout("a\nb\n{}")
2019-05-20 19:36:59 +00:00
.with_stderr(
"\
[COMPILING] [..]
[COMPILING] [..]
c
d
{a
[FINISHED] [..]
2019-05-20 19:36:59 +00:00
",
)
.run();
}
2019-11-25 02:42:45 +00:00
#[cargo_test]
fn build_lib_only() {
let p = project()
.file("src/main.rs", "fn main() {}")
.file("src/lib.rs", r#" "#)
.build();
p.cargo("build --lib -v")
.with_stderr(
"\
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib \
--emit=[..]link -C debuginfo=2 \
-C metadata=[..] \
--out-dir [..] \
-L dependency=[CWD]/target/debug/deps`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
)
.run();
}
#[cargo_test]
fn build_with_no_lib() {
let p = project()
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("build --lib")
.with_status(101)
.with_stderr("[ERROR] no library targets found in package `foo`")
.run();
}
#[cargo_test]
fn build_with_relative_cargo_home_path() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = ["wycats@example.com"]
[dependencies]
"test-dependency" = { path = "src/test_dependency" }
"#,
)
.file("src/main.rs", "fn main() {}")
.file("src/test_dependency/src/lib.rs", r#" "#)
.file(
"src/test_dependency/Cargo.toml",
&basic_manifest("test-dependency", "0.0.1"),
)
.build();
p.cargo("build").env("CARGO_HOME", "./cargo_home/").run();
}
#[cargo_test]
fn user_specific_cfgs_are_filtered_out() {
let p = project()
.file("Cargo.toml", &basic_bin_manifest("foo"))
.file("src/main.rs", r#"fn main() {}"#)
.file(
"build.rs",
r#"
fn main() {
assert!(std::env::var_os("CARGO_CFG_PROC_MACRO").is_none());
assert!(std::env::var_os("CARGO_CFG_DEBUG_ASSERTIONS").is_none());
}"#,
)
.build();
p.cargo("rustc -- --cfg debug_assertions --cfg proc_macro")
.run();
p.process(&p.bin("foo")).run();
}