From e435a371dbbb3f0fa6e0eb1aa68269ee3abd2ccd Mon Sep 17 00:00:00 2001 From: Guillaume Bouchard Date: Fri, 6 Sep 2024 09:35:57 +0400 Subject: [PATCH 1/2] fix: run with 'nix run' The standard nix builds creates a binary which is reproducible with pinned shared libraries in `/nix/store` as well as a pinned library loader (also located in `/nix/store`). However the `preFixup` phase is replacing the reproducible and pinned library loader by one which is hopefully located in `/lib64/ld-linux-x86-64.so.2` (e.g. for `x86-64` systems). I don't understand this fix because: - It breaks reproducibility and pinning because there is no guarantee that the file in `/lib64/ld-linux-x86-64.so.2` exists (e.g. on nixos systems) or that it is compatible (e.g. on system with a more recent libc). - It does not bring any other benefit of making the binary self contained because it still depends on a few shared libraries: ``` linux-vdso.so.1 (0x00007f95bad0d000) libX11.so.6 => /nix/store/44q9wnzpgv77rl0yjszs0bac5apk2c83-libX11-1.8.9/lib/libX11.so.6 (0x00007f95babc2000) libpthread.so.0 => /nix/store/dbcw19dshdwnxdv5q2g6wldj6syyvq7l-glibc-2.39-52/lib/libpthread.so.0 (0x00007f95babbd000) libresolv.so.2 => /nix/store/dbcw19dshdwnxdv5q2g6wldj6syyvq7l-glibc-2.39-52/lib/libresolv.so.2 (0x00007f95babac000) libc.so.6 => /nix/store/dbcw19dshdwnxdv5q2g6wldj6syyvq7l-glibc-2.39-52/lib/libc.so.6 (0x00007f95ba9bf000) libxcb.so.1 => /nix/store/inw0qwiz9mq2748g0whfa43q2qs2ic60-libxcb-1.17.0/lib/libxcb.so.1 (0x00007f95ba992000) /nix/store/dbcw19dshdwnxdv5q2g6wldj6syyvq7l-glibc-2.39-52/lib/ld-linux-x86-64.so.2 => /nix/store/wlffq5p6mxxgfap10sav3ij936jzqm59-glibc-2.39-52/lib64/ld-linux-x86-64.so.2 (0x00007f95bad0f000) libXau.so.6 => /nix/store/wgzlxm5hzkpfzaa1qjc4pzzc9fhkwf2c-libXau-1.0.11/lib/libXau.so.6 (0x00007f95ba98d000) libXdmcp.so.6 => /nix/store/sg6xmva8xipj3mw1ip22n4f6vqmzb47r-libXdmcp-1.1.5/lib/libXdmcp.so.6 (0x00007f95ba985000) ``` Note that I don't really understand the comment: > Un-Nix the build so it can dlopen() X11 outside of Nix environments. Alternates solutions: - Either build the binary in fully static mode, so there is no shared libraries and library loader. - Provide two builds artifacts, one (the default) which does not do the patch and can hence be run directly using `nix run` and one other which does this patching. Note that with this commit, users can directly run `tsui` using `nix run 'github:neuralinkcorp/tsui'` (once merged). --- flake.nix | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/flake.nix b/flake.nix index b10e1b5..d6c5ffd 100644 --- a/flake.nix +++ b/flake.nix @@ -31,12 +31,6 @@ let pkgs = nixpkgsFor.${system}; pname = "tsui"; - - linuxInterpreters = { - x86_64 = "/lib64/ld-linux-x86-64.so.2"; - aarch64 = "/lib/ld-linux-aarch64.so.1"; - }; - linuxInterpreter = linuxInterpreters.${pkgs.stdenv.hostPlatform.parsed.cpu.name}; in { tsui = pkgs.buildGoModule { @@ -65,11 +59,6 @@ vendorHash = "sha256-FIbkPE5KQ4w7Tc7kISQ7ZYFZAoMNGiVlFWzt8BPCf+A="; buildInputs = dependenciesFor pkgs; - - # Un-Nix the build so it can dlopen() X11 outside of Nix environments. - preFixup = if pkgs.stdenv.isLinux then '' - patchelf --remove-rpath --set-interpreter ${linuxInterpreter} $out/bin/${pname} - '' else null; }; }); From f90196a65bb1d0078e82c470951e5a6acb4176f9 Mon Sep 17 00:00:00 2001 From: Guillaume Bouchard Date: Sun, 8 Sep 2024 14:12:21 +0400 Subject: [PATCH 2/2] feat: restore the library loader hack and add a bundle - `nix run .#` (or `nix run 'github:neuralinkcorp/tsui') still works - `nix build .#tsui_no_nix_ld` builds a version with the dynamic loader hack (e.g. what was the default). - (bonus): `nix bundle` builds a local `tsui` auto-extractable self contained archive which should (in theory, perfect world, ...) be able to be relocated in another system without nix. --- flake.nix | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index d6c5ffd..2d9caf9 100644 --- a/flake.nix +++ b/flake.nix @@ -31,8 +31,14 @@ let pkgs = nixpkgsFor.${system}; pname = "tsui"; + + linuxInterpreters = { + x86_64 = "/lib64/ld-linux-x86-64.so.2"; + aarch64 = "/lib/ld-linux-aarch64.so.1"; + }; + linuxInterpreter = linuxInterpreters.${pkgs.stdenv.hostPlatform.parsed.cpu.name}; in - { + rec { tsui = pkgs.buildGoModule { inherit pname; inherit version; @@ -60,6 +66,23 @@ buildInputs = dependenciesFor pkgs; }; + + # This is an attempt at building a package independent from nix. + # In order to do so, it changes the library loader for the one + # usually found in `/lib/ld-linux....so` + # Note that this does not change binary rpath, so libraries may still + # be searched in `/nix/store`, but depending on the new ld-linux + # used, it may also fallsback onto more "traditional" (e.g. + # `/usr/lib64`) directories. + # Note that this breaks the run on nixos-system, because + # `/lib/ld-linux...` is not a real library loader. + tsui_no_nix_ld = tsui.overrideAttrs (oldAttrs: + { + # Un-Nix the build so it can dlopen() X11 outside of Nix environments. + preFixup = if pkgs.stdenv.isLinux then '' + patchelf --remove-rpath --set-interpreter ${linuxInterpreter} $out/bin/${pname} + '' else null; + }); }); # Add dependencies that are only needed for development @@ -78,5 +101,10 @@ # flake provides only one package or there is a clear "main" # package. defaultPackage = forAllSystems (system: self.packages.${system}.tsui); + + # nix bundle .# creates a file `tsui` in current directory which is a + # self auto-extractable archive which should be self contained and hence + # easy to deploy. + bundles = forAllSystems (system: self.packages.${system}.tsui); }; }