我目前正在尝试将一些闭源软件打包到 Nix 派生中。该应用程序作为一大堆.deb
文件分发,其中大多数包含应用程序其他部分可以使用的库。
为了简化,假设app.deb
包含实际应用程序,并lib.deb
包含应用程序所需的库。
目前我有:
# default.nix
let
nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-23.11";
pkgs = import nixpkgs {
config = { };
overlays = [ ];
};
in {
lib = pkgs.callPackage ./lib.nix { };
app = pkgs.callPackage ./app.nix { };
}
# lib.nix
{ lib, stdenv, autoPatchelfHook, dpkg, requireFile,
libcxx, libgcc, }:
stdenv.mkDerivation {
pname = "myapp-lib";
version = "1.0.0";
src = requireFile {
name = "lib.deb";
sha256 = "313e8686118ccba397de0bdfca101f1053b758227fd9d3510ea78644f2450bfe";
url = "https://softwarecorp.example/downloads";
};
nativeBuildInputs = [
dpkg
autoPatchelfHook
];
unpackPhase = "dpkg-deb -x $src .";
buildInputs = [ libcxx libgcc ];
installPhase = ''
cp -r lib $out/
'';
}
# app.nix
{ lib, stdenv, autoPatchelfHook, dpkg, requireFile,
libcxx, }:
stdenv.mkDerivation {
pname = "myapp-bin";
version = "1.0.0";
src = requireFile {
name = "app.deb";
sha256 = "f4abbdb3f83d982569c5cd30ce5ad63ec4e49011d165e17a2c59d9a613f163b9";
url = "https://softwarecorp.example/downloads";
};
nativeBuildInputs = [
dpkg
autoPatchelfHook
];
unpackPhase = "dpkg-deb -x $src .";
buildInputs = [ libcxx ];
installPhase = ''
cp -r bin $out/
'';
runtimeDependencies = [ myapp-lib ]; # <-- how to do this?
}
推导lib
是建立在它自己的基础上的,现在我想将它包含的东西添加到app
推导中。我不能只是将其添加到文件顶部的包依赖项的常规列表中。我还想避免此时将包提交给 nixpkgs,因为我不确定我是否能够完全打包应用程序,并且在我知道可以完成之前我不想成为它的维护者。
或者,是否有任何好的模式来打包这样的闭源软件,从而避免需要进行大量的推导?据我所知,这里的库都具有相同的版本,并且从未在公司产品的其他任何地方使用过,因此在这里构建单个派生是可以接受的。
答案1
为了避免进行两次派生,可以简单地不打包该库并在installPhase
.这可以通过提取库文件来完成postUnpack
:
# app.nix
{
stdenv,
autoPatchelfHook,
dpkg,
requireFile,
libcxx,
}: let
myLib = requireFile {
name = "lib.deb";
sha256 = "313e8686118ccba397de0bdfca101f1053b758227fd9d3510ea78644f2450bfe";
url = "https://softwarecorp.example/downloads";
};
in
stdenv.mkDerivation {
pname = "myapp-bin";
version = "1.0.0";
src = requireFile {
name = "app.deb";
sha256 = "f4abbdb3f83d982569c5cd30ce5ad63ec4e49011d165e17a2c59d9a613f163b9";
url = "https://softwarecorp.example/downloads";
};
nativeBuildInputs = [
dpkg
autoPatchelfHook
];
unpackPhase = "dpkg-deb -x $src .";
postUnpack = ''
dpkg-deb -x ${myLib} .
cp -r lib $out/
'';
buildInputs = [libcxx];
installPhase = ''
cp -r bin $out/
'';
}
套餐epson-alc1100
是这种实现的一个例子。
答案2
首先,您需要能够lib
在编写 的表达式时访问推导app
。因此,您应该更改 的底部default.nix
以拥有一个“递归”集,其中元素可以相互引用,并lib
作为参数传递给app
:
{
lib = pkgs.callPackage ./lib.nix { };
app = pkgs.callPackage ./app.nix { inherit lib; };
}
现在app.nix
需要一个名为 的参数lib
,但看起来您已经添加了该参数。 (实际上,在您的真实代码中,我希望参数被命名为其他名称,因为pkgs.lib
是 提供的库nixpkgs
,并且您希望能够在推导中使用它而不会发生名称冲突。)
现在app.nix
,只需写下inherit lib;
您要传递到的集合即可mkDerivation
。这相当于lib = lib;
,这意味着它将设置一个名为lib
等于lib
派生输出路径的环境变量。 (尽管您在问题中写了什么,但我认为这不是runtimeDependencies
有效的论据mkDerivation
。)
现在,在您的构建器脚本中,app
您可以执行任何需要的lib
操作来使其成为app
.例如,您可以编写ln -s $out/lib $lib
一个符号链接。您要在此处执行的操作的确切细节取决于应用程序如何查找其库的详细信息,而我没有这些详细信息,因此我只能告诉您一般性的信息。
运行nix-build -A app
并查看result
当前目录中的符号链接以查看您构建的内容,并确保它lib
以您期望的方式引用。