{ lib, stdenv, releaseTools, autoconf-archive, autoreconfHook, aws-sdk-cpp, boehmgc, nlohmann_json, bison, boost, brotli, bzip2, curl, editline, readline, flex, git, gtest, jq, libarchive, libcpuid, libgit2, libseccomp, libsodium, man, darwin, lowdown, mdbook, mdbook-linkcheck, mercurial, openssh, openssl, pkg-config, rapidcheck, sqlite, toml11, unixtools, xz, busybox-sandbox-shell ? null, # Configuration Options #: # This probably seems like too many degrees of freedom, but it # faithfully reflects how the underlying configure + make build system # work. The top-level flake.nix will choose useful combinations of these # options to CI. pname ? "nix", versionSuffix ? "", # Whether to build Nix. Useful to skip for tasks like testing existing pre-built versions of Nix doBuild ? true, # Run the unit tests as part of the build. See `installUnitTests` for an # alternative to this. doCheck ? __forDefaults.canRunInstalled, # Run the functional tests as part of the build. doInstallCheck ? test-client != null || __forDefaults.canRunInstalled, # Check test coverage of Nix. Probably want to use with at least # one of `doCHeck` or `doInstallCheck` enabled. withCoverageChecks ? false, # Whether to build the regular manual enableManual ? __forDefaults.canRunInstalled, # Whether to use garbage collection for the Nix language evaluator. # # If it is disabled, we just leak memory, but this is not as bad as it # sounds so long as evaluation just takes places within short-lived # processes. (When the process exits, the memory is reclaimed; it is # only leaked *within* the process.) # # Temporarily disabled on Windows because the `GC_throw_bad_alloc` # symbol is missing during linking. # # Disabled on OpenBSD because of missing `_data_start` symbol while linking enableGC ? !stdenv.hostPlatform.isWindows && !stdenv.hostPlatform.isOpenBSD, # Whether to enable Markdown rendering in the Nix binary. enableMarkdown ? !stdenv.hostPlatform.isWindows, # Which interactive line editor library to use for Nix's repl. # # Currently supported choices are: # # - editline (default) # - readline readlineFlavor ? if stdenv.hostPlatform.isWindows then "readline" else "editline", # Whether to install unit tests. This is useful when cross compiling # since we cannot run them natively during the build, but can do so # later. installUnitTests ? doBuild && !__forDefaults.canExecuteHost, # For running the functional tests against a pre-built Nix. Probably # want to use in conjunction with `doBuild = false;`. test-daemon ? null, test-client ? null, # Avoid setting things that would interfere with a functioning devShell forDevShell ? false, # Not a real argument, just the only way to approximate let-binding some # stuff for argument defaults. __forDefaults ? { canExecuteHost = stdenv.buildPlatform.canExecute stdenv.hostPlatform; canRunInstalled = doBuild && __forDefaults.canExecuteHost; }, }: let inherit (lib) fileset; version = lib.fileContents ./.version + versionSuffix; # selected attributes with defaults, will be used to define some # things which should instead be gotten via `finalAttrs` in order to # work with overriding. attrs = { inherit doBuild doCheck doInstallCheck; }; mkDerivation = if withCoverageChecks then # TODO support `finalAttrs` args function in # `releaseTools.coverageAnalysis`. argsFun: releaseTools.coverageAnalysis ( let args = argsFun args; in args ) else stdenv.mkDerivation; in mkDerivation ( finalAttrs: let inherit (finalAttrs) doCheck doInstallCheck ; doBuild = !finalAttrs.dontBuild; # Either running the unit tests during the build, or installing them # to be run later, requiresthe unit tests to be built. buildUnitTests = doCheck || installUnitTests; in { inherit pname version; src = let baseFiles = fileset.fileFilter (f: f.name != ".gitignore") ./.; in fileset.toSource { root = ./.; fileset = fileset.intersection baseFiles ( fileset.unions ( [ # For configure ./.version ./configure.ac ./m4 # TODO: do we really need README.md? It doesn't seem used in the build. ./README.md # This could be put behind a conditional ./maintainers/local.mk # For make, regardless of what we are building ./local.mk ./Makefile ./Makefile.config.in ./mk (fileset.fileFilter (f: lib.strings.hasPrefix "nix-profile" f.name) ./scripts) ] ++ lib.optionals doBuild [ ./doc ./misc ./precompiled-headers.h (fileset.difference ./src ./src/perl) ./COPYING ./scripts/local.mk ] ++ lib.optionals enableManual [ ./doc/manual ] ++ lib.optionals buildUnitTests [ ./tests/unit ] ++ lib.optionals doInstallCheck [ ./tests/functional ] ) ); }; VERSION_SUFFIX = versionSuffix; outputs = [ "out" ] ++ lib.optional doBuild "dev" # If we are doing just build or just docs, the one thing will use # "out". We only need additional outputs if we are doing both. ++ lib.optional (doBuild && enableManual) "doc" ++ lib.optional installUnitTests "check" ++ lib.optional doCheck "testresults"; nativeBuildInputs = [ autoconf-archive autoreconfHook pkg-config ] ++ lib.optionals doBuild [ bison flex ] ++ lib.optionals enableManual [ (lib.getBin lowdown) mdbook mdbook-linkcheck ] ++ lib.optionals doInstallCheck [ git mercurial openssh ] ++ lib.optionals (doInstallCheck || enableManual) [ jq # Also for custom mdBook preprocessor. ] ++ lib.optionals enableManual [ man ] ++ lib.optional stdenv.hostPlatform.isStatic unixtools.hexdump; buildInputs = lib.optionals doBuild ( [ brotli bzip2 curl libarchive libgit2 libsodium openssl sqlite toml11 xz ({ inherit readline editline; }.${readlineFlavor}) ] ++ lib.optionals enableMarkdown [ lowdown ] ++ lib.optionals buildUnitTests [ gtest rapidcheck ] ++ lib.optional stdenv.isLinux libseccomp ++ lib.optional stdenv.hostPlatform.isDarwin darwin.apple_sdk.libs.sandbox ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid # There have been issues building these dependencies ++ lib.optional ( stdenv.hostPlatform == stdenv.buildPlatform && (stdenv.isLinux || stdenv.isDarwin) ) aws-sdk-cpp ); propagatedBuildInputs = lib.optionals doBuild ( [ boost nlohmann_json ] ++ lib.optional enableGC boehmgc ); dontBuild = !attrs.doBuild; doCheck = attrs.doCheck; configureFlags = [ (lib.enableFeature doBuild "build") (lib.enableFeature buildUnitTests "unit-tests") (lib.enableFeature doInstallCheck "functional-tests") (lib.enableFeature enableManual "doc-gen") (lib.enableFeature enableGC "gc") (lib.enableFeature enableMarkdown "markdown") (lib.enableFeature installUnitTests "install-unit-tests") (lib.withFeatureAs true "readline-flavor" readlineFlavor) ] ++ lib.optionals (!forDevShell) [ "--sysconfdir=/etc" ] ++ lib.optionals installUnitTests [ "--with-check-bin-dir=${builtins.placeholder "check"}/bin" "--with-check-lib-dir=${builtins.placeholder "check"}/lib" ] ++ lib.optionals (doBuild) [ "--with-boost=${boost}/lib" ] ++ lib.optionals (doBuild && stdenv.isLinux) [ "--with-sandbox-shell=${busybox-sandbox-shell}/bin/busybox" ] ++ lib.optional ( doBuild && stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux") ) "LDFLAGS=-fuse-ld=gold" ++ lib.optional (doBuild && stdenv.hostPlatform.isStatic) "--enable-embedded-sandbox-shell"; enableParallelBuilding = true; makeFlags = "profiledir=$(out)/etc/profile.d PRECOMPILE_HEADERS=1"; preCheck = '' mkdir $testresults ''; installTargets = lib.optional doBuild "install"; installFlags = "sysconfdir=$(out)/etc"; # In this case we are probably just running tests, and so there isn't # anything to install, we just make an empty directory to signify tests # succeeded. installPhase = if finalAttrs.installTargets != [ ] then null else '' mkdir -p $out ''; postInstall = lib.optionalString doBuild ( lib.optionalString stdenv.hostPlatform.isStatic '' mkdir -p $out/nix-support echo "file binary-dist $out/bin/nix" >> $out/nix-support/hydra-build-products '' ) + lib.optionalString enableManual '' mkdir -p ''${!outputDoc}/nix-support echo "doc manual ''${!outputDoc}/share/doc/nix/manual" >> ''${!outputDoc}/nix-support/hydra-build-products ''; # So the check output gets links for DLLs in the out output. preFixup = lib.optionalString (stdenv.hostPlatform.isWindows && builtins.elem "check" finalAttrs.outputs) '' ln -s "$check/lib/"*.dll "$check/bin" ln -s "$out/bin/"*.dll "$check/bin" ''; doInstallCheck = attrs.doInstallCheck; installCheckFlags = "sysconfdir=$(out)/etc"; # Work around buggy detection in stdenv. installCheckTarget = "installcheck"; # Work around weird bug where it doesn't think there is a Makefile. installCheckPhase = if (!doBuild && doInstallCheck) then '' runHook preInstallCheck mkdir -p src/nix-channel make installcheck -j$NIX_BUILD_CORES -l$NIX_BUILD_CORES '' else null; # Needed for tests if we are not doing a build, but testing existing # built Nix. preInstallCheck = lib.optionalString (!doBuild) '' mkdir -p src/nix-channel '' # See https://github.com/NixOS/nix/issues/2523 # Occurs often in tests since https://github.com/NixOS/nix/pull/9900 + lib.optionalString stdenv.hostPlatform.isDarwin '' export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES ''; separateDebugInfo = !stdenv.hostPlatform.isStatic; # TODO Always true after https://github.com/NixOS/nixpkgs/issues/318564 strictDeps = !withCoverageChecks; hardeningDisable = lib.optional stdenv.hostPlatform.isStatic "pie"; meta = { platforms = lib.platforms.unix ++ lib.platforms.windows; mainProgram = "nix"; broken = !(lib.all (a: a) [ # We cannot run or install unit tests if we don't build them or # Nix proper (which they depend on). (installUnitTests -> doBuild) (doCheck -> doBuild) # The build process for the manual currently requires extracting # data from the Nix executable we are trying to document. (enableManual -> doBuild) ]); }; } // lib.optionalAttrs withCoverageChecks { lcovFilter = [ "*/boost/*" "*-tab.*" ]; hardeningDisable = [ "fortify" ]; NIX_CFLAGS_COMPILE = "-DCOVERAGE=1"; dontInstall = false; } // lib.optionalAttrs (test-daemon != null) { NIX_DAEMON_PACKAGE = test-daemon; } // lib.optionalAttrs (test-client != null) { NIX_CLIENT_PACKAGE = test-client; } )