Skip to content

Add -C <DIR> flag to cargo to change directory before invoking #10098

Open

Description

@lilyball

View all comments

Problem

Cargo infers the manifest path and reads config based on the current directory. Plugins may potentially locate other config this same way. Cargo commands offer a --manifest-path flag to override the manifest, but this doesn't override config.

For example, given the following:

> cat bin/foo/.cargo/config.toml
[build]
target = "wasm32-unknown-unknown"
target-dir = "../../target"
> cargo build --manifest-path bin/foo/Cargo.toml

The resulting build will use the host platform instead of wasm32-unknown-unknown and the build artifacts will end up in bin/foo/target. But were I to run cd bin/foo && cargo build it would use the correct target and target dir.

Proposed Solution

Cargo should have a flag -C <DIR> (or --directory <DIR>) that exists at the top level rather than in the subcommands. This flag would cause cargo to change its working directory to the specified one before processing any commands or loading any config. It would be roughly equivalent to ( cd <DIR> && cargo … ).

Besides fixing the issue of loading cargo config, this is also a simpler interface for end users than --manifest-path as it means they don't have to worry about where the specific Cargo.toml file is, they can just run cargo as though it were in a specific directory.

This flag is inspired by both make and git which offer the same -C <DIR> (make has the long --directory form, I don't believe git has a long form). The desired behavior here should be based on git as it also defines how multiple -C flags interact (subsequent ones are interpreted relative to the earlier ones). Like git, any other flags or parameters that take relative paths should then be interpreted relative to the working directory caused by the -C option.

Notes

Regarding rustup and rust-toolchain.toml overrides, I'm inclined to say rustup should honor this flag as well and interpret it prior to locating an override file. The idea here is that saying cargo -C $path … should behave indistinguishably from running cargo within that path.

Activity

  1. added
    C-feature-requestCategory: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted`
    on Nov 19, 2021
  2. lilyball commented on Nov 19, 2021

    @lilyball
    ContributorAuthor

    This request was inspired by my surprised at cargo build --manifest-path bin/foo/Cargo.toml not applying the config from bin/foo/.cargo/config.toml. I considered filing that as a bug, but I'm not sure what the actual correct behavior there should be, whereas a -C flag has an obvious answer (and is easier to use).

  3. thomcc commented on Nov 30, 2021

    @thomcc
    Member

    Yeah, I hit this issue too. I think ideally --manifest-path made cargo do the right thing here, although I guess that would be a breaking change, and I can see some use cases for it using the current directory.

  4. added
    A-cliArea: Command-line interface, option parsing, etc.
    A-configurationArea: cargo config files and env vars
    on Dec 6, 2021
  5. Eh2406 commented on Dec 10, 2021

    @Eh2406
    Contributor

    I believe that @joshtriplett have brought this up at cargo meetings before, but I cannot find notes at this time.

  6. olson-dan commented on Mar 15, 2022

    @olson-dan

    Ran into this today as well, let me just echo that it's pretty unfortunate that using --manifest-path produces a different and potentially incorrect build depending on where it's invoked from. I'd prefer if config location started in the directory of the manifest than a new config option.

    Potentially this might not be breaking, because anyone depending on the current behavior would have to be building from the root of the project anyway.

  7. lilyball commented on Mar 17, 2022

    @lilyball
    ContributorAuthor

    At this point, I think that the current behavior of --manifest-path is actually correct. The .cargo/config.toml file controls the behavior of cargo itself, it's not crate configuration, and so the location I invoke cargo from should be what determines how to find the cargo config. Having a separate -C <DIR> flag solves this. Especially the part about toolchain overrides (e.g. rust-toolchain.yaml) as that is explicitly based on your current path.

  8. compenguy commented on Jul 26, 2022

    @compenguy
    Contributor

    At this point, I think that the current behavior of --manifest-path is actually correct. The .cargo/config.toml file controls the behavior of cargo itself, it's not crate configuration, and so the location I invoke cargo from should be what determines how to find the cargo config.

    This is contrary to the cargo config documentation, which says:

    With this structure, you can specify configuration per-package, and even possibly check it into version control. You can also specify personal defaults with a configuration file in your home directory.

    the per-package .cargo/config.toml checked into version control is being ignored when built via --manifest-path, unless the cwd is currently somewhere within the package directory tree, but the primary use case for --manifest-path is to make build independent of cwd. This is either a cargo bug, or a cargo documentation bug, take your pick, but my vote is for cargo bug.

  9. epage commented on Jul 26, 2022

    @epage
    Contributor

    btw #2930 is the issue about the config being relative to CWD rather than --manifest-path. This issue is more about acknowledging things as they currently are and providing a mechanism for dealing with it

    the per-package .cargo/config.toml checked into version control is being ignored when built via --manifest-path, unless the cwd is currently somewhere within the package directory tree, but the primary use case for --manifest-path is to make build independent of cwd. This is either a cargo bug, or a cargo documentation bug, take your pick, but my vote is for cargo bug.

    I could see there being some minor wording tweaks to the documentation. My guess is its written assuming auto-discovery of the manifest in which case, it is correct. That assumption should be made more clear though.

  10. weihanglo commented on Jan 27, 2023

    @weihanglo
    Member
  11. 23 remaining items

  12. weihanglo commented on Aug 5, 2026

    @weihanglo
    Member

    @ChrisDenton For option 4, those surprises could lead to more issues being filed against rust-lang/rustup repo, even though -C is a Cargo flag. We also want to make sure t-rustup is fully aware of and aligned with this option, since it affects rustup's user experience, not just Cargo.

  13. ChrisDenton commented on Aug 5, 2026

    @ChrisDenton
    Member

    For sure, it's a least worst option rather than a perfect solution. I think documenting this case will help. Maybe cargo could also warn if a rust-toolchain.toml is present but I fear that might be too noisy.

    But this is all hypothetical at this point, right? We don't really have a good way to gauge how this will play out if few people are using it atm?

  14. epage commented on Aug 5, 2026

    @epage
    Contributor

    Maybe cargo could also warn if a rust-toolchain.toml is present but I fear that might be too noisy.

    Cargo generally limits its warnings to when a user has a reasonable way to turn it off. We are adding a linting system but this would be outside of that.

    This would also have false positives because the file could lead to the same result.

    We also wouldn't know about config overrides.

  15. removed
    I-nominated-to-discussTo be discussed during issue triage on the next Cargo team meeting
    on Aug 5, 2026
  16. rami3l commented on Aug 10, 2026

    @rami3l
    Member

    @weihanglo I still feel strange about this: it feels like either rustup or cargo needs to intercept this flag, but not both, since the behavior of both would rely on the current working directory (specifically, in rustup, this would influence directory overrides via both rust-toolchain.toml and rustup override set).

    Once cd has been performed it should influence both, so I think it probably should be a rustup feature rather than a cargo one, meaning rustup would take -C alongside +toolchain (taking the option 1 in #10098 (comment)) and cd before doing anything else.

    However, considering the fact that people might be using cargo without rustup, there might still be a use case for cargo -C.

    Thus, we may end up with both tools supporting this option, with cargo -C being rarely used by the user. In the end I doubt whether that would be the best way forward.

  17. djc commented on Aug 10, 2026

    @djc
    Contributor

    I'm not a fan of the plan of supporting -C and just breaking people who rely on rust-toolchain.toml.

    I have wanted this feature many times, but I'd rather come up with a better plan to support it well instead of having an implementation that breaks a bunch of expectations.

  18. ChrisDenton commented on Aug 10, 2026

    @ChrisDenton
    Member

    I think if we want to switch rust-toolchain.toml via the command line then we need to properly support this in rustup itself.

  19. djc commented on Aug 10, 2026

    @djc
    Contributor

    Yup. Maybe we could communicate whether/how we changed the current working dir to Cargo via an environment variable?

  20. rami3l commented on Aug 10, 2026

    @rami3l
    Member

    Yup. Maybe we could communicate whether/how we changed the current working dir to Cargo via an environment variable?

    @djc That'd make perfect sense to me, but I think the main question would be how to capture the user’s intent in rustup.

  21. ChrisDenton commented on Aug 10, 2026

    @ChrisDenton
    Member

    In any case we probably should take a moment to explorer the design space on the rustup side and then come back to Cargo.

  22. djc commented on Aug 11, 2026

    @djc
    Contributor

    In any case we probably should take a moment to explorer the design space on the rustup side and then come back to Cargo.

    I don't see many downsides to doing so in this issue, where everyone can keep track of what's going on?

    Here's my straw man proposal:

    If rustup in proxy mode sees an invocation of cargo with a -C option passed in, we change the working dir for the child process and set RUSTUP_SET_CWD containing the path that we set in the child's environment.

  23. rami3l commented on Aug 11, 2026

    @rami3l
    Member

    If rustup in proxy mode sees an invocation of cargo with a -C option passed in, we change the working dir for the child process and set RUSTUP_SET_CWD containing the path that we set in the child's environment.

    @djc I'm not sure about this, considering the fact that rustup fully delegates the resolution of RUSTUP_SET_CWD to cargo will cause the inverse case scenario compared the one proposed above (where cargo supports -C but rustup is not informed): now rustup will recognize the new CWD but cargo may or may not act accordingly, depending on how recent it is.

  24. djc commented on Aug 11, 2026

    @djc
    Contributor

    @djc I'm not sure about this, considering the fact that rustup fully delegates the resolution of RUSTUP_SET_CWD to cargo will cause the inverse case scenario compared the one proposed above (where cargo supports -C but rustup is not informed): now rustup will recognize the new CWD but cargo may or may not act accordingly, depending on how recent it is.

    If we still pass -C on to Cargo as well (which I didn't articulate in my previous message), it would make older Cargo fail, while newer Cargo can act accordingly. Seems okay?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-cliArea: Command-line interface, option parsing, etc.A-configurationArea: cargo config files and env varsC-feature-requestCategory: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted`S-needs-designStatus: Needs someone to work further on the design for the feature or fix. NOT YET accepted.

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions