如何在我的沙丘项目中将包含路径标志传递给 ocamlc/ocamlopt

How can I pass include path flags to ocamlc/ocamlopt in my dune project

我正在使用 NixOS and compiling the cohttp server example using 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})))

config/dune

(executable
 (name discover)
 (libraries dune.configurator))

config/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)

现在编译成功了,但是这种编写自定义程序以获取环境变量并将其放入标志参数的方法似乎很笨拙。

是否有在沙丘中完成此操作的标准方法(使用 -I 添加到 ocamlopt 命令行的路径)?

如果没有,是否有更简单的方法从 dune 个文件中读取环境变量?

使用 stdenv.mkDerivation 或(如上面 Robert Hensing 所建议的那样)ocamlPackages.buildDunePackage 而不是 runCommand。后者导致 NIX_CFLAGS_COMPILENIX_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
  ];
}