Эдуард Султанов
ed@it.nsc.ru
Ровно такие же проблемы были и у меня. Результат похож, но другой компилятор - другие заморочки. Если у Вас Watcom и Вам неинтересны причины, то найдете в конце примеры makefile и plugin.lnk. Если у Вас другой компилятор - посмотрите все вплоть до конкретной реализации, может Вам это поможет.
Конкретнее:
Залог успешного похудения вашего плагина состоит в контроле того что используете вы сами, а что ваш компилятор:
Желательно использовать Win API и не
пользовать без разбора библиотечные функции
типа printf и a2i. Как правило все
функции семейства используют одну виртуальную и
соответственно донельзя универсальную. Можно
привести много причин вредности использовании,
но нас интересует одна: размер. Можете мне не
верить и попробовать заменить ваш printf на
несколько strcat или еще лучше (но не на
много) вручную сбить строку. Хитростей тут нет.
Это не зависит от компилятора. Просто надо
немного думать :-) В конце концов пару
простеньких функций сделать несложно.
Да, любой современный компилятор в обьектнике выдает больше чем вы написали в исходнике. Во-первых startup - инициализация переменных, используемых библиотеками, инициализация памяти и еще много чего. Как правило ненужного. Во-вторых проверка стека. Все они будут видны если вы дизассемблируете обьектный файл. И вообще иногда бывает интересно посмотреть на результат работы компилятора.
Я вообще-то приверженец радикального подхода: никаких библиотек. Но это совсем необязательно. Если включить у линкера оптимизацию, то пользовать библиотеки вполне возможно. Но надо помнить главное: используя одну библиотечную функцию вы можете подлинковать половину библиотеки, только потому что используемая функция их все пользует. Естественно это не касается стандартных динамических библиотек.
Если скомпилировать плагин,
например так: "wpp386 -bd -d0 -mf Blocks.cpp".
Потом получившийся файл отдать на растерзание
дизассемблеру: "wdis -a Blocks.obj > Blocks.asm",
получиться примерно следующее:
---------------- 'Block.asm' ------------------
.387
.386p
.model flat
PUBLIC `_SetStartupInfo@4`
PUBLIC `_OpenPlugin@8`
PUBLIC `_GetPluginInfo@4`
; Это,понятно, то что мы экспортируем в Far.
; К стати, полезно видеть как это выглядит. Об этом чуть ниже.
PUBLIC `W?GetMsg$n(i)pna`
; "Наша" собственная функция. Позаимствовал у ER :-)
EXTRN __CHK:BYTE
; Вот !!! Проверка стека вначале функции.
EXTRN memset_:BYTE
; Библиотечная функция
EXTRN `__imp__RegisterClipboardFormatA@4`:BYTE
; Импорт. Из DLL-ки. Об этом чуть ниже
EXTRN __DLLstart_:BYTE
; Вот !!! Так называемый startup.
---------------- !'Block.asm' ------------------
Чтобы не смотреть беспомощно на то
что вытворяет линкер с вашим обьектником, к стати
обычно не большим, нужно взять все под контроль.
Лично я не стал цацкатся и оглядываться на
копирайты и просто взял рекомендуемую для Win32 DLL
библиотеку CLIB3R.lib и распотрошил. Достал
оттуда DLLStart и функции mem* и str*.
Оставил от всего DLLStart только
mov eax,00000001H
ret 0000000cH
ну и естественно немного
подправленный копирайт :-) Слинковал я все
это в библиотеку mindll.lib (входит в поставку энциклопедии).
Получилось 5.6K. Я ничего не сказал про __CHK,
потому что отключил проверку стека. Но, если Вам
это не по душе, можете включить в библиотеку и ее.
Только лучше,сначала, маленько прохудить. Лично я
не нашел в ней ничего полезного.
Теперь о подключаемых DLL. Каждый
компилятор имеет вариант своей статической
библиотеки в виде DLL. Для такой динамической
линковки есть свой lib-файл. Так что если вы
экспериментируете с библиотеками и Вам удалось
наконец найти библиотеку с которой dll-ка плагина
не ужасающе громадна - посмотрите на вашу dll-ку
QuickViewer'ом - что ему надо для работы. Если это что-то
помимо user32.dll, kernel32.dll, advapi32.dll
то ваш плагин, скорее всего, будет работать
только у пользователей такого же компилятора.
Так что лучше обрубить линкеру крылья и все
библиотеки прописывать самому. Так вернее.
;---------------- 'makefile' ------------------
# Это собственно рабочий кусок.
#Я привык их делать сам, а не из IDE - так понятнее.
Blocks.dll : Blocks.obj
wlink file Blocks.obj @plugin >err.log
# ну тут наверно все понятно файл plugin.lnk будет чуть позже.
Blocks.obj : Blocks.cpp Blocks.hpp
wpp386 -3r -bd -d0 -mf -s Blocks.cpp
# ключи:
# -3r оптимизация под 386 и передача параметров через регистр.
# -bd - для DLL.
# -d0 - без информации для дебагера.
# -mf - Модель памяти flat.
# -s - отключить проверку стека.
---------------- !'makefile' ------------------
;---------------- 'plugin.lnk' ------------------
FORMAT
WINDOWS NT DLL
# Это формат выходного файла
OPTION
NODEFAULTLIB,
NOSTDCALL
# Первое - чтобы линкер не подключил что не надо
# Второе - чтобы экспортные функции экспортировались "как есть"
# к стати вот как они декларируются:
# extern "C"
# {
# void WINAPI _export SetStartupInfo(struct PluginStartupInfo *Info);
# HANDLE WINAPI _export OpenPlugin(int OpenFrom,int Item);
# void WINAPI _export GetPluginInfo(struct PluginInfo *Info);
# };
# обратите внимание на ключевое слово "_export"
LIBRARY
mindll.lib,
USER32.LIB,
KERNEL32.LIB,
ADVAPI32.LIB
# Здесь перечисленные сами библиотеки.
# Первое описано выше
# Со второй по четвертую - соответствуют стандартным DLL-кам.
RUNTIME CONSOLE
# Особо ни на что не влияет.
---------------- !'plugin.lnk' ------------------
Вот с этим всем из 4K С++ файла
получаем 4K dll. Это конечно не показатель, но все же :-)
18.10.1999