Глава 11 . Компиляция во внутренний код (ocamlopt)
В этой главе описывается высокопроизводительный компилятор
внутреннего кода Objective Caml ocamlopt
,
который компилирует исходные тексты Caml в объектные файлы с
внутренним кодом и компонует последние в самостоятельные
исполняемые файлы.
Этот компилятор доступен не на всех платформах. Генерируемый
им код работает быстрее байткода, создаваемого
ocamlc
, однако возрастает как время
компиляции, так и размер исполняемых файлов. Тем не менее,
совместимость с байткодом исключительно выскока: один и тот же
код работает одинаково вне зависимости от того, скомпилирован он
ocamlc
или
ocamlopt
.
Файлы с внутренним кодом нельзя смешивать с файлами с
байкодом: программа должна быть скомилирована целиком либо
ocamlc
, либо ocamlopt
.
Объектные файлы с внутренним кодом, кроме того, не могут
загружаться в интерактивную систему
ocaml
.
11 . 1 Обзор компилятора
ocamlopt
имеет интерфейс командной
строки, весьма схожий с ocamlc
. Компилятор
принимает те же типы аргументов:
-
Аргументы, заканчивающиеся на
.mli
считаются исходными файлами для интерфейсов единиц компиляции. В интерфейсах указываются имена, экспортируемые единицами компиляции: там объявлены имена переменных и их типы, определены типы данных, объявлены абстрактные типы данных, и т.д. Из файлаX.mli
компиляторocamlopt
создаст файлX.cmi
со скомпилированным интерфейсом. Результат идентичен файлу, создаваемомуocamlc
. -
Аргументы, заканчивающиеся на
.ml
считаются исходными файлами для реализаций единиц компиляции. Реализации содержат определения для имен, экспортируемых единицей, а также выражения, вычисляемые на предмет их сторонних эффектов. Из файлаX.ml
компиляторocamlopt
создает два файла -X.o
. с внутренним кодом иX.cmx
с дополнительной информацией для компоновки и оптимизации клиентов единицы. На компилированную реализацию всегда следует ссылаться по имениX.cmx
(ocamlopt
, считает что любой файл.o
скомпилирован из кода на языке С, а не Caml).Реализация сверяется с интерфейсом
X.mli
(если он существует), как описано в документацииocamlc
(гл. 8). -
Аргументы, заканчивающиеся на
.cmx
считаются скомпилированным объектным кодом. Они компонуются с объектными файлы, полученными при компиляции аргументов.ml
, и стандартной библиотекой Caml, давая в результате исполняемую программу во внутреннем коде. Порядок следования в командной строке аргументов.cmx
и.ml
важен: во время исполнения единицы компиляции инициализируются в том же порядке, так что во время компоновки ошибкой будет использовать компонент единицы до ее инициализации. Поэтому файлX.cmx
должен стоять в командной строке компилятора прежде любых файлов.cmx
, ссылающихся на единицуX
. -
Аргументы, заканчивающиеся на
.cmxa
считаются библиотеками объектного кода. Такая библиотека в двух файлах (lib.cmxa
иlib.a
) содержит набор объектных файлов (.cmx/.o
). Она создается командойocamlopt -a
(см. описание опций ниже). Объектные файлы в библиотеке компонуются как обычные файлы.cmx
в том же порядке, в каком строился файл.cma
. Единственное различие состоитв том, что, если в программе нет ссылок на какой-то объектный файл в библиотеке, то он и не компонуется с программой. -
Аргументы, заканчивающиеся на
.c
, передаются комплятору С, который генерирует объектный файл.o
. Затем этот файл компонуется с программой. -
Аргументы, заканчивающиеся на
.o
,.a
или.so
(.obj
,.lib
и.dll
под Windows) считаются объекнтыми файлами и библиотеками С. Они компонуются с программой.
Результатом стадии компоновки является обычный исполняемый
файл. Для запуска ему не нужна
ocamlrun
.
11 . 2 Параметры
ocamlc
разпознает следующие параметры
командной строки:
- -a
-
Строит библиотеку (файл
.cmx/.a
) из объектных файлов (.cmx/.o
), перечисленных в командной строке, не компонуя их в исполняемый файл. Имя библиотеки задается параметром-o
. По умолчанию используетсяlibrary.cmxa
.Если в командной строке присутствуют параметры
-cclib
или-ccopt
, они также сохраняются в библиотеке, а затем при автоматически добавляются к командам при компоновке, если только не задан параметр-noautolink
. - -cclib -llibname
-
Передать компилятору и компоновщику С опцию -llibname. В результате указанная библиотека С будет скомпонована с программой.
- -ccopt option
-
Передать указанную опцию компилятору и компоновщику С. Например,
-ccopt -L
dir заставит его искать библиотеки С в каталоге dir. - -compact
-
Оптимизировать код по размеру, а не быстродействию. В результате получаются программы чуть меньшего размера, работающие чуть медленее. По умолчанию используется оптимизация по быстродействию.
- -i
-
Компилятор выводит все определенные имена, а также выведенные типы или определения при компиляции реализации (файла
.ml
). Это бывает полезно для проверки типов, распознанных компилятором. Кроме того, поскольку вывод соответствует синтаксису интерфейсов, он может помочь явно написать интерфейс (файл.mli
) для файла: достаточно перенаправить вывод компилятора в файл.mli
и убрать из результата декларации имен, экспорт которых не предполагается. - -I directory
-
Добавляет
directory
к списку каталогов, в которых ищутся компилированные файлы интерфейсов (.cmi
), компилированные объектные файлы (.cmx
) и библиотеки (.cmxa
). По умолчанию в первую очередь файлы ищутся в текущем каталоге, затем - в каталоге стандартной библиотеки. Каталоги, заданные опцией-I
учитываются после текущего, в том же порядке, как они заданы в командной строке, но перед стандартной библиотекой.Если каталог начиначается со знака
+
, то он считается заданным относительно каталога стандартной библиотеки. Например,-I +labltk
добавляет к списку поиска подкаталогlabltk
стандартной библиотеки. - -inline n
-
Устанавливает агрессивность встраиваемости в значение n, где n - положительное целое число. Значение
-inline 0
приводит к тому, что функции вовсе не становятся встраиваемыми, за исключением тех, тело которых меньше точки вызова. Таким образом, встраиваемость не приводит к увеличению объема кода. Агрессивность по умолчанию (-inline 1
предусматривает встраиваемость чуть больших по размеру функций, что дает небольшой прирост кода. Дальнейнее увеличение значения этого параметра приводит к том, что все более и более объемные функции становятся кандидатами на встраивание, но и код от этого может значительно вырасти. - -linkall
-
Форсирует компоновку всех модулей библиотеки. Без этого параметра модули, на которых ссылок нет, не компонуются. При построении библиотеки (флаг
-a
) установка флага-linkall
приводит к тому, что в последующем при компиляции программ, использующих эту библиотеку, все модули библиотеки будут компоноваться заново. - -noassert
-
Отключает проверку утверждений, и утверждения не компилируются. При компоновке ранее скомпилированных файлов этот флаг не работает.
- -noautolink
-
При компоновке библиотек
.cmxa
опции-custom
,-cclib
и-ccopt
, вероятно хранящиеся в библиотеках (если они были указаны при построении библиотек), игнорируются. Этот флаг полезен, если библиотека содержит неправильные спецификации библиотек или опций С. В этом случае надо указать в командной строке правильные библиотеки и опции С. - -nolabels
-
Игнорировать неопциональные метки в типах. В этом случае метки не могут использоваться в приложениях, и порядок аргументов становится строгим.
- -o exec-file
-
Имя файла, создаваемого компоновщиком. По умолчанию по традициям Unix создается файл
a.out
. Если используется опция-a
, укажите имя библиотеки. Если используется опция-output-obj
, укажите имя объектного файла. - -output-obj
-
Вместо исполняемого файла компоновщик создает объектный файл С. Это позволяет при необходимости оформить код Caml как библиотеку С, которую можно вызывать из любой программы С. Более подробно см. раздел 18.7.5. По умолчанию создается файл
camlprog.o
, но имя может быть задано с помощью опции-o
. - -p
-
Генерировать дополнительный код для записи профилировочной информации при исполнении программы. Такую информацию можно изучить с помощью программы
gprof
(см. подробнее гл. 17). Параметр должен быть задан как во время компиляции, так и во время компоновки. Можно компоновать объектные файлы, скомпилированные в обычном режиме, но профилирование в этом случае будет менее точным.- Unix
-
Подробную информацию о профайлах см. в страницах руководства Unix
gprof(1)
.Полная поддержка
gprof
есть только на некоторых платформах (в настоящее время - Intel x86/Linux и Alpha/Digital Unix). На других платформах профайлы менее точны (нет графов вызова, только профайл по времени). - Windows
-
Этот параметр не работает под Windows.
- -pack
-
Создает объектный файл (
.cmx/.o
) и связанный с с ним скомпилированный интерфейс (.cmi
), которые включают все объектные файлы.cmx
, перечисленные в командной строке. Эти файлы становятся субмодулями результирующего файла.cmx
. Имя последнего задается опцией-o
. Например,ocamlopt -pack -o p.cmx a.cmx b.cmx c.cmx
создает компилированные файлы
p.cmx
иp.cmi
, описывающие единицу компиляции, включающую субмодули A, B и C, соотвествующие содержанию объектных файловa.cmx
,b.cmx
иc.cmx
. В дальнейшем на них можно ссылаться какP.A
,P.B
иP.C
.- Unix
-
Параметр
-pack
доступен лишь на тех платформах, для которых существуют инструменты GNUbinutils
nm
иobjcopy
.
- -pp command
-
Компилятр вызывает заданную команду
command
как препроцессор для каждого исходного файла. Вывод команды перенаправляется в промежуточный файл, который и компилируется. Если компиляция проходит без ошибок, по ее завершении промежуточный файл удаляется. Имя файла конструируется на основе имени исходного файла и получает расширение.ppi
для интерфейса (.mli
) или.ppo
для реализации (.ml
). - -principal
-
Во время проверки типов компилятор проверяет также информацию о путях, следя чтобы все типы выводились приниципально. Программы, допустимые в режиме
-principal
, допустимы и в режиме по умолчанию с эквивалентными типами, однако бинарные сигнатуры в этом случае другие. - -rectypes
-
Разрешает во время проверки типа произвольные рекурсивные типы. По умолчанию поддерживаются только рекурсивные типы с рекурсией по типу объекта.
- -S
-
Сохранять код ассемблера, полученный во время компиляции. Код для файла
X.ml
сохраняется какX.s
. - -thread
-
Компилирует или компонует многопоточные программы с использованием библиотеки
thread
, описанной в главе 24. На самом деле, эта опция просто подключает особую версию стандартной библиотеки, безопасную по потокам. - -unsafe
-
Отключает проверку границ на массивах и обращении к строкам (конструкции
v.(i)
иs.[i]
). Программы, собранные с этой опцией несколько быстрее, но не являются безопасными: при обращении к элементу за пределами массива или границы строки может произойти все, что угодно. - -v
-
Выводит номер версии компилятора и путь к стандартной библиотеке, после чего прекращает работу.
- -verbose
-
Выводит все внешние команды перед их выполнением. В частности это касается ассемблера, компилятора и компоновщика C.
- -version
-
Выводит номер версии компилятора в краткой форме (например
3.06
) и прекращает работу. - -w warning-list
-
Включает или выключает предупреждения согласно аргументу
warning-list
. Аргумент является строкой из одной или нескольких букв следующего значения:- A/a
-
включить/выключить все предупреждения.
- C/c
-
включить/выключить предупреждения о подозрительных комментариях.
- D/d
-
Включить/выключить предупреждения об использовании устаревших функций.
- F/f
-
Включить/выключить предупреждения о неполном применении функций (например,
f x; expr
при том, что вызовf x
имеет тип функции). - L/l
-
Включить/выключить предупреждения о пропуске меток в вызовах.
- M/m
-
Включить/выключить предупреждения о переопределенных методах.
- P/p
-
Включить/выключить предупреждения о неполных совпадениях (пропущенные ветки в поиске по образцу).
- S/s
-
Включить/выключить предупреждения о предложениях с типом, отличным от
unit
(например,expr1; expr2
, когдаexpr1
не имеет типunit
. - U/u
-
Включить/выключить предупреждения о неиспользуемых (избыточных) совпадениях с образцом.
- V/v
-
Включить/выключить предупреждения о скрытых переменных экземпляра.
- X/x
-
Включить/выключить все остальные предупреждения.
По умолчанию используется установка
-w Al
(все предупреждения, кроме меток). - -warn-error
-
Все предупреждения, включенные в аргумент
warning-list
считаются ошибками. Компилятор останавливается на ошибке при появлении одного из предупреждений, вместо того, чтобы продолжать выполнение.warning-list
является строкой из одной или нескольких букв того же значения, что и в опцииw
: прописная буква превращает предупреждение в ошибку, строчная оставляет ее предупреждением. Значение по умолчанию --warn-error a
(все предупреждения не считаются ошибками). - -where
-
Выводит путь к стандартной библиотеке и прекращает работу.
11 . 3 Распространенные ошибки
Сообщения об ошибказ практически идентичны сообщениям ocamlc
. См. раздел 8.4.
11 . 4 Совместимость с компилятором байткода
В этом разделе перечислены известные случаи несовместимости компилятора байткода и компилятора во внутренний код. В остальном код, созданный этими компиляторами, должен работать одинаково.
-
Следующие операции приводят к остановке программы через системное прерывание или аварийный сигнал Unix (байткод вызывает исключение):
-
Целочисленное деление или деление по модулю на ноль.
-
Переполнение стека.
-
(Только на процессорах Alpha). Операции над числами с плавающей точкой, в которых участвуют бесконечные или денормализованные числа (все остальные процессоры, поддерживаемые
ocamlopt
работают с такими числами правильно, по стандарту IEEE 754).
В частности, переполнение стека из-за глубокой рекурсии на большинстве ядер Unix приводит к сигналу "нарушение сегментации".
-
-
Сигналы отмечены лишь по время выделения кучи программой. Иными словами, если сигнал возник в части кода, который не смог выделить память, его обработчик будет вызван лишь в следующий момент выделения кучи.
Лучший способ избежать таких несовместимостей - это
никогда не перехватывать исключения
Division_by_zero
и
Stack_overflow
, то есть независимо от
компилятора считать такие ситуаци ошибками. Зачастую лучше
заранее проверить делитель, чем ловить исключение.