You are running nix/NixOS and have ever encountered the following problem?
$ ./myapp
bash: ./myapp: No such file or directory
Fear not, now there is nix-alien
which will download necessary dependencies
for you.
$ nix-alien myapp # Run the binary inside a FHS shell with all needed shared dependencies to execute the binary
$ nix-alien-ld myapp # Spawns you inside a shell with NIX_LD_LIBRARY_PATH set to the needed dependencies, to be used with nix-ld
$ nix-alien-find-libs myapp # Lists all libs needed for the binary
If your binary is located in ~/myapp
, run:
$ nix --extra-experimental-features "nix-command flakes" run github:thiagokokada/nix-alien -- ~/myapp
Tip
If you are trying to run an OpenGL binary (e.g.: blender
) in non-NixOS
systems, you can wrap the command above in
nixGL:
$ nix --extra-experimental-features "nix-command flakes" run --impure github:guibou/nixGL --override-input nixpkgs nixpkgs/nixos-unstable -- nix run github:thiagokokada/nix-alien -- blender
Once nix-alien
is installed in your system, all you need to do is run:
$ nix-alien ~/myapp
This will run nix-alien
on ~/myapp
binary with a FHSUserEnv
including all
shared library dependencies. The resulting default.nix
file will be saved to
$XDG_CACHE_HOME/nix-alien/<path-uuid>/fhs-env/default.nix
, making the next
evaluation faster. The cache is based on the binary absolute path. You can also
pass --recreate
flag to force the recreation of default.nix
file, and
--destination
to change where default.nix
file will be saved.
To pass arguments to the app:
$ nix-alien ~/myapp -- --foo bar
In case you're using nix-ld
, there is also
nix-alien-ld
:
$ nix-alien-ld -- ~/myapp
This will spawn a wrapped binary with NIX_LD_LIBRARY_PATH
and NIX_LD
setup.
The resulting default.nix
file will be saved to
$XDG_CACHE_HOME/nix-alien/<path-uuid>/nix-ld/default.nix
, making the next
evaluation faster. The cache is based on the binary absolute path. You can also
pass --recreate
flag to force the recreation of default.nix
file, and
--destination
to change where default.nix
file will be saved.
To pass arguments to the app:
$ nix-alien-ld ~/myapp -- --foo bar
If you want to use the fzf
based menu to find the libraries for scripting
purposes, you can run:
$ nix-alien-find-libs ~/myapp
This will print the found libraries on the stdout
. The informational messages
are printed to stderr
, so you can easily redirect them to /dev/null
if
needed. You can also use --json
flag to print the result as a JSON instead.
There are also some other options, check them using --help
flag on each
program. Example for nix-alien
:
usage: nix-alien [-h] [--version] [-l LIBRARY] [-p PACKAGE] [-c CANDIDATE] [-r] [-d PATH] [-P] [-E] [-s] [-f] program ...
positional arguments:
program Program to run
ellipsis Arguments to be passed to the program
options:
-h, --help show this help message and exit
--version show program's version number and exit
-l LIBRARY, --additional-libs LIBRARY
Additional library to search. May be passed multiple times
-p PACKAGE, --additional-packages PACKAGE
Additional package to add. May be passed multiple times
-c CANDIDATE, --select-candidates CANDIDATE
Library candidates that will be auto-selected if found via regex. Useful for automation.
-r, --recreate Recreate 'default.nix' file if exists
-d PATH, --destination PATH
Path where 'default.nix' file will be created
-P, --print-destination
Print where 'default.nix' file is located and exit
-E, --edit Edit 'default.nix' using $EDITOR (or 'nano' if unset)
-s, --silent Silence informational messages
-f, --flake Create and use 'flake.nix' file instead (experimental)
You can run the scripts from this repo directly without cloning or installing them, assuming you're using a resonable up-to-date nix and enabled experimental Flakes support.
$ nix run "github:thiagokokada/nix-alien#nix-alien" -- ~/myapp
$ nix run "github:thiagokokada/nix-alien#nix-alien-ld" -- ~/myapp
$ nix run "github:thiagokokada/nix-alien#nix-alien-find-libs" -- ~/myapp
Or if you don't have Flakes enabled but still wants to run it without downloading it first:
$ nix --extra-experimental-features "nix-command flakes" run "github:thiagokokada/nix-alien#nix-alien" -- ~/myapp
$ nix --extra-experimental-features "nix-command flakes" run "github:thiagokokada/nix-alien#nix-alien-ld" -- ~/myapp
$ nix --extra-experimental-features "nix-command flakes" run "github:thiagokokada/nix-alien#nix-alien-find-libs" -- ~/myapp
You can add the following contents to a /etc/nixos/nix-alien.nix
file:
{ ... }:
let
nix-alien-pkgs = import (
builtins.fetchTarball "https://github.com/thiagokokada/nix-alien/tarball/master"
) { };
in
{
environment.systemPackages = with nix-alien-pkgs; [
nix-alien
];
# Optional, but this is needed for `nix-alien-ld` command
programs.nix-ld.enable = true;
}
And afterwards, add it to imports
section on /etc/nixos/configuration.nix
file.
Warning
Overriding nix-alien
inputs may cause mismatches between the
nix-index-database
and nixpkgs
, causing possibly incorrect results, so it
is unsupported.
If you're using NixOS with Flakes, you can do something similar to your NixOS
setup to install nix-alien
on system PATH
:
{
description = "nix-alien-on-nixos";
inputs.nixpkgs.url = "github:NixOS/nixpkgs";
inputs.nix-alien.url = "github:thiagokokada/nix-alien";
outputs = { self, nixpkgs, nix-alien }: {
nixosConfigurations.nix-alien-desktop = nixpkgs.lib.nixosSystem rec {
system = "x86_64-linux"; # or aarch64-linux
specialArgs = { inherit self system; };
modules = [
({ self, system, ... }: {
environment.systemPackages = with self.inputs.nix-alien.packages.${system}; [
nix-alien
];
# Optional, needed for `nix-alien-ld`
programs.nix-ld.enable = true;
})
];
};
};
}
Alternatively, you can also use the included overlay. Keep in mind that the
overlay will use your current nixpkgs
pin instead the one included in this
project flake.lock
file.
This has the advantage of reducing the general size of your /nix/store
,
however since the version of nixpkgs
you currently have is not tested this may
cause issues.
{
description = "nix-alien-on-nixos";
inputs.nixpkgs.url = "github:NixOS/nixpkgs";
inputs.nix-alien.url = "github:thiagokokada/nix-alien";
outputs = { self, nixpkgs, nix-alien }: {
nixosConfigurations.nix-alien-desktop = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; # or aarch64-linux
specialArgs = { inherit self; };
modules = [
({ self, ... }: {
nixpkgs.overlays = [
self.inputs.nix-alien.overlays.default
];
environment.systemPackages = with pkgs; [
nix-alien
];
# Optional, needed for `nix-alien-ld`
programs.nix-ld.enable = true;
})
];
};
};
}
You can add the following contents to your Home-Manager configuration file:
{ ... }:
let
nix-alien-pkgs = import (
builtins.fetchTarball "https://github.com/thiagokokada/nix-alien/tarball/master"
) { };
in
{
# ...
home.packages = with nix-alien-pkgs; [
nix-alien
];
}
If you're using Home-Manager with Flakes, you can use:
{
description = "nix-alien-on-home-manager";
inputs.nixpkgs.url = "github:NixOS/nixpkgs";
inputs.home-manager.url = "github:nix-community/home-manager";
inputs.nix-alien.url = "github:thiagokokada/nix-alien";
outputs = { self, nixpkgs, home-manager, nix-alien }:
let
system = "x86_64-linux"; # or aarch64-linux
pkgs = import nixpkgs { inherit system; };
in {
homeConfigurations.nix-alien-home = home-manager.lib.homeManagerConfiguration rec {
inherit pkgs;
extraSpecialArgs = { inherit self system; };
modules = [
({ self, system, ... }: {
home.packages = with self.inputs.nix-alien.packages.${system}; [
nix-alien
];
})
];
};
};
}
On non-Flakes system, you can use nix-shell
to start a development shell.
On Flakes enabled system, you can use nix develop
instead.
If you have nix-direnv
installed, there is a .envrc
file configured to start the Flakes enabled
setup automatically. Just run direnv allow
inside this repo.
Binaries loading shared libraries dynamically (e.g.: with dlopen
) will
probably not work with this script. However, this can be workarounded using
either --additional-libs/-l
or --additional-packages/-p
flag. The first one
can be used as:
$ nix-alien -l libGL.so.1 -l libz.so.1 ~/myapp
And this will be searched using nix-locate
in a similar way as the other
libraries found in the binary. The second one can be used as:
$ nix-alien -p libGL -p zlib ~/myapp
To direct add the package to default.nix
file.
Warning
There is no validation in -p
flag, so you can receive an undefied variable
error in case of an inexistent package.
This is achieved by enumerating the shared library dependencies from the ELF
header using ldd
(actually,
pylddwrap
) and then searching for the
equivalent library in nixpkgs
. This is done by querying nix-locate
locally.
To solve possible conflicts, human intervation is needed, but thanks to
fzf
and
pyfzf
this is made easy by
showing an interactive list.
- Inspired by Lassulus/nix-autobahn
- Thanks to Mic92/nix-ld, Mic92/nix-index-database and bennofs/nix-index, since without them this project wouldn't be possible