Илья Ермаков писал(а):
В КП вообще нет понятия "совместимый модуль", а совместимость через фингерпринты проверяется по каждой сущности.
Если я откомпилировал MyStrings и загрузчику говорю подгружать его вместо Strings, он по каждой использованной конкретным модулем-клиентом процедуре проверит совместимость.
Спасибо, так уже понятнее, что вы пытаетесь сделать.
Я не согласен, что учет имени модуля при расчете отпечатка (фингерпринта) - это концептуальная ошибка. И вот почему.
Язык предоставляет гарантии типовой совместимости. На уровне Сообщения и уровне исходных текстов это выглядит как некая абстрактная система правил и выводов.
Теоретически, можно сделать среду исполнения, в которой не будет никаких ocf/osf файлов, а компиляция будет производиться по требованию при загрузке модуля. Ничто в Сообщении этому не препятствует.
Однако это непроизводительно. Поэтому компилируют раз, используют (загружают) - многократно.
В такой среде возникает промежуточное представление (состояние) - машинный файл ocf. И вместе с ним - проблема рассинхронизации:
В момент времени t:
MODULE Exp; VAR p*: INTEGER; END Exp. -> Exp.ocf
MODULE Imp; IMPORT Exp; BEGIN Exp.p := 123456 END Imp. -> Imp.ocfПри компиляции Imp все требования Сообщения удовлетворены, Imp корректен.
Затем в момент времени t':
MODULE Exp'; VAR p*: POINTER TO ... END Exp'. -> Exp.ocfНо в t' модуль Imp Не перекомпилируется. Imp.ocf по-прежнему считается корректным. Если он будет загружен, то среда не обеспечит гарантии безопасности, обещанные языком. Таким образом, среда должна проверять корректность модуля при загрузке, а не только при компиляции.
Чтобы проверить эту корректность, можно
А) перекомпилировать Imp. Но исходного текста может не оказаться под рукой, а может - он вообще не доступен (в силу лицензирования). Тогда можно
Б) Воспользоваться символьным файлом Imp - там достаточно сведений, чтобы проверить корректность сопряжения Imp и Exp. Но, во-первых, это довольно трудоемко (так казалось в середине 90х), а во-вторых, символьного файла тоже может не оказаться под рукой. Можно, конечно, сохранить символьную информацию в ocf, но это ж сколько байтов потребуется! (так казалось в 90х)
В) Можно "схитрить": в Imp.ocf записать датувремя или отпечаток от Exp.ocf. Тогда при загрузке Imp загрузчик увидит, что Finger(Exp'.ocf) # Imp.ocf.Finger(Exp.ocf), и откажет в загрузке. Придется перекомпилировать Imp. (Это отличается от А, поскольку там предлагалось перекомпилировать, чтобы проверить корректность; а в В приходится перекомпилировать, поскольку установлена некорректность).
ЕМНИП, так и было в системе Оберон. И в Модуле до Оберона.
Но это очень хлопотно: всамделе,
MODULE Exp''; VAR p*: INTEGER; VAR q: CHAR END Exp.При таких изменениях загрузчик все равно откажется загружать Imp, придется перекомпилировать; но
очевидно, что Imp можно и не перекомпилируя загружать, ведь изменения не коснулись того, от чего Imp зависел. (Даже если бы q была экспортирована)
Вот когда кому-то надоело по сто раз перекомпилировать пол-системы, он решил написать дипломную или диссер, и формализовать, что это за "
очевидно" такое. И придумались отпечатки (фингерпринты) как средство более конкретного отслеживания рассинхронизации. Теперь среда оперирует фактами вида:
Модуль Imp импортирует Exp.p с отпечатком fp.
Модуль Exp экспортирует p с отпечатком fp.Загрузчик проверяет соответствие и в случае несоответствия отказывает в загрузке. Теперь реже нужно перекомпилировать "вхолостую": среда "поумнела" и "понимает", что в случае Exp'' модуль Imp по-прежнему корректен.
Отмечу, что это - вовсе не контроль версий. И не контроль соответствия реализаций. Так, процедура Proc* может вообще получить другую реализацию в Exp', при этом ее отпечаток останется неизменным, и клиенты спокойно загрузятся.
Цель всей этой отпечатковой системы - обеспечить языковые гарантии безопасности и строгой типизации, только и всего. И сделать это производительно - без "втягивания" символьной информации и без проверки типизации при загрузке.
Поэтому я не согласен, что учет имени модуля при расчете отпечатка - это концептуальная ошибка.
Похоже, я согласен с Trurl, в том, что вы пытаетесь сделать то, на что среда не рассчитана. Вам, как я понял, нужно оперировать фактами вида
Модуль Cheat экспортирует p, которую можно использовать вместо Exp.p с отпечатком fp.Таких фактов в ББ нигде нет. Но, если уж очень надо, то можно соорудить некий чит-тул, который будет на основе Cheat.ocf и Exp.ocf делать DoCheat.ocf, в котором машкоды будут из Cheat.ocf, а отпечатки из Exp.ocf. Так вы сможете на свой страх и риск обмануть штатный загрузчик. Он ведь не "вчитывается" в отпечатки, не удостоверяется в их корректности.
Либо - поскольку вы в загрузчиках уже разбирались и всякие чудесности вплоть до горячей замены делали - почему бы не сделать еще один загрузчик, который напрямую будет понимать факты
Вместо Exp следует использовать Cheat.Но самым простым мне кажется следующее:
Вашу реализацию назвать по-честному Strings и разместить в Secondary directory (в рабочей папке ББ). Тогда загрузчик будет подгружать его вместо штатного Strings из primary directory.
(Вероятно, я чего-то еще не знаю в постановке задачи, из-за чего это не подходит?)