mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-28 11:20:36 +00:00
auto merge of #142 : rust-lang/cargo/new-names, r=alexcrichton
This PR moves Cargo over to the new naming based on [RFC 35](https://github.com/rust-lang/rfcs/blob/master/complete/0035-remove-crate-id.md). * You should no longer use `#[crate_name]` or `#[crate_id]` in any crate managed by Cargo. * You no longer need a `[[lib]]` section in your `Cargo.toml` if you name your library `src/lib.rs`. * You no longer need a `[[bin]]` section in your `Cargo.toml` if you name your library `src/main.rs`. * You can include multiple `[[bins]]` in `src/bin/*.rs` and Cargo will treat them as if they were specified via `[[bin]]`. This commit does not yet add support for `-C metadata` or `-C extra-file-name`, but that is coming soon.
This commit is contained in:
commit
a6061db0d0
@ -49,9 +49,6 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
|
||||
}))
|
||||
};
|
||||
|
||||
let update = options.update_remotes;
|
||||
let jobs = options.jobs;
|
||||
|
||||
let env = if options.release {
|
||||
"release"
|
||||
} else {
|
||||
|
@ -9,7 +9,7 @@ extern crate serialize;
|
||||
extern crate hammer;
|
||||
|
||||
use std::os;
|
||||
use std::io::fs;
|
||||
use std::io::{UserExecute, fs};
|
||||
|
||||
use cargo::ops;
|
||||
use cargo::{execute_main_without_stdin};
|
||||
@ -65,7 +65,7 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
|
||||
// TODO: The proper fix is to have target knows its expected
|
||||
// output and only run expected executables.
|
||||
if file.display().to_str().as_slice().contains("dSYM") { continue; }
|
||||
if !file.is_file() { continue; }
|
||||
if !is_executable(&file) { continue; }
|
||||
|
||||
try!(util::process(file).exec().map_err(|e| {
|
||||
CliError::from_boxed(e.box_error(), 1)
|
||||
@ -74,3 +74,8 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn is_executable(path: &Path) -> bool {
|
||||
if !path.is_file() { return false; }
|
||||
path.stat().map(|stat| stat.perm.intersects(UserExecute)).unwrap_or(false)
|
||||
}
|
||||
|
@ -310,6 +310,10 @@ impl Target {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_name<'a>(&'a self) -> &'a str {
|
||||
self.name.as_slice()
|
||||
}
|
||||
|
||||
pub fn get_path<'a>(&'a self) -> &'a Path {
|
||||
&self.path
|
||||
}
|
||||
|
@ -4,11 +4,12 @@ use util;
|
||||
use core::{Package,Manifest,SourceId};
|
||||
use util::{CargoResult, human};
|
||||
use util::important_paths::find_project_manifest_exact;
|
||||
use util::toml::{Layout, project_layout};
|
||||
|
||||
pub fn read_manifest(contents: &[u8], source_id: &SourceId)
|
||||
pub fn read_manifest(contents: &[u8], layout: Layout, source_id: &SourceId)
|
||||
-> CargoResult<(Manifest, Vec<Path>)>
|
||||
{
|
||||
util::toml::to_manifest(contents, source_id).map_err(human)
|
||||
util::toml::to_manifest(contents, source_id, layout).map_err(human)
|
||||
}
|
||||
|
||||
pub fn read_package(path: &Path, source_id: &SourceId)
|
||||
@ -17,8 +18,10 @@ pub fn read_package(path: &Path, source_id: &SourceId)
|
||||
log!(5, "read_package; path={}; source-id={}", path.display(), source_id);
|
||||
let mut file = try!(File::open(path));
|
||||
let data = try!(file.read_to_end());
|
||||
let (manifest, nested) = try!(read_manifest(data.as_slice(),
|
||||
source_id));
|
||||
|
||||
let layout = project_layout(&path.dir_path());
|
||||
let (manifest, nested) =
|
||||
try!(read_manifest(data.as_slice(), layout, source_id));
|
||||
|
||||
Ok((Package::new(manifest, path, source_id), nested))
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ fn rustc(root: &Path, target: &Target, cx: &mut Context) -> Job {
|
||||
|
||||
log!(5, "command={}", rustc);
|
||||
|
||||
cx.config.shell().verbose(|shell| shell.status("Running", rustc.to_str()));
|
||||
let _ = cx.config.shell().verbose(|shell| shell.status("Running", rustc.to_str()));
|
||||
|
||||
proc() {
|
||||
if primary {
|
||||
@ -248,12 +248,16 @@ fn build_base_args(into: &mut Args, target: &Target, crate_types: Vec<&str>,
|
||||
cx: &Context) {
|
||||
// TODO: Handle errors in converting paths into args
|
||||
into.push(target.get_path().display().to_str());
|
||||
|
||||
into.push("--crate-name".to_str());
|
||||
into.push(target.get_name().to_str());
|
||||
|
||||
for crate_type in crate_types.iter() {
|
||||
into.push("--crate-type".to_str());
|
||||
into.push(crate_type.to_str());
|
||||
}
|
||||
|
||||
let mut out = cx.dest.clone();
|
||||
let out = cx.dest.clone();
|
||||
let profile = target.get_profile();
|
||||
|
||||
if profile.get_opt_level() != 0 {
|
||||
@ -269,8 +273,13 @@ fn build_base_args(into: &mut Args, target: &Target, crate_types: Vec<&str>,
|
||||
into.push("--test".to_str());
|
||||
}
|
||||
|
||||
into.push("--out-dir".to_str());
|
||||
into.push(out.display().to_str());
|
||||
if target.is_lib() {
|
||||
into.push("--out-dir".to_str());
|
||||
into.push(out.display().to_str());
|
||||
} else {
|
||||
into.push("-o".to_str());
|
||||
into.push(out.join(target.get_name()).display().to_str());
|
||||
}
|
||||
}
|
||||
|
||||
fn build_deps_args(dst: &mut Args, cx: &Context) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
use serialize::Decodable;
|
||||
use std::collections::HashMap;
|
||||
use std::str;
|
||||
use std::io::fs;
|
||||
use toml;
|
||||
|
||||
use core::{SourceId, GitKind};
|
||||
@ -9,8 +10,52 @@ use core::{Summary, Manifest, Target, Dependency, PackageId};
|
||||
use core::source::Location;
|
||||
use util::{CargoResult, Require, human};
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct Layout {
|
||||
lib: Option<Path>,
|
||||
bins: Vec<Path>
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
fn main<'a>(&'a self) -> Option<&'a Path> {
|
||||
self.bins.iter().find(|p| {
|
||||
match p.filename_str() {
|
||||
Some(s) => s == "main.rs",
|
||||
None => false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn project_layout(root: &Path) -> Layout {
|
||||
let mut lib = None;
|
||||
let mut bins = vec!();
|
||||
|
||||
if root.join("src/lib.rs").exists() {
|
||||
lib = Some(root.join("src/lib.rs"));
|
||||
}
|
||||
|
||||
if root.join("src/main.rs").exists() {
|
||||
bins.push(root.join("src/main.rs"));
|
||||
}
|
||||
|
||||
fs::readdir(&root.join("src/bin"))
|
||||
.map(|v| v.move_iter())
|
||||
.map(|i| i.filter(|f| f.extension_str() == Some("rs")))
|
||||
.map(|mut i| i.collect())
|
||||
.map(|found| bins.push_all_move(found));
|
||||
|
||||
Layout {
|
||||
lib: lib,
|
||||
bins: bins
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_manifest(contents: &[u8],
|
||||
source_id: &SourceId) -> CargoResult<(Manifest, Vec<Path>)> {
|
||||
source_id: &SourceId,
|
||||
layout: Layout)
|
||||
-> CargoResult<(Manifest, Vec<Path>)>
|
||||
{
|
||||
let contents = try!(str::from_utf8(contents).require(|| {
|
||||
human("Cargo.toml is not valid UTF-8")
|
||||
}));
|
||||
@ -22,7 +67,7 @@ pub fn to_manifest(contents: &[u8],
|
||||
manifest\n\n{}", e)))
|
||||
};
|
||||
|
||||
let pair = try!(toml_manifest.to_manifest(source_id).map_err(|err| {
|
||||
let pair = try!(toml_manifest.to_manifest(source_id, &layout).map_err(|err| {
|
||||
human(format!("Cargo.toml is not a valid manifest\n\n{}", err))
|
||||
}));
|
||||
let (mut manifest, paths) = pair;
|
||||
@ -55,8 +100,6 @@ pub fn to_manifest(contents: &[u8],
|
||||
_ => m.add_unused_key(key),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
pub fn parse(toml: &str, file: &str) -> CargoResult<toml::Table> {
|
||||
@ -145,16 +188,98 @@ struct Context<'a> {
|
||||
nested_paths: &'a mut Vec<Path>
|
||||
}
|
||||
|
||||
// These functions produce the equivalent of specific manifest entries. One
|
||||
// wrinkle is that certain paths cannot be represented in the manifest due
|
||||
// to Toml's UTF-8 requirement. This could, in theory, mean that certain
|
||||
// otherwise acceptable executable names are not used when inside of
|
||||
// `src/bin/*`, but it seems ok to not build executables with non-UTF8
|
||||
// paths.
|
||||
fn inferred_lib_target(name: &str, layout: &Layout) -> Option<Vec<TomlTarget>> {
|
||||
layout.lib.as_ref().map(|lib| {
|
||||
vec![TomlTarget {
|
||||
name: name.to_str(),
|
||||
crate_type: None,
|
||||
path: Some(lib.display().to_str()),
|
||||
test: None
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
fn inferred_bin_targets(name: &str, layout: &Layout) -> Option<Vec<TomlTarget>> {
|
||||
Some(layout.bins.iter().filter_map(|bin| {
|
||||
let name = if bin.as_str() == Some("src/main.rs") {
|
||||
Some(name.to_str())
|
||||
} else {
|
||||
bin.filestem_str().map(|f| f.to_str())
|
||||
};
|
||||
|
||||
name.map(|name| {
|
||||
TomlTarget {
|
||||
name: name,
|
||||
crate_type: None,
|
||||
path: Some(bin.display().to_str()),
|
||||
test: None
|
||||
}
|
||||
})
|
||||
}).collect())
|
||||
}
|
||||
|
||||
impl TomlManifest {
|
||||
pub fn to_manifest(&self, source_id: &SourceId)
|
||||
pub fn to_manifest(&self, source_id: &SourceId, layout: &Layout)
|
||||
-> CargoResult<(Manifest, Vec<Path>)>
|
||||
{
|
||||
let mut sources = vec!();
|
||||
let mut nested_paths = vec!();
|
||||
|
||||
let project = self.project.as_ref().or_else(|| self.package.as_ref());
|
||||
let project = try!(project.require(|| {
|
||||
human("No `package` or `project` section found.")
|
||||
}));
|
||||
|
||||
|
||||
// If we have no lib at all, use the inferred lib if available
|
||||
// If we have a lib with a path, we're done
|
||||
// If we have a lib with no path, use the inferred lib or_else package name
|
||||
|
||||
let lib = if self.lib.is_none() || self.lib.get_ref().is_empty() {
|
||||
inferred_lib_target(project.name.as_slice(), layout)
|
||||
} else {
|
||||
Some(self.lib.get_ref().iter().map(|t| {
|
||||
if layout.lib.is_some() && t.path.is_none() {
|
||||
TomlTarget {
|
||||
name: t.name.clone(),
|
||||
crate_type: t.crate_type.clone(),
|
||||
path: layout.lib.as_ref().map(|p| p.display().to_str()),
|
||||
test: t.test
|
||||
}
|
||||
} else {
|
||||
t.clone()
|
||||
}
|
||||
}).collect())
|
||||
};
|
||||
|
||||
let bins = if self.bin.is_none() || self.bin.get_ref().is_empty() {
|
||||
inferred_bin_targets(project.name.as_slice(), layout)
|
||||
} else {
|
||||
let bin = layout.main();
|
||||
|
||||
Some(self.bin.get_ref().iter().map(|t| {
|
||||
if bin.is_some() && t.path.is_none() {
|
||||
TomlTarget {
|
||||
name: t.name.clone(),
|
||||
crate_type: t.crate_type.clone(),
|
||||
path: bin.as_ref().map(|p| p.display().to_str()),
|
||||
test: t.test
|
||||
}
|
||||
} else {
|
||||
t.clone()
|
||||
}
|
||||
}).collect())
|
||||
};
|
||||
|
||||
// Get targets
|
||||
let targets = normalize(self.lib.as_ref().map(|l| l.as_slice()),
|
||||
self.bin.as_ref().map(|b| b.as_slice()));
|
||||
let targets = normalize(lib.as_ref().map(|l| l.as_slice()),
|
||||
bins.as_ref().map(|b| b.as_slice()));
|
||||
|
||||
if targets.is_empty() {
|
||||
debug!("manifest has no build targets; project={}", self.project);
|
||||
@ -176,11 +301,6 @@ impl TomlManifest {
|
||||
try!(process_dependencies(&mut cx, true, self.dev_dependencies.as_ref()));
|
||||
}
|
||||
|
||||
let project = self.project.as_ref().or_else(|| self.package.as_ref());
|
||||
let project = try!(project.require(|| {
|
||||
human("No `package` or `project` section found.")
|
||||
}));
|
||||
|
||||
let pkgid = try!(project.to_package_id(source_id.get_location()));
|
||||
let summary = Summary::new(&pkgid, deps.as_slice());
|
||||
Ok((Manifest::new(
|
||||
@ -257,7 +377,9 @@ struct TomlTarget {
|
||||
}
|
||||
|
||||
fn normalize(lib: Option<&[TomlLibTarget]>,
|
||||
bin: Option<&[TomlBinTarget]>) -> Vec<Target> {
|
||||
bin: Option<&[TomlBinTarget]>)
|
||||
-> Vec<Target>
|
||||
{
|
||||
log!(4, "normalizing toml targets; lib={}; bin={}", lib, bin);
|
||||
|
||||
fn target_profiles(target: &TomlTarget) -> Vec<Profile> {
|
||||
|
@ -92,8 +92,8 @@ test!(cargo_compile_with_invalid_code {
|
||||
{filename}:1 invalid rust code!
|
||||
^~~~~~~
|
||||
Could not execute process \
|
||||
`rustc {filename} --crate-type bin -g --out-dir {} -L {} -L {}` (status=101)\n",
|
||||
target.display(),
|
||||
`rustc {filename} --crate-name foo --crate-type bin -g -o {} -L {} -L {}` (status=101)\n",
|
||||
target.join("foo").display(),
|
||||
target.display(),
|
||||
target.join("deps").display(),
|
||||
filename = format!("src{}foo.rs", path::SEP)).as_slice()));
|
||||
@ -176,6 +176,142 @@ test!(cargo_compile_with_warnings_in_a_dep_package {
|
||||
execs().with_stdout("test passed\n"));
|
||||
})
|
||||
|
||||
test!(cargo_compile_with_nested_deps_inferred {
|
||||
let mut p = project("foo");
|
||||
let bar = p.root().join("bar");
|
||||
let baz = p.root().join("baz");
|
||||
|
||||
p = p
|
||||
.file(".cargo/config", format!(r#"
|
||||
paths = ["{}", "{}"]
|
||||
"#, escape_path(&bar), escape_path(&baz)).as_slice())
|
||||
.file("Cargo.toml", r#"
|
||||
[project]
|
||||
|
||||
name = "foo"
|
||||
version = "0.5.0"
|
||||
authors = ["wycats@example.com"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
bar = "0.5.0"
|
||||
|
||||
[[bin]]
|
||||
|
||||
name = "foo"
|
||||
"#)
|
||||
.file("src/foo.rs",
|
||||
main_file(r#""{}", bar::gimme()"#, ["bar"]).as_slice())
|
||||
.file("bar/Cargo.toml", r#"
|
||||
[project]
|
||||
|
||||
name = "bar"
|
||||
version = "0.5.0"
|
||||
authors = ["wycats@example.com"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
baz = "0.5.0"
|
||||
"#)
|
||||
.file("bar/src/lib.rs", r#"
|
||||
extern crate baz;
|
||||
|
||||
pub fn gimme() -> String {
|
||||
baz::gimme()
|
||||
}
|
||||
"#)
|
||||
.file("baz/Cargo.toml", r#"
|
||||
[project]
|
||||
|
||||
name = "baz"
|
||||
version = "0.5.0"
|
||||
authors = ["wycats@example.com"]
|
||||
"#)
|
||||
.file("baz/src/lib.rs", r#"
|
||||
pub fn gimme() -> String {
|
||||
"test passed".to_str()
|
||||
}
|
||||
"#);
|
||||
|
||||
p.cargo_process("cargo-build")
|
||||
.exec_with_output()
|
||||
.assert();
|
||||
|
||||
assert_that(&p.bin("foo"), existing_file());
|
||||
|
||||
assert_that(
|
||||
cargo::util::process(p.bin("foo")),
|
||||
execs().with_stdout("test passed\n"));
|
||||
})
|
||||
|
||||
test!(cargo_compile_with_nested_deps_correct_bin {
|
||||
let mut p = project("foo");
|
||||
let bar = p.root().join("bar");
|
||||
let baz = p.root().join("baz");
|
||||
|
||||
p = p
|
||||
.file(".cargo/config", format!(r#"
|
||||
paths = ["{}", "{}"]
|
||||
"#, escape_path(&bar), escape_path(&baz)).as_slice())
|
||||
.file("Cargo.toml", r#"
|
||||
[project]
|
||||
|
||||
name = "foo"
|
||||
version = "0.5.0"
|
||||
authors = ["wycats@example.com"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
bar = "0.5.0"
|
||||
|
||||
[[bin]]
|
||||
|
||||
name = "foo"
|
||||
"#)
|
||||
.file("src/main.rs",
|
||||
main_file(r#""{}", bar::gimme()"#, ["bar"]).as_slice())
|
||||
.file("bar/Cargo.toml", r#"
|
||||
[project]
|
||||
|
||||
name = "bar"
|
||||
version = "0.5.0"
|
||||
authors = ["wycats@example.com"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
baz = "0.5.0"
|
||||
"#)
|
||||
.file("bar/src/lib.rs", r#"
|
||||
extern crate baz;
|
||||
|
||||
pub fn gimme() -> String {
|
||||
baz::gimme()
|
||||
}
|
||||
"#)
|
||||
.file("baz/Cargo.toml", r#"
|
||||
[project]
|
||||
|
||||
name = "baz"
|
||||
version = "0.5.0"
|
||||
authors = ["wycats@example.com"]
|
||||
"#)
|
||||
.file("baz/src/lib.rs", r#"
|
||||
pub fn gimme() -> String {
|
||||
"test passed".to_str()
|
||||
}
|
||||
"#);
|
||||
|
||||
p.cargo_process("cargo-build")
|
||||
.exec_with_output()
|
||||
.assert();
|
||||
|
||||
assert_that(&p.bin("foo"), existing_file());
|
||||
|
||||
assert_that(
|
||||
cargo::util::process(p.bin("foo")),
|
||||
execs().with_stdout("test passed\n"));
|
||||
})
|
||||
|
||||
test!(cargo_compile_with_nested_deps_shorthand {
|
||||
let mut p = project("foo");
|
||||
let bar = p.root().join("bar");
|
||||
@ -636,18 +772,16 @@ test!(custom_build_in_dependency {
|
||||
version = "0.5.0"
|
||||
authors = ["wycats@example.com"]
|
||||
build = "{}"
|
||||
|
||||
[[lib]]
|
||||
name = "bar"
|
||||
"#, escape_path(&build.bin("foo"))))
|
||||
.file("bar/src/bar.rs", r#"
|
||||
.file("bar/src/lib.rs", r#"
|
||||
pub fn bar() {}
|
||||
"#);
|
||||
assert_that(p.cargo_process("cargo-build"),
|
||||
execs().with_status(0));
|
||||
})
|
||||
|
||||
test!(many_crate_types {
|
||||
// this is testing that src/<pkg-name>.rs still works (for now)
|
||||
test!(many_crate_types_old_style_lib_location {
|
||||
let mut p = project("foo");
|
||||
p = p
|
||||
.file("Cargo.toml", r#"
|
||||
@ -685,6 +819,44 @@ test!(many_crate_types {
|
||||
file1.ends_with(os::consts::DLL_SUFFIX));
|
||||
})
|
||||
|
||||
test!(many_crate_types_correct {
|
||||
let mut p = project("foo");
|
||||
p = p
|
||||
.file("Cargo.toml", r#"
|
||||
[project]
|
||||
|
||||
name = "foo"
|
||||
version = "0.5.0"
|
||||
authors = ["wycats@example.com"]
|
||||
|
||||
[[lib]]
|
||||
|
||||
name = "foo"
|
||||
crate_type = ["rlib", "dylib"]
|
||||
"#)
|
||||
.file("src/lib.rs", r#"
|
||||
pub fn foo() {}
|
||||
"#);
|
||||
assert_that(p.cargo_process("cargo-build"),
|
||||
execs().with_status(0));
|
||||
|
||||
let files = fs::readdir(&p.root().join("target")).assert();
|
||||
let mut files: Vec<String> = files.iter().filter_map(|f| {
|
||||
match f.filename_str().unwrap() {
|
||||
"deps" => None,
|
||||
s if s.contains("fingerprint") || s.contains("dSYM") => None,
|
||||
s => Some(s.to_str())
|
||||
}
|
||||
}).collect();
|
||||
files.sort();
|
||||
let file0 = files.get(0).as_slice();
|
||||
let file1 = files.get(1).as_slice();
|
||||
println!("{} {}", file0, file1);
|
||||
assert!(file0.ends_with(".rlib") || file1.ends_with(".rlib"));
|
||||
assert!(file0.ends_with(os::consts::DLL_SUFFIX) ||
|
||||
file1.ends_with(os::consts::DLL_SUFFIX));
|
||||
})
|
||||
|
||||
test!(unused_keys {
|
||||
let mut p = project("foo");
|
||||
p = p
|
||||
|
Loading…
x
Reference in New Issue
Block a user