FreeSource: AltLinux/Policy/OCaml

Эта страница была перенесена на altlinux.org. Текст на freesource.info заморожен.

(По мотивам письма bga@ в devel@)

Складывается ощущение, что после Виталия Луговского у нас не было серьёзных

знатоков OCaml =). Давайте соберём хотя бы отрывочные знания и, возможно,

сформируем некое policy.

TODO: дополнить использованием макросов из rpm-build-ocaml

Ликбез

Objective Caml (http://caml.inria.fr/ocaml/index.en.html) — функциональный

язык с элементами императивного стиля. Компиляторы OCaml могут создавать

байт-код и нативный код, и сами, в свою очередь, имеются в вариантах байт-

кода и нативные. Например:

ocamlc – байт-кодный компилятор в байт-код

ocamlc.opt – нативный компилятор в байт-код

ocamlopt – байт-кодный компилятор в нативный код

ocamlopt.opt – нативный компилятор в нативный код

(Примечание: в наших пакетах ocamlc и ocamlopt обычно являются

символическими ссылками на ocamlc.opt и ocamlopt.opt соответственно.)

Байт-код существует для большей переносимости, т.е. предполагается,

что байт-код одинаково выполняется на любой архитектуре, где существует

интерпретатор байт-кода – ocamlrun (он бывает только нативный).

С другой стороны, от нативного кода ожидается бОльшая производительность.

Байт-код можно отличить по заголовку "#!/usr/bin/ocamlrun" в первой

строке, за которой следуют двоичные данные. Существует вариант линковки,

когда интерпретатор байт-кода (ocamlrun) внедряется в конечную программу

и его самостоятельная копия для запуска уже не требуется. Такая программа

выглядит как обычный исполняемый файл, но командой strip можно отсечь

от него байт-код, после чего останется уже знакомый нам ocamlrun =).

Во втором случае кросс-платформенность программы неочевидна:

с одной стороны, она не выполнится на посторонней архитектуре,

с другой – можно выполнить содержащийся в ней байт-код с помощью

нативной версии ocamlrun: «ocamlrun ./progname --args».

Существуют следующие типы (расширения) файлов:

.ml – исходные тексты

.mli – описания интерфейсов

.cmi – скомпилированные описания интерфейсов

.cmo – скомпилированные в байт-код исходные тексты

.cma – собранный в библиотеку байт-код

.cmx – скомпилированные нативно исходные тексты

.cmxa – собранный в библиотеку нативный код

.o – скомпилированный нативный код (ELF)

.a – статическая библиотека из этих ELF-ов

Исполняемый байт-код получается сборкой всех .cma и .cmo, нативный -

сборкой всех .cmxa и .cmx. При этом для каждого .cmxa должен иметься

одноимённый .a, а для .cmx – .o (они так и генерируются компилятором

попарно.)

Проблема 1

Раз существует архитектуро-независимый байт-код, неплохо бы его помещать

в noarch-пакеты. Однако, из одного spec-файла rpm собирает пакеты только

какой-нибудь одной архитектуры, так что, выделив байт-код в отдельный

пакет, мы всё равно назовём его i586 или x86_64. Раз так, стоит ли вообще

его выделять? Не лучше ли собирать всё нативно?

Сейчас в наших пакетах одни только нативные версии ocamlc и ocamlopt, но

есть и байт-кодные, и нативные ocamldoc, camlp4r и т.д. Непоследовательно.

Бинарная несовместимость

После выпуска 3.08.3 в рассылке Debian возникли вопросы, а существует ли

бинарная совместимость между разными версиями OCaml?

http://lists.debian.org/debian-ocaml-maint/2005/01/msg00042.html

Оказалось, что даже между 3.08.2 и 3.08.3 её может не быть. Причины

тому (по мнению Jacques Garrigue) изложены в этой ветке:

http://lists.debian.org/debian-ocaml-maint/2005/01/msg00050.html

А вот здесь признание Xavier Leroy (одного из разработчиков OCaml) в том,

что бинарная совместимость никогда не входила в их планы =) :

http://lists.debian.org/debian-ocaml-maint/2005/01/msg00056.html

Из всей дискуссии я делаю вывод, что методы экспериментально установить

совместимость/несовместимость существуют, но затраты на эти эксперименты

слишком велики. Проще заранее предположить несовместимость и паковать

программы с привязкой к одной конкретной версии.

Примечание: Казалось бы, эта несовместимость противоречит кросс-

платформенности байт-кода, да и вообще его сути. Но можно предположить,

что в рамках одной версии компилятора и интерпретатора байт-код кросс-

платформен, а в разных – нет. Впрочем, camlp4, собранный как байт-код

на x86_64 компилятором 3.09.3 отлично запустился на i586 c интерпретатором

3.08.0 =). Вопрос в том, будем ли мы надеяться на удачу и ждать, не наступит

ли кто на грабли? Мне кажется, пока нет чёткого заключения «наш байт-код

не зависит от версии интерпретатора», лучше жёстко закрепить версию. Если

такое заключение всё же было, а я пропустил, пожалуйста, укажите.

Проблема 2

В свежих spec-файлах стала появляться зависимость

Requires: %{get_dep ocaml}

что, вообще говоря, неверно, т.к. порождает

Requires: ocaml >= 3.09.1

или вроде того. См. выше про несовместимость. Лучше было указывать

Requires: ocaml = %{get_SVR ocaml}

что порождает

Requires: ocaml = 3.09.1-alt1

Кроме того, нужно разобраться, для чего нужны зависимости, и на что

влияет версия. Например, упомянутый мной camlp4 3.09.3 не стал работать

с синтаксическими расширениями pa_*.cmo от 3.08.0 по причине

“interface mismatch on Grammar”.

Все .cmi, .cmo, .cma, .cmxa должны линковаться тем же компилятором, что

и сами были порождены. Таким образом, на бинарные библиотеки накладывается

зависимость Requires: ocaml = <версия>, где <версия> определяется в момент

сборки. Третий, зависимый по "Build Requires: libname" пакет при сборке

вытянет именно эту <версию>.

Байт-кодные программы должны зависеть по

Requires: ocaml-runtime = <версия>

а нативные ни от чего не зависят =).

При сборке ранее указывалось "Build Requires: ocaml = <версия>". Я считаю,

что достаточно "Build Requires: ocaml", а <версия> определится с помощью

%{get_SVR ocaml}. Это позволит при выходе нового OCaml пересобирать

зависимые пакеты роботу.

Итого, от мэйнтейнера требуется собрать по spec-файлу бинарные пакеты

и внимательно их рассмотреть: есть исполняемый байткод внутри – проставить

зависимость на ocaml-runtime = <версия>, есть .cmo/.cmi/.cmx/.cma/.cmxa -

проставить зависимость на ocaml = <версия>. В пакеты libname-runtime стоит

класть только библиотеки, необходимые для запуска использующего их байт-

кода. Обычно это %_libdir/ocaml/stublibs/dll*.so. Все прочие, «не необ-

ходимые» файлы пусть остаются в libname.