-
-
Notifications
You must be signed in to change notification settings - Fork 18k
zig: fix impurities for Zig compiler and Zig outputs #214440
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
By default, Zig will use the generate code for the native CPU. This is
impure and leads to illegal instruction crashes for users which have
different CPUs than the build bots.
Change Zig's default to -mcpu=baseline.
To test, I built on my new AMD Zen 3 machine used qemu to emulate an old
Intel Sandy Bridge machine, and observed no crashes with this patch:
$ nix-shell -I ~/Projects/ -p ncdu \
--run 'qemu-x86_64-static -cpu SandyBridge $(which ncdu)'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, upstream here. I'd like to work with you on this and help come to a satisfactory resolution for nixos maintainers as well as our mutual users.
I think cpu-purity.patch as currently implemented is problematic, because it has far-reaching consequences well beyond the scope of making nixos packages use the baseline CPU. It's also a widely used data structure, and it's difficult to be sure this diff will not violate assumptions in many places of the codebase.
Please consider that, while it is crucial for zig to use the baseline CPU when zig is being used by nix to build nix packages for binary distributions, another important use case is nixos users directly using the zig binary provided by nixos to develop their own upstream projects. This patch will cause great confusion and harm for the latter use case.
Looking at the rest of this pull request, to me the explicit uses of -Dcpu=baseline look like the right tool for the job. Is there some reason this solution is unsatisfactory?
P.S. I am available to discuss this topic in #nixos on libera.
| runHook preInstall | ||
|
|
||
| zig build -Drelease-safe=true -Dcpu=baseline --prefix $out install | ||
| zig build -Drelease-safe=true --prefix $out install |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"install" is the default build step and can therefore be omitted, having the same effect as before:
| zig build -Drelease-safe=true --prefix $out install | |
| zig build -Drelease-safe=true -Dcpu=baseline --prefix $out |
|
Split the commit per expression. |
In my opinion, it shouldn't be the job of every package to make the toolchain deterministic. Nix' toolchains should be deterministic by default. For example, Nix' C compiler wrapper scripts try hard to make the C compiler deterministic, going as far as to strip out
I don't know what the policy for Nixpkgs is, but I am following the lead of how the C toolchain seems to work. |
Okay, that makes sense. What is the best way to configure Zig to be deterministic by default regarding CPU code generation? (I understand there are complications with things like libc detection. I don't know if that's relevant to -mcpu.) |
|
Wouldn't it be better to make a custom build step for Zig, used internally within Nixpkgs? Example: Relevant feature that the hypothetical build step can support #185665 (comment):
|
|
Another way to do it would be to have a setup hook for zig to make baseline the default, so this will work automatically for existing uses of zig within I'm not familiar enough with zig to know how to do that, just throwing some ideas |
|
Given the nature of discussion, I will put this in draft mode. |
|
I am against the I believe the upstream developers (hello andrewrk :)) can provide such tooling. |
|
@AndersonTorres from outside this conversation, marking someone else's PR as draft seems like a breach of protocol. |
|
There is no other suitable tool to provide a more accurate status. Also it can be easily reverted when desired. |
|
Draft status reverted as desired. |
|
Is it ready to merge? All tests are passing. |
|
No. The current approach has notable drawbacks, as @andrewrk pointed out in #214440 (review) |
Can you reiterate them here (perhaps rephrased from the Nix point of view rather than upstream's)? I don't find @andrewrk's arguments compelling enough to block this patch. Maybe I'm misunderstanding something about how Nix should mandate purity. |
|
I think what I'm hearing is:
|
|
It seems like the time to add a default to baseline would be when Zig support is added to the nixpkgs builders. I'm in favor of just patching in the build argument for each package for now, to get us un-broken. |
I agree zig should default to baseline cpu when used as a dependency in nixpkgs, but zig is also used outside the nix sandbox, and the patch changes the default that could be confusing for users and upstream.
I don't know much about the other compilers, but for rust it is abstracted away with |
|
So we need to create a |
|
I think setup hooks are the best option here, creating a What I'm not sure about is how we should handle cases like ncdu, where the flags wouldn't be able to be set automatically due to its use of a Makefile. We could either wrap Zig and make the flags be set conditionally, or we can just specify the flags manually for ncdu as we do now with its @strager If you'd like assistance with any of this, or have any better ideas based on these, feel free to reach out -- more than happy to help. |
|
threw something together, just an idea and still need more work, feel free to open a new pr or update in this one --- a/pkgs/development/compilers/zig/0.10.nix
+++ b/pkgs/development/compilers/zig/0.10.nix
@@ -4,6 +4,7 @@
, cmake
, coreutils
, llvmPackages
+, makeWrapper
, libxml2
, zlib
}:
@@ -22,6 +23,7 @@ stdenv.mkDerivation rec {
nativeBuildInputs = [
cmake
llvmPackages.llvm.dev
+ makeWrapper
];
buildInputs = [
@@ -49,11 +51,19 @@ stdenv.mkDerivation rec {
"-DCMAKE_SKIP_BUILD_RPATH=ON"
];
+ postInstall = ''
+ mkdir -p $out/nix-support/bin
+ makeWrapper $out/bin/zig $out/nix-support/bin/zig \
+ --append-flags -Dcpu=baseline
+ '';
+
doCheck = true;
installCheckPhase = ''
$out/bin/zig test --cache-dir "$TMPDIR" -I $src/test $src/test/behavior.zig
'';
+ setupHook = ./setup-hook.sh;
+
meta = with lib; {
homepage = "https://ziglang.org/";
description =
--- /dev/null
+++ b/pkgs/development/compilers/zig/setup-hook.sh
@@ -0,0 +1,5 @@
+zigWrapperHook() {
+ export PATH=@out@/nix-support/bin:$PATH
+}
+
+postUnpackHooks+=(zigWrapperHook) |
|
As an alternative to that, we could also make a Zig wrapper a la cc-wrapper that sets flags based on commands/environment variables, and I'd be happy to work on this if you (@strager) don't mind. |
It seems like we should do as @ifreund recommends, a one flag patch, and allow the zig builder story to bake awhile. |
|
Agreed. I can confirm that the following patch builds on both aarch64-linux and aarch64-darwin. @strager if you wouldn't mind updating this branch to this in the meantime, so we can fix the big issue at hand, that'd be great. (Feel free to update the comment if you'd like.) Thanks! diff --git a/pkgs/development/compilers/zig/0.10.nix b/pkgs/development/compilers/zig/0.10.nix
index 89f23b9ca25..966be329bef 100644
--- a/pkgs/development/compilers/zig/0.10.nix
+++ b/pkgs/development/compilers/zig/0.10.nix
@@ -47,6 +47,9 @@ stdenv.mkDerivation rec {
cmakeFlags = [
# file RPATH_CHANGE could not write new RPATH
"-DCMAKE_SKIP_BUILD_RPATH=ON"
+
+ # ensure determinism in the compiler build
+ "-DZIG_TARGET_MCPU=baseline"
];
doCheck = true;
diff --git a/pkgs/development/compilers/zig/0.9.1.nix b/pkgs/development/compilers/zig/0.9.1.nix
index e7c62a4cf93..637186f686e 100644
--- a/pkgs/development/compilers/zig/0.9.1.nix
+++ b/pkgs/development/compilers/zig/0.9.1.nix
@@ -62,6 +62,9 @@ stdenv.mkDerivation rec {
cmakeFlags = [
# file RPATH_CHANGE could not write new RPATH
"-DCMAKE_SKIP_BUILD_RPATH=ON"
+
+ # ensure determinism in the compiler build
+ "-DZIG_TARGET_MCPU=baseline"
];
doCheck = true; |
Is it ready to merge? All tests are passing. |
|
It seems that people prefer #215994 and per-package workarounds instead of my fix-everything solution. I didn't test that patch, but it seems like it should do the right thing. |
|
Hi @strager, please see #214440 (comment) and the surrounding discussion for ideas with regards to the problem of what the compiler outputs. Do you have any thoughts on the matter? (Lastly, I was waiting until some time passed before submitting my own PR with just the Zig compiler fix as a courtesy towards you for starting this work, but I assume the author of the other PR didn't see that there was a discussion here -- sorry about that.) |
|
I did not see this PR, sorry. I do think it would be beneficial to fix this globally rather than require every individual package to do so. |
|
@strager Are you open to resurrecting this? I just reviewed another new zig package and would prefer your global implementation to setting baseline on all packages. (Which surely misses some) |
|
We should be setting the baseline for all Nixpkg packages but we should do it through a different approach. The following are relevant: Edit: I think the approach that Ekaitz is taking for Guix is a good role model. |
I agree. I think that Nix-built tools should behave the same whether you are building another Nix package or using the tool outside of Nix, and that behavior should be "it works". Other people, such as @sagehane and Zig's lead maintainer, disagree and think that the "same" tool should behave in two different ways depending on how it's invoked. I'm not interested fighting this fight though. |
|
tl;dr of what I'm trying to convey: How does modifying the behaviour of Zig aid the users to have consistent/predictable behaviour outside of the Nix build system? I would think it does the opposite.
Well yeah, is that strange? Isn't that how other compilers/build systems packaged by Nixpkgs work too? Or does something like GCC/make enforce compiling for a baseline when used for userspace too? |
I agree that my proposal does not work toward that goal. I don't think that's a goal of Nix or Nixpkgs, but I could be wrong.
I am not advocating for "enforcing" compiling for the baseline. I am advocating for a compiling for the baseline by default. I think both GCC and Clang compile for the baseline by default at least on Linux x86_64 (both upstream and in Nix). |
Description of changes
By default, Zig will use the generate code for the native CPU. This is impure and leads to illegal instruction crashes for users which have different CPUs than the build bots.
Change Zig's default to -mcpu=baseline.
To test, I built on my new AMD Zen 3 machine used qemu to emulate an old Intel Sandy Bridge machine, and observed no crashes with this patch:
Things done
sandbox = trueset innix.conf? (See Nix manual)nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage./result/bin/)nixos/doc/manual/md-to-db.shto update generated release notes