Spec-Zone.ru › OCaml 4.14

Глава 11 Партионная компиляция (ocamlc)

  • 11.1 Обзор компилятора
  • 11.2 Опции
  • 11.3 Модули и файловая система
  • 11.4 Распространённые ошибки
  • 11.5 Справочник по предупреждениям

В этой главе описывается партионный компилятор OCaml ocamlc, который компилирует исходные файлы OCaml в байт-кодовые объектные файлы и связывает эти объектные файлы для создания автономных исполняемых файлов байт-кода. Эти исполняемые файлы затем запускаются интерпретатором байт-кода ocamlrun.

11.1 Обзор компилятора

Команда ocamlc имеет интерфейс командной строки, похожий на интерфейсы большинства компиляторов C. Она принимает несколько типов аргументов и обрабатывает их последовательно после обработки всех опций:

  • Аргументы, оканчивающиеся на .mli, рассматриваются как исходные файлы интерфейсов единиц компиляции. Интерфейсы определяют имена, экспортируемые единицами компиляции: они объявляют имена значений с их типами, определяют публичные типы данных, объявляют абстрактные типы данных и т.д. Из файла x.mli компилятор ocamlc создаёт скомпилированный интерфейс в файле x.cmi.
  • Аргументы, оканчивающиеся на .ml, рассматриваются как исходные файлы реализаций единиц компиляции. Реализации предоставляют определения для экспортируемых имен единицы и также содержат выражения, которые должны быть оценены для их побочных эффектов. Из файла x.ml компилятор ocamlc создаёт скомпилированный байт-код объекта в файле x.cmo.

    Если существует файл интерфейса x.mli, реализация x.ml проверяется по отношению к соответствующему скомпилированному интерфейсу x.cmi, который предполагается существующим. Если интерфейс x.mli не предоставлен, компиляция x.ml создаёт скомпилированный файл интерфейса x.cmi в дополнение к скомпилированному объектному коду x.cmo. Созданный файл x.cmi соответствует интерфейсу, экспортирующему всё, что определено в реализации x.ml.

  • Аргументы, оканчивающиеся на .cmo, рассматриваются как скомпилированный байт-код объекта. Эти файлы связываются вместе, вместе с объектными файлами, полученными при компиляции аргументов .ml (если таковые имеются), и стандартной библиотекой OCaml, для создания автономной исполняемой программы. Порядок представления аргументов .cmo и .ml в командной строке важен: единицы компиляции инициализируются в этом порядке во время выполнения, и использование компонента единицы до его инициализации является ошибкой на этапе линковки. Следовательно, данный файл x.cmo должен предшествовать всем файлам .cmo, которые ссылаются на единицу x.
  • Аргументы, оканчивающиеся на .cma, рассматриваются как библиотеки объектного байт-кода. Библиотека объектного байт-кода упаковывает в один файл набор объектных байт-кодовых файлов (.cmo). Библиотеки строятся с помощью ocamlc -a (см. описание опции -a ниже).
  • Аргументы, оканчивающиеся на .c, передаются компилятору C, который генерирует объектный файл .o (.obj в Windows). Этот объектный файл связывается с программой, если установлен флаг -custom (см. описание -custom ниже).
  • Аргументы, оканчивающиеся на .o или .a (.obj или .lib в Windows) считаются объектные файлы и библиотеки C. Они передаются C-линкеру при линковке в режиме -custom (см. описание -custom ниже).
  • Аргументы, оканчивающиеся на .so (.dll в Windows) считаются динамическими библиотеками C (DLL). Во время линковки они проверяются на внешние функции C, на которые ссылается код OCaml, и их имена записываются в сгенерированный исполняемый файл байт-кода. Система выполнения ocamlrun затем загружает их динамически при запуске программы.

Выводом фазы линковки является файл, содержащий скомпилированный байт-код, который может быть выполнен интерпретатором байт-кода OCaml: команда с именем ocamlrun. Если имя файла, созданного на фазе линковки, a.out, команда

        ocamlrun a.out arg1 arg2 … argn

выполняет скомпилированный код, содержащийся в a.out, передавая ему аргументы в виде строк символов arg1 до argn. (См. главу 13 для более подробной информации.)

На большинстве систем файл, созданный фазой линковки, может быть запущен напрямую, как в:

        ./a.out arg1 arg2 … argn

Созданный файл имеет установленный исполняемый бит и сам запускает интерпретатор байт-кода.

Компилятор может выводить некоторую информацию о своих внутренних этапах. Он может выводить файлы .cmt для реализации единицы компиляции и .cmti для сигнатур, если ему передана опция -bin-annot (см. описание -bin-annot ниже). Каждый такой файл содержит типизированное абстрактное синтаксическое дерево (AST), которое создаётся во время процедуры проверки типов. Это дерево содержит всю доступную информацию о местоположении и конкретном типе каждого термина в исходном файле. AST является частичным, если проверка типов не удалась.

Эти файлы .cmt и .cmti обычно полезны для инструментов инспектирования кода.

11.2 Опции

Следующие опции командной строки распознаются ocamlc. Опции -pack, -a, -c, -output-obj и -output-complete-obj являются взаимоисключающими.

-a
Создать библиотеку (.cma файл) из объектных файлов (.cmo файлы), указанных в командной строке, вместо их компоновки в исполняемый файл. Имя библиотеки должно быть задано с помощью опции -o.

Если в командной строке передаются опции -custom, -cclib или -ccopt, эти опции сохраняются в результирующей библиотеке .cma. Затем компоновка с этой библиотекой автоматически добавляет обратно опции -custom, -cclib и -ccopt, как если бы они были предоставлены в командной строке, если не указана опция -noautolink.

