Skip to content

Commit

Permalink
pkgs/top-level: make package sets composable
Browse files Browse the repository at this point in the history
The various pkgsXYZ top-level package sets did not pass localSystem /
crossSystem to lower levels, so far. This change propagates original
arguments to lower levels, which include the overrides made by an upper
package sets.

There is an extensive test-suite to test various combinations of package
sets in pkgs/test/top-level. There are a few basic promises made:

- Package sets must be idempotent. pkgsMusl.pkgsMusl === pkgsMusl.

- Once pkgsCross is used any subsequent package sets should affect the
  **host platform** and not the build platform. Examples:
  - pkgsMusl.pkgsCross.aarch64-multiplatform is a cross compilation from
musl to glibc/aarch64
  - pkgsCross.aarch64-multiplatform.pkgsMusl is a cross compilation to
musl/aarch64

- Modifications from an earlier layer should not be lost, unless
  explicitly overwritten. Examples:
  - pkgsStatic.pkgsMusl should still be static.
  - pkgsStatic.pkgsCross.gnu64 should be static, but with glibc instead
of musl.

Exceptions / TODOs:
- pkgsExtraHardening is currently not idempotent, because it applies the
  same flags over and over again.

Resolves NixOS#136549
Resolves NixOS#114510
Resolves NixOS#212494
Resolves NixOS#281596
  • Loading branch information
wolfgangwalther committed Feb 8, 2025
1 parent 47b8d66 commit 1f9012b
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 41 deletions.
5 changes: 5 additions & 0 deletions lib/systems/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,11 @@ let
isNoStdTarget =
any (t: hasInfix t final.rust.rustcTarget) ["-none" "nvptx" "switch" "-uefi"];
};
} // {
_type = "platform";
override = if allArgs._type or null == "platform" then allArgs.override else (
newArgs: elaborate (allArgs // newArgs)
);
};
in assert final.useAndroidPrebuilt -> final.isAndroid;
assert foldl
Expand Down
39 changes: 20 additions & 19 deletions pkgs/test/top-level/stage.nix
Original file line number Diff line number Diff line change
Expand Up @@ -94,34 +94,35 @@ assert isIdempotent "pkgsStatic";
assert isIdempotent "pkgsi686Linux";
assert isIdempotent "pkgsx86_64Darwin";

# TODO: fails
# assert isNoop [ "pkgsStatic" ] "pkgsMusl";
# TODO: fails because of ppc64-musl
# assert lib.all (sys: isNoop [ "pkgsCross" sys ] "pkgsMusl") allMuslExamples;
assert isNoop [ "pkgsStatic" ] "pkgsMusl";
assert lib.all (sys: isNoop [ "pkgsCross" sys ] "pkgsMusl") allMuslExamples;
assert lib.all (sys: isNoop [ "pkgsCross" sys ] "pkgsLLVM") allLLVMExamples;

# TODO: fails
# assert isComposable "pkgsExtraHardening";
# assert isComposable "pkgsLLVM";
assert isComposable "pkgsExtraHardening";
assert isComposable "pkgsLLVM";
# TODO: Results in infinite recursion
# assert isComposable "pkgsLLVMLibc";
# assert isComposable "pkgsArocc";
# assert isComposable "pkgsZig";
# TODO: attribute 'abi' missing
# assert isComposable "pkgsMusl";
# TODO: fails
# assert isComposable "pkgsStatic";
# assert isComposable "pkgsi686Linux";
assert isComposable "pkgsArocc";
assert isComposable "pkgsZig";
assert isComposable "pkgsMusl";
assert isComposable "pkgsStatic";
assert isComposable "pkgsi686Linux";

# Special cases regarding buildPlatform vs hostPlatform
# TODO: fails
# assert discardEvaluationErrors (pkgsCross.gnu64.pkgsMusl.stdenv.hostPlatform.isMusl);
# assert discardEvaluationErrors (pkgsCross.gnu64.pkgsi686Linux.stdenv.hostPlatform.isx86_32);
# assert discardEvaluationErrors (pkgsCross.mingwW64.pkgsLinux.stdenv.hostPlatform.isLinux);
# assert discardEvaluationErrors (pkgsCross.aarch64-darwin.pkgsx86_64Darwin.stdenv.hostPlatform.isx86_64);
assert discardEvaluationErrors (pkgsCross.mingwW64.pkgsLinux.stdenv.hostPlatform.isLinux);
assert discardEvaluationErrors (
pkgsCross.aarch64-darwin.pkgsx86_64Darwin.stdenv.hostPlatform.isx86_64
);

# pkgsCross should keep upper cross settings
# TODO: fails
# assert discardEvaluationErrors (with pkgsStatic.pkgsCross.gnu64.stdenv.hostPlatform; isGnu && isStatic);
# assert discardEvaluationErrors (with pkgsLLVM.pkgsCross.musl64.stdenv.hostPlatform; isMusl && useLLVM);
assert discardEvaluationErrors (
with pkgsStatic.pkgsCross.gnu64.stdenv.hostPlatform; isGnu && isStatic
);
assert discardEvaluationErrors (
with pkgsLLVM.pkgsCross.musl64.stdenv.hostPlatform; isMusl && useLLVM
);

