nix 实战经验:安装和打包 |
nix 的使用确实存在一定的复杂性,甚至需要学习其独特的编程语言,但我始终致力于以简洁的方式掌握它的使用。为了避开复杂的配置文件管理,我一直在寻找更简洁的方法。以下是我目前的学习成果,期待与您分享如何进行操作: 首先,使用 nix 来安装软件包非常简单。只需要在命令行输入 其次,如果你有一个 C++ 程序,名为 paperjam,并希望为其构建一个自定义的 nix 包,你需要创建一个名为 default.nix 的文件。在这个文件中,你可以描述你的程序及其依赖项。例如,如果你的程序依赖于 Boost C++ 库和 Python 解释器,你的 default.nix 文件可能如下:
最后,如果你想安装特定版本的 hugo,例如五年前的版本,你可以先在 nixpkgs 中找到相应的源,然后使用 虽然我对 nix 的理解仍停留在初级阶段,可能存在表述不准确的地方。甚至我自己也对于我是否真的喜欢上 nix 感到不确定 —— 它的使用确实具有一定的复杂性!但是,它成功帮助我编译了一些以前难以编译的软件,而且通常情况下,它的安装速度要比 homebrew 快。 尽管我对“声明式的包管理”不太感兴趣,但我仍然对nix的几个方面大为赞赏。首先,它提供了二进制包,这些包被托管在https://cache.nixos.org/上,使得下载和安装都变得相当迅速。对于那些没有提供二进制包的软件,nix能够让编译过程变得更为简单。我认为这主要归功于以下两个原因: 首先,nix允许我们在系统中安装同一库或程序的多个版本。例如,我当前的计算机上就同时安装了两个不同版本的node,一个位于/nix/store/4ykq0lpvmskdlhrvz1j3kwslgc6c7pnv-nodejs-16.17.1,另一个位于/nix/store/5y4bd2r99zhdbir95w5pf51bwfg37bwa-nodejs-18.9.1。这使得我们可以根据实际需要轻松切换和使用不同版本的软件。 其次,nix在构建包时使用了隔离的环境,只使用我们明确声明的依赖项的特定版本。这就意味着我们无需担心包可能会依赖于系统中其他我们并未了解的包。再也不用与LD_LIBRARY_PATH战斗了!这种机制使得我们能够更加精确地控制软件包的构建环境,避免了因依赖问题导致的各种错误和冲突。 在本文后面,我将通过两个具体的例子来展示nix如何帮助我在编译软件时遇到了更小困难。 下面是我开始使用 nix 的步骤: 首先,要进行安装,我尝试了两种方法。一种是官方提供的安装程序,另一种是非官方的安装程序,该程序来自 zero-to-nix.com。在 MacOS 上使用标准的多用户安装卸载 nix 的教程 有点复杂,因此我选择了一个卸载教程更为简单的安装方法。 接着,我把 最后,我使用 举个例子,如果我想安装 fish,只需要执行以下命令:
这会从 https://cache.nixos.org 下载一些二进制文件,非常简单。 有些人使用 nix 来安装他们的 Node、Python 和 Ruby 包,但我并没有这样做,我还是像以前一样使用 我认为nix包主仓库中的包是由https://github.com/NixOS/nixpkgs/定义的。 你可以在https://search.nixos.org/packages查找包,似乎有两种官方推荐的查找包的方式:
我发现了一种我更喜欢的从命令行搜索nix包的方式:
在nix中,所有的东西都是通过符号链接来安装的。nix的一个主要设计是,没有一个单一的bin文件夹来存放所有的包,而是使用了符号链接。有许多层的符号链接。例如,以下是一些符号链接的例子: 在我机器上的~/.nix-profile最终是一个到/nix/var/nix/profiles/per-user/bork/profile-111-link的链接。 这意味着,如果我安装了新版本的fish但我并不满意,我可以很容易地退回先前的版本,只需运行nix-env --rollback,这样就可以让我回到之前的配置文件目录了。 卸载包并不意味着删除它们 如果我像这样卸载 nix 包,实际上并不会释放任何硬盘空间,而仅仅是移除了符号链接: $ nix-env --uninstall oil 我尚不清楚如何彻底删除包 - 我试着运行了如下的垃圾收集命令,这似乎删除了一些项目: $ nix-collect-garbage...85 store paths deleted, 74.90 MiB freed 然而,我系统上仍然存在
$ nix-collect-garbage -d --delete-old 尽管如此,上述命令仍无法删除
你可以通过以下的方式升级 nix 包: nix-channel --updatenix-env --upgrade (这与 我还没真正尝试升级任何东西。我推测,如果升级过程中出现任何问题,我可以通过以下方式轻松地回滚(因为在 nix 中,所有事物都是不可变的!): nix-env --rollback 有人向我推荐了 Ian Henry 的 这篇文章,该文章讨论了 在历经数月使用现存的nix包之后,我萌生了制作自定义包的想法。这个包是为一个名为paperjam的程序量身定做的,而这个程序目前尚未被打包封装。 实际上,由于我系统上的libiconv版本不正确,我在没有nix的情况下遇到了编译paperjam的难题。我坚信,即使我对如何制作nix包一无所知,使用nix来编译它可能会更加简单。事实证明,我的想法是正确的! 然而,梳理并实现这个目标的过程相当复杂,因此我在此详述了我实现它的方法和步骤。 构建示例包的步骤在我着手制作 步骤 1: 从 GitHub 的 nixpkgs 下载任意一个包,以 wget https://raw.githubusercontent.com/NixOS/nixpkgs/47993510dcb7713a29591517cb6ce682cc40f0ca/pkgs/shells/dash/default.nix -O dash.nix 步骤 2: 用 步骤 3: 运行 这将开始编译该包。 步骤 4: 运行 这会将该包安装到我的 就这么简单!一旦我完成了这些步骤,我便感觉自己能够逐步修改 制作自定义包的过程因为 以下是 with import <nixpkgs> {};stdenv.mkDerivation rec { pname = "libpaper"; version = "0.1"; src = fetchFromGitHub { owner = "naota"; repo = "libpaper"; rev = "51ca11ec543f2828672d15e4e77b92619b497ccd"; hash = "sha256-S1pzVQ/ceNsx0vGmzdDWw2TjPVLiRgzR4edFblWsekY="; }; buildInputs = [ ]; meta = with lib; { homepage = "https://github.com/naota/libpaper"; description = "libpaper"; platforms = platforms.unix; license = with licenses; [ bsd3 gpl2 ]; };} 这个脚本基本上告诉 nix 如何从 GitHub 下载源代码。 我通过运行 接下来,我需要编译
我首先从散列值为空开始,然后运行 我只是在 nixpkgs 仓库中运行 然后我执行了: nix-build paperjam.nixnix-env -i -f paperjam.nix 然后所有的东西都开始工作了,我成功地安装了 下一个目标:安装一个五年前的 Hugo 版本当前,我使用的是 2018 年的 Hugo 0.40 版本来构建我的博客。由于我并不需要任何的新功能,因此我并没有感到有升级的必要。对于在 Linux 上操作,这个过程非常简单:Hugo 的发行版本是静态二进制文件,这意味着我可以直接从 发布页面 下载五年前的二进制文件并运行。真的很方便! 但在我的 Mac 电脑上,我遇到了一些复杂的情况。过去五年中,Mac 的硬件已经发生了一些变化,因此我下载的 Mac 版 Hugo 二进制文件并不能运行。同时,我尝试使用 我曾试图通过在 Linux docker 容器中运行 Hugo 来解决这个问题,但我并不太喜欢这个方法:尽管可以工作,但它运行得有些慢,而且我个人感觉这样做有些多余。毕竟,编译一个 Go 程序不应该那么麻烦! 幸好,Nix 来救援!接下来,我将介绍我是如何使用 nix 来安装旧版本的 Hugo。 使用 nix 安装 Hugo 0.40 版本我的目标是安装 Hugo 0.40,并将其添加到我的 PATH 中,以 步骤 1: 在 nixpkgs 仓库中搜索找到 Hugo 0.40。 我在此链接中找到了相应的 步骤 2: 下载该文件并进行构建。 我下载了带有 虽然这个过程几乎无需进行修改就能成功运行,但我仍然做了两处小调整:
步骤 3: 将 我编写了一个简短的后安装脚本,用以重命名 Hugo 二进制文件。 postInstall = '' mv $out/bin/hugo $out/bin/hugo-0.40 ''; 我是通过在 nixpkgs 仓库中运行 步骤 4: 安装。 我通过运行 所有的步骤都顺利运行了!我把最终的 可重复的构建过程并非神秘,其实它们极其复杂我觉得值得一提的是,这个 |