-absname
Принудительно отображать абсолютные пути к именам файлов в сообщениях об ошибках.
-annot
Устарело начиная с OCaml 4.11. Пожалуйста, используйте -bin-annot вместо этого.
-args filename
Читать дополнительные аргументы командной строки, завершающиеся символом новой строки, из filename.
-args0 filename
Читать дополнительные аргументы командной строки, завершающиеся нулевым символом, из filename.
-bin-annot
Выгружать подробную информацию о компиляции (типы, привязки, хвостовые вызовы и т.д.) в бинарном формате. Информация для файла src.ml (соотв. src.mli) помещается в файл src.cmt (соотв. src.cmti). В случае ошибки типа выгрузить всю информацию, выведенную анализатором типов до ошибки. Файлы *.cmt и *.cmti, созданные с помощью -bin-annot, содержат больше информации и значительно компактнее, чем файлы, созданные с помощью -annot.
-c
Только компиляция. Подавить этап компоновки компиляции. Исходные файлы преобразуются в скомпилированные файлы, но исполняемый файл не создается. Эта опция полезна для отдельной компиляции модулей.
-cc ccomp
Использовать ccomp в качестве компоновщика C при компоновке в режиме «пользовательского времени выполнения» (см. опцию -custom) и в качестве компилятора C для компиляции исходных файлов .c.
-cclib -llibname
Передать опцию -llibname компоновщику C при компоновке в режиме «пользовательского времени выполнения» (см. опцию -custom). Это приводит к тому, что данная библиотека C компонуется с программой.
-ccopt option
Передать данную опцию компилятору и компоновщику C. При компоновке в режиме «пользовательского времени выполнения», например, -ccopt -Ldir заставляет компоновщик C искать библиотеки C в каталоге dir. (См. опцию -custom).
-color mode
Включить или отключить цвета в сообщениях компилятора (особенно предупреждения и ошибки). Поддерживаются следующие режимы:
auto
использовать эвристику для включения цветов только в том случае, если вывод поддерживает их (терминал ANSI-совместимый tty);
always
включить цвета безусловно;
never
отключить вывод цвета.

Переменная окружения OCAML_COLOR учитывается, если -color не указана. Её значениями являются auto/always/never, как указано выше.

Если -color не указана, OCAML_COLOR не установлена и установлена переменная окружения NO_COLOR, то вывод цвета отключен. В противном случае, используется значение по умолчанию 'auto', и текущая эвристика проверяет, что переменная окружения TERM существует и не пуста или не равна dumb, и что выполняется 'isatty(stderr)'.

-error-style mode
Управлять способом вывода сообщений об ошибках и предупреждений. Поддерживаются следующие режимы:
short
выводить только ошибку и её местоположение;
contextual
как short, но также отображать фрагмент исходного кода, соответствующий местоположению ошибки.
Значение по умолчанию — contextual.

Переменная окружения OCAML_ERROR_STYLE учитывается, если -error-style не указана. Её значениями являются short/contextual, как указано выше.

-compat-32
Проверить, может ли сгенерированный исполняемый байт-код работать на 32-битных платформах, и сигнализировать об ошибке, если нет. Это полезно при компиляции байт-кода на 64-битной машине.
-config
Вывести номер версии ocamlc и подробное резюме его конфигурации, затем завершить работу.
-config-var var
Вывести значение конкретной переменной конфигурации из вывода -config, затем завершить работу. Если переменная не существует, код выхода отличен от нуля. Эта опция доступна только начиная с OCaml 4.08, поэтому авторам скриптов следует предусмотреть резервный вариант для более старых версий.
-custom
Компоновка в режиме «пользовательского времени выполнения». В режиме компоновки по умолчанию компоновщик создает байт-код, предназначенный для выполнения с общей системой времени выполнения, ocamlrun. В режиме пользовательского времени выполнения компоновщик создает выходной файл, содержащий как систему времени выполнения, так и байт-код для программы. Результирующий файл больше, но его можно выполнять напрямую, даже если команда ocamlrun не установлена. Кроме того, режим «пользовательского времени выполнения» позволяет статическую компоновку кода OCaml с пользовательскими функциями C, как описано в главе 20.
Unix: Никогда не используйте команду strip для исполняемых файлов, созданных с помощью ocamlc -custom, это удалит часть байт-кода исполняемого файла.
Unix: Предупреждение о безопасности: никогда не устанавливайте биты «setuid» или «setgid» для исполняемых файлов, созданных с помощью ocamlc -custom, это сделает их уязвимыми для атак.
-depend ocamldep-args
Вычислить зависимости, как это сделала бы команда ocamldep. Остальные аргументы интерпретируются так, как если бы они были переданы команде ocamldep.
-dllib -llibname
Обеспечьте динамическую загрузку C-совместимой библиотеки dlllibname.so (в Windows — dlllibname.dll) системой выполнения ocamlrun при запуске программы.
-dllpath dir
Добавляет директорию dir в путь поиска динамических C-библиотек во время выполнения. При линковке библиотеки поиск ведётся в стандартном пути (соответствующем опции -I). Опция -dllpath просто помещает dir в создаваемый исполняемый файл, где ocamlrun может его найти и использовать, как описано в разделе 13.3.
-for-pack module-path
Создаёт объектный файл (.cmo), который позже можно включить как подмодуль (с заданным путём доступа) в единицу компиляции, созданную с помощью -pack. Например, ocamlc -for-pack P -c A.ml сгенерирует a..cmo, который позже можно использовать с ocamlc -pack -o P.cmo a.cmo. Примечание: вы по-прежнему можете упаковать модуль, который был скомпилирован без -for-pack, но в этом случае исключения будут выведены с неверными именами.
-g
Добавляет отладочную информацию во время компиляции и линковки. Эта опция необходима для отладки программы с помощью ocamldebug (см. главу 18) и для создания трассировок стека при завершении программы с необработанным исключением (см. раздел 13.2).
-i
Принуждает компилятор выводить все определённые имена (с их выведенными типами или определениями) при компиляции реализации (.ml файл). Не создаются скомпилированные файлы (.cmo и .cmi файлы). Это может быть полезно для проверки типов, выведенных компилятором. Также, так как вывод соответствует синтаксису интерфейсов, это может помочь в написании явного интерфейса (.mli файл) для файла: просто перенаправьте стандартный вывод компилятора в .mli файл и отредактируйте его, удалив все объявления неэкспортированных имён.
-I directory
Добавляет заданную директорию в список директорий, которые просматриваются при поиске скомпилированных файлов интерфейсов (.cmi), скомпилированных объектных файлов (.cmo), библиотек (.cma) и C-библиотек, указанных с помощью -cclib -lxxx. По умолчанию сначала ищется текущая директория, затем — стандартная директория библиотек. Директории, добавленные с -I, ищутся после текущей директории в порядке их указания в командной строке, но перед стандартной директорией библиотек. Смотрите также опцию -nostdlib.

