mirror of
https://github.com/NixOS/nix.git
synced 2025-11-22 02:09:36 +01:00
Makes the cross-x86_64-w64-mingw32 devshell slightly less broken. It still needs a bit of massaging to function, but that's much less cumbersome now that the generic machinery with genericClosure that evaluates drvPath doesn't barf on unavailable packages.
337 lines
10 KiB
Nix
337 lines
10 KiB
Nix
{
|
|
lib,
|
|
devFlake,
|
|
}:
|
|
|
|
let
|
|
# Some helper functions
|
|
|
|
/**
|
|
Compute a filtered closure of build inputs.
|
|
|
|
Specifically, `buildInputsClosure cond startSet` computes the closure formed
|
|
by recursive application of `p: filter cond p.buildInputs ++ filter cond p.propagatedBuildInputs`
|
|
to `startSet`.
|
|
|
|
Example:
|
|
```nix
|
|
builtInputsClosure isInternal [ pkg1 pkg2 ]
|
|
=> [ pkg1 pkg3 pkg2 pkg10 ]
|
|
```
|
|
|
|
Note: order tbd
|
|
|
|
Note: `startSet` is *NOT* filtered.
|
|
*/
|
|
buildInputsClosureCond =
|
|
cond: startSet:
|
|
let
|
|
closure = builtins.genericClosure {
|
|
startSet = map (d: {
|
|
key = d.drvPath;
|
|
value = d;
|
|
}) startSet;
|
|
operator =
|
|
d:
|
|
let
|
|
r =
|
|
map
|
|
(d': {
|
|
key = d'.drvPath;
|
|
value = d';
|
|
})
|
|
(
|
|
lib.filter cond d.value.buildInputs or [ ] ++ lib.filter cond d.value.propagatedBuildInputs or [ ]
|
|
);
|
|
in
|
|
r;
|
|
};
|
|
in
|
|
map (item: item.value) closure;
|
|
|
|
/**
|
|
`[ pkg1 pkg2 ]` -> `{ "...-pkg2.drv" = null; "...-pkg1.drv" = null }`
|
|
|
|
Note: fairly arbitrary order (hash based). Use for efficient set membership test only.
|
|
*/
|
|
byDrvPath =
|
|
l:
|
|
lib.listToAttrs (
|
|
map (c: {
|
|
name =
|
|
# Just a lookup key
|
|
builtins.unsafeDiscardStringContext c.drvPath;
|
|
value = null;
|
|
}) l
|
|
);
|
|
|
|
/**
|
|
Stable dedup.
|
|
|
|
Unlike `listToAttrs` -> `attrValues`, this preserves the input ordering,
|
|
which is more predictable ("deterministic") than e.g. sorting store paths,
|
|
whose hashes affect the ordering on every change.
|
|
*/
|
|
# TODO: add to Nixpkgs lib, refer from uniqueStrings
|
|
dedupByString =
|
|
key: l:
|
|
let
|
|
r =
|
|
lib.foldl'
|
|
(
|
|
a@{ list, set }:
|
|
elem:
|
|
let
|
|
k = builtins.unsafeDiscardStringContext (key elem);
|
|
in
|
|
if set ? ${k} then
|
|
a
|
|
else
|
|
let
|
|
# Note: O(n²) copying. Use linkedLists to concat them in one go at the end.
|
|
# https://github.com/NixOS/nixpkgs/pull/452088
|
|
newList = [ elem ] ++ list;
|
|
newSet = set // {
|
|
${k} = null;
|
|
};
|
|
in
|
|
builtins.seq newList builtins.seq newSet {
|
|
list = newList;
|
|
set = newSet;
|
|
}
|
|
)
|
|
{
|
|
list = [ ];
|
|
set = { };
|
|
}
|
|
l;
|
|
in
|
|
r.list;
|
|
|
|
in
|
|
|
|
{ pkgs }:
|
|
|
|
# TODO: don't use nix-util for this?
|
|
pkgs.nixComponents2.nix-util.overrideAttrs (
|
|
finalAttrs: prevAttrs:
|
|
|
|
let
|
|
stdenv = pkgs.nixDependencies2.stdenv;
|
|
buildCanExecuteHost = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
|
|
modular = devFlake.getSystem stdenv.buildPlatform.system;
|
|
transformFlag =
|
|
prefix: flag:
|
|
assert builtins.isString flag;
|
|
let
|
|
rest = builtins.substring 2 (builtins.stringLength flag) flag;
|
|
in
|
|
"-D${prefix}:${rest}";
|
|
havePerl = stdenv.buildPlatform == stdenv.hostPlatform && stdenv.hostPlatform.isUnix;
|
|
ignoreCrossFile = flags: builtins.filter (flag: !(lib.strings.hasInfix "cross-file" flag)) flags;
|
|
|
|
availableComponents = lib.filterAttrs (
|
|
k: v: lib.meta.availableOn pkgs.hostPlatform v
|
|
) allComponents;
|
|
|
|
activeComponents = buildInputsClosureCond isInternal (
|
|
lib.attrValues (finalAttrs.passthru.config.getComponents availableComponents)
|
|
);
|
|
|
|
allComponents = lib.filterAttrs (k: v: lib.isDerivation v) pkgs.nixComponents2;
|
|
internalDrvs = byDrvPath (
|
|
# Drop the attr names (not present in buildInputs anyway)
|
|
lib.attrValues availableComponents
|
|
++ lib.concatMap (c: lib.attrValues c.tests or { }) (lib.attrValues availableComponents)
|
|
);
|
|
|
|
isInternal =
|
|
dep: internalDrvs ? ${builtins.unsafeDiscardStringContext dep.drvPath or "_non-existent_"};
|
|
|
|
in
|
|
{
|
|
pname = "shell-for-nix";
|
|
|
|
passthru = {
|
|
inherit activeComponents;
|
|
|
|
# We use this attribute to store non-derivation values like functions and
|
|
# perhaps other things that are primarily for overriding and not the shell.
|
|
config = {
|
|
# Default getComponents
|
|
getComponents =
|
|
c:
|
|
builtins.removeAttrs c (
|
|
lib.optionals (!havePerl) [ "nix-perl-bindings" ]
|
|
++ lib.optionals (!buildCanExecuteHost) [ "nix-manual" ]
|
|
);
|
|
};
|
|
|
|
/**
|
|
Produce a devShell for a given set of nix components
|
|
|
|
Example:
|
|
|
|
```nix
|
|
shell.withActiveComponents (c: {
|
|
inherit (c) nix-util;
|
|
})
|
|
```
|
|
*/
|
|
withActiveComponents =
|
|
f2:
|
|
finalAttrs.finalPackage.overrideAttrs (
|
|
finalAttrs: prevAttrs: {
|
|
passthru = prevAttrs.passthru // {
|
|
config = prevAttrs.passthru.config // {
|
|
getComponents = f2;
|
|
};
|
|
};
|
|
}
|
|
);
|
|
|
|
small =
|
|
(finalAttrs.finalPackage.withActiveComponents (
|
|
c:
|
|
lib.intersectAttrs (lib.genAttrs [
|
|
"nix-cli"
|
|
"nix-util-tests"
|
|
"nix-store-tests"
|
|
"nix-expr-tests"
|
|
"nix-fetchers-tests"
|
|
"nix-flake-tests"
|
|
"nix-functional-tests"
|
|
"nix-perl-bindings"
|
|
] (_: null)) c
|
|
)).overrideAttrs
|
|
(o: {
|
|
mesonFlags = o.mesonFlags ++ [
|
|
# TODO: infer from activeComponents or vice versa
|
|
"-Dkaitai-struct-checks=false"
|
|
"-Djson-schema-checks=false"
|
|
];
|
|
});
|
|
};
|
|
|
|
# Remove the version suffix to avoid unnecessary attempts to substitute in nix develop
|
|
version = lib.fileContents ../.version;
|
|
name = finalAttrs.pname;
|
|
|
|
installFlags = "sysconfdir=$(out)/etc";
|
|
shellHook = ''
|
|
PATH=$prefix/bin:$PATH
|
|
unset PYTHONPATH
|
|
export MANPATH=$out/share/man:$MANPATH
|
|
|
|
# Make bash completion work.
|
|
XDG_DATA_DIRS+=:$out/share
|
|
|
|
# Make the default phases do the right thing.
|
|
# FIXME: this wouldn't be needed if the ninja package set buildPhase() instead of $buildPhase.
|
|
# FIXME: mesonConfigurePhase shouldn't cd to the build directory. It would be better to pass '-C <dir>' to ninja.
|
|
|
|
cdToBuildDir() {
|
|
if [[ ! -e build.ninja ]]; then
|
|
cd build
|
|
fi
|
|
}
|
|
|
|
configurePhase() {
|
|
mesonConfigurePhase
|
|
}
|
|
|
|
buildPhase() {
|
|
cdToBuildDir
|
|
ninjaBuildPhase
|
|
}
|
|
|
|
checkPhase() {
|
|
cdToBuildDir
|
|
mesonCheckPhase
|
|
}
|
|
|
|
installPhase() {
|
|
cdToBuildDir
|
|
ninjaInstallPhase
|
|
}
|
|
'';
|
|
|
|
# We use this shell with the local checkout, not unpackPhase.
|
|
src = null;
|
|
# Workaround https://sourceware.org/pipermail/gdb-patches/2025-October/221398.html
|
|
# Remove when gdb fix is rolled out everywhere.
|
|
separateDebugInfo = false;
|
|
|
|
env = {
|
|
# For `make format`, to work without installing pre-commit
|
|
_NIX_PRE_COMMIT_HOOKS_CONFIG = "${(pkgs.formats.yaml { }).generate "pre-commit-config.yaml"
|
|
modular.pre-commit.settings.rawConfig
|
|
}";
|
|
}
|
|
// lib.optionalAttrs stdenv.hostPlatform.isLinux {
|
|
CC_LD = "mold";
|
|
CXX_LD = "mold";
|
|
};
|
|
|
|
dontUseCmakeConfigure = true;
|
|
|
|
mesonFlags =
|
|
map (transformFlag "libutil") (ignoreCrossFile pkgs.nixComponents2.nix-util.mesonFlags)
|
|
++ map (transformFlag "libstore") (ignoreCrossFile pkgs.nixComponents2.nix-store.mesonFlags)
|
|
++ map (transformFlag "libfetchers") (ignoreCrossFile pkgs.nixComponents2.nix-fetchers.mesonFlags)
|
|
++ lib.optionals havePerl (
|
|
map (transformFlag "perl") (ignoreCrossFile pkgs.nixComponents2.nix-perl-bindings.mesonFlags)
|
|
)
|
|
++ map (transformFlag "libexpr") (ignoreCrossFile pkgs.nixComponents2.nix-expr.mesonFlags)
|
|
++ map (transformFlag "libcmd") (ignoreCrossFile pkgs.nixComponents2.nix-cmd.mesonFlags);
|
|
|
|
nativeBuildInputs =
|
|
let
|
|
inputs =
|
|
dedupByString (v: "${v}") (
|
|
lib.filter (x: !isInternal x) (lib.lists.concatMap (c: c.nativeBuildInputs) activeComponents)
|
|
)
|
|
++ lib.optional (
|
|
!buildCanExecuteHost
|
|
# Hack around https://github.com/nixos/nixpkgs/commit/bf7ad8cfbfa102a90463433e2c5027573b462479
|
|
&& !(stdenv.hostPlatform.isWindows && stdenv.buildPlatform.isDarwin)
|
|
&& stdenv.hostPlatform.emulatorAvailable pkgs.buildPackages
|
|
&& lib.meta.availableOn stdenv.buildPlatform (stdenv.hostPlatform.emulator pkgs.buildPackages)
|
|
) pkgs.buildPackages.mesonEmulatorHook
|
|
++ [
|
|
pkgs.buildPackages.gnused
|
|
modular.pre-commit.settings.package
|
|
(pkgs.writeScriptBin "pre-commit-hooks-install" modular.pre-commit.settings.installationScript)
|
|
pkgs.buildPackages.nixfmt-rfc-style
|
|
pkgs.buildPackages.shellcheck
|
|
pkgs.buildPackages.include-what-you-use
|
|
pkgs.buildPackages.gdb
|
|
]
|
|
++ lib.optional (stdenv.cc.isClang && stdenv.hostPlatform == stdenv.buildPlatform) (
|
|
lib.hiPrio pkgs.buildPackages.clang-tools
|
|
)
|
|
++ lib.optional stdenv.hostPlatform.isLinux pkgs.buildPackages.mold-wrapped;
|
|
in
|
|
# FIXME: separateDebugInfo = false doesn't actually prevent -Wa,--compress-debug-sections
|
|
# from making its way into NIX_CFLAGS_COMPILE.
|
|
lib.filter (p: !lib.hasInfix "separate-debug-info" p) inputs;
|
|
|
|
propagatedNativeBuildInputs = dedupByString (v: "${v}") (
|
|
lib.filter (x: !isInternal x) (
|
|
lib.lists.concatMap (c: c.propagatedNativeBuildInputs) activeComponents
|
|
)
|
|
);
|
|
|
|
buildInputs = [
|
|
pkgs.gbenchmark
|
|
]
|
|
++ dedupByString (v: "${v}") (
|
|
lib.filter (x: !isInternal x) (lib.lists.concatMap (c: c.buildInputs) activeComponents)
|
|
)
|
|
++ lib.optional havePerl pkgs.perl;
|
|
|
|
propagatedBuildInputs = dedupByString (v: "${v}") (
|
|
lib.filter (x: !isInternal x) (lib.lists.concatMap (c: c.propagatedBuildInputs) activeComponents)
|
|
);
|
|
}
|
|
)
|