Использование COLLAPSE в
проектах MCK.
Установка
COLLAPSE. Выделите для размещения
COLLAPSE директорию, например
C:\KOL\Prj\COLLAPSE и распакуйте в нее архив дистрибутива
(Ниже, если путь начинается с COLLAPSE, то
имеется в виду эта директория).
П-код генерируется в MCK для всех форм
автоматически (еще до установки COLLAPSE). В случае,
если на форме используются design-time компоненты, для
которых генерация П-кода еще не реализована, П-код не генерируется. Отследить
эту ситуацию визуально возможно следующими способами:
- просмотреть текст генерируемого inc-файла (лучше
загрузить в редактор Delphi IDE): [имя_модуля]_1.inc.
Если нет оформления процедуры New[имя_типа_формы]
в виде {$IFDEF Pcode}...{$ELSE} прежний
паскаль-код {$ENDIF}, то П-код не мог быть
сгенерирован.
- открыть консоль (в компоненте
TKOLProject выставить свойство
consoleOut в
true. Если при генерации кода (выставить
BUILD в
true) появляются желтые
сообщения о неподдержке какими-то компонентами П-кодирования, то П-код
сгенерирован не будет, и форма будет инициализирована в run-time
обычным образом, с помощью паскаль-кода.
Для невизульного контроля в
run-time можно проверить
первый байт кода процедуры на
$E4..$E7 первую строку
байт-кода на call RunPCodeN
с N=0..3 (если нет, то
процедура не П-кодированная).
Но для того, чтобы сгенерированный код начал работать, необходимо выполнить
еще некоторое количество действий.
- добавить в список символов условной компиляции
слово
Pcode; эту опцию всегда можно изменить на
noPcode или вообще удалить, и сгенерировать
проект без использования П-кода, как раньше;
(как вариант: возможно добавлять опцию {$define Pcode}
отдельно в каждый модуль с формой или самописным П-кодом,
но тогда надо добавить такое же определение в файл самого проекта,
чтобы был скомпилирован вызов InstallCollapse);
- в опциях проекта в секции
Linker для группы
Map file выбрать значение
Detailed;
- добавить в проект путь к директории
COLLAPSE (оттуда будут использоваться
Collapse.pas и BaseLib.pas -
при установке символа Pcode);
- скопировать в директорию проекта
файл
Pcompiler.cfg из папки
COLLAPSE\Units и
настроить его (открыть в тестовом редакторе и исправить пути). Обратите
внимание, что в ключе /M обязательно надо указать правильное имя
map-файла
проекта вместо Project1.map; если предполагается
использование отладчика, проверьте так же корректность пути
к COLLAPSE\Debuger;
- скопировать так же в директорию проекта пустые
файлы (или создать
вручную) из той же директории COLLAPSE\Units :
CollapseUses.inc, CollapseObjects.inc - они позже могут пригодиться, если
используются П-кодированные дополнительные компоненты MCK;
- изменить в компоненте
TKOLProject опцию
CallPCompiler, вписав туда
полный путь к П-компилятору (COLLAPSE\PCompiler\PCompiler.exe).
Вообще, если П-компилятор всегда будет вызываться только вручную, это
поле можно оставить пустым. Но тогда не следует забывать вызывать П-компилятор
перед запуском, если в дизайн-свойствах были сделаны изменения;
- настроить так же
ручной вызов П-компилятора в
Delphi
IDE Tools:
Tools | Configure Tools... | Add | Browse... выберите
COLLAPSE\PCompiler\PCompiler.exe и обязательно добавьте в поле макросов
$EDNAME.
Дайте новому инструменту имя, например, PCompiler, и
вы можете теперь вызывать его прямо из Delphi для
П-компиляции текущего проекта. Обратите внимание, что в момент вызова в
редакторе IDE Delphi текущим должен быть один из
исходных файлов проекта, и inc-файлы,
генерируемые MCK, не должны быть загружены (это
препятствует их модификации, точнее, Delphi не всегда
"замечает", что они изменились на диске, если они загружены в редактор).
Возможно так же настроить вызов П-компилятора с дополнительной опцией
/A (итого поле параметров будет выглядеть:
/A $EDNAME) - для полной перекомпиляции всех
модулей. Такой вызов может понадобиться при обновлении версии П-компилятора.
- При первом же применении П-компилятора к коду,
сгенерерированному в MCK, обязательно потребуется
добавить в uses
каждого модуля формы, использующего П-код, ссылку на
Collapse.
Рекомендуется использовать uses в части
implementation, а не в интерфейсной, и
добавлять например так:
{$IFDEF PCode}, Collapse
{$ENDIF};
Или так:
{$IFNDEF noPCode},
Collapse {$ENDIF};
Первый вариант следует использовать, если
все формы компилируются в П-код установкой (добавлением) символа
PCode в опции проекта, второй вариант - в случае,
если каждая форма приготавливается к использованию П-кода отдельно
(например, добавлением в начало текста модуля строк:
{$IFNDEF noPCode}
{$DEFINE PCode} {$ENDIF}
Вот теперь можно убедиться, что inc-файлы содержат
П-код, и вызвать П-компилятор. После его завершения все файлы проекта,
содержащие П-код, модифицируются и для П-кода формируется откомпилированный
ассемблерный код (он содержит только директивы данных DB, DW
и DD и начинается с
одного из байтов
$E4..$E7
вызова одной из процедур
RunPCodeN, N=0..3). Осталось запустить полученный проект на
исполнение и убедиться, что он работает так же, как и раньше. (Если не так же,
то это какая-то ошибка, пишите мне или автору зеркала, вероятна проблема с
генерацией П-кода в каком-либо из них). Если требуется запустить П-код на
отладку, добавьте в опции проекта символ
COLLAPSE_DEBUG (путь к отладчику должен быть
прописан в PCompiler.cfg в ключе
/D).
В процессе компиляции ассемблерного кода, выданного
П-компилятором, Dephi может обнаружить некоторые
ошибки.
- Например, размер идентификаторов, поддерживаемых
встроенным в Delphi компилятором ассемблера,
ограничен 32 символами. Всех такие имена процедур, переменных, полей
структур должны быть изменены в исходном коде, и процедура генерации П-кода
и П-компиляция должны быть выполнены заново.
- Если встретилась ошибка
'Undeclared identifier ...' в модулях
CollapseProcTableN.pas, и речь идет об известном вам идентификаторе,
то необходимо добавить ссылку на модуль, в котором этот идентификатор
объявлен, в файл CollapseUses.inc (в виде
,
имя_модуля).
- Если встретилась противоположная ошибка о
дублировании объявления (скорее всего вида n_<имя_процедуры>),
то слишком длинное имя процедуры было обрезано до 32 символов (так
как встроенный в Delphi ассемблер не может
работать с идентификаторами длиннее 32 символов), после чего совпало с
другим именем, первые символы которого совпадают с данным. Решение: изменить
имена процедур, вызвавшие конфликт, на более короткие.
- Если при явном отсутствии ошибок в тексте компилятор
Delphi сообщает о синтаксической ошибке (например,
Waiting for ';' but ...), то надо запустить на
этом модуле П-компилятор.
Теперь можно сравнивать размер исходного exe-файла,
без опции Pcode. Для
проектов достаточно мелких П-код не приносит выгоды, поскольку первоначально в
код программы добавляется 500-600 байт, и уже после этого код начинает
постепенно сокращаться. Эффект по уменьшению кода наступает для достаточно
больших проектов, при большом размере инициализирующих процедур (т.е. при
большом количестве MCK-компонентов на формах),
поскольку П-код все-таки в 2 с лишним раза компактнее оригинального Паскаль-кода. Еще
большего эффекта, кстати, можно ожидать в случае сжатия проекта какой-либо
программой упаковки (например, UPX). П-код не содержит
относительных смещений в себе, и может сжиматься по
крайней мере не хуже, а то и лучше, чем оригинальный машинный код.
Если в коде проекта имеются другие длинные (и очень длинные) инициализирующие
куски кода, например, в OnShow, то их тоже может иметь
смысл перекодировать вручную в П-код и подвергнуть П-компиляции. См.
соответствующий документ. Если у вас есть компонент KOL
с зеркалом MCK и вы хотите его сделать
П-кодированным, то вам понадобится так же научить его в
design-time строить П-код, аналогично тому, как это делают основные
MCK-компоненты. См. так же соответствующую инструкцию.
Дополнительная возможность
Collapse: если в файле Collapse.pas
раскомментарить строку {$DEFINE NOEXCEPTIONONEXIT}, то при возникновении
любого исключения при завершении приложения, исключение будет подавлено, и
выполнена системная процедура Halt. Если вам
действительно нужно такое поведение, желательно так же выставить переменную
AppletTerminating в значение
TRUE как только приложение решает начать процедуру завершения (возможно
не только в обработчике OnClose главной формы, но и
при любом другом способе завершения, чем раньше, тем лучше. В частности, если
установить эту переменную в true при запуске
приложения, то любое необработанное исключение немедленно завершит приложение
без каких-либо сообщений).
Примечание: да, я знаю, что это очень плохо, и лучше так никогда не делать. Но,
к сожалению, встречаются ситуации, когда причина исключения неустранима и
возникает в какой-либо используемой библиотеке или даже в системной функции, и
единственный способ побороть исключение на выходе - это просто подавить его.
(Пример: мое приложение для просмотра изображений. Оно использует чужой код для
распаковки изображений из различных форматов, который может вести себя
некорректно при наличии на входе сбойных изображений, или изображений
неподдерживаемых форматов).
Владимир Кладов, 3.12.2005, последнее изменение:
21.01.2006