rust-lang/cargo

Cargo looks for manifest in parent dirs even if one exists, even with --manifest-path

Closed this issue · 7 comments

detly commented

Problem

I have a project with nested, non-workspace cargo projects. It's a niche but real use case.

I found that if the parent project has a broken manifest, the child project cannot be built, even if its manifest is completely valid. Here's an example project, the child is in testbins/does-build.

does-build • cargo build
error: failed to parse manifest at `/home/jason/Code/test-binary/Cargo.toml`

Caused by:
  can't find `test_it_builds` bin at `src/bin/test_it_builds.rs` or `src/bin/test_it_builds/main.rs`. Please specify bin.path if you want to use a non-default path.

Note that the error is in the parent project. The child project is fine. It's the same if I use --manifest-path ./Cargo.toml.

Steps

  1. Clone linked project.
  2. Change directory to testbins/does-build.
  3. cargo build --manifest-path ./Cargo.toml.

Possible Solution(s)

It all works, and crucially, builds the child project but not the parent, if the parent manifest is fixed.

Notes

Seems related: #7871

The docs say:

Path to the Cargo.toml file. By default, Cargo searches for the Cargo.toml file in the current directory or any parent directory.

I would expect that by default it stops when it finds one, but that's not explicitly stated. However, the behaviour with --manifest-path seems very unexpected.

Version

cargo 1.62.0 (a748cf5a3 2022-06-08)`

The thing that trips me up about this documentation

Path to the Cargo.toml file. By default, Cargo searches for the Cargo.toml file in the current directory or any parent directory.

(which is on every instance of --manifest-path in the cargo reference to the best of my knowledge) is that it says that Cargo searches for "the Cargo.toml file" (i.e. one file) "in the current directory" (so preferring a local file over one further up the directory hierarchy) "or any parent directory" ("or," not "and," i.e. "only if one wasn't found there.")

This supposedly documents the default behavior ("By default, ..."), but isn't true, as it definitely also looks at/for Cargo.toml files further up the directory tree despite there being one in the current directory, but what's even more confusing is that it still does this even when being given an explicit --manifest-path option, which you'd think would override whatever is done "[by] default."

ehuss commented

Cargo needs to search for other Cargo.toml files to discover if it is part of a workspace. I don't think that is something that can be changed, but Cargo could provide more information in the error message. Also, the workspaces chapter could mention this behavior as well (the workspaces chapter needs a lot of expansion in general).

detly commented

Cargo needs to search for other Cargo.toml files to discover if it is part of a workspace. I don't think that is something that can be changed,

I guess I see the point here, you have two mutually exclusive(?) options for when Cargo recurses upwards and finds an invalid manifest:

  1. It interprets it as no manifest and keeps going; if it finds nothing else then the original child project is not in a workspace.
  2. It interprets it as a manifest, but an invalid one. The child project IS (possibly) in a workspace, but can't be built.

1 would be surprising if it was actually a workspace child. 2 is surprising when it's not. Since it is far, far more likely to be a workspace project than my niche thing (actually a workaround for #1982) then I see why you'd have it that way, even with the --manifest-path option (how else would Cargo know that the --manifest-path's project is part of a workspace?).

Nonetheless, there seems to be no way to explicitly inform Cargo that you actually know this is a top-level ie. not-a-workspace project. This is close to what is being asked for in #7871, but that seems to be asking for a CLI flag, which cannot be committed to version control in the manifest itself.

epage commented

Nonetheless, there seems to be no way to explicitly inform Cargo that you actually know this is a top-level ie. not-a-workspace project.

You could always workaround this by putting

[workspace]

In your Cargo.toml.

detly commented

@epage - you mean, literally the empty section [workspace]?

Yes, putting [workspace] in a manifest marks it as the root package. This makes it so it won't search for another workspace root as the package is the root.

detly commented

FYI I used this suggestion and it's worked perfectly for weeks. I'll close this because I don't actually think anything should be changed here, I just needed a way to achieve a niche goal, which I got.