Как правильно собираются проекты на Haskell
13 ноября 2013
Что-то в последнее время мне подозрительно часто стали задавать этот вопрос. Как по мне, тут все предельно просто, и на пост тема едва ли тянет. Но раз люди интересуются, видимо, у них возникают какие-то сложности с самостоятельным поиском ответа, так что, наверное, кому-нибудь этот пост пригодится.
Примем за рабочую теорию, что установку Haskell Platform вы осилили. И, конечно же, вы уже знаете, что пакеты в мире Haskell принято хранить и искать на Hackage, а устанавливать при помощи программы cabal:
cabal install имя-пакета
Когда вы работаете над собственным проектом, все примерно то же самое. Вы также создаете пакет, содержащий модули и исполняемые файлы, и собираете его с помощью cabal. Возможно, вам не захочется заливать свой код на Hackage, но это и не требуется. Давайте рассмотрим сборку моего пакета с примерами использования OpenGL в Haskell.
Склонируем 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 содержит следующий код:
main = defaultMain
Он генерируется автоматически при создании скелета пакета, о чем чуть ниже.
Наконец, самый главный файл, opengl-examples.cabal. Здесь задается описание пакета, перечисляются его зависимости и так далее. Можно провести аналогию с rebar.config из мира Erlang.
Посмотрим на содержимое cabal-файла:
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 сам установит все зависимости и соберет пакет. Компиляция займет какое-то время. Кроме того, поскольку в пакете используется OpenGL, cabal может попросить вас установить некоторые зависимости с помощью системного менеджера пакетов. Когда сборка завершится, собранные программы можно будет запустить таким образом:
При использовании описанного выше подхода все пакеты и их зависимости ставятся в ~/.cabal
, в одну кучу. С одной стороны, это хорошо, потому что, если несколько пакетов зависят от одного и того же пакета, его придется собрать только один раз. Однако при этом могут возникать конфликтные ситуации, когда несколько пакетов имеют в зависимостях один и тот же пакет, но разных версий. Для борьбы с этой проблемой в cabal 1.18 была добавлена поддержка так называемых песочниц.
Узнайте версию вашего cabal, сказав:
Если версия оказалась меньше, чем 1.18, скажите:
cabal install cabal-install
… а также убедитесь, что каталог $HOME/.cabal/bin/
прописан в переменной окружения $PATH.
Теперь попробуем собрать пакет в песочнице:
cabal install
./.cabal-sandbox/bin/rotating-pyramid
Для открытия REPL скажите:
… где jumping-triangle — это имя исполняемого файла. Если вы работаете над библиотекой, этот параметр можно опустить.
До выхода cabal 1.18 вместо песочниц было принято пользоваться программу cabal-dev. Если вам по каким-то причинам хочется использовать именно ее, скажите:
Пользоваться cabal-dev очень просто:
./cabal-dev/bin/rotating-pyramid
cabal-dev ghci
В первом приближении дела обстоят как-то так. Более подробную информацию вы найдете, например, в Cabal User Guide.
Для закрепления материала советую вам попробовать создать простенький пакет, содержащий программу, выводящую в консоль «Привет, мир!», а также собрать ее описанными выше способами. Для создания скелета пакета используйте команду cabal init
. Думаю, все это займет у вас от силы минут десять. Затем добавьте в проект какие-нибудь зависимости. Например, попробуйте написать программу, запрашивающую у пользователя строку, а затем выводящую эту строку в base64.
Любые вопросы и дополнения, как всегда, горячо приветствуются.
Дополнение: Также вас могут заинтересовать заметки Устанавливаем самую свежую версию компилятора Haskell и Сборка проектов на Haskell при помощи Stack.
Метки: Haskell, Функциональное программирование.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.