#define FUSE_REGISTER_MODULE(name,factory) \
int name##_initialize(void) { .......; return 0; } \
__declspec(dllexport) int name##_init = name##_initialize();
Правда, линкер может повыбрасывать якобы неиспользующиеся переменные вместе с функциями.
Чтобы этого не было, переменная объявлена экспортируемой.
Поскольку в виндах можно экспортировать что угодно в любом модуле — хоть dll, хоть exe — должно прокатить.
Перекуём баги на фичи!
Re[2]: Аналог __attribute__((constructor)) в MSVC?
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Cyberax, Вы писали:
К><>
К>Ну, можно прибегнуть к такому фокусу К>
К>#define FUSE_REGISTER_MODULE(name,factory) \
К> int name##_initialize(void) { .......; return 0; } \
К> __declspec(dllexport) int name##_init = name##_initialize();
К>
К>Правда, линкер может повыбрасывать якобы неиспользующиеся переменные вместе с функциями. К>Чтобы этого не было, переменная объявлена экспортируемой. К>Поскольку в виндах можно экспортировать что угодно в любом модуле — хоть dll, хоть exe — должно прокатить.
MSVC в С не поддерживает динамическую инициализацию глобальных переменных...
Не подскажете аналог GCCшного "__attribute__((constructor))" в MSVC для чистого С?
Нету. В gcc это — расширение языка C. В стандартом C ( не CPP ) вроде нету конструкторов, деструкторов и вызовов функций для глобальных объектов . Можно только константными значениями инициализировать.
Или как вариант способ построить таблицу <имя>-<фабричная_функция>.
в main(), DllMain(), WinMain() или что там еще исполняется:
Это честный метод для стандартного С. Макрос для произвольного места кода чтобы что-то регистрировал, насколько я знаю, сделать нельзя. Можно сделать макрос который можно будет использовать строго в одном .c файле, но это ничем не будет отличаться от вышеуказанного кода.
Re[2]: Аналог __attribute__((constructor)) в MSVC?
Здравствуйте, EyeOfHell, Вы писали:
EOH>Нету. В gcc это — расширение языка C. В стандартом C ( не CPP ) вроде нету конструкторов, деструкторов и вызовов функций для глобальных объектов . Можно только константными значениями инициализировать.
А есть ли аналогичные расширения Microsoft для MSVC?
Sapienti sat!
Re[3]: Аналог __attribute__((constructor)) в MSVC?
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, EyeOfHell, Вы писали:
EOH>>Нету. В gcc это — расширение языка C. В стандартом C ( не CPP ) вроде нету конструкторов, деструкторов и вызовов функций для глобальных объектов . Можно только константными значениями инициализировать. C>А есть ли аналогичные расширения Microsoft для MSVC?
самое простое обявить нужные функции как dllexport и проанализировать таблицу экспорта dll/exe
Здравствуйте, Cyberax, Вы писали:
C>Не подскажете аналог GCCшного "__attribute__((constructor))" в MSVC для чистого С? Или как вариант способ построить таблицу <имя>-<фабричная_функция>.
Есть ещё вариант с препроцессингом.
В исходном тексте ты разбрасываешь (по месту) объявления вида
Здравствуйте, Кодт, Вы писали:
К>При известной ловкости рук, можно даже на бат-файле сделать. Но конечно, perl или хотя бы grep+awk здесь будут сподручнее.
Не пойдёт... FUSE_REGISTER_MODULE делается из сторонних библиотек, которые собираются своими системами.
Видимо, действительно проще всего проанализировать таблицу экспорта.
Sapienti sat!
Re[3]: Аналог __attribute__((constructor)) в MSVC?
Здравствуйте, Cyberax, Вы писали:
К>>При известной ловкости рук, можно даже на бат-файле сделать. Но конечно, perl или хотя бы grep+awk здесь будут сподручнее. C>Не пойдёт... FUSE_REGISTER_MODULE делается из сторонних библиотек, которые собираются своими системами.
... а ты хочешь подсунуть им свой макрос? Т.е. подменить их зависимости?
Но если это в твоих силах, то почему бы тебе их исходники не пропарсить?
C>Видимо, действительно проще всего проанализировать таблицу экспорта.
Таблицу экспорта у объектников? А что, хорошая мысль. Сделать то же, что и __attribute__((constructor)) — всё равно линкер должен собрать ссылки на конструкторы, а так это сделаешь ты за линкера.
Только лучше делать сигнатуру префиксом имени, а не суффиксом — парсить будет чуть быстрее
Здравствуйте, Кодт, Вы писали:
К>... а ты хочешь подсунуть им свой макрос? Т.е. подменить их зависимости?
Да.
К>Но если это в твоих силах, то почему бы тебе их исходники не пропарсить?
Я портирую OpenSource-библиотеку FUSE (Filesystem in User SpacE). Её уже использует куча проектов на Линуксе. Хотелось бы, чтобы на Windows их можно было перенести простой перекомпиляцией с моим заголовочником и библиотекой. Т.е. хочется source level compatibility — с остальным кодом оно, вроде бы, вполне получается.
По крайней мере, "Hello world" из примеров к FUSE у меня уже работает на Windows.
К>Таблицу экспорта у объектников? А что, хорошая мысль. Сделать то же, что и __attribute__((constructor)) — всё равно линкер должен собрать ссылки на конструкторы, а так это сделаешь ты за линкера.
Я прямо в рантайме хочу это сделать
К>Только лучше делать сигнатуру префиксом имени, а не суффиксом — парсить будет чуть быстрее К>
Здравствуйте, Cyberax, Вы писали:
C>Привет всем!
C>Не подскажете аналог GCCшного "__attribute__((constructor))" в MSVC для чистого С? Или как вариант способ построить таблицу <имя>-<фабричная_функция>.
C>Я портирую FUSE на Windows и нужно вот такой макрос перенести: C>
Здравствуйте, alexeiz, Вы писали:
A>Не совсем понял, что должен делать этот attribute. Вызывать эту функцию в crt init что-ли? Если так, то посмотри, может тебе подойдет вот это: http://www.rsdn.ru/Forum/message/1972258.flat.aspx
Здравствуйте, Cyberax, Вы писали:
C>Не подскажете аналог GCCшного "__attribute__((constructor))" в MSVC для чистого С? Или как вариант способ построить таблицу <имя>-<фабричная_функция>.
Может подойдет способ, который используется в ATL для создания object map (OBJECT_ENTRY_AUTO). Там вначале объявляются две переменных-ограничителя, каждый в своем сегменте.
уже предлагал Кодт. В качестве "утилиты, которая собирает все вхождения и рожает файл" используется майкрософтовский линкер который собирает и упорядочивает секции данных в исполняемом модуле. В этом смысле оно будет работать с длл.
Сам инициализирующий цикл (как и register_all у Кодта) надо вызывать ручками, вставив его, например, в DllMain (так делает ATL). IMHO для портирования это вполне приемлемо, поскольку DllMain всё равно придется реализовывать.
Re[4]: Аналог __attribute__((constructor)) в MSVC?
Здравствуйте, lazyden, Вы писали:
C>>А как оно с DLLями работает? L>Ээ, не совсем понял
Что будет, если регистрации будут разбросаны по нескольким DLL?
L>Фактически, такой способ
уже предлагал Кодт. В качестве "утилиты, которая собирает все вхождения и рожает файл" используется майкрософтовский линкер который собирает и упорядочивает секции данных в исполняемом модуле. В этом смысле оно будет работать с длл.
Ок, буду смотреть.
Здравствуйте, Cyberax, Вы писали:
C>Не подскажете аналог GCCшного "__attribute__((constructor))" в MSVC для чистого С? Или как вариант способ построить таблицу <имя>-<фабричная_функция>.
Ран-тайм MSVC использует ряд магических секций в исполняемом файле для своих целей. В частности есть секция, которая содержит указатели на функции, которые инициализируют глобальные объекты и выполняют динамическую инициализацию глобальных переменных. Точнее это не одна секция, а множество секций. Секции от ".CRT$XIA" до .CRT$XIZ" (по алфавиту, исключая границы) инициализируют С ран-тайм, секции от ".CRT$XA" до .CRT$XCZ" (по алфавиту, исключая границы) инициализируют С++ глобальные объекты и динамически инициализируемые глобальные объекты.
Правда в выполняемом файле все эти секции в итоге объединяются в секцию ".data":
#pragma comment(linker, "/merge:.CRT=.data")
Но это уже не важно, главное ран-тайм может найти и выполнить все функции, которые изначально содержались в этих секциях. Ищет он их до-тупого просто: размещает "граничные" переменные в секциях ".CRT$XIA"/".CRT$XIZ" и ".CRT$XCA"/".CRT$XCZ", а потом находит все, что расположено между ними:
Ну это, так, лирическое отступление. Собственно тебе нужен следующий макрос:
#define CTOR(X) \
int X(); \
__declspec(dllexport) \
__declspec(allocate(".CRT$XCU")) \
int(*my_ctors_##X)() = &X; \
int X() \
/**/
__declspec(allocate(".CRT$XCU")) размещает указатель на функцию в сегменте функций инициализации.
__declspec(dllexport) подавляет оптимизации линкера в релиз-сборке.
Вот полный пример:
#include <stdio.h>
#pragma section(".CRT$XCU")
#define CTOR(X) \
int X(); \
__declspec(dllexport) \
__declspec(allocate(".CRT$XCU")) \
int(*my_ctors_##X)() = &X; \
int X() \
/**/int volatile x = 0;
CTOR(ctor1)
{
x += 1;
return 0;
}
CTOR(ctor2)
{
x += 10;
return 0;
}
int main()
{
printf("%d\n", x);
}
Метод это, в принципе, полу-документированный, но положиться на него можно. Так как уже слишком много людей всё это расхачило и используют в своём коде. Например, в boost.thread используется аналогичный приём дабы получать нотификации о создании/завершении потоков: [Trick] DllMain нотификации без DLL