管理包

使用 nix-env 和 nix 可以映射到传统的包管理器上

  1. 包管理工具

命令作用

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 包
  1. 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 转为字符串。转换的结果为包构建后的绝对路径

现在假设有以下文件:

simple.c
int main (int argc, char *argv[]){
  return 0;
}
simple_builder.sh:
#!/bin/bash

export PATH="$coreutils/bin:$gcc/bin"
mkdir $out
gcc -o $out/simple $src
default.nix
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)

依然以上面的例子为例,现在将文件内容修改为:

default.nix
with (import <nixpkgs> { }); (1)

stdenv.mkDerivation rec{
  name = "simple";
  builder = "${bash}/bin/bash";
  args = [ ./simple_builder.sh ];
  src = ./simple.c;
}
1导入 nixpkgs 环境
simple_builder.sh
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 卡驱动的版本

Last moify: 2024-08-02 14:05:21
Build time:2025-08-18 18:43:08
Powered By asphinx