← На главную

Как правильно собираются проекты на Haskell

Что-то в последнее время мне подозрительно часто стали задавать этот вопрос. Как по мне, тут все предельно просто, и на пост тема едва ли тянет. Но раз люди интересуются, видимо, у них возникают какие-то сложности с самостоятельным поиском ответа, так что, наверное, кому-нибудь этот пост пригодится.

Примем за рабочую теорию, что установку Haskell Platform вы осилили. И, конечно же, вы уже знаете, что пакеты в мире Haskell принято хранить и искать на Hackage, а устанавливать при помощи программы cabal:

cabal update cabal install имя-пакета

Когда вы работаете над собственным проектом, все примерно то же самое. Вы также создаете пакет, содержащий модули и исполняемые файлы, и собираете его с помощью cabal. Возможно, вам не захочется заливать свой код на Hackage, но это и не требуется. Давайте рассмотрим сборку моего пакета с примерами использования OpenGL в Haskell.

Склонируем git-репозиторий и перейдем в каталог с пакетом:

git clone git@bitbucket.org:afiskon/hs-opengl-examples.git cd hs-opengl-examples

Вот как выглядит содержимое пакета:

. +-- data |   +-- box.jpg |   +-- bricks.png +-- LICENSE +-- opengl-examples.cabal +-- Setup.hs +-- src +-- BlackWindow.hs +-- JumpingTriangle.hs +-- MovingTriangle.hs +-- RedTriangle.hs +-- RedWindow.hs +-- RotatingPyramid.hs +-- TexturedBox.hs +-- TexturedWalls.hs +-- Utils +-- Drawing.hs

Здесь мы видим следующее. LICENSE – это файл с текстом лицензии, его, в принципе, можно оставлять пустым. В каталоге src содержатся все исходники. Файл Setup.hs содержит следующий код:

import Distribution.Simple main = defaultMain

Он генерируется автоматически при создании скелета пакета, о чем чуть ниже.

Наконец, самый главный файл, opengl-examples.cabal. Здесь задается описание пакета, перечисляются его зависимости и так далее. Можно провести аналогию с rebar.config из мира Erlang.

Посмотрим на содержимое cabal-файла:

name: opengl-examples version: 0.2.0 stability: Stable category: Graphics synopsis: OpenGL Examples description: OpenGL Examples license: BSD3 license-file: LICENSE author: Alexander Alexeev homepage: http://eax.me/haskell-opengl/ maintainer: mail@eax.me copyright: 2013 build-type: Simple cabal-version: >=1.8 data-dir: data data-files: *.jpg, *.png executable black-window ghc-options: -O2 -Wall -fno-warn-missing-signatures hs-source-dirs: src main-is: BlackWindow.hs build-depends: base >= 4.5, OpenGL >= 2.8, GLUT >= 2.4

На мой взгляд, формат более чем самодокументируемый и в дополнительных пояснениях не нуждается. Отмечу только, что я опустил описание всех исполняемых файлов, кроме первого, с именем black-window. Остальные исполняемые файлы описываются аналогичным образом.

Чтобы установить такой пакет, нужно просто перейти в его каталог и сказать:

cabal install

Cabal сам установит все зависимости и соберет пакет. Компиляция займет какое-то время. Кроме того, поскольку в пакете используется OpenGL, cabal может попросить вас установить некоторые зависимости с помощью системного менеджера пакетов. Когда сборка завершится, собранные программы можно будет запустить таким образом:

~/.cabal/bin/rotating-pyramid

При использовании описанного выше подхода все пакеты и их зависимости ставятся в ~/.cabal, в одну кучу. С одной стороны, это хорошо, потому что, если несколько пакетов зависят от одного и того же пакета, его придется собрать только один раз. Однако при этом могут возникать конфликтные ситуации, когда несколько пакетов имеют в зависимостях один и тот же пакет, но разных версий. Для борьбы с этой проблемой в cabal 1.18 была добавлена поддержка так называемых песочниц.

Узнайте версию вашего cabal, сказав:

cabal --version

Если версия оказалась меньше, чем 1.18, скажите:

cabal update cabal install cabal-install

… а также убедитесь, что каталог $HOME/.cabal/bin/ прописан в переменной окружения $PATH.

Теперь попробуем собрать пакет в песочнице:

cabal sandbox init cabal install ./.cabal-sandbox/bin/rotating-pyramid

Для открытия REPL скажите:

cabal repl jumping-triangle

… где jumping-triangle – это имя исполняемого файла. Если вы работаете над библиотекой, этот параметр можно опустить.

До выхода cabal 1.18 вместо песочниц было принято пользоваться программу cabal-dev. Если вам по каким-то причинам хочется использовать именно ее, скажите:

cabal install cabal-dev

Пользоваться cabal-dev очень просто:

cabal-dev install ./cabal-dev/bin/rotating-pyramid cabal-dev ghci

В первом приближении дела обстоят как-то так. Более подробную информацию вы найдете, например, в Cabal User Guide.

Для закрепления материала советую вам попробовать создать простенький пакет, содержащий программу, выводящую в консоль «Привет, мир!», а также собрать ее описанными выше способами. Для создания скелета пакета используйте команду cabal init. Думаю, все это займет у вас от силы минут десять. Затем добавьте в проект какие-нибудь зависимости. Например, попробуйте написать программу, запрашивающую у пользователя строку, а затем выводящую эту строку в base64.

Любые вопросы и дополнения, как всегда, горячо приветствуются.

Дополнение: Также вас могут заинтересовать заметки Устанавливаем самую свежую версию компилятора Haskell и Сборка проектов на Haskell при помощи Stack.