emptyFile
41 changes: 19 additions & 22 deletions pkgs/top-level/stage.nix
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ let
# Convenience attributes for instantitating package sets. Each of
# these will instantiate a new version of allPackages.
otherPackageSets = let
isNative = lib.systems.equals stdenv.hostPlatform stdenv.buildPlatform;
mkPkgs = name: nixpkgsArgs: nixpkgsFun (nixpkgsArgs // {
overlays = [
(self': super': {
Expand All @@ -196,14 +197,14 @@ let
# will refer to the "hello" package built for the ARM6-based
# Raspberry Pi.
pkgsCross = lib.mapAttrs (n: crossSystem:
nixpkgsFun { inherit crossSystem; })
nixpkgsFun { crossSystem = stdenv.hostPlatform.override crossSystem; })
lib.systems.examples;

pkgsLLVM = mkPkgs "pkgsLLVM" {
# Bootstrap a cross stdenv using the LLVM toolchain.
# This is currently not possible when compiling natively,
# so we don't need to check hostPlatform != buildPlatform.
crossSystem = stdenv.hostPlatform // {
crossSystem = stdenv.hostPlatform.override {
useLLVM = true;
linker = "lld";
};
Expand All @@ -213,7 +214,7 @@ let
# Bootstrap a cross stdenv using LLVM libc.
# This is currently not possible when compiling natively,
# so we don't need to check hostPlatform != buildPlatform.
crossSystem = stdenv.hostPlatform // {
crossSystem = stdenv.hostPlatform.override {
config = lib.systems.parse.tripleFromSystem (makeLLVMParsedPlatform stdenv.hostPlatform.parsed);
libc = "llvm";
};
Expand All @@ -223,7 +224,7 @@ let
# Bootstrap a cross stdenv using the Aro C compiler.
# This is currently not possible when compiling natively,
# so we don't need to check hostPlatform != buildPlatform.
crossSystem = stdenv.hostPlatform // {
crossSystem = stdenv.hostPlatform.override {
useArocc = true;
linker = "lld";
};
Expand All @@ -233,7 +234,7 @@ let
# Bootstrap a cross stdenv using the Zig toolchain.
# This is currently not possible when compiling natively,
# so we don't need to check hostPlatform != buildPlatform.
crossSystem = stdenv.hostPlatform // {
crossSystem = stdenv.hostPlatform.override {
useZig = true;
linker = "lld";
};
Expand All @@ -243,17 +244,15 @@ let
# default GNU libc on Linux systems. Non-Linux systems are not
# supported. 32-bit is also not supported.
pkgsMusl = if stdenv.hostPlatform.isLinux && stdenv.buildPlatform.is64bit then mkPkgs "pkgsMusl" {
${if stdenv.hostPlatform == stdenv.buildPlatform
then "localSystem" else "crossSystem"} = {
${if isNative then "localSystem" else "crossSystem"} = stdenv.hostPlatform.override {
config = lib.systems.parse.tripleFromSystem (makeMuslParsedPlatform stdenv.hostPlatform.parsed);
};
} else throw "Musl libc only supports 64-bit Linux systems.";

# All packages built for i686 Linux.
# Used by wine, firefox with debugging version of Flash, ...
pkgsi686Linux = if stdenv.hostPlatform.isLinux && stdenv.hostPlatform.isx86 then mkPkgs "pkgsi686Linux" {
${if stdenv.hostPlatform == stdenv.buildPlatform
then "localSystem" else "crossSystem"} = {
${if isNative then "localSystem" else "crossSystem"} = stdenv.hostPlatform.override {
config = lib.systems.parse.tripleFromSystem (stdenv.hostPlatform.parsed // {
cpu = lib.systems.parse.cpuTypes.i686;
});
Expand All @@ -262,35 +261,33 @@ let

# x86_64-darwin packages for aarch64-darwin users to use with Rosetta for incompatible packages
pkgsx86_64Darwin = if stdenv.hostPlatform.isDarwin then mkPkgs "pkgsx86_64Darwin" {
localSystem = {
config = lib.systems.parse.tripleFromSystem (stdenv.hostPlatform.parsed // {
${if isNative then "localSystem" else "crossSystem"} = stdenv.hostPlatform.override {
config = lib.systems.parse.tripleFromSystem (stdenv.buildPlatform.parsed // {
cpu = lib.systems.parse.cpuTypes.x86_64;
});
};
} else throw "x86_64 Darwin package set can only be used on Darwin systems.";

# If already linux: the same package set unaltered
# Otherwise, return a natively built linux package set for the current cpu architecture string.
# Otherwise, return a linux package set for the current cpu architecture string.
# ABI and other details will be set to the default for the cpu/os pair.
pkgsLinux =
if stdenv.hostPlatform.isLinux
then self
else mkPkgs "pkgsLinux" {
localSystem = lib.systems.elaborate "${stdenv.hostPlatform.parsed.cpu.name}-linux";
${if isNative then "localSystem" else "crossSystem"} = lib.systems.elaborate "${stdenv.hostPlatform.parsed.cpu.name}-linux";
};

# Fully static packages.
# Currently uses Musl on Linux (couldn’t get static glibc to work).
pkgsStatic = mkPkgs "pkgsStatic" {
crossSystem = {
crossSystem = stdenv.hostPlatform.override ({
isStatic = true;
config = lib.systems.parse.tripleFromSystem (
if stdenv.hostPlatform.isLinux
then makeMuslParsedPlatform stdenv.hostPlatform.parsed
else stdenv.hostPlatform.parsed
);
gcc = lib.optionalAttrs (stdenv.hostPlatform.system == "powerpc64-linux") { abi = "elfv2"; } //
stdenv.hostPlatform.gcc or {};
};
} // lib.optionalAttrs stdenv.hostPlatform.isLinux {
config = lib.systems.parse.tripleFromSystem (makeMuslParsedPlatform stdenv.hostPlatform.parsed);
} // lib.optionalAttrs (stdenv.hostPlatform.system == "powerpc64-linux") {
gcc = { abi = "elfv2"; } // stdenv.hostPlatform.gcc or {};
});
};

pkgsExtraHardening = mkPkgs "pkgsExtraHardening" {
Expand Down

0 comments on commit 1f9012b

Please sign in to comment.