Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions doc/book/src/reference/config.md

@weihanglo weihanglo Aug 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How should test and bench be handled? We went with cargo test having build.profile override the default test so users will get consistent behavior between cargo build and cargo test. Alternatively, we could have told users to set profile.test.inherits = "debug". Changing the inheritance is even less obvious though it is likely to run into fewer issues if projects change the test profile.

How do we communicate and document this? Do we need to decide before proceeding?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My assumption is that this will behave as people expect and the only documentation burden is on the fields. If there is something I'm overlooking, let me know!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented in other threads.

Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ rustc-wrapper = "…" # run this wrapper instead of `rustc`
rustc-workspace-wrapper = "…" # run this wrapper instead of `rustc` for workspace members
rustdoc = "rustdoc" # the doc generator tool
target = "triple" # build for the target triple (ignored by `cargo install`)
profile = "dev" # build using the specified profile (ignored by `cargo install`)
target-dir = "target" # path of where to place generated artifacts
build-dir = "target" # path of where to place intermediate build artifacts
rustflags = ["…", "…"] # custom flags to pass to all compiler invocations
Expand Down Expand Up @@ -119,6 +120,7 @@ user-agent = "…" # the user-agent header

[install]
root = "/some/path" # `cargo install` destination directory
profile = "release" # build using the specified profile

[net]
retry = 3 # network retries
Expand Down Expand Up @@ -544,6 +546,22 @@ Can be overridden with the `--target` CLI option.
target = ["x86_64-unknown-linux-gnu", "i686-unknown-linux-gnu"]
```

#### `build.profile`
* Type: string
* Default: `"dev"`
* Environment: `CARGO_BUILD_PROFILE`

The default [profile] to compile with.
Comment on lines +551 to +554

@weihanglo weihanglo Aug 21, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might need to be expanded. For example, explaing what scope it apply to, and the relationship with bench and test profiles. The tricky part is the default is not always dev for different scope. We should point that one.

(It's okay to be a bit vague, if we plan to change it in the future)

View changes since the review


Can be overridden with the `--release` or `--profile` CLI options.

```toml
[build]
profile = "debug"
```

> **MSRV:** Respected as of 1.100.

#### `build.target-dir`
* Type: string (path)
* Default: `"target"`
Expand Down Expand Up @@ -921,6 +939,26 @@ your home directory).

Can be overridden with the `--root` command-line option.

#### `install.profile`
* Type: string
* Default: `"release"`
* Environment: `CARGO_INSTALL_PROFILE`

The default [profile] to compile with.

@weihanglo weihanglo Aug 21, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not clear what it is associated with. I don't think install.profile is self-explained enough. Maybe something like

Suggested change
The default [profile] to compile with.
The default [profile] to compile with when using `cargo install`.

View changes since the review


Can be overridden with the `--debug` or `--profile` CLI options.

```toml
[install]
profile = "tool"

[profile.tool]
inherits = "release"
lto = true
```

> **MSRV:** Respected as of 1.100.

### `[net]`

The `[net]` table controls networking configuration.
Expand Down Expand Up @@ -1551,6 +1589,7 @@ Report progress to the terminal emulator for display in places like the task bar
[source replacement]: source-replacement.md
[revision]: https://git-scm.com/docs/gitrevisions
[registries]: registries.md
[profile]: profiles.md
[`cargo:token`]: registry-authentication.md#cargotoken
[crates.io]: https://crates.io/
[target triple]: ../appendix/glossary.md#target '"target" (glossary)'
Expand Down
4 changes: 4 additions & 0 deletions doc/book/src/reference/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ In summary, the supported environment variables are:
* `CARGO_BUILD_TARGET` --- The default target platform, see [`build.target`].
* `CARGO_BUILD_TARGET_DIR` --- The default output directory, see [`build.target-dir`].
* `CARGO_BUILD_BUILD_DIR` --- The default build directory, see [`build.build-dir`].
* `CARGO_BUILD_PROFILE` --- The default profile, see [`build.profile`].
* `CARGO_BUILD_RUSTFLAGS` --- Extra `rustc` flags, see [`build.rustflags`].
* `CARGO_BUILD_RUSTDOCFLAGS` --- Extra `rustdoc` flags, see [`build.rustdocflags`].
* `CARGO_BUILD_INCREMENTAL` --- Incremental compilation, see [`build.incremental`].
Expand All @@ -116,6 +117,7 @@ In summary, the supported environment variables are:
* `CARGO_HTTP_MULTIPLEXING` --- Whether HTTP/2 multiplexing is used, see [`http.multiplexing`].
* `CARGO_HTTP_USER_AGENT` --- The HTTP user-agent header, see [`http.user-agent`].
* `CARGO_INSTALL_ROOT` --- The default directory for [`cargo install`], see [`install.root`].
* `CARGO_INSTALL_PROFILE` --- The default profile, see [`install.profile`].
* `CARGO_NET_RETRY` --- Number of times to retry network errors, see [`net.retry`].
* `CARGO_NET_GIT_FETCH_WITH_CLI` --- Enables the use of the `git` executable to fetch, see [`net.git-fetch-with-cli`].
* `CARGO_NET_OFFLINE` --- Offline mode, see [`net.offline`].
Expand Down Expand Up @@ -172,6 +174,7 @@ In summary, the supported environment variables are:
[`build.target`]: config.md#buildtarget
[`build.target-dir`]: config.md#buildtarget-dir
[`build.build-dir`]: config.md#buildbuild-dir
[`build.profile`]: config.md#buildprofile
[`build.rustflags`]: config.md#buildrustflags
[`build.rustdocflags`]: config.md#buildrustdocflags
[`build.incremental`]: config.md#buildincremental
Expand All @@ -194,6 +197,7 @@ In summary, the supported environment variables are:
[`http.multiplexing`]: config.md#httpmultiplexing
[`http.user-agent`]: config.md#httpuser-agent
[`install.root`]: config.md#installroot
[`install.profile`]: config.md#installprofile
[`net.retry`]: config.md#netretry
[`net.git-fetch-with-cli`]: config.md#netgit-fetch-with-cli
[`net.offline`]: config.md#netoffline
Expand Down
8 changes: 7 additions & 1 deletion src/bin/cargo/commands/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,17 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
if args.flag("workspace") {
spec.extend(ws.members().map(|package| package.name().to_string()))
};
let default_profile = gctx
.build_config()?
.profile
.as_ref()
.map(|p| p.as_ref())
.unwrap_or_else(|| "dev");
let opts = CleanOptions {
gctx,
spec,
targets: args.targets()?,
requested_profile: args.get_profile_name("dev", ProfileChecking::Custom)?,
requested_profile: args.get_profile_name(default_profile, ProfileChecking::Custom)?,
profile_specified: args.contains_id("profile") || args.flag("release"),
doc: args.flag("doc"),
dry_run: args.dry_run(),
Expand Down
8 changes: 7 additions & 1 deletion src/bin/cargo/commands/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use cargo::util::IntoUrl;
use cargo::util::VersionExt;
use cargo::workspace::{GitReference, SourceId, Workspace};
use cargo_util_schemas::manifest::PackageName;
use cargo_util_schemas::manifest::ProfileName;
use itertools::Itertools;
use semver::VersionReq;

Expand Down Expand Up @@ -224,8 +225,13 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
ProfileChecking::Custom,
)?;

let default_profile = gctx.get::<Option<ProfileName>>("install.profile")?;
let default_profile = default_profile
.as_ref()
.map(|p| p.as_ref())
.unwrap_or_else(|| "release");
compile_opts.build_config.requested_profile =
args.get_profile_name("release", ProfileChecking::Custom)?;
args.get_profile_name(default_profile, ProfileChecking::Custom)?;
if args.dry_run() {
gctx.cli_unstable().fail_if_stable_opt("--dry-run", 11123)?;
}
Expand Down
8 changes: 7 additions & 1 deletion src/bin/cargo/commands/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,14 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
let mut compile_opts =
args.compile_options(gctx, UserIntent::Test, Some(&ws), ProfileChecking::Custom)?;

let default_profile = gctx
.build_config()?
.profile
.as_ref()
.map(|p| p.as_ref())
.unwrap_or_else(|| "test");
compile_opts.build_config.requested_profile =
args.get_profile_name("test", ProfileChecking::Custom)?;
args.get_profile_name(default_profile, ProfileChecking::Custom)?;

// `TESTNAME` is actually an argument of the test binary, but it's
// important, so we explicitly mention it and reconfigure.
Expand Down
2 changes: 2 additions & 0 deletions src/context/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::borrow::Cow;
use std::ffi::OsStr;

use cargo_credential::Secret;
use cargo_util_schemas::manifest::ProfileName;
use serde::Deserialize;
use serde_untagged::UntaggedEnumVisitor;

Expand Down Expand Up @@ -205,6 +206,7 @@ pub struct CargoBuildConfig {
pub build_dir: Option<ConfigRelativePath>,
pub incremental: Option<bool>,
pub target: Option<BuildTargetConfig>,
pub profile: Option<ProfileName>,
pub jobs: Option<JobsConfig>,
pub rustflags: Option<StringList>,
pub rustdocflags: Option<StringList>,
Expand Down
9 changes: 8 additions & 1 deletion src/util/command_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,14 @@ Run `{cmd}` to see possible targets."
intent,
)?;
build_config.message_format = message_format.unwrap_or(MessageFormat::Human);
build_config.requested_profile = self.get_profile_name("dev", profile_checking)?;
let default_profile = gctx
.build_config()?
.profile
.as_ref()
.map(|p| p.as_ref())
.unwrap_or_else(|| "dev");
build_config.requested_profile =
self.get_profile_name(default_profile, profile_checking)?;
build_config.unit_graph = self.flag("unit-graph");
build_config.future_incompat_report = self.flag("future-incompat-report");
build_config.compile_time_deps_only = self.flag("compile-time-deps");
Expand Down
156 changes: 156 additions & 0 deletions tests/testsuite/profile_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,3 +483,159 @@ fn named_env_profile() {
"#]])
.run();
}

#[cargo_test]
fn check_uses_build_profile() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check")
.env("CARGO_BUILD_PROFILE", "release")
.with_stderr_data(str![[r#"
[CHECKING] foo v0.1.0 ([ROOT]/foo)
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s

"#]])
.run();
}

#[cargo_test]
fn check_ignores_install_profile() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check")
.env("CARGO_INSTALL_PROFILE", "release")
.with_stderr_data(str![[r#"
[CHECKING] foo v0.1.0 ([ROOT]/foo)
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s

"#]])
.run();
}

#[cargo_test]
fn test_uses_build_profile() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("test --no-run")
.env("CARGO_BUILD_PROFILE", "release")
.with_stderr_data(str![[r#"
[COMPILING] foo v0.1.0 ([ROOT]/foo)
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
[EXECUTABLE] unittests src/main.rs (target/release/build/foo/[HASH]/out/foo-[HASH])

"#]])
.run();
}

#[cargo_test]
fn test_ignores_install_profile() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("test --no-run")
.env("CARGO_INSTALL_PROFILE", "release")
.with_stderr_data(str![[r#"
[COMPILING] foo v0.1.0 ([ROOT]/foo)
[FINISHED] `test` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[EXECUTABLE] unittests src/main.rs (target/debug/build/foo/[HASH]/out/foo-[HASH])

"#]])
.run();
}

#[cargo_test]
fn install_uses_install_profile() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("install")
.env("CARGO_INSTALL_PROFILE", "debug")
.with_stderr_data(str![[r#"
[WARNING] using `cargo install` to install the binaries from the package in current working directory is deprecated, use `cargo install --path .` instead. [NOTE] use `cargo build` if you want to simply build the package.
[INSTALLING] foo v0.1.0 ([ROOT]/foo)
[COMPILING] foo v0.1.0 ([ROOT]/foo)
[FINISHED] `debug` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
[INSTALLED] package `foo v0.1.0 ([ROOT]/foo)` (executable `foo[EXE]`)
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries

"#]])
.run();
}

#[cargo_test]
fn install_ignores_build_profile() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("install")
.env("CARGO_BUILD_PROFILE", "dev")
.with_stderr_data(str![[r#"
[WARNING] using `cargo install` to install the binaries from the package in current working directory is deprecated, use `cargo install --path .` instead. [NOTE] use `cargo build` if you want to simply build the package.
[INSTALLING] foo v0.1.0 ([ROOT]/foo)
[COMPILING] foo v0.1.0 ([ROOT]/foo)
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
[INSTALLED] package `foo v0.1.0 ([ROOT]/foo)` (executable `foo[EXE]`)
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries

"#]])
.run();
}
Loading