зеркало из
				https://github.com/iharh/notes.git
				synced 2025-11-04 07:36:08 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			162 строки
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			162 строки
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
https://nixos.org/guides/nix-pills/developing-with-nix-shell.html
 | 
						|
 | 
						|
10.1. What's nix-shell
 | 
						|
 | 
						|
The nix-shell tool
 | 
						|
    https://nixos.org/manual/nix/stable/#sec-nix-shell
 | 
						|
drops us in a shell by setting up the necessary environment variables to hack on a derivation.
 | 
						|
It does not build the derivation, it only serves as a preparation so that we can run the build steps manually.
 | 
						|
 | 
						|
I remind you, in a nix environment you don't have access to libraries and programs unless you install them with nix-env.
 | 
						|
However installing libraries with nix-env is not good practice.
 | 
						|
We prefer to have isolated environments for development.
 | 
						|
 | 
						|
$ nix-shell hello.nix
 | 
						|
[nix-shell]$ make
 | 
						|
    bash: make: command not found
 | 
						|
[nix-shell]$ echo $baseInputs
 | 
						|
    /nix/store/jff4a6zqi0yrladx3kwy4v6844s3swpc-gnutar-1.27.1 [...]
 | 
						|
 | 
						|
First thing to notice, we call nix-shell on a nix expression which returns a derivation.
 | 
						|
We then enter a new bash shell, but it's really useless.
 | 
						|
We expected to have the GNU hello world build inputs available in PATH, including GNU make, but it's not the case.
 | 
						|
 | 
						|
But, we have the environment variables that we set in the derivation, like $baseInputs, $buildInputs, $src and so on.
 | 
						|
 | 
						|
That means we can source our builder.sh, and it will build the derivation.
 | 
						|
You may get an error in the installation phase, because the user may not have the permission to write to /nix/store:
 | 
						|
 | 
						|
[nix-shell]$ source builder.sh
 | 
						|
...
 | 
						|
 | 
						|
It didn't install, but it built. Things to notice:
 | 
						|
    * We sourced builder.sh, therefore it ran all the steps including setting up the PATH for us.
 | 
						|
    * The working directory is no more a temp directory created by nix-build, but the current directory. Therefore, hello-2.10 has been unpacked there. 
 | 
						|
 | 
						|
We're able to "cd" into hello-2.10 and type make, because now it's available.
 | 
						|
 | 
						|
In other words, "nix-shell" drops us in a shell with the same (or almost) environment used to run the builder!
 | 
						|
 | 
						|
 | 
						|
10.2. A builder for nix-shell
 | 
						|
 | 
						|
The previous steps are a bit annoying of course, but we can improve our builder to be more nix-shell friendly.
 | 
						|
 | 
						|
First of all, we were able to source builder.sh because it was in our current directory, but that's not nice.
 | 
						|
We want the builder.sh that is stored in the nix store, the one that would be used by nix-build.
 | 
						|
To do so, the right way is to pass the usual environment variable through the derivation.
 | 
						|
 | 
						|
Note: $builder is already defined, but it's the bash executable, not our builder.sh.
 | 
						|
Our builder.sh is an argument to bash.
 | 
						|
 | 
						|
Second, we don't want to run the whole builder, we only want it to setup the necessary environment for manually building the project.
 | 
						|
So we'll write two files:
 | 
						|
    * one for setting up the environment,
 | 
						|
    * and the real builder.sh that runs with nix-build.
 | 
						|
 | 
						|
Additionally, we'll wrap the phases in functions, it may be useful, and move the "set -e" to the builder instead of the setup.
 | 
						|
The "set -e" is annoying in nix-shell.
 | 
						|
 | 
						|
Here is our modified autotools.nix.
 | 
						|
Noteworthy is the setup = ./setup.sh; attribute in the derivation,
 | 
						|
which adds setup.sh to the nix store and as usual, adds a $setup environment variable in the builder.
 | 
						|
 | 
						|
