Часть 3.5, внеочередная: багофича и опенсорс

В прошлой части я наткнулся на довольно странный глюк: расхваленный мной фреймворк отказался автоматически ставить библиотеки. Как и обещал, я написал репорт в трекер миража на гитхабе, и со мной вышел на связь очень любезный и умный д-р Hannes Mehnert из Кембриджского университета. После нескольких часов анализа корень проблемы был найден и устранён [спойлер: моя криворукость], а доктор закоммитил в мираж решение ещё одной системной проблемы, которую мы обнаружили в процессе мозгоштурма. Так мне довелось причаститься докторской благодати и послужить мировому добру… или злу, если из миража кто-нибудь мозги для Альтрона сделает. А теперь я покажу, в чём была проблема, и как она вылечилась.

Итак, меня подвела любовь к DSL и красивым синтаксисам. В OCaml-е издавна практиковались всевозможные синтаксические расширения. Язык создавался отчасти как инструмент для анализа других языков, и поэтому с инструментами синтаксического, лексического и прочих анализов там всё в порядке. Другое дело, что при использовании классического инструмента — генератора DSL camlp4 — происходит препроцессинг (переписывание) исходника, и при попытке разобраться в последующих сообщениях об ошибках будут возникать проблемы: в репортах будут не те строки, не те слова и т.п. Со временем старый добрый camlp4 был заменён на более удобный ppx. Ppx-синтаксов развелось куча и для всего, а использовать их значительно проще, так как не надо вставлять в Makefile громоздкие промежуточные таргеты с перпроцессорами — достаточно в уже существующих таргетах добавить компилятору в качестве входного модуля нужный ppx-пакет.

Много новых слов, пора показывать на пальцах. Итак, есть пакет lwt — реализация «тонких тредов» для OCaml. В нём реализована монадная модель вызова тредов. Например, есть инфиксный комбинатор >>=. Он берёт результат функции «слева» и вызывает с ним функцию «справа», причём справа часто пишут анонимную функцию: done_something_with x >>= fun y -> do_something_else_with y. Часто обе две функции просто что-то делают и ничего от них возвращать не требуется. Точнее, FP-шники говорят «от них требуется возвращать ничего» — то есть unit, (). Тогда фраза записывается так: done_something () >>= fun () -> do_something_else (). Использование синтаксического расширения ppx_lwt позволяет написать фразу короче: done_something () >> do_something_else (). Эту конструкцию мы видели вот тут:

См. седьмую строчку, перед «хвостом» loop (n - 1).

Для того, чтобы воспользоваться «благом цивилизации», я поступил как привык поступать: включил нужный мне ppx-пакет (lwt.ppx) в конфигурацию зависимостей юникернела:

Генератор вспомогательного кода (собственно, программа mirage) приготовил из того, что увидел на пятой строчке, некоторый список пакетов, в т.ч. lwt.ppx — и скормил его инсталлятору пакетов opam — мол, давай ставь. Opam увидел, что имя одного из пакетов ему не нравится (lwt.ppx означает «пакет ppx внутри пакета lwt», a opam, как и его рубишный коллега gem, умеет работать только с пакетами, а не с пакетами-внутри-пакетов) — и молча прервал работу. Пайплайн решил, что зависимости установлены, — и сообщив, что всё в порядке, закончил таск make depend. А всё было не в порядке. Дальше было то, о чём писалось сколько-то там букофф — чесание лба, установка депенденсей руками и т.п.

Хорошо. Долго ли, коротко ли — проблема была понята, и пайплайн заработал. Зависимости стали ставиться автоматом, но мне пришлось отказаться от синтакс-пакета и красивого комбинатора >>. А это было неприятно: мне-то хочется тут хвастаться код-порном, а не длинными умными анонимными функциями. К счастью, доктор Ханнес объяснил, что можно прописывать зависимости в файл _tags в корне проекта (ах вот он для чего!). И вот что получилось в результате:

Раз. Удаляем каку из конфигуратора:

Два. Создаём в корне проекта файл _tags с таким содержимым:

Три. Запускаем пайплайн конфигурации/компиляции:

Voila!

Сейчас, конечно, вся конфигурация здорового человека уже закоммичена в репу примера, и о вчерашнем приключении можно только прочитать в блоге. В следующей серии вернёмся к линуксу, виртуалкам и запуску нашего юникернела на реальном (хотя и виртуализованном) «железе».

To be continued

--

--