Регистрация объекта в статической библиотеке - PullRequest
7 голосов
/ 17 мая 2009

Я реализовал очень простую «систему плагинов» как часть статической библиотеки . Каждый «плагин» реализует поддержку определенного формата изображения, например, GIF, JPEG и т. Д. Кроме того, у меня есть Singleton (класс с именем PluginManager), который хранит список всех доступных плагинов.

Сложность в том, что я хочу отключить / включить плагины, добавляя или удаляя их исходные файлы из файла проекта. Для этого каждый плагин создает глобальную переменную (с разными именами) и регистрирует плагин в конструкторе этого класса на PluginManager.

Примерно так в формате JPEG ...

struct JPEGPlugin
{
  // constructor will register plugin
  JPEGPlugin()
  {
    PluginManager::Singleton().RegisterPlugin(this);
  }

  // plenty of other code
  ...
};

JPEGPlugin jpeg_instance;  // instantiate in global scope

Однако, хотя теоретически это работает идеально, при подключении этой статической библиотеки к другому коду для создания исполняемого файла происходит сбой. Пока этот исполняемый файл не имеет доступа к глобальным переменным плагина (например, jpeg_instance), компоновщик не видит соединения (он полностью игнорирует побочные эффекты конструктора) и не включает код в конечный исполняемый файл. Другими словами, плагин JPEG недоступен в финальном приложении.

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

Но, может быть, кто-то на SO знает, как заставить это работать?

Ответы [ 4 ]

2 голосов
/ 17 мая 2009

Я не знаю, является ли это решением для того, как вы решили эту проблему, но у нас была похожая проблема со статической регистрацией фабрики объектов, и в Visual Studio мы решили ее, объявив классы, связанные с __declspec (dllexport) это было необходимо, хотя участвующие библиотеки не были dll. Но без этого компоновщик пропустит не ссылочные классы.

Решение для реестра, с которым мы работали, немного отличалось и не затрагивало объекты, выделенные стеком. Я снял части с CPP-модуля, там же я обнаружил подход __declspec iirc.

[править] Нам также пришлось #include объявление зарегистрированного класса из некоторой части кода.

2 голосов
/ 17 мая 2009

Поскольку это статическая библиотека, вы можете подумать о том, чтобы менеджер регистрировал плагины (вместо того, чтобы плагины регистрировали себя). Файл заголовка может определять некоторый символ предварительной обработки (например, JPEG_PLUGIN), который управляет тем, регистрирует ли менеджер плагин на основе включения заголовка:

#include "JpegPlugin.h"

void PluginManager::RegisterPlugins()
{
#idef JPEG_PLUGIN
    RegisterPlugin(&jpeg_instance);
#endif
}

JpegPlugin.h не обязательно должен включать определение JpegPlugin. Это может быть что-то вроде этого:

#ifndef JPEG_PLUGIN_HEADER
#define JPEG_PLUGIN_HEADER

#if 0 // change this to 1 to use the plugin
#define JPEG_PLUGIN
#include "Jpeg_PluginCls.h"
#endif

#endif
1 голос
/ 17 мая 2009

Это продолжение ответа Харальда Шейриха .

Я провел некоторые эксперименты, и похоже, что в Release Mode в MSVC ++ 2005 (но не в режиме отладки) для компоновщика будет установлен флаг /OPT:REF, который согласно документации LINK привести к удалению любых не связанных символов из окончательного EXE-файла. И, веб-страница для __declspec(selectany), кажется, указывает, что конструкторы для глобальных объектов не рассматриваются как ссылки на объект (неправильно ИМХО, но у вас это есть). Так что я думаю, что эта проблема «уходит» для отладочных сборок - это правильно?

Итак, я думаю, что предложение Харальда об использовании __declspec(dllexport) является удобным способом пометить символ как «ссылочный», потому что он указан внутри исходного кода. Если по какой-то причине вы хотели избежать экспорта символа, я подозреваю, что вы могли бы сделать то же самое, либо используя флаг компоновщика /INCLUDE:mysymbol , либо отключив флаг /OPT:REF.

0 голосов
/ 26 октября 2016

пожалуйста:

  1. добавить статический проект lib в качестве ссылки на exe-проект
  2. установить оба параметра "зависимости библиотеки ссылок" и "Использовать зависимость библиотеки ссылок в качестве входных данных" как true.

Смотрите это: config

Если для параметра «Использовать зависимость библиотеки ссылок в качестве входных данных» задано значение «Да», система ссылок проекта в файлах .obj для .lib создается в зависимых проектах. Таким образом, все символы сохраняются.

...