Reputation: 12814
I made the following small Nix derivation to locally build the Zig toolchain from source for me to use locally as part of a Nix shell.
with import (fetchTarball {
url = "https://github.com/nixos/nixpkgs/tarball/b139b6056c8ad4ef7e0cffb81304d59cf077589b";
sha256 = "0sn9l19ckvdh227n0rfxk1cjnslhb5hr3g8czf3a436zkyfdl3if";
}) {};
let
zig = stdenv.mkDerivation rec {
name = "zig";
src = fetchFromGitHub {
owner = "ziglang";
repo = "zig";
rev = "476bdc8b0b02cbd09f6a856aa7dc548dea565109";
hash = "sha256-VdMNzvoWNGvVFiblE7vajOetmHa0hyUWw5tWWVZjKEs=";
};
nativeBuildInputs = [
cmake
llvmPackages_15.llvm.dev
];
buildInputs = [
libxml2
zlib
] ++ (with llvmPackages_15; [
libclang
lld
llvm
]);
preBuild = ''
export HOME=$TMPDIR;
'';
doCheck = false;
};
in
mkShell {
nativeBuildInputs = [
zig
];
}
My intent is that of improving my knowledge of Nix while also following the recommendation from the Zig getting started page:
It’s fine to evaluate Zig using a tagged version, but if you decide that you like Zig and want to dive deeper, we encourage you to upgrade to a nightly build, mainly because that way it will be easier for you to get help: most of the community and sites like ziglearn.org track the master branch for the reasons stated above.
This works fine on my MacBook Pro (macOS Ventura 13.1.1 on M1 Pro), but when I try to build it on my Linux laptop (Ubuntu 22.04 on Lenovo T480) when the build is at the stage3
phase (IIUC that's when you have a fully bootstrapped Zig compiler which builds "itself") I get a lot of the following errors:
warning: Encountered error: FileNotFound, falling back to default ABI and dynamic linker.
Once the build is done, trying to run any zig
subcommand (e.g. running zig version
) causes a No such file or directory
error to pop up. If I run ldd $(which zig)
I see the following output:
linux-vdso.so.1 (0x00007ffd05bfb000)
libclang-cpp.so.15 => /nix/store/lchazlk4r4rb1qgifxx7w8fsqgwwd835-clang-15.0.7-lib/lib/libclang-cpp.so.15 (0x00007f5e99600000)
libstdc++.so.6 => /nix/store/k88zxp7cvd5gpharprhg9ah0vhz2asq7-gcc-12.2.0-lib/lib/libstdc++.so.6 (0x00007f5e99200000)
libLLVM-15.so => /nix/store/yvcnhajqbwcq35vpnsm1waw557dxcn5v-llvm-15.0.7-lib/lib/libLLVM-15.so (0x00007f5e91200000)
libz.so.1 => /nix/store/9dz5lmff9ywas225g6cpn34s0wbldnxa-zlib-1.2.13/lib/libz.so.1 (0x00007f5e9d291000)
libc.so.6 => /nix/store/lqz6hmd86viw83f9qll2ip87jhb7p1ah-glibc-2.35-224/lib/libc.so.6 (0x00007f5e90e00000)
/lib/ld-musl-x86_64.so.1 => /nix/store/lqz6hmd86viw83f9qll2ip87jhb7p1ah-glibc-2.35-224/lib64/ld-linux-x86-64.so.2 (0x00007f5e9d2b1000)
libm.so.6 => /nix/store/lqz6hmd86viw83f9qll2ip87jhb7p1ah-glibc-2.35-224/lib/libm.so.6 (0x00007f5e9d1af000)
libgcc_s.so.1 => /nix/store/lqz6hmd86viw83f9qll2ip87jhb7p1ah-glibc-2.35-224/lib/libgcc_s.so.1 (0x00007f5e9d195000)
libffi.so.8 => /nix/store/bmnh7b67zx6l5wi6vgjvsfwrzw7ivfph-libffi-3.4.4/lib/libffi.so.8 (0x00007f5e9d188000)
librt.so.1 => /nix/store/lqz6hmd86viw83f9qll2ip87jhb7p1ah-glibc-2.35-224/lib/librt.so.1 (0x00007f5e9d181000)
libdl.so.2 => /nix/store/lqz6hmd86viw83f9qll2ip87jhb7p1ah-glibc-2.35-224/lib/libdl.so.2 (0x00007f5e9d17c000)
libncursesw.so.6 => /nix/store/35s126gfkfrwbiv49kv9kxqdpd9zvcvm-ncurses-6.4/lib/libncursesw.so.6 (0x00007f5e9d108000)
libxml2.so.2 => /nix/store/yz7qfy85damywy6397vp7nqly0y4qm2r-libxml2-2.10.3/lib/libxml2.so.2 (0x00007f5e9949a000)
The problematic line seems to be the following, where there seems to be a mismatch:
/lib/ld-musl-x86_64.so.1 => /nix/store/lqz6hmd86viw83f9qll2ip87jhb7p1ah-glibc-2.35-224/lib64/ld-linux-x86-64.so.2 (0x00007f5e9d2b1000)
Running sudo patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 $(which zig)
patches the problem, but I'd like to get to a clean solution whereby the right linker is found and used and the derivation works across operating systems.
I tried to add musl
to the build inputs for the Zig compiler derivation but it started throwing a lot of compilation errors and I quickly backed off.
Assuming I need to point the Zig compiler to the right linker, how can I do that? If I'm wrong in my assumption, how can I solve this problem?
Upvotes: 2
Views: 950
Reputation: 12814
I originally based my derivation on the one I could find on the nixpkgs
stable 22.11 channel which builds Zig 0.9.1 (which is quite old). Looking at the one in the unstable channel (which builds the latest stable release, 0.10.1) I noticed the following which was lacking in the derivation for the previous version:
postPatch = ''
# Zig's build looks at /usr/bin/env to find dynamic linking info. This
# doesn't work in Nix' sandbox. Use env from our coreutils instead.
substituteInPlace lib/std/zig/system/NativeTargetInfo.zig --replace "/usr/bin/env" "${coreutils}/bin/env"
'';
To the best of my understanding, the big change starting with Zig 0.10.x is that the Zig compiler is now bootstrapped, which is probably why I experienced this problem. I'm slightly more confused as to why this works on macOS, but that's probably a problem for another day.
As such, I applied the following modifications:
diff --git a/shell.nix b/shell.nix
index f554c8d..bb466de 100644
--- a/shell.nix
+++ b/shell.nix
@@ -21,6 +21,7 @@ let
];
buildInputs = [
+ coreutils
libxml2
zlib
] ++ (with llvmPackages_15; [
@@ -33,7 +34,25 @@ let
export HOME=$TMPDIR;
'';
- doCheck = false;
+ postPatch = ''
+ # Zig's build looks at /usr/bin/env to find dynamic linking info. This
+ # doesn't work in Nix' sandbox. Use env from our coreutils instead.
+ substituteInPlace lib/std/zig/system/NativeTargetInfo.zig --replace "/usr/bin/env" "${coreutils}/bin/env"
+ '';
+
+ 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;
+ installCheckPhase = ''
+ $out/bin/zig test --cache-dir "$TMPDIR" -I $src/test $src/test/behavior.zig
+ '';
+
};
in
mkShell {
And it works! Tested on both my Linux and macOS laptops!
Upvotes: 0