Как заставить включение «неиспользуемых» определений объектов в библиотеку - PullRequest
11 голосов
/ 08 декабря 2010

Мой вопрос похож на эти, но, похоже, не совсем соответствует:

Как принудительно включить объектный файл в статическую библиотеку при компоновке в исполняемый файл?

Принудительный экспорт символов с 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, по-видимому, в этом случае ничего не делает.

Ответы [ 2 ]

5 голосов
/ 08 декабря 2010

Ну, другие ответы, где хорошие попытки, но в конечном итоге бесплодны.Я собираюсь использовать трюк с переоборудованием, но остальная часть, похоже, была красной сельдью;это имеет смысл, так как рассматриваемый шаблон фактически нигде больше не используется, поэтому тот факт, что он не был явно создан, не должен иметь значения ... объявление глобального все еще происходит в модуле перевода A, у него есть побочные эффекты... Я не думаю, что стандарт позволяет оптимизировать его.

Неудачный момент, когда в стандарте не говорится, требуется ли вообще включать единицу перевода, или нет.Я думаю, что C ++ 0x что-то делает с этим, но, возможно, нет ... Во всяком случае, MS чувствует себя свободным вообще не включать модуль, и, поскольку это не так, глобальный элемент в конечном итоге не включается в исполняемый файл и, следовательнодругого дерьма не происходит.

То, что я решил сделать, и, конечно, есть много других способов, это создать переменную tag файла.Затем этот тег присваивается в функции, которая доступна в глобальном масштабе (она должна быть назначена или назначена, или ссылка оптимизирована).Затем эта функция должна вызываться из исполняемого файла.

Я решил сделать это таким образом, потому что тогда все остальное работает так же, как и всегда.В конечном итоге я не изменяю поведение, как если бы просто написал функцию регистрации, которая регистрировала типы вручную.Кроме того, я могу делать другие вещи таким образом ... Я просто должен убедиться, что все, что может попасть в эту классификацию fucktardery, имеет тег и к нему есть доступ.

Я напишу кучувспомогательные макросы, чтобы сделать это в основном безболезненно.

1 голос
/ 08 декабря 2010

Есть опция компоновщика / OPT: REF и / OPT: NOREF, доступ к которой осуществляется через компоновщик-> оптимизация-> ссылки.

...