Skip to content
Merged
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
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ multiple_crate_versions = "allow"
future_not_send = "allow"

[workspace.dependencies]
artifact_profile = { path = "crates/artifact_profile" }
anstream = "1.0.0"
anyhow = "1.0.103"
assert2 = "0.4.0"
Expand Down Expand Up @@ -201,3 +202,32 @@ codegen-units = 1
strip = "symbols" # set to `false` for debug information
debug = false # set to `true` for debug information
panic = "abort" # Let it crash and force ourselves to write safe Rust.

# Cargo compiles artifact dependencies declared under `[build-dependencies]`
# with the build-override profile — opt-level 0, no codegen-units setting —
# even in release builds, and even with `target = "target"`. Their output
# still lands under `target/<triple>/release/`, so the missing optimization
# is easy to miss. (Artifact deps under `[dependencies]`/`[dev-dependencies]`
# get the normal profile and need nothing here.) See
# https://github.com/rust-lang/cargo/issues/16719.
#
# These are the workspace's build-dependency artifacts: the preload libraries
# are injected into every traced process and run inside every intercepted
# libc call, and the napi library backs the Node.js client.
#
# `strip` must be restated: a package override resets an inherited `strip`
# to "debuginfo" when the field is omitted (Cargo quirk in profile merging).
[profile.release.package.fspy_preload_unix]
opt-level = 3
codegen-units = 1
strip = "symbols"

[profile.release.package.fspy_preload_windows]
opt-level = 3
codegen-units = 1
strip = "symbols"

[profile.release.package.vt_client_napi]
opt-level = 3
codegen-units = 1
strip = "symbols"
13 changes: 13 additions & 0 deletions crates/artifact_profile/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "artifact_profile"
version = "0.0.0"
edition = "2024"
license.workspace = true
publish = false

[lib]
test = false
doctest = false

[lints]
workspace = true
63 changes: 63 additions & 0 deletions crates/artifact_profile/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//! Build-script guard for crates that are consumed as artifact dependencies.
//!
//! This is the producer side of the artifact contract, and it has to live
//! here rather than in `materialized_artifact_build`: that crate runs from the
//! *consuming* crate's build script, which only ever sees its own profile.
//! A consumer's build script reports `OPT_LEVEL=3` while the artifact it just
//! embedded was built at 0, and the artifact's path records nothing about how
//! it was compiled. Only the artifact crate's own build script can tell.

use std::env;

/// Fails the build when the calling crate is compiled without optimizations
/// in a release build.
///
/// Cargo compiles artifact dependencies declared under `[build-dependencies]`
/// with the build-override profile — opt-level 0 — even in release builds, and
/// it only reads profiles from the root manifest of the workspace being built.
/// A workspace that depends on this repo therefore has to opt in explicitly,
/// and nothing tells it otherwise: the output still lands under
/// `target/<triple>/release/`, and the only symptom is a slower binary. See
/// <https://github.com/rust-lang/cargo/issues/16719>.
///
/// Call this from the artifact crate's own build script, where `OPT_LEVEL`
/// reports that crate's own profile rather than its parent's.
///
/// Only the optimization level is checked. Cargo passes `OPT_LEVEL`, `DEBUG`
/// and `PROFILE` to build scripts but not `codegen-units` or `strip`, so the
/// rest of the recommended profile block cannot be verified here — which is
/// why the failure prints the whole block rather than just the one setting.
/// `strip` in particular must be restated by anyone adding an override at all:
/// a package override that omits it silently resets an inherited
/// `strip = "symbols"` to `"debuginfo"`.
///
/// # Panics
///
/// Panics — failing the build — when `PROFILE` is `release` and `OPT_LEVEL` is
/// `0`.
pub fn require_optimized_in_release() {
// `PROFILE` is `release` for release-like profiles and `debug` otherwise,
// so debug builds — where opt-level 0 is correct — never trip this.
if env::var("PROFILE").as_deref() != Ok("release")
|| env::var("OPT_LEVEL").as_deref() != Ok("0")
{
return;
}
let package = env::var("CARGO_PKG_NAME").unwrap_or_else(|_| "this crate".into());
panic!(
"\n\n\
`{package}` was built without optimizations in a release build.\n\n\
It is an artifact dependency, which Cargo compiles with the\n\
build-override profile (opt-level 0) even in release builds. Profiles\n\
only take effect from the root manifest of the workspace being built,\n\
so add this to the root Cargo.toml of *your* workspace:\n\n \
[profile.release.package.{package}]\n \
opt-level = 3\n \
codegen-units = 1\n \
strip = \"symbols\"\n\n\
Keep all three: an override that omits `strip` resets it to\n\
\"debuginfo\", and `codegen-units` is dropped by the build-override\n\
profile. Without this block the crate ships unoptimized and nothing\n\
else reports it.\n"
);
}
3 changes: 3 additions & 0 deletions crates/fspy_preload_unix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@ fspy_shared_unix = { workspace = true }
libc = { workspace = true }
nix = { workspace = true, features = ["signal", "fs", "socket", "mman", "time"] }

[build-dependencies]
artifact_profile = { workspace = true }

[lints]
workspace = true
6 changes: 6 additions & 0 deletions crates/fspy_preload_unix/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
fn main() {
// This library is injected into every traced process and runs inside every
// intercepted libc call, so an unoptimized build is a silent, large
// regression for whoever consumes it.
artifact_profile::require_optimized_in_release();
}
3 changes: 3 additions & 0 deletions crates/fspy_preload_windows/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@ winsafe = { workspace = true }
[target.'cfg(target_os = "windows")'.dev-dependencies]
tempfile = { workspace = true }

[build-dependencies]
artifact_profile = { workspace = true }

[lints]
workspace = true
3 changes: 3 additions & 0 deletions crates/fspy_preload_windows/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
fn main() {
// Injected into every traced process; see the unix preload's build.rs.
artifact_profile::require_optimized_in_release();

if std::env::var_os("CARGO_CFG_TARGET_OS").unwrap() == "windows" {
println!("cargo:rustc-cdylib-link-arg=/EXPORT:DetourFinishHelperProcess,@1,NONAME");
}
Expand Down
1 change: 1 addition & 0 deletions crates/vt_client_napi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ vt_str = { workspace = true }
vt_client = { workspace = true }

[build-dependencies]
artifact_profile = { workspace = true }
napi-build = { workspace = true }

[lints]
Expand Down
3 changes: 3 additions & 0 deletions crates/vt_client_napi/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ extern crate napi_build;
use std::{env, fs, path::PathBuf};

fn main() {
// Shipped inside the built product; see `artifact_profile`.
artifact_profile::require_optimized_in_release();

napi_build::setup();

// Keep this crate's napi-derive type-defs out of any consumer's generated
Expand Down
Loading