Spec-Zone.ru › Haskell 9

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

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

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

Давайте создадим программу «Hello, World», скомпилируем и запустим ее. Сначала создайте файл 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 могут использоваться только динамические флаги (см. Динамические и опции режима).

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

Примечание

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

Не рекомендуется перемещать все содержимое ваших Makefiles в исходные файлы, но в некоторых обстоятельствах псевдодиректива 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

Модуль «literate Haskell».

.hspp

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

.hi

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

.hie

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

.hc

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

.c

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

.ll

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

.bc

Файл bitcode llvm-intermediate-language, обычно создаваемый компилятором.

.s

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

.o

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

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

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

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

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

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

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

--interactive

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

--run ⟨file⟩

Запуск точки входа сценария. Аналогично 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 (обычно что-то вроде /usr/local/lib/ghc-5.04 на Unix). Это значение $libdir в файле конфигурации пакета (см. Пакеты).

--print-ld-flags

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

--print-object-splitting-supported

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

--print-project-git-commit-id

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

--print-project-version

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

--print-rts-ways

Пакеты, такие как Runtime System, могут быть скомпилированы различными способами: - профилирование - с поддержкой профилирования - динамически - с динамической загрузкой - логирование - регистрация событий RTS - многопоточно - многопоточный RTS - отладка - 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 был скомпилирован в режиме без регистрации, 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. Протокол GHC Jobserver

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

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

Существуют два типа участников в протоколе GHC Jobserver:

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

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

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

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

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

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

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

    Сам GHC действует как jobclient, что можно включить с помощью флага -jsem.

-jsem

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

Использование -jsem переопределит использование -j[⟨n⟩], и наоборот.

5.1.5.3. Множественные домашние модули

Компилятор также поддерживает построение нескольких модулей в одном вызове. В современных проектах обычно работают с несколькими взаимозависимыми пакетами одновременно, используя поддержку множественных домашниx модулей, вы можете загрузить все эти локальные пакеты в одну сессию 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, в данный момент вы можете запустить сессию GHCi с несколькими модулями, но поддерживается только команда :reload.

-unit @⟨filename⟩

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

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

-working-dir ⟨dir⟩

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

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

Этот параметр также может быть запрошен функцией getPackageRoot Template Haskell. Он предназначен для использования с вспомогательными функциями, такими как 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 будет компилировать один или несколько файлов исходного кода, указанных в командной строке.

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

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

Суффикс, указывающий на начало

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

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

Обработка литеральных препроцессоров

.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⟩

Принудительно обрабатывает все файлы, следующие за этим параметром в командной строке, как если бы у них был суффикс ⟨суффикс⟩. Например, чтобы скомпилировать 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, скрывая пути к исходным и целевым файлам.

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

-fprint-unicode-syntax

При включении GHC выводит сигнатуры типов, используя символы Юникода из расширения 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

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

-fdiagnostics-as-json

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

Структура вывода описана в JSON Schema. Схему можно скачать 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
По умолчанию:

включено

Управляет отображением GHC строки исходного кода, где была обнаружена ошибка. Это также влияет на связанный символ «^», который указывает на область кода с ошибкой.

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

включено

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

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

авто

Управляет тем, будет ли GHC выводить индексы ошибок в виде ANSI-гиперссылок на Индекс ошибок Haskell. При значении «авто» этот флаг будет отображать гиперссылки, если терминал их поддерживает; при значении «всегда» этот флаг будет отображать гиперссылки независимо от возможностей терминала.

-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-бекенда).

-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 для реализации операций с плавающей запятой fused multiply-add вида x * y + z. Это позволяет вычислить умножение и сложение в одной инструкции, без промежуточной операции округления. Поддерживаемые архитектуры: X86 с набором инструкций FMA3 (включая большинство процессоров для потребителей с 2013 года), PowerPC и AArch64.

Когда этот флаг отключён, GHC использует C-реализацию fused multiply-add, которая может выполнять несовместимую с 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.12.1/docs/users_guide/using.html

Spec-Zone.ru

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