Если заданная директория начинается с +, она берётся относительно стандартной директории библиотек. Например, -I +unix добавляет поддиректорию unix стандартной библиотеки в путь поиска.

-impl filename
Скомпилировать файл filename как файл реализации, даже если его расширение не .ml.
-intf filename
Скомпилировать файл filename как файл интерфейса, даже если его расширение не .mli.
-intf-suffix string
Распознавать имена файлов, заканчивающиеся на string, как файлы интерфейса (вместо по умолчанию .mli).
-labels
Метки не игнорируются в типах, метки могут использоваться в приложениях, и помеченные параметры могут быть указаны в любом порядке. Это значение по умолчанию.
-linkall
Принудительно подключать все модули, содержащиеся в библиотеках. Если этот флаг не задан, неиспользуемые модули не подключаются. При построении библиотеки (опция -a), установка опции -linkall заставляет все последующие ссылки программ, использующих эту библиотеку, подключать все модули, содержащиеся в библиотеке. При компиляции модуля (опция -c), установка опции -linkall гарантирует, что этот модуль всегда будет подключён, если он помещён в библиотеку, и эта библиотека подключена.
-make-runtime
Создать собственную систему выполнения (в файле, указанном опцией -o), включающую C-объектные файлы и библиотеки, указанные в командной строке. Эта пользовательская система выполнения может быть использована позже для выполнения байткодовых исполняемых файлов, созданных с помощью ocamlc -use-runtime runtime-name опцию. Подробнее см. в разделе 20.1.6.
-match-context-rows
Установите количество строк контекста, используемого для оптимизации при компиляции сопоставления с образцом. Значение по умолчанию — 32. Более низкие значения приводят к более быстрому компилению, но к менее оптимизированному коду. Эта расширенная опция предназначена для использования в случае, если программа, интенсивно использующая сопоставление с образцом, приводит к существенному увеличению времени компиляции.
Укажите имя выходного файла, создаваемого компилятором. По умолчанию выходное имя — a.out в Unix и camlprog.exe в Windows. Если указан параметр -a, укажите имя создаваемой библиотеки. Если указан параметр -pack, укажите имя создаваемого упакованного объектного файла. Если указаны параметры -output-obj или -output-complete-obj, укажите имя создаваемого выходного файла. Если указан параметр -c, укажите имя объектного файла, созданного для следующего исходного файла в командной строке.
-opaque
При компиляции реализации родным компилятором по умолчанию создаётся файл .cmx с информацией для межмодульной оптимизации. Он также ожидает наличие файлов .cmx для зависимостей текущего компилируемого источника и использует их для оптимизации. Начиная с OCaml 4.03, компилятор будет выдавать предупреждение, если не сможет найти файл .cmx одной из таких зависимостей.

Параметр -opaque, доступный начиная с 4.04, отключает информацию о межмодульной оптимизации для текущего компилируемого модуля. При компиляции интерфейса .mli использование -opaque помечает скомпилированный интерфейс .cmi таким образом, что последующие компиляции модулей, зависящих от него, не будут полагаться на соответствующий файл .cmx и не будут предупреждать об его отсутствии. При компиляции реализации .ml родным компилятором использование -opaque генерирует .cmx, который не содержит никакой информации о межмодульной оптимизации.

Использование этого параметра может снизить качество генерируемого кода, но сокращает время компиляции, как при чистых, так и при инкрементных сборках. Действительно, при использовании родного компилятора, когда изменяется реализация компиляционной единицы, все единицы, зависящие от неё, могут потребовать перекомпиляции — потому что информация о межмодульной оптимизации может измениться. Если компиляционная единица, реализация которой изменилась, была скомпилирована с помощью -opaque, такая перекомпиляция не нужна. Таким образом, этот параметр можно использовать, например, для ускорения циклов редактирования-компиляции-тестирования.

-open Module
Открывает указанный модуль перед обработкой файлов интерфейса или реализации. Если задано несколько параметров -open, они обрабатываются в порядке следования, так как будто инструкции open! Module1;; ... open! ModuleN;; были добавлены в начало каждого файла.
-output-obj
Принуждает компоновщик создать объектный файл C вместо исполняемого файла байт-кода. Это полезно для упаковки OCaml-кода в библиотеку C, которую можно вызывать из любой C-программы. См. главу 20, раздел 20.7.5. Имя выходного объектного файла необходимо установить с помощью параметра -o. Этот параметр также может быть использован для создания файла исходного кода C (.c расширение) или скомпилированной общей/динамической библиотеки (.so расширение, .dll в Windows).
-output-complete-exe
Создаёт автономный исполняемый файл, связывая объектный файл C, содержащий программу байт-кода, систему времени выполнения OCaml и любой другой статический C-код, переданный ocamlc. Результат подобен -custom, за исключением того, что байт-код встроен в C-код, поэтому он больше недоступен для инструментов, таких как ocamldebug. С другой стороны, полученный бинарник устойчив к strip.
-output-complete-obj
То же, что и параметр -output-obj, за исключением того, что создаваемый объектный файл включает библиотеки времени выполнения и автоматической компоновки.
-pack
Создаёт файл объектного кода байт-кода (.cmo файл) и связанный с ним скомпилированный интерфейс (.cmi), объединяющий объектные файлы, указанные в командной строке, представляя их в виде подмодулей выходного файла .cmo. Имя выходного файла .cmo необходимо указать с помощью параметра -o. Например,
        ocamlc -pack -o p.cmo a.cmo b.cmo c.cmo
