dastapov: (Default)
[personal profile] dastapov
Сегодня я хочу прервать долгую тишину в эфире и написать объективное и непредвзятое сравнение отсталого и отстойного компилятора ocaml с современными и прогрессивными компиляторами для всех остальных языков.

Что же плохо в компиляторе ocaml (заодно пройдемся и по интерпретатору)?

Претензия номер раз: он не умеет компилировать проекты из нескольких файлов. Допустим, у нас есть foo.ml и bar.ml следующего содержания:

foo.ml
======
let foo = 42;;

bar.ml
======
let bar = Foo.foo + 1;;

let () =
    Printf.printf "bar = %d\n" bar;;


Попробуем поставить себя на место новичка в ocaml и скомпилировать их. Так как основной модуль у нас bar, компилируем его:
adept> ocamlopt bar.ml
File "bar.ml", line 1, characters 10-17:
Error: Unbound module Foo


Вопрос: что мешает компилятору немного проявить немного инициативы и найти у себя под носом модуль foo и скомпилировать его, раз уж его недостает? Вроде на дворе у нас 21-ый век ... Ну ладно, мы не гордые - укажем модуль вручную:
adept> ocamlopt bar.ml foo.ml
File "bar.ml", line 1, characters 10-17:
Error: Unbound module Foo


Увы и ах, компилятор надо кормить с ложечки, подавая файлы в правильном порядке - все зависимости должны быть указаны до модулей, которые их используют. Не компиляторово это дело - заниматься топологической сортировкой:
adept> ocamlopt foo.ml bar.ml 
adept> ./a.out
bar = 43


Ура! Заработало! Теперь разберемся с раздельной компиляцией.

Претензия номер два: раздельная компиляция сделана через зад.
Может, раз совместная компиляция модулей foo и bar - это такая проблема, стоит собирать их по отдельности, а потом линковать? А вот фиг - проще не будет!

adept> ocamlopt -c bar.ml
File "bar.ml", line 1, characters 10-17:
Error: Unbound module Foo


То есть, раздельную компиляцию нужно выполнять тоже с учетом топологической сортировки по зависимостям.

Кроме того, на пути заботливо разложены дополнительные грабли под названием cross-module inlining и присыпаны листиками. Давайте вручную опишем интерфейс модуля foo и скомпилируем все раздельно:
[2] adept> cat foo.mli
val foo : int;;
adept> ocamlopt -c foo.mli
adept> ocamlopt -c foo.ml
adept> ocamlopt -c bar.ml
adept> ocamlopt foo.cmx bar.cmx


Теперь вручную изменим реализацию "foo", не меняя интерфейс, напимер добавим туда неэкспортируемое определение "let boo = 666". Теперь скомпилируем модуль "foo" (только реализацию - ведь интерфейс-то мы не меняли) и перелинкуем программу:
adept> ocamlopt -c foo.ml
adept> ocamlopt foo.cmx bar.cmx
File "_none_", line 1, characters 0-1:
Error: Files bar.cmx and foo.cmx
       make inconsistent assumptions over implementation Foo


Казалось бы, что за нафиг? А все дело в том, что в процессе компиляции "bar.ml" компилятор увидел файл "foo.cmx" и подумал: "О! А почему бы не попробовать сделать cross-module inlining?". В результате в bar.cmx осталась ссылка на sha1(?) хеш foo.cmx. Именно это приводит к проблемам в линковке.

Однако, если перед вызовом "ocamlopt -c bar.ml" убрать foo.cmx куда-то в сторонку, а потом вернуть его обратно, все скомпилируется, cross-module inlining не выполнится и потом можно будет перекомпилировать foo.ml отдельно от всего остального и перелинковать программу без всяких проблем.

Что тут плохо:
1)Если сначала все собрать без inlining-а, а потом в какой-то момент перекомпилировать bar.ml, компилятор выполнит inlining

2)Нельзя получить хоть какую-то диагностику от компилятора о том, делается ли inlinining или нет

3)Нельзя запретить(!) inlining. Опция "inline=0", вопреки ожиданиям, не запрещает inlining, просто делает его очень "безинициативным"

Печальное следствие 1: если хочется для ускорения разработки наплевать на скорость скомпилированного кода и уменьшить количество пересобираемых модулей путем отключения inlining-а, надо очень сильно извращаться.

