Модули, символьные файлы и ключи

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

Что получается при компиляции

Из Math.Mod компилятор делает два файла:

Смотреть .rsc можно командой ORTool.DecObj Math.rsc — она печатает заголовок и дизассемблированный код.

Ключ

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

compiling Math  447     0 32C32F12

Ключ меняется тогда и только тогда, когда меняется интерфейс: состав экспортированных имён, их типы, порядок. Изменение тела процедуры при том же заголовке ключ не трогает.

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

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

Ключ /s

Отсюда и смысл ключа /s в команде компиляции. По умолчанию компилятор отказывается перезаписывать символьный файл, если интерфейс изменился, — потому что это молча сломает всех, кто уже собран.

/s говорит «да, я знаю, перезаписывай». После этого всех зависимых надо пересобрать. Порядок пересборки — от тех, кто ни от кого не зависит, к тем, кто зависит от всех.

При пересборке неизменённого исходника интерфейс не меняется, ключ остаётся прежним, и /s безвреден. Именно поэтому в лабораторных он стоит везде.

Порядок сборки

Порядок задаётся импортами. Для этой системы он получается такой (начало):

Kernel  FileDir  Files  Modules  Input  Display  Viewers
Fonts  Texts  Oberon  ...  ORS  ORB  ORG  ORP  ...

Его не надо помнить: он выводится из самих исходников топологической сортировкой по IMPORT. Мы так и делаем, когда пересобираем систему целиком.

Что показывает пересборка

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

Мы пересобрали всю систему внутри неё самой. Тридцать семь объектных файлов из тридцати девяти собрались побайтово идентично. Два исключения оказались находками:

Первое вы воспроизведёте своими руками в лабораторной №7: посмотрите длину Math.rsc до и после.

Ещё три несогласованности

Заодно выяснилось, что три модуля с этого образа не компилируются компилятором с того же образа:

модуль сообщение причина
RISC pos 926 bad divisor в тексте IR DIV 80000000H, а эта константа как знаковое целое отрицательна; делитель должен быть положительным
ORC import not available импортирует модуль V24, которого на образе нет ни исходником, ни символьным файлом
Net девять раз incompatible parameters сигнатуры вызовов SCC разошлись с SCC.Mod этого же образа

Это не поломка нашей машины и не ошибка сборки: диагностику выдаёт сам компилятор Оберона, а расхождение в Math.rsc видно побайтовым сравнением файлов.

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