генерирует скомпилированные файлы p.cmo и p.cmi, описывающие компиляционную единицу, имеющую три подмодуля A, B и C, соответствующие содержимому объектных файлов a.cmo, b.cmo и c.cmo. Это содержимое можно использовать как P.A, P.B и P.C в остальной части программы.
-pp command
Заставляет компилятор вызвать данную команду в качестве препроцессора для каждого исходного файла. Вывод команды перенаправляется в промежуточный файл, который компилируется. Если ошибок компиляции нет, промежуточный файл удаляется после этого.
-ppx command
После разбора, абстрактное синтаксическое дерево передаётся на обработку препроцессору command. Модуль Ast_mapper, описанный в главе 27: Ast_mapper , реализует внешний интерфейс препроцессора.
-principal
Проверяет пути информации при проверке типов, чтобы убедиться, что все типы получены принципиальным способом. При использовании меченных аргументов и/или полиморфных методов этот флаг необходим, чтобы гарантировать, что будущие версии компилятора смогут корректно выводить типы, даже если внутренние алгоритмы изменятся. Все программы, принятые в режиме -principal, также принимаются в режиме по умолчанию с эквивалентными типами, но различными бинарными подписями, и это может замедлить проверку типов; тем не менее, рекомендуется использовать его один раз перед публикацией исходного кода.
-rectypes
Разрешает произвольные рекурсивные типы во время проверки типов. По умолчанию поддерживаются только рекурсивные типы, где рекурсия проходит через тип объекта. Обратите внимание, что после создания интерфейса с помощью этого флага, вы должны использовать его снова для всех зависимостей.
-runtime-variant suffix
Добавляет строку suffix к имени библиотеки времени выполнения, используемой программой. В настоящее время поддерживается только один такой суффикс: d, и только если компилятор OCaml был сконфигурирован с параметром -with-debug-runtime. Этот суффикс предоставляет отладочную версию времени выполнения, что полезно для отладки проблем с указателями в низкоуровневом коде, например, C-стыках.
-stop-after pass
Останавливает компиляцию после указанного этапа компиляции. В настоящее время поддерживаются следующие этапы: parsing, typing.
-safe-string
Внушает разделение между типами string и bytes, делая строки неизменяемыми. Это значение по умолчанию.
-short-paths
Когда тип виден под несколькими модульными путями, используйте самый короткий при печати имени типа в выведенных интерфейсах и сообщениях об ошибках и предупреждениях. Имена идентификаторов, начинающиеся с символа подчеркивания _ или содержащие двойные подчеркивания __, увеличивают длину на +10 при вычислении.
-strict-sequence
Принудительно задайте тип левой части каждой последовательности как unit.
-strict-formats
Отклоняйте недопустимые форматы, которые принимались в старых реализациях форматов. Вы должны использовать этот флаг для обнаружения и исправления таких недопустимых форматов, так как они будут отклоняться будущими версиями OCaml.
-unboxed-types
Если тип может быть не упакован (т.е. запись с одним аргументом или конкретный тип данных с одним конструктором одного аргумента), он будет не упакован, если не помечен как [@@ocaml.boxed].
-no-unboxed-types
Если тип может быть не упакован, он будет упакован, если не помечен как [@@ocaml.unboxed]. Это значение по умолчанию.
-unsafe
Отключить проверку границ для доступа к массивам и строкам (конструкции v.(i) и s.[i]). Программы, скомпилированные с флагом -unsafe, поэтому немного быстрее, но небезопасны: может произойти что угодно, если программа обращается к массиву или строке за пределами его границ. Кроме того, отключите проверку на ноль в операциях целочисленного деления и взятия остатка. С флагом -unsafe целочисленное деление (или взятие остатка) на ноль может остановить программу или продолжить с неопределенным результатом вместо возбуждения исключения Division_by_zero.
-unsafe-string
Идентифицировать типы string и bytes, тем самым делая строки изменяемыми. Это предназначено для совместимости со старым исходным кодом и не должно использоваться с новым ПО.
-use-runtime runtime-name
Сгенерировать исполняемый файл байткода, который может быть запущен на пользовательской системе выполнения runtime-name, созданной ранее с помощью ocamlc -make-runtime runtime-name. Дополнительная информация в разделе 20.1.6.
-v
Вывести номер версии компилятора и расположение каталога стандартной библиотеки, затем завершить работу.
-verbose
Вывести все внешние команды перед их выполнением, в частности вызовы компилятора C и компоновщика в режиме -custom. Полезно для отладки проблем с библиотеками C.
-version or -vnum
Вывести номер версии компилятора в краткой форме (например, 3.11.0), затем завершить работу.
-w warning-list
Включить, отключить или отметить как фатальные предупреждения, указанные аргументом warning-list. Каждое предупреждение может быть включено или выключено, и каждое предупреждение может быть фатальным или не фатальным. Если предупреждение отключено, оно не отображается и никак не влияет на компиляцию (даже если оно фатальное). Если предупреждение включено, оно нормально отображается компилятором всякий раз, когда исходный код его вызывает. Если оно включено и фатальное, компилятор также остановится с ошибкой после его отображения.

Аргумент warning-list — это последовательность спецификаторов предупреждений без разделителей между ними. Спецификатор предупреждения — это одно из следующего:

+num
Включить предупреждение номер num.
-num
Отключить предупреждение номер num.
@num
Включить и отметить как фатальное предупреждение номер num.
+num1..num2
Включить предупреждения в указанном диапазоне.
-num1..num2
Отключить предупреждения в указанном диапазоне.
@num1..num2
Включить и отметить как фатальные предупреждения в указанном диапазоне.
+letter
Включить набор предупреждений, соответствующих letter. Буква может быть заглавной или строчной.
-letter
Отключить набор предупреждений, соответствующих letter. Буква может быть заглавной или строчной.
@letter
Включить и отметить как фатальный набор предупреждений, соответствующих letter. Буква может быть заглавной или строчной.
uppercase-letter
Включить набор предупреждений, соответствующих uppercase-letter.
lowercase-letter
Отключить набор предупреждений, соответствующих lowercase-letter.

Альтернативно, warning-list может указать одно предупреждение по его мнемоническому имени (см. ниже), следующим образом:

+name
Включить предупреждение name.
-name
Отключить предупреждение name.
@name
Включить и отметить как фатальное предупреждение name.

Номера предупреждений, буквы и имена, которые в настоящее время не определены, игнорируются. Предупреждения следующие (имя после каждого номера указывает мнемоническое имя этого предупреждения).

1 comment-start
Подозрительная метка начала комментария.
2 comment-not-end
Подозрительная метка конца комментария.
3
Устаревший синоним предупреждения ’устаревший’.
4 fragile-match
Хрупкое сопоставление с образцом: сопоставление, которое останется полным, даже если к одному из типов вариантов, с которым производится сопоставление, будут добавлены дополнительные конструкторы.
5 ignored-partial-application
Частично применённая функция: выражение, результат которого имеет тип функции и игнорируется.
6 labels-omitted
Метка опущена в применении функции.
7 method-override
Метод переопределён.
8 partial-match
Частичное совпадение: недостающие случаи в сопоставлении с образцом.
9 missing-record-field-pattern
Отсутствующие поля в шаблоне записи.
10 non-unit-statement
Выражение в левой части последовательности, которое не имеет тип unit (и которое не является функцией, см. предупреждение номер 5).
11 redundant-case
Избыточный случай в сопоставлении с образцом (неиспользуемый случай сопоставления).
12 redundant-subpat
Избыточный подшаблон в сопоставлении с образцом.
13 instance-variable-override
Переменная экземпляра переопределена.
14 illegal-backslash
Неправильный обратный слэш в строковой константе.
15 implicit-public-methods
Приватный метод неявно сделан публичным.
16 unerasable-optional-argument
Неудаляемый необязательный аргумент.
17 undeclared-virtual-method
Необъявленный виртуальный метод.
18 not-principal
Неглавный тип.
19 non-principal-labels
Тип без главенства.
20 ignored-extra-argument
Неиспользуемый аргумент функции.
21 nonreturning-statement
Невозвращаемое оператор.
22 preprocessor
Предупреждение препроцессора.
23 useless-record-with
Бесполезная запись with часть.
24 bad-module-name
Неправильное имя модуля: имя файла исходного кода не является допустимым именем модуля OCaml.
25
Игнорируется: теперь часть предупреждения 8.
26 unused-var
Подозрительная неиспользуемая переменная: неиспользуемая переменная, которая связана с let или as и не начинается с символа подчёркивания (_).
27 unused-var-strict
Неопасная неиспользуемая переменная: неиспользуемая переменная, которая не связана с let ни с as, и не начинается с символа подчёркивания (_).
28 wildcard-arg-to-constant-constr
Шаблон подстановки `*` в качестве аргумента константному конструктору.
29 eol-in-string
Неэкранированный конец строки в строковой константе (непереносимый код).
30 duplicate-definitions
Два метки или конструктора с одинаковым именем определены в двух взаимно рекурсивных типах.
31 module-linked-twice
Модуль подключается дважды в одном исполняемом файле.
32 unused-value-declaration
Неиспользуемое объявление значения.
33 unused-open
Неиспользуемый оператор open.
34 unused-type-declaration
Неиспользуемое объявление типа.
35 unused-for-index
Неиспользуемый индекс цикла for.
36 unused-ancestor
Неиспользуемый предковый объект.
37 unused-constructor
Неиспользуемый конструктор.
38 unused-extension
Неиспользуемый расширяющий конструктор.
39 unused-rec-flag
Неиспользуемый флаг rec.
40 name-out-of-scope
Имя конструктора или метки используется вне области видимости.
41 ambiguous-name
Неоднозначное имя конструктора или метки.
42 disambiguated-name
Разрешённое имя конструктора или метки (предупреждение совместимости).
43 nonoptional-label
Необязательная метка применена как необязательная.
44 open-shadow-identifier
Оператор open затеняет уже определённый идентификатор.
45 open-shadow-label-constructor
Оператор open затеняет уже определённую метку или конструктор.
46 bad-env-variable
Ошибка в переменной среды.
47 attribute-payload
Неправильная нагрузка атрибута.
48 eliminated-optional-arguments
Неявное исключение необязательных аргументов.
49 no-cmi-file
Отсутствует файл cmi при поиске псевдонима модуля.
50 unexpected-docstring
Неожиданный комментарий документации.
51 wrong-tailcall-expectation
Вызов функции с неправильным атрибутом @tailcall
END_OF_DOCUMENT_MARKER
52 fragile-literal-pattern (см. 11.5.3)
Хрупкий шаблон константы.
53 misplaced-attribute
Атрибут не может появиться в данном контексте.
54 duplicated-attribute
Атрибут используется более одного раза в выражении.
55 inlining-impossible
Встраивание невозможно.
56 unreachable-case
Недостижимый случай в сопоставлении с образцом (на основе информации о типе).
57 ambiguous-var-in-pattern-guard (см. 11.5.4)
Неоднозначные переменные в шаблонах «или» в условиях.
58 no-cmx-file
Файл cmx отсутствует.
59 flambda-assignment-to-non-mutable-value
Присвоение неизменяемому значению.
60 unused-module
Неиспользуемое объявление модуля.
61 unboxable-type-in-prim-decl
Тип, который можно разложить, в примитивном объявлении.
62 constraint-on-gadt
Ограничение типа на объявлении типа GADT.
63 erroneous-printed-signature
Некорректная напечатанная сигнатура.
64 unsafe-array-syntax-without-parsing
-unsafe используется с препроцессором, возвращающим дерево синтаксического анализа.
65 redefining-unit
Объявление типа, определяющее новый конструктор ’()’.
66 unused-open-bang
Неиспользуемое оператор open!.
67 unused-functor-parameter
Неиспользуемый параметр функтора.
68 match-on-mutable-state-prevent-uncurry
Сопоставление с образцом, зависящее от изменяемого состояния, предотвращает разворачивание оставшихся аргументов.
69 unused-field
Неиспользуемое поле записи.
70 missing-mli
Отсутствует файл интерфейса.
71 unused-tmc-attribute
Неиспользуемый атрибут @tail_mod_cons.
72 tmc-breaks-tailcall
Преобразование @tail_mod_cons превращает хвостовой вызов в нехвостовой.
A
все предупреждения
C
предупреждения 1, 2.
D
Псевдоним предупреждения 3.
E
Псевдоним предупреждения 4.
F
Псевдоним предупреждения 5.
K
предупреждения 32, 33, 34, 35, 36, 37, 38, 39.
L
Псевдоним предупреждения 6.
M
Псевдоним предупреждения 7.
P
Псевдоним предупреждения 8.
R
Псевдоним предупреждения 9.
S
Псевдоним предупреждения 10.
U
предупреждения 11, 12.
V
Псевдоним предупреждения 13.
X
предупреждения 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 30.
Y
Псевдоним предупреждения 26.
Z
Псевдоним предупреждения 27.