Печальное следствие 2: нет простого способа компилировать код на ocaml. Если писать для своей системы сборки правила вида "ocamlopt -o prog.exe foo.ml bar.ml baz.ml", то придется руками переставлять имена модулей туда-сюда при любом изменении графа зависимостей. А неявные правила (implicit rules) вида "%.cmx: %.ml" нельзя использовать без механизма обнаружения зависимоей (об этом - позже). Нельзя также наплевать на компиляцию вообще и сказать "да хрен с ним, проинтерпретируйте мой код" (об этом тоже подробнее будет позже).

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

Продолжение следует, у меня накипело :)

(no subject)

Date: 2011-11-10 09:08 am (UTC)
From: [identity profile] gds.livejournal.com
кто-то не прочитал документацию. Все проблемы решаются "ocamlbuild bar.native".
Инлайнинг отключать/запрещать не надо.

(no subject)

Date: 2011-11-10 09:14 am (UTC)
From: [identity profile] http://users.livejournal.com/_adept_/
1)ocamlbuild не идет "из коробки". Можно сказать, что это придирки. Но если есть хост, на котором ocamlopt есть, а ocamlbuild - нет, то все, попадалово.

2)Страшно мало мест, в который написано "сразу используйте ocamlbuild". В частности, оф. документация про него молчок. Вот это уже гораздо хуже

2)Как только ситуация становится чуть более сложной и ocamlbuild не может справится с ней с дефолтными правилами, он становится неудобен. См, например, http://brion.inria.fr/gallium/index.php/Ocamlbuild_example_with_C_stubs. То есть, если начать с ocamlbuild, то потом сложно масштабироваться.
Edited Date: 2011-11-10 09:15 am (UTC)

(no subject)

Date: 2011-11-10 09:15 am (UTC)
From: [identity profile] dimitrykakadu.livejournal.com
1я вещь решается ситемами сборки, 2я тоже.

Скажу, что в фадиезе не лучше. Там даже тулы а-ля ocamldep нет, надо файлы сортировать руками. И конпелирует он проект целиком. Поменял один файл --- перекомпилировать надо вместе с отсальными. долго-долго перкомпилировать.

(no subject)

Date: 2011-11-10 09:15 am (UTC)
From: [identity profile] http://users.livejournal.com/_adept_/
Про системы сборки будет отдельно :) Все, как одна - страшные, как смертный грех.

Про F# - спасибо, был не в курсе, теперь буду знать.
Edited Date: 2011-11-10 09:16 am (UTC)

(no subject)

Date: 2011-11-10 09:20 am (UTC)
From: [identity profile] gds.livejournal.com
1. Идёт "из коробки" как раз, просто не надо пользоваться древними версиями.

2. Мест -- мало, но чтение рассылки и минимальное разглядывание нормальных библиотек вполне даёт представление о нём. И да, он появился относительно недавно, поэтому ситуация вполне объяснима.

3. ocamlbuild можно докрутить в любую нужную сторону. Собственно, ссылка как раз демонстрирует это. И это -- в среднем чище, чем лепить свои мейкфайлы или использовать ocamlmakefile какой-нибудь. (проверял.)

(no subject)

Date: 2011-11-10 09:39 am (UTC)
From: [identity profile] http://users.livejournal.com/_adept_/
1. Таки уже да, посыпаю голову пеплом

2. Тут получается как в известном анекдоте про ложечки - они нашлись, а осадок неприятный уже остался.

(no subject)

Date: 2011-11-10 09:49 am (UTC)
From: [identity profile] zeux.livejournal.com
Ага, расстройство. В .NET мире вообще как-то потеряли навык раздельной компиляции. В F# к тому же потеряли навык быстрой компиляции (впрочем, я не использовал другие ML языки, может там тоже не фонтан).
Распилить проект на assembly помогает, наполовину - если собирать корневую то пересоберутся все, т.к. зависимость по датам изменения dll, а не по внешнему интерфейсу. Это впрочем лечится неделей возни с MSBuild вечерами.

(no subject)

Date: 2011-11-10 01:35 pm (UTC)
From: [identity profile] balmerdx.livejournal.com
"В .NET мире вообще как-то потеряли навык раздельной компиляции. " - это значит что бывают медленные .NET проекты, которые долго компилируются. Или чтото другое имеется ввиду?

(no subject)

Date: 2011-11-10 04:34 pm (UTC)
From: [identity profile] zeux.livejournal.com
Зависит от того, что такое долго, right?
Я хочу время инкрементальной компиляции, сопоставимое с внятным С++ проектом на внятном тулчейне - любое изменение реализации приводит к билду длительностью в пару секунд.
На работе в С++-ной кодобазе на PS3 вот так - при том что вся линковка статическая.
В .NET даже в C# этот лимит достигается на проекте с количеством кода в разы меньшем чем в рабочем, в F# еще хуже.

