Dynamic libs with Nix+Racket
When installing a package with nix-shell, you get a temporary profile
that contains everything that was on your parent profile (where you
ran nix-shell
) plus the installed packages from that nix-shell
command.
nixpkgs repo is big and generally ok, but there are hurdles here and there, that you must be able to jump if you want to walk least-walked-paths.
Let’s see what happens (from my dimm understanding still) when you install a dynamic library that is not directly linked from your installed packages.
I was trying to do a testrun of racket’s libgit2 library.
The first attempt failed, because racket couldn’t find the .so
.
> (require libgit2)
. . ../../../../nix/store/rlw4h5mibwyavzhr1mscr95ibzl17i52-racket-7.7/share/racket/collects/ffi/unsafe.rkt:131:0: ffi-lib: couldn't open "libgit2.so.0.26.0" (libgit2.so.0.26.0: cannot open shared object file: No such file or directory)
Instant thought was to install the library using nix-shell -p libgit2
, but the error was the same.
$ ls $LD_LIBRARY_PATH | grep libgit # <- no results
So, somehow the library is not added to the LD_LIBRARY_PATH.
Let’s go first for the easy path.
$ nix-env -i libgit2
$ drracket
This just works, so we have a last resort solution. But nix-env is not cool, and we want to learn how to disentangle the whole thing!
Looking at more walked paths, I installed pygit2
to see what python
does:
$ nix-shell -p python37Packages.pygit2
$ python -c 'import pygit2'
$ ls $LD_LIBRARY_PATH | grep libgit # <- no results
And this one worked, but the library is not in the library path either. Let’s see how git proper gets the library…
ldd -v =git | grep libgit # <- no results
Note: =git
is a zshism for $(whereis git | cut -f2 -f' ')
.
Shit. At this point, I’m not sure if the git
binary is compiled
statically or something. Let’s open the nixpkgs repo and see:
The files we’re mostly concerned about are:
- https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/python-modules/pygit2/default.nix
- https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/version-management/git-and-tools/git/default.nix
- https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/libraries/git2/default.nix
In the first one, the python libgit binding, we see it depends on libgit package.
The second one, the git cli binary, we see no mentions to libgit2, so I imagine it compiles everything statically, and that’s why we didn’t see anything in the ldd command. The only suspicious thing we see is that
preConfigure = lib.optionalString stdenv.isDarwin ''
export DYLD_LIBRARY_PATH="${libgit2}/lib"
'';
Third one is the libgit2 package itself. But there’s not much you can get from it.
So time to read a bit more:
- https://github.com/NixOS/nixpkgs/issues/56860
- https://github.com/uniphil/nix-for-devs#os-library-dependencies
- https://github.com/nixcloud/nix-shell-workshop
- https://www.reddit.com/r/NixOS/comments/4e9r8x/what_goes_in_lb_library_path/
- https://unix.stackexchange.com/questions/190719/how-to-use-libraries-installed-by-nix-at-run-time
So it seems for libraries that are not tied to anything in your
environment, you have to manually add them to your
LD_LIBRARY_PATH. It’s a bit of a bummer, but it kinda
works. $(nix-build '<nixpkgs>' -A libgit2)
this builds the library,
and links a ‘result’ directory to the built lib. We currently don’t
care about the result
directory, but we want to add that built lib
to the LD_LIBRARY_PATH.
$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(nix-build '<nixpkgs>' -A libgit2)/lib
$ drracket
(require libgit2) ; WORKSSS!!
A way to build this into your own shell.nix files is like this:
with import <nixpkgs> {};
stdenv.mkDerivation {
name = "racket";
buildInputs = [
racket
libgit2
];
LD_LIBRARY_PATH="${libgit2}/lib";
}