You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何从源码构建Nix包?default.nix编写逻辑技术问询

从源码构建NixOS软件包的关键要点(以gedit为例)

我太懂这种感觉了——明明能看懂Nix表达式的语法,可真要动手写一个能构建出软件包的default.nix,脑子里就一片空白,看着gedit那种现成的表达式,完全摸不着别人是怎么一步步凑出来的对吧?其实你没搞懂的不是Nix语言,而是把软件的常规构建流程映射到Nix表达式的逻辑,下面我就拆解几个核心要点:

1. 先搞懂软件本身的构建流程,这是基础

Nix不是凭空构建软件的,它本质上是把你在常规Linux环境下编译软件的步骤,用Nix的方式封装起来。比如gedit是GNOME旗下的编辑器,它的常规构建流程是:

  • meson setup生成构建文件(因为它用meson构建系统)
  • ninja编译代码
  • meson install把产物安装到指定目录

你得先搞清楚目标软件用什么构建系统(meson、autotools、cmake还是其他)、需要哪些依赖(编译时的工具、运行时的库)、有没有自定义的配置参数——这些信息是写Nix表达式的前提。

2. 用好Nixpkgs的通用构建函数:stdenv.mkDerivation(或其封装)

绝大多数Nix软件包都是基于stdenv.mkDerivation来写的,它帮你处理了环境变量、路径隔离、依赖传递这些底层细节。以gedit为例,它用的是GNOME专属的封装gnome.mkDerivation(本质是对stdenv.mkDerivation的扩展,专门处理GNOME软件的共性需求,比如gsettings schema安装、图标处理)。

你需要重点关注这些核心参数:

  • src:指定软件源码的来源,比如gedit用fetchFromGitLab拉取GNOME仓库的源码,你需要填对仓库地址、commit哈希或者版本号。
  • nativeBuildInputs编译时需要的工具,比如meson、ninja、pkg-config、gettext——这些工具是用来生成构建文件、编译代码的,不需要打包到最终的软件包里。
  • buildInputs运行时依赖的库,比如gtk3、libadwaita、gtksourceview5——这些是gedit运行时必须链接的库,会被自动包含到最终的包中。
  • mesonFlags(针对meson构建的软件):传递给meson setup的自定义参数,比如启用某个插件、关闭某个功能,比如gedit可能会加-Dplugin_markdown=true来启用markdown插件。

3. 参考Nixpkgs里的同类包,抄作业是最快的方法

Nixpkgs仓库里有几十万现成的包,找和你的目标软件同类的例子是最有效的学习方式。比如gedit是GNOME桌面应用,你可以去看pkgs/desktops/gnome/apps目录下的其他应用(比如gnome-text-editornautilus),它们的表达式结构几乎一致:

  • 都用gnome.mkDerivation
  • 依赖的编译工具大同小异(meson、ninja、pkg-config这些基本是标配)
  • 运行时依赖都是GNOME生态的库(gtk、libadwaita等)

看别人怎么处理依赖、怎么传递构建参数,比自己瞎琢磨快多了。

4. 调试迭代:用nix-buildnix-shell排查问题

写表达式不可能一次就对,学会调试很重要:

  • nix-build -A gedit构建gedit,看终端输出的日志,如果报错说“找不到某个库”,就把对应的库加到buildInputs里;如果说“找不到某个命令”,就加到nativeBuildInputs里。
  • nix-shell -A gedit --pure进入一个纯净的构建环境,手动执行常规的构建步骤(比如meson setup buildninja -C build),看哪里卡壳,这样能精准定位需要补充的依赖或参数。

举个简化版的gedit表达式例子

{ lib, stdenv, fetchFromGitLab, meson, ninja, pkg-config, gettext, gtk3, libadwaita, gtksourceview5 }:

stdenv.mkDerivation rec {
  pname = "gedit";
  version = "44.2";

  src = fetchFromGitLab {
    domain = "gitlab.gnome.org";
    owner = "GNOME";
    repo = pname;
    rev = version;
    hash = "sha256-xxxxxxxxx"; # 替换成实际的哈希值
  };

  nativeBuildInputs = [ meson ninja pkg-config gettext ];

  buildInputs = [ gtk3 libadwaita gtksourceview5 ];

  mesonFlags = [ "-Dplugin_example=true" ];

  meta = with lib; {
    description = "GNOME's text editor";
    homepage = "https://wiki.gnome.org/Apps/Gedit";
    license = licenses.gpl2Plus;
    platforms = platforms.linux;
    maintainers = teams.gnome.members;
  };
}

这个简化版里,我们用stdenv.mkDerivation定义了包的基本信息、源码、依赖和构建参数,和实际的gedit表达式核心逻辑是一致的。

说白了,写Nix包表达式的核心就是:把你手动编译软件的每一步,翻译成Nix能理解的参数和配置,再借助Nixpkgs的现有工具和同类例子,慢慢就能上手了。

内容的提问来源于stack exchange,提问作者ricky

火山引擎 最新活动