(no subject)

Date: 2011-11-10 06:08 pm (UTC)
From: [identity profile] ximaera.livejournal.com
Омг. Не припоминаю, чтобы мне приходилось читать рассылку GCC, GHC или Python. И erlang-dev я читал-то исключительно в академически-познавательных целях.

(no subject)

Date: 2011-11-10 07:03 pm (UTC)
From: [identity profile] gds.livejournal.com
то есть, информация о нужных утилитах и библиотеках приходит из всемирного эфира, или таки есть какие-нибудь другие источники, ищущиеся интернетами?

(no subject)

Date: 2011-11-10 07:32 pm (UTC)
From: [identity profile] ximaera.livejournal.com
Во-первых, о библиотеках мы сейчас не говорим (хотя удобно, когда батарейки в комплекте), во-вторых, как-то мало вы предлагаете вариантов. Есть ещё, скажем, такой: достаточная информация о нужных утилитах приходит из официальной документации.

(no subject)

Date: 2011-11-10 07:43 pm (UTC)
From: [identity profile] gds.livejournal.com
1. любая нормальная ОС умеет окамловские пакеты -- достаточно лишь использовать нормальные ОС. Для одной из ненормальных ОС (их всего одна) у меня есть своё решение, опенсорс, поддерживаемое, дополняемое.

2. варианты были самые очевидные, не полный список, конечно. Не нужно много ума, чтобы посмотреть, кто, как и чем собирает окамловские проекты. Это реально очень просто, очень тупо. Если бы у меня возник вопрос -- я бы посмотрел, как белые люди это делают. Есть даже специальные камлунити для того, чтобы это просто и быстро выяснить у живых людей, которые, может, ещё что хорошее посоветуют.

Утилита ocamlbuild -- не является нужной в смысле необходимости. Без неё можно, но она является удобной, и даже очень. Например, когда я смотрел на тот же эрланг, я как-то не встречал ничего про dyalizer -- а ведь тоже нужная утилита. Потом, конечно, подсказали про него, но, всё же, я же не возмущался с таким удивлением, как будто от меня скрыли тайну партии и всего такого.

(no subject)

Date: 2011-11-10 10:32 pm (UTC)
From: [identity profile] ximaera.livejournal.com
2. Почему их нужно собирать чем-то отдельным, а не {make,cmake,scons,you name it}? Зачастую в проекте код не на одном языке, а на 2-3. Что, под каждый язык свой сборщик прикручивать?

Ну а как живётся с make без ocamlbuild, мы недавно заслушали.

Что касается dialyzer, то вы невнимательно читали официальную документацию :-) См. http://www.erlang.org/doc/man/

(no subject)

Date: 2011-11-10 10:36 pm (UTC)
From: [identity profile] ximaera.livejournal.com
А, ну и да,

1. Так, значит, информацию об окамловских библиотеках тоже в Интернете искать не надо? Тем более неудобно то, что в официальной документации ничего не сказано про основное средство для сборки (хотя я сам её не читал, но верю окружающим на слово, что ничего таки не сказано).

(no subject)

Date: 2011-11-10 11:11 pm (UTC)
From: [identity profile] gds.livejournal.com
ocamlbuild -- хорошая система сборки для окамловских проектов. Остальное прикручивается легко, не сильно сложнее, чем к make. А вот scons и прочее -- ересь.

(no subject)

Date: 2011-11-10 11:16 pm (UTC)
From: [identity profile] ximaera.livejournal.com
Правильно ли я вас понимаю, что код на OCaml обладает свойствами, создающими принципиальные проблемы при сборке с помощью scons/GNU Make? Тто есть OCaml никогда и не предназначался для сборки make'ом, и так делать не надо?

(no subject)

Date: 2011-11-10 11:23 pm (UTC)
From: [identity profile] gds.livejournal.com
неправильно, конечно.

(no subject)

Date: 2011-11-10 11:25 pm (UTC)
From: [identity profile] ximaera.livejournal.com
> А вот scons и прочее -- ересь

> неправильно, конечно.

Тогда я вас не понимаю.

Profile

dastapov: (Default)
Dmitry Astapov

May 2022

M T W T F S S
       1
2345678
9101112131415
161718 19202122
23242526272829
3031     

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags