我正在使用NixOS并使用cohttp server example编译dune。这个例子值得注意的是它链接到两个C库:openssl和libev。
初步尝试
这是我的shell.nix:
with import <nixpkgs> { };
let spec = {
buildInputs = with ocamlPackages; [
ocaml
findlib
dune
# ocaml libs (and external library deps)
cohttp-lwt-unix openssl libev
]);
};
in runCommand "dummy" spec ""
这是我的沙丘文件:
(executable
(name server_example)
(libraries cohttp-lwt-unix))
和dune build server_example.exe
的输出
...
/nix/store/3xwc1ip20b0p68sxqbjjll0va4pv5hbv-binutils-2.30/bin/ld: cannot find -lssl
/nix/store/3xwc1ip20b0p68sxqbjjll0va4pv5hbv-binutils-2.30/bin/ld: cannot find -lcrypto
/nix/store/3xwc1ip20b0p68sxqbjjll0va4pv5hbv-binutils-2.30/bin/ld: cannot find -lev
好吧,不是非常令人惊讶,因为它们位于NixOS的非标准位置。我需要将相关路径添加到由dune调用的ocamlopt命令行,例如:-I ${openssl.out}/lib -I ${libev}/lib
。
现在,openssl包含pkg-config文件,但是将pkg-config添加到我的shell.nix
没有明显的效果。
第二次尝试,使用配置器
我使用configurator创建一个程序,将环境变量中的标志添加到我的dune可执行文件的构建标志中。
shell.nix
with import <nixpkgs> { };
let spec = {
buildInputs = with ocamlPackages; [
ocaml
findlib
dune
configurator
# ocaml libs (and external library deps)
cohttp-lwt-unix openssl libev
]);
shellHook = ''
export OCAML_FLAGS="-I ${openssl.out}/lib -I ${libev}/lib"
'';
};
in runCommand "dummy" spec ""
沙丘
(executable
(name server_example)
(flags (:standard (:include flags.sexp)))
(libraries cohttp-lwt-unix))
(rule
(targets flags.sexp)
(deps (:discover config/discover.exe))
(action (run %{discover})))
配置/沙丘
(executable
(name discover)
(libraries dune.configurator))
配置/ discover.ml
open Sys
module C = Configurator.V1
let () =
C.main ~name:"getflags" (fun _c ->
let libs =
match getenv_opt "OCAML_FLAGS" with
| None -> []
| Some flags -> C.Flags.extract_blank_separated_words flags
in
C.Flags.write_sexp "flags.sexp" libs)
编译现在成功了,但是这种编写自定义程序以获取环境变量并将其放入flags参数的方法似乎很笨拙。
是否有一种标准方法可以在沙丘中实现这一目标(使用-I
添加ocamlopt命令行的路径)?
如果没有,是否有更简单的方法从dune
文件中读取环境变量?
使用stdenv.mkDerivation
或(如上面的Robert Hensing所建议的)ocamlPackages.buildDunePackage
而不是runCommand
。后者导致在NIX_CFLAGS_COMPILE
或NIX_LDFLAGS
环境变量中不包括openssl和libev的环境。使用mkDerivation
会导致填充这些变量。
一旦这些变量到位,通过dune
编译成功,可执行文件链接到libssl和libev。
此外,显式包含libev和openssl是不必要的,因为它们被声明为通过cohttp-lwt-unix传播的构建输入。
shell.nix:
with import <nixpkgs> { };
with ocamlPackages;
buildDunePackage {
pname = "dummy";
version = "0";
buildInputs = [
cohttp-lwt-unix
];
}