1- # nix-ld-rs
1+ # nix-ld
22
33Run unpatched dynamic binaries on NixOS.
4- This is a rewrite of [ nix-ld] ( https://github.com/Mic92/nix-ld ) in Rust, with extra functionalities.
5- It's intended to be upstreamed at some point.
64
7- ## Usage
5+ ## Where is this useful?
6+
7+ While many proprietary packages in nixpkgs have already been patched with
8+ ` autoPatchelfHook ` patching, there are cases where patching is not possible:
9+
10+ - Use binary executable downloaded with third-party package managers (e.g. vscode, npm or pip) without having to patch them on every update.
11+ - Run games or proprietary software that attempts to verify its integrity.
12+ - Run programs that are too large for the nix store (e.g. FPGA IDEs).
13+
14+ While there are other solutions such as ` buildFHSUserEnv ` that restore a Linux file
15+ hierarchy as found on common Linux systems (` ld-linux-x86-64.so.2 ` ), these
16+ sandboxes have their own weaknesses:
17+
18+ - setuid binaries cannot be executed inside a fhsuserenv
19+ - inside a ` buildFHSUserEnv ` you can not use other sandbox tools like bwrap or 'nix build'.
20+ - ` buildFHSUserEnv ` requires a subshell which does not work well with direnv
21+
22+ ## How does nix-ld work?
23+
24+ Also read this [ blog post] ( https://blog.thalheim.io/2022/12/31/nix-ld-a-clean-solution-for-issues-with-pre-compiled-executables-on-nixos/ )
25+ to get the explaination in full detail. A summary is below:
26+
27+ Precompiled binaries that were not created for NixOS usually have a so-called
28+ link-loader hardcoded into them. On Linux/x86_64 this is for example
29+ ` /lib64/ld-linux-x86-64.so.2 ` . for glibc. NixOS, on the other hand, usually has
30+ its dynamic linker in the glibc package in the Nix store and therefore cannot
31+ run these binaries. Nix-ld provides a shim layer for these types of binaries. It
32+ is installed in the same location where other Linux distributions install their
33+ link loader, ie. ` /lib64/ld-linux-x86-64.so.2 ` and then loads the actual link
34+ loader as specified in the environment variable ` NIX_LD ` . In addition, it also
35+ accepts a colon-separated path from library lookup paths in ` NIX_LD_LIBRARY_PATH ` .
36+ This environment variable is rewritten to ` LD_LIBRARY_PATH ` before
37+ passing execution to the actual ld. This allows you to specify additional
38+ libraries that the executable needs to run.
39+
40+ ## Installation
41+
42+ nix-ld is part of nixpkgs since NixOS 22.05. There one can enable it with the following
43+ nixos setting:
44+
45+ ``` nix
46+ {
47+ programs.nix-ld.enable = true;
48+ }
49+ ```
50+
51+ To install ` nix-ld ` from the repository instead, use the following method:
52+
53+ ``` sh
54+ $ sudo nix-channel --add https://github.com/Mic92/nix-ld/archive/main.tar.gz nix-ld
55+ $ sudo nix-channel --update
56+ ```
57+
58+ ` /etc/nixos/configuration.nix `
59+
60+ ``` nix
61+ {
62+ imports = [
63+ <nix-ld/modules/nix-ld.nix>
64+ ];
65+ # The module in this repository defines a new module under (programs.nix-ld.dev) instead of (programs.nix-ld)
66+ # to not collide with the nixpkgs version.
67+ programs.nix-ld.dev.enable = true;
68+ }
69+ ```
70+
871
9- ` nix-ld-rs ` is a drop-in replacement for ` nix-ld ` .
72+ ### With nix flake
1073
11- It honors the following environment variables:
74+ Add the following lines to ` /etc/nixos/flake.nix ` . Replace ` myhostname ` with the
75+ actual hostname of your system.
76+
77+ ``` nix
78+ # flake.nix
79+ {
80+ inputs.nixpkgs.url = "github:NixOS/nixpkgs/master";
81+ inputs.nix-ld.url = "github:Mic92/nix-ld";
82+ # this line assume that you also have nixpkgs as an input
83+ inputs.nix-ld.inputs.nixpkgs.follows = "nixpkgs";
84+
85+ outputs = { nix-ld, nixpkgs, ... }: {
86+ # replace `myhostname` with your actual hostname
87+ nixosConfigurations.myhostname = nixpkgs.lib.nixosSystem {
88+ system = "x86_64-linux";
89+ modules = [
90+ # ... add this line to the rest of your configuration modules
91+ nix-ld.nixosModules.nix-ld
92+
93+ # The module in this repository defines a new module under (programs.nix-ld.dev) instead of (programs.nix-ld)
94+ # to not collide with the nixpkgs version.
95+ { programs.nix-ld.dev.enable = true; }
96+ ];
97+ };
98+ };
99+ }
100+ ```
101+
102+ ## Usage
103+
104+ nix-ld honors the following environment variables:
12105
13106- ` NIX_LD `
14107- ` NIX_LD_{system} `
@@ -19,19 +112,69 @@ It honors the following environment variables:
19112Here ` {system} ` is the value of the Nix ` system ` with dashes replaced with underscores, like ` x86_64_linux ` .
20113You can also run ` nix-ld-rs ` directly for a list.
21114
22- ## Use in NixOS
115+ After setting up the nix-ld symlink as described above, one needs to set at least
116+ ` NIX_LD ` and ` NIX_LD_LIBRARY_PATH ` to run executables. For example, this can
117+ be done with a ` shell.nix ` in a nix-shell like this:
23118
24- ```
25- { pkgs, ... }: {
26- programs.nix-ld.enable = true;
27- programs.nix-ld.package = pkgs.nix-ld-rs;
119+ ``` nix
120+ with import <nixpkgs> {};
121+ mkShell {
122+ NIX_LD_LIBRARY_PATH = lib.makeLibraryPath [
123+ stdenv.cc.cc
124+ openssl
125+ # ...
126+ ];
127+ NIX_LD = lib.fileContents "${stdenv.cc}/nix-support/dynamic-linker";
28128}
29129```
30130
31- ## Extra functionalities
131+ A full example is shown in [ ` ./examples/masterpdfeditor.nix ` ] ( examples/masterpdfeditor.nix ) .
132+
133+ In [ nix-autobahn] ( https://github.com/Lassulus/nix-autobahn ) there is also a
134+ script called ` nix-autobahn-ld ` that automates generating shell expressions.
135+
136+ In [ nix-alien] ( https://github.com/thiagokokada/nix-alien ) there is another
137+ script called ` nix-alien-ld ` that uses another strategy, wrapping the program in
138+ a ` writeShellScriptBin ` with the ` NIX_LD ` /` NIX_LD_LIBRARY_PATH ` environment
139+ variables set.
32140
33- - ` NIX_LD_LIBRARY_PATH ` doesn't affect child processes (on ` x86_64-linux ` and ` aarch64-linux ` )
34- - For example, shell environments spawned by the binary VSCode Server no longer get polluted
141+ To figure out what libraries a program needs, you can use ` ldd ` on the binary or
142+ set the ` LD_DEBUG=libs ` environment variable.
143+
144+ ## FAQ
145+
146+ ### How to find libraries for my executables?
147+
148+ You can use tools like [ nix-autobahn] ( https://github.com/Lassulus/nix-autobahn ) ,
149+ [ nix-alien] ( https://github.com/thiagokokada/nix-alien ) or use
150+ [ nix-index] ( https://github.com/bennofs/nix-index )
151+
152+ ### Why not set LD_LIBRARY_PATH directly instead of NIX_LD_LIBRARY_PATH?
153+
154+ LD_LIBRARY_PATH affects all programs, which can inject the wrong libraries in
155+ correct build nix application that have an RPATH set in their executable.
156+
157+ ### Does this work on non-NixOS system?
158+
159+ No. Normal Linux distributions will have their own link-loader. Replacing those
160+ with nix-ld will break the system.
161+
162+ ### My python/nodejs/ruby/$interpreter libraries do not find the libraries configured by nix-ld
163+
164+ Nix-ld is only used by unpatched executables that use the link loader at ` /lib `
165+ or ` /lib64 ` . If you use for example python from nixpkgs than it will not pick
166+ up ` NIX_LD_LIBRARY_PATH ` and ` NIX_LD ` since these types of binaries are
167+ configured to use a glibc from the nix store. If you encounter these cases i.e.
168+ when you are trying to use python packages installed in a virtualenv than you
169+ need to set ` LD_LIBRARY_PATH ` directly. You can also create yourself a wrapper
170+ like this:
171+
172+ ``` nix
173+ (pkgs.writeShellScriptBin "python" ''
174+ export LD_LIBRARY_PATH=$NIX_LD_LIBRARY_PATH
175+ exec ${pkgs.python3}/bin/python "$@"
176+ '')
177+ ```
35178
36179## Development
37180
@@ -47,7 +190,7 @@ It's recommended to set up transparent emulation using binfmt-misc so you can ru
47190
48191Run ` cargo test ` or ` cargo nextest run ` to run the integration tests, and ` just test ` to run them on all supported platforms (binfmt required).
49192
50- ### Current behavior
193+ ## Current behavior
51194
52195<table >
53196<thead >
0 commit comments