Пакет — это библиотека модулей Haskell, известных компилятору. GHC поставляется с несколькими пакетами: см. сопроводительную документацию по библиотекам. Дополнительные пакеты можно получить на сайте HackageDB.
Использовать пакет очень просто: если вы используете --make или GHCi, то большинство установленных пакетов будет автоматически доступно вашей программе без каких-либо дополнительных параметров. Исключения из этого правила описаны ниже в разделе Использование пакетов.
Создать собственные пакеты также довольно просто: мы предоставляем инфраструктуру Cabal, которая автоматизирует настройку, сборку, установку и распространение пакета. Вам нужно лишь написать простой файл конфигурации, поместить несколько файлов в нужные места — и пакет готов. Подробности см. в документации Cabal, а также в библиотеках Cabal (например, Distribution.Simple).
5.9.1. Использование пакетов
GHC знает только об установленных пакетах. Установленные пакеты хранятся в базах данных пакетов. Подробные сведения о базах данных пакетов и о том, как управлять тем, какие базы данных пакетов или конкретные наборы пакетов доступны GHC, см. в разделе Базы данных пакетов.
Чтобы посмотреть, какие пакеты доступны в данный момент, используйте команду ghc-pkg list:
$ ghc-pkg list
/usr/lib/ghc-6.12.1/package.conf.d:
Cabal-1.7.4
array-0.2.0.1
base-3.0.3.0
base-4.2.0.0
bin-package-db-0.0.0.0
binary-0.5.0.1
bytestring-0.9.1.4
containers-0.2.0.1
directory-1.0.0.2
(dph-base-0.4.0)
(dph-par-0.4.0)
(dph-prim-interface-0.4.0)
(dph-prim-par-0.4.0)
(dph-prim-seq-0.4.0)
(dph-seq-0.4.0)
extensible-exceptions-0.1.1.0
ffi-1.0
filepath-1.1.0.1
(ghc-6.12.1)
ghc-prim-0.1.0.0
haskeline-0.6.2
haskell98-1.0.1.0
hpc-0.5.0.2
integer-gmp-0.1.0.0
mtl-1.1.0.2
old-locale-1.0.0.1
old-time-1.0.0.1
pretty-1.0.1.0
process-1.0.1.1
random-1.0.0.1
rts-1.0.1
syb-0.1.0.0
template-haskell-2.4.0.0
terminfo-0.3.1
time-1.1.4
unix-2.3.1.0
utf8-string-0.3.4
Установленный пакет по умолчанию либо открыт, либо скрыт. Пакеты, скрытые по умолчанию, перечислены в скобках (например, (lang-1.0)) или, если ваш терминал поддерживает цвет, выделены синим цветом в выводе ghc-pkg list. Описанные ниже флаги командной строки позволяют открыть скрытый пакет или скрыть открытый. В коде Haskell можно импортировать только модули из открытых пакетов; если вы попытаетесь импортировать модуль из скрытого пакета, GHC выдаст сообщение об ошибке. Следует отметить, что скрытый пакет всё ещё может быть слинкован с вашей программой как зависимость открытого пакета — ограничивается только прямой импорт его модулей.
Если открыто несколько версий пакета, GHC отдаст предпочтение самой поздней. Кроме того, некоторые пакеты могут быть неисправны: например, они отсутствуют в базе данных пакетов или неисправна одна из их зависимостей; в этом случае такие пакеты исключаются из набора пакетов по умолчанию.
Примечание
Если вы используете Cabal, то статус пакета — открытый или скрытый — не имеет значения: доступные пакеты определяются зависимостями, перечисленными в спецификации .cabal. Статус пакетов — открытый или скрытый — важен только при непосредственном использовании ghc или ghci.
Подобно статусу скрытия пакета, существует статус доверия пакету. Пакет может быть доверенным или недоверенным (отвергнутым). По умолчанию пакеты считаются недоверенными. Это свойство пакета имеет значение только при компиляции кода с использованием функции GHC Safe Haskell (см. раздел Safe Haskell) с включённым флагом -fpackage-trust.
Чтобы посмотреть, какие модули предоставляет пакет, используйте команду ghc-pkg (см. раздел Управление пакетами (команда ghc-pkg)):
$ ghc-pkg field network exposed-modules
exposed-modules: Network.BSD,
Network.CGI,
Network.Socket,
Network.URI,
Network
Параметры командной строки GHC, управляющие пакетами:
-
-package ⟨pkg⟩ -
Этот параметр открывает установленный пакет ⟨pkg⟩. Пакет ⟨pkg⟩ можно указать полностью, вместе с номером версии (например,
network-1.0), либо опустить номер версии — в этом случае GHC автоматически откроет самую позднюю исправную версию из установленных версий пакета.По умолчанию (если не указан
-hide-all-packages) GHC открывает только одну версию пакета, а все остальные версии становятся скрытыми. Если параметр-packageуказан несколько раз для одного и того же пакета, последний параметр переопределяет предыдущие. С другой стороны, если используется-hide-all-packages, GHC позволяет открыть несколько версий пакета, указав параметр-packageнесколько раз с разными версиями одного пакета.Параметр
-packageподдерживает сокращение списка модулей и их переименование, описанные в разделе Сокращение списка и переименование модулей.Параметр
-package ⟨pkg⟩также приводит к тому, что пакет ⟨pkg⟩ линкуется с полученным исполняемым файлом или разделяемым объектом. Статическая или динамическая линковка библиотеки пакета определяется парой флагов-static/-dynamic.В режиме
--makeи режиме--interactive(см. раздел Режимы работы) компилятор обычно определяет, какие пакеты требуются текущим модулям Haskell, и линкует только их. Однако в пакетном режиме информация о зависимостях недоступна, поэтому при линковке необходимо явно указывать параметры-package. Ещё один случай, когда может понадобиться использовать-packageдля принудительной линковки пакета, — пакет не содержит модулей Haskell (например, в нём может быть только библиотека C). В этом случае GHC не сможет обнаружить зависимость от него, поэтому его необходимо указать явно.Например, чтобы слинковать программу, состоящую из объектных файлов
Foo.oиMain.o, в которой используется пакетnetwork, необходимо передать GHC флаг-packageследующим образом:$ ghc -o myprog Foo.o Main.o -package network
Этот же флаг необходим, даже если мы скомпилировали модули из исходного кода, поскольку GHC всё ещё считает, что работает в пакетном режиме:
$ ghc -o myprog Foo.hs Main.hs -package network
-
-package-id ⟨unit-id⟩ -
Открывает пакет, как и
-package ⟨pkg⟩, но пакет указывается по его идентификатору unit (то есть по значениюidв его записи в базе данных установленных пакетов, ранее также называвшемуся идентификатором установленного пакета), а не по имени. Это более надёжный способ указания пакетов, позволяющий выбирать пакеты, которые в противном случае были бы затенены. Cabal передаёт GHC флаги-package-id. Параметр-package-idподдерживает сокращение списка модулей и их переименование, описанные в разделе Сокращение списка и переименование модулей.
-
-hide-all-packages -
Игнорирует флаг открытости установленных пакетов и скрывает их все по умолчанию. Если вы используете этот флаг, все необходимые вам пакеты (включая
base) нужно явно открыть с помощью параметров-package ⟨pkg⟩.Это хороший способ защитить программу от различий в глобально открытых пакетах, а явное указание зависимостей пакета — это полезная практика. Cabal всегда передаёт GHC флаг
-hide-all-packagesименно по этой причине.
-
-hide-package ⟨pkg⟩ -
Этот параметр действует противоположно параметру
-package ⟨pkg⟩: он скрывает указанный пакет, то есть ни один его модуль нельзя будет импортировать с помощью директив Haskellimport.Обратите внимание, что пакет всё ещё может быть слинкован с итоговой программой, если он является прямой или косвенной зависимостью другого открытого пакета.
-
-ignore-package ⟨pkg⟩ -
Заставляет компилятор вести себя так, как если бы пакет ⟨pkg⟩ и все зависящие от него пакеты вообще не были установлены.
Указание
-ignore-package ⟨pkg⟩равносильно указанию флагов-hide-package ⟨pkg⟩для пакета ⟨pkg⟩ и всех зависящих от него пакетов. Иногда заранее неизвестно, какие установленные пакеты зависят от ⟨pkg⟩; в таких случаях может быть полезен флаг-ignore-package ⟨pkg⟩.
-
-no-auto-link-packages -
По умолчанию GHC автоматически линкует пакеты
base,ghc-internalиrts. Этот флаг отключает такое поведение.Идентификатор unit автоматически линкуемого пакета
baseможно задать с помощью флага-base-unit-id ⟨unit-id⟩.
-
-base-unit-id ⟨unit-id⟩ -
По умолчанию компилятор линкуется с пакетами
base,ghc-internalиrts; этот флаг задаёт, с каким пакетомbaseбудет выполнена линковка.Передавать этот флаг нужно только в том случае, если вы точно знаете, что делаете. Дистрибутивы могут задать идентификатор unit по умолчанию для base во время установки, указав переменную среды
BASE_UNIT_ID.
-
-this-unit-id ⟨unit-id⟩ -
Сообщает GHC, что компилируемый модуль является частью идентификатора unit ⟨unit-id⟩; внутри системы эти ключи используются для определения равенства типов и символов компоновщика. Начиная с GHC 8.0 идентификаторы unit могут состоять только из буквенно-цифровых символов, дефисов, подчёркиваний и точек. В будущих выпусках GHC оставляет за собой право придавать другим символам специальное значение.
- -trust ⟨pkg⟩
-
Этот параметр открывает установленный пакет ⟨pkg⟩ и помечает его как доверенный для GHC. Эта команда работает почти так же, как команда
-package ⟨pkg⟩, но дополнительно помечает выбранные пакеты как доверенные для GHC независимо от содержимого базы данных пакетов (см. раздел Safe Haskell).
- -distrust ⟨pkg⟩
-
Этот параметр открывает установленный пакет ⟨pkg⟩ и помечает его как недоверенный для GHC. Эта команда работает почти так же, как команда
-package ⟨pkg⟩, но дополнительно помечает выбранные пакеты как недоверенные для GHC независимо от содержимого базы данных пакетов (см. раздел Safe Haskell).
- -distrust-all-packages
-
Игнорирует флаг доверия установленных пакетов и по умолчанию считает их недоверенными. Если вы используете этот флаг и Safe Haskell, то все пакеты, которым вы доверяете (включая
base), необходимо явно пометить как доверенные с помощью параметров-trust ⟨pkg⟩. Этот параметр не меняет статус пакета — открытый он или скрытый, поэтому он не равнозначен применению параметра-distrust ⟨pkg⟩ко всем пакетам в системе (см. раздел Safe Haskell).
5.9.2. Пакет main
Каждая полноценная программа на Haskell должна определять main в модуле Main пакета main. Если не указать флаг -this-unit-id ⟨unit-id⟩, код будет скомпилирован для пакета main. В противном случае во время линковки возникнет довольно невразумительная ошибка следующего вида:
/usr/bin/ld: Undefined symbols: _ZCMain_main_closure
5.9.3. Последствия использования пакетов для языка Haskell
При использовании пакетов в программе могут оказаться два модуля с одинаковыми именами: возможно, вы использовали пакет P, содержащий скрытый модуль M, а в вашей программе также есть модуль M. Или, возможно, зависимости используемых вами пакетов содержат некоторые совпадающие модули. Возможно, программа даже содержит несколько версий одного пакета из-за зависимостей других пакетов.
Сами по себе ни один из этих сценариев не приводит к ошибке [1], но они могут иметь интересные последствия. Например, если у вас есть тип M.T из версии 1 пакета P, то он не является тем же типом, что и M.T из версии 2 пакета P, и GHC выдаст ошибку, если вы попытаетесь использовать один тип там, где ожидается другой.
Формально говоря, в Haskell 98 сущность (функция, тип или класс) в программе однозначно определяется парой: именем модуля, в котором она определена, и её именем. В GHC сущность однозначно определяется тройкой: пакет, модуль и имя.
5.9.4. Сокращение списка и переименование модулей
При подключении пакетов из нескольких источников может возникнуть ситуация, когда несколько пакетов предоставляют модули с одинаковыми именами. Раньше различать эти модули можно было только с помощью импортов с указанием пакета. Однако начиная с GHC 7.10 флаги -package ⟨pkg⟩ (и их варианты) были расширены: теперь пользователь может явно указать, какие модули пакета будут доступны, по аналогии со списками импорта, которые можно указывать при импорте модулей.
Вместо того чтобы указывать в параметре пакета -package только имя пакета P, можно указать имя пакета и заключённый в скобки список имён модулей, разделённых запятыми. Например, -package "base (Data.List, Data.Bool)" делает видимыми из пакета base только модули Data.List и Data.Bool. Поддерживается также переименование модулей, если вам нужно одновременно обращаться к обоим модулям; для этого используется запись OldModName as NewModName, например -package "base (Data.Bool as Bool). Можно также написать -package "base with (Data.Bool as Bool), чтобы включить все исходные связи (то есть переименование только добавляет новые имена). Важно указывать кавычки, чтобы оболочка передала имя пакета и список сокращения/переименования как один аргумент GHC.
Импорт пакета с сокращением списка/переименованием не скрывает другие версии пакета: например, если containers-0.9 уже открыт, -package "containers-0.8 (Data.List as ListV8)" лишь добавит дополнительную связь в окружение. Аналогично, -package "base (Data.Bool as Bool)" -package "base (Data.List as List)" равнозначно -package "base (Data.Bool as Bool, Data.List as List)". Буквальные имена должны соответствовать модулям, определённым в исходном пакете, поэтому, например, -package "base (Data.Bool as Bool, Bool as Baz)" недопустимо, если в исходном пакете не был определён модуль Bool. При скрытии пакета также удаляются все его переименования.
Переименование можно использовать для предоставления альтернативного Prelude, например -hide-all-packages -package "basic-prelude (BasicPrelude as Prelude)", вместо расширения Переназначаемый синтаксис и неявный импорт Prelude.
5.9.5. Базы данных пакетов
База данных пакетов хранит сведения об установленных пакетах. Это каталог, обычно называемый package.conf.d, содержащий файл для каждого пакета и двоичный кэш данных пакетов в файле package.cache. Обычно вам не нужно просматривать или изменять содержимое базы данных пакетов напрямую; управлять базами данных пакетов можно с помощью инструмента ghc-pkg (см. раздел Управление пакетами (команда ghc-pkg)).
GHC использует, в частности, две базы данных пакетов:
- Глобальная база данных пакетов, поставляемая вместе с установкой GHC, например
/usr/lib/ghc-6.12.1/package.conf.d. - Пользовательская база данных пакетов, личная для каждого пользователя. В Unix-системах это будет
$XDG_DATA_HOME/ghc/arch-os-version/package.conf.d, а в Windows — что-то вродеC:\Documents And Settings\user\ghc\package.conf.d. Инструментghc-pkgзнает, где должен находиться этот файл, и создаст его, если он отсутствует (см. раздел Управление пакетами (команда ghc-pkg)).
Стек баз данных пакетов: Базы данных пакетов организованы в виде стека. При запуске GHC добавляет в стек глобальную и пользовательскую базы данных пакетов именно в таком порядке, если не задана переменная GHC_PACKAGE_PATH. Если задана переменная GHC_PACKAGE_PATH, она определяет начальный стек баз данных. Несколько описанных ниже параметров командной строки могут дополнительно изменять этот начальный стек. Эффективный стек баз данных пакетов GHC можно посмотреть, запустив GHC с флагом -v.
Из этой структуры стека следует, что порядок флагов -package-db ⟨file⟩ или значений GHC_PACKAGE_PATH имеет значение. Каждый подстек должен быть корректно сформирован (пакеты в базах данных, расположенных выше в стеке, могут ссылаться на пакеты ниже, но не наоборот).
Затенение пакетов: При использовании нескольких баз данных пакетов иногда, хотя и редко, один и тот же идентификатор установленного пакета может присутствовать более чем в одной базе данных. В этом случае пакеты, расположенные ближе к вершине стека, переопределяют ( затеняют) пакеты ниже. Если конфликтующие пакеты оказываются эквивалентными (при сравнении ABI-хеша), один из них заменяет все ссылки на другой; в противном случае переопределённый пакет и все зависящие от него пакеты удаляются.
Выбор версии пакета: При выборе пакета GHC ищет пакеты во всех доступных базах данных. Если доступны несколько версий одного пакета, будет выбрана самая поздняя исправная версия.
Разрешение конфликтов версий: Если доступно несколько экземпляров выбранной GHC версии пакета, GHC выберет один из них без определённого порядка.
Управлять стеком баз данных пакетов GHC можно с помощью следующих параметров:
-
-package-db ⟨file⟩ -
Добавляет базу данных пакетов ⟨file⟩ на вершину текущего стека.
-
-no-global-package-db -
Удаляет глобальную базу данных пакетов из стека.
-
-no-user-package-db -
Запрещает загрузку локальной пользовательской базы данных пакетов в начальный стек.
-
-clear-package-db -
Сбрасывает текущий стек баз данных пакетов. Этот параметр удаляет из стека все ранее указанные базы данных пакетов (включая базы данных, заданные переменной среды
GHC_PACKAGE_PATH).
-
-global-package-db -
Добавляет глобальную базу данных пакетов на вершину текущего стека. Этот параметр можно использовать после
-no-global-package-db, чтобы указать место в стеке, куда следует загрузить глобальную базу данных пакетов.
-
-user-package-db -
Добавляет пользовательскую базу данных пакетов на вершину текущего стека. Этот параметр можно использовать после
-no-user-package-db, чтобы указать место в стеке, куда следует загрузить пользовательскую базу данных пакетов.
5.9.5.1. Переменная среды GHC_PACKAGE_PATH
-
GHC_PACKAGE_PATH -
Переменной среды
GHC_PACKAGE_PATHможно присвоить список файлов с базами данных пакетов, разделённых символом:(в Windows — символом;). Этот список баз данных пакетов, используемый GHC и ghc-pkg, задаёт стек баз данных пакетов сверху вниз. Такой порядок выбран для соответствия поведению переменной средыPATH, в которой более ранние элементы пути имеют приоритет над последующими. Подробные сведения об использовании стека баз данных пакетов см. в разделе Базы данных пакетов.Обычно
GHC_PACKAGE_PATHзаменяет стек пакетов по умолчанию. Например, все приведённые ниже команды эквивалентны и создают стек, в котором db1 находится на вершине, а за ним следует db2 (в Windows используйте;вместо:):$ ghc -clear-package-db -package-db db2.conf -package-db db1.conf $ env GHC_PACKAGE_PATH=db1.conf:db2.conf ghc $ env GHC_PACKAGE_PATH=db2.conf ghc -package-db db1.conf
Однако если
GHC_PACKAGE_PATHзаканчивается разделителем, базы данных по умолчанию (то есть пользовательская и глобальная базы данных пакетов в таком порядке) добавляются в конец пути. Например, чтобы дополнить обычный набор пакетов собственной базой данных, можно выполнить (в Unix):$ export GHC_PACKAGE_PATH=$XDG_DATA_HOME/.my-ghc-packages.conf:
Чтобы проверить, правильно ли задано значение
GHC_PACKAGE_PATH, выполнитеghc-pkg list— команда выведет все используемые базы данных в обратном порядке их поиска.
5.9.5.2. Окружения пакетов
Файл окружения пакетов указывает ghc, какие именно пакеты должны быть видимы. С его помощью можно создавать окружения для ghc или ghci, действующие в рамках сеанса оболочки или в определённом месте файловой системы. Предполагается, что ими управляют инструменты сборки и управления пакетами, чтобы ghc и ghci автоматически использовали созданное инструментом окружение.
В случае ghci файл окружения считывается один раз при инициализации. Если файл изменится, необходимо перезапустить GHCi, чтобы изменения вступили в силу.
Файл содержит идентификаторы пакетов и, при необходимости, базы данных пакетов — по одной директиве в каждой строке:
clear-package-db global-package-db user-package-db package-db db.d/ package-id id_1 package-id id_2 ... package-id id_n
Если найден такой файл окружения пакетов, его действие эквивалентно передаче следующих аргументов командной строки ghc:
-hide-all-packages -clear-package-db -global-package-db -user-package-db -package-db db.d/ -package-id id_1 -package-id id_2 ... -package-id id_n
Обратите внимание на неявный параметр -hide-all-packages и на то, что используется -package-id ⟨unit-id⟩, а не -package ⟨pkg⟩. Это связано с тем, что окружение точно задаёт, какие пакеты должны быть видимы.
Обратите внимание: если для директивы package-db указан относительный путь, он должен быть задан относительно расположения файла окружения пакетов.
-
-package-env ⟨file⟩|⟨name⟩ -
Использовать окружение пакетов из файла ⟨file⟩ или из
$XDG_DATA_HOME/ghc/arch-os-version/environments/⟨name⟩. Если задано значение-, окружение пакетов не считывается.
-
GHC_ENVIRONMENT -
Задаёт путь к файлу окружения пакетов, который должен использовать GHC. Если задан флаг
-package-env ⟨file⟩|⟨name⟩, он имеет приоритет.
В указанном порядке ghc ищет файл окружения пакетов в следующих местах:
- Файл ⟨file⟩, если передан параметр
-package-env ⟨file⟩|⟨name⟩. - Файл
$XDG_DATA_HOME/ghc/arch-os-version/environments/name, если передан параметр-package-env ⟨name⟩. - Файл ⟨file⟩, если для переменной среды
GHC_ENVIRONMENTзадано значение ⟨file⟩. - Файл
$XDG_DATA_HOME/ghc/arch-os-version/environments/name, если для переменной средыGHC_ENVIRONMENTзадано значение ⟨name⟩.
Кроме того, если не указан -hide-all-packages, ghc также ищет файл окружения пакетов в следующих местах:
- Файл
.ghc.environment.arch-os-version, если он существует в текущем или любом родительском каталоге (но не в домашнем каталоге пользователя). - Файл
$XDG_DATA_HOME/ghc/arch-os-version/environments/default, если он существует.
Окружения пакетов можно изменять с помощью дополнительных аргументов командной строки; например, если указать в командной строке -package foo, пакет ⟨foo⟩ будет видим, даже если он не указан в текущем окружении пакетов.