diff --git a/lib/attrsets.nix b/lib/attrsets.nix index 0335146e2a6b4..04e32c3636cd7 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -840,6 +840,33 @@ rec { ) [pattern attrs])); + /* Pattern intersection. Specifically, the following is true + if it does not `throw`: + + forall patternList, + forall arg, + matchAttrs (intersectPatterns patternList) arg + == all (matchAttrs patternList) arg + + Type: + intersectPatterns :: [ AttrSet ] -> AttrSet + */ + intersectPatterns = let + inherit (lib) any unique isFunction elem; + inherit (lib.strings) concatStringsSep; + mergeLeaves = path: list: + let list' = unique list; in + # avoid introducing any new dependencies on function equality + assert any isFunction list -> throw "function found in pattern list at path '${concatStringsSep "." path}'"; + assert length list == 0 -> throw "this should not happen; path '${concatStringsSep "." path}'"; + assert length list' != 1 -> throw "disjoint patterns intersected at path '${concatStringsSep "." path}', values=${builtins.toString list'}"; + elemAt list' 0; + intersectPatterns' = path: list: + if !(any isAttrs list) then mergeLeaves path list + else if all isAttrs list then mapAttrs (k: v: intersectPatterns' (path++[k]) v) (zipAttrs list) + else throw "mix of attrsets and non-attrsets at path '${concatStringsSep "." path}', values = ${concatStringsSep "\n" (map builtins.toJSON list)}"; + in list: (intersectPatterns' [] list); + /* Override only the attributes that are already present in the old set useful for deep-overriding. diff --git a/lib/lists.nix b/lib/lists.nix index 5d9af0cf7114e..a60c634bd97e0 100644 --- a/lib/lists.nix +++ b/lib/lists.nix @@ -673,9 +673,15 @@ rec { => [ "13" "14" "23" "24" ] */ crossLists = builtins.trace - "lib.crossLists is deprecated, use lib.cartesianProductOfSets instead" + "lib.crossLists is deprecated, use lib.cartesianProductOfLists instead" (f: foldl (fs: args: concatMap (f: map f args) fs) [f]); + cartesianProductOfLists = lists: + let + inherit (lib) cartesianProductOfSets toString nameValuePair genAttrs attrValues; + attrs = builtins.listToAttrs (imap0 (i: nameValuePair (builtins.toString i)) lists); + cross = cartesianProductOfSets attrs; + in map attrValues cross; /* Remove duplicate elements from the list. O(n^2) complexity. diff --git a/lib/systems/default.nix b/lib/systems/default.nix index 78ccd50ba79a5..3482b87efc66c 100644 --- a/lib/systems/default.nix +++ b/lib/systems/default.nix @@ -27,6 +27,25 @@ rec { let removeFunctions = a: lib.filterAttrs (_: v: !builtins.isFunction v) a; in a: b: removeFunctions a == removeFunctions b; + # This function returns the elements of `systems.doubles.all` + # which match its argument, which can be either a pattern (see + # `lib.systems.inspect.patterns`) or a nix-double string. It is + # used mainly for backward compatibility with existing code that + # expects `meta.{bad,hydra,""}platforms` to be a list of strings. + doublesFromPattern = pattern: + if lib.isString pattern + then [pattern] + else lib.filter + (double: lib.meta.platformMatch (elaborate double) pattern) + doubles.all; + + # like above, but applied to a (disjunctive) list, with some + # optimizations for common cases on Hydra + doublesFromPatterns = patterns: + if lib.all lib.isString patterns + then patterns + else lib.concatMap doublesFromPattern patterns; + /* List of all Nix system doubles the nixpkgs flake will expose the package set for. All systems listed here must be supported by nixpkgs as `localSystem`. diff --git a/pkgs/development/compilers/ghc/9.2.4-binary.nix b/pkgs/development/compilers/ghc/9.2.4-binary.nix index 79b006ce5537b..1cad92fb7f0b0 100644 --- a/pkgs/development/compilers/ghc/9.2.4-binary.nix +++ b/pkgs/development/compilers/ghc/9.2.4-binary.nix @@ -38,11 +38,20 @@ let # set `exePathForLibraryCheck = null`. # * To skip file checking for a specific arch specfic library, # set `fileToCheckFor = null`. - ghcBinDists = { - # Binary distributions for the default libc (e.g. glibc, or libSystem on Darwin) - # nixpkgs uses for the respective system. - defaultLibc = { - i686-linux = { + ghcBinDists = + let + # return a disjunctive-list-of-patterns which is the intersection of its arguments + intersectPatternDisjunctions = lists: + (map lib.attrsets.intersectPatterns (lib.lists.cartesianProductOfLists lists)); + + # lib.systems.inspect.patterns are either disjunction-lists or + # singletons; wrap the singletons as a singleton-disjunction + patterns = lib.mapAttrs (_: lib.toList) lib.systems.inspect.patterns; + in { + # Binary distributions for the default libc (e.g. glibc, or libSystem on Darwin) + # nixpkgs uses for the respective system. + "i686-*-linux-gnu*" = { + patternList = with patterns; intersectPatternDisjunctions [ isx86_32 isLinux isGnu ]; variantSuffix = ""; src = { url = "${downloadsUrl}/${version}/ghc-${version}-i386-deb9-linux.tar.xz"; @@ -57,7 +66,8 @@ let { nixPackage = ncurses5; fileToCheckFor = "libtinfo.so.5"; } ]; }; - x86_64-linux = { + "x86_64-*-linux-gnu*" = { + patternList = with patterns; intersectPatternDisjunctions [ isx86_64 isLinux isGnu ]; variantSuffix = ""; src = { url = "${downloadsUrl}/${version}/ghc-${version}-x86_64-deb10-linux.tar.xz"; @@ -69,7 +79,8 @@ let { nixPackage = ncurses6; fileToCheckFor = "libtinfo.so.6"; } ]; }; - aarch64-linux = { + "aarch64-*-linux-gnu*" = { + patternList = with patterns; intersectPatternDisjunctions [ isAarch64 isLinux isGnu ]; variantSuffix = ""; src = { url = "${downloadsUrl}/${version}/ghc-${version}-aarch64-deb10-linux.tar.xz"; @@ -82,7 +93,8 @@ let { nixPackage = numactl; fileToCheckFor = null; } ]; }; - x86_64-darwin = { + "x86_64-*-darwin" = { + patternList = with patterns; intersectPatternDisjunctions [ isx86_64 isDarwin ]; variantSuffix = ""; src = { url = "${downloadsUrl}/${version}/ghc-${version}-x86_64-apple-darwin.tar.xz"; @@ -96,7 +108,8 @@ let ]; isHadrian = true; }; - aarch64-darwin = { + "aarch64-*-darwin" = { + patternList = with patterns; intersectPatternDisjunctions [ isAarch64 isDarwin ]; variantSuffix = ""; src = { url = "${downloadsUrl}/${version}/ghc-${version}-aarch64-apple-darwin.tar.xz"; @@ -110,10 +123,9 @@ let ]; isHadrian = true; }; - }; - # Binary distributions for the musl libc for the respective system. - musl = { - x86_64-linux = { + # Binary distributions for the musl libc for the respective system. + "x86_64-*-linux-musl" = { + patternList = with patterns; intersectPatternDisjunctions [ isx86_64 isLinux isMusl ]; variantSuffix = "-musl"; src = { url = "${downloadsUrl}/${version}/ghc-${version}-x86_64-alpine3.12-linux-gmp.tar.xz"; @@ -127,13 +139,20 @@ let { nixPackage = gmp.override { withStatic = true; }; fileToCheckFor = null; } ]; }; - }; }; - distSetName = if stdenv.hostPlatform.isMusl then "musl" else "defaultLibc"; - - binDistUsed = ghcBinDists.${distSetName}.${stdenv.hostPlatform.system} - or (throw "cannot bootstrap GHC on this platform ('${stdenv.hostPlatform.system}' with libc '${distSetName}')"); + binDistUsed = + let + inherit (stdenv) hostPlatform; + inherit (lib) filter concatSepStrings attrNames any attrValues; + pred = binDist: any (lib.meta.platformMatch hostPlatform) binDist.patternList; + in + lib.lists.findSingle + pred + (throw "cannot bootstrap GHC on ${hostPlatform.config}") + (throw "bug in nixpkgs, please report: ${hostPlatform.config} has multiple GHC bindists:"+ + " ${concatSepStrings " " (map attrNames (filter pred ghcBinDists))}") + (attrValues ghcBinDists); gmpUsed = (builtins.head ( builtins.filter ( @@ -416,17 +435,8 @@ stdenv.mkDerivation rec { homepage = "http://haskell.org/ghc"; description = "The Glasgow Haskell Compiler"; license = lib.licenses.bsd3; - # HACK: since we can't encode the libc / abi in platforms, we need - # to make the platform list dependent on the evaluation platform - # in order to avoid eval errors with musl which supports less - # platforms than the default libcs (i. e. glibc / libSystem). - # This is done for the benefit of Hydra, so `packagePlatforms` - # won't return any platforms that would cause an evaluation - # failure for `pkgsMusl.haskell.compiler.ghc922Binary`, as - # long as the evaluator runs on a platform that supports - # `pkgsMusl`. - platforms = builtins.attrNames ghcBinDists.${distSetName}; - hydraPlatforms = builtins.filter (p: minimal || p != "aarch64-linux") platforms; + platforms = lib.concatMap (binDist: binDist.patternList) (lib.attrValues ghcBinDists); + hydraPlatforms = builtins.filter (p: minimal || p != "aarch64-linux") (lib.systems.doublesFromPatterns platforms); maintainers = lib.teams.haskell.members; }; } diff --git a/pkgs/stdenv/generic/check-meta.nix b/pkgs/stdenv/generic/check-meta.nix index 63fd00d266e4e..e2392e2ed45d4 100644 --- a/pkgs/stdenv/generic/check-meta.nix +++ b/pkgs/stdenv/generic/check-meta.nix @@ -273,7 +273,7 @@ let priority = int; pkgConfigModules = listOf str; platforms = listOf (either str (attrsOf anything)); # see lib.meta.platformMatch - hydraPlatforms = listOf str; + hydraPlatforms = platforms; broken = bool; unfree = bool; unsupported = bool; diff --git a/pkgs/top-level/release-lib.nix b/pkgs/top-level/release-lib.nix index 38e6f8072776c..f16baaa8e018c 100644 --- a/pkgs/top-level/release-lib.nix +++ b/pkgs/top-level/release-lib.nix @@ -146,10 +146,12 @@ rec { /* Recursively map a (nested) set of derivations to an isomorphic set of meta.platforms values. */ packagePlatforms = mapAttrs (name: value: - if isDerivation value then - value.meta.hydraPlatforms - or (lib.subtractLists (value.meta.badPlatforms or []) - (value.meta.platforms or [ "x86_64-linux" ])) + if isDerivation value + then if value?meta.hydraPlatforms + then lib.systems.doublesFromPatterns value.meta.hydraPlatforms + else (lib.subtractLists + (lib.systems.doublesFromPatterns (value.meta.badPlatforms or [])) + (value.meta.platforms or [ "x86_64-linux" ])) else if value.recurseForDerivations or false || value.recurseForRelease or false then packagePlatforms value else