Значение по умолчанию — -w +a-4-6-7-9-27-29-32..42-44-45-48-50-60. Оно отображается командой ocamlc -help. Обратите внимание, что предупреждения 5 и 10 не всегда срабатывают, в зависимости от внутренних механизмов проверяющего типов.

-warn-error warning-list
Отмечает как фатальные предупреждения, указанные в аргументе warning-list. Компилятор завершит работу с ошибкой, когда будет выведено одно из этих предупреждений. Списки предупреждений warning-list имеют такое же значение, как и для параметра -w: знак + (или заглавная буква) отмечает соответствующее предупреждение как фатальное, знак - (или строчная буква) возвращает его к статусу не фатального предупреждения, а знак @ одновременно включает и отмечает соответствующее предупреждение как фатальное.

Примечание: в производственном коде не рекомендуется использовать наборы предупреждений (т.е. буквы) в качестве аргументов для -warn-error, потому что это может нарушить сборку при добавлении новых предупреждений в будущих версиях OCaml.

Значение по умолчанию — -warn-error -a+31 (только предупреждение 31 является фатальным).

-warn-help
Отобразить описание всех доступных номеров предупреждений.
-where
Вывести расположение стандартной библиотеки, а затем завершить работу.
-with-runtime
Включить в сгенерированную программу систему выполнения. Это значение по умолчанию.
-without-runtime
Компилятор не включает систему выполнения (ни ссылку на неё) в сгенерированную программу; её необходимо предоставить отдельно.
- file
Обрабатывать file как имя файла, даже если оно начинается с символа тире (-).
-help or --help
Отобразить краткое руководство по использованию и завершить работу.
contextual-cli-control

Контекстуальное управление параметрами командной строки

Командную строку компилятора можно изменять «извне» с помощью следующих механизмов. Они являются экспериментальными и могут быть изменены. Их следует использовать только для экспериментальной и опытной работы, а не в релизах.

OCAMLPARAM (переменная окружения)
Набор аргументов, которые будут вставлены перед или после аргументов из командной строки. Аргументы задаются в виде списка, разделенного запятыми, пар имя=значение. Знак _ используется для указания позиции аргументов командной строки, т.е. a=x,_,b=y означает, что a=x должно быть выполнено перед разбором аргументов, а b=y — после. Наконец, альтернативный разделитель может быть задан как первый символ строки, в наборе :|; ,.
ocaml_compiler_internal_params (файл в директории stdlib)
Сопоставление имён файлов со списками аргументов, которые будут добавлены в командную строку (и аргументы OCAMLPARAM).
OCAML_FLEXLINK (переменная окружения)
Альтернативный исполняемый файл для использования в Windows для flexlink вместо заданного значения. В основном используется для начальной загрузки.

11.3 Модули и файловая система

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

Компилятор всегда выводит имя модуля, беря прописную часть имени исходного файла (.ml или .mli файл). То есть он удаляет ведущее имя директории, если таковое имеется, а также суффикс .ml или .mli; затем он меняет первую букву на заглавную, чтобы соответствовать требованию, что имена модулей должны быть заглавными. Например, компиляция файла mylib/misc.ml предоставляет реализацию для модуля под названием Misc. Другие единицы компиляции могут ссылаться на компоненты, определённые в mylib/misc.ml, под именами Misc.имя; они также могут использовать open Misc, а затем использовать имена имя без квалификатора.

Файлы .cmi и .cmo, созданные компилятором, имеют то же базовое имя, что и исходный файл. Следовательно, скомпилированные файлы всегда имеют базовое имя, равное (с учётом заглавной первой буквы) имени модуля, который они описывают (для файлов .cmi) или реализуют (для файлов .cmo).

Когда компилятор сталкивается со ссылкой на свободный идентификатор модуля Mod, он ищет в пути поиска файл с именем Mod.cmi или mod.cmi и загружает скомпилированный интерфейс, содержащийся в этом файле. Вследствие этого, переименование файлов .cmi не рекомендуется: имя файла .cmi всегда должно соответствовать имени единицы компиляции, которую он реализует. Допустимо перемещать их в другую директорию, если их базовое имя сохраняется, и компилятору задаются правильные опции -I. Компилятор выдаст ошибку, если загрузит файл .cmi, который был переименован.

Скомпилированные файлы байткода (.cmo файлы), с другой стороны, могут быть свободно переименованы после создания. Это потому, что компоновщик никогда не пытается найти сам файл .cmo, который реализует модуль с заданным именем: он вместо этого полагается на то, что пользователь предоставит список файлов .cmo вручную.

11.4 Распространённые ошибки

В этом разделе описаны и объяснены наиболее часто встречающиеся сообщения об ошибках.

Файл filename не найден
Указанный файл не был найден ни в текущем каталоге, ни в каталогах пути поиска. Файл filename — это либо скомпилированный интерфейсный файл (.cmi), либо скомпилированный байт-код файл (.cmo). Если filename имеет формат mod.cmi, это означает, что вы пытаетесь скомпилировать файл, который ссылается на идентификаторы из модуля mod, но вы ещё не скомпилировали интерфейс для модуля mod. Исправление: сначала скомпилируйте mod.mli или mod.ml, чтобы создать скомпилированный интерфейс mod.cmi.

