{ pkgs, pkgsStatic, lib, stdenv, closureInfo, runCommand, aws-sdk-cpp, # If the patched version of Boehm isn't passed, then patch it based off of # pkgs.boehmgc. This allows `callPackage`ing this file without needing to # to implement behavior that this package flat out doesn't build without # anyway, but also allows easily overriding the patch logic. boehmgc-nix ? __forDefaults.boehmgc-nix, boehmgc, buildPackages, nlohmann_json, build-release-notes ? __forDefaults.build-release-notes, boost, brotli, bzip2, callPackage, capnproto, cmake, curl-lix ? __forDefaults.curl-lix, fetchpatch2, curl, doxygen, git, gtest, jq, libarchive, libcpuid, libseccomp, libsystemtap, lix-clang-tidy ? null, llvmPackages, lsof, lowdown-unsandboxed, lowdown, mdbook, # older nixpkgs only have v1, newer nixpkgs only have v2 mdbook-linkcheck ? null, mdbook-linkcheck2 ? mdbook-linkcheck, mercurial, meson, ninja, openssl, passt, pegtl, pkg-config, python3, rapidcheck, removeReferencesTo, rustPlatform, rustc, cargo, sqlite, systemtap-lix ? __forDefaults.systemtap-lix, toml11, util-linuxMinimal ? utillinuxMinimal, utillinuxMinimal ? null, xz, zstd, yq, wrapBintoolsWith, busybox-sandbox-shell, bash, pname ? "lix", versionSuffix ? "", officialRelease ? __forDefaults.versionJson.official_release, # Set to true to build the release notes for the next release. buildUnreleasedNotes ? true, internalApiDocs ? false, # Support garbage collection in the evaluator. enableGC ? sanitize == null || !builtins.elem "address" sanitize, # List of Meson sanitize options. Accepts values of b_sanitize, e.g. # "address", "undefined", "thread". # Enabling the "address" sanitizer will disable garbage collection in the evaluator. sanitize ? null, # include sanitizer libraries in the build closure (mostly for devshells) includeSanitizerLibs ? sanitize != null, # Turn compiler warnings into errors. werror ? false, lintInsteadOfBuild ? false, useLld ? false, # FIXME(jade): figure out if it is possible to support non-linux systems for dtrace probes withDtrace ? lib.meta.availableOn stdenv.hostPlatform libsystemtap && lib.meta.availableOn stdenv.buildPlatform systemtap-lix, # In CI, we want to make sure both static and dynamic versions of our libraries build. # Building them entirely separately is way too expensive for our anemic CI, so we instead # ask Meson to `-Ddefault_library=both`. However that also installs both kinds of libraries, # which takes up waaaay more space. So we'll delete the installed static libraries in postInstall. ciBuildAndDeleteBothLibraries ? !stdenv.hostPlatform.isStatic, # Not a real argument, just the only way to approximate let-binding some # stuff for argument defaults. __forDefaults ? { canRunInstalled = stdenv.buildPlatform.canExecute stdenv.hostPlatform; versionJson = builtins.fromJSON (builtins.readFile ./version.json); boehmgc-nix = (boehmgc.override { enableLargeConfig = true; }).overrideAttrs (oldAttrs: { /* TODO: Use the `initialMarkStackSize` override when https://github.com/NixOS/nixpkgs/pull/439943 hits a stable branch Increase the initial mark stack size to avoid stack overflows, since these inhibit parallel marking (see GC_mark_some()). To check whether the mark stack is too small, run Nix with GC_PRINT_STATS=1 and look for messages such as `Mark stack overflow`, `No room to copy back mark stack`, and `Grew mark stack to ... frames`. */ NIX_CFLAGS_COMPILE = (oldAttrs.NIX_CFLAGS_COMPILE or "") + " -DINITIAL_MARK_STACK_SIZE=1048576"; }); curl-lix = # curl 8.21.0 /somehow/ breaks Lix unit tests. # See https://github.com/NixOS/nixpkgs/issues/534713 # FIXME remove once fixed if lib.versionAtLeast curl.version "8.21" then curl.overrideAttrs ( { patches ? [ ], ... }: { patches = patches ++ [ # See https://github.com/curl/curl/commit/2a2104f3cff44bb28bb570a093be52bbeeed8f23 (fetchpatch2 { name = "fix-wakeup-consumption-revert.patch"; url = "https://github.com/curl/curl/commit/2a2104f3cff44bb28bb570a093be52bbeeed8f23.patch"; hash = "sha256-dkwr1ZaR7XB408JxeIKhuHxJrlwf3J01jL6lnOLXo1I="; revert = true; }) ]; } ) else # Filter out the version backported in Nixpkgs # https://github.com/NixOS/nixpkgs/issues/534713#event-27130052199 curl.overrideAttrs (prev: { patches = lib.filter (patch: !lib.strings.hasSuffix "fix-wakeup-consumption.patch" patch) ( prev.patches or [ ] ); }); # Avoid a bunch of build closure of the tracer, we just need the dtrace # generator. systemtap-lix = buildPackages.linuxPackages.systemtap.override { withStap = false; }; build-release-notes = callPackage ./maintainers/build-release-notes.nix { }; }, }: # gcc miscompiles coroutines at least until 13.2, possibly longer assert stdenv.cc.isClang; let inherit (__forDefaults) canRunInstalled; inherit (lib) fileset; inherit (stdenv) hostPlatform buildPlatform; version = __forDefaults.versionJson.version + versionSuffix; # This could be the dtrace for macOS, etc, but I have no idea if it is # packaged or if it works. dtrace-generator = if withDtrace then systemtap-lix else null; # This is for sys/sdt.h dtrace-headers = if withDtrace then libsystemtap else null; # FIXME(jade): can be removed once our nixpkgs has https://github.com/NixOS/nixpkgs/pull/435749 (probably 25.11?) dontWrapPython = drv: drv.overridePythonAttrs (old: { dontWrapPythonPrograms = true; }); aws-sdk-cpp-nix = if aws-sdk-cpp == null then null else (aws-sdk-cpp.override { apis = [ "s3" "transfer" ]; customMemoryManagement = false; }).overrideAttrs { # this overrideAttrs is needed to match the configuration of # aws-sdk-cpp in nixpkgs' builds of lix so we don't rebuild this in # practice requiredSystemFeatures = [ ]; }; # Reimplementation of Nixpkgs' Meson cross file, with some additions to make # it actually work. mesonCrossFile = deps: runCommand "lix-cross-file.conf" { input = '' [properties] # Meson is convinced that if !buildPlatform.canExecute hostPlatform then we cannot # build anything at all, which is not at all correct. If we can't execute the host # platform, we'll just disable tests and doc gen. needs_exe_wrapper = false [binaries] # Meson refuses to consider any CMake binary during cross compilation if it's # not explicitly specified here, in the cross file. # https://github.com/mesonbuild/meson/blob/0ed78cf6fa6d87c0738f67ae43525e661b50a8a2/mesonbuild/cmake/executor.py#L72 cmake = 'cmake' [project options] builtin-dep-closure = @deps@ ''; passAsFile = [ "input" ]; } '' substitute $inputPath $out --replace-fail @deps@ "$(cat ${deps})" ''; mesonNativeFile = deps: runCommand "lix-native-file.conf" { input = '' [project options] builtin-dep-closure = @deps@ ''; passAsFile = [ "input" ]; } '' substitute $inputPath $out --replace-fail @deps@ "$(cat ${deps})" ''; # Remove once https://github.com/NixOS/nixpkgs/pull/476848 lands here. pyxattrForPython = p: p.pyxattr.overrideAttrs (old: { buildInputs = lib.filter (lib.meta.availableOn stdenv.hostPlatform) old.buildInputs; meta.platforms = old.meta.platforms ++ lib.platforms.darwin; }); inputsForPython = p: [ p.python-frontmatter p.pycapnp ]; checkInputsForPython = p: [ (dontWrapPython p.pytest) p.pytest-xdist p.pytest-timeout p.tappy p.ruff p.aiohttp p.mistletoe (pyxattrForPython p) ]; devShellInputsForPython = p: [ p.yapf p.requests p.xdg-base-dirs p.packaging p.xonsh ]; # The internal API docs need these for the build, but if we're not building # Nix itself, then these don't need to be propagated. maybePropagatedInputs = lib.optional enableGC boehmgc-nix ++ [ nlohmann_json ]; # .gitignore has already been processed, so any changes in it are irrelevant # at this point. It is not represented verbatim for test purposes because # that would interfere with repo semantics. baseFiles = fileset.fileFilter (f: f.name != ".gitignore") ./.; configureFiles = fileset.unions [ ./version.json ]; topLevelBuildFiles = fileset.unions ([ ./meson.build ./meson.options ./meson ./scripts/meson.build (fileset.fileFilter (f: lib.strings.hasSuffix ".wrap" f.name) ./subprojects) ./subprojects/aws_sdk ./tools # Required for meson to generate Cargo wraps ./Cargo.lock ./Cargo.toml ./.cargo/config.toml ]); functionalTestFiles = fileset.unions [ ./tests/functional ./tests/functional2 ./tests/unit (fileset.fileFilter (f: lib.strings.hasPrefix "nix-profile" f.name) ./scripts) ]; # Nixpkgs only provides an lld wrapper if the entire Nixpkgs is instantiated with "linker = lld", # but we can just make one ourselves. lldBintools = wrapBintoolsWith { bintools = llvmPackages.bintools; }; # Rustc will use `cc` as the linker by default, but we need to link the C++ standard library. # However the C++ compiler is not unprefixed `c++` in Nixpkgs when cross compiling. # This is a fair amount of logic to encode in a Cargo config.toml, so the most reasonable # options are to have meson `configure_file()` a config.toml, # or just use these environment variables. cxxLinkerFor = stdenv: lib.getExe' stdenv.cc "${stdenv.cc.targetPrefix}c++"; hostCargoEnvVar = hostPlatform.rust.cargoEnvVarTarget; buildCargoEnvVar = buildPlatform.rust.cargoEnvVarTarget; # Environment variables that set Cargo config values. cargoConfigEnv = { "CARGO_TARGET_${hostCargoEnvVar}_LINKER" = cxxLinkerFor stdenv; } // lib.optionalAttrs (hostCargoEnvVar != buildCargoEnvVar) { "CARGO_TARGET_${buildCargoEnvVar}_LINKER" = cxxLinkerFor buildPackages.clangStdenv; }; in assert (lintInsteadOfBuild -> lix-clang-tidy != null); stdenv.mkDerivation (finalAttrs: { inherit pname version; __structuredAttrs = true; # python3.withPackages does not splice properly, see https://github.com/NixOS/nixpkgs/issues/305858 lixPythonForBuild = python3.pythonOnBuildForHost.withPackages ( p: lib.concatLists [ (inputsForPython p) (lib.optionals finalAttrs.doCheck (checkInputsForPython p)) ] ); # precompile the bridge generator since the zngur parser takes so long to build. this way we can # cache the generator in ci and for devshells, both of which decrease cycle times by quite a bit licxxbridge = rustPlatform.buildRustPackage { pname = "licxxbridge"; version = "0.0.0"; src = fileset.toSource { root = ./.; fileset = fileset.unions [ ./Cargo.toml ./Cargo.lock ./tools/licxxbridge # these are only needed to let cargo parse the manifests at all, they're not used elsewise ./lix/lix-doc/Cargo.toml ./lix/lix-doc/src/lib.rs ./lix/lix-rs/Cargo.toml ./lix/lix-rs/src/lib.rs ]; }; cargoDeps = rustPlatform.importCargoLock { lockFile = ./Cargo.lock; }; cargoBuildFlags = [ "-p" "licxxbridge" ]; cargoTestFlags = [ "-p" "licxxbridge" ]; meta.mainProgram = "licxxbridge"; }; buildTestShell = if hostPlatform.isLinux then "${pkgsStatic.bash}/bin" else if hostPlatform.isDarwin then "${bash}/bin" else null; buildTestEnv = if hostPlatform.isLinux then lib.makeBinPath [ pkgsStatic.busybox pkgsStatic.acl ] else lib.makeBinPath [ pkgs.darwin.file_cmds pkgs.darwin.shell_cmds pkgs.darwin.text_cmds ]; src = fileset.toSource { root = ./.; fileset = fileset.intersection baseFiles ( fileset.unions ( [ configureFiles topLevelBuildFiles functionalTestFiles ] ++ lib.optionals (!finalAttrs.dontBuild || internalApiDocs || lintInsteadOfBuild) [ ./doc ./lix ./misc ./contrib/plugins ./COPYING ] ++ lib.optionals lintInsteadOfBuild [ ./.clang-tidy ] ) ); }; outputs = [ "out" ] ++ lib.optionals (!finalAttrs.dontBuild) [ "dev" "doc" ]; dontBuild = lintInsteadOfBuild; mesonFlags = let sanitizeOpts = lib.optional ( sanitize != null ) "-Db_sanitize=${builtins.concatStringsSep "," sanitize}"; in lib.optionals hostPlatform.isLinux [ # You'd think meson could just find this in PATH, but busybox is in buildInputs, # which don't actually get added to PATH. And buildInputs is correct over # nativeBuildInputs since this should be a busybox executable on the host. "-Dsandbox-shell=${lib.getExe' busybox-sandbox-shell "busybox"}" "-Dpasta-path=${lib.getExe' passt "pasta"}" ] ++ lib.optional ( finalAttrs.buildTestShell != null ) "-Dbuild-test-shell=${finalAttrs.buildTestShell}" ++ lib.optional (finalAttrs.buildTestEnv != null) "-Dbuild-test-env=${finalAttrs.buildTestEnv}" ++ lib.optionals useLld [ "-Dc_link_args=-fuse-ld=lld" "-Dcpp_link_args=-fuse-ld=lld" ] ++ lib.optionals hostPlatform.isStatic [ "-Denable-embedded-sandbox-shell=true" "-Denable-contrib-plugins=false" "-Db_sanitize=none" ] ++ lib.optional ciBuildAndDeleteBothLibraries "-Ddefault_library=both" # musl doesn't support fibers, and we can't detect this with meson alone. ++ lib.optional hostPlatform.isMusl "-Ddisable-fibers=true" ++ lib.optional (finalAttrs.dontBuild && !lintInsteadOfBuild) "-Denable-build=false" ++ lib.optional (!finalAttrs.dontBuild) "-Dlicxxbridge=${lib.getExe finalAttrs.licxxbridge}" ++ lib.optional lintInsteadOfBuild "-Dlix-clang-tidy-checks-path=${lix-clang-tidy}/lib/liblix-clang-tidy.${ if hostPlatform.isDarwin then "dylib" else "so" }" ++ [ # mesonConfigurePhase automatically passes -Dauto_features=enabled, # so we must explicitly enable or disable features that we are not passing # dependencies for. (lib.mesonEnable "gc" enableGC) (lib.mesonEnable "internal-api-docs" internalApiDocs) (lib.mesonEnable "dtrace-probes" withDtrace) (lib.mesonBool "enable-tests" (finalAttrs.finalPackage.doCheck || lintInsteadOfBuild)) (lib.mesonBool "enable-docs" canRunInstalled) (lib.mesonBool "werror" werror) ] ++ lib.optional ( hostPlatform != buildPlatform ) "--cross-file=${mesonCrossFile finalAttrs.builtinDeps}" ++ lib.optional ( hostPlatform == buildPlatform ) "--native-file=${mesonNativeFile finalAttrs.builtinDeps}" # Temporary workaround for https://git.lix.systems/lix-project/lix/issues/832 ++ lib.optional (hostPlatform.isDarwin) "-Db_lto=false" ++ sanitizeOpts; # We only include CMake so that Meson can locate toml11, which only ships CMake dependency metadata. dontUseCmakeConfigure = true; # depsBuildBuild is put in PATH before nativeBuildInputs, but clangStdenv.cc's version # of clang-tidy doesn't seem to work. Thankfully, if we're linting, we don't need to # compile things for the build platform either. depsBuildBuild = lib.optionals (!lintInsteadOfBuild) [ # clangStdenv is spliced but clangStdenv.cc is not: # https://github.com/NixOS/nixpkgs/issues/211340 buildPackages.clangStdenv.cc ]; nativeBuildInputs = [ rustPlatform.cargoSetupHook finalAttrs.lixPythonForBuild meson ninja cmake rustc cargo capnproto # Required for libstd++ assertions that leaks inside of the final binary. removeReferencesTo dtrace-generator ] ++ [ (lib.getBin lowdown-unsandboxed) (lib.warnIf ( # if mdbook 0.5 is backported to 25.11 (lib.trivial.release == "25.11" && lib.versionAtLeast mdbook.version "0.5.0") # or 25.11 is EOL || (lib.trivial.oldestSupportedRelease > 2511) ) "Workarounds for mdbook 0.4.x/0.5.x interoperability can be removed as 0.5.0 is in nixpkgs-stable" mdbook ) mdbook-linkcheck2 ] ++ [ pkg-config # Tests git mercurial jq yq lsof zstd # For mTLS tests curl-lix ] ++ lib.optional useLld lldBintools ++ lib.optional hostPlatform.isLinux util-linuxMinimal ++ lib.optional (!officialRelease && buildUnreleasedNotes) build-release-notes ++ lib.optional internalApiDocs doxygen ++ lib.optionals lintInsteadOfBuild [ llvmPackages.libllvm # required for a wrapped clang-tidy llvmPackages.clang-tools # load-bearing order (just as below); the actual stdenv wrapped clang # needs to precede the unwrapped clang in PATH such that calling `clang` # can compile things. stdenv.cc # required for run-clang-tidy llvmPackages.clang-unwrapped ]; buildInputs = [ curl-lix bzip2 xz brotli openssl sqlite libarchive boost lowdown toml11 pegtl capnproto dtrace-headers ] # NOTE(Raito): I'd have expected that the LLVM packaging would inject the # libunwind library path directly in the wrappers, but it does inject # -lunwind without injecting the library path... ++ lib.optionals stdenv.hostPlatform.isStatic [ llvmPackages.libunwind ] ++ lib.optionals hostPlatform.isLinux [ libseccomp passt ] ++ lib.optional internalApiDocs rapidcheck ++ lib.optional hostPlatform.isx86_64 libcpuid # There have been issues building these dependencies ++ lib.optional (hostPlatform.canExecute buildPlatform) aws-sdk-cpp-nix ++ lib.optionals (finalAttrs.dontBuild) maybePropagatedInputs # I am so sorry. This is because checkInputs are required to pass # configure, but we don't actually want to *run* the checks here. ++ lib.optionals lintInsteadOfBuild finalAttrs.checkInputs; checkInputs = [ gtest (rapidcheck.overrideAttrs (old: { patches = (old.patches or [ ]) ++ [ ./misc/rapidcheck-gen-hpp.patch ]; })) ]; propagatedBuildInputs = lib.optionals (!finalAttrs.dontBuild) maybePropagatedInputs; disallowedReferences = [ boost buildPackages.python3 finalAttrs.lixPythonForBuild ]; # dep closure for builtin builders in meson array form for immediate use builtinDeps = if hostPlatform.isStatic then builtins.toFile "lix-static-dep-closure" "[]" else runCommand "lix-builtin-dep-closure" { closure = closureInfo { # closureInfo does not work all that well for things like lowdown, # where it finds only -out but not -lib. we'll take -out and -lib, # ignoring -bin, -man, -dev, etc. and hope that'll be good enough. rootPaths = lib.flatten ( map (drv: [ (drv.out or [ ]) (drv.lib or [ ]) ]) ( lib.subtractLists finalAttrs.disallowedReferences ( finalAttrs.buildInputs ++ finalAttrs.propagatedBuildInputs # include compiler wrapper as an input to get the sanitizer libraries too ++ lib.optional includeSanitizerLibs stdenv.cc ) ) ); }; } '' closure=($(cat $closure/store-paths)) closure="$(printf ", '%s'" "''${closure[@]}")" printf "[%s]" "''${closure:2}" >$out ''; env = { # Meson allows referencing a /usr/share/cargo/registry shaped thing for subproject sources. # Turns out the Nix-generated Cargo dependencies are named the same as they # would be in a Cargo registry cache. MESON_PACKAGE_CACHE_DIR = finalAttrs.cargoDeps; VERSION_SUFFIX = versionSuffix; } # Putting these here means they'll also work in the dev shell. // cargoConfigEnv // lib.optionalAttrs (finalAttrs.buildTestEnv != null) { BUILD_TEST_ENV = finalAttrs.buildTestEnv; } // lib.optionalAttrs (finalAttrs.buildTestShell != null) { BUILD_TEST_SHELL = finalAttrs.buildTestShell; } // lib.optionalAttrs hostPlatform.isStatic { NIX_CFLAGS_COMPILE = " -static"; } // lib.optionalAttrs (hostPlatform.isStatic && stdenv.cc.libcxx == null) { # pkgsStatic.clangStdenv.cc does not have the correct libstdc++. # It's using pkgsStatic.buildPackages.gcc.cc, whose libstdc++ appears # to have object files that were compiled with -fno-pic, # (R_X86_64_32, R_X86_64_32S, and R_X86_64_TPOFF32 relocations). # pkgsStatic.gcc.cc's libstdc++ has the correct relocations, but idk # what the correct `wrapCCWith`/`stdenv.cc.override` incantation is. # But just putting that libstdc++ in `-L` seems to make the driver find # the right things. NIX_CFLAGS_LINK = "-L${lib.getLib pkgsStatic.gcc.cc}/lib"; }; cargoDeps = rustPlatform.importCargoLock { lockFile = ./Cargo.lock; }; preConfigure = '' # Fix up /usr/bin/env shebangs relied on by the build patchShebangs --build tests/ doc/manual/ ''; mesonBuildType = "debugoptimized"; installTargets = lib.optional internalApiDocs "internal-api-html"; enableParallelBuilding = true; doCheck = canRunInstalled && !lintInsteadOfBuild; mesonCheckFlags = [ "--suite=check" ]; # the tests access localhost. __darwinAllowLocalNetworking = true; # Make sure the internal API docs are already built, because mesonInstallPhase # won't let us build them there. They would normally be built in buildPhase, # but the internal API docs are conventionally built with doBuild = false. preInstall = (lib.optionalString internalApiDocs '' meson ''${mesonBuildFlags:-} compile "$installTargets" '') # evil, but like above, we do not want to run an actual build phase + lib.optionalString lintInsteadOfBuild '' ninja clang-tidy ''; installPhase = lib.optionalString lintInsteadOfBuild '' runHook preInstall touch $out runHook postInstall ''; postInstall = lib.optionalString (!finalAttrs.dontBuild) '' mkdir -p $doc/nix-support echo "doc manual $doc/share/doc/nix/manual" >> $doc/nix-support/hydra-build-products '' + lib.optionalString ciBuildAndDeleteBothLibraries '' rm -f $out/lib/liblix{cmd,expr,fetchers,main,store,util}${hostPlatform.extensions.staticLibrary} '' + lib.optionalString hostPlatform.isStatic '' mkdir -p $out/nix-support echo "file binary-dist $out/bin/nix" >> $out/nix-support/hydra-build-products '' + lib.optionalString internalApiDocs '' mkdir -p $out/nix-support echo "doc internal-api-docs $out/share/doc/nix/internal-api/html" >> "$out/nix-support/hydra-build-products" '' + lib.optionalString (sanitize == null) '' # Drop all references to libstd++ include files due to `__FILE__` leaking in libstd++ assertions. # we do NOT want to do this during asan builds because it breaks the test suite! but as we do not # actually want to ship asan builds in any reasonable capacity the leak will not matter that much find "$out" -type f -exec remove-references-to -t ${stdenv.cc.cc.stdenv.cc.cc} '{}' + ''; doInstallCheck = finalAttrs.doCheck; mesonInstallCheckFlags = [ "--suite=installcheck" "--max-lines=10000" ]; installCheckPhase = '' runHook preInstallCheck ( unset -v preCheck preCheckHooks postCheck postCheckHooks mesonCheckFlags=("''${mesonInstallCheckFlags[@]}") mesonCheckPhase ) runHook postInstallCheck ''; # NOTE: This is disabled everywhere except Darwin due to Nixpkgs # corrupting `.debug_gdb_scripts` segments (which currently aren't used on Darwin) separateDebugInfo = !hostPlatform.isStatic && !finalAttrs.dontBuild && hostPlatform.isDarwin; strictDeps = true; # strictoverflow is disabled because we trap on signed overflow instead hardeningDisable = [ "strictoverflow" ]; meta = { mainProgram = "nix"; platforms = lib.platforms.unix; }; # Export the patched version of boehmgc. # flake.nix exports that into its overlay. passthru = { inherit (__forDefaults) boehmgc-nix curl-lix build-release-notes pegtl ; # The collection of dependency logic for this derivation is complicated enough that # it's easier to parameterize the devShell off an already called package.nix. mkDevShell = { pkgsBuildHost, mkShell, bashInteractive, clangbuildanalyzer, doxygen, glibcLocales, just, nixfmt, skopeo, tree, # Lix specific packages pre-commit-checks, contribNotice, check-syscalls, # Rust development tools rust-analyzer, cargo, rustc, rustfmt, rustPlatform, # debuggers gdb, rr, }: let glibcFix = lib.optionalAttrs (buildPlatform.isLinux && glibcLocales != null) { # Required to make non-NixOS Linux not complain about missing locale files during configure in a dev shell LOCALE_ARCHIVE = "${lib.getLib pkgsBuildHost.glibcLocales}/lib/locale/locale-archive"; }; # FIXME: these have to be added twice due to the nix shell using a # wrapped python instead of build inputs for its python inputs pythonEnv = python3.pythonOnBuildForHost.withPackages ( p: lib.concatLists [ (inputsForPython p) (checkInputsForPython p) (devShellInputsForPython p) ] ); # pkgs.mkShell uses pkgs.stdenv by default, regardless of inputsFrom. actualMkShell = mkShell.override { inherit stdenv; }; in actualMkShell ( glibcFix // { name = "lix-shell-env"; # finalPackage is necessary to propagate stuff that is set by mkDerivation itself, # like doCheck. inputsFrom = [ finalAttrs.finalPackage ]; # For Meson to find Boost. env = finalAttrs.env; mesonFlags = # I guess this is necessary because mesonFlags to mkDerivation doesn't propagate in inputsFrom, # which only propagates stuff set in hooks? idk. finalAttrs.mesonFlags # Clangd breaks when GCC is using precompiled headers, so for the devshell specifically # we make precompiled C++ stdlib conditional on using Clang. # https://git.lix.systems/lix-project/lix/issues/374 ++ [ (lib.mesonBool "enable-pch-std" stdenv.cc.isClang) ]; depsBuildBuild = [ # From a strict deps point-of-view, I'm pretty sure this is literally incorrect. # The clang-tidy from clang-tools is for checking source files that are compiled # for the host machine. # However, we need a clang-tools version of clang-tidy in PATH before # clangStdenv.cc, and it seems like all depsBuildBuild things come before # "packages" things. # I also tried just putting these in `packages` with the correct ordering, # but that did not work. # I guess the platform offsets really do matter here, even in the devshell. buildPackages.llvmPackages.clang-tools # This *has* clang-tidy, but it doesn't (seem to?) work. buildPackages.clangStdenv.cc ]; packages = lib.optional (stdenv.cc.isClang && hostPlatform == buildPlatform) llvmPackages.clang-tools ++ [ # Why are we providing a bashInteractive? Well, when you run # `bash` from inside `nix develop`, say, because you are using it # via direnv, you will by default get bash (unusable edition). bashInteractive check-syscalls pythonEnv # docker image tool skopeo just nixfmt # Included above when internalApiDocs is true, but we set that to # false intentionally to save dev build time. # To build them in a dev shell, you can set -Dinternal-api-docs=enabled when configuring. doxygen # Load-bearing order. Must come before clang-unwrapped below, but after clang_tools above. stdenv.cc # git-clang-format llvmPackages.libclang.python # Required for releng scripts tree ] ++ [ rust-analyzer cargo rustc rustfmt rustPlatform.rustLibSrc rustPlatform.rustcSrc ] ++ lib.optionals stdenv.cc.isClang [ # Required for clang-tidy checks. llvmPackages.llvm llvmPackages.clang-unwrapped.dev ] ++ lib.optionals (pre-commit-checks ? enabledPackages) pre-commit-checks.enabledPackages ++ lib.optional (lib.meta.availableOn buildPlatform clangbuildanalyzer) clangbuildanalyzer ++ lib.optional (!stdenv.isDarwin) gdb ++ lib.optional (lib.meta.availableOn buildPlatform rr && hostPlatform == buildPlatform) rr ++ finalAttrs.checkInputs; shellHook = '' # don't re-run the hook in (other) nested nix-shells function lixShellHook() { # n.b. how the heck does this become -env-env? well, `nix develop` does it: # https://git.lix.systems/lix-project/lix/src/commit/7575db522e9008685c4009423398f6900a16bcce/src/nix/develop.cc#L240-L241 # this is, of course, absurd. if [[ $name != lix-shell-env && $name != lix-shell-env-env ]]; then return fi PATH=$prefix/bin''${PATH:+:''${PATH}} unset PYTHONPATH export MANPATH=$out/share/man:''${MANPATH:-} # default build dir. lets rust-analyzer find generated code export MESON_BUILD_DIR="$PWD/build" # Make bash completion work. XDG_DATA_DIRS+=:$out/share if [[ ! -f ./.this-is-lix ]]; then echo "Dev shell not started from inside a Lix repo, skipping repo setup" >&2 return fi ${lib.optionalString (pre-commit-checks ? shellHook) pre-commit-checks.shellHook} # Allow `touch .nocontribmsg` to turn this notice off. if ! [[ -f .nocontribmsg ]]; then cat ${contribNotice} fi # Install the Gerrit commit-msg hook. # (git common dir is the main .git, including for worktrees) if gitcommondir=$(git rev-parse --git-common-dir 2>/dev/null) && [[ ! -f "$gitcommondir/hooks/commit-msg" ]]; then echo 'Installing Gerrit commit-msg hook (adds Change-Id to commit messages)' >&2 mkdir -p "$gitcommondir/hooks" curl -s -Lo "$gitcommondir/hooks/commit-msg" https://gerrit.lix.systems/tools/hooks/commit-msg chmod u+x "$gitcommondir/hooks/commit-msg" fi unset gitcommondir } lixShellHook ''; } ); perl-bindings = pkgs.callPackage ./perl { inherit fileset stdenv; nix = finalAttrs.finalPackage; }; binaryTarball = pkgs.callPackage ./nix-support/binary-tarball.nix { nix = finalAttrs.finalPackage; }; }; })