-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Infer multi-file binaries like src/bin/server/main.rs
by convention
#4214
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @matklad (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
src/cargo/util/toml.rs
Outdated
}).map(|i| { | ||
i.path().join("main.rs") | ||
// Filter only directories where main.rs is present | ||
}).filter(|f| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like indentation is off here. I would format this as
fn try_add_mains_from_dirs(files: &mut Vec<PathBuf>, root: PathBuf) {
if let Ok(new) = fs::read_dir(&root) {
let new: Vec<PathBuf> = new.filter_map(|i| i.ok())
// Filter only directories
.filter(|i| {
i.file_type().map(|f| f.is_dir()).unwrap_or(false)
// Convert DirEntry into PathBuf and append "main.rs"
})
.map(|i| {
i.path().join("main.rs")
// Filter only directories where main.rs is present
})
.filter(|f| {
f.as_path()
.exists()
}).collect();
files.extend(new);
}
}
Awesome, @msehnout ! Could you add a test from the issue? This one:
It should be an error unless there are explicit Also, I think there's unfortunately one more code path that needs to be modified here. With the current implantation, I think that the following test will fail: Cargo.toml: [package]
name = "foo"
[[bin]]
name = "bar"
# Note, no `path` key! file layout:
What happens here (at least, this is what I think happens here, the logic is quite complicated :) ) is that Cargo won't use implicit targets from That is, there's an implicit contract between the |
tests/build.rs
Outdated
assert_that(&p.bin("bar2"), existing_file()); | ||
assert_that(&p.bin("bar3"), existing_file()); | ||
assert_that(&p.bin("bar4"), existing_file()); | ||
assert_that(&p.bin("main"), existing_file()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I don't think we should implicitly name binary main
... Does it happen with stable Cargo as well? Looks like a bug to me!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm using stable cargo and it creates a binary called "main" when there is src/bin/main.rs
Thanks for the review. I'll submit changes soon. :-) |
I tried to modify |
src/cargo/util/toml.rs
Outdated
if parent.ends_with("src/bin") { | ||
// This would always return name "main" | ||
// Fixme: Is this what we want? based on what @matklad said, I don't think so | ||
// bin.file_stem().and_then(|s| s.to_str()).map(|f| f.to_string()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is preexisting behavior, so we should leave it as is to preserve backwards compatibility. And I am not actually sure that this is wrong in the first place, it's just curious :)
tests/build.rs
Outdated
.file("src/bin/foo/main.rs", "fn main() {}"); | ||
|
||
// TODO: This should output the error from toml.rs:756 | ||
assert_that(p.cargo_process("build"), execs().with_status(101)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right! You could use with_stderr_contains
to check the error message.
It seems to work finally. Do you have any more comments regarding the code? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I believe the logic is quite correct and tests are thorough!
However, I think we've missed the most important part here: it's probably a good idea to document this new convention :)
The relevant docs are here: https://github.com/rust-lang/cargo/blob/64c3217eb459da25df9f9a9818b7775b4387ae8c/src/doc/manifest.md#the-project-layout.
We should tell that multiline binaries go to src/bin/foo/main.rs
by convention.
src/cargo/util/toml.rs
Outdated
@@ -505,7 +525,24 @@ fn inferred_bin_targets(name: &str, layout: &Layout) -> Vec<TomlTarget> { | |||
*bin == layout.root.join("src").join("main.rs") { | |||
Some(name.to_string()) | |||
} else { | |||
bin.file_stem().and_then(|s| s.to_str()).map(|f| f.to_string()) | |||
// bin is either a source file or a directory with main.rs inside. | |||
if bin.ends_with("main.rs") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's change this to bin.ends_with("main.rs") && !bin.ends_with("src/bin/main.rs")
so that we one if
inside.
src/cargo/util/toml.rs
Outdated
@@ -1463,6 +1500,12 @@ fn inferred_bin_path(bin: &TomlBinTarget, | |||
return path.to_path_buf() | |||
} | |||
|
|||
// check for the case where src/bin/foo/main.rs is present | |||
let path = Path::new("src").join("bin").join(bin.name()).join(&format!("main.rs")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last bit could be .join("main.rs")
.
src/cargo/util/toml.rs
Outdated
@@ -1472,6 +1515,12 @@ fn inferred_bin_path(bin: &TomlBinTarget, | |||
return path.to_path_buf() | |||
} | |||
|
|||
// we can also have src/bin/foo/main.rs, but the former one is preferred | |||
let path = Path::new("src").join("bin").join(bin.name()).join(&format!("main.rs")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
LGTM! @alexcrichton do you want to add something else here? |
@bors: r=matklad |
📌 Commit f08a9d3 has been approved by |
Infer multi-file binaries like `src/bin/server/main.rs` by convention This feature is described in issue #4086
☀️ Test successful - status-appveyor, status-travis |
This feature is described in issue #4086