Если filename имеет формат mod.cmo, это означает, что вы пытаетесь связать файл байт-кода, который ещё не существует. Исправление: сначала скомпилируйте mod.ml.

Если ваша программа расположена в нескольких каталогах, эта ошибка также может возникнуть, потому что вы не указали каталоги для поиска. Исправление: добавьте правильные опции -I в командную строку.

Поврежденный скомпилированный интерфейс filename
Компилятор выводит эту ошибку, когда пытается прочитать файл скомпилированного интерфейса (.cmi), имеющий неправильную структуру. Это означает, что при записи файла .cmi что-то пошло не так: диск был заполнен, компилятор был прерван во время создания файла и т. д. Эта ошибка также может возникнуть, если файл .cmi был изменён после его создания компилятором. Исправление: удалите повреждённый файл .cmi и перестройте его.
Это выражение имеет тип t1, но используется с типом t2
Это, пожалуй, самая распространённая ошибка типа в программах. Тип t1 — это тип, выведенный для выражения (часть программы, отображаемая в сообщении об ошибке), анализируя само выражение. Тип t2 — это ожидаемый тип в контексте выражения; он выводится путём анализа того, как используется значение этого выражения в остальной части программы. Если два типа t1 и t2 несовместимы, то выдаётся вышеуказанная ошибка.

В некоторых случаях трудно понять, почему два типа t1 и t2 несовместимы. Например, компилятор может сообщить, что «выражение типа foo нельзя использовать с типом foo», и кажется, что оба типа foo совместимы. Это не всегда верно. Два конструктора типов могут иметь одинаковое имя, но фактически представлять разные типы. Это может произойти, если конструктор типа переопределён. Пример:

        type foo = A | B
        let f = function A -> 0 | B -> 1
        type foo = C | D
        f C

Это приводит к сообщению об ошибке «выражение C типа foo не может быть использовано с типом foo».

Тип этого выражения, t, содержит переменные типов, которые нельзя обобщить
Переменные типов ('a, 'b, …) в типе t могут быть в одном из двух состояний: обобщённый (что означает, что тип t действителен для всех возможных примеров переменных) и не обобщённый (что означает, что тип t действителен только для одного примера переменных). В привязке let let name = expr, система проверки типов обычно обобщает как можно больше переменных типа в типе expr. Однако это приводит к некорректности (хорошо типизированная программа может аварийно завершить работу) в сочетании с полиморфными изменяемыми структурами данных. Для предотвращения этого обобщение выполняется только в привязках let, если связанное выражение expr принадлежит классу «синтаксических значений», которые включают константы, идентификаторы, функции, кортежи синтаксических значений и т. д. Во всех остальных случаях (например, expr — это применение функции), может быть создана полиморфная изменяемая структура, и поэтому обобщение выключено для всех переменных, встречающихся в контравариантных или невариантных ветвях типа. Например, если тип не значения — 'a list, переменная обобщаема (list — ковариантный конструктор типа), но не в 'a list -> 'a list (левая ветвь -> контравариантна) или 'a ref (ref невариантна).

