Spec-Zone.ru › Haskell 9

5.1. Использование GHC

5.1.1. Начало работы: компиляция программ

В этой главе вы найдёте полный справочник по синтаксису командной строки GHC, включая все более чем 400 флагов. Это большая и сложная система со множеством деталей, поэтому разобраться, с чего начать, может быть непросто. Поэтому в этом вводном разделе кратко описаны основные способы использования GHC для компиляции программы на Haskell, прежде чем в следующих разделах мы подробно рассмотрим весь синтаксис.

Создадим программу «Привет, мир», скомпилируем и запустим её. Для начала создайте файл hello.hs, содержащий код на Haskell:

main = putStrLn "Hello, World!"

Чтобы скомпилировать программу, используйте GHC следующим образом:

$ ghc hello.hs

(где $ обозначает приглашение командной строки: вводить его не нужно). GHC скомпилирует исходный файл hello.hs, создав объектный файл hello.o и файл интерфейса hello.hi, а затем скомпонует объектный файл с библиотеками, входящими в состав GHC, чтобы создать исполняемый файл с именем hello в Unix/Linux/Mac или hello.exe в Windows.

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

Затем можно запустить программу следующим образом:

$ ./hello
Hello World!

Если программа состоит из нескольких модулей, достаточно указать GHC имя исходного файла, содержащего модуль Main, и GHC проанализирует объявления import, чтобы найти другие модули, составляющие программу, и их исходные файлы. Это означает, что, за исключением модуля Main, имя каждого исходного файла должно соответствовать имени содержащегося в нём модуля (точки заменяются разделителями каталогов). Например, модуль Data.Person находился бы в файле Data/Person.hs в Unix/Linux/Mac или Data\Person.hs в Windows.

5.1.2. Обзор параметров

Поведение GHC управляется параметрами, которые по историческим причинам иногда также называют флагами или аргументами командной строки. Параметры можно задавать тремя способами:

5.1.2.1. Аргументы командной строки

Вызов GHC имеет следующий вид:

ghc [argument...]

Аргументы командной строки — это параметры или имена файлов.

Параметры командной строки начинаются с -. Их нельзя объединять: -vO отличается от -v -O. Параметры необязательно должны предшествовать именам файлов: например, ghc *.o -o foo. Сначала обрабатываются все параметры, а затем они применяются ко всем файлам; например, нельзя вызвать ghc -c -O1 Foo.hs -O2 Bar.hs, чтобы применить разные уровни оптимизации к файлам Foo.hs и Bar.hs.

Помимо передачи аргументов через командную строку, их можно передавать с помощью файлов ответов в стиле GNU. Например:

$ cat response-file
-O1
Hello.hs
-o Hello
$ ghc @response-file

Примечание

Обратите внимание, что параметры командной строки зависят от порядка: аргументы обрабатываются слева направо. При наличии неявно устанавливаемых флагов это может приводить к неожиданным результатам. Например, рассмотрим -fno-specialise и -O1 (который подразумевает -fspecialise). Эти две командные строки дают совершенно разные результаты:

-fno-specialise -O1

-fspecialise будет включён, поскольку -fno-specialise переопределяется параметром -O1.

-O1 -fno-specialise

-fspecialise не будет включён, поскольку -fno-specialise переопределяет -fspecialise, подразумеваемый параметром -O1.

5.1.2.2. Параметры командной строки в исходных файлах

Иногда полезно тесно связать исходный файл с необходимыми ему параметрами командной строки. Например, если в исходном файле на Haskell намеренно используются затеняющие имена, его следует компилировать с параметром -Wno-name-shadowing. Вместо того чтобы вести список параметров для каждого файла в Makefile, их можно указать непосредственно в исходном файле с помощью OPTIONS_GHC прагмы

{-# OPTIONS_GHC -Wno-name-shadowing #-}
module X where
...

OPTIONS_GHC — это прагма в заголовке файла (см. прагму OPTIONS_GHC).

В прагме OPTIONS_GHC можно использовать только динамические флаги (см. Динамические параметры и параметры режима).

Обратите внимание, что ваша командная оболочка не обрабатывает параметры, указанные в исходном файле: они просто буквально включаются в массив аргументов командной строки, который компилятор хранит внутри. Поэтому вас ждёт большое разочарование, если вы попробуете использовать подстановку шаблонов и тому подобное внутри OPTIONS_GHC.

Примечание

Содержимое OPTIONS_GHC добавляется в конец параметров командной строки, поэтому параметры, указанные в исходном файле, имеют приоритет над параметрами командной строки.

Не рекомендуется переносить всё содержимое Makefile в исходные файлы, однако в некоторых случаях прагма OPTIONS_GHC — это правильное решение. (Если вы используете -keep-hc-file и в вашем модуле указаны флаги OPTION, то OPTIONS_GHC будет помещен в созданный файл .hc.)

5.1.2.3. Установка параметров в GHCi

Параметры также можно изменять в GHCi с помощью команды :set.

5.1.3. Динамические параметры и параметры режима

Каждый параметр командной строки GHC относится к одной из двух категорий: динамической или режимной.

Режим: режим можно указывать только в командной строке. Можно передать только один флаг режима. Например, --make или -E. Доступные режимы перечислены в разделе Режимы работы.

Динамический параметр: динамический флаг можно указывать в командной строке, в прагме OPTIONS_GHC исходного файла или задавать с помощью команды :set в GHCi.

В справочных таблицах флагов (Справочник по флагам) указано состояние каждого флага.

5.1.4. Значимые расширения файлов

Для файлов с «значимыми» расширениями (например, .lhs или .o) автоматически выполняется нужное действие.

.hs

Модуль Haskell.

.lhs

Модуль на «литературном Haskell».

.hspp

Файл, созданный препроцессором.

.hi

Файл интерфейса Haskell, вероятно созданный компилятором.

.hie

Расширенный файл интерфейса Haskell, созданный компилятором Haskell.

.hc

Промежуточный файл C, созданный компилятором Haskell.

.c

Файл C, не созданный компилятором Haskell.

.ll

Исходный файл на промежуточном языке LLVM, обычно создаваемый компилятором.

.bc

Файл битового кода на промежуточном языке LLVM, обычно создаваемый компилятором.

.s

Исходный файл на языке ассемблера, обычно создаваемый компилятором.

.o

Объектный файл, созданный ассемблером.

Файлы с другими расширениями (или без расширений) передаются непосредственно компоновщику.

5.1.5. Режимы работы

Поведение GHC в первую очередь определяется флагом режима. Можно указать только один из этих флагов, но он не обязательно должен быть первым параметром командной строки. Например,

$ ghc Main.hs --make -o my-application

Если флаг режима не указан, GHC перейдёт в режим --make (Использование ghc --make), если в командной строке указаны исходные файлы Haskell; в противном случае он свяжет указанные в командной строке объектные файлы, чтобы создать исполняемый файл.

Доступны следующие флаги режима:

--interactive

Интерактивный режим, также доступный как ghci. Подробное описание интерактивного режима приведено в разделе Использование GHCi.

--run ⟨file⟩

Запустить точку входа main скрипта. Подобно runghc/runhaskell, по умолчанию этот режим использует интерпретатор байт-кода. Если в командной строке есть аргумент --, все следующие за ним аргументы будут переданы скрипту. Все аргументы, предшествующие --, интерпретируются как аргументы GHC.

--make

В этом режиме GHC автоматически соберёт многомодульную программу на Haskell, самостоятельно определив зависимости. Если ваша программа на Haskell проста, этот способ, скорее всего, будет гораздо проще и быстрее, чем использование make. Режим make описан в разделе Использование ghc --make.

Этот режим используется по умолчанию, если в командной строке указаны исходные файлы Haskell; в этом случае параметр --make можно опустить.

-e ⟨expr⟩

Режим вычисления выражений. Он очень похож на интерактивный режим, но вместо него вычисляется одно выражение (⟨expr⟩), заданное в командной строке. Этот флаг можно указывать несколько раз; в таком случае выражения вычисляются последовательно. Подробнее см. Режим вычисления выражений.

-E

Остановиться после препроцессирования (файл .hspp)

-C

Остановиться после генерации C (файл .hc)

-S

Остановиться после генерации ассемблерного кода (файл .s)

-c

Остановиться после генерации объектного файла (.o)

Это традиционный режим пакетной компиляции, в котором GHC может компилировать исходные файлы по одному или связывать объектные файлы в исполняемый файл. См. Режим пакетного компилятора.

--merge-objs

Объединить набор статических объектных файлов в библиотеку, оптимизированную для загрузки в GHCi. См. Создание библиотек GHCi.

-M

Режим генерации зависимостей. В этом режиме GHC можно использовать для генерации сведений о зависимостях, подходящих для использования в Makefile. См. Генерация зависимостей.

--frontend ⟨module⟩

Запустить GHC с указанным подключаемым модулем внешнего интерфейса. Подробнее см. Подключаемые модули внешнего интерфейса.

-shared

Создать разделяемый объект (или DLL в Windows). См. Создание DLL.

--help
-?

Вывести длинное сообщение со справкой по использованию в стандартный вывод, а затем завершить работу.

--show-iface ⟨file⟩

Прочитать интерфейс из ⟨file⟩ и вывести его в текстовом виде в stdout. Например, ghc --show-iface M.hi.

--supported-extensions
--supported-languages

Вывести список поддерживаемых языковых расширений.

--show-options

Вывести список поддерживаемых параметров командной строки. Этот флаг можно использовать для автодополнения в оболочке.

--info

Вывести сведения о компиляторе.

--version
-V

Вывести строку в одну строку с номером версии GHC.

--numeric-version

Вывести только числовой номер версии GHC.

--print-booter-version

Вывести числовую версию двоичного файла GHC, использованного для начальной загрузки сборки этого компилятора.

--print-build-platform

Вывести целевую строку платформы сборки, на которой был собран GHC, в формате, сформированном GNU Autotools. Формат: cpu-manufacturer-operating_system-(kernel), например x86_64-unknown-linux.

--print-c-compiler-flags

Вывести список флагов, переданных компилятору C при сборке GHC.

--print-c-compiler-link-flags

Вывести список флагов, переданных компилятору C на этапе компоновки при сборке GHC.

--print-debug-on

Вывести True, если GHC был собран с флагом -DDebug. Он включает проверки утверждений и дополнительный отладочный код. Флаг можно задать в GhcStage1HcOpts и/или GhcStage2HcOpts; он автоматически устанавливается для вариантов сборки devel1 и devel2.

--print-global-package-db

Вывести путь к каталогу глобальной базы пакетов GHC. База пакетов хранит сведения об установленных пакетах в каталоге, содержащем отдельный файл для каждого пакета. Этот флаг выводит путь к глобальной базе, поставляемой с GHC; в Unix он выглядит примерно так: /usr/lib/ghc/package.conf.d. Могут существовать и другие базы пакетов, например пользовательская база пакетов. Подробнее см. Базы пакетов.

--print-have-interpreter

Вывести YES, если GHC был собран со встроенным интерпретатором, и NO в противном случае. Если в эту сборку GHC не включён интерпретатор, запуск в интерактивном режиме (см. --interactive) приведёт к ошибке. Это относится только к интерактивному использованию GHC, но не к отдельным исполняемым файлам GHCi (см. Использование GHCi).

--print-have-native-code-generator

Вывести YES, если генератор машинного кода поддерживает целевую платформу, и NO в противном случае. (См. Генератор машинного кода (-fasm).)

--print-host-platform

Вывести целевую строку платформы хоста, то есть платформы, на которой должен работать GHC, в формате, сформированном GNU Autotools. Формат: cpu-manufacturer-operating_system-(kernel), например x86_64-unknown-linux.

--print-leading-underscore

Вывести YES, если GHC был собран для использования символов с подчёркиванием в начале в объектных файлах, и NO в противном случае. Обычно это зависит от целевой платформы.

--print-libdir

Вывести путь к каталогу библиотек GHC. Это корень дерева каталогов, содержащего библиотеки, интерфейсы и включаемые файлы GHC (в Unix он обычно выглядит примерно так: /usr/local/lib/ghc-5.04). Это значение $libdir в файле конфигурации пакета (см. Пакеты).

--print-ld-flags

Вывести флаги компоновки, используемые для сборки GHC.

--print-object-splitting-supported

Вывести NO, поскольку разделение объектных файлов больше не поддерживается. Более переносимый и надёжный альтернативный вариант описан в разделе -split-sections.

--print-project-git-commit-id

Вывести идентификатор коммита Git, из которого был собран этот GHC. Это позволяет определить конкретную ревизию, из которой получен текущий двоичный файл, что особенно полезно при разработке самого GHC. Значение задаётся скриптом configure.

--print-project-version

Вывести версию, заданную скриптом configure во время сборки. Это просто версия GHC.

--print-rts-ways

Пакеты, например система выполнения (Runtime System), могут собираться в нескольких вариантах: - profiling — с поддержкой профилирования - dynamic — с динамической компоновкой - logging — с журналированием событий RTS - threaded — многопоточная RTS - debug — RTS с отладочной информацией

Возможны различные сочетания этих вариантов.

--print-stage

GHC собирается с помощью самого GHC, и эта сборка выполняется по этапам, которым присваиваются номера.

  • Этап 0 — установленный у вас GHC. «Установленный у вас GHC» также называется «компилятором начальной загрузки».
  • Этап 1 — первый GHC, который мы собираем с помощью этапа 0. Затем этап 1 используется для сборки пакетов.
  • Этап 2 — второй GHC, который мы собираем с помощью этапа 1. Обычно именно его мы устанавливаем при выполнении make install.
  • Этап 3 является необязательным, но иногда его собирают для проверки этапа 2.

Этап 1 не поддерживает интерактивное выполнение (GHCi) и Template Haskell.

--print-support-smp

Вывести YES, если GHC был собран с поддержкой нескольких процессоров, и NO в противном случае.

--print-tables-next-to-code

Вывести YES, если GHC был собран с флагом --enable-tables-next-to-code, и NO в противном случае. Этот параметр включён по умолчанию, поскольку он позволяет получить более эффективное расположение кода.

--print-target-platform

Вывести целевую строку целевой платформы, то есть платформы, на которой будут выполняться сгенерированные двоичные файлы, в формате, сформированном GNU Autotools. Формат: cpu-manufacturer-operating_system-(kernel), например x86_64-unknown-linux.

--print-unregisterised

Вывести YES, если этот GHC был собран в режиме без регистровой оптимизации (unregisterised), и NO в противном случае. «Без регистровой оптимизации» означает, что GHC отключит большинство платформенно-зависимых приёмов и оптимизаций. Будут доступны только генераторы кода LLVM и C. Подробнее см. Компиляция без регистровой оптимизации.

5.1.5.1. Использование ghc --make

В этом режиме GHC собирает многомодульную программу на Haskell, проходя по зависимостям от одного или нескольких корневых модулей (обычно это только Main). Например, если ваш модуль Main находится в файле с именем Main.hs, скомпилировать и скомпоновать программу можно так:

ghc --make Main.hs

На самом деле GHC автоматически переходит в режим make, если в командной строке указаны исходные файлы Haskell и не задан другой режим. Поэтому в этом случае можно просто ввести:

ghc Main.hs

Можно указать любое количество имён исходных файлов или модулей; GHC определит все модули программы, пройдя по импортам из этих начальных модулей. Затем он попытается скомпилировать каждый устаревший модуль и, наконец, если есть модуль Main, программа также будет скомпонована в исполняемый файл.

Основные преимущества использования ghc --make по сравнению с традиционными Makefile:

  • GHC не нужно перезапускать перед каждой компиляцией, поэтому он может кэшировать данные между компиляциями. Компиляция многомодульной программы с помощью ghc --make может выполняться до двух раз быстрее, чем последовательный запуск ghc для каждого исходного файла.
  • Вам не нужно писать Makefile.
  • При каждом запуске GHC заново вычисляет зависимости, поэтому они никогда не расходятся с исходным кодом.
  • С помощью флага -j[⟨n⟩] можно компилировать модули параллельно. Укажите -j ⟨n⟩, чтобы компилировать ⟨n⟩ задач параллельно. Если ⟨n⟩ не задано, используется число процессоров.

С --make можно использовать любые параметры командной строки, описанные в остальной части этой главы. Однако следует учитывать, что все параметры, указанные в командной строке, применяются ко всем компилируемым исходным файлам. Если параметр должен применяться только к одному исходному файлу, используйте прагму OPTIONS_GHC (см. Параметры командной строки в исходных файлах).

Если программу нужно скомпоновать с дополнительными объектными файлами (например, с некоторым вспомогательным кодом на C), укажите эти файлы в командной строке, и GHC включит их в исполняемый файл при компоновке.

Для обратной совместимости с существующими сценариями make при использовании вместе с -c этап компоновки пропускается (как и при --make -no-link).

Обратите внимание, что GHC может отслеживать зависимости, только если ему доступен исходный файл. Поэтому, если программа включает модуль без исходного файла, GHC выдаст сообщение об ошибке, даже если для этого модуля имеются объектный файл и файл интерфейса. Исключение составляют модули пакетов, исходные файлы которых могут как присутствовать, так и отсутствовать.

Исходные файлы программы необязательно должны находиться в одном каталоге; для добавления каталогов в путь поиска можно использовать параметр -i (см. Путь поиска).

-j[⟨n⟩]

По возможности выполнять компиляцию параллельно. Во время компиляции GHC будет использовать до ⟨N⟩ потоков. Если N не задано, используется число процессоров. Обратите внимание, что компиляция модуля может начаться только после сборки его зависимостей.

5.1.5.2. Протокол Jobserver GHC

Протокол Jobserver GHC описан в предложении GHC № 540.

Этот протокол позволяет серверу динамически запускать множество экземпляров клиентского процесса, ограничивая их общее число используемых возможностей значением <n>. Это достигается координацией через системный семафор (семафор POSIX в Linux и Darwin или семафор Win32 в Windows).

В протоколе Jobserver GHC участвуют два типа процессов:

  • Jobserver создаёт системный семафор с определённым количеством доступных токенов.

    Каждый раз перед запуском нового подпроцесса jobclient сервер обязан сначала получить один токен из семафора. Этот токен необходимо освободить после завершения подпроцесса.

    После завершения работы jobserver обязан уничтожить созданный им семафор.

  • Jobclient — это подпроцесс, запущенный jobserver или другим jobclient.

    Каждый jobclient начинает работу с одним доступным токеном (своим неявным токеном, полученным от родительского процесса, который его запустил) и может запросить дополнительные токены через протокол Jobserver, ожидая появления токена в семафоре.

    Каждый раз перед запуском нового подпроцесса jobclient обязан передать дочернему jobclient один токен. Это может быть неявный токен jobclient или другой токен, полученный им из семафора.

    Каждый jobclient обязан освободить ровно столько токенов, сколько он получил из семафора (не считая неявных токенов).

    Сам GHC выступает в роли jobclient; этот режим можно включить с помощью флага -jsem.

-jsem

По возможности выполнять компиляцию параллельно, координируя работу с другими процессами через семафор ⟨sem⟩ (заданный в виде строки). Если семафор не существует, возникает ошибка.

Параметр -jsem имеет приоритет над параметром -j[⟨n⟩], и наоборот.

5.1.5.3. Несколько домашних единиц

Компилятор также поддерживает сборку нескольких единиц за один запуск. В современных проектах часто приходится одновременно работать с несколькими взаимозависимыми пакетами. Поддержка нескольких домашних единиц позволяет загрузить все эти локальные пакеты в один сеанс ghc и быстро получать сведения о том, как изменения влияют на другие зависимые пакеты.

Чтобы задать несколько единиц, параметр -unit @⟨filename⟩ указывается несколько раз, вместе с файлом ответа, содержащим аргументы для каждой единицы. Файл ответа содержит список аргументов, разделённых символами новой строки.

ghc -unit @unitA -unit @unitB

где файл ответа unitA содержит обычные аргументы, которые передаются в режим --make.

-this-unit-id a-0.1.0.0
-i
-isrc
A1
A2
...

После этого, запустившись в режиме --make, компилятор скомпилирует обе единицы — a и b.

GHCi полностью поддерживает несколько домашних единиц. Их можно указать с помощью параметра -unit @⟨filename⟩.

ghc --interactive -unit @unitA -unit @unitB
-unit @⟨filename⟩

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

Для упрощения работы с несколькими единицами добавлено несколько дополнительных флагов.

-working-dir ⟨dir⟩

Обычно предполагается, что пакет компилируется в каталоге, где находится его файл cabal. Поэтому все пути, используемые компилятором, считаются относительными к этому каталогу. При работе с несколькими домашними единицами компилятор часто запускается не из стандартного каталога, а из каталога, где находится файл cabal.project. В этом случае можно передать параметр -working-dir, задающий путь от текущего каталога до каталога, который единица считает корневым; обычно это каталог, содержащий файл cabal.

При указании этого флага все относительные пути, используемые компилятором, отсчитываются от рабочего каталога. В частности, это относится к флагам -i и -I⟨dir⟩.

Значение этого параметра также можно получить с помощью функции Template Haskell getPackageRoot. Он предназначен для использования с вспомогательными функциями, такими как makeRelativeToProject, которые делают относительные пути к файлам относительными к каталогу компиляции, а не к каталогу, содержащему файл .cabal.

-this-package-name ⟨unit-id⟩

Этот флаг упрощает неудобное взаимодействие расширения PackageImports и нескольких домашних единиц. При использовании PackageImports в импорте можно указать имя пакета, чтобы различать модули с одинаковыми именами, находящиеся в разных пакетах.

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

-hidden-module ⟨module name⟩

Этот флаг можно указывать несколько раз, чтобы задать модули домашней единицы, которые не должны быть видны за её пределами.

Флаг предназначен главным образом для воссоздания различия между открытыми и скрытыми модулями установленных пакетов.

-reexported-module ⟨reexport-spec⟩

Этот флаг можно указывать несколько раз, чтобы задать модули, которые не определены в единице, но должны быть реэкспортированы. В результате другие единицы будут видеть такой модуль так, как будто он определён в этой единице.

Простая форма флага позволяет реэкспортировать один модуль под тем же именем:

-reexported-module A

В более сложной форме флага при реэкспорте можно переименовать модуль:

-reexported-module "A as B"

Этот флаг позволяет воспроизвести возможность реэкспорта модулей пакетов при работе с несколькими домашними единицами.

5.1.5.3.1. Требование замкнутости домашних единиц

При работе с несколькими домашними единицами необходимо обеспечить одно важное свойство замкнутости.

Внешние единицы не должны зависеть от домашних единиц.

Компилятор проверяет это свойство замкнутости, однако вызывающий GHC инструмент должен обеспечить, чтобы переданный список домашних единиц удовлетворял этому инварианту.

Например, предположим, что у нас есть три единицы: p, q и r, причём p зависит от q, а q — от r. Тогда согласно свойству замкнутости, если мы загружаем p и r как домашние единицы, необходимо также загрузить q, поскольку q зависит от домашней единицы r, а q нужна, потому что от неё зависит p.

5.1.5.4. Режим вычисления выражений

Этот режим очень похож на интерактивный, но в нём вычисляется одно выражение, заданное в командной строке как аргумент параметра -e:

ghc -e expr

В командной строке можно указать исходные файлы Haskell; они будут загружены так же, как в интерактивном режиме. Выражение вычисляется в контексте загруженных модулей.

Например, чтобы загрузить и запустить программу на Haskell, содержащую модуль Main, можно выполнить:

ghc -e Main.main Main.hs

Или можно просто использовать этот режим для вычисления выражений в контексте Prelude:

$ ghc -e "interact (unlines.map reverse.lines)"
hello
olleh

5.1.5.5. Режим пакетной компиляции

В пакетном режиме GHC компилирует один или несколько исходных файлов, указанных в командной строке.

Первая запускаемая фаза определяется суффиксом каждого входного файла, а последняя — флагом. Если подходящий флаг не указан, компиляция проходит до этапа компоновки. Сводная информация приведена в таблице:

Фаза системы компиляции

Суффикс, указывающий «начать здесь»

Флаг, указывающий «остановиться после»

(суффикс) выходного файла

препроцессор literate

.lhs

.hs

препроцессор C (необязательный)

.hs (с -cpp)

-E

.hspp

компилятор Haskell

.hs

-C, -S

.hc, .s

компилятор C (необязательный)

.hc или .c

-S

.s

ассемблер

.s

-c

.o

компоновщик

⟨другое⟩

a.out

Таким образом, типичный вызов может выглядеть так:

ghc -c Foo.hs

чтобы скомпилировать исходный файл Haskell Foo.hs в объектный файл Foo.o.

Примечание

Результат работы собственно компилятора Haskell зависит от используемого генератора кода. Подробнее см. в разделе Бэкенды GHC.

Примечание

Предварительная обработка является необязательной; её включает флаг -cpp. Подробнее см. в разделе Параметры, влияющие на препроцессор C.

Примечание

Параметр -E выполняет только этапы предварительной обработки компилятора и сохраняет результат в файл.

Примечание

Параметр -C доступен только в том случае, если GHC собран в режиме без регистрации. Подробнее см. в разделе Компиляция без регистрации.

5.1.5.5.1. Переопределение поведения по умолчанию для файла

Как описано выше, способ обработки файла GHC зависит от его суффикса. Это поведение можно переопределить с помощью параметра -x ⟨suffix⟩:

-x ⟨suffix⟩

Файлы, следующие за этим параметром в командной строке, обрабатываются так, как если бы у них был суффикс ⟨suffix⟩. Например, чтобы скомпилировать модуль Haskell в файле M.my-hs, используйте ghc -c -x hs M.my-hs.

5.1.6. Параметры подробности вывода

См. также режимы --help, --version, --numeric-version и --print-libdir в разделе Режимы работы.

-v

Параметр -v включает подробный вывод GHC: компилятор сообщает номер версии и показывает (в stderr), как именно он запускает каждую фазу системы компиляции. Кроме того, он передаёт флаг -v большинству фаз; каждая из них сообщает свой номер версии (и, возможно, некоторую другую информацию).

Пожалуйста, пожалуйста, используйте параметр -v при сообщении об ошибках! Первое, что мы хотим проверить, — действительно ли вы запускали нужные компоненты в правильном порядке.

-v⟨n⟩

Чтобы предоставить больше возможностей для управления подробностью вывода компилятора, флаг -v принимает необязательный числовой аргумент. Указание только -v эквивалентно -v3, а остальные уровни имеют следующие значения:

-v0

Отключить все необязательные сообщения (значение по умолчанию).

-v1

Минимальный уровень подробности: выводить одну строку на компиляцию (значение по умолчанию при включённых параметрах --make или --interactive).

-v2

Выводить название каждой фазы компиляции при её выполнении (эквивалентно -dshow-passes).

-v3

То же, что и -v2, но дополнительно выводится полная командная строка (если применимо) для каждой фазы компиляции.

-v4

То же, что и -v3, но дополнительно выводится промежуточное представление программы после каждой фазы компиляции (за исключением предварительно обработанных файлов и файлов C/ассемблера).

-fprint-potential-instances

Если GHC не удаётся найти экземпляр класса, он выводит краткий список некоторых известных ему экземпляров. С этим флагом он выводит все известные ему экземпляры.

-fhide-source-paths

Начиная с минимального уровня подробности (-v1, см. -v), GHC отображает имя, путь к исходному файлу и целевой путь каждого скомпилированного модуля. Этот флаг позволяет сократить вывод GHC, скрыв пути к исходным и целевым файлам.

Следующие флаги управляют отображением типов в сообщениях об ошибках и в GHCi:

-fprint-unicode-syntax

Если этот параметр включён, GHC выводит сигнатуры типов, используя символы Unicode из расширения UnicodeSyntax. Например:

ghci> :set -fprint-unicode-syntax
ghci> :t +v (>>)
(>>) ∷ Monad m ⇒ ∀ a b. m a → m b → m b
-fprint-explicit-foralls

Параметр -fprint-explicit-foralls заставляет GHC явно выводить квантификацию forall на верхнем уровне типа; обычно она опускается. Например, в GHCi:

ghci> let f x = x
ghci> :t f
f :: a -> a
ghci> :set -fprint-explicit-foralls
ghci> :t f
f :: forall a. a -> a

Однако независимо от настройки флага кванторы выводятся в следующих случаях:

  • Для вложенных foralls, например:

    ghci> :t GHC.ST.runST
    GHC.ST.runST :: (forall s. GHC.ST.ST s a) -> a
    
  • Если вид одного из квантифицированных переменных типа содержит переменную вида, например:

    ghci> :i Data.Type.Equality.sym
    Data.Type.Equality.sym ::
      forall k (a :: k) (b :: k).
      (a Data.Type.Equality.:~: b) -> b Data.Type.Equality.:~: a
            -- Defined in Data.Type.Equality
    
-fprint-explicit-kinds

Параметр -fprint-explicit-kinds заставляет GHC выводить в типах аргументы вида, которые обычно опускаются. Это может быть важно при использовании полиморфизма по видам. Например:

ghci> :set -XPolyKinds
ghci> data T a (b :: l) = MkT
ghci> :t MkT
MkT :: forall k l (a :: k) (b :: l). T a b
ghci> :set -fprint-explicit-kinds
ghci> :t MkT
MkT :: forall k l (a :: k) (b :: l). T @{k} @l a b
ghci> :set -XNoPolyKinds
ghci> :t MkT
MkT :: T @{*} @* a b

Обратите внимание, что в приведённом выше выводе у T есть две переменные вида (k и l) и две переменные типа (a и b). Заметьте, что k — выведенная переменная, а l — заданная переменная (см. раздел Выведенные и заданные переменные типа), поэтому в типе T @{k} @l a b они отображаются с помощью немного различающегося синтаксиса. Применение l (с @l) — это стандартный синтаксис видимого применения типа (см. раздел Видимое применение типа). Применение k (с @{k}), однако, использует гипотетический синтаксис видимого применения типа для выведенных переменных типа. Этот синтаксис в настоящее время не доступен программисту, но всё же отображается при включённом параметре -fprint-explicit-kinds.

-fprint-explicit-coercions

Параметр -fprint-explicit-coercions заставляет GHC выводить приведения в типах. Пытаясь доказать равенство типов разных видов, GHC использует приведения на уровне типов. Пользователям редко требуется видеть их, поскольку они предназначены для внутреннего использования.

-fprint-axiom-incomps

Параметр -fprint-axiom-incomps указывает GHC отображать несовместимости между уравнениями замкнутых семейств типов, когда они выводятся командами :info или --show-iface ⟨file⟩.

ghci> :i Data.Type.Equality.==
type family (==) (a :: k) (b :: k) :: Bool
  where
      (==) (f a) (g b) = (f == g) && (a == b)
      (==) a a = 'True
      (==) _1 _2 = 'False
ghci> :set -fprint-axiom-incomps
ghci> :i Data.Type.Equality.==
type family (==) (a :: k) (b :: k) :: Bool
  where
      {- #0 -} (==) (f a) (g b) = (f == g) && (a == b)
      {- #1 -} (==) a a = 'True
          -- incompatible with: #0
      {- #2 -} (==) _1 _2 = 'False
          -- incompatible with: #1, #0

Уравнения нумеруются начиная с 0, а комментарий после каждого уравнения ссылается на все предшествующие уравнения, с которыми оно несовместимо.

-fprint-equality-relations

Параметр -fprint-equality-relations указывает GHC различать отношения равенства при выводе. Например, ~ — однородное поднятое равенство (виды его аргументов совпадают), тогда как ~~ — неоднородное поднятое равенство (виды его аргументов могут различаться), а ~# — неоднородное неподнятое равенство, внутреннее отношение равенства, используемое решателем GHC. Как правило, пользователям не нужно вникать в эти тонкости; вероятно, вам подойдёт ~. Без параметра -fprint-equality-relations GHC выводит все эти отношения как ~. См. также раздел Ограничения равенства.

-fprint-expanded-synonyms

Если этот параметр включён, GHC также выводит типы после раскрытия синонимов типов в сообщениях об ошибках типов. Например, при следующих синонимах типов:

type Foo = Int
type Bar = Bool
type MyBarST s = ST s Bar

Это сообщение об ошибке:

Couldn't match type 'Int' with 'Bool'
Expected type: ST s Foo
  Actual type: MyBarST s

Превратится в такое:

Couldn't match type 'Int' with 'Bool'
Expected type: ST s Foo
  Actual type: MyBarST s
Type synonyms expanded:
Expected type: ST s Int
  Actual type: ST s Bool
-fprint-redundant-promotion-ticks

Расширение DataKinds позволяет использовать конструкторы данных на уровне типов:

type B = True     -- refers to the data constructor True (of type Bool)

Если существует одноимённый конструктор типа, при разрешении имён он имеет приоритет:

data True = MkT
type B = True     -- now refers to the type constructor (of kind Type)

Мы можем указать GHC предпочесть конструктор данных конструктору типа, используя специальный синтаксис для устранения неоднозначности пространства имён, который называется штрихом продвижения:

data True = MkT
type B = 'True
    -- refers to the data constructor True (of type Bool)
    -- even in the presence of a type constructor of the same name

Обратите внимание, что штрих продвижения не является оператором продвижения. Его единственная цель — указать GHC предпочесть продвинутый конструктор данных конструктору типа в случае конфликта имён. Поэтому GHC не выводит штрих, если конфликта имён нет:

ghci> type B = False
ghci> :kind! B
B :: Bool
= False          -- no promotion tick here

ghci> data False -- introduce a name conflict

ghci> :kind! B
B :: Bool
= 'False         -- promotion tick resolves the name conflict

Параметр -fprint-redundant-promotion-ticks указывает GHC выводить штрих продвижения всегда.

-fprint-typechecker-elaboration

Если этот параметр включён, GHC также выводит в предупреждениях дополнительную информацию от проверяющего типы. Например:

main :: IO ()
main = do
  return $ let a = "hello" in a
  return ()

Это предупреждение:

A do-notation statement discarded a result of type ‘[Char]’
Suppress this warning by saying
  ‘_ <- ($) return let a = "hello" in a’
or by using the flag -fno-warn-unused-do-bind

Превратится в такое:

A do-notation statement discarded a result of type ‘[Char]’
Suppress this warning by saying
  ‘_ <- ($)
          return
          let
            AbsBinds [] []
              {Exports: [a <= a
                           <>]
               Exported types: a :: [Char]
                               [LclId, Str=DmdType]
               Binds: a = "hello"}
          in a’
or by using the flag -fno-warn-unused-do-bind
-fdefer-diagnostics

При сборке многомодульной программы на Haskell этот флаг группирует диагностические сообщения по уровню серьёзности и выводит их после остальных сообщений. Этот флаг может сделать диагностические сообщения заметнее при использовании вместе с параметрами --make и -j[⟨n⟩]. В противном случае нужные ошибки бывает трудно найти, а предупреждения можно не заметить среди множества других сообщений.

-fdiagnostics-as-json

Заставляет GHC выводить диагностические сообщения в стандартизованном формате JSON непосредственно в stderr. Формат соответствует соглашению JSON Lines, в котором каждая диагностика представляет собой отдельный объект JSON, отделённый символом новой строки.

Структура вывода описана в схеме JSON. Схему можно скачать here.

-fdiagnostics-color=⟨always|auto|never⟩

Заставляет GHC выводить сообщения об ошибках цветом. Для этого терминал должен поддерживать цветовые коды ANSI, иначе текст будет отображаться искажённо. Значение по умолчанию — auto: GHC попытается определить, поддерживает ли терминал цвета, и выберет соответствующее поведение.

Точная цветовая схема задаётся переменной окружения GHC_COLORS (или GHC_COLOURS). Ей можно присвоить список пар key=value, разделённых двоеточиями. Настройки по умолчанию таковы:

header=:message=1:warning=1;35:error=1;31:fatal=1;31:margin=1;34

Каждое значение должно быть подстрокой Select Graphic Rendition (SGR). Форматирование каждого элемента может наследоваться от родительских элементов. Например, если header оставить пустым, он унаследует форматирование message. Если же задать для header значение 1 (жирный шрифт), текст будет выделен жирным, но цвет унаследуется от message.

В настоящее время в основном сообщении используется следующее дерево наследования:

  • message

    • header

      • warning
      • error
      • fatal

В диагностике с указателями наследование между margin, warning, error и fatal в настоящее время отсутствует.

Переменной окружения также можно присвоить специальные значения never или always. Это эквивалентно заданию соответствующего флага -fdiagnostics-color, но с более низким приоритетом.

-fdiagnostics-show-caret
По умолчанию:

вкл.

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

-fshow-error-context
По умолчанию:

вкл.

Управляет отображением информации о контексте, в котором произошла ошибка. Этот параметр определяет, будет ли выводиться часть сообщения об ошибке с формулировками «В уравнении…», «В образце…» и т. п.

-fprint-error-index-links=⟨always|auto|never⟩
По умолчанию:

автоматически

Управляет выводом индексов ошибок в виде гиперссылок ANSI на индекс ошибок Haskell. В режиме автоматического выбора гиперссылки отображаются, если это поддерживается терминалом; в режиме always гиперссылки отображаются независимо от возможностей терминала.

-ferror-spans

Заставляет GHC выводить полный диапазон исходного кода синтаксической конструкции, связанной с сообщением об ошибке. Обычно GHC выводит только местоположение начала этой конструкции.

Например:

test.hs:3:6: parse error on input `where'

превращается в:

test296.hs:3:6-10: parse error on input `where'

Возможны также диапазоны, охватывающие несколько строк:

test.hs:(5,4)-(6,7):
    Conflicting definitions for `a'
    Bound at: test.hs:5:4
              test.hs:6:7
    In the binding group for: a, b, a

Обратите внимание, что нумерация строк начинается с единицы, а столбцов — с нуля. Такой выбор сделан в соответствии с существующей практикой (так, например, работает Emacs).

-fkeep-going
Появился в версии:

8.10.1

Заставляет GHC продолжать компиляцию, если в модуле обнаружена ошибка. Все модули, прямо или косвенно зависящие от него, немедленно исключаются из компиляции, а результат всей компиляции всё равно отмечается как содержащий ошибку. Этот параметр не действует при использовании параллельной компиляции (-j[⟨n⟩]).

-freverse-errors

Заставляет GHC выводить ошибки в обратном порядке номеров строк, так что ошибки и предупреждения, возникшие в конце файла, отображаются первыми.

-Rghc-timing

Выводит однострочную сводку статистики времени выполнения GHC. Этот параметр эквивалентен +RTS -tstderr; см. раздел Параметры RTS для управления сборщиком мусора.

5.1.7. Платформозависимые флаги

Некоторые флаги имеют смысл только для определённых целевых платформ.

-mavx

(только x86) Этот флаг позволяет генератору кода (как собственному генератору машинного кода, так и бэкенду LLVM) генерировать инструкции x86_64 AVX.

-mavx2

(только x86) Этот флаг позволяет генератору кода (как собственному генератору машинного кода, так и бэкенду LLVM) генерировать инструкции x86_64 AVX2.

-mavx512cd

(только x86) Этот флаг позволяет генератору кода (как собственному генератору машинного кода, так и бэкенду LLVM) генерировать инструкции x86_64 AVX512-CD.

-mavx512er

(только x86) Этот флаг позволяет генератору кода (как собственному генератору машинного кода, так и бэкенду LLVM) генерировать инструкции x86_64 AVX512-ER.

-mavx512f

(только x86) Этот флаг позволяет генератору кода (как собственному генератору машинного кода, так и бэкенду LLVM) генерировать инструкции x86_64 AVX512-F.

-mavx512pf

(только x86) Этот флаг позволяет генератору кода (как собственному генератору машинного кода, так и бэкенду LLVM) генерировать инструкции x86_64 AVX512-PF.

-msse

(только x86) При использовании собственного генератора машинного кода использовать регистры и набор инструкций SSE для выполнения операций с плавающей точкой. Это значительно повышает производительность операций с плавающей точкой, но полученный скомпилированный код будет работать только на процессорах с поддержкой SSE (Intel Pentium 3 и новее или AMD Athlon XP и новее). Бэкенд LLVM также использует SSE, если процессор его поддерживает, но определяет это автоматически, поэтому флаг не требуется.

Начиная с GHC 8.10 предполагается, что SSE2 поддерживается платформами x86 и x86-64, и по умолчанию используется именно он. Даже при установке этого флага вместо него будет использоваться SSE2.

-msse2

(только x86, добавлен в GHC 7.0.1) При использовании собственного генератора машинного кода использовать регистры и набор инструкций SSE2 для выполнения операций с плавающей точкой. Это значительно повышает производительность операций с плавающей точкой, но полученный скомпилированный код будет работать только на процессорах с поддержкой SSE2 (Intel Pentium 4 и новее или AMD Athlon 64 и новее). Бэкенд LLVM также использует SSE2, если процессор его поддерживает, но определяет это автоматически, поэтому флаг не требуется.

Начиная с GHC 8.10 предполагается, что SSE2 поддерживается платформами x86 и x86-64, и по умолчанию используется именно он.

-msse3

(только x86) Использовать набор инструкций SSE3 для выполнения некоторых операций с плавающей точкой и битовых операций (как при использовании собственного генератора машинного кода, так и бэкенда LLVM).

-mssse3
Появился в версии:

9.14.1

(только x86) Использовать набор инструкций SSSE3 для выполнения некоторых векторных операций (как при использовании собственного генератора машинного кода, так и бэкенда LLVM).

-msse4

(только x86) Использовать набор инструкций SSE4 для выполнения некоторых операций с плавающей точкой и битовых операций (как при использовании собственного генератора машинного кода, так и бэкенда LLVM).

-msse4.2

(только x86, добавлен в GHC 7.4.1) Использовать набор инструкций SSE4.2 для выполнения некоторых операций с плавающей точкой и битовых операций — как при использовании собственного генератора машинного кода, так и бэкенда LLVM. Полученный скомпилированный код будет работать только на процессорах с поддержкой SSE4.2 (Intel Core i7 и новее).

-mbmi

(только x86) Использовать набор инструкций BMI1 для выполнения некоторых битовых операций.

Обратите внимание, что в настоящее время GHC не использует инструкции, специфичные для BMI, поэтому при использовании с собственным генератором машинного кода этот флаг не действует.

-mbmi2

(только x86, добавлен в GHC 7.4.1) Использовать набор инструкций BMI2 для выполнения некоторых битовых операций — как при использовании собственного генератора машинного кода, так и бэкенда LLVM.

Полученный скомпилированный код будет работать только на процессорах с поддержкой BMI2 (Intel Haswell и новее, AMD Excavator, Zen и новее).

-mfma
По умолчанию:

по умолчанию выключен, за исключением Aarch64, где он включён.

Появился в версии:

9.8.1

Использовать собственные инструкции FMA для реализации операций умножения с последующим сложением с плавающей точкой вида x * y + z. Это позволяет выполнить умножение и сложение одной инструкцией без промежуточного округления. Поддерживаемые архитектуры: X86 с набором инструкций FMA3 (включая большинство потребительских процессоров, выпущенных с 2013 года), PowerPC и AArch64.

Если этот флаг отключён, GHC использует реализацию слитого умножения-сложения на C, которая на некоторых платформах может выполнять программную эмуляцию, не соответствующую IEEE (в зависимости от реализации стандартной библиотеки C).

5.1.8. Haddock

-haddock

По умолчанию GHC игнорирует комментарии Haddock (-- | ... и -- ^ ...) и не проверяет, связаны ли они с допустимым элементом, например с сигнатурой типа верхнего уровня. С этим флагом GHC будет разбирать комментарии Haddock и включать их в создаваемый файл интерфейса.

Рекомендуется использовать -Winvalid-haddock, чтобы получать уведомления об отброшенных комментариях документации.

5.1.9. Различные флаги

Некоторые флаги имеют смысл только в определённых сценариях использования.

-ghcversion-file ⟨path to ghcversion.h⟩

При использовании GHC для компиляции файлов C GHC добавляет пути включения пакетов и напрямую подключает ghcversion.h. Компилятор ищет путь к файлу ghcversion.h пакета rts в базе данных пакетов. В некоторых случаях база данных пакетов компилятора не содержит пакет rts либо требуется указать конкретный файл ghcversions.h для подключения. Этот параметр позволяет указать путь к подключаемому файлу ghcversions.h. В первую очередь он предназначен для использования системой сборки GHC.

-H ⟨size⟩

Установить минимальный размер кучи равным ⟨size⟩. Этот параметр эквивалентен +RTS -Hsize; см. Параметры RTS для управления сборщиком мусора.

5.1.9.1. Другие переменные окружения

GHC также можно настроить с помощью различных переменных окружения.

GHC_NO_UNICODE

Если значение не пустое, отключает вывод диагностических сообщений в Unicode независимо от настроек локали. Обычно GHC может определить, что локаль не поддерживает Unicode, и автоматически перейти на ASCII, однако в некоторых особых случаях (например, если вывод GHC перенаправлен) может возникнуть invalid argument (cannot encode character '\8216'). В таком случае задайте GHC_NO_UNICODE.

GHC_CHARENC

Если установлено значение UTF-8, компилятор всегда будет выводить данные в кодировке UTF-8 независимо от текущей локали.

© 2002–2007 The University Court of the University of Glasgow. All rights reserved.
Licensed under the Glasgow Haskell Compiler License.
https://downloads.haskell.org/~ghc/9.14.1/docs/users_guide/using.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API