Мой вопрос похож на эти, но, похоже, не совсем соответствует:
Как принудительно включить объектный файл в статическую библиотеку при компоновке в исполняемый файл?
Принудительный экспорт символов с MSVC
То, что у меня есть, выглядит примерно так:
struct thingy;
struct container
{
static container& instance(); // singleton
int register_thingy(thingy*);
};
struct thingy
{
virtual ~thingy() {}
virtual int id() const = 0;
};
//template trick to force registration.
template < typename Derived >
struct registered_thingy : thingy
{
registered_thingy() : my_id(my_static_id) {}
int id() const { return my_id; }
private:
int my_id;
static int my_static_id;
}
template < typename Derived >
int registered_thingy<Derived>::my_static_id =
container::instance().register_thingy(new Derived);
Теперь, в файле concrete_thingy.cpp
, у меня есть:
struct my_concrete_thingy : registered_thingy<my_concrete_thingy>
{
my_concrete_thingy() {} // registered_thingy's constructor not called otherwise
};
Конечно, вышесказанное совершенно бесполезно, но здесь абстрагируется реальное поведение.
Это прекрасно работает при использовании в приложении, которое компилируется в целом. Проблема сейчас в том, что я пока не могу использовать эту технику, в то же время ограничивая поведение, стоящее за collection
в библиотеке. Другими словами, у меня есть файл thingys.lib
, который содержит concrete_thingy.cpp
, но регистрация не происходит, когда он связан с исполняемым файлом. collection
заканчивает существовать и работает нормально, но он пустой.
Теперь это СТАТИЧЕСКАЯ библиотека, а не DLL. Это может немного изменить проблему, и методы, о которых говорится в приведенных выше ссылках, похоже, не применяются. Один из них, конечно, касается функций, и я не понимаю, как можно применить его к этим структурам C ++.
Я пытался использовать метод #pragma comment
со следующими тремя строками (по отдельности, конечно) в concrete_thingy.cpp
, ни одна из которых не работала:
#pragma comment (linker, "/export:concrete_thingy")
#pragma comment (linker, "/export:concrete_thingy::my_static_id")
#pragma comment (linker, "/export:registered_thingy<concrete_thingy>::my_static_id")
Если concrete_thingy.cpp
находится в исполняемом файле, а не в библиотеке, все работает нормально.
Итак, вот мои вопросы:
1) Можно ли сделать то, что я пытаюсь сделать? Наверное, да, но я просто не знаю как.
2) Если это возможно, как мне заставить MSVC ++ 2010 это сделать?
3) Если это возможно, как я могу сделать это портативным способом?
Короче говоря, то, что я пытаюсь сделать, было бы похоже на создание абстрактной фабрики, которая создает реализации абстракции. Он ничего не знает об этих реализациях, которые зарегистрированы с использованием глобальной хитрости инициализации. Все это должно быть в статической библиотеке, с которой может быть связано приложение, и эти реализации должны быть доступны через эту фабрику. Никто ничего не знает об этих реализациях, кроме них самих, и поэтому нормальное связывание приводит к их исчезновению и глобальным переменным их регистрации.
Это не совсем то, чем я занимаюсь, но достаточно близко.
Редактировать: ================================================== =======
Похоже, это поведение "по замыслу". MS признает, что конструирование объектов, вызывающих побочные эффекты, должно происходить независимо от того, используются они или нет, в стандарте они используют лазейку, которая позволяет им не включать единицы перевода, в которых ничего не используется: \
https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=244410&wa=wsignin1.0&siteid=210
Параметр / OPT: NOREF, по-видимому, в этом случае ничего не делает.