Необобщённые переменные типа в типе не создают проблем внутри данной структуры или единицы компиляции (содержимое файла .ml или интерактивной сессии), но они не могут быть разрешены внутри сигнатур или скомпилированных интерфейсов (.cmi файл), поскольку они могут быть использованы несогласованно позже. Таким образом, компилятор выдает ошибку, когда структура или единица компиляции определяет значение name, тип которого содержит необобщённые переменные типа. Есть два способа исправить эту ошибку:

  • Добавьте ограничение типа или файл .mli, чтобы дать мономорфный тип (без переменных типа) для name. Например, вместо того, чтобы писать
        let sort_int_list = List.sort Stdlib.compare
        (* inferred type 'a list -> 'a list, with 'a not generalized *)
    
    напишите
        let sort_int_list = (List.sort Stdlib.compare : int list -> int list);;
    
  • Если вам действительно нужен полиморфный тип для name, преобразуйте его определяющее выражение в функцию, добавив дополнительный параметр. Например, вместо того, чтобы писать
        let map_length = List.map Array.length
        (* inferred type 'a array list -> int list, with 'a not generalized *)
    
    напишите
        let map_length lv = List.map Array.length lv
    
Ссылка на неопределённый глобальный модуль mod
Эта ошибка появляется при попытке связать неполный или неправильно упорядоченный набор файлов. Либо вы забыли указать реализацию для единицы компиляции под названием mod в командной строке (как правило, файл под названием mod.cmo или библиотека, содержащая этот файл). Исправление: добавьте недостающий файл .ml или .cmo в командную строку. Либо вы указали реализацию для модуля под названием mod, но она указана слишком поздно в командной строке: реализация mod должна предшествовать всем файлам байт-кода, которые ссылаются на mod. Исправление: измените порядок файлов .ml и .cmo в командной строке.

Конечно, вы всегда столкнётесь с этой ошибкой, если у вас есть взаимно рекурсивные функции в разных модулях. Например, функция Mod1.f вызывает функцию Mod2.g, а функция Mod2.g вызывает функцию Mod1.f. В этом случае, независимо от того, какие перестановки вы выполните в командной строке, программа будет отклонена на этапе компоновки. Исправления:

  • Поместите функции f и g в один модуль.
  • Параметризуйте одну функцию через другую. Например, вместо
    mod1.ml:    let f x = ... Mod2.g ...
    mod2.ml:    let g y = ... Mod1.f ...
    
    определите
    mod1.ml:    let f g x = ... g ...
    mod2.ml:    let rec g y = ... Mod1.f g ...
    
    и свяжите mod1.cmo перед mod2.cmo.
  • Используйте ссылку, чтобы хранить одну из двух функций, как в:
    mod1.ml:    let forward_g =
                    ref((fun x -> failwith "forward_g") : <type>)
                let f x = ... !forward_g ...
    mod2.ml:    let g y = ... Mod1.f ...
                let _ = Mod1.forward_g := g
    
Внешняя функция f недоступна
Эта ошибка появляется при попытке связать код, который вызывает внешние функции, написанные на C. Как объяснено в главе 20, такой код должен быть связан с библиотеками C, которые реализуют необходимую функцию C f. Если рассматриваемые библиотеки C не являются динамическими библиотеками (DLL), код необходимо связать в режиме «специального времени выполнения». Исправление: добавьте необходимые библиотеки C в командную строку и, возможно, опцию -custom.

11.5 Справочная информация по предупреждениям

В этом разделе подробно описаны и объяснены некоторые предупреждения:

11.5.1 Предупреждение 6: Метка опущена в применении функции

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

let f ~x ~y = x + y
let test = f 2 3

> let test = f 2 3
>            ^
> Warning 6 [labels-omitted]: labels x, y were omitted in the application of this function.

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

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

Со временем стало привычным включать это предупреждение, чтобы избежать ошибок в порядке аргументов. Теперь предупреждение включено по умолчанию с OCaml 4.13. Приложения labels-omitted больше не рекомендуются, но пользователи, желающие сохранить этот переходный стиль, могут отключить предупреждение явно.

11.5.2 Предупреждение 9: отсутствующие поля в шаблоне записи

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

type 'a point = {x : 'a; y : 'a}
let dx { x } = x (* implicit field elision: trigger warning 9 *)
let dy { y; _ } = y (* explicit field elision: do not trigger warning 9 *)

11.5.3 Предупреждение 52: хрупкий шаблон константы

Некоторые конструкторы, такие как конструкторы исключений Failure и Invalid_argument, принимают в качестве параметра значение string, содержащее текстовое сообщение, предназначенное для пользователя.

Эти текстовые сообщения обычно не стабильны со временем: места вызова, создающие эти конструкторы, могут уточнить сообщение в будущей версии, чтобы сделать его более явным и т.д. Поэтому опасно сопоставлять точное значение сообщения. Например, до OCaml 4.02, Array.iter2 вызывало исключение

  Invalid_argument "arrays must have the same length"

С 4.03 оно вызывает более полезное сообщение

  Invalid_argument "Array.iter2: arrays must have the same length"

но это означает, что любой код в форме

  try ...
  with Invalid_argument "arrays must have the same length" -> ...

теперь сломан и может страдать от необработанных исключений.

Предупреждение 52 предназначено для предотвращения написания такого хрупкого кода в первую очередь. Оно не возникает при каждом сопоставлении с литеральной строкой, а только в том случае, когда авторы библиотек выразили свое намерение, возможно, изменить значение параметра конструктора в будущем, используя атрибут ocaml.warn_on_literal_pattern (см. раздел руководства об встроенных атрибутах в 10.12.1):

type t =
  | Foo of string [@ocaml.warn_on_literal_pattern]
  | Bar of string

let no_warning = function
  | Bar "specific value" -> 0
  | _ -> 1

let warning = function
  | Foo "specific value" -> 0
  | _ -> 1

Warning 52 [fragile-literal-pattern]: Code should not depend on the actual values of
this constructor's arguments. They are only for information
and may change in future versions. (See manual section 11.5)

В частности, все встроенные исключения со строковым аргументом имеют этот атрибут: Invalid_argument, Failure, Sys_error все вызовут это предупреждение, если вы сопоставите конкретный строковый аргумент.

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

Если ваш код вызывает это предупреждение, вы не должны изменять способ проверки конкретной строки, чтобы избежать предупреждения (например, используя сравнение строк внутри правой части вместо литерального шаблона), так как ваш код останется хрупким. Вместо этого вам следует расширить область шаблона, сопоставив все возможные значения.

let warning = function
  | Foo _ -> 0
  | _ -> 1

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

Например,

try (int_of_string count_str, bool_of_string choice_str) with
  | Failure "int_of_string" -> (0, true)
  | Failure "bool_of_string" -> (-1, false)

должно быть переписано в более атомарные проверки. Например, используя шаблоны исключений, описанные в разделе 9.6, можно написать:

match int_of_string count_str with
  | exception (Failure _) -> (0, true)
  | count ->
    begin match bool_of_string choice_str with
    | exception (Failure _) -> (-1, false)
    | choice -> (count, choice)
    end

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

11.5.4 Предупреждение 57: неоднозначные переменные шаблона «или» под защитой

Семантика шаблонов «или» в OCaml определена с предвзятостью слева направо: значение v соответствует шаблону p | q, если оно соответствует p или q, но если оно соответствует обоим, среда, захваченная совпадением, является средой, захваченной p, а никогда не захваченной q.

Хотя это свойство обычно интуитивно понятно, есть по крайней мере один конкретный случай, где может быть ожидаема другая семантика. Рассмотрим шаблон, за которым следует условие when: | p when g -> e, например:

     | ((Const x, _) | (_, Const x)) when is_neutral x -> branch

Семантика ясна: сопоставить scrutinee с шаблоном, если оно соответствует, проверить условие и если условие выполняется, принять ветвь. В частности, рассмотрим входные данные (Const a, Const b), где a не проходит тест is_neutral a, а b проходит тест is_neutral b. С семантикой слева направо приведенный выше фрагмент кода не принимается его вводом: соответствие (Const a, Const b) с шаблоном «или» выполняется в левой ветви, оно возвращает среду x -> a, а затем условие is_neutral a проверяется и терпит неудачу, ветвь не принимается.

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

     | (Const x, _) when is_neutral x -> branch
     | (_, Const x) when is_neutral x -> branch

Это не семантика, принятая OCaml.

Предупреждение 57 посвящено этим запутанным случаям, когда указанная семантика слева направо не эквивалентна недетерминированной семантике (любая ветвь может быть принята) относительно конкретного условия. Более точно, оно предупреждает, когда условие использует «неоднозначные» переменные, которые связаны с разными частями scrutinee разными сторонами шаблона «или».

© 1995-2022 INRIA.
https://v2.ocaml.org/releases/4.14/htmlman/comp.html

Spec-Zone.ru

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