管理包
使用 nix-env 和 nix 可以映射到传统的包管理器上
包管理工具
命令 | 作用 |
---|---|
nix-env -i python | 从所有 channel 中查找包并安装 |
nix-env -iA nixpkgs.python | 安装 channel nixpkgs 中的 python |
nix-env -e | 删除包 |
nix search firefox | 从所有 chanel 中查找包 |
nix search nixpkgs firefox | 从 nixpkgs 中搜索包 firefox |
尽管可以以这种方式管理包,但是并不推荐。更推荐使用 [配置文件] 的方式管理系统的包 |
配置文件
Nix 对于用户的配置文件为 /home/tea/.nixpkgs/config.nix,一个范例内容如下:
{ pkgs ? import <nixpkgs> { }
}:
{
allowUnfree = true;
packageOverrides = pkgs: with pkgs;rec {
teapyEnv = pkgs.myEnvFun {
name = "teapyEnv";
buildInputs = with python3Packages; [
python3
django
];
};
pyPkgs = pkgs.python3.withPackages (p: with p; [
django
sphinx
recommonmark
sphinxcontrib-plantuml
rstcheck
]);
teaProfile = writeText "teaProfile" ''
#!/bin/bash
export CC="ccache gcc"
export CPP="ccache cpp"
export CXX="ccache g++"
export PKG_CONFIG_PATH=~/.nix-profile/lib/pkgconfig
'';
teaEnvs = with pkgs; buildEnv {
name = "teaEnvs";
paths = [
(runCommand "profile" { } ''
mkdir -p $out/etc/profile.d
cp ${teaProfile} $out/etc/profile.d/teaProfile.sh
'')
gcc
cmake
ninja
ccache
];
extraOutputsToInstall = [ "dev" ];
};
};
}
然后在 ~/.basrhc 文件中添加:
if [ -d $HOME/.nix-profile/etc/profile.d ]; then
for i in $HOME/.nix-profile/etc/profile.d/*.sh; do
if [ -r $i ]; then
. $i
fi
done
fi
import
import 用于导入一个 表达式,用法一般有两种:
还记得吗?Nix 将所有的内容视为表达式,这包括 Nix 文件和 Nix 包 |
import 方式
表达式 | 功能 |
---|---|
import ./file.nix | 从文件中导入表达式 |
import <nixpkgs> | 从 nixpkgs 中导入表达式 |
其中第二种方式会从 $NIX_PATH
中搜索路径。默认情况下为 ~/.nix-defexpr/channels
。一个典型的例子为:
. ├── nixpkgs -> /nix/store/dgg8jy58h3p0klx7dl4b3gjp97z68fmj-nixpkgs-22.05/nixpkgs │ ├── CONTRIBUTING.md │ ├── COPYING │ ├── default.nix │ ├── doc │ ├── flake.nix │ ├── lib │ ├── maintainers │ ├── nixos │ ├── nixpkgs -> . [recursive, not followed] │ ├── pkgs │ ├── programs.sqlite │ ├── README.md │ └── svn-revision └── nixpkgs-unstable -> /nix/store/hcy82cwhw54pgdp17rzlbi2w1jjpz8kq-nixpkgs-unstable/nixpkgs-unstable ├── CONTRIBUTING.md ├── COPYING ├── default.nix ├── doc ├── flake.nix ├── lib ├── maintainers ├── nixos ├── pkgs ├── README.md └── svn-revision
如上图所示,import nixpkgs
相当于从 ~/.nix-defexpr/channels
中导入 nixpkgs 表达式。
Details
如果你执行了下列命令:
$ nix-channel --add https://mirrors.tuna.tsinghua.edu.cn/nix-channels/nixpkgs-unstable nixpkgs-unstable
然后在 Nix 中写下了下面的命令来构建包:
{ pkgs ? import <nixpkgs-unstable> {} }:
会发现 Nix 找不到 nixpkgs-unstable。这是因为每个 nix channel 都是一个包,需要下载后才能使用:
$ nix-channel update
Derivation
derivation 函数用于指导 Nix 如何构建包。Nix 要想构建包,都要使用 Derivation 函数。
derivation 产生的输出是一个表,此表的内容为:
buildins.derivation rec{
system: "x86_64-linux"; // 必须参数
name: "package_name"; // 必须参数
builder: "./builder.sh"; // 必须参数
outputs = [ "lib" "headers" "doc"]; // 可选参数
}
derivation 作为 builtins 中的一个函数,在 Nix 中总是全局可见的,并不需要使用 builtins.derivation 的方式调用
如果 derivation 包含了一个 out 属性,derivation 就可以使用 builtins.toString 转为字符串。转换的结果为包构建后的绝对路径 |
现在假设有以下文件:
int main (int argc, char *argv[]){
return 0;
}
#!/bin/bash
export PATH="$coreutils/bin:$gcc/bin"
mkdir $out
gcc -o $out/simple $src
with (import <nixpkgs> { });
builtins.derivation rec{
name = "simple";
builder = "${bash}/bin/bash";
args = [ ./simple_builder.sh ];
inherit gcc coreutils;
src = ./simple.c;
system = builtins.currentSystem;
}
Details
default.nix 的另一种写法为:
let
nixpkgs = import <nixpkgs> { };
in
with nixpkgs; builtins.derivation rec{
name = "simple";
builder = "${bash}/bin/bash";
args = [ ./simple_builder.sh ];
inherit gcc coreutils;
src = ./simple.c;
system = builtins.currentSystem;
}
执行 nix-build default
,然后文件就会在 ./result 中构建
stdenv
stdenv 是 nixpkgs 导出的一个库。是对 builtins.derivation 的一次封装,提供了构建时常用的一些命令:
GNU C/C++ 编译器
GNU oreutils
GNU findutils
GNU diffutils
GNU sed
GNU grep
GNU awk
GNU tar
gzip, bzip2 和 xz
GNU make
bash
patch 命令
patchelf 命令(Linux Only)
依然以上面的例子为例,现在将文件内容修改为:
with (import <nixpkgs> { }); (1)
stdenv.mkDerivation rec{
name = "simple";
builder = "${bash}/bin/bash";
args = [ ./simple_builder.sh ];
src = ./simple.c;
}
1 | 导入 nixpkgs 环境 |
source $stdenv/setup (1)
mkdir -p $out/bin
gcc -o $out/bin/simple $src
1 | 导入标准环境 |
两者对比可以发现,现在 bash, gcc 等无需手动导入,而是 stdenv 自带。
在构建包时,永远不要使用 builtins.derivation,而是使用 stdenv.mkDerivation |
构建开发环境
nixpkgs 提供了通过对 stdenv.mkDerivation 进行特化,得到了另一个函数 nixpkgs.mkShell 用于构建 Shell 环境。
例如:
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
packages = [ pkgs.gnumake ];
inputsFrom = [ pkgs.hello pkgs.gnutar ];
shellHook = ''
export DEBUG=1
'';
}
Details
mkShell 的完整实现位于 mkshell
其内容如下:
{
lib,
stdenv,
buildEnv,
}:
# A special kind of derivation that is only meant to be consumed by the
# nix-shell.
{
name ? "nix-shell",
# a list of packages to add to the shell environment
packages ? [ ],
# propagate all the inputs from the given derivations
inputsFrom ? [ ],
buildInputs ? [ ],
nativeBuildInputs ? [ ],
propagatedBuildInputs ? [ ],
propagatedNativeBuildInputs ? [ ],
...
}@attrs:
let
mergeInputs =
name:
(attrs.${name} or [ ])
++ (lib.subtractLists inputsFrom (lib.flatten (lib.catAttrs name inputsFrom)));
rest = builtins.removeAttrs attrs [
"name"
"packages"
"inputsFrom"
"buildInputs"
"nativeBuildInputs"
"propagatedBuildInputs"
"propagatedNativeBuildInputs"
"shellHook"
];
in
stdenv.mkDerivation (
{
inherit name;
buildInputs = mergeInputs "buildInputs";
nativeBuildInputs = packages ++ (mergeInputs "nativeBuildInputs");
propagatedBuildInputs = mergeInputs "propagatedBuildInputs";
propagatedNativeBuildInputs = mergeInputs "propagatedNativeBuildInputs";
shellHook = lib.concatStringsSep "\n" (
lib.catAttrs "shellHook" (lib.reverseList inputsFrom ++ [ attrs ])
);
phases = [ "buildPhase" ];
buildPhase = ''
echo "------------------------------------------------------------" >>$out
echo " WARNING: the existence of this path is not guaranteed." >>$out
echo " It is an internal implementation detail for pkgs.mkShell." >>$out
echo "------------------------------------------------------------" >>$out
echo >> $out
# Record all build inputs as runtime dependencies
export >> $out
'';
}
// rest
)
显卡
非 NixOS 上的 Nix 包管理器要运行 OpenGL 软件,需要进行额外处理。最简单的方式是使用 NixGL:
nix-channel --add https://github.com/guibou/nixGL/archive/main.tar.gz nixgl
nix-channel --update
nix-env -iA nixgl.auto.nixGLDefault --argstr nvidiaVersion 515.65.01
其中 nvidia 的版本为自己电脑安装的 N 卡驱动的版本