diff --git a/doc/manual/rl-next/build-cores-auto-detect.md b/doc/manual/rl-next/build-cores-auto-detect.md new file mode 100644 index 00000000000..67ab6995b4c --- /dev/null +++ b/doc/manual/rl-next/build-cores-auto-detect.md @@ -0,0 +1,6 @@ +--- +synopsis: "`build-cores = 0` now auto-detects CPU cores" +prs: [13402] +--- + +When `build-cores` is set to `0`, nix now automatically detects the number of available CPU cores and passes this value via `NIX_BUILD_CORES`, instead of passing `0` directly. This matches the behavior when `build-cores` is unset. This prevents the builder from having to detect the number of cores. diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index de512834783..1f80cb379e5 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -140,7 +140,7 @@ std::vector getUserConfigFiles() return files; } -unsigned int Settings::getDefaultCores() +unsigned int Settings::getDefaultCores() const { const unsigned int concurrency = std::max(1U, std::thread::hardware_concurrency()); const unsigned int maxCPU = getMaxCPU(); diff --git a/src/libstore/include/nix/store/globals.hh b/src/libstore/include/nix/store/globals.hh index 0ac689b55c1..8dfdf11cb01 100644 --- a/src/libstore/include/nix/store/globals.hh +++ b/src/libstore/include/nix/store/globals.hh @@ -43,8 +43,6 @@ const uint32_t maxIdsPerBuild = class Settings : public Config { - unsigned int getDefaultCores(); - StringSet getDefaultSystemFeatures(); StringSet getDefaultExtraPlatforms(); @@ -57,6 +55,8 @@ public: Settings(); + unsigned int getDefaultCores() const; + Path nixPrefix; /** @@ -153,7 +153,7 @@ public: Setting buildCores{ this, - getDefaultCores(), + 0, "cores", R"( Sets the value of the `NIX_BUILD_CORES` environment variable in the [invocation of the `builder` executable](@docroot@/language/derivations.md#builder-execution) of a derivation. @@ -166,15 +166,13 @@ public: --> For instance, in Nixpkgs, if the attribute `enableParallelBuilding` for the `mkDerivation` build helper is set to `true`, it passes the `-j${NIX_BUILD_CORES}` flag to GNU Make. - The value `0` means that the `builder` should use all available CPU cores in the system. + If set to `0`, nix will detect the number of CPU cores and pass this number via NIX_BUILD_CORES. > **Note** > > The number of parallel local Nix build jobs is independently controlled with the [`max-jobs`](#conf-max-jobs) setting. )", - {"build-cores"}, - // Don't document the machine-specific default value - false}; + {"build-cores"}}; /** * Read-only mode. Don't copy stuff to the store, don't change diff --git a/src/libstore/unix/build/derivation-builder.cc b/src/libstore/unix/build/derivation-builder.cc index fd62aa664a4..cf6c0a5b134 100644 --- a/src/libstore/unix/build/derivation-builder.cc +++ b/src/libstore/unix/build/derivation-builder.cc @@ -1083,7 +1083,7 @@ void DerivationBuilderImpl::initEnv() env["NIX_STORE"] = store.storeDir; /* The maximum number of cores to utilize for parallel building. */ - env["NIX_BUILD_CORES"] = fmt("%d", settings.buildCores); + env["NIX_BUILD_CORES"] = fmt("%d", settings.buildCores ? settings.buildCores : settings.getDefaultCores()); /* In non-structured mode, set all bindings either directory in the environment or via a file, as specified by diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc index cde9d67424a..04ea44c3dc2 100644 --- a/src/nix-build/nix-build.cc +++ b/src/nix-build/nix-build.cc @@ -542,7 +542,7 @@ static void main_nix_build(int argc, char * * argv) env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmpDir.path().string(); env["NIX_STORE"] = store->storeDir; - env["NIX_BUILD_CORES"] = std::to_string(settings.buildCores); + env["NIX_BUILD_CORES"] = fmt("%d", settings.buildCores ? settings.buildCores : settings.getDefaultCores()); auto parsedDrv = StructuredAttrs::tryParse(drv.env); DerivationOptions drvOptions; diff --git a/tests/functional/build-cores.nix b/tests/functional/build-cores.nix new file mode 100644 index 00000000000..9b763f7d866 --- /dev/null +++ b/tests/functional/build-cores.nix @@ -0,0 +1,11 @@ +with import ./config.nix; + +{ + # Test derivation that checks the NIX_BUILD_CORES environment variable + testCores = mkDerivation { + name = "test-build-cores"; + buildCommand = '' + echo "$NIX_BUILD_CORES" > $out + ''; + }; +} diff --git a/tests/functional/build-cores.sh b/tests/functional/build-cores.sh new file mode 100755 index 00000000000..a226774c6a7 --- /dev/null +++ b/tests/functional/build-cores.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +source common.sh + +clearStoreIfPossible + +echo "Testing build-cores configuration behavior..." + +# Test 1: When build-cores is set to a non-zero value, NIX_BUILD_CORES should have that value +echo "Testing build-cores=4..." +rm -f "$TEST_ROOT"/build-cores-output +nix-build --cores 4 build-cores.nix -A testCores -o "$TEST_ROOT"/build-cores-output +result=$(cat "$(readlink "$TEST_ROOT"/build-cores-output)") +if [[ "$result" != "4" ]]; then + echo "FAIL: Expected NIX_BUILD_CORES=4, got $result" + exit 1 +fi +echo "PASS: build-cores=4 correctly sets NIX_BUILD_CORES=4" +rm -f "$TEST_ROOT"/build-cores-output + +# Test 2: When build-cores is set to 0, NIX_BUILD_CORES should be resolved to getDefaultCores() +echo "Testing build-cores=0..." +nix-build --cores 0 build-cores.nix -A testCores -o "$TEST_ROOT"/build-cores-output +result=$(cat "$(readlink "$TEST_ROOT"/build-cores-output)") +if [[ "$result" == "0" ]]; then + echo "FAIL: NIX_BUILD_CORES should not be 0 when build-cores=0" + exit 1 +fi +echo "PASS: build-cores=0 resolves to NIX_BUILD_CORES=$result (should be > 0)" +rm -f "$TEST_ROOT"/build-cores-output + +echo "All build-cores tests passed!" diff --git a/tests/functional/meson.build b/tests/functional/meson.build index cd1bc631978..501ed45c79f 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -145,6 +145,7 @@ suites = [ 'placeholders.sh', 'ssh-relay.sh', 'build.sh', + 'build-cores.sh', 'build-delete.sh', 'output-normalization.sh', 'selfref-gc.sh',