pkgs: attrs:
 | 
						|
    with pkgs;
 | 
						|
    let defaultAttrs = {
 | 
						|
        builder = "${bash}/bin/bash";
 | 
						|
        args = [ ./builder.sh ];
 | 
						|
        setup = ./setup.sh;
 | 
						|
        baseInputs = [ gnutar gzip gnumake gcc binutils-unwrapped coreutils gawk gnused gnugrep patchelf findutils ];
 | 
						|
        buildInputs = [];
 | 
						|
        system = builtins.currentSystem;
 | 
						|
    };
 | 
						|
    in
 | 
						|
        derivation (defaultAttrs // attrs)
 | 
						|
 | 
						|
Thanks to that, we can split builder.sh into setup.sh and builder.sh.
 | 
						|
What builder.sh does is sourcing $setup and calling the genericBuild function.
 | 
						|
Everything else is just some bash changes.
 | 
						|
 | 
						|
 | 
						|
Here is the modified builder.sh.
 | 
						|
 | 
						|
set -e
 | 
						|
source $setup
 | 
						|
genericBuild
 | 
						|
 | 
						|
 | 
						|
Here is the modified setup.sh.
 | 
						|
 | 
						|
unset PATH
 | 
						|
for p in $baseInputs $buildInputs; do
 | 
						|
    export PATH=$p/bin${PATH:+:}$PATH
 | 
						|
done
 | 
						|
 | 
						|
function unpackPhase() {
 | 
						|
    tar -xzf $src
 | 
						|
 | 
						|
    for d in *; do
 | 
						|
        if [ -d "$d" ]; then
 | 
						|
            cd "$d"
 | 
						|
            break
 | 
						|
        fi
 | 
						|
    done
 | 
						|
}
 | 
						|
 | 
						|
function configurePhase() {
 | 
						|
    ./configure --prefix=$out
 | 
						|
}
 | 
						|
 | 
						|
function buildPhase() {
 | 
						|
    make
 | 
						|
}
 | 
						|
 | 
						|
function installPhase() {
 | 
						|
    make install
 | 
						|
}
 | 
						|
 | 
						|
function fixupPhase() {
 | 
						|
    find $out -type f -exec patchelf --shrink-rpath '{}' \; -exec strip '{}' \; 2>/dev/null
 | 
						|
}
 | 
						|
 | 
						|
function genericBuild() {
 | 
						|
    unpackPhase
 | 
						|
    configurePhase
 | 
						|
    buildPhase
 | 
						|
    installPhase
 | 
						|
    fixupPhase
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
Finally, here is hello.nix.
 | 
						|
 | 
						|
let
 | 
						|
    pkgs = import <nixpkgs> {};
 | 
						|
    mkDerivation = import ./autotools.nix pkgs;
 | 
						|
in mkDerivation {
 | 
						|
    name = "hello";
 | 
						|
    src = ./hello-2.10.tar.gz;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
Now back to nix-shell:
 | 
						|
 | 
						|
$ nix-shell hello.nix
 | 
						|
[nix-shell]$ source $setup
 | 
						|
[nix-shell]$
 | 
						|
 | 
						|
Now you can run, for example, unpackPhase which unpacks $src and enters the directory.
 | 
						|
And you can run commands like ./configure, make etc. manually, or run phases with their respective functions.
 | 
						|
 | 
						|
It's that straightforward, nix-shell builds the .drv file and its input dependencies,
 | 
						|
then drops into a shell by setting up the environment variables necessary to build the .drv, in particular those passed to the derivation function.
 | 
						|
 | 
						|
 | 
						|
10.3. Conclusion
 | 
						|
 | 
						|
With nix-shell we're able to drop into an isolated environment for developing a project, with the necessary dependencies just like nix-build does.
 | 
						|
Additionally, we can build and debug the project manually, step by step like you would do in any other operating system.
 | 
						|
Note that we never installed gcc, make, etc. system-wide.
 | 
						|
These tools and libraries are available per-build. 
 |