Nixpkgs CERNLIB 构建 Hook:CERN、CERN_LEVEL 与 CERN_ROOT 环境变量的设置机制
【免费下载链接】nixpkgsNix Packages collection & NixOS项目地址: https://gitcode.com/GitHub_Trending/ni/nixpkgs
CERNLIB 是高能物理数据分析的遗留库集合,其构建系统强依赖CERN、CERN_LEVEL、CERN_ROOT三个环境变量。本文以 nixpkgs 文档 CERNLIB hook 说明 为主体,结合仓库中实际的 hook 实现 setup-hook.sh 与打包定义 package.nix,完整讲解这个 hook 的工作原理、版本/输出路径替换机制,以及下游程序如何借助它正确完成编译。
一、背景:CERNLIB 及其构建系统对环境的依赖
CERNLIB 是一套面向高能物理(High Energy Physics)数据分析的遗留(legacy)库与模块集合。这一点可以从 nixpkgs 中 cernlib 包的元数据得到确认,package.nix 中的meta将其描述为:
"Legacy collection of libraries and modules for data analysis in high energy physics"
CERNLIB 的构建系统(make 体系)并不像现代构建系统那样从 CMake、Meson 等工具自动推导路径,而是约定通过一组环境变量来定位自身的安装树与版本层级。按 官方 hook 文档 的说法,CERN、CERN_LEVEL和CERN_ROOT是 CERNLIB 构建系统的一部分,某些程序必须在其存在的前提下才能正确编译。因此,nixpkgs 为 cernlib 提供了一个专用 setup hook,把这三个变量注入到每一个“使用 cernlib 作为构建输入”的派生构建环境中。
该 hook 文档收录于 nixpkgs 手册的 Hooks reference 章节(见 doc/hooks/index.md),与 cc-wrapper、cmake、python 等数十个构建期 hook 并列。
二、三个环境变量的含义与取值
hook 文档明确了它设置的全部变量集合,共三个:
| 变量 | 作用 | 在 hook 中的取值 |
|---|---|---|
CERN | CERNLIB 安装/构建树的根位置 | 被替换为构建产物输出路径@out@ |
CERN_LEVEL | CERNLIB 的版本层级(version level),用于区分不同年代的 CERNLIB 库布局 | 被替换为包的version |
CERN_ROOT | CERNLIB 构建系统的顶层目录变量 | 直接引用$CERN |
其中CERN_LEVEL是 CERNLIB 历史上表示版本级别的变量,下游库的 make 体系会用它拼接出对应的头文件与库文件目录;CERN_ROOT则是整个构建树的顶层,通常与CERN一致指向安装位置。从源码结构看,nixpkgs 的 hook 实现正是按这一约定把“安装位置”与“版本级别”绑定到 store 输出路径上,从而让 CERNLIB 的 make 体系在 Nix 的隔离构建环境中也能正确找到自身资源。
三、Hook 的源码级实现
3.1 setup-hook.sh:三行脚本
hook 的全部逻辑位于 setup-hook.sh,内容非常精炼:
export CERN_LEVEL=@version@ export CERN=@out@ export CERN_ROOT=$CERN三行export分别对应上表中的三个变量,其中两处使用了 nixpkgs 的占位符替换语法:
@version@:构建系统在注入该脚本前,会用 cernlib 包定义中的version字段替换它。结合 package.nix 中version = "2025.09.18.4"的定义,最终生效的是export CERN_LEVEL=2025.09.18.4。@out@:被替换为该派生输出的 store 路径(即 cernlib 安装完成后的out输出目录),从而保证CERN精确指向 Nix store 中的实际安装位置,而不是构建期的临时目录。CERN_ROOT不经过占位符替换,而是直接取$CERN的运行时值,保证两者恒等。
3.2 setupHook 属性:把脚本挂到包上
hook 脚本本身只是一个文件,它通过 package.nix 中的setupHook属性挂载到 cernlib 包上:
setupHook = ./setup-hook.sh;这是 nixpkgs setup hook 框架的标准用法:当一个包声明了setupHook时,该脚本就成为该“hook 包”的一部分。任何把 cernlib 列入buildInputs(或nativeBuildInputs)的下游派生,在构建阶段都会由 stdenv 自动 source 这个脚本,于是CERN、CERN_LEVEL、CERN_ROOT在其 configure、compile、install 各阶段全程可见。这正是文档所说“some programs to compile correctly”得以成立的机制——下游程序不需要(也不应该)自己在preConfigure里手写这些export,只需依赖 cernlib 这一个输入即可。
四、cernlib 包本身的构建要点
hook 依附的 cernlib 包(package.nix)是一个典型的stdenv.mkDerivation+ CMake 构建,了解它的几个关键细节有助于理解 hook 所处的完整上下文。
4.1 版本与来源
version = "2025.09.18.4"; pname = "cernlib"; year = lib.versions.major version;源码通过fetchurl以双 URL 方式抓取(ftp.riken.jp镜像与 CERNLIB 官方站点互为备份),year由版本号的主段推导出来用于拼接下载路径。
4.2 postPatch:两处针对性补丁
postPatch 阶段做了两处修改:
- 将 CMake 中查找
gsed的逻辑放宽为查找sed——Nix 构建环境里 GNU sed 就是sed,不存在gsed这个名字,不放宽会导致find_program失败; - 把
packlib/cspack/tcpaw/tcpaw.c中对已废弃的<termio.h>的引用替换为 POSIX 的<termios.h>(包括struct termio→struct termios)。现代 Linux 内核与 glibc 已不再提供termio.h,这是上游代码在新平台上编译的必要修正。
4.3 preConfigure:绕过 gfortran 的 -iframework 干扰
preConfigure 阶段用sed从NIX_CFLAGS_COMPILE中剔除-iframework参数。源码注释说明:gfortran 对-iframework会发出警告,而该警告会干扰 CMake 的check_fortran_compiler_flag探测逻辑(注释中同时引用了一个上游 issue 作为佐证)。这是 Nix 的 Darwin 相关默认编译参数与 CMake Fortran 特性探测之间的已知交互问题。
4.4 构建依赖与平台支持
buildInputs组合了 Fortran 编译器(gfortran)、X11 家族库(libx11、libxaw、libxft、libxt、motif)、freetype、openssl、libxcrypt,并在 Linux 目标平台上追加libnsl(见 package.nix 的lib.optional stdenv.hostPlatform.isLinux libnsl)。meta.platforms声明支持aarch64-linux、i686-linux、x86_64-linux三个 Linux 平台,许可证为 GPL-2(lib.licenses.gpl2)。
五、在下游包中使用该 hook
从 hook 的挂载方式可以推断其使用模式:
buildInputs = [ cernlib ]; # 或 nativeBuildInputs把 cernlib 加入构建输入后,stdenv 会在构建期自动 source 上述setup-hook.sh,CERN、CERN_LEVEL、CERN_ROOT随即生效,CERNLIB 依赖型程序(典型为历史遗留的高能物理分析代码)的 C 编译器与链接器即可通过 CERNLIB 的 make 体系约定找到头文件与库。由于@out@被替换为 store 输出路径,依赖关系同时也通过 Nix 的依赖图正确表达——下游派生会记录对 cernlib 输出的依赖,保证安装的 CERNLIB 在运行时依然存在。
六、小结与参考文件
这个 hook 展示了 nixpkgs setup hook 框架处理“构建系统强依赖特定环境变量”类问题的标准范式:把环境约定收敛为一个极小的 hook 脚本,用@version@/@out@占位符与 Nix 的包模型对齐,再通过setupHook属性随包分发。对 CERNLIB 生态而言,它保证了一组遗留物理分析程序能在现代 Nix 构建环境中按上游约定完成编译。
关键参考文件:
- CERNLIB hook 文档:hook 的职责定义(三个环境变量的出处)
- Hooks reference 索引:该文档在 nixpkgs 手册中的位置
- setup-hook.sh:hook 的完整实现(3 行)
- package.nix:cernlib 打包定义,含
setupHook挂载(L61)、postPatch补丁(L31-L39)、preConfigure修正(L43-L45)与元数据(L63-L72)
【免费下载链接】nixpkgsNix Packages collection & NixOS项目地址: https://gitcode.com/GitHub_Trending/ni/nixpkgs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考