Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/stdenv/cross-compilation.chapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ depsBuildBuild = [ buildPackages.stdenv.cc ];
Add the following to your `mkDerivation` invocation.

```nix
doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
doCheck = lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform;
```

#### Package using Meson needs to run binaries for the host platform during build. {#cross-meson-runs-host-code}
Expand All @@ -162,7 +162,7 @@ e.g.
```
nativeBuildInputs = [
meson
] ++ lib.optionals (!stdenv.buildPlatform.canExecute stdenv.hostPlatform) [
] ++ lib.optionals (!lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform) [
mesonEmulatorHook
];
```
Expand Down
2 changes: 1 addition & 1 deletion doc/stdenv/meta.chapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ This means that `broken` can be used to express constraints, for example:
- Does not cross compile

```nix
meta.broken = !(stdenv.buildPlatform.canExecute stdenv.hostPlatform)
meta.broken = !(lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform)
```

- Broken if all of a certain set of its dependencies are broken
Expand Down
161 changes: 111 additions & 50 deletions lib/systems/default.nix
Original file line number Diff line number Diff line change
@@ -1,9 +1,100 @@
{ lib }:
let inherit (lib.attrsets) mapAttrs; in
{ lib
}:
let
inherit (lib.attrsets) mapAttrs;

selectEmulator = platform: pkgs:
let
qemu-user = pkgs.qemu.override {
smartcardSupport = false;
spiceSupport = false;
openGLSupport = false;
virglSupport = false;
vncSupport = false;
gtkSupport = false;
sdlSupport = false;
pulseSupport = false;
pipewireSupport = false;
smbdSupport = false;
seccompSupport = false;
enableDocs = false;
hostCpuTargets = [ "${platform.qemuArch}-linux-user" ];
};
wine = (pkgs.winePackagesFor "wine${toString platform.parsed.cpu.bits}").minimal;
in
if lib.systems.canExecute pkgs.stdenv.hostPlatform platform
then "${pkgs.runtimeShell} -c '\"$@\"' --"
else if platform.isWindows
then "${wine}/bin/wine${lib.optionalString (platform.parsed.cpu.bits == 64) "64"}"
else if platform.isLinux && pkgs.stdenv.hostPlatform.isLinux && platform.qemuArch != null
then "${qemu-user}/bin/qemu-${platform.qemuArch}"
else if platform.isWasi
then "${pkgs.wasmtime}/bin/wasmtime"
else if platform.isMmix
then "${pkgs.mmixware}/bin/mmix"
else null;

rec {
doubles = import ./doubles.nix { inherit lib; };

parse = import ./parse.nix { inherit lib; };

isCompatiblePlaceholder = _: throw "2022-05-23: isCompatible has been removed in favor of canExecute, refer to the 22.11 changelog for details";

# These definitions have to be floated out into a `let … in` binding to ensure
# that they are the same exact value struct in the evaluating Nix
# implementation. Due to a quirk in how equality is implemented, values including
# functions are considered equal if they have the same memory location as long as
# they are inside a container value and not compared directly. Thus any attribute
# set will compare equal to itself even if it contains functions.
# By floating the functions out of the attribute set construction we'll ensure
# that the functions have the same memory location regardless of what call to
# lib.systems.elaborate produced them. This ensures that platform sets will be
# equal even if they have been constructed by different calls to lib.systems.elaborate
# —as long as their other contents are the same.
#
# For details see:
# - https://github.com/NixOS/nix/issues/3371
# - https://code.tvl.fyi/about/tvix/docs/value-pointer-equality.md

# uncomment after 24.05 branch-off
/*
canExecutePlaceholder = _: throw "2023-06-17: `platform.canExecute` has been removed in favor of `lib.systems.canExecute platform`";
emulatorAvailablePlaceholder = _: throw "2023-06-17: `platform.emulatorAvailable` has been removed in favor of `lib.systems.emulatorAvailable platform`";
emulatorPlaceholder = _: throw "2023-06-17: `platform.emulator` has been removed in favor of `lib.systems.emulator platform`";
*/

# uncomment after 23.11 branch-off
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# uncomment after 23.11 branch-off
# uncomment in January 2024, after 23.05 EOL

# delete after 24.05 branch-off
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# delete after 24.05 branch-off
# delete canExecutePlaceholder, emulatorAvailablePlaceholder and emulatorPlaceholder after 24.05 branch-off (throwing would have been nice, but throws off `==` equality when comparing platforms elaborated on distinct but compatible Nixpkgs source trees)
  • Won't be grouped by the comment syntax anymore, so be explicit
  • Explain why not throw in this case

/*
canExecutePlaceholder = _: lib.warn "2023-06-17: `platform.canExecute` has been removed in favor of `lib.systems.canExecute platform`"
self: plat: canExecute self plat;
emulatorAvailablePlaceholder = _: lib.warn "2023-06-17: `platform.emulatorAvailable` has been removed in favor of `lib.systems.emulatorAvailabl
self: pkgs: emulatorAvailable self pkgs;
emulatorPlaceholder = _: lib.warn "2023-06-17: `platform.emulator` has been removed in favor of `lib.systems.emulator platform`"
self: pkgs: emulator self pkgs;
*/

# delete out after 23.11 branch-off
canExecutePlaceholder = self: plat: canExecute self plat;
emulatorAvailablePlaceholder = self: pkgs: emulatorAvailable self pkgs;
emulatorPlaceholder = self: pkgs: emulator self pkgs;

canExecute = machinePlatform: binaryPlatform:
machinePlatform.isAndroid == binaryPlatform.isAndroid &&
parse.isCompatible machinePlatform.parsed.cpu binaryPlatform.parsed.cpu
&& machinePlatform.parsed.kernel == binaryPlatform.parsed.kernel;

emulatorAvailable = platform: pkgs: (selectEmulator platform pkgs) != null;

emulator = platform: pkgs:
if (emulatorAvailable platform pkgs)
then selectEmulator platform pkgs
else throw "Don't know how to run ${platform.config} executables.";


in rec {
doubles = import ./doubles.nix { inherit lib; };
inherit parse;
inspect = import ./inspect.nix { inherit lib; };
platforms = import ./platforms.nix { inherit lib; };
examples = import ./examples.nix { inherit lib; };
Expand Down Expand Up @@ -34,6 +125,8 @@ rec {
*/
flakeExposed = import ./flake-systems.nix { };

inherit canExecute emulatorAvailable emulator;

# Elaborate a `localSystem` or `crossSystem` so that it contains everything
# necessary.
#
Expand All @@ -53,12 +146,19 @@ rec {
# Either of these can be losslessly-extracted from `parsed` iff parsing succeeds.
system = parse.doubleFromSystem final.parsed;
config = parse.tripleFromSystem final.parsed;
# Determine whether we can execute binaries built for the provided platform.
canExecute = platform:
final.isAndroid == platform.isAndroid &&
parse.isCompatible final.parsed.cpu platform.parsed.cpu
&& final.parsed.kernel == platform.parsed.kernel;
isCompatible = _: throw "2022-05-23: isCompatible has been removed in favor of canExecute, refer to the 22.11 changelog for details";

# Placeholders for removed functions that inform the user about their replacements
#isCompatible = isCompatiblePlaceholder final;

# 2023-06-17: `platform.canExecute` is deprecated in favor of `lib.systems.canExecute platform`
canExecute = canExecutePlaceholder final;

# 2023-06-17: `platform.emulatorAvailable` has been removed in favor of `lib.systems.emulatorAvailable platform`
emulatorAvailable = emulatorAvailablePlaceholder final;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These also don't need to be placeholders, right?

Copy link
Author

@ghost ghost Nov 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were added by @sternenseemann here: #238331 (review) in commit 5d8e668d16f7ce7c32399007d3a49a27322ac3ed

They do need to be placeholders, because they are functions. And Nix's definition of equality for functions is crackheaded.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See 5d8e668#diff-2165823a8d82c5dd1353601bd290df8bd431f9ee2096750d9ef655cf5d251998R37-R47

 # These definitions have to be floated out into a `let … in` binding to ensure
 # that they are the same exact value struct in the evaluating Nix
 # implementation. Due to a quirk in how equality is implemented, values including
 # functions are considered equal if they have the same memory location as long as
 # they are inside a container value and not compared directly. Thus any attribute
 # set will compare equal to itself even if it contains functions.
 # By floating the functions out of the attribute set construction we'll ensure
 # that the functions have the same memory location regardless of what call to
 # lib.systems.elaborate produced them. This ensures that platform sets will be
 # equal even if they have been constructed by different calls to lib.systems.elaborate
 # —as long as their other contents are the same.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, right.


# 2023-06-17: `platform.emulator` has been removed in favor of `lib.systems.emulator platform`
emulator = emulatorPlaceholder final;

# Derived meta-data
libc =
/**/ if final.isDarwin then "libSystem"
Expand Down Expand Up @@ -314,47 +414,8 @@ rec {
if final.isMacOS then "MACOSX_DEPLOYMENT_TARGET"
else if final.isiOS then "IPHONEOS_DEPLOYMENT_TARGET"
else null;
} // (
let
selectEmulator = pkgs:
let
qemu-user = pkgs.qemu.override {
smartcardSupport = false;
spiceSupport = false;
openGLSupport = false;
virglSupport = false;
vncSupport = false;
gtkSupport = false;
sdlSupport = false;
pulseSupport = false;
pipewireSupport = false;
smbdSupport = false;
seccompSupport = false;
enableDocs = false;
hostCpuTargets = [ "${final.qemuArch}-linux-user" ];
};
wine = (pkgs.winePackagesFor "wine${toString final.parsed.cpu.bits}").minimal;
in
if pkgs.stdenv.hostPlatform.canExecute final
then "${pkgs.runtimeShell} -c '\"$@\"' --"
else if final.isWindows
then "${wine}/bin/wine${lib.optionalString (final.parsed.cpu.bits == 64) "64"}"
else if final.isLinux && pkgs.stdenv.hostPlatform.isLinux && final.qemuArch != null
then "${qemu-user}/bin/qemu-${final.qemuArch}"
else if final.isWasi
then "${pkgs.wasmtime}/bin/wasmtime"
else if final.isMmix
then "${pkgs.mmixware}/bin/mmix"
else null;
in {
emulatorAvailable = pkgs: (selectEmulator pkgs) != null;

emulator = pkgs:
if (final.emulatorAvailable pkgs)
then selectEmulator pkgs
else throw "Don't know how to run ${final.config} executables.";

}) // mapAttrs (n: v: v final.parsed) inspect.predicates

} // mapAttrs (n: v: v final.parsed) inspect.predicates
// mapAttrs (n: v: v final.gcc.arch or "default") architectures.predicates
// args;
in assert final.useAndroidPrebuilt -> final.isAndroid;
Expand Down
28 changes: 28 additions & 0 deletions lib/tests/systems.nix
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,33 @@ lib.runTests (
testunix = mseteq unix (linux ++ darwin ++ freebsd ++ openbsd ++ netbsd ++ illumos ++ cygwin ++ redox);
})


# Uncomment after 23.11
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be in sync with the other uncomment comment.

Suggested change
# Uncomment after 23.11
# Uncomment after 23.05 EOL in January 2024

/*
# Verify that pointer equality doesn't influence the result of comparing two
# platform sets that are the same, but have been constructed by independent calls
# to `lib.systems.elaborate`.
// builtins.listToAttrs (builtins.map (input: {
name = "test_equality_same_argument_${input}";
value = {
expr = lib.systems.elaborate input == lib.systems.elaborate input;
expected = true;
};
}) [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" "x86_64-unknown-linux-musl" "powerpc64le-unknown-linux-gnu" "riscv64-linux" ])

# Verify that pointer equality doesn't influence the result of comparing two
# platform sets that are the same, but have been constructed by two different,
# but effectively equivalent arguments to `lib.systems.elaborate` (in one case
# we pass the `system` as a string, the other time it is placed in a skeleton
# platform attribute set).
// builtins.listToAttrs (builtins.map (system: {
name = "test_equality_equivalent_argument_${system}";
value = {
expr = lib.systems.elaborate system == lib.systems.elaborate { inherit system; };
expected = true;
};
}) [ "x86_64-linux" "riscv64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-netbsd" ])

// {
test_equals_example_x86_64-linux = {
expr = lib.systems.equals (lib.systems.elaborate "x86_64-linux") (lib.systems.elaborate "x86_64-linux");
Expand All @@ -79,6 +106,7 @@ lib.runTests (
expected = null;
};
}
*/

# Generate test cases to assert that a change in any non-function attribute makes a platform unequal
// lib.concatMapAttrs (platformAttrName: origValue: {
Expand Down
2 changes: 1 addition & 1 deletion nixos/modules/system/boot/binfmt.nix
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ let
''
else interpreter;

getEmulator = system: (lib.systems.elaborate { inherit system; }).emulator pkgs;
getEmulator = system: lib.systems.emulator (lib.systems.elaborate { inherit system; }) pkgs;
getQemuArch = system: (lib.systems.elaborate { inherit system; }).qemuArch;

# Mapping of systems to “magicOrExtension” and “mask”. Mostly taken from:
Expand Down
2 changes: 1 addition & 1 deletion pkgs/applications/audio/fire/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ stdenv.mkDerivation rec {
# Fails to find fp.h on its own
env.NIX_CFLAGS_COMPILE = lib.optionalString stdenv.hostPlatform.isDarwin "-isystem ${CoreServices}/Library/Frameworks/CoreServices.framework/Versions/Current/Frameworks/CarbonCore.framework/Versions/Current/Headers/";

doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
doCheck = lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform;

meta = with lib; {
description = "Multi-band distortion plugin by Wings";
Expand Down
2 changes: 1 addition & 1 deletion pkgs/applications/editors/emacs/make-emacs.nix
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,6 @@ mkDerivation (finalAttrs: {
};

meta = meta // {
broken = withNativeCompilation && !(stdenv.buildPlatform.canExecute stdenv.hostPlatform);
broken = withNativeCompilation && !(lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform);
};
})
2 changes: 1 addition & 1 deletion pkgs/applications/misc/girara/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ stdenv.mkDerivation rec {

mesonFlags = [
"-Ddocs=disabled" # docs do not seem to be installed
(lib.mesonEnable "tests" (stdenv.buildPlatform.canExecute stdenv.hostPlatform))
(lib.mesonEnable "tests" (lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform))
];

checkPhase = ''
Expand Down
2 changes: 1 addition & 1 deletion pkgs/applications/misc/hugo/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ buildGoModule rec {

ldflags = [ "-s" "-w" "-X github.com/gohugoio/hugo/common/hugo.vendorInfo=nixpkgs" ];

postInstall = let emulator = stdenv.hostPlatform.emulator buildPackages; in ''
postInstall = let emulator = lib.systems.emulator stdenv.hostPlatform buildPackages; in ''
${emulator} $out/bin/hugo gen man
installManPage man/*
installShellCompletion --cmd hugo \
Expand Down
2 changes: 1 addition & 1 deletion pkgs/applications/misc/raider/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ stdenv.mkDerivation rec {
ninja
pkg-config
wrapGAppsHook4
] ++ lib.optionals (!stdenv.buildPlatform.canExecute stdenv.hostPlatform) [
] ++ lib.optionals (!lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform) [
mesonEmulatorHook
];

Expand Down
2 changes: 1 addition & 1 deletion pkgs/applications/networking/cluster/stern/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ buildGoModule rec {
ldflags = [ "-s" "-w" "-X github.com/stern/stern/cmd.version=${version}" ];

postInstall = let
stern = if stdenv.buildPlatform.canExecute stdenv.hostPlatform then "$out" else buildPackages.stern;
stern = if lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform then "$out" else buildPackages.stern;
in
''
for shell in bash zsh; do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ buildGoModule rec {

nativeBuildInputs = [ installShellFiles ];

postInstall = lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
postInstall = lib.optionalString (lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform) ''
installShellCompletion --cmd gitops \
--bash <($out/bin/gitops completion bash 2>/dev/null) \
--fish <($out/bin/gitops completion fish 2>/dev/null) \
Expand Down
2 changes: 1 addition & 1 deletion pkgs/applications/networking/remote/freerdp/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
, withUnfree ? false

# tries to compile and run generate_argument_docbook.c
, withManPages ? stdenv.buildPlatform.canExecute stdenv.hostPlatform
, withManPages ? lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform

, buildPackages
}:
Expand Down
2 changes: 1 addition & 1 deletion pkgs/applications/networking/sync/rclone/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ buildGoModule rec {
postInstall =
let
rcloneBin =
if stdenv.buildPlatform.canExecute stdenv.hostPlatform
if lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform
then "$out"
else lib.getBin buildPackages.rclone;
in
Expand Down
2 changes: 1 addition & 1 deletion pkgs/applications/science/math/eigenmath/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ stdenv.mkDerivation rec {
hash = "sha256-roPyRaT89I3HbyvBK/owiigMus1EeKEhhKHFsgfzp10=";
};

checkPhase = let emulator = stdenv.hostPlatform.emulator buildPackages; in ''
checkPhase = let emulator = lib.systems.emulator stdenv.hostPlatform buildPackages; in ''
runHook preCheck

for testcase in selftest1 selftest2; do
Expand Down
4 changes: 2 additions & 2 deletions pkgs/applications/version-management/gh/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ buildGoModule rec {

buildPhase = ''
runHook preBuild
make GO_LDFLAGS="-s -w" GH_VERSION=${version} bin/gh ${lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) "manpages"}
make GO_LDFLAGS="-s -w" GH_VERSION=${version} bin/gh ${lib.optionalString (lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform) "manpages"}
runHook postBuild
'';

installPhase = ''
runHook preInstall
install -Dm755 bin/gh -t $out/bin
'' + lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
'' + lib.optionalString (lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform) ''
installManPage share/man/*/*.[1-9]

installShellCompletion --cmd gh \
Expand Down
2 changes: 1 addition & 1 deletion pkgs/applications/window-managers/wayfire/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ stdenv.mkDerivation (finalAttrs: {
"--sysconfdir /etc"
"-Duse_system_wlroots=enabled"
"-Duse_system_wfconfig=enabled"
(lib.mesonEnable "wf-touch:tests" (stdenv.buildPlatform.canExecute stdenv.hostPlatform))
(lib.mesonEnable "wf-touch:tests" (lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform))
];

passthru.providedSessions = [ "wayfire" ];
Expand Down
2 changes: 1 addition & 1 deletion pkgs/applications/window-managers/wayfire/wf-config.nix
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ stdenv.mkDerivation (finalAttrs: {
dontUseCmakeConfigure = true;

mesonFlags = [
(lib.mesonEnable "tests" (stdenv.buildPlatform.canExecute stdenv.hostPlatform))
(lib.mesonEnable "tests" (lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform))
];

doCheck = true;
Expand Down
2 changes: 1 addition & 1 deletion pkgs/desktops/gnome/core/gnome-bluetooth/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ stdenv.mkDerivation rec {
docbook-xsl-nons
docbook_xml_dtd_43
python3
] ++ lib.optionals (!stdenv.buildPlatform.canExecute stdenv.hostPlatform) [
] ++ lib.optionals (!lib.systems.canExecute stdenv.buildPlatform stdenv.hostPlatform) [
mesonEmulatorHook
];

Expand Down
Loading