使用 autotools 工具链推导的最佳实践
首先要明晰我们的构建方式:
- 为构建指定依赖包,这包括构建时依赖和运行时依赖;
- 指定构建脚本进行构建,并修复生成文件,删减不需要的可执行文件依赖库;
- 将生成的推导加入到用户的自定义仓库中。
基于此,我们可以分为 4 步。
构建统一依赖制定 nix 脚本
# autotools.nix
pkgs: attrs:
let
default_attrs = {
builder = "${pkgs.bash}/bin/bash";
args = [ ./builder.sh ];
base_pkgs = with pkgs; [
gnutar
gzip
gnumake
gcc
coreutils
gawk
gnused
gnugrep
binutils.bintools
findutils
patchelf
];
build_pkgs = [ ];
system = builtins.currentSystem;
};
in
derivation (default_attrs // attrs)
这是一个双变量函数,或者称为双层函数,这样我们可以对于该函数进行复用。它指定了如下的属性:
- 构建主程序,也就是
bash ./builder.sh; autotools所依赖的构建依赖包base_pkgs,以及可调整的针对于特定包的依赖build_pkgs;- 可执行文件运行系统,指定为当前系统,对于笔者来说是
x86_64-linux; - 最后一行表示将默认集合与用户自定义集合合并,如果有冲突以用户为准,将合并集合用于生成推导。
一个使用实例如下:
let
pkgs = import <nixpkgs> { };
mk_derivation = import ./autotools.nix pkgs;
in
mk_derivation {
name = "my_application";
src = "./application.tar.gz";
}
注意以上的 autotools.nix 中提到的 builder.sh 将马上给予解释。
构建脚本
以下的通用构建脚本适用于读者已经将 tar 形式压缩包下载之后,分为四个步骤:
- 初始化环境变量:将传入的推导依赖的可执行文件添加到
PATH环境变量中,将传入的推导依赖的库文件 添加到PKG_CONFIG_PATH环境变量中; - 解包阶段:将源文件解压并进入到解压目录中;
- 构建阶段:执行系统构建,并且指定安装到 NixOS 推导的默认路径中,也就是
--prefix,这将会影响 生成的可执行文件的硬编码路径; - 修复阶段:这将会移除可执行文件中的冗余依赖与冗余调试信息。
set -e
# set up environment phase
unset PATH
unset PKG_CONFIG_PATH
for p in $base_pkgs $build_pkgs; do
if [ -d $p/bin ]; then
export PATH="$p/bin${PATH:+:}$PATH"
fi
if [ -d $p/lib/pkgconfig ]; then
export PKG_CONFIG_PATH="$p/lib/pkgconfig${PKG_CONFIG_PATH:+:}$PKG_CONFIG_PATH"
fi
done
# unpack phase
tar xf $src
for d in *; do
if [ -d "$d" ]; then
cd "$d"
break
fi
done
# build phase
./configure --prefix=$out
make
make install
# fix up phase
find $out -type f -exec patchelf --shrink-rpath '{}' \; -exec strip '{}' \; 2>/dev/null
使用 input pattern 的 nix 推导脚本
以下将所需依赖以及需要配置的选项作为参数传入,以达到依据用户要求动态生成的目的。
# graphviz.nix
{ mk_derivation, lib, gd_support? true, gd, pkg-config }:
mk_derivation {
name = "graphviz";
src = ./graphviz-2.49.3.tar.gz;
build_pkgs =
if gd_support
then [
pkg-config
(lib.getLib gd)
(lib.getDev gd)
]
else [];
}
使用 default.nix 将推导目标添加到仓库中
我们将可以在 nix repl 环境中 :l ./default.nix 将推导目标添加进来。
也可以直接在目录下执行 nix-build 生成所有推导目标。
也可以在目录下执行 nix-build -A gnu-hello 生成特定推导目标。
如果不在该目录下,那么可以执行 nix-build {repository path} -A {specfic derivation}。
# default.nix
let
pkgs = import <nixpkgs> { };
mk_derivation = import ./autotools.nix pkgs;
in
with pkgs; # will ignore mk_derivation because it is defined in `let` block
{
gnu-hello = import ./gnu_hello/hello.nix { inherit mk_derivation; };
graphviz = import ./graphviz/graphviz_opt.nix {
inherit
mk_derivation
lib
gd
pkg-config
;
};
graphviz_core = import ./graphviz/graphviz_opt.nix {
inherit
mk_derivation
lib
gd
pkg-config
;
gd_support = false;
};
}
目录结构
├── autotools.nix
├── builder.sh
├── default.nix
├── gnu_hello
│ ├── hello.nix
│ ├── hello-2.12.1.tar.gz
├── graphviz
│ ├── graphviz-2.49.3.tar.gz
│ └── graphviz_opt.nix