Refactor build flags handling and add tool alias management
- Introduced a new method `apply_default_string` to streamline the application of default values for string fields in build flags. - Enhanced `apply_flags_table` to utilize the new method for setting various build flags, improving code readability and maintainability. - Added support for additional build flags: `fuse_ld`, `ranlib`, `strip`, `nm`, `objcopy`, `objdump`, and `readelf`. - Implemented a new command `set` to manage tool aliases for compilers, linkers, and shells, allowing users to set preferred tools in the build environment. - Improved error handling and validation for tool alias configuration, ensuring that existing non-symlink files are not replaced. - Added tests to verify the correct behavior of tool alias management and build flag application.
This commit is contained in:
Generated
+41
-14
@@ -363,6 +363,15 @@ dependencies = [
|
|||||||
"roff",
|
"roff",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cmake"
|
||||||
|
version = "0.1.58"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cmov"
|
name = "cmov"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@@ -417,9 +426,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -934,7 +943,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"libgit2-sys",
|
"libgit2-sys",
|
||||||
"log",
|
"log",
|
||||||
"openssl-probe",
|
"openssl-probe 0.1.6",
|
||||||
"openssl-sys",
|
"openssl-sys",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
@@ -1385,9 +1394,9 @@ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libgit2-sys"
|
name = "libgit2-sys"
|
||||||
version = "0.18.3+1.9.2"
|
version = "0.18.4+1.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487"
|
checksum = "9b26f66f35e1871b22efcf7191564123d2a446ca0538cde63c23adfefa9b15b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1403,6 +1412,7 @@ version = "0.37.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1"
|
checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cc",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
@@ -1428,6 +1438,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "4735e9cbde5aac84a5ce588f6b23a90b9b0b528f6c5a8db8a4aff300463a0839"
|
checksum = "4735e9cbde5aac84a5ce588f6b23a90b9b0b528f6c5a8db8a4aff300463a0839"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
|
"cmake",
|
||||||
"libc",
|
"libc",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
@@ -1581,14 +1592,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "native-tls"
|
name = "native-tls"
|
||||||
version = "0.2.14"
|
version = "0.2.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
|
checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"openssl",
|
"openssl",
|
||||||
"openssl-probe",
|
"openssl-probe 0.2.1",
|
||||||
"openssl-sys",
|
"openssl-sys",
|
||||||
"schannel",
|
"schannel",
|
||||||
"security-framework",
|
"security-framework",
|
||||||
@@ -1693,6 +1704,21 @@ version = "0.1.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-probe"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-src"
|
||||||
|
version = "300.6.0+3.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8e8cbfd3a4a8c8f089147fd7aaa33cf8c7450c4d09f8f80698a0cf093abeff4"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.111"
|
version = "0.9.111"
|
||||||
@@ -1701,6 +1727,7 @@ checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
"openssl-src",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
@@ -1964,9 +1991,9 @@ checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.13.3"
|
version = "0.13.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0"
|
checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -2132,9 +2159,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.11.1"
|
version = "3.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
@@ -2440,9 +2467,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tar"
|
name = "tar"
|
||||||
version = "0.4.45"
|
version = "0.4.46"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973"
|
checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"filetime",
|
"filetime",
|
||||||
"libc",
|
"libc",
|
||||||
|
|||||||
+14
-2
@@ -6,6 +6,18 @@ edition = "2024"
|
|||||||
[lints.rust]
|
[lints.rust]
|
||||||
warnings = "deny"
|
warnings = "deny"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
# Prefer vendored/static native libraries while keeping libc dynamically linked.
|
||||||
|
static-except-libc = [
|
||||||
|
"git2/vendored-libgit2",
|
||||||
|
"git2/vendored-openssl",
|
||||||
|
"git2/zlib-ng-compat",
|
||||||
|
"reqwest/native-tls-vendored",
|
||||||
|
"rusqlite/bundled",
|
||||||
|
"xz2/static",
|
||||||
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.102"
|
anyhow = "1.0.102"
|
||||||
ar = "0.9.0"
|
ar = "0.9.0"
|
||||||
@@ -20,7 +32,7 @@ semver = "1.0.28"
|
|||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
yaml-rust2 = "0.11.0"
|
yaml-rust2 = "0.11.0"
|
||||||
sha2 = "0.11.0"
|
sha2 = "0.11.0"
|
||||||
tar = "0.4.45"
|
tar = "0.4.46"
|
||||||
tempfile = "=3.27.0"
|
tempfile = "=3.27.0"
|
||||||
thiserror = "2.0.18"
|
thiserror = "2.0.18"
|
||||||
toml = "1.1.2"
|
toml = "1.1.2"
|
||||||
@@ -35,7 +47,7 @@ suppaftp = "8.0.2"
|
|||||||
minisign = "0.9.1"
|
minisign = "0.9.1"
|
||||||
petgraph = "0.8.3"
|
petgraph = "0.8.3"
|
||||||
fd-lock = "4.0.4"
|
fd-lock = "4.0.4"
|
||||||
reqwest = { version = "0.13.2", default-features = false, features = ["blocking", "native-tls"] }
|
reqwest = { version = "0.13.4", default-features = false, features = ["blocking", "native-tls"] }
|
||||||
filetime = "0.2.29"
|
filetime = "0.2.29"
|
||||||
clap_complete = "4.6.5"
|
clap_complete = "4.6.5"
|
||||||
clap_mangen = "0.3.0"
|
clap_mangen = "0.3.0"
|
||||||
|
|||||||
@@ -11,10 +11,41 @@ const BUILD_OPTION_KEYS: &[&str] = &[
|
|||||||
];
|
];
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
println!("cargo:rerun-if-env-changed=CC");
|
||||||
for key in BUILD_OPTION_KEYS {
|
for key in BUILD_OPTION_KEYS {
|
||||||
println!("cargo:rerun-if-env-changed={key}");
|
println!("cargo:rerun-if-env-changed={key}");
|
||||||
if let Ok(value) = std::env::var(key) {
|
if let Ok(value) = std::env::var(key) {
|
||||||
println!("cargo:rustc-env={key}={value}");
|
println!("cargo:rustc-env={key}={value}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if std::env::var_os("CARGO_FEATURE_STATIC_EXCEPT_LIBC").is_some()
|
||||||
|
&& std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("linux")
|
||||||
|
{
|
||||||
|
let libgcc_eh = gcc_runtime_archive("libgcc_eh.a").unwrap_or_else(|| {
|
||||||
|
panic!("static-except-libc requires libgcc_eh.a for static libgcc linkage")
|
||||||
|
});
|
||||||
|
println!("cargo:rustc-link-arg-bin=depot=-Wl,--whole-archive");
|
||||||
|
println!("cargo:rustc-link-arg-bin=depot={libgcc_eh}");
|
||||||
|
println!("cargo:rustc-link-arg-bin=depot=-Wl,--no-whole-archive");
|
||||||
|
println!("cargo:rustc-link-arg-bin=depot=-static-libgcc");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gcc_runtime_archive(name: &str) -> Option<String> {
|
||||||
|
let compiler = std::env::var_os("CC").unwrap_or_else(|| "cc".into());
|
||||||
|
let output = std::process::Command::new(compiler)
|
||||||
|
.arg(format!("-print-file-name={name}"))
|
||||||
|
.output()
|
||||||
|
.ok()?;
|
||||||
|
if !output.status.success() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let path = String::from_utf8(output.stdout).ok()?;
|
||||||
|
let path = path.trim();
|
||||||
|
if path.is_empty() || path == name || !std::path::Path::new(path).exists() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(path.to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,17 @@
|
|||||||
# apply everywhere without crowding the main /etc/depot.toml.
|
# apply everywhere without crowding the main /etc/depot.toml.
|
||||||
|
|
||||||
# Toolchain selection.
|
# Toolchain selection.
|
||||||
|
# tool_dir = "/usr/bin"
|
||||||
cc = "clang"
|
cc = "clang"
|
||||||
# cxx = "clang++"
|
# cxx = "$TOOL_DIR/clang++"
|
||||||
# ar = "ar"
|
# ar = "$TOOL_DIR/ar"
|
||||||
# ld = "ld.lld"
|
# ranlib = "$TOOL_DIR/ranlib"
|
||||||
|
# strip = "$TOOL_DIR/strip"
|
||||||
|
# ld = "$TOOL_DIR/ld.lld"
|
||||||
|
# nm = "$TOOL_DIR/nm"
|
||||||
|
# objcopy = "$TOOL_DIR/objcopy"
|
||||||
|
# objdump = "$TOOL_DIR/objdump"
|
||||||
|
# readelf = "$TOOL_DIR/readelf"
|
||||||
|
|
||||||
# Compiler defaults. These are merged with package-level flags unless a package
|
# Compiler defaults. These are merged with package-level flags unless a package
|
||||||
# explicitly replaces them.
|
# explicitly replaces them.
|
||||||
@@ -18,6 +25,8 @@ cflags += ["-pipe"]
|
|||||||
|
|
||||||
# Linker defaults.
|
# Linker defaults.
|
||||||
ldflags = ["-Wl,-O1"]
|
ldflags = ["-Wl,-O1"]
|
||||||
|
# Select a linker through compiler drivers such as clang/gcc.
|
||||||
|
# fuse_ld = "lld"
|
||||||
|
|
||||||
# Link-time optimization policy.
|
# Link-time optimization policy.
|
||||||
ltoflags = ["-flto=auto"]
|
ltoflags = ["-flto=auto"]
|
||||||
|
|||||||
+12
-5
@@ -16,15 +16,20 @@ prefix = "/usr"
|
|||||||
|
|
||||||
# Default toolchain commands. These are passed through to builders that honor
|
# Default toolchain commands. These are passed through to builders that honor
|
||||||
# CC/CXX/AR and related variables.
|
# CC/CXX/AR and related variables.
|
||||||
|
# tool_dir = "/usr/bin"
|
||||||
cc = "clang"
|
cc = "clang"
|
||||||
ar = "ar"
|
ar = "ar"
|
||||||
|
|
||||||
# Optional examples:
|
# Optional examples:
|
||||||
# cxx = "clang++"
|
# cxx = "$TOOL_DIR/clang++"
|
||||||
# ld = "ld.lld"
|
# ld = "$TOOL_DIR/ld.lld"
|
||||||
# cpp = "cpp"
|
# cpp = "$TOOL_DIR/cpp"
|
||||||
# strip = "strip"
|
# strip = "$TOOL_DIR/strip"
|
||||||
# ranlib = "ranlib"
|
# ranlib = "$TOOL_DIR/ranlib"
|
||||||
|
# nm = "$TOOL_DIR/nm"
|
||||||
|
# objcopy = "$TOOL_DIR/objcopy"
|
||||||
|
# objdump = "$TOOL_DIR/objdump"
|
||||||
|
# readelf = "$TOOL_DIR/readelf"
|
||||||
|
|
||||||
[build.flags]
|
[build.flags]
|
||||||
# Baseline C compiler flags for packages that do not supply their own.
|
# Baseline C compiler flags for packages that do not supply their own.
|
||||||
@@ -39,6 +44,8 @@ cflags += ["-g"]
|
|||||||
# Optional C++ and linker defaults:
|
# Optional C++ and linker defaults:
|
||||||
# cxxflags = ["-O2"]
|
# cxxflags = ["-O2"]
|
||||||
ldflags = ["-Wl,-O1"]
|
ldflags = ["-Wl,-O1"]
|
||||||
|
# Select a linker through compiler drivers such as clang/gcc.
|
||||||
|
# fuse_ld = "lld"
|
||||||
|
|
||||||
# Link-time optimization defaults. When use_lto is true, Depot will inject
|
# Link-time optimization defaults. When use_lto is true, Depot will inject
|
||||||
# ltoflags into the appropriate compiler and linker flag sets automatically.
|
# ltoflags into the appropriate compiler and linker flag sets automatically.
|
||||||
|
|||||||
@@ -10,8 +10,11 @@
|
|||||||
prefix = "/usr/local"
|
prefix = "/usr/local"
|
||||||
|
|
||||||
# Personal toolchain preference.
|
# Personal toolchain preference.
|
||||||
|
# tool_dir = "/usr/bin"
|
||||||
cc = "clang"
|
cc = "clang"
|
||||||
# cxx = "clang++"
|
# cxx = "$TOOL_DIR/clang++"
|
||||||
|
# ranlib = "$TOOL_DIR/ranlib"
|
||||||
|
# strip = "$TOOL_DIR/strip"
|
||||||
|
|
||||||
[build.flags]
|
[build.flags]
|
||||||
# User-local compiler preferences.
|
# User-local compiler preferences.
|
||||||
@@ -22,6 +25,7 @@ carch = "x86_64"
|
|||||||
# Examples:
|
# Examples:
|
||||||
# cxxflags = ["-O2", "-g"]
|
# cxxflags = ["-O2", "-g"]
|
||||||
# ldflags = ["-Wl,-O1"]
|
# ldflags = ["-Wl,-O1"]
|
||||||
|
# fuse_ld = "lld"
|
||||||
# makeflags = "-j4"
|
# makeflags = "-j4"
|
||||||
|
|
||||||
# Optional install directory overrides for supported builders.
|
# Optional install directory overrides for supported builders.
|
||||||
|
|||||||
+125
-14
@@ -335,6 +335,7 @@ fn bootstrap_package_is_complete(
|
|||||||
fn bootstrap_required_payload_paths(package: &str) -> &'static [&'static str] {
|
fn bootstrap_required_payload_paths(package: &str) -> &'static [&'static str] {
|
||||||
match package {
|
match package {
|
||||||
"bmake" => &["system/binaries/bmake", "system/share/mk/sys.mk"],
|
"bmake" => &["system/binaries/bmake", "system/share/mk/sys.mk"],
|
||||||
|
"byacc" => &["system/binaries/yacc"],
|
||||||
"llvm-clang-pass1" => &[
|
"llvm-clang-pass1" => &[
|
||||||
"system/tools/bin/llvm-config",
|
"system/tools/bin/llvm-config",
|
||||||
"system/tools/bin/llvm-tblgen",
|
"system/tools/bin/llvm-tblgen",
|
||||||
@@ -348,6 +349,7 @@ fn bootstrap_required_payload_paths(package: &str) -> &'static [&'static str] {
|
|||||||
fn bootstrap_recipe_revision(package: &str) -> Option<u32> {
|
fn bootstrap_recipe_revision(package: &str) -> Option<u32> {
|
||||||
match package {
|
match package {
|
||||||
"bmake" => Some(2),
|
"bmake" => Some(2),
|
||||||
|
"byacc" => Some(1),
|
||||||
"llvm" => Some(3),
|
"llvm" => Some(3),
|
||||||
"ubase" => Some(1),
|
"ubase" => Some(1),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -1584,7 +1586,7 @@ fn write_generated_recipe(
|
|||||||
}
|
}
|
||||||
spec.push_str("no_strip = true\n");
|
spec.push_str("no_strip = true\n");
|
||||||
spec.push_str(
|
spec.push_str(
|
||||||
"passthrough_env = [\"DEPOT_LBI_CHROOT\", \"DEPOT_LBI_CHROOT_ROOT\", \"DEPOT_LBI_DEPOT_EXE\", \"DEPOT_LBI_SYSROOT\", \"LWI_MAKE_FLAGS\", \"LWI_MAKE_JOBS\"]\n\n",
|
"passthrough_env = [\"DEPOT_LBI_CHROOT\", \"DEPOT_LBI_CHROOT_ROOT\", \"DEPOT_LBI_DEPOT_EXE\", \"DEPOT_LBI_SYSROOT\", \"LBI_CCACHE\", \"LWI_MAKE_FLAGS\", \"LWI_MAKE_JOBS\"]\n\n",
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(primary) = primary_source {
|
if let Some(primary) = primary_source {
|
||||||
@@ -1753,6 +1755,19 @@ fi
|
|||||||
script.push_str("export LWI_CFLAGS=\"${LWI_CFLAGS:-${CFLAGS:-}}\"\n");
|
script.push_str("export LWI_CFLAGS=\"${LWI_CFLAGS:-${CFLAGS:-}}\"\n");
|
||||||
script.push_str("export LWI_CXXFLAGS=\"${LWI_CXXFLAGS:-$LWI_CFLAGS}\"\n");
|
script.push_str("export LWI_CXXFLAGS=\"${LWI_CXXFLAGS:-$LWI_CFLAGS}\"\n");
|
||||||
script.push_str("export LBI_CUSTOM_LDFLAGS=\"${LBI_CUSTOM_LDFLAGS:-${LDFLAGS:-}}\"\n\n");
|
script.push_str("export LBI_CUSTOM_LDFLAGS=\"${LBI_CUSTOM_LDFLAGS:-${LDFLAGS:-}}\"\n\n");
|
||||||
|
if uses_llvm_cmake_ccache(package) {
|
||||||
|
script.push_str(
|
||||||
|
r#"if [ -z "${LBI_CCACHE:-}" ]; then
|
||||||
|
LBI_CCACHE="$(command -v ccache)" || {
|
||||||
|
echo "depot: LLVM bootstrap requires ccache in PATH for the CMake compiler launcher" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
export LBI_CCACHE
|
||||||
|
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
let uses_cross_toolchain = use_cross_toolchain_by_default(package);
|
let uses_cross_toolchain = use_cross_toolchain_by_default(package);
|
||||||
if uses_cross_toolchain {
|
if uses_cross_toolchain {
|
||||||
script.push_str(
|
script.push_str(
|
||||||
@@ -2112,6 +2127,8 @@ fn apply_bootstrap_package_overrides(package: &BookPackage, command: &str) -> St
|
|||||||
ensure_mandoc_postinstall_uses_staged_man(command)
|
ensure_mandoc_postinstall_uses_staged_man(command)
|
||||||
} else if package.name == "bmake" {
|
} else if package.name == "bmake" {
|
||||||
ensure_bmake_install_avoids_double_destdir(command)
|
ensure_bmake_install_avoids_double_destdir(command)
|
||||||
|
} else if package.name == "byacc" {
|
||||||
|
ensure_byacc_exposes_unprefixed_yacc(command)
|
||||||
} else if package.name == "ubase" {
|
} else if package.name == "ubase" {
|
||||||
ensure_ubase_moves_bin_payload(command)
|
ensure_ubase_moves_bin_payload(command)
|
||||||
} else if package.name == "sqlite" {
|
} else if package.name == "sqlite" {
|
||||||
@@ -2141,6 +2158,23 @@ fi"#
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ensure_byacc_exposes_unprefixed_yacc(command: &str) -> String {
|
||||||
|
if !command_runs_install_step(command) {
|
||||||
|
return command.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"{command}\n{}",
|
||||||
|
r#"if [ ! -e "$DESTDIR/system/binaries/yacc" ] && [ -e "$DESTDIR/system/binaries/$LBI_TARGET-yacc" ]; then
|
||||||
|
ln -sf "$LBI_TARGET-yacc" "$DESTDIR/system/binaries/yacc"
|
||||||
|
fi
|
||||||
|
if [ ! -e "$DESTDIR/system/documentation/man-pages/man1/yacc.1" ] \
|
||||||
|
&& [ -e "$DESTDIR/system/documentation/man-pages/man1/$LBI_TARGET-yacc.1" ]; then
|
||||||
|
ln -sf "$LBI_TARGET-yacc.1" "$DESTDIR/system/documentation/man-pages/man1/yacc.1"
|
||||||
|
fi"#
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn command_runs_install_step(command: &str) -> bool {
|
fn command_runs_install_step(command: &str) -> bool {
|
||||||
command.lines().any(|line| {
|
command.lines().any(|line| {
|
||||||
let trimmed = line.trim_start();
|
let trimmed = line.trim_start();
|
||||||
@@ -2479,25 +2513,46 @@ fn ensure_llvm_runtime_links_skip_missing_crt(command: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_llvm_cmake_uses_ccache(command: &str) -> String {
|
fn ensure_llvm_cmake_uses_ccache(command: &str) -> String {
|
||||||
if command.contains("-DLLVM_CCACHE_BUILD=ON") {
|
let command = command
|
||||||
return command.to_string();
|
.replace(" -DLLVM_CCACHE_BUILD=ON \\\n", "")
|
||||||
|
.replace(" -DLLVM_CCACHE_BUILD=ON \\", "")
|
||||||
|
.replace("-DLLVM_CCACHE_BUILD=ON", "");
|
||||||
|
|
||||||
|
if command.contains("-DCMAKE_C_COMPILER_LAUNCHER=")
|
||||||
|
&& command.contains("-DCMAKE_CXX_COMPILER_LAUNCHER=")
|
||||||
|
&& command.contains("-DCMAKE_ASM_COMPILER_LAUNCHER=")
|
||||||
|
{
|
||||||
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let launcher_flags = concat!(
|
||||||
|
" -DCMAKE_C_COMPILER_LAUNCHER=\"$LBI_CCACHE\" \\\n",
|
||||||
|
" -DCMAKE_CXX_COMPILER_LAUNCHER=\"$LBI_CCACHE\" \\\n",
|
||||||
|
" -DCMAKE_ASM_COMPILER_LAUNCHER=\"$LBI_CCACHE\" \\"
|
||||||
|
);
|
||||||
|
|
||||||
if command.contains("lbi_cmake build-llvm") {
|
if command.contains("lbi_cmake build-llvm") {
|
||||||
return command.replace(
|
return command.replace(
|
||||||
"lbi_cmake build-llvm \\",
|
"lbi_cmake build-llvm \\",
|
||||||
"lbi_cmake build-llvm \\\n -DLLVM_CCACHE_BUILD=ON \\",
|
&format!("lbi_cmake build-llvm \\\n{launcher_flags}"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if command.contains("cmake -G Ninja \"../llvm\"") {
|
if command.contains("cmake -G Ninja \"../llvm\"") {
|
||||||
return command.replace(
|
return command.replace(
|
||||||
"cmake -G Ninja \"../llvm\" \\",
|
"cmake -G Ninja \"../llvm\" \\",
|
||||||
"cmake -G Ninja \"../llvm\" \\\n -DLLVM_CCACHE_BUILD=ON \\",
|
&format!("cmake -G Ninja \"../llvm\" \\\n{launcher_flags}"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
command.to_string()
|
command
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uses_llvm_cmake_ccache(package: &BookPackage) -> bool {
|
||||||
|
matches!(
|
||||||
|
package.name.as_str(),
|
||||||
|
"llvm-clang-pass1" | "llvm-clang-pass2"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_llvm_pass2_uses_pass1_native_tools(command: &str) -> String {
|
fn ensure_llvm_pass2_uses_pass1_native_tools(command: &str) -> String {
|
||||||
@@ -4688,10 +4743,13 @@ EOF"#
|
|||||||
let build_script =
|
let build_script =
|
||||||
generated_build_script(&package, &recipe, "x86_64-unknown-linux-musl", "x86_64");
|
generated_build_script(&package, &recipe, "x86_64-unknown-linux-musl", "x86_64");
|
||||||
|
|
||||||
assert!(build_script.contains("-DLLVM_CCACHE_BUILD=ON"));
|
assert!(build_script.contains("export LBI_CCACHE"));
|
||||||
assert!(
|
assert!(build_script.contains(
|
||||||
build_script.contains("cmake -G Ninja \"../llvm\" \\\n -DLLVM_CCACHE_BUILD=ON \\")
|
"cmake -G Ninja \"../llvm\" \\\n -DCMAKE_C_COMPILER_LAUNCHER=\"$LBI_CCACHE\" \\"
|
||||||
);
|
));
|
||||||
|
assert!(build_script.contains("-DCMAKE_CXX_COMPILER_LAUNCHER=\"$LBI_CCACHE\""));
|
||||||
|
assert!(build_script.contains("-DCMAKE_ASM_COMPILER_LAUNCHER=\"$LBI_CCACHE\""));
|
||||||
|
assert!(!build_script.contains("-DLLVM_CCACHE_BUILD=ON"));
|
||||||
assert!(build_script.contains("-DLLVM_NATIVE_TOOL_DIR=\"$LBI_SYSROOT/system/tools/bin\""));
|
assert!(build_script.contains("-DLLVM_NATIVE_TOOL_DIR=\"$LBI_SYSROOT/system/tools/bin\""));
|
||||||
assert!(
|
assert!(
|
||||||
build_script
|
build_script
|
||||||
@@ -6231,6 +6289,43 @@ sed -i \
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn byacc_generated_script_exposes_unprefixed_yacc() {
|
||||||
|
let mut package = test_recipe(8).package;
|
||||||
|
package.name = "byacc".to_string();
|
||||||
|
package.title = "byacc stage 2 20260126".to_string();
|
||||||
|
package.version = "20260126".to_string();
|
||||||
|
package.recipe_id = "8-12-byacc".to_string();
|
||||||
|
let recipe = PageRecipe {
|
||||||
|
input_files: vec!["byacc-20260126.tgz".to_string()],
|
||||||
|
source_urls: vec!["https://example.invalid/byacc-20260126.tgz".to_string()],
|
||||||
|
extract_dir: Some("byacc-20260126".to_string()),
|
||||||
|
commands: vec![
|
||||||
|
"lbi_configure --with-manpage-format=normal".to_string(),
|
||||||
|
"make $LWI_MAKE_FLAGS".to_string(),
|
||||||
|
"make ${LWI_MAKE_FLAGS:-} install".to_string(),
|
||||||
|
],
|
||||||
|
dependencies: Vec::new(),
|
||||||
|
license: "BSD-3-Clause".to_string(),
|
||||||
|
description: "byacc".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let build_script =
|
||||||
|
generated_build_script(&package, &recipe, "x86_64-lbi-linux-musl", "x86_64");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
build_script.contains(r#"ln -sf "$LBI_TARGET-yacc" "$DESTDIR/system/binaries/yacc""#)
|
||||||
|
);
|
||||||
|
assert!(build_script.contains(
|
||||||
|
r#"ln -sf "$LBI_TARGET-yacc.1" "$DESTDIR/system/documentation/man-pages/man1/yacc.1""#
|
||||||
|
));
|
||||||
|
assert_eq!(
|
||||||
|
bootstrap_required_payload_paths("byacc"),
|
||||||
|
&["system/binaries/yacc"]
|
||||||
|
);
|
||||||
|
assert_eq!(bootstrap_recipe_revision("byacc"), Some(1));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn generated_python_bootstrap_specs_use_custom_chroot_script() {
|
fn generated_python_bootstrap_specs_use_custom_chroot_script() {
|
||||||
let tmp = tempfile::tempdir().unwrap();
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
@@ -6329,10 +6424,13 @@ sed -i \
|
|||||||
assert!(build_script.contains("export LBI_SYSROOT=\"${DEPOT_LBI_SYSROOT:-$LBI_ROOT}\""));
|
assert!(build_script.contains("export LBI_SYSROOT=\"${DEPOT_LBI_SYSROOT:-$LBI_ROOT}\""));
|
||||||
assert!(build_script.contains("export LWI_CXXFLAGS=\"${LWI_CXXFLAGS:-$LWI_CFLAGS}\""));
|
assert!(build_script.contains("export LWI_CXXFLAGS=\"${LWI_CXXFLAGS:-$LWI_CFLAGS}\""));
|
||||||
assert!(build_script.contains("rm -rf build-llvm"));
|
assert!(build_script.contains("rm -rf build-llvm"));
|
||||||
assert!(build_script.contains("-DLLVM_CCACHE_BUILD=ON"));
|
assert!(build_script.contains("LBI_CCACHE=\"$(command -v ccache)\""));
|
||||||
assert!(
|
assert!(build_script.contains(
|
||||||
build_script.contains("cmake -G Ninja \"../llvm\" \\\n -DLLVM_CCACHE_BUILD=ON \\")
|
"cmake -G Ninja \"../llvm\" \\\n -DCMAKE_C_COMPILER_LAUNCHER=\"$LBI_CCACHE\" \\"
|
||||||
);
|
));
|
||||||
|
assert!(build_script.contains("-DCMAKE_CXX_COMPILER_LAUNCHER=\"$LBI_CCACHE\""));
|
||||||
|
assert!(build_script.contains("-DCMAKE_ASM_COMPILER_LAUNCHER=\"$LBI_CCACHE\""));
|
||||||
|
assert!(!build_script.contains("-DLLVM_CCACHE_BUILD=ON"));
|
||||||
assert!(build_script.contains("LLVM_ENABLE_RUNTIMES=\"compiler-rt\""));
|
assert!(build_script.contains("LLVM_ENABLE_RUNTIMES=\"compiler-rt\""));
|
||||||
assert!(build_script.contains("COMPILER_RT_BUILD_BUILTINS=ON"));
|
assert!(build_script.contains("COMPILER_RT_BUILD_BUILTINS=ON"));
|
||||||
assert!(build_script.contains("COMPILER_RT_DEFAULT_TARGET_ONLY=ON"));
|
assert!(build_script.contains("COMPILER_RT_DEFAULT_TARGET_ONLY=ON"));
|
||||||
@@ -6456,6 +6554,7 @@ sed -i \
|
|||||||
|
|
||||||
assert!(build_script.contains(" --target=\"$LBI_TARGET\" \\\n"));
|
assert!(build_script.contains(" --target=\"$LBI_TARGET\" \\\n"));
|
||||||
assert!(build_script.contains(" --host=\"$LBI_TARGET\" \\\n"));
|
assert!(build_script.contains(" --host=\"$LBI_TARGET\" \\\n"));
|
||||||
|
assert!(!build_script.contains(" --build=\"$LBI_TARGET\" \\\n"));
|
||||||
assert!(build_script.contains("-DCMAKE_C_COMPILER_TARGET=\"$LBI_TARGET\""));
|
assert!(build_script.contains("-DCMAKE_C_COMPILER_TARGET=\"$LBI_TARGET\""));
|
||||||
assert!(build_script.contains("-DCMAKE_CXX_COMPILER_TARGET=\"$LBI_TARGET\""));
|
assert!(build_script.contains("-DCMAKE_CXX_COMPILER_TARGET=\"$LBI_TARGET\""));
|
||||||
assert!(
|
assert!(
|
||||||
@@ -6470,6 +6569,18 @@ sed -i \
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn copied_build_profile_does_not_default_build_tuple() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
|
||||||
|
copy_build_profile(tmp.path(), "x86_64-unknown-linux-musl", "x86_64").unwrap();
|
||||||
|
|
||||||
|
let profile = fs::read_to_string(tmp.path().join("etc/profile.d/lbi-build.sh")).unwrap();
|
||||||
|
assert!(profile.contains(" --target=\"$LBI_TARGET\" \\\n"));
|
||||||
|
assert!(profile.contains(" --host=\"$LBI_TARGET\" \\\n"));
|
||||||
|
assert!(!profile.contains(" --build=\"$LBI_TARGET\" \\\n"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rewrite_make_flags_does_not_duplicate_existing_parallel_flags() {
|
fn rewrite_make_flags_does_not_duplicate_existing_parallel_flags() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -491,6 +491,18 @@ fn generate_lib32_meson_cross_file(
|
|||||||
let ld = meson_binary_value(&command_words(&flags.ld), "linker")?;
|
let ld = meson_binary_value(&command_words(&flags.ld), "linker")?;
|
||||||
content.push_str(&format!("ld = {ld}\n"));
|
content.push_str(&format!("ld = {ld}\n"));
|
||||||
}
|
}
|
||||||
|
for (name, command, label) in [
|
||||||
|
("strip", flags.strip.as_str(), "strip"),
|
||||||
|
("nm", flags.nm.as_str(), "nm"),
|
||||||
|
("objcopy", flags.objcopy.as_str(), "objcopy"),
|
||||||
|
("objdump", flags.objdump.as_str(), "objdump"),
|
||||||
|
("readelf", flags.readelf.as_str(), "readelf"),
|
||||||
|
] {
|
||||||
|
if !command.trim().is_empty() {
|
||||||
|
let value = meson_binary_value(&command_words(command), label)?;
|
||||||
|
content.push_str(&format!("{name} = {value}\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
content.push_str(&format!(
|
content.push_str(&format!(
|
||||||
"\n[host_machine]\nsystem = 'linux'\ncpu_family = '{cpu_family}'\ncpu = '{arch}'\nendian = 'little'\n"
|
"\n[host_machine]\nsystem = 'linux'\ncpu_family = '{cpu_family}'\ncpu = '{arch}'\nendian = 'little'\n"
|
||||||
));
|
));
|
||||||
@@ -961,7 +973,12 @@ mod tests {
|
|||||||
cc: "clang -m32".to_string(),
|
cc: "clang -m32".to_string(),
|
||||||
cxx: "clang++ -m32".to_string(),
|
cxx: "clang++ -m32".to_string(),
|
||||||
ar: "llvm-ar".to_string(),
|
ar: "llvm-ar".to_string(),
|
||||||
|
strip: "llvm-strip".to_string(),
|
||||||
ld: "ld.lld".to_string(),
|
ld: "ld.lld".to_string(),
|
||||||
|
nm: "llvm-nm".to_string(),
|
||||||
|
objcopy: "llvm-objcopy".to_string(),
|
||||||
|
objdump: "llvm-objdump".to_string(),
|
||||||
|
readelf: "llvm-readelf".to_string(),
|
||||||
..BuildFlags::default()
|
..BuildFlags::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -970,6 +987,12 @@ mod tests {
|
|||||||
assert!(content.contains("Generated by depot for target: i686-sfg-linux-gnu"));
|
assert!(content.contains("Generated by depot for target: i686-sfg-linux-gnu"));
|
||||||
assert!(content.contains("c = ['clang', '-m32', '--target=i686-sfg-linux-gnu']"));
|
assert!(content.contains("c = ['clang', '-m32', '--target=i686-sfg-linux-gnu']"));
|
||||||
assert!(content.contains("cpp = ['clang++', '-m32', '--target=i686-sfg-linux-gnu']"));
|
assert!(content.contains("cpp = ['clang++', '-m32', '--target=i686-sfg-linux-gnu']"));
|
||||||
|
assert!(content.contains("strip = 'llvm-strip'"));
|
||||||
|
assert!(content.contains("ld = 'ld.lld'"));
|
||||||
|
assert!(content.contains("nm = 'llvm-nm'"));
|
||||||
|
assert!(content.contains("objcopy = 'llvm-objcopy'"));
|
||||||
|
assert!(content.contains("objdump = 'llvm-objdump'"));
|
||||||
|
assert!(content.contains("readelf = 'llvm-readelf'"));
|
||||||
assert!(content.contains("cpu_family = 'x86'"));
|
assert!(content.contains("cpu_family = 'x86'"));
|
||||||
assert!(content.contains("cpu = 'i686'"));
|
assert!(content.contains("cpu = 'i686'"));
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
+388
-26
@@ -205,9 +205,36 @@ pub fn set_env_var(env_vars: &mut EnvVars, key: &str, value: impl Into<String>)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_expanded_env_var(env_vars: &mut EnvVars, key: &str, value: impl AsRef<str>) {
|
||||||
|
let expanded = expand_with_envs(value.as_ref(), env_vars);
|
||||||
|
set_env_var(env_vars, key, expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configured_tool_or_default(configured: &str, default: &str) -> String {
|
||||||
|
let configured = configured.trim();
|
||||||
|
if configured.is_empty() {
|
||||||
|
default.to_string()
|
||||||
|
} else {
|
||||||
|
configured.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configured_defaulted_tool_or_default(
|
||||||
|
configured: &str,
|
||||||
|
implicit_default: &str,
|
||||||
|
default: &str,
|
||||||
|
) -> String {
|
||||||
|
let configured = configured.trim();
|
||||||
|
if configured.is_empty() || configured == implicit_default {
|
||||||
|
default.to_string()
|
||||||
|
} else {
|
||||||
|
configured.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn apply_declared_env_vars(spec: &PackageSpec, env_vars: &mut EnvVars) {
|
fn apply_declared_env_vars(spec: &PackageSpec, env_vars: &mut EnvVars) {
|
||||||
for raw in &spec.build.flags.env_vars {
|
for raw in &spec.build.flags.env_vars {
|
||||||
let expanded = spec.expand_vars(raw);
|
let expanded = expand_with_envs(&spec.expand_vars(raw), env_vars);
|
||||||
let entry = expanded.trim();
|
let entry = expanded.trim();
|
||||||
if entry.is_empty() {
|
if entry.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
@@ -234,6 +261,21 @@ fn apply_declared_env_vars(spec: &PackageSpec, env_vars: &mut EnvVars) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Expand environment variables in a string using Depot's build env first,
|
||||||
|
/// falling back to the parent process environment.
|
||||||
|
pub(crate) fn expand_with_envs(input: &str, envs: &[(String, String)]) -> String {
|
||||||
|
let mut result = input.to_string();
|
||||||
|
for (key, value) in envs {
|
||||||
|
result = result.replace(&format!("${key}"), value);
|
||||||
|
result = result.replace(&format!("${{{key}}}"), value);
|
||||||
|
}
|
||||||
|
for (key, value) in std::env::vars() {
|
||||||
|
result = result.replace(&format!("${key}"), &value);
|
||||||
|
result = result.replace(&format!("${{{key}}}"), &value);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
fn default_libdir_for_variant(lib32_variant: bool) -> &'static str {
|
fn default_libdir_for_variant(lib32_variant: bool) -> &'static str {
|
||||||
if lib32_variant {
|
if lib32_variant {
|
||||||
"/usr/lib32"
|
"/usr/lib32"
|
||||||
@@ -513,6 +555,23 @@ pub(crate) fn install_dirs(flags: &crate::package::BuildFlags) -> InstallDirs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn apply_install_dir_env_vars(env_vars: &mut EnvVars, flags: &crate::package::BuildFlags) {
|
||||||
|
let dirs = install_dirs(flags);
|
||||||
|
set_env_var(env_vars, "PREFIX", flags.prefix.clone());
|
||||||
|
set_env_var(env_vars, "BINDIR", dirs.bindir);
|
||||||
|
set_env_var(env_vars, "SBINDIR", dirs.sbindir);
|
||||||
|
set_env_var(env_vars, "LIBDIR", dirs.libdir);
|
||||||
|
set_env_var(env_vars, "LIBEXECDIR", dirs.libexecdir);
|
||||||
|
set_env_var(env_vars, "SYSCONFDIR", dirs.sysconfdir);
|
||||||
|
set_env_var(env_vars, "LOCALSTATEDIR", dirs.localstatedir);
|
||||||
|
set_env_var(env_vars, "SHAREDSTATEDIR", dirs.sharedstatedir);
|
||||||
|
set_env_var(env_vars, "INCLUDEDIR", dirs.includedir);
|
||||||
|
set_env_var(env_vars, "DATAROOTDIR", dirs.datarootdir);
|
||||||
|
set_env_var(env_vars, "DATADIR", dirs.datadir);
|
||||||
|
set_env_var(env_vars, "MANDIR", dirs.mandir);
|
||||||
|
set_env_var(env_vars, "INFODIR", dirs.infodir);
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn install_destdir_path(
|
pub(crate) fn install_destdir_path(
|
||||||
build_dir: &Path,
|
build_dir: &Path,
|
||||||
destdir: &Path,
|
destdir: &Path,
|
||||||
@@ -628,6 +687,10 @@ fn compiler_flag_sets(
|
|||||||
"build.flags.ltoflags",
|
"build.flags.ltoflags",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if let Some(fuse_ld) = fuse_ld_flag(&flags.fuse_ld) {
|
||||||
|
ldflags.insert(0, fuse_ld);
|
||||||
|
}
|
||||||
|
|
||||||
if flags.use_lto && !ltoflags.is_empty() {
|
if flags.use_lto && !ltoflags.is_empty() {
|
||||||
cflags.extend(ltoflags.iter().cloned());
|
cflags.extend(ltoflags.iter().cloned());
|
||||||
cxxflags.extend(ltoflags.iter().cloned());
|
cxxflags.extend(ltoflags.iter().cloned());
|
||||||
@@ -637,6 +700,26 @@ fn compiler_flag_sets(
|
|||||||
(cflags, cxxflags, ldflags, ltoflags)
|
(cflags, cxxflags, ldflags, ltoflags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fuse_ld_flag(fuse_ld: &str) -> Option<String> {
|
||||||
|
let fuse_ld = fuse_ld.trim();
|
||||||
|
if fuse_ld.is_empty() {
|
||||||
|
None
|
||||||
|
} else if fuse_ld.starts_with("-fuse-ld=") || fuse_ld.starts_with("--ld-path=") {
|
||||||
|
Some(fuse_ld.to_string())
|
||||||
|
} else if fuse_ld.contains('/') {
|
||||||
|
Some(format!("-fuse-ld={fuse_ld}"))
|
||||||
|
} else {
|
||||||
|
let driver_name = match fuse_ld {
|
||||||
|
"ld.lld" => "lld",
|
||||||
|
"ld.mold" => "mold",
|
||||||
|
"ld.gold" => "gold",
|
||||||
|
"ld.bfd" => "bfd",
|
||||||
|
_ => fuse_ld,
|
||||||
|
};
|
||||||
|
Some(format!("-fuse-ld={driver_name}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn rust_ltoflags(flags: &crate::package::BuildFlags) -> Vec<String> {
|
fn rust_ltoflags(flags: &crate::package::BuildFlags) -> Vec<String> {
|
||||||
sanitize_flag_list(flags.rustltoflags.clone(), "build.flags.rustltoflags")
|
sanitize_flag_list(flags.rustltoflags.clone(), "build.flags.rustltoflags")
|
||||||
}
|
}
|
||||||
@@ -664,21 +747,25 @@ pub fn standard_build_env(
|
|||||||
let mut env_vars: EnvVars = Vec::new();
|
let mut env_vars: EnvVars = Vec::new();
|
||||||
let export_compiler_flags = export_compiler_flags && !flags.no_flags;
|
let export_compiler_flags = export_compiler_flags && !flags.no_flags;
|
||||||
|
|
||||||
|
if !flags.tool_dir.trim().is_empty() {
|
||||||
|
set_expanded_env_var(&mut env_vars, "TOOL_DIR", flags.tool_dir.trim());
|
||||||
|
}
|
||||||
|
|
||||||
if include_compiler_env && export_compiler_flags {
|
if include_compiler_env && export_compiler_flags {
|
||||||
let (cflags, cxxflags, ldflags, ltoflags) = compiler_flag_sets(flags);
|
let (cflags, cxxflags, ldflags, ltoflags) = compiler_flag_sets(flags);
|
||||||
|
|
||||||
if !cflags.is_empty() {
|
if !cflags.is_empty() {
|
||||||
set_env_var(&mut env_vars, "CFLAGS", cflags.join(" "));
|
set_expanded_env_var(&mut env_vars, "CFLAGS", cflags.join(" "));
|
||||||
}
|
}
|
||||||
if !cxxflags.is_empty() {
|
if !cxxflags.is_empty() {
|
||||||
set_env_var(&mut env_vars, "CXXFLAGS", cxxflags.join(" "));
|
set_expanded_env_var(&mut env_vars, "CXXFLAGS", cxxflags.join(" "));
|
||||||
}
|
}
|
||||||
if !ltoflags.is_empty() {
|
if !ltoflags.is_empty() {
|
||||||
set_env_var(&mut env_vars, "LTOFLAGS", ltoflags.join(" "));
|
set_expanded_env_var(&mut env_vars, "LTOFLAGS", ltoflags.join(" "));
|
||||||
}
|
}
|
||||||
let rust_ltoflags = rust_ltoflags(flags);
|
let rust_ltoflags = rust_ltoflags(flags);
|
||||||
if !rust_ltoflags.is_empty() {
|
if !rust_ltoflags.is_empty() {
|
||||||
set_env_var(&mut env_vars, "RUSTLTOFLAGS", rust_ltoflags.join(" "));
|
set_expanded_env_var(&mut env_vars, "RUSTLTOFLAGS", rust_ltoflags.join(" "));
|
||||||
}
|
}
|
||||||
|
|
||||||
let ldflags = if !ldflags.is_empty() || !flags.libc.is_empty() {
|
let ldflags = if !ldflags.is_empty() || !flags.libc.is_empty() {
|
||||||
@@ -693,7 +780,7 @@ pub fn standard_build_env(
|
|||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
if !ldflags.is_empty() {
|
if !ldflags.is_empty() {
|
||||||
set_env_var(&mut env_vars, "LDFLAGS", ldflags);
|
set_expanded_env_var(&mut env_vars, "LDFLAGS", ldflags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -712,15 +799,9 @@ pub fn standard_build_env(
|
|||||||
if !effective_carch.is_empty() {
|
if !effective_carch.is_empty() {
|
||||||
set_env_var(&mut env_vars, "CARCH", effective_carch);
|
set_env_var(&mut env_vars, "CARCH", effective_carch);
|
||||||
}
|
}
|
||||||
if !flags.prefix.is_empty() {
|
apply_install_dir_env_vars(&mut env_vars, flags);
|
||||||
set_env_var(&mut env_vars, "PREFIX", flags.prefix.clone());
|
|
||||||
}
|
|
||||||
if !flags.makeflags.trim().is_empty() {
|
if !flags.makeflags.trim().is_empty() {
|
||||||
set_env_var(
|
set_expanded_env_var(&mut env_vars, "MAKEFLAGS", flags.makeflags.trim());
|
||||||
&mut env_vars,
|
|
||||||
"MAKEFLAGS",
|
|
||||||
flags.makeflags.trim().to_string(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set_env_var(&mut env_vars, "DEPOT_ROOTFS", flags.rootfs.clone());
|
set_env_var(&mut env_vars, "DEPOT_ROOTFS", flags.rootfs.clone());
|
||||||
@@ -732,13 +813,60 @@ pub fn standard_build_env(
|
|||||||
|
|
||||||
if include_compiler_env {
|
if include_compiler_env {
|
||||||
if let Some(cc_cfg) = cross {
|
if let Some(cc_cfg) = cross {
|
||||||
set_env_var(&mut env_vars, "CC", cc_cfg.cc.clone());
|
let default_flags = BuildFlags::default();
|
||||||
set_env_var(&mut env_vars, "CXX", cc_cfg.cxx.clone());
|
set_expanded_env_var(
|
||||||
set_env_var(&mut env_vars, "AR", cc_cfg.ar.clone());
|
&mut env_vars,
|
||||||
set_env_var(&mut env_vars, "RANLIB", cc_cfg.ranlib.clone());
|
"CC",
|
||||||
set_env_var(&mut env_vars, "STRIP", cc_cfg.strip.clone());
|
configured_defaulted_tool_or_default(&flags.cc, &default_flags.cc, &cc_cfg.cc),
|
||||||
set_env_var(&mut env_vars, "LD", cc_cfg.ld.clone());
|
);
|
||||||
set_env_var(&mut env_vars, "NM", cc_cfg.nm.clone());
|
set_expanded_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
"CXX",
|
||||||
|
configured_defaulted_tool_or_default(&flags.cxx, &default_flags.cxx, &cc_cfg.cxx),
|
||||||
|
);
|
||||||
|
set_expanded_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
"AR",
|
||||||
|
configured_defaulted_tool_or_default(&flags.ar, &default_flags.ar, &cc_cfg.ar),
|
||||||
|
);
|
||||||
|
set_expanded_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
"RANLIB",
|
||||||
|
configured_tool_or_default(&flags.ranlib, &cc_cfg.ranlib),
|
||||||
|
);
|
||||||
|
set_expanded_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
"STRIP",
|
||||||
|
configured_tool_or_default(&flags.strip, &cc_cfg.strip),
|
||||||
|
);
|
||||||
|
set_expanded_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
"LD",
|
||||||
|
configured_tool_or_default(&flags.ld, &cc_cfg.ld),
|
||||||
|
);
|
||||||
|
set_expanded_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
"NM",
|
||||||
|
configured_tool_or_default(&flags.nm, &cc_cfg.nm),
|
||||||
|
);
|
||||||
|
set_expanded_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
"OBJCOPY",
|
||||||
|
configured_tool_or_default(&flags.objcopy, &cc_cfg.objcopy),
|
||||||
|
);
|
||||||
|
set_expanded_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
"OBJDUMP",
|
||||||
|
configured_tool_or_default(&flags.objdump, &cc_cfg.objdump),
|
||||||
|
);
|
||||||
|
set_expanded_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
"READELF",
|
||||||
|
configured_tool_or_default(&flags.readelf, &cc_cfg.readelf),
|
||||||
|
);
|
||||||
|
if !flags.cpp.trim().is_empty() {
|
||||||
|
set_expanded_env_var(&mut env_vars, "CPP", flags.cpp.trim());
|
||||||
|
}
|
||||||
set_env_var(&mut env_vars, "CROSS_PREFIX", cc_cfg.prefix.clone());
|
set_env_var(&mut env_vars, "CROSS_PREFIX", cc_cfg.prefix.clone());
|
||||||
set_env_var(
|
set_env_var(
|
||||||
&mut env_vars,
|
&mut env_vars,
|
||||||
@@ -746,14 +874,32 @@ pub fn standard_build_env(
|
|||||||
format!("{}-", cc_cfg.prefix),
|
format!("{}-", cc_cfg.prefix),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
set_env_var(&mut env_vars, "CC", flags.cc.clone());
|
set_expanded_env_var(&mut env_vars, "CC", flags.cc.trim());
|
||||||
set_env_var(&mut env_vars, "CXX", flags.cxx.clone());
|
set_expanded_env_var(&mut env_vars, "CXX", flags.cxx.trim());
|
||||||
set_env_var(&mut env_vars, "AR", flags.ar.clone());
|
set_expanded_env_var(&mut env_vars, "AR", flags.ar.trim());
|
||||||
|
if !flags.ranlib.trim().is_empty() {
|
||||||
|
set_expanded_env_var(&mut env_vars, "RANLIB", flags.ranlib.trim());
|
||||||
|
}
|
||||||
|
if !flags.strip.trim().is_empty() {
|
||||||
|
set_expanded_env_var(&mut env_vars, "STRIP", flags.strip.trim());
|
||||||
|
}
|
||||||
if !flags.ld.trim().is_empty() {
|
if !flags.ld.trim().is_empty() {
|
||||||
set_env_var(&mut env_vars, "LD", flags.ld.clone());
|
set_expanded_env_var(&mut env_vars, "LD", flags.ld.trim());
|
||||||
|
}
|
||||||
|
if !flags.nm.trim().is_empty() {
|
||||||
|
set_expanded_env_var(&mut env_vars, "NM", flags.nm.trim());
|
||||||
|
}
|
||||||
|
if !flags.objcopy.trim().is_empty() {
|
||||||
|
set_expanded_env_var(&mut env_vars, "OBJCOPY", flags.objcopy.trim());
|
||||||
|
}
|
||||||
|
if !flags.objdump.trim().is_empty() {
|
||||||
|
set_expanded_env_var(&mut env_vars, "OBJDUMP", flags.objdump.trim());
|
||||||
|
}
|
||||||
|
if !flags.readelf.trim().is_empty() {
|
||||||
|
set_expanded_env_var(&mut env_vars, "READELF", flags.readelf.trim());
|
||||||
}
|
}
|
||||||
if !flags.cpp.trim().is_empty() {
|
if !flags.cpp.trim().is_empty() {
|
||||||
set_env_var(&mut env_vars, "CPP", flags.cpp.clone());
|
set_expanded_env_var(&mut env_vars, "CPP", flags.cpp.trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1026,6 +1172,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn env_value<'a>(env: &'a EnvVars, key: &str) -> Option<&'a str> {
|
||||||
|
env.iter()
|
||||||
|
.find(|(candidate, _)| candidate == key)
|
||||||
|
.map(|(_, value)| value.as_str())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prepare_command() {
|
fn test_prepare_command() {
|
||||||
let mut cmd = Command::new("ls");
|
let mut cmd = Command::new("ls");
|
||||||
@@ -1143,14 +1295,121 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_standard_build_env_exports_native_linker_and_cpp() {
|
fn test_standard_build_env_exports_native_linker_and_cpp() {
|
||||||
let mut spec = mk_spec(Vec::new(), Vec::new());
|
let mut spec = mk_spec(Vec::new(), Vec::new());
|
||||||
|
spec.build.flags.ranlib = "llvm-ranlib".to_string();
|
||||||
|
spec.build.flags.strip = "llvm-strip".to_string();
|
||||||
spec.build.flags.ld = "ld.lld".to_string();
|
spec.build.flags.ld = "ld.lld".to_string();
|
||||||
|
spec.build.flags.nm = "llvm-nm".to_string();
|
||||||
|
spec.build.flags.objcopy = "llvm-objcopy".to_string();
|
||||||
|
spec.build.flags.objdump = "llvm-objdump".to_string();
|
||||||
|
spec.build.flags.readelf = "llvm-readelf".to_string();
|
||||||
spec.build.flags.cpp = "clang-cpp".to_string();
|
spec.build.flags.cpp = "clang-cpp".to_string();
|
||||||
|
|
||||||
let env = standard_build_env(&spec, None, true, true);
|
let env = standard_build_env(&spec, None, true, true);
|
||||||
|
assert!(env.iter().any(|(k, v)| k == "RANLIB" && v == "llvm-ranlib"));
|
||||||
|
assert!(env.iter().any(|(k, v)| k == "STRIP" && v == "llvm-strip"));
|
||||||
assert!(env.iter().any(|(k, v)| k == "LD" && v == "ld.lld"));
|
assert!(env.iter().any(|(k, v)| k == "LD" && v == "ld.lld"));
|
||||||
|
assert!(env.iter().any(|(k, v)| k == "NM" && v == "llvm-nm"));
|
||||||
|
assert!(
|
||||||
|
env.iter()
|
||||||
|
.any(|(k, v)| k == "OBJCOPY" && v == "llvm-objcopy")
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
env.iter()
|
||||||
|
.any(|(k, v)| k == "OBJDUMP" && v == "llvm-objdump")
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
env.iter()
|
||||||
|
.any(|(k, v)| k == "READELF" && v == "llvm-readelf")
|
||||||
|
);
|
||||||
assert!(env.iter().any(|(k, v)| k == "CPP" && v == "clang-cpp"));
|
assert!(env.iter().any(|(k, v)| k == "CPP" && v == "clang-cpp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_standard_build_env_exports_tool_dir_and_expands_tool_commands() {
|
||||||
|
let mut spec = mk_spec(
|
||||||
|
vec!["--gcc-toolchain=$TOOL_DIR"],
|
||||||
|
vec!["-B$TOOL_DIR", "-Wl,--as-needed"],
|
||||||
|
);
|
||||||
|
spec.build.flags.tool_dir = "/opt/depot-tools/bin".to_string();
|
||||||
|
spec.build.flags.cc = "$TOOL_DIR/clang".to_string();
|
||||||
|
spec.build.flags.cxx = "$TOOL_DIR/clang++".to_string();
|
||||||
|
spec.build.flags.ar = "$TOOL_DIR/llvm-ar".to_string();
|
||||||
|
spec.build.flags.ranlib = "$TOOL_DIR/llvm-ranlib".to_string();
|
||||||
|
spec.build.flags.ld = "$TOOL_DIR/ld.lld".to_string();
|
||||||
|
spec.build.flags.env_vars = vec!["LLVM_CONFIG=$TOOL_DIR/llvm-config".to_string()];
|
||||||
|
|
||||||
|
let env = standard_build_env(&spec, None, true, true);
|
||||||
|
|
||||||
|
assert_eq!(env_value(&env, "TOOL_DIR"), Some("/opt/depot-tools/bin"));
|
||||||
|
assert_eq!(env_value(&env, "CC"), Some("/opt/depot-tools/bin/clang"));
|
||||||
|
assert_eq!(env_value(&env, "CXX"), Some("/opt/depot-tools/bin/clang++"));
|
||||||
|
assert_eq!(env_value(&env, "AR"), Some("/opt/depot-tools/bin/llvm-ar"));
|
||||||
|
assert_eq!(
|
||||||
|
env_value(&env, "RANLIB"),
|
||||||
|
Some("/opt/depot-tools/bin/llvm-ranlib")
|
||||||
|
);
|
||||||
|
assert_eq!(env_value(&env, "LD"), Some("/opt/depot-tools/bin/ld.lld"));
|
||||||
|
assert_eq!(
|
||||||
|
env_value(&env, "CFLAGS"),
|
||||||
|
Some("--gcc-toolchain=/opt/depot-tools/bin")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
env_value(&env, "LDFLAGS"),
|
||||||
|
Some("-B/opt/depot-tools/bin -Wl,--as-needed")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
env_value(&env, "LLVM_CONFIG"),
|
||||||
|
Some("/opt/depot-tools/bin/llvm-config")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_standard_build_env_cross_uses_package_tool_overrides() {
|
||||||
|
let mut spec = mk_spec(Vec::new(), Vec::new());
|
||||||
|
spec.build.flags.cc = "/tools/bin/clang".to_string();
|
||||||
|
spec.build.flags.cxx = "/tools/bin/clang++".to_string();
|
||||||
|
spec.build.flags.ar = "/tools/bin/llvm-ar".to_string();
|
||||||
|
spec.build.flags.ranlib = "/tools/bin/llvm-ranlib".to_string();
|
||||||
|
spec.build.flags.strip = "/tools/bin/llvm-strip".to_string();
|
||||||
|
spec.build.flags.ld = "/tools/bin/ld.lld".to_string();
|
||||||
|
spec.build.flags.nm = "/tools/bin/llvm-nm".to_string();
|
||||||
|
spec.build.flags.objcopy = "/tools/bin/llvm-objcopy".to_string();
|
||||||
|
spec.build.flags.objdump = "/tools/bin/llvm-objdump".to_string();
|
||||||
|
spec.build.flags.readelf = "/tools/bin/llvm-readelf".to_string();
|
||||||
|
spec.build.flags.cpp = "/tools/bin/clang-cpp".to_string();
|
||||||
|
let cross = CrossConfig {
|
||||||
|
prefix: "x86_64-test-linux-gnu".into(),
|
||||||
|
cc: "x86_64-test-linux-gnu-gcc".into(),
|
||||||
|
cxx: "x86_64-test-linux-gnu-g++".into(),
|
||||||
|
ar: "x86_64-test-linux-gnu-ar".into(),
|
||||||
|
ranlib: "x86_64-test-linux-gnu-ranlib".into(),
|
||||||
|
strip: "x86_64-test-linux-gnu-strip".into(),
|
||||||
|
ld: "x86_64-test-linux-gnu-ld".into(),
|
||||||
|
nm: "x86_64-test-linux-gnu-nm".into(),
|
||||||
|
objcopy: "x86_64-test-linux-gnu-objcopy".into(),
|
||||||
|
objdump: "x86_64-test-linux-gnu-objdump".into(),
|
||||||
|
readelf: "x86_64-test-linux-gnu-readelf".into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let env = standard_build_env(&spec, Some(&cross), true, true);
|
||||||
|
|
||||||
|
assert_eq!(env_value(&env, "CC"), Some("/tools/bin/clang"));
|
||||||
|
assert_eq!(env_value(&env, "CXX"), Some("/tools/bin/clang++"));
|
||||||
|
assert_eq!(env_value(&env, "AR"), Some("/tools/bin/llvm-ar"));
|
||||||
|
assert_eq!(env_value(&env, "RANLIB"), Some("/tools/bin/llvm-ranlib"));
|
||||||
|
assert_eq!(env_value(&env, "STRIP"), Some("/tools/bin/llvm-strip"));
|
||||||
|
assert_eq!(env_value(&env, "LD"), Some("/tools/bin/ld.lld"));
|
||||||
|
assert_eq!(env_value(&env, "NM"), Some("/tools/bin/llvm-nm"));
|
||||||
|
assert_eq!(env_value(&env, "OBJCOPY"), Some("/tools/bin/llvm-objcopy"));
|
||||||
|
assert_eq!(env_value(&env, "OBJDUMP"), Some("/tools/bin/llvm-objdump"));
|
||||||
|
assert_eq!(env_value(&env, "READELF"), Some("/tools/bin/llvm-readelf"));
|
||||||
|
assert_eq!(env_value(&env, "CPP"), Some("/tools/bin/clang-cpp"));
|
||||||
|
assert_eq!(
|
||||||
|
env_value(&env, "CROSS_PREFIX"),
|
||||||
|
Some("x86_64-test-linux-gnu")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_standard_build_env_exports_effective_carch_for_cross_and_lib32() {
|
fn test_standard_build_env_exports_effective_carch_for_cross_and_lib32() {
|
||||||
let spec = mk_spec(Vec::new(), Vec::new());
|
let spec = mk_spec(Vec::new(), Vec::new());
|
||||||
@@ -1175,6 +1434,24 @@ mod tests {
|
|||||||
.any(|(k, v)| k == "CARCH" && v == "aarch64"),
|
.any(|(k, v)| k == "CARCH" && v == "aarch64"),
|
||||||
"expected cross builds to export target CARCH"
|
"expected cross builds to export target CARCH"
|
||||||
);
|
);
|
||||||
|
assert!(
|
||||||
|
cross_env
|
||||||
|
.iter()
|
||||||
|
.any(|(k, v)| k == "OBJCOPY" && v == "aarch64-linux-gnu-objcopy"),
|
||||||
|
"expected cross builds to export OBJCOPY"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
cross_env
|
||||||
|
.iter()
|
||||||
|
.any(|(k, v)| k == "OBJDUMP" && v == "aarch64-linux-gnu-objdump"),
|
||||||
|
"expected cross builds to export OBJDUMP"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
cross_env
|
||||||
|
.iter()
|
||||||
|
.any(|(k, v)| k == "READELF" && v == "aarch64-linux-gnu-readelf"),
|
||||||
|
"expected cross builds to export READELF"
|
||||||
|
);
|
||||||
|
|
||||||
let mut lib32_spec = spec.clone();
|
let mut lib32_spec = spec.clone();
|
||||||
lib32_spec.build.flags.lib32_variant = true;
|
lib32_spec.build.flags.lib32_variant = true;
|
||||||
@@ -1271,6 +1548,29 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_standard_build_env_injects_fuse_ld_into_ldflags() {
|
||||||
|
let mut spec = mk_spec(Vec::new(), vec!["-Wl,--as-needed"]);
|
||||||
|
spec.build.flags.fuse_ld = "/usr/bin/ld.lld".into();
|
||||||
|
|
||||||
|
let env = standard_build_env(&spec, None, true, true);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
env_value(&env, "LDFLAGS"),
|
||||||
|
Some("-fuse-ld=/usr/bin/ld.lld -Wl,--as-needed")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_standard_build_env_normalizes_fuse_ld_tool_names() {
|
||||||
|
let mut spec = mk_spec(Vec::new(), Vec::new());
|
||||||
|
spec.build.flags.fuse_ld = "ld.lld".into();
|
||||||
|
|
||||||
|
let env = standard_build_env(&spec, None, true, true);
|
||||||
|
|
||||||
|
assert_eq!(env_value(&env, "LDFLAGS"), Some("-fuse-ld=lld"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_standard_build_env_applies_replace_flag_rules() {
|
fn test_standard_build_env_applies_replace_flag_rules() {
|
||||||
let mut spec = mk_spec(vec!["-D_FORTIFY_SOURCE=3", "-O2"], vec!["-Wl,-O3"]);
|
let mut spec = mk_spec(vec!["-D_FORTIFY_SOURCE=3", "-O2"], vec!["-Wl,-O3"]);
|
||||||
@@ -1383,6 +1683,62 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_standard_build_env_exports_install_dir_vars() {
|
||||||
|
let mut spec = mk_spec(Vec::new(), Vec::new());
|
||||||
|
spec.build.flags.prefix = "/system".into();
|
||||||
|
spec.build.flags.bindir = "/system/binaries".into();
|
||||||
|
spec.build.flags.sbindir = "/system/systembinaries".into();
|
||||||
|
spec.build.flags.libdir = "/system/libraries".into();
|
||||||
|
spec.build.flags.libexecdir = "/system/libexec".into();
|
||||||
|
spec.build.flags.sysconfdir = "/system/configuration".into();
|
||||||
|
spec.build.flags.localstatedir = "/system/variable".into();
|
||||||
|
spec.build.flags.sharedstatedir = "/system/variable/lib".into();
|
||||||
|
spec.build.flags.includedir = "/system/headers".into();
|
||||||
|
spec.build.flags.datarootdir = "/system/share".into();
|
||||||
|
spec.build.flags.datadir = "/system/data".into();
|
||||||
|
spec.build.flags.mandir = "/system/documentation/man-pages".into();
|
||||||
|
spec.build.flags.infodir = "/system/documentation/info".into();
|
||||||
|
|
||||||
|
let env = standard_build_env(&spec, None, false, true);
|
||||||
|
|
||||||
|
assert_eq!(env_value(&env, "PREFIX"), Some("/system"));
|
||||||
|
assert_eq!(env_value(&env, "BINDIR"), Some("/system/binaries"));
|
||||||
|
assert_eq!(env_value(&env, "SBINDIR"), Some("/system/systembinaries"));
|
||||||
|
assert_eq!(env_value(&env, "LIBDIR"), Some("/system/libraries"));
|
||||||
|
assert_eq!(env_value(&env, "LIBEXECDIR"), Some("/system/libexec"));
|
||||||
|
assert_eq!(env_value(&env, "SYSCONFDIR"), Some("/system/configuration"));
|
||||||
|
assert_eq!(env_value(&env, "LOCALSTATEDIR"), Some("/system/variable"));
|
||||||
|
assert_eq!(
|
||||||
|
env_value(&env, "SHAREDSTATEDIR"),
|
||||||
|
Some("/system/variable/lib")
|
||||||
|
);
|
||||||
|
assert_eq!(env_value(&env, "INCLUDEDIR"), Some("/system/headers"));
|
||||||
|
assert_eq!(env_value(&env, "DATAROOTDIR"), Some("/system/share"));
|
||||||
|
assert_eq!(env_value(&env, "DATADIR"), Some("/system/data"));
|
||||||
|
assert_eq!(
|
||||||
|
env_value(&env, "MANDIR"),
|
||||||
|
Some("/system/documentation/man-pages")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
env_value(&env, "INFODIR"),
|
||||||
|
Some("/system/documentation/info")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_standard_build_env_install_dir_vars_use_effective_defaults() {
|
||||||
|
let mut spec = mk_spec(Vec::new(), Vec::new());
|
||||||
|
spec.build.flags.lib32_variant = true;
|
||||||
|
|
||||||
|
let env = standard_build_env(&spec, None, false, true);
|
||||||
|
|
||||||
|
assert_eq!(env_value(&env, "LIBDIR"), Some("/usr/lib32"));
|
||||||
|
assert_eq!(env_value(&env, "LIBEXECDIR"), Some("/usr/lib32"));
|
||||||
|
assert_eq!(env_value(&env, "DATAROOTDIR"), Some("/usr/share"));
|
||||||
|
assert_eq!(env_value(&env, "DATADIR"), Some("/usr/share"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_standard_build_env_exports_passthrough_env() {
|
fn test_standard_build_env_exports_passthrough_env() {
|
||||||
let mut spec = mk_spec(Vec::new(), Vec::new());
|
let mut spec = mk_spec(Vec::new(), Vec::new());
|
||||||
@@ -1407,6 +1763,7 @@ mod tests {
|
|||||||
spec.build.flags.env_vars = vec![
|
spec.build.flags.env_vars = vec![
|
||||||
"SETUPTOOLS_SCM_PRETEND_VERSION=$version".into(),
|
"SETUPTOOLS_SCM_PRETEND_VERSION=$version".into(),
|
||||||
"PYO3_CONFIG_FILE=$specdir/pyo3.toml".into(),
|
"PYO3_CONFIG_FILE=$specdir/pyo3.toml".into(),
|
||||||
|
"PKG_CONFIG_PATH=$LIBDIR/pkgconfig".into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let env = standard_build_env(&spec, None, false, true);
|
let env = standard_build_env(&spec, None, false, true);
|
||||||
@@ -1420,6 +1777,11 @@ mod tests {
|
|||||||
.any(|(k, v)| k == "PYO3_CONFIG_FILE" && v == "/tmp/specs/demo/pyo3.toml"),
|
.any(|(k, v)| k == "PYO3_CONFIG_FILE" && v == "/tmp/specs/demo/pyo3.toml"),
|
||||||
"expected env_vars values to expand specdir variables"
|
"expected env_vars values to expand specdir variables"
|
||||||
);
|
);
|
||||||
|
assert!(
|
||||||
|
env.iter()
|
||||||
|
.any(|(k, v)| k == "PKG_CONFIG_PATH" && v == "/usr/lib/pkgconfig"),
|
||||||
|
"expected env_vars values to expand install directory variables"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
+19
-7
@@ -58,7 +58,10 @@ pub fn build(
|
|||||||
configure_cmd.arg("INSTALLDIRS=vendor");
|
configure_cmd.arg("INSTALLDIRS=vendor");
|
||||||
}
|
}
|
||||||
for arg in &flags.configure {
|
for arg in &flags.configure {
|
||||||
configure_cmd.arg(spec.expand_vars(arg));
|
configure_cmd.arg(crate::builder::expand_with_envs(
|
||||||
|
&spec.expand_vars(arg),
|
||||||
|
&env_vars,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
for arg in crate::builder::static_build_args_for(crate::package::BuildType::Perl, flags)? {
|
for arg in crate::builder::static_build_args_for(crate::package::BuildType::Perl, flags)? {
|
||||||
configure_cmd.arg(arg);
|
configure_cmd.arg(arg);
|
||||||
@@ -291,13 +294,19 @@ pub(crate) fn run_helper_configure(
|
|||||||
configure_cmd.arg("INSTALLDIRS=vendor");
|
configure_cmd.arg("INSTALLDIRS=vendor");
|
||||||
}
|
}
|
||||||
for arg in &flags.configure {
|
for arg in &flags.configure {
|
||||||
configure_cmd.arg(context.expand_vars(arg));
|
configure_cmd.arg(crate::builder::expand_with_envs(
|
||||||
|
&context.expand_vars(arg),
|
||||||
|
&helper_env,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
for arg in crate::builder::static_build_args_for(crate::package::BuildType::Perl, &flags)? {
|
for arg in crate::builder::static_build_args_for(crate::package::BuildType::Perl, &flags)? {
|
||||||
configure_cmd.arg(arg);
|
configure_cmd.arg(arg);
|
||||||
}
|
}
|
||||||
for arg in extra_args {
|
for arg in extra_args {
|
||||||
configure_cmd.arg(context.expand_vars(arg));
|
configure_cmd.arg(crate::builder::expand_with_envs(
|
||||||
|
&context.expand_vars(arg),
|
||||||
|
&helper_env,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
crate::builder::prepare_tool_command(&mut configure_cmd, &helper_env);
|
crate::builder::prepare_tool_command(&mut configure_cmd, &helper_env);
|
||||||
|
|
||||||
@@ -350,12 +359,15 @@ pub(crate) fn run_helper_install(
|
|||||||
for target in &install_targets {
|
for target in &install_targets {
|
||||||
install_cmd.arg(target);
|
install_cmd.arg(target);
|
||||||
}
|
}
|
||||||
for arg in extra_args {
|
|
||||||
install_cmd.arg(context.expand_vars(arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut install_env = env_vars.to_vec();
|
let mut install_env = env_vars.to_vec();
|
||||||
crate::builder::set_env_var(&mut install_env, "DESTDIR", destdir.clone());
|
crate::builder::set_env_var(&mut install_env, "DESTDIR", destdir.clone());
|
||||||
|
for arg in extra_args {
|
||||||
|
install_cmd.arg(crate::builder::expand_with_envs(
|
||||||
|
&context.expand_vars(arg),
|
||||||
|
&install_env,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
crate::builder::prepare_tool_command(&mut install_cmd, &install_env);
|
crate::builder::prepare_tool_command(&mut install_cmd, &install_env);
|
||||||
|
|
||||||
let status = command_status_with_sh_fallback(&mut install_cmd).with_context(|| {
|
let status = command_status_with_sh_fallback(&mut install_cmd).with_context(|| {
|
||||||
|
|||||||
+12
-5
@@ -36,7 +36,6 @@ pub fn build(
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let flags = &spec.build.flags;
|
let flags = &spec.build.flags;
|
||||||
let actual_src = resolve_actual_src(spec, src_dir)?;
|
let actual_src = resolve_actual_src(spec, src_dir)?;
|
||||||
let config_settings = normalize_pep517_config_settings(spec)?;
|
|
||||||
fs::create_dir_all(destdir)
|
fs::create_dir_all(destdir)
|
||||||
.with_context(|| format!("Failed to create DESTDIR: {}", destdir.display()))?;
|
.with_context(|| format!("Failed to create DESTDIR: {}", destdir.display()))?;
|
||||||
|
|
||||||
@@ -44,6 +43,7 @@ pub fn build(
|
|||||||
crate::builder::set_env_var(&mut env_vars, "PYTHONNOUSERSITE", "1");
|
crate::builder::set_env_var(&mut env_vars, "PYTHONNOUSERSITE", "1");
|
||||||
crate::builder::set_env_var(&mut env_vars, "PYTHONDONTWRITEBYTECODE", "1");
|
crate::builder::set_env_var(&mut env_vars, "PYTHONDONTWRITEBYTECODE", "1");
|
||||||
crate::builder::set_env_var(&mut env_vars, "SETUPTOOLS_USE_DISTUTILS", "local");
|
crate::builder::set_env_var(&mut env_vars, "SETUPTOOLS_USE_DISTUTILS", "local");
|
||||||
|
let config_settings = normalize_pep517_config_settings(spec, &env_vars)?;
|
||||||
|
|
||||||
let mut state = StateTracker::new_with_namespace(
|
let mut state = StateTracker::new_with_namespace(
|
||||||
&actual_src,
|
&actual_src,
|
||||||
@@ -84,10 +84,13 @@ pub fn build(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn normalize_pep517_config_settings(spec: &PackageSpec) -> Result<Vec<String>> {
|
fn normalize_pep517_config_settings(
|
||||||
|
spec: &PackageSpec,
|
||||||
|
env_vars: &[(String, String)],
|
||||||
|
) -> Result<Vec<String>> {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
for raw in &spec.build.flags.config_settings {
|
for raw in &spec.build.flags.config_settings {
|
||||||
let expanded = spec.expand_vars(raw);
|
let expanded = crate::builder::expand_with_envs(&spec.expand_vars(raw), env_vars);
|
||||||
let trimmed = expanded.trim();
|
let trimmed = expanded.trim();
|
||||||
if trimmed.is_empty() {
|
if trimmed.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
@@ -821,9 +824,11 @@ mod tests {
|
|||||||
"setup-args=--plat-name=x86_64".into(),
|
"setup-args=--plat-name=x86_64".into(),
|
||||||
"builddir".into(),
|
"builddir".into(),
|
||||||
"version=$version".into(),
|
"version=$version".into(),
|
||||||
|
"libdir=$LIBDIR".into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let normalized = normalize_pep517_config_settings(&spec)?;
|
let env_vars = crate::builder::standard_build_env(&spec, None, false, true);
|
||||||
|
let normalized = normalize_pep517_config_settings(&spec, &env_vars)?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
normalized,
|
normalized,
|
||||||
vec![
|
vec![
|
||||||
@@ -831,6 +836,7 @@ mod tests {
|
|||||||
"setup-args=--plat-name=x86_64".to_string(),
|
"setup-args=--plat-name=x86_64".to_string(),
|
||||||
"builddir=".to_string(),
|
"builddir=".to_string(),
|
||||||
"version=1.2.3".to_string(),
|
"version=1.2.3".to_string(),
|
||||||
|
"libdir=/usr/lib".to_string(),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -840,7 +846,8 @@ mod tests {
|
|||||||
fn normalize_pep517_config_settings_rejects_invalid_key() {
|
fn normalize_pep517_config_settings_rejects_invalid_key() {
|
||||||
let mut spec = mk_spec();
|
let mut spec = mk_spec();
|
||||||
spec.build.flags.config_settings = vec!["bad key=value".into()];
|
spec.build.flags.config_settings = vec!["bad key=value".into()];
|
||||||
let err = normalize_pep517_config_settings(&spec)
|
let env_vars = crate::builder::standard_build_env(&spec, None, false, true);
|
||||||
|
let err = normalize_pep517_config_settings(&spec, &env_vars)
|
||||||
.expect_err("invalid config setting key should fail");
|
.expect_err("invalid config setting key should fail");
|
||||||
assert!(err.to_string().contains("expected KEY=VALUE or KEY"));
|
assert!(err.to_string().contains("expected KEY=VALUE or KEY"));
|
||||||
}
|
}
|
||||||
|
|||||||
+75
-1
@@ -250,6 +250,32 @@ pub struct ConfigArgs {
|
|||||||
pub rootfs_args: RootfsArgs,
|
pub rootfs_args: RootfsArgs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Arguments for selecting canonical tool aliases in the configured tool directory.
|
||||||
|
#[derive(Debug, Clone, Args)]
|
||||||
|
pub struct SetArgs {
|
||||||
|
#[command(flatten)]
|
||||||
|
pub rootfs_args: RootfsArgs,
|
||||||
|
|
||||||
|
/// Tool role to configure, such as compiler, linker, or shell.
|
||||||
|
#[arg(value_enum)]
|
||||||
|
pub role: ToolRoleArg,
|
||||||
|
|
||||||
|
/// Literal separator used by commands like `depot set compiler to clang`.
|
||||||
|
#[arg(value_name = "to")]
|
||||||
|
pub connector: String,
|
||||||
|
|
||||||
|
/// Tool implementation to select for the requested role.
|
||||||
|
pub implementation: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tool alias role configurable through `depot set`.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]
|
||||||
|
pub enum ToolRoleArg {
|
||||||
|
Compiler,
|
||||||
|
Linker,
|
||||||
|
Shell,
|
||||||
|
}
|
||||||
|
|
||||||
/// Arguments for Depot system-build state management commands.
|
/// Arguments for Depot system-build state management commands.
|
||||||
#[derive(Debug, Clone, Args)]
|
#[derive(Debug, Clone, Args)]
|
||||||
pub struct SystemArgs {
|
pub struct SystemArgs {
|
||||||
@@ -373,6 +399,8 @@ pub enum Commands {
|
|||||||
Repo(RepoArgs),
|
Repo(RepoArgs),
|
||||||
/// Show current configuration
|
/// Show current configuration
|
||||||
Config(ConfigArgs),
|
Config(ConfigArgs),
|
||||||
|
/// Select canonical tool aliases, e.g. `depot set compiler to clang`
|
||||||
|
Set(SetArgs),
|
||||||
/// Manage system build stage, package layers, and book-style layout state
|
/// Manage system build stage, package layers, and book-style layout state
|
||||||
System(SystemArgs),
|
System(SystemArgs),
|
||||||
/// Generate shell completion scripts and a man page into an output directory.
|
/// Generate shell completion scripts and a man page into an output directory.
|
||||||
@@ -591,7 +619,7 @@ pub enum RepoKindArg {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::{
|
use super::{
|
||||||
BuildArgs, Cli, Commands, ConvertArgs, InstallArgs, RepoArgs, RepoCommands, SearchArgs,
|
BuildArgs, Cli, Commands, ConvertArgs, InstallArgs, RepoArgs, RepoCommands, SearchArgs,
|
||||||
UpdateArgs,
|
SetArgs, ToolRoleArg, UpdateArgs,
|
||||||
};
|
};
|
||||||
use clap::{CommandFactory, Parser};
|
use clap::{CommandFactory, Parser};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -631,6 +659,52 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_accepts_role_to_implementation_form() {
|
||||||
|
let cli = Cli::try_parse_from([
|
||||||
|
"depot",
|
||||||
|
"set",
|
||||||
|
"--rootfs",
|
||||||
|
"/tmp/rootfs",
|
||||||
|
"compiler",
|
||||||
|
"to",
|
||||||
|
"clang",
|
||||||
|
])
|
||||||
|
.unwrap();
|
||||||
|
match cli.command {
|
||||||
|
Commands::Set(SetArgs {
|
||||||
|
rootfs_args,
|
||||||
|
role,
|
||||||
|
connector,
|
||||||
|
implementation,
|
||||||
|
}) => {
|
||||||
|
assert_eq!(rootfs_args.rootfs, PathBuf::from("/tmp/rootfs"));
|
||||||
|
assert_eq!(role, ToolRoleArg::Compiler);
|
||||||
|
assert_eq!(connector, "to");
|
||||||
|
assert_eq!(implementation, "clang");
|
||||||
|
}
|
||||||
|
_ => panic!("expected set command"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_accepts_shell_role() {
|
||||||
|
let cli = Cli::try_parse_from(["depot", "set", "shell", "to", "dash"]).unwrap();
|
||||||
|
match cli.command {
|
||||||
|
Commands::Set(SetArgs {
|
||||||
|
role,
|
||||||
|
connector,
|
||||||
|
implementation,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
assert_eq!(role, ToolRoleArg::Shell);
|
||||||
|
assert_eq!(connector, "to");
|
||||||
|
assert_eq!(implementation, "dash");
|
||||||
|
}
|
||||||
|
_ => panic!("expected set command"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn update_accepts_no_package_names() {
|
fn update_accepts_no_package_names() {
|
||||||
let cli = Cli::try_parse_from(["depot", "update"]).unwrap();
|
let cli = Cli::try_parse_from(["depot", "update"]).unwrap();
|
||||||
|
|||||||
+9
-3
@@ -1,7 +1,7 @@
|
|||||||
use crate::cli::{
|
use crate::cli::{
|
||||||
BuildArgs, Cli, Commands, ConfigArgs, ConvertArgs, InfoArgs, InstallArgs, InternalCommands,
|
BuildArgs, Cli, Commands, ConfigArgs, ConvertArgs, InfoArgs, InstallArgs, InternalCommands,
|
||||||
ListArgs, OwnsArgs, RemoveArgs, RepoCommands, RepoKindArg, SearchArgs, SignArgs, SystemArgs,
|
ListArgs, OwnsArgs, RemoveArgs, RepoCommands, RepoKindArg, SearchArgs, SetArgs, SignArgs,
|
||||||
UpdateArgs,
|
SystemArgs, UpdateArgs,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
bootstrap, builder, cli_assets, config, cross, db, deps, index, install, locking, package,
|
bootstrap, builder, cli_assets, config, cross, db, deps, index, install, locking, package,
|
||||||
@@ -66,7 +66,7 @@ fn rootfs_is_system_root(rootfs: &Path) -> bool {
|
|||||||
fn command_requires_live_root(command: &Commands) -> bool {
|
fn command_requires_live_root(command: &Commands) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
command,
|
command,
|
||||||
Commands::Install(_) | Commands::Remove(_) | Commands::Update(_)
|
Commands::Install(_) | Commands::Remove(_) | Commands::Update(_) | Commands::Set(_)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +100,7 @@ fn command_rootfs(command: &Commands) -> Option<&Path> {
|
|||||||
Commands::Sign(args) => Some(&args.rootfs_args.rootfs),
|
Commands::Sign(args) => Some(&args.rootfs_args.rootfs),
|
||||||
Commands::Repo(args) => Some(repo_command_rootfs(&args.command)),
|
Commands::Repo(args) => Some(repo_command_rootfs(&args.command)),
|
||||||
Commands::Config(args) => Some(&args.rootfs_args.rootfs),
|
Commands::Config(args) => Some(&args.rootfs_args.rootfs),
|
||||||
|
Commands::Set(args) => Some(&args.rootfs_args.rootfs),
|
||||||
Commands::System(args) => Some(&args.rootfs_args.rootfs),
|
Commands::System(args) => Some(&args.rootfs_args.rootfs),
|
||||||
Commands::Check(_)
|
Commands::Check(_)
|
||||||
| Commands::Convert(_)
|
| Commands::Convert(_)
|
||||||
@@ -125,6 +126,7 @@ fn command_assume_yes(command: &Commands) -> bool {
|
|||||||
| Commands::Sign(_)
|
| Commands::Sign(_)
|
||||||
| Commands::Repo(_)
|
| Commands::Repo(_)
|
||||||
| Commands::Config(_)
|
| Commands::Config(_)
|
||||||
|
| Commands::Set(_)
|
||||||
| Commands::System(_)
|
| Commands::System(_)
|
||||||
| Commands::GenerateArtifacts(_)
|
| Commands::GenerateArtifacts(_)
|
||||||
| Commands::MakeSpec(_)
|
| Commands::MakeSpec(_)
|
||||||
@@ -2167,6 +2169,7 @@ fn run_direct_install_request(
|
|||||||
// Install from spec (normal build)
|
// Install from spec (normal build)
|
||||||
let mut pkg_spec = package::PackageSpec::from_file(&spec_path)?;
|
let mut pkg_spec = package::PackageSpec::from_file(&spec_path)?;
|
||||||
pkg_spec.apply_config(config);
|
pkg_spec.apply_config(config);
|
||||||
|
pkg_spec.build.flags.rootfs = build_cmd::build_env_rootfs(options.rootfs);
|
||||||
(pkg_spec, None)
|
(pkg_spec, None)
|
||||||
};
|
};
|
||||||
let built_from_source = staging_dir.is_none();
|
let built_from_source = staging_dir.is_none();
|
||||||
@@ -2567,6 +2570,7 @@ mod check;
|
|||||||
mod install_cmd;
|
mod install_cmd;
|
||||||
mod misc;
|
mod misc;
|
||||||
mod repo;
|
mod repo;
|
||||||
|
mod set;
|
||||||
mod update;
|
mod update;
|
||||||
|
|
||||||
pub fn run(cli: Cli) -> Result<()> {
|
pub fn run(cli: Cli) -> Result<()> {
|
||||||
@@ -2591,6 +2595,7 @@ pub fn run(cli: Cli) -> Result<()> {
|
|||||||
| Commands::Sign(_)
|
| Commands::Sign(_)
|
||||||
| Commands::Repo(_)
|
| Commands::Repo(_)
|
||||||
| Commands::Config(_)
|
| Commands::Config(_)
|
||||||
|
| Commands::Set(_)
|
||||||
| Commands::System(_)
|
| Commands::System(_)
|
||||||
| Commands::GenerateArtifacts(_)
|
| Commands::GenerateArtifacts(_)
|
||||||
| Commands::Convert(_)
|
| Commands::Convert(_)
|
||||||
@@ -2613,6 +2618,7 @@ pub fn run(cli: Cli) -> Result<()> {
|
|||||||
Commands::Repo(args) => repo::run_repo(args.command)?,
|
Commands::Repo(args) => repo::run_repo(args.command)?,
|
||||||
Commands::GenerateArtifacts(args) => misc::run_generate_artifacts(args)?,
|
Commands::GenerateArtifacts(args) => misc::run_generate_artifacts(args)?,
|
||||||
Commands::Config(args) => misc::run_config(args)?,
|
Commands::Config(args) => misc::run_config(args)?,
|
||||||
|
Commands::Set(args) => set::run_set(args)?,
|
||||||
Commands::System(args) => misc::run_system(args)?,
|
Commands::System(args) => misc::run_system(args)?,
|
||||||
Commands::MakeSpec(args) => misc::run_make_spec(args)?,
|
Commands::MakeSpec(args) => misc::run_make_spec(args)?,
|
||||||
Commands::Convert(args) => misc::run_convert(args)?,
|
Commands::Convert(args) => misc::run_convert(args)?,
|
||||||
|
|||||||
@@ -11,6 +11,17 @@ use self::support::{
|
|||||||
requested_outputs, should_install_test_deps, warn_if_running_as_root_for_build,
|
requested_outputs, should_install_test_deps, warn_if_running_as_root_for_build,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub(crate) fn build_env_rootfs(rootfs: &Path) -> String {
|
||||||
|
if rootfs == Path::new("/") {
|
||||||
|
return "/".to_string();
|
||||||
|
}
|
||||||
|
rootfs
|
||||||
|
.canonicalize()
|
||||||
|
.unwrap_or_else(|_| rootfs.to_path_buf())
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned()
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn run_build(args: BuildArgs, cli_test_deps: bool) -> Result<()> {
|
pub(super) fn run_build(args: BuildArgs, cli_test_deps: bool) -> Result<()> {
|
||||||
let BuildArgs {
|
let BuildArgs {
|
||||||
rootfs_args,
|
rootfs_args,
|
||||||
@@ -46,6 +57,7 @@ pub(super) fn run_build(args: BuildArgs, cli_test_deps: bool) -> Result<()> {
|
|||||||
let mut auto_installed_deps = AutoInstalledDependencyTracker::default();
|
let mut auto_installed_deps = AutoInstalledDependencyTracker::default();
|
||||||
let build_result: Result<()> = (|| {
|
let build_result: Result<()> = (|| {
|
||||||
pkg_spec.apply_config(&config);
|
pkg_spec.apply_config(&config);
|
||||||
|
pkg_spec.build.flags.rootfs = build_env_rootfs(&rootfs);
|
||||||
let lib32_only = effective_lib32_only(&pkg_spec, cli_lib32_only);
|
let lib32_only = effective_lib32_only(&pkg_spec, cli_lib32_only);
|
||||||
let requested_outputs = requested_outputs(&pkg_spec, lib32_only);
|
let requested_outputs = requested_outputs(&pkg_spec, lib32_only);
|
||||||
let db_path = config.installed_db_path(&rootfs);
|
let db_path = config.installed_db_path(&rootfs);
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ pub(crate) fn package_spec_from_repo_record(
|
|||||||
runtime: record.runtime_dependencies.clone(),
|
runtime: record.runtime_dependencies.clone(),
|
||||||
test: Vec::new(),
|
test: Vec::new(),
|
||||||
optional: record.optional_dependencies.clone(),
|
optional: record.optional_dependencies.clone(),
|
||||||
groups: Vec::new(),
|
groups: record.groups.clone(),
|
||||||
lib32: None,
|
lib32: None,
|
||||||
},
|
},
|
||||||
package_alternatives: Default::default(),
|
package_alternatives: Default::default(),
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ fn current_process_env_vars() -> Vec<(String, String)> {
|
|||||||
"RUSTLTOFLAGS",
|
"RUSTLTOFLAGS",
|
||||||
"SETUPTOOLS_USE_DISTUTILS",
|
"SETUPTOOLS_USE_DISTUTILS",
|
||||||
"STRIP",
|
"STRIP",
|
||||||
|
"TOOL_DIR",
|
||||||
];
|
];
|
||||||
|
|
||||||
ALLOWED_ENV_VARS
|
ALLOWED_ENV_VARS
|
||||||
|
|||||||
@@ -0,0 +1,434 @@
|
|||||||
|
use super::*;
|
||||||
|
use crate::cli::ToolRoleArg;
|
||||||
|
use std::io::ErrorKind;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
struct ToolAlias {
|
||||||
|
alias: &'static str,
|
||||||
|
target: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn run_set(args: SetArgs) -> Result<()> {
|
||||||
|
let SetArgs {
|
||||||
|
rootfs_args,
|
||||||
|
role,
|
||||||
|
connector,
|
||||||
|
implementation,
|
||||||
|
} = args;
|
||||||
|
|
||||||
|
if connector != "to" {
|
||||||
|
anyhow::bail!("Expected `to` in set command, for example: depot set compiler to clang");
|
||||||
|
}
|
||||||
|
|
||||||
|
let implementation = implementation.trim().to_ascii_lowercase();
|
||||||
|
let aliases = aliases_for_selection(role, &implementation)?;
|
||||||
|
let rootfs = rootfs_args.rootfs;
|
||||||
|
let config = config::Config::for_rootfs(&rootfs);
|
||||||
|
let mut set_lock = locking::open_lock(&config)?;
|
||||||
|
let set_lock_path = locking::lock_path(&config);
|
||||||
|
let _set_lock_guard = locking::try_write(&mut set_lock, &set_lock_path, "set")?;
|
||||||
|
let alias_dir = configured_alias_dir(&config);
|
||||||
|
let host_alias_dir = dir_in_rootfs(&rootfs, &alias_dir);
|
||||||
|
|
||||||
|
configure_tool_aliases(&host_alias_dir, &aliases).with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Failed to set {} to {} in {}",
|
||||||
|
role_name(role),
|
||||||
|
implementation,
|
||||||
|
host_alias_dir.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
ui::success(format!(
|
||||||
|
"Set {} to {} in {}",
|
||||||
|
role_name(role),
|
||||||
|
implementation,
|
||||||
|
host_alias_dir.display()
|
||||||
|
));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn role_name(role: ToolRoleArg) -> &'static str {
|
||||||
|
match role {
|
||||||
|
ToolRoleArg::Compiler => "compiler",
|
||||||
|
ToolRoleArg::Linker => "linker",
|
||||||
|
ToolRoleArg::Shell => "shell",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configured_alias_dir(config: &config::Config) -> PathBuf {
|
||||||
|
let configured = config
|
||||||
|
.build_overrides
|
||||||
|
.get("flags")
|
||||||
|
.and_then(|flags| flags.get("bindir"))
|
||||||
|
.or_else(|| config.build_overrides.get("bindir"))
|
||||||
|
.and_then(|value| value.as_str())
|
||||||
|
.map(str::trim)
|
||||||
|
.filter(|value| !value.is_empty())
|
||||||
|
.unwrap_or("/system/binaries");
|
||||||
|
PathBuf::from(configured)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dir_in_rootfs(rootfs: &Path, dir: &Path) -> PathBuf {
|
||||||
|
let rootfs = resolve_rootfs_base(rootfs);
|
||||||
|
if dir.is_absolute() && dir.starts_with(&rootfs) {
|
||||||
|
dir.to_path_buf()
|
||||||
|
} else if dir.is_absolute() {
|
||||||
|
rootfs.join(dir.strip_prefix("/").unwrap_or(dir))
|
||||||
|
} else {
|
||||||
|
rootfs.join(dir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_rootfs_base(rootfs: &Path) -> PathBuf {
|
||||||
|
if rootfs.exists() {
|
||||||
|
rootfs.canonicalize().unwrap_or_else(|_| {
|
||||||
|
std::env::current_dir()
|
||||||
|
.map(|cwd| cwd.join(rootfs))
|
||||||
|
.unwrap_or_else(|_| rootfs.to_path_buf())
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
std::env::current_dir()
|
||||||
|
.map(|cwd| cwd.join(rootfs))
|
||||||
|
.unwrap_or_else(|_| rootfs.to_path_buf())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn aliases_for_selection(role: ToolRoleArg, implementation: &str) -> Result<Vec<ToolAlias>> {
|
||||||
|
let aliases = match (role, implementation) {
|
||||||
|
(ToolRoleArg::Compiler, "clang") => vec![
|
||||||
|
ToolAlias {
|
||||||
|
alias: "cc",
|
||||||
|
target: "clang",
|
||||||
|
},
|
||||||
|
ToolAlias {
|
||||||
|
alias: "c++",
|
||||||
|
target: "clang++",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
(ToolRoleArg::Compiler, "gcc") => vec![
|
||||||
|
ToolAlias {
|
||||||
|
alias: "cc",
|
||||||
|
target: "gcc",
|
||||||
|
},
|
||||||
|
ToolAlias {
|
||||||
|
alias: "c++",
|
||||||
|
target: "g++",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
(ToolRoleArg::Linker, "lld" | "ld.lld") => vec![ToolAlias {
|
||||||
|
alias: "ld",
|
||||||
|
target: "ld.lld",
|
||||||
|
}],
|
||||||
|
(ToolRoleArg::Linker, "mold") => vec![ToolAlias {
|
||||||
|
alias: "ld",
|
||||||
|
target: "mold",
|
||||||
|
}],
|
||||||
|
(ToolRoleArg::Shell, "bash") => vec![ToolAlias {
|
||||||
|
alias: "sh",
|
||||||
|
target: "bash",
|
||||||
|
}],
|
||||||
|
(ToolRoleArg::Shell, "dash") => vec![ToolAlias {
|
||||||
|
alias: "sh",
|
||||||
|
target: "dash",
|
||||||
|
}],
|
||||||
|
(ToolRoleArg::Shell, "zsh") => vec![ToolAlias {
|
||||||
|
alias: "sh",
|
||||||
|
target: "zsh",
|
||||||
|
}],
|
||||||
|
(ToolRoleArg::Compiler, _) => {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Unsupported compiler selection `{implementation}`; supported: clang, gcc"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(ToolRoleArg::Linker, _) => {
|
||||||
|
anyhow::bail!("Unsupported linker selection `{implementation}`; supported: lld, mold")
|
||||||
|
}
|
||||||
|
(ToolRoleArg::Shell, _) => {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Unsupported shell selection `{implementation}`; supported: bash, dash, zsh"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(aliases)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn configure_tool_aliases(tool_dir: &Path, aliases: &[ToolAlias]) -> Result<()> {
|
||||||
|
use std::os::unix::fs as unix_fs;
|
||||||
|
|
||||||
|
for alias in aliases {
|
||||||
|
validate_tool_name("alias", alias.alias)?;
|
||||||
|
validate_tool_name("target", alias.target)?;
|
||||||
|
let target_path = tool_dir.join(alias.target);
|
||||||
|
match fs::metadata(&target_path) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) if err.kind() == ErrorKind::NotFound => {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Cannot set {} to {}; target tool is missing: {}",
|
||||||
|
alias.alias,
|
||||||
|
alias.target,
|
||||||
|
target_path.display()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
return Err(err)
|
||||||
|
.with_context(|| format!("Failed to inspect {}", target_path.display()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let alias_path = tool_dir.join(alias.alias);
|
||||||
|
match fs::symlink_metadata(&alias_path) {
|
||||||
|
Ok(metadata) if metadata.file_type().is_symlink() => {
|
||||||
|
let current = fs::read_link(&alias_path)
|
||||||
|
.with_context(|| format!("Failed to read symlink {}", alias_path.display()))?;
|
||||||
|
if current == Path::new(alias.target) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fs::remove_file(&alias_path)
|
||||||
|
.with_context(|| format!("Failed to replace {}", alias_path.display()))?;
|
||||||
|
}
|
||||||
|
Ok(_) => {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Refusing to replace non-symlink tool alias: {}",
|
||||||
|
alias_path.display()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) if err.kind() == ErrorKind::NotFound => {}
|
||||||
|
Err(err) => {
|
||||||
|
return Err(err)
|
||||||
|
.with_context(|| format!("Failed to inspect {}", alias_path.display()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unix_fs::symlink(alias.target, &alias_path)
|
||||||
|
.with_context(|| format!("Failed to create symlink {}", alias_path.display()))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
fn configure_tool_aliases(_tool_dir: &Path, _aliases: &[ToolAlias]) -> Result<()> {
|
||||||
|
anyhow::bail!("depot set requires Unix symlink support")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_tool_name(kind: &str, name: &str) -> Result<()> {
|
||||||
|
if name.is_empty() || name.contains('/') || name.contains('\0') {
|
||||||
|
anyhow::bail!("Invalid tool {kind}: {name:?}");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::cli::{RootfsArgs, ToolRoleArg};
|
||||||
|
|
||||||
|
fn set_args(rootfs: &Path, role: ToolRoleArg, implementation: &str) -> SetArgs {
|
||||||
|
SetArgs {
|
||||||
|
rootfs_args: RootfsArgs {
|
||||||
|
rootfs: rootfs.to_path_buf(),
|
||||||
|
},
|
||||||
|
role,
|
||||||
|
connector: "to".into(),
|
||||||
|
implementation: implementation.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_tool_dir(rootfs: &Path) -> PathBuf {
|
||||||
|
let etc = rootfs.join("etc/depot.d");
|
||||||
|
fs::create_dir_all(&etc).unwrap();
|
||||||
|
fs::write(
|
||||||
|
etc.join("build.toml"),
|
||||||
|
r#"
|
||||||
|
[flags]
|
||||||
|
tool_dir = "/system/tools/bin"
|
||||||
|
bindir = "/system/binaries"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let tool_dir = rootfs.join("system/binaries");
|
||||||
|
fs::create_dir_all(&tool_dir).unwrap();
|
||||||
|
tool_dir
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn configured_alias_dir_prefers_bindir_over_tool_dir() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
make_tool_dir(tmp.path());
|
||||||
|
let config = config::Config::for_rootfs(tmp.path());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
configured_alias_dir(&config),
|
||||||
|
PathBuf::from("/system/binaries")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dir_in_rootfs_does_not_duplicate_host_absolute_rootfs_paths() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let rootfs = tmp.path().canonicalize().unwrap();
|
||||||
|
let host_dir = rootfs.join("system/binaries");
|
||||||
|
|
||||||
|
assert_eq!(dir_in_rootfs(&rootfs, &host_dir), host_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compiler_selection_maps_aliases() {
|
||||||
|
assert_eq!(
|
||||||
|
aliases_for_selection(ToolRoleArg::Compiler, "clang").unwrap(),
|
||||||
|
vec![
|
||||||
|
ToolAlias {
|
||||||
|
alias: "cc",
|
||||||
|
target: "clang"
|
||||||
|
},
|
||||||
|
ToolAlias {
|
||||||
|
alias: "c++",
|
||||||
|
target: "clang++"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
aliases_for_selection(ToolRoleArg::Compiler, "gcc").unwrap(),
|
||||||
|
vec![
|
||||||
|
ToolAlias {
|
||||||
|
alias: "cc",
|
||||||
|
target: "gcc"
|
||||||
|
},
|
||||||
|
ToolAlias {
|
||||||
|
alias: "c++",
|
||||||
|
target: "g++"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn linker_selection_maps_aliases() {
|
||||||
|
assert_eq!(
|
||||||
|
aliases_for_selection(ToolRoleArg::Linker, "lld").unwrap(),
|
||||||
|
vec![ToolAlias {
|
||||||
|
alias: "ld",
|
||||||
|
target: "ld.lld"
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
aliases_for_selection(ToolRoleArg::Linker, "mold").unwrap(),
|
||||||
|
vec![ToolAlias {
|
||||||
|
alias: "ld",
|
||||||
|
target: "mold"
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shell_selection_maps_aliases() {
|
||||||
|
for shell in ["bash", "dash", "zsh"] {
|
||||||
|
assert_eq!(
|
||||||
|
aliases_for_selection(ToolRoleArg::Shell, shell).unwrap(),
|
||||||
|
vec![ToolAlias {
|
||||||
|
alias: "sh",
|
||||||
|
target: shell
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[test]
|
||||||
|
fn run_set_switches_compiler_aliases() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let tool_dir = make_tool_dir(tmp.path());
|
||||||
|
fs::write(tool_dir.join("clang"), "").unwrap();
|
||||||
|
fs::write(tool_dir.join("clang++"), "").unwrap();
|
||||||
|
fs::write(tool_dir.join("gcc"), "").unwrap();
|
||||||
|
fs::write(tool_dir.join("g++"), "").unwrap();
|
||||||
|
|
||||||
|
run_set(set_args(tmp.path(), ToolRoleArg::Compiler, "clang")).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
fs::read_link(tool_dir.join("cc")).unwrap(),
|
||||||
|
PathBuf::from("clang")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
fs::read_link(tool_dir.join("c++")).unwrap(),
|
||||||
|
PathBuf::from("clang++")
|
||||||
|
);
|
||||||
|
|
||||||
|
run_set(set_args(tmp.path(), ToolRoleArg::Compiler, "gcc")).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
fs::read_link(tool_dir.join("cc")).unwrap(),
|
||||||
|
PathBuf::from("gcc")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
fs::read_link(tool_dir.join("c++")).unwrap(),
|
||||||
|
PathBuf::from("g++")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[test]
|
||||||
|
fn run_set_switches_linker_alias() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let tool_dir = make_tool_dir(tmp.path());
|
||||||
|
fs::write(tool_dir.join("ld.lld"), "").unwrap();
|
||||||
|
fs::write(tool_dir.join("mold"), "").unwrap();
|
||||||
|
|
||||||
|
run_set(set_args(tmp.path(), ToolRoleArg::Linker, "lld")).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
fs::read_link(tool_dir.join("ld")).unwrap(),
|
||||||
|
PathBuf::from("ld.lld")
|
||||||
|
);
|
||||||
|
|
||||||
|
run_set(set_args(tmp.path(), ToolRoleArg::Linker, "mold")).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
fs::read_link(tool_dir.join("ld")).unwrap(),
|
||||||
|
PathBuf::from("mold")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[test]
|
||||||
|
fn run_set_switches_shell_alias() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let tool_dir = make_tool_dir(tmp.path());
|
||||||
|
fs::write(tool_dir.join("dash"), "").unwrap();
|
||||||
|
fs::write(tool_dir.join("zsh"), "").unwrap();
|
||||||
|
fs::write(tool_dir.join("bash"), "").unwrap();
|
||||||
|
|
||||||
|
run_set(set_args(tmp.path(), ToolRoleArg::Shell, "dash")).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
fs::read_link(tool_dir.join("sh")).unwrap(),
|
||||||
|
PathBuf::from("dash")
|
||||||
|
);
|
||||||
|
|
||||||
|
run_set(set_args(tmp.path(), ToolRoleArg::Shell, "zsh")).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
fs::read_link(tool_dir.join("sh")).unwrap(),
|
||||||
|
PathBuf::from("zsh")
|
||||||
|
);
|
||||||
|
|
||||||
|
run_set(set_args(tmp.path(), ToolRoleArg::Shell, "bash")).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
fs::read_link(tool_dir.join("sh")).unwrap(),
|
||||||
|
PathBuf::from("bash")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[test]
|
||||||
|
fn run_set_refuses_to_replace_real_tool_alias() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let tool_dir = make_tool_dir(tmp.path());
|
||||||
|
fs::write(tool_dir.join("clang"), "").unwrap();
|
||||||
|
fs::write(tool_dir.join("clang++"), "").unwrap();
|
||||||
|
fs::write(tool_dir.join("cc"), "real binary").unwrap();
|
||||||
|
|
||||||
|
let err = run_set(set_args(tmp.path(), ToolRoleArg::Compiler, "clang")).unwrap_err();
|
||||||
|
assert!(err.to_string().contains("Failed to set compiler to clang"));
|
||||||
|
assert!(err.chain().any(|cause| {
|
||||||
|
cause
|
||||||
|
.to_string()
|
||||||
|
.contains("Refusing to replace non-symlink")
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
+85
-1
@@ -41,6 +41,90 @@ fn lib32_args() -> Lib32Args {
|
|||||||
Lib32Args { lib32_only: false }
|
Lib32Args { lib32_only: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_env_rootfs_uses_selected_non_live_rootfs() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let expected = tmp.path().canonicalize().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
build_cmd::build_env_rootfs(tmp.path()),
|
||||||
|
expected.to_string_lossy()
|
||||||
|
);
|
||||||
|
assert_eq!(build_cmd::build_env_rootfs(Path::new("/")), "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn install_post_extract_env_uses_selected_non_live_rootfs() -> Result<()> {
|
||||||
|
let _guard = assume_yes_test_lock();
|
||||||
|
let temp = tempfile::tempdir().context("Failed to create temp dir")?;
|
||||||
|
let rootfs = temp.path().join("rootfs");
|
||||||
|
let spec_dir = temp.path().join("packages").join("demo");
|
||||||
|
let source_dir = temp.path().join("source").join("demo-1.0.0");
|
||||||
|
let observed_env = temp.path().join("post-extract-rootfs.txt");
|
||||||
|
fs::create_dir_all(&rootfs)?;
|
||||||
|
fs::create_dir_all(&spec_dir)?;
|
||||||
|
fs::create_dir_all(&source_dir)?;
|
||||||
|
fs::write(source_dir.join("README"), "demo source")?;
|
||||||
|
fs::write(
|
||||||
|
spec_dir.join("build.sh"),
|
||||||
|
"mkdir -p \"$DESTDIR/usr/bin\"\nprintf demo > \"$DESTDIR/usr/bin/demo\"\n",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let spec_path = spec_dir.join("demo.toml");
|
||||||
|
fs::write(
|
||||||
|
&spec_path,
|
||||||
|
format!(
|
||||||
|
r#"[package]
|
||||||
|
name = "demo"
|
||||||
|
version = "1.0.0"
|
||||||
|
revision = 1
|
||||||
|
description = "demo"
|
||||||
|
homepage = "https://example.test/demo"
|
||||||
|
license = "MIT"
|
||||||
|
|
||||||
|
[[source]]
|
||||||
|
url = "file://{}"
|
||||||
|
sha256 = "skip"
|
||||||
|
extract_dir = "demo-1.0.0"
|
||||||
|
post_extract = ["printf '%s' \"$DEPOT_ROOTFS\" > '{}'"]
|
||||||
|
|
||||||
|
[build]
|
||||||
|
type = "custom"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
build = []
|
||||||
|
runtime = []
|
||||||
|
optional = []
|
||||||
|
"#,
|
||||||
|
source_dir.display(),
|
||||||
|
observed_env.display()
|
||||||
|
),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let config = config::Config::for_rootfs(&rootfs);
|
||||||
|
register_required_development_package_if_configured(&config, &rootfs)?;
|
||||||
|
|
||||||
|
run(Cli {
|
||||||
|
command: Commands::Install(InstallArgs {
|
||||||
|
rootfs_args: rootfs_args(rootfs.clone()),
|
||||||
|
prompt_args: prompt_args(true),
|
||||||
|
build_exec_args: BuildExecArgs {
|
||||||
|
no_deps: true,
|
||||||
|
..build_exec_args()
|
||||||
|
},
|
||||||
|
lib32_args: lib32_args(),
|
||||||
|
spec_or_archive: vec![spec_path],
|
||||||
|
spec: None,
|
||||||
|
}),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
fs::read_to_string(&observed_env)?,
|
||||||
|
build_cmd::build_env_rootfs(&rootfs)
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn test_binary_repo_record(name: &str, filename: &str) -> db::repo::BinaryRepoPackageRecord {
|
fn test_binary_repo_record(name: &str, filename: &str) -> db::repo::BinaryRepoPackageRecord {
|
||||||
db::repo::BinaryRepoPackageRecord {
|
db::repo::BinaryRepoPackageRecord {
|
||||||
repo_name: "core".into(),
|
repo_name: "core".into(),
|
||||||
@@ -378,7 +462,7 @@ fn binary_install_path_uses_repo_record_metadata_without_archive_metadata() -> R
|
|||||||
assert_eq!(installed[0].package.name, "pkg");
|
assert_eq!(installed[0].package.name, "pkg");
|
||||||
assert!(rootfs.path().join("usr/bin/hello").exists());
|
assert!(rootfs.path().join("usr/bin/hello").exists());
|
||||||
|
|
||||||
let db_path = cfg.db_dir.join("packages.db");
|
let db_path = cfg.installed_db_path(rootfs.path());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db::get_package_version(&db_path, "pkg")?,
|
db::get_package_version(&db_path, "pkg")?,
|
||||||
Some("1.0".into())
|
Some("1.0".into())
|
||||||
|
|||||||
+31
-9
@@ -269,11 +269,16 @@ impl Config {
|
|||||||
home.join(".local/share/depot"),
|
home.join(".local/share/depot"),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
let variable_root = if is_system_root {
|
||||||
|
abs_rootfs.join("var")
|
||||||
|
} else {
|
||||||
|
abs_rootfs.join("system/variable")
|
||||||
|
};
|
||||||
(
|
(
|
||||||
abs_rootfs.join("var/cache/depot/sources"),
|
variable_root.join("cache/depot/sources"),
|
||||||
abs_rootfs.join("var/cache/depot/packages"),
|
variable_root.join("cache/depot/packages"),
|
||||||
abs_rootfs.join("var/cache/depot/build"),
|
variable_root.join("cache/depot/build"),
|
||||||
abs_rootfs.join("var/lib/depot"),
|
variable_root.join("lib/depot"),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -307,7 +312,11 @@ impl Config {
|
|||||||
/// to per-user directories under `$HOME`.
|
/// to per-user directories under `$HOME`.
|
||||||
pub fn installed_db_path(&self, rootfs: &Path) -> PathBuf {
|
pub fn installed_db_path(&self, rootfs: &Path) -> PathBuf {
|
||||||
let abs_rootfs = resolve_rootfs_base(rootfs);
|
let abs_rootfs = resolve_rootfs_base(rootfs);
|
||||||
abs_rootfs.join("var/lib/depot/packages.db")
|
if abs_rootfs == Path::new("/") || abs_rootfs.as_os_str() == "/" {
|
||||||
|
abs_rootfs.join("var/lib/depot/packages.db")
|
||||||
|
} else {
|
||||||
|
abs_rootfs.join("system/variable/lib/depot/packages.db")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load system-level and user-level overrides
|
/// Load system-level and user-level overrides
|
||||||
@@ -592,15 +601,20 @@ mod tests {
|
|||||||
config
|
config
|
||||||
.cache_dir
|
.cache_dir
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.contains("var/cache/depot/sources")
|
.contains("system/variable/cache/depot/sources")
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
config
|
config
|
||||||
.build_dir
|
.build_dir
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.contains("var/cache/depot/build")
|
.contains("system/variable/cache/depot/build")
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
config
|
||||||
|
.db_dir
|
||||||
|
.to_string_lossy()
|
||||||
|
.contains("system/variable/lib/depot")
|
||||||
);
|
);
|
||||||
assert!(config.db_dir.to_string_lossy().contains("var/lib/depot"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -713,7 +727,7 @@ cflags += ["-g"]
|
|||||||
let config = Config::for_rootfs(&root);
|
let config = Config::for_rootfs(&root);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.installed_db_path(&root),
|
config.installed_db_path(&root),
|
||||||
PathBuf::from("/tmp/test_root/var/lib/depot/packages.db")
|
PathBuf::from("/tmp/test_root/system/variable/lib/depot/packages.db")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -738,6 +752,7 @@ cflags += ["-g"]
|
|||||||
r#"
|
r#"
|
||||||
[build]
|
[build]
|
||||||
prefix = "/opt/depot"
|
prefix = "/opt/depot"
|
||||||
|
tool_dir = "/opt/toolchain/bin"
|
||||||
cc = "clang"
|
cc = "clang"
|
||||||
|
|
||||||
[build.flags]
|
[build.flags]
|
||||||
@@ -763,6 +778,13 @@ test_deps = true
|
|||||||
config.build_overrides.get("cc").and_then(|v| v.as_str()),
|
config.build_overrides.get("cc").and_then(|v| v.as_str()),
|
||||||
Some("clang")
|
Some("clang")
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
config
|
||||||
|
.build_overrides
|
||||||
|
.get("tool_dir")
|
||||||
|
.and_then(|v| v.as_str()),
|
||||||
|
Some("/opt/toolchain/bin")
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config
|
config
|
||||||
.build_overrides
|
.build_overrides
|
||||||
|
|||||||
@@ -1014,6 +1014,12 @@ pub fn spec_to_minimal_toml(spec: &PackageSpec) -> anyhow::Result<String> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if !spec.build.flags.fuse_ld.is_empty() {
|
||||||
|
flags_tbl.insert(
|
||||||
|
"fuse_ld".into(),
|
||||||
|
Value::String(spec.build.flags.fuse_ld.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
if !spec.build.flags.ltoflags.is_empty() {
|
if !spec.build.flags.ltoflags.is_empty() {
|
||||||
flags_tbl.insert(
|
flags_tbl.insert(
|
||||||
"ltoflags".into(),
|
"ltoflags".into(),
|
||||||
@@ -1114,6 +1120,45 @@ pub fn spec_to_minimal_toml(spec: &PackageSpec) -> anyhow::Result<String> {
|
|||||||
if spec.build.flags.ar != defaults.ar {
|
if spec.build.flags.ar != defaults.ar {
|
||||||
flags_tbl.insert("ar".into(), Value::String(spec.build.flags.ar.clone()));
|
flags_tbl.insert("ar".into(), Value::String(spec.build.flags.ar.clone()));
|
||||||
}
|
}
|
||||||
|
if !spec.build.flags.ranlib.is_empty() {
|
||||||
|
flags_tbl.insert(
|
||||||
|
"ranlib".into(),
|
||||||
|
Value::String(spec.build.flags.ranlib.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if !spec.build.flags.strip.is_empty() {
|
||||||
|
flags_tbl.insert(
|
||||||
|
"strip".into(),
|
||||||
|
Value::String(spec.build.flags.strip.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if !spec.build.flags.ld.is_empty() {
|
||||||
|
flags_tbl.insert("ld".into(), Value::String(spec.build.flags.ld.clone()));
|
||||||
|
}
|
||||||
|
if !spec.build.flags.nm.is_empty() {
|
||||||
|
flags_tbl.insert("nm".into(), Value::String(spec.build.flags.nm.clone()));
|
||||||
|
}
|
||||||
|
if !spec.build.flags.objcopy.is_empty() {
|
||||||
|
flags_tbl.insert(
|
||||||
|
"objcopy".into(),
|
||||||
|
Value::String(spec.build.flags.objcopy.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if !spec.build.flags.objdump.is_empty() {
|
||||||
|
flags_tbl.insert(
|
||||||
|
"objdump".into(),
|
||||||
|
Value::String(spec.build.flags.objdump.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if !spec.build.flags.readelf.is_empty() {
|
||||||
|
flags_tbl.insert(
|
||||||
|
"readelf".into(),
|
||||||
|
Value::String(spec.build.flags.readelf.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if !spec.build.flags.cpp.is_empty() {
|
||||||
|
flags_tbl.insert("cpp".into(), Value::String(spec.build.flags.cpp.clone()));
|
||||||
|
}
|
||||||
if !spec.build.flags.libc.is_empty() {
|
if !spec.build.flags.libc.is_empty() {
|
||||||
flags_tbl.insert("libc".into(), Value::String(spec.build.flags.libc.clone()));
|
flags_tbl.insert("libc".into(), Value::String(spec.build.flags.libc.clone()));
|
||||||
}
|
}
|
||||||
@@ -1849,6 +1894,7 @@ mod tests {
|
|||||||
config_settings: vec!["editable_mode=compat".into()],
|
config_settings: vec!["editable_mode=compat".into()],
|
||||||
rustflags: vec!["-Ctarget-cpu=native".into()],
|
rustflags: vec!["-Ctarget-cpu=native".into()],
|
||||||
cxxflags: vec!["-O2".into(), "-fno-rtti".into()],
|
cxxflags: vec!["-O2".into(), "-fno-rtti".into()],
|
||||||
|
fuse_ld: "lld".into(),
|
||||||
ltoflags: vec!["-flto=auto".into()],
|
ltoflags: vec!["-flto=auto".into()],
|
||||||
target: "x86_64-unknown-linux-gnu".into(),
|
target: "x86_64-unknown-linux-gnu".into(),
|
||||||
keep: vec!["etc/locale.gen".into()],
|
keep: vec!["etc/locale.gen".into()],
|
||||||
@@ -1928,6 +1974,7 @@ mod tests {
|
|||||||
assert!(toml.contains("config_setting = ["));
|
assert!(toml.contains("config_setting = ["));
|
||||||
assert!(toml.contains("rustflags = ["));
|
assert!(toml.contains("rustflags = ["));
|
||||||
assert!(toml.contains("cxxflags = ["));
|
assert!(toml.contains("cxxflags = ["));
|
||||||
|
assert!(toml.contains("fuse_ld = \"lld\""));
|
||||||
assert!(toml.contains("ltoflags = ["));
|
assert!(toml.contains("ltoflags = ["));
|
||||||
assert!(toml.contains("target = \"x86_64-unknown-linux-gnu\""));
|
assert!(toml.contains("target = \"x86_64-unknown-linux-gnu\""));
|
||||||
assert!(toml.contains("keep = ["));
|
assert!(toml.contains("keep = ["));
|
||||||
|
|||||||
+313
-63
@@ -368,7 +368,16 @@ impl PackageSpec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn apply_default_string(target: &mut String, default: &str, value: &toml::Value) {
|
||||||
|
if let Some(s) = value.as_str()
|
||||||
|
&& (target.trim().is_empty() || target == default)
|
||||||
|
{
|
||||||
|
*target = s.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn apply_flags_table(&mut self, table: &toml::map::Map<String, toml::Value>) {
|
fn apply_flags_table(&mut self, table: &toml::map::Map<String, toml::Value>) {
|
||||||
|
let default_flags = BuildFlags::default();
|
||||||
for (k, v) in table {
|
for (k, v) in table {
|
||||||
// match case-insensitively for common keys (allow CXX/Cc etc.)
|
// match case-insensitively for common keys (allow CXX/Cc etc.)
|
||||||
match k.to_lowercase().as_str() {
|
match k.to_lowercase().as_str() {
|
||||||
@@ -471,6 +480,20 @@ impl PackageSpec {
|
|||||||
self.build.flags.ldflags = vec![s.to_string()];
|
self.build.flags.ldflags = vec![s.to_string()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"fuse_ld" | "fuse-ld" => {
|
||||||
|
Self::apply_default_string(
|
||||||
|
&mut self.build.flags.fuse_ld,
|
||||||
|
&default_flags.fuse_ld,
|
||||||
|
v,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
"tool_dir" | "tool-dir" | "tools_dir" | "tools-dir" => {
|
||||||
|
Self::apply_default_string(
|
||||||
|
&mut self.build.flags.tool_dir,
|
||||||
|
&default_flags.tool_dir,
|
||||||
|
v,
|
||||||
|
);
|
||||||
|
}
|
||||||
"replace_ldflags" | "replace-ldflags" => {
|
"replace_ldflags" | "replace-ldflags" => {
|
||||||
if let Some(arr) = v.as_array() {
|
if let Some(arr) = v.as_array() {
|
||||||
self.build.flags.replace_ldflags = arr
|
self.build.flags.replace_ldflags = arr
|
||||||
@@ -565,109 +588,169 @@ impl PackageSpec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"cc" => {
|
"cc" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(&mut self.build.flags.cc, &default_flags.cc, v);
|
||||||
self.build.flags.cc = s.to_string();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"cxx" => {
|
"cxx" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(&mut self.build.flags.cxx, &default_flags.cxx, v);
|
||||||
self.build.flags.cxx = s.to_string();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"ar" => {
|
"ar" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(&mut self.build.flags.ar, &default_flags.ar, v);
|
||||||
self.build.flags.ar = s.to_string();
|
}
|
||||||
}
|
"ranlib" => {
|
||||||
|
Self::apply_default_string(
|
||||||
|
&mut self.build.flags.ranlib,
|
||||||
|
&default_flags.ranlib,
|
||||||
|
v,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
"strip" => {
|
||||||
|
Self::apply_default_string(
|
||||||
|
&mut self.build.flags.strip,
|
||||||
|
&default_flags.strip,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"ld" => {
|
"ld" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(&mut self.build.flags.ld, &default_flags.ld, v);
|
||||||
self.build.flags.ld = s.to_string();
|
}
|
||||||
}
|
"nm" => {
|
||||||
|
Self::apply_default_string(&mut self.build.flags.nm, &default_flags.nm, v);
|
||||||
|
}
|
||||||
|
"objcopy" => {
|
||||||
|
Self::apply_default_string(
|
||||||
|
&mut self.build.flags.objcopy,
|
||||||
|
&default_flags.objcopy,
|
||||||
|
v,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
"objdump" => {
|
||||||
|
Self::apply_default_string(
|
||||||
|
&mut self.build.flags.objdump,
|
||||||
|
&default_flags.objdump,
|
||||||
|
v,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
"readelf" => {
|
||||||
|
Self::apply_default_string(
|
||||||
|
&mut self.build.flags.readelf,
|
||||||
|
&default_flags.readelf,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"cpp" => {
|
"cpp" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(&mut self.build.flags.cpp, &default_flags.cpp, v);
|
||||||
self.build.flags.cpp = s.to_string();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"prefix" => {
|
"prefix" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.prefix = s.to_string();
|
&mut self.build.flags.prefix,
|
||||||
}
|
&default_flags.prefix,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"bindir" => {
|
"bindir" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.bindir = s.to_string();
|
&mut self.build.flags.bindir,
|
||||||
}
|
&default_flags.bindir,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"sbindir" => {
|
"sbindir" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.sbindir = s.to_string();
|
&mut self.build.flags.sbindir,
|
||||||
}
|
&default_flags.sbindir,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"libdir" => {
|
"libdir" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.libdir = s.to_string();
|
&mut self.build.flags.libdir,
|
||||||
}
|
&default_flags.libdir,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"libexecdir" => {
|
"libexecdir" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.libexecdir = s.to_string();
|
&mut self.build.flags.libexecdir,
|
||||||
}
|
&default_flags.libexecdir,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"sysconfdir" => {
|
"sysconfdir" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.sysconfdir = s.to_string();
|
&mut self.build.flags.sysconfdir,
|
||||||
}
|
&default_flags.sysconfdir,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"localstatedir" => {
|
"localstatedir" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.localstatedir = s.to_string();
|
&mut self.build.flags.localstatedir,
|
||||||
}
|
&default_flags.localstatedir,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"sharedstatedir" => {
|
"sharedstatedir" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.sharedstatedir = s.to_string();
|
&mut self.build.flags.sharedstatedir,
|
||||||
}
|
&default_flags.sharedstatedir,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"includedir" => {
|
"includedir" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.includedir = s.to_string();
|
&mut self.build.flags.includedir,
|
||||||
}
|
&default_flags.includedir,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"datarootdir" => {
|
"datarootdir" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.datarootdir = s.to_string();
|
&mut self.build.flags.datarootdir,
|
||||||
}
|
&default_flags.datarootdir,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"datadir" => {
|
"datadir" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.datadir = s.to_string();
|
&mut self.build.flags.datadir,
|
||||||
}
|
&default_flags.datadir,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"mandir" => {
|
"mandir" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.mandir = s.to_string();
|
&mut self.build.flags.mandir,
|
||||||
}
|
&default_flags.mandir,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"infodir" => {
|
"infodir" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.infodir = s.to_string();
|
&mut self.build.flags.infodir,
|
||||||
}
|
&default_flags.infodir,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"chost" => {
|
"chost" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.chost = s.to_string();
|
&mut self.build.flags.chost,
|
||||||
}
|
&default_flags.chost,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"cbuild" => {
|
"cbuild" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.cbuild = s.to_string();
|
&mut self.build.flags.cbuild,
|
||||||
}
|
&default_flags.cbuild,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"carch" => {
|
"carch" => {
|
||||||
if let Some(s) = v.as_str() {
|
Self::apply_default_string(
|
||||||
self.build.flags.carch = s.to_string();
|
&mut self.build.flags.carch,
|
||||||
}
|
&default_flags.carch,
|
||||||
|
v,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
"makeflags" | "make_flags" | "make-flags" => {
|
"makeflags" | "make_flags" | "make-flags" => {
|
||||||
if let Some(s) = v.as_str() {
|
if let Some(s) = v.as_str() {
|
||||||
@@ -1318,16 +1401,51 @@ impl PackageSpec {
|
|||||||
self.build.flags.cc = s.to_string();
|
self.build.flags.cc = s.to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"cxx" => {
|
||||||
|
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
||||||
|
self.build.flags.cxx = s.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
"ar" => {
|
"ar" => {
|
||||||
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
||||||
self.build.flags.ar = s.to_string();
|
self.build.flags.ar = s.to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"ranlib" => {
|
||||||
|
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
||||||
|
self.build.flags.ranlib = s.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"strip" => {
|
||||||
|
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
||||||
|
self.build.flags.strip = s.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
"ld" => {
|
"ld" => {
|
||||||
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
||||||
self.build.flags.ld = s.to_string();
|
self.build.flags.ld = s.to_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"nm" => {
|
||||||
|
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
||||||
|
self.build.flags.nm = s.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"objcopy" => {
|
||||||
|
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
||||||
|
self.build.flags.objcopy = s.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"objdump" => {
|
||||||
|
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
||||||
|
self.build.flags.objdump = s.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"readelf" => {
|
||||||
|
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
||||||
|
self.build.flags.readelf = s.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
"cpp" => {
|
"cpp" => {
|
||||||
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
if let Some(s) = values.last().and_then(|v| v.as_str()) {
|
||||||
self.build.flags.cpp = s.to_string();
|
self.build.flags.cpp = s.to_string();
|
||||||
@@ -2511,8 +2629,17 @@ type = "custom"
|
|||||||
r#"
|
r#"
|
||||||
[flags]
|
[flags]
|
||||||
cc = "my-cc"
|
cc = "my-cc"
|
||||||
|
cxx = "my-cxx"
|
||||||
|
ar = "my-ar"
|
||||||
|
ranlib = "my-ranlib"
|
||||||
|
strip = "my-strip"
|
||||||
ld = "ld.lld"
|
ld = "ld.lld"
|
||||||
|
nm = "my-nm"
|
||||||
|
objcopy = "my-objcopy"
|
||||||
|
objdump = "my-objdump"
|
||||||
|
readelf = "my-readelf"
|
||||||
CPP = "clang-cpp"
|
CPP = "clang-cpp"
|
||||||
|
tool_dir = "/opt/toolchain/bin"
|
||||||
cflags = ["-O2"]
|
cflags = ["-O2"]
|
||||||
replace_cflags = ["-O2=>-O3"]
|
replace_cflags = ["-O2=>-O3"]
|
||||||
cxxflags = ["-O2", "-pipe"]
|
cxxflags = ["-O2", "-pipe"]
|
||||||
@@ -2672,8 +2799,17 @@ post_configure = ["echo configured"]
|
|||||||
spec.apply_config(&config);
|
spec.apply_config(&config);
|
||||||
|
|
||||||
assert_eq!(spec.build.flags.cc, "my-cc");
|
assert_eq!(spec.build.flags.cc, "my-cc");
|
||||||
|
assert_eq!(spec.build.flags.cxx, "my-cxx");
|
||||||
|
assert_eq!(spec.build.flags.ar, "my-ar");
|
||||||
|
assert_eq!(spec.build.flags.ranlib, "my-ranlib");
|
||||||
|
assert_eq!(spec.build.flags.strip, "my-strip");
|
||||||
assert_eq!(spec.build.flags.ld, "ld.lld");
|
assert_eq!(spec.build.flags.ld, "ld.lld");
|
||||||
|
assert_eq!(spec.build.flags.nm, "my-nm");
|
||||||
|
assert_eq!(spec.build.flags.objcopy, "my-objcopy");
|
||||||
|
assert_eq!(spec.build.flags.objdump, "my-objdump");
|
||||||
|
assert_eq!(spec.build.flags.readelf, "my-readelf");
|
||||||
assert_eq!(spec.build.flags.cpp, "clang-cpp");
|
assert_eq!(spec.build.flags.cpp, "clang-cpp");
|
||||||
|
assert_eq!(spec.build.flags.tool_dir, "/opt/toolchain/bin");
|
||||||
assert!(spec.build.flags.cflags.contains(&"-O2".to_string()));
|
assert!(spec.build.flags.cflags.contains(&"-O2".to_string()));
|
||||||
assert!(spec.build.flags.cflags.contains(&"-g".to_string()));
|
assert!(spec.build.flags.cflags.contains(&"-g".to_string()));
|
||||||
assert!(
|
assert!(
|
||||||
@@ -2873,6 +3009,33 @@ post_configure = ["echo configured"]
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_apply_config_preserves_package_scalar_tool_and_layout_overrides() {
|
||||||
|
let mut spec = mk_spec("foo", "1.0");
|
||||||
|
spec.build.flags.ld = "ld.lld".to_string();
|
||||||
|
spec.build.flags.libdir = "/package/lib".to_string();
|
||||||
|
spec.build.flags.sysconfdir = "/package/etc".to_string();
|
||||||
|
let mut config = crate::config::Config::for_rootfs(Path::new("/tmp/nonexistent"));
|
||||||
|
config.build_overrides = toml::from_str(
|
||||||
|
r#"
|
||||||
|
ld = "/config/bin/ld"
|
||||||
|
fuse_ld = "/config/bin/ld.lld"
|
||||||
|
ranlib = "/config/bin/ranlib"
|
||||||
|
libdir = "/config/lib"
|
||||||
|
sysconfdir = "/config/etc"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
spec.apply_config(&config);
|
||||||
|
|
||||||
|
assert_eq!(spec.build.flags.ld, "ld.lld");
|
||||||
|
assert_eq!(spec.build.flags.libdir, "/package/lib");
|
||||||
|
assert_eq!(spec.build.flags.sysconfdir, "/package/etc");
|
||||||
|
assert_eq!(spec.build.flags.ranlib, "/config/bin/ranlib");
|
||||||
|
assert_eq!(spec.build.flags.fuse_ld, "/config/bin/ld.lld");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_no_flags_from_spec() {
|
fn parse_no_flags_from_spec() {
|
||||||
let tmp = tempfile::tempdir().unwrap();
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
@@ -2906,6 +3069,61 @@ no_flags = true
|
|||||||
assert!(spec.build.flags.no_flags);
|
assert!(spec.build.flags.no_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_tool_commands_from_spec() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let path = tmp.path().join("pkg.toml");
|
||||||
|
|
||||||
|
std::fs::write(
|
||||||
|
&path,
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "1.0"
|
||||||
|
description = "d"
|
||||||
|
homepage = "h"
|
||||||
|
license = "MIT"
|
||||||
|
|
||||||
|
[source]
|
||||||
|
url = "https://example.com/foo.tar.gz"
|
||||||
|
sha256 = "skip"
|
||||||
|
extract_dir = "foo"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
type = "custom"
|
||||||
|
|
||||||
|
[build.flags]
|
||||||
|
cc = "/tools/bin/cc"
|
||||||
|
cxx = "/tools/bin/c++"
|
||||||
|
ar = "/tools/bin/ar"
|
||||||
|
ranlib = "/tools/bin/ranlib"
|
||||||
|
strip = "/tools/bin/strip"
|
||||||
|
ld = "/tools/bin/ld"
|
||||||
|
fuse_ld = "/usr/bin/ld.lld"
|
||||||
|
nm = "/tools/bin/nm"
|
||||||
|
objcopy = "/tools/bin/objcopy"
|
||||||
|
objdump = "/tools/bin/objdump"
|
||||||
|
readelf = "/tools/bin/readelf"
|
||||||
|
cpp = "/tools/bin/cpp"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let spec = PackageSpec::from_file(&path).unwrap();
|
||||||
|
assert_eq!(spec.build.flags.cc, "/tools/bin/cc");
|
||||||
|
assert_eq!(spec.build.flags.cxx, "/tools/bin/c++");
|
||||||
|
assert_eq!(spec.build.flags.ar, "/tools/bin/ar");
|
||||||
|
assert_eq!(spec.build.flags.ranlib, "/tools/bin/ranlib");
|
||||||
|
assert_eq!(spec.build.flags.strip, "/tools/bin/strip");
|
||||||
|
assert_eq!(spec.build.flags.ld, "/tools/bin/ld");
|
||||||
|
assert_eq!(spec.build.flags.fuse_ld, "/usr/bin/ld.lld");
|
||||||
|
assert_eq!(spec.build.flags.nm, "/tools/bin/nm");
|
||||||
|
assert_eq!(spec.build.flags.objcopy, "/tools/bin/objcopy");
|
||||||
|
assert_eq!(spec.build.flags.objdump, "/tools/bin/objdump");
|
||||||
|
assert_eq!(spec.build.flags.readelf, "/tools/bin/readelf");
|
||||||
|
assert_eq!(spec.build.flags.cpp, "/tools/bin/cpp");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_ltoflags_and_use_lto_from_spec() {
|
fn parse_ltoflags_and_use_lto_from_spec() {
|
||||||
let tmp = tempfile::tempdir().unwrap();
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
@@ -4282,6 +4500,9 @@ pub struct BuildFlags {
|
|||||||
/// Extra flags exported to `LDFLAGS`.
|
/// Extra flags exported to `LDFLAGS`.
|
||||||
#[serde(default, deserialize_with = "deserialize_string_or_array")]
|
#[serde(default, deserialize_with = "deserialize_string_or_array")]
|
||||||
pub ldflags: Vec<String>,
|
pub ldflags: Vec<String>,
|
||||||
|
/// Linker selected through compiler drivers with `-fuse-ld=<value>`.
|
||||||
|
#[serde(default, alias = "fuse-ld")]
|
||||||
|
pub fuse_ld: String,
|
||||||
/// Ordered replacement rules applied to `ldflags` before export.
|
/// Ordered replacement rules applied to `ldflags` before export.
|
||||||
#[serde(
|
#[serde(
|
||||||
default,
|
default,
|
||||||
@@ -4416,6 +4637,9 @@ pub struct BuildFlags {
|
|||||||
/// Autotools configure script path, relative to source root or absolute.
|
/// Autotools configure script path, relative to source root or absolute.
|
||||||
#[serde(default, alias = "configure-file")]
|
#[serde(default, alias = "configure-file")]
|
||||||
pub configure_file: String,
|
pub configure_file: String,
|
||||||
|
/// Directory containing the configured compiler, linker, and binutils tools.
|
||||||
|
#[serde(default, alias = "tool-dir", alias = "tools_dir", alias = "tools-dir")]
|
||||||
|
pub tool_dir: String,
|
||||||
/// C compiler
|
/// C compiler
|
||||||
#[serde(default = "default_cc")]
|
#[serde(default = "default_cc")]
|
||||||
pub cc: String,
|
pub cc: String,
|
||||||
@@ -4425,9 +4649,27 @@ pub struct BuildFlags {
|
|||||||
/// Archiver
|
/// Archiver
|
||||||
#[serde(default = "default_ar")]
|
#[serde(default = "default_ar")]
|
||||||
pub ar: String,
|
pub ar: String,
|
||||||
|
/// Archive indexer exported as `RANLIB` when configured.
|
||||||
|
#[serde(default)]
|
||||||
|
pub ranlib: String,
|
||||||
|
/// Strip executable exported as `STRIP` when configured.
|
||||||
|
#[serde(default)]
|
||||||
|
pub strip: String,
|
||||||
/// Linker executable or linker flavor override for supported builders.
|
/// Linker executable or linker flavor override for supported builders.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub ld: String,
|
pub ld: String,
|
||||||
|
/// Symbol table dumper exported as `NM` when configured.
|
||||||
|
#[serde(default)]
|
||||||
|
pub nm: String,
|
||||||
|
/// Object copy tool exported as `OBJCOPY` when configured.
|
||||||
|
#[serde(default)]
|
||||||
|
pub objcopy: String,
|
||||||
|
/// Object dump tool exported as `OBJDUMP` when configured.
|
||||||
|
#[serde(default)]
|
||||||
|
pub objdump: String,
|
||||||
|
/// ELF reader exported as `READELF` when configured.
|
||||||
|
#[serde(default)]
|
||||||
|
pub readelf: String,
|
||||||
/// C preprocessor executable exported as `CPP` when configured.
|
/// C preprocessor executable exported as `CPP` when configured.
|
||||||
#[serde(default, alias = "CPP")]
|
#[serde(default, alias = "CPP")]
|
||||||
pub cpp: String,
|
pub cpp: String,
|
||||||
@@ -4700,6 +4942,7 @@ impl Default for BuildFlags {
|
|||||||
cxxflags_lib32: Vec::new(),
|
cxxflags_lib32: Vec::new(),
|
||||||
replace_cxxflags_lib32: Vec::new(),
|
replace_cxxflags_lib32: Vec::new(),
|
||||||
ldflags: Vec::new(),
|
ldflags: Vec::new(),
|
||||||
|
fuse_ld: String::new(),
|
||||||
replace_ldflags: Vec::new(),
|
replace_ldflags: Vec::new(),
|
||||||
ltoflags: Vec::new(),
|
ltoflags: Vec::new(),
|
||||||
rustltoflags: Vec::new(),
|
rustltoflags: Vec::new(),
|
||||||
@@ -4720,10 +4963,17 @@ impl Default for BuildFlags {
|
|||||||
config_settings: Vec::new(),
|
config_settings: Vec::new(),
|
||||||
configure_lib32: Vec::new(),
|
configure_lib32: Vec::new(),
|
||||||
configure_file: String::new(),
|
configure_file: String::new(),
|
||||||
|
tool_dir: String::new(),
|
||||||
cc: default_cc(),
|
cc: default_cc(),
|
||||||
cxx: default_cxx(),
|
cxx: default_cxx(),
|
||||||
ar: default_ar(),
|
ar: default_ar(),
|
||||||
|
ranlib: String::new(),
|
||||||
|
strip: String::new(),
|
||||||
ld: String::new(),
|
ld: String::new(),
|
||||||
|
nm: String::new(),
|
||||||
|
objcopy: String::new(),
|
||||||
|
objdump: String::new(),
|
||||||
|
readelf: String::new(),
|
||||||
cpp: String::new(),
|
cpp: String::new(),
|
||||||
libc: String::new(),
|
libc: String::new(),
|
||||||
rootfs: default_rootfs(),
|
rootfs: default_rootfs(),
|
||||||
|
|||||||
+200
-11
@@ -531,8 +531,14 @@ fn is_elf_file(path: &Path) -> Result<bool> {
|
|||||||
Ok(n == 4 && magic == [0x7F, b'E', b'L', b'F'])
|
Ok(n == 4 && magic == [0x7F, b'E', b'L', b'F'])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn auto_strip_elf_files(destdir: &Path) -> Result<usize> {
|
fn auto_strip_elf_files(destdir: &Path, strip_command: &str) -> Result<usize> {
|
||||||
let mut stripped = 0usize;
|
let mut stripped = 0usize;
|
||||||
|
let strip_command = strip_command.trim();
|
||||||
|
let strip_command = if strip_command.is_empty() {
|
||||||
|
"strip"
|
||||||
|
} else {
|
||||||
|
strip_command
|
||||||
|
};
|
||||||
for entry in WalkDir::new(destdir).into_iter().filter_map(|e| e.ok()) {
|
for entry in WalkDir::new(destdir).into_iter().filter_map(|e| e.ok()) {
|
||||||
if !entry.file_type().is_file() {
|
if !entry.file_type().is_file() {
|
||||||
continue;
|
continue;
|
||||||
@@ -542,19 +548,21 @@ fn auto_strip_elf_files(destdir: &Path) -> Result<usize> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let status = Command::new("strip")
|
let status = Command::new(strip_command)
|
||||||
.arg("--strip-debug")
|
.arg("--strip-debug")
|
||||||
.arg(path)
|
.arg(path)
|
||||||
.status()
|
.status()
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"Failed to execute strip for {} (disable with build.flags.no_strip = true)",
|
"Failed to execute {} for {} (disable with build.flags.no_strip = true)",
|
||||||
|
strip_command,
|
||||||
path.display()
|
path.display()
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
"strip failed for {} with status {} (disable with build.flags.no_strip = true)",
|
"{} failed for {} with status {} (disable with build.flags.no_strip = true)",
|
||||||
|
strip_command,
|
||||||
path.display(),
|
path.display(),
|
||||||
status
|
status
|
||||||
);
|
);
|
||||||
@@ -878,7 +886,7 @@ pub fn process(destdir: &Path, spec: &PackageSpec) -> Result<()> {
|
|||||||
if spec.build.flags.no_strip {
|
if spec.build.flags.no_strip {
|
||||||
crate::log_info!("Skipping auto-strip: disabled by build.flags.no_strip");
|
crate::log_info!("Skipping auto-strip: disabled by build.flags.no_strip");
|
||||||
} else {
|
} else {
|
||||||
let stripped = auto_strip_elf_files(destdir)?;
|
let stripped = auto_strip_elf_files(destdir, &spec.build.flags.strip)?;
|
||||||
if stripped > 0 {
|
if stripped > 0 {
|
||||||
crate::log_info!("Stripped {} ELF file(s)", stripped);
|
crate::log_info!("Stripped {} ELF file(s)", stripped);
|
||||||
}
|
}
|
||||||
@@ -968,7 +976,14 @@ fn normalize_lbi_tree_paths(root: &Path) -> Result<usize> {
|
|||||||
let mut changed = 0usize;
|
let mut changed = 0usize;
|
||||||
for (from, to) in mappings {
|
for (from, to) in mappings {
|
||||||
let src = root.join(from);
|
let src = root.join(from);
|
||||||
if !src.exists() {
|
let src_meta = match fs::symlink_metadata(&src) {
|
||||||
|
Ok(metadata) => metadata,
|
||||||
|
Err(err) if err.kind() == io::ErrorKind::NotFound => continue,
|
||||||
|
Err(err) => {
|
||||||
|
return Err(err).with_context(|| format!("Failed to inspect {}", src.display()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if src_meta.file_type().is_symlink() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let dst = root.join(to);
|
let dst = root.join(to);
|
||||||
@@ -1242,7 +1257,10 @@ fn copy_tree_preserving_layout_no_overwrite(
|
|||||||
.with_context(|| format!("Failed to create directory {}", parent.display()))?;
|
.with_context(|| format!("Failed to create directory {}", parent.display()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if dst_path.symlink_metadata().is_ok() {
|
if let Ok(dst_metadata) = dst_path.symlink_metadata() {
|
||||||
|
if duplicate_staged_path_is_equivalent(src_path, &metadata, &dst_path, &dst_metadata)? {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
"Failed to replay relocated path into {}: destination already exists",
|
"Failed to replay relocated path into {}: destination already exists",
|
||||||
dst_path.display()
|
dst_path.display()
|
||||||
@@ -1281,6 +1299,65 @@ fn copy_tree_preserving_layout_no_overwrite(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn symlink_target_path_inside_rootfs(
|
||||||
|
rootfs: &Path,
|
||||||
|
link_rel: &str,
|
||||||
|
target: &Path,
|
||||||
|
) -> Result<Option<PathBuf>> {
|
||||||
|
let mut normalized = PathBuf::new();
|
||||||
|
if target.is_absolute() {
|
||||||
|
for component in target.components() {
|
||||||
|
match component {
|
||||||
|
Component::RootDir => {}
|
||||||
|
Component::CurDir => {}
|
||||||
|
Component::Normal(segment) => normalized.push(segment),
|
||||||
|
Component::ParentDir | Component::Prefix(_) => return Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Some(parent) = Path::new(link_rel).parent() {
|
||||||
|
normalized.push(parent);
|
||||||
|
}
|
||||||
|
for component in target.components() {
|
||||||
|
match component {
|
||||||
|
Component::CurDir => {}
|
||||||
|
Component::Normal(segment) => normalized.push(segment),
|
||||||
|
Component::ParentDir => {
|
||||||
|
if !normalized.pop() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Component::RootDir | Component::Prefix(_) => return Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if normalized.as_os_str().is_empty() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some(rootfs.join(normalized)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_relocate_directory_for_symlink_swap(
|
||||||
|
rootfs: &Path,
|
||||||
|
link_rel: &str,
|
||||||
|
symlink_path: &Path,
|
||||||
|
) -> Result<bool> {
|
||||||
|
let target = fs::read_link(symlink_path)
|
||||||
|
.with_context(|| format!("Failed to read symlink {}", symlink_path.display()))?;
|
||||||
|
let Some(target_path) = symlink_target_path_inside_rootfs(rootfs, link_rel, &target)? else {
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
match target_path.symlink_metadata() {
|
||||||
|
Ok(metadata) => Ok(metadata.file_type().is_dir()),
|
||||||
|
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(false),
|
||||||
|
Err(err) => Err(err)
|
||||||
|
.with_context(|| format!("Failed to inspect symlink target {}", target_path.display())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn remove_path_in_place(path: &Path, rel: &str) -> Result<()> {
|
fn remove_path_in_place(path: &Path, rel: &str) -> Result<()> {
|
||||||
let metadata = path
|
let metadata = path
|
||||||
.symlink_metadata()
|
.symlink_metadata()
|
||||||
@@ -1530,9 +1607,25 @@ impl FsTransaction {
|
|||||||
|
|
||||||
/// Commit the transaction (delete backup directory).
|
/// Commit the transaction (delete backup directory).
|
||||||
pub fn commit(self) -> Result<()> {
|
pub fn commit(self) -> Result<()> {
|
||||||
|
let tx_base_dir = self.tx_dir.parent().map(Path::to_path_buf);
|
||||||
if self.tx_dir.exists() {
|
if self.tx_dir.exists() {
|
||||||
fs::remove_dir_all(&self.tx_dir)?;
|
fs::remove_dir_all(&self.tx_dir)?;
|
||||||
}
|
}
|
||||||
|
if let Some(tx_base_dir) = tx_base_dir {
|
||||||
|
match fs::remove_dir(&tx_base_dir) {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(err)
|
||||||
|
if matches!(
|
||||||
|
err.kind(),
|
||||||
|
io::ErrorKind::DirectoryNotEmpty | io::ErrorKind::NotFound
|
||||||
|
) => {}
|
||||||
|
Err(err) => {
|
||||||
|
return Err(err).with_context(|| {
|
||||||
|
format!("Failed to remove tx dir {}", tx_base_dir.display())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1548,6 +1641,11 @@ pub fn install_atomic(
|
|||||||
remove_paths: &[String],
|
remove_paths: &[String],
|
||||||
keep_paths: &[String],
|
keep_paths: &[String],
|
||||||
) -> Result<FsTransaction> {
|
) -> Result<FsTransaction> {
|
||||||
|
let tx_base_dir = if rootfs != Path::new("/") && tx_base_dir.starts_with(rootfs) {
|
||||||
|
rootfs.join(".depot-tx")
|
||||||
|
} else {
|
||||||
|
tx_base_dir.to_path_buf()
|
||||||
|
};
|
||||||
let keep_rules: Vec<KeepMatcher> = keep_paths
|
let keep_rules: Vec<KeepMatcher> = keep_paths
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| KeepMatcher::from_spec(p))
|
.map(|p| KeepMatcher::from_spec(p))
|
||||||
@@ -1561,7 +1659,7 @@ pub fn install_atomic(
|
|||||||
.collect();
|
.collect();
|
||||||
let remove_set: HashSet<&str> = remove_paths.iter().map(String::as_str).collect();
|
let remove_set: HashSet<&str> = remove_paths.iter().map(String::as_str).collect();
|
||||||
|
|
||||||
fs::create_dir_all(tx_base_dir)
|
fs::create_dir_all(&tx_base_dir)
|
||||||
.with_context(|| format!("Failed to create tx dir: {}", tx_base_dir.display()))?;
|
.with_context(|| format!("Failed to create tx dir: {}", tx_base_dir.display()))?;
|
||||||
|
|
||||||
let ts = SystemTime::now()
|
let ts = SystemTime::now()
|
||||||
@@ -1655,7 +1753,13 @@ pub fn install_atomic(
|
|||||||
if let Ok(dest_meta) = dest_path.symlink_metadata() {
|
if let Ok(dest_meta) = dest_path.symlink_metadata() {
|
||||||
let backup_path = tx.backup_path(&install_rel_path);
|
let backup_path = tx.backup_path(&install_rel_path);
|
||||||
if dest_meta.file_type().is_dir() {
|
if dest_meta.file_type().is_dir() {
|
||||||
if !remove_set.contains(install_rel_path.as_str()) {
|
let can_relocate = file_type.is_symlink()
|
||||||
|
&& can_relocate_directory_for_symlink_swap(
|
||||||
|
rootfs,
|
||||||
|
&install_rel_path,
|
||||||
|
src_path,
|
||||||
|
)?;
|
||||||
|
if !remove_set.contains(install_rel_path.as_str()) && !can_relocate {
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
"Refusing to replace existing directory with packaged file/symlink: {}",
|
"Refusing to replace existing directory with packaged file/symlink: {}",
|
||||||
install_rel_path
|
install_rel_path
|
||||||
@@ -1684,7 +1788,11 @@ pub fn install_atomic(
|
|||||||
// Remove destination if it exists (we backed it up) so we can overwrite
|
// Remove destination if it exists (we backed it up) so we can overwrite
|
||||||
if let Ok(dest_meta) = dest_path.symlink_metadata() {
|
if let Ok(dest_meta) = dest_path.symlink_metadata() {
|
||||||
if dest_meta.file_type().is_dir() {
|
if dest_meta.file_type().is_dir() {
|
||||||
if !remove_set.contains(install_rel_path.as_str()) {
|
let relocated_for_symlink_swap =
|
||||||
|
tx.relocated.iter().any(|rel| rel == &install_rel_path);
|
||||||
|
if !remove_set.contains(install_rel_path.as_str())
|
||||||
|
&& !relocated_for_symlink_swap
|
||||||
|
{
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
"Refusing to replace existing directory with packaged file/symlink: {}",
|
"Refusing to replace existing directory with packaged file/symlink: {}",
|
||||||
install_rel_path
|
install_rel_path
|
||||||
@@ -1703,7 +1811,8 @@ pub fn install_atomic(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if file_type.is_symlink() {
|
if file_type.is_symlink() {
|
||||||
let target = fs::read_link(src_path)?;
|
let target = fs::read_link(src_path)
|
||||||
|
.with_context(|| format!("Failed to read staged symlink {}", rel_path))?;
|
||||||
std::os::unix::fs::symlink(target, &dest_path)
|
std::os::unix::fs::symlink(target, &dest_path)
|
||||||
.with_context(|| format!("Failed to create symlink: {}", install_rel_path))?;
|
.with_context(|| format!("Failed to create symlink: {}", install_rel_path))?;
|
||||||
tx.replay_relocated_dir_if_present(&install_rel_path)?;
|
tx.replay_relocated_dir_if_present(&install_rel_path)?;
|
||||||
@@ -1949,6 +2058,49 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[test]
|
||||||
|
fn process_preserves_lbi_compatibility_symlinks() {
|
||||||
|
use std::os::unix::fs as unix_fs;
|
||||||
|
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let destdir = tmp.path().join("dest");
|
||||||
|
std::fs::create_dir_all(destdir.join("system/binaries")).unwrap();
|
||||||
|
std::fs::create_dir_all(destdir.join("system/documentation/man-pages")).unwrap();
|
||||||
|
std::fs::create_dir_all(destdir.join("system/share")).unwrap();
|
||||||
|
std::fs::create_dir_all(destdir.join("usr")).unwrap();
|
||||||
|
|
||||||
|
unix_fs::symlink("system/binaries", destdir.join("bin")).unwrap();
|
||||||
|
unix_fs::symlink("../system/binaries", destdir.join("usr/bin")).unwrap();
|
||||||
|
unix_fs::symlink("../system/share", destdir.join("usr/share")).unwrap();
|
||||||
|
unix_fs::symlink(
|
||||||
|
"../documentation/man-pages",
|
||||||
|
destdir.join("system/share/man"),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let spec = mk_spec_for_stage_processing();
|
||||||
|
process(&destdir, &spec).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
std::fs::read_link(destdir.join("bin")).unwrap(),
|
||||||
|
PathBuf::from("system/binaries")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
std::fs::read_link(destdir.join("usr/bin")).unwrap(),
|
||||||
|
PathBuf::from("../system/binaries")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
std::fs::read_link(destdir.join("usr/share")).unwrap(),
|
||||||
|
PathBuf::from("../system/share")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
std::fs::read_link(destdir.join("system/share/man")).unwrap(),
|
||||||
|
PathBuf::from("../documentation/man-pages")
|
||||||
|
);
|
||||||
|
assert!(destdir.join("system/documentation/man-pages").is_dir());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn process_rejects_conflicting_lbi_normalized_paths() {
|
fn process_rejects_conflicting_lbi_normalized_paths() {
|
||||||
let tmp = tempfile::tempdir().unwrap();
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
@@ -2256,6 +2408,43 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn install_atomic_relocates_existing_directory_into_packaged_symlink_target() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let rootfs = tmp.path().join("root");
|
||||||
|
let destdir = tmp.path().join("dest");
|
||||||
|
let tx_base = rootfs.join("var/cache/depot/build/tx");
|
||||||
|
std::fs::create_dir_all(rootfs.join("var/lib/depot")).unwrap();
|
||||||
|
std::fs::write(rootfs.join("var/lib/depot/lock"), "state").unwrap();
|
||||||
|
std::fs::create_dir_all(rootfs.join("system/variable/lib/depot")).unwrap();
|
||||||
|
std::fs::write(rootfs.join("system/variable/lib/depot/lock"), "state").unwrap();
|
||||||
|
std::fs::create_dir_all(destdir.join("system/variable/lib/misc")).unwrap();
|
||||||
|
std::os::unix::fs::symlink("system/variable", destdir.join("var")).unwrap();
|
||||||
|
|
||||||
|
let tx = install_atomic(&destdir, &rootfs, &tx_base, &[], &[]).unwrap();
|
||||||
|
|
||||||
|
let var_meta = rootfs.join("var").symlink_metadata().unwrap();
|
||||||
|
assert!(var_meta.file_type().is_symlink());
|
||||||
|
assert_eq!(
|
||||||
|
std::fs::read_link(rootfs.join("var")).unwrap(),
|
||||||
|
PathBuf::from("system/variable")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
std::fs::read_to_string(rootfs.join("system/variable/lib/depot/lock")).unwrap(),
|
||||||
|
"state"
|
||||||
|
);
|
||||||
|
assert!(rootfs.join("system/variable/lib/misc").is_dir());
|
||||||
|
|
||||||
|
tx.rollback().unwrap();
|
||||||
|
let restored = rootfs.join("var").symlink_metadata().unwrap();
|
||||||
|
assert!(restored.file_type().is_dir());
|
||||||
|
assert_eq!(
|
||||||
|
std::fs::read_to_string(rootfs.join("var/lib/depot/lock")).unwrap(),
|
||||||
|
"state"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn install_atomic_replaces_obsolete_directory_with_symlink() {
|
fn install_atomic_replaces_obsolete_directory_with_symlink() {
|
||||||
|
|||||||
+5
-4
@@ -348,10 +348,11 @@ datarootdir = "/system/share"
|
|||||||
datadir = "/system/share"
|
datadir = "/system/share"
|
||||||
mandir = "/system/documentation/man-pages"
|
mandir = "/system/documentation/man-pages"
|
||||||
infodir = "/system/documentation/info"
|
infodir = "/system/documentation/info"
|
||||||
cc = "clang"
|
tool_dir = "/system/tools/bin"
|
||||||
cxx = "clang++"
|
cc = "$TOOL_DIR/clang"
|
||||||
ar = "llvm-ar"
|
cxx = "$TOOL_DIR/clang++"
|
||||||
ld = "ld.lld"
|
ar = "$TOOL_DIR/llvm-ar"
|
||||||
|
ld = "$TOOL_DIR/ld.lld"
|
||||||
carch = "{arch}"
|
carch = "{arch}"
|
||||||
chost = "{target}"
|
chost = "{target}"
|
||||||
target = "{target}"
|
target = "{target}"
|
||||||
|
|||||||
Reference in New Issue
Block a user