Как я могу передать включить флаги пути к ocamlc / ocamlopt в моем проекте дюны - PullRequest
2 голосов
/ 13 апреля 2019

Я использую NixOS и компилирую пример cohttp-сервера , используя 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. Мне нужно добавить соответствующие пути в командную строку 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, кажется неуклюжим.

Есть ли стандартный способ сделать это в дюне (добавить пути к командной строке ocamlopt с помощью -I)?

Если нет, есть ли более простой способ прочитать переменную окружения из dune файлов?

1 Ответ

0 голосов
/ 29 апреля 2019

Используйте stdenv.mkDerivation или (как предложено Роберт Хенсинг выше) ocamlPackages.buildDunePackage вместо runCommand.Последнее приводит к тому, что среда не включает openssl и libev в переменные окружения NIX_CFLAGS_COMPILE или NIX_LDFLAGS.Использование 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
  ];
}
...