2016-09-30 2 views
1

У меня есть проект OCaml, который в настоящее время построен с использованием OCamlMake. Я не доволен текущей системой сборки, так как она оставляет все артефакты сборки в том же каталоге, что и исходные файлы, а также требует вручную указать порядок зависимостей между модулями. Я хотел бы перейти на систему сборки, которая не страдает от этих проблем. Я решил попробовать Oasis, но столкнулся с проблемами.Дополнительные зависимости с ocamlbuild

Проблемы возникают из-за того, что проект построен очень определенным образом. Он поддерживает несколько разных баз данных (PostgreSQL, MySQL, SQLite). В настоящее время для компиляции бэкэнда базы данных пользователь должен установить дополнительные библиотеки, необходимые для этого бэкэнд, и включить его, установив переменную среды. Вот как это выглядит в Makefile:

ifdef MYSQL_LIBDIR 
    DB_CODE += mysql_database.ml 
    DB_AUXLIBS += $(MYSQL_LIBDIR) 
    DB_LIBS += mysql 
endif 

Обратите внимание, что это также добавляет дополнительный модуль в список скомпилированных модулей. Важный бит заключается в том, что нет никакой зависимости (в смысле импорта модуля) между любым доступным модулем из точки входа приложения и модуля БД. Скорее всего, каждый модуль базы данных базы данных содержит код верхнего уровня, который запускается, когда модуль инициируется и регистрируется, используя побочные эффекты, с основным приложением.

Я не могу настроить эту настройку для работы с Oasis. Я заявил, каждый из серверных баз данных модулей в качестве отдельной библиотеки, которые могут быть включены для компиляции с флагом:

Library mysql-backend 
    Path   : . 
    Build  $: flag(mysql) 
    Install  : false 
    BuildTools : ocamlbuild 
    BuildDepends : main, mysql 
    Modules  : Mysql_backend 

Однако, я не могу понять, способ сказать Oasis, чтобы связать дополнительные модули в исполняемый файл. Я попытался выяснить способ сделать это, изменив файл myocamlbuild.ml, но не смог. Могу ли я достичь этого с помощью описанной функции rulehere?

Если то, что я описываю, не может быть достигнуто с помощью ocamlbuild, есть ли какой-нибудь инструмент ither, который мог бы выполнить эту работу и избежать проблем с OCamlMake?

ответ

1

Ну, я думаю, что ответы это: https://github.com/links-lang/links/pull/77 :)

+0

Я не уверен, как это решает проблему. Вопрос заключался в том, как реализовать необязательные зависимости, раздел объекта не решает этого, вам все равно нужно явно указывать зависимость в главной программе. В основном, вопрос заключался в том, как реализовать полиморфизм на уровне компиляции, когда вы можете заменить библиотеки одним и тем же интерфейсом, но разными реализациями. – ivg

+0

ah, ok Я вижу, вы также внедрили условную ссылку в плагине myocamlbuild. Немного жестко, но должно работать. В идеале мы должны внести свой вклад в оазис. Поскольку ваш PR - это PoC, он может работать :) – ivg

0

К сожалению, это за пределами возможностей оазиса. Это ограничение не имеет ничего общего с ocamlbuild, это просто потому, что автор oasis пытался сохранить его простым и не предоставлял необязательные зависимости в качестве функции.

Как всегда, дополнительный уровень косвенности может решить вашу проблему. Что вам нужно, это сценарий конфигурации (configure), который будет генерировать файл _oasis для вас, в зависимости от параметров, предоставляемых пользователем.

Например, в our project мы имеем аналогичную настройку, то есть несколько разных бэкэнд, которые могут быть выбраны пользователем на этапе конфигурации, с --{enable,disable}-<feature>. Мы достигли этого, написав собственный скрипт ./configure, который генерирует файл _oasis, в зависимости от конфигурации. Скрипт конфигурации просто объединяет полученные _oasis файлы с фрагментов, описанных в папке oasis.

Альтернативным решением было бы использовать m4 или только cpp и иметь файл _oasis.in, который предварительно обрабатывается.

+0

Если ограничение не имеет ничего общего с 'ocamlbuild', могу ли я как-то использовать' myocamlbuild.ml', чтобы получить то, что я хочу? –

+0

Думаю, вы смешиваете эти два инструмента. 'myocamlbuild.ml' - это плагин для ocamlbuild. 'ocamlbuild' - это компилятор, который знает, как строить вещи, из данных рецептов. В плагине вы можете научить 'ocamlbuild' как создавать новые вещи (например, латекс, C++, препроцессинг). 'ocamlbuild' не используется для описания вашего проекта. Вы можете описать свой проект вручную, либо в Makefile, либо с помощью 'mlpack'. – ivg

+0

ivg: предварительная обработка файла оазиса, вероятно, является наихудшим способом сделать что-то: это заставляет вашу систему сборки зависеть от оазиса, чего она не должна, и это чрезвычайно тяжело. См. Мой ответ для лучшего решения. – Drup

1

Я видел этот вопрос и начал работать над ней, прежде чем я заметил ответ Друп в выше. Ниже приведено автономное решение ocamlbuild, которое по сути совпадает с Drup.

open Ocamlbuild_plugin 

let enable_plugin() = 
    let plugins = try string_list_of_file "plugin.config" with _ -> [] in 
    dep ["ocaml"; "link_with_plugin"; "byte"] 
    (List.map (fun p -> p^".cmo") plugins); 
    dep ["ocaml"; "link_with_plugin"; "native"] 
    (List.map (fun p -> p^".cmx") plugins); 
() 

let() = dispatch begin 
    function 
    | Before_rules -> enable_plugin() 
    | _ ->() 
end 

Использование тега link_with_plugin на целевом ocamlbuild будет делать это зависит от любого модуля, путь (без расширения), перечислены в файле plugin.config. Например, если у вас есть плагины pluga.ml, plugb.ml и файл main.ml, тогда запись pluga plugb в plugin.config и имеющая <main.{cmo,cmx}>: link_with_plugin свяжет оба модуля плагина в основном исполняемом файле.

Смежные вопросы