Регистрация объектов в статической библиотеке

StackOverflow https://stackoverflow.com/questions/873731

  •  22-08-2019
  •  | 
  •  

Вопрос

Я реализовал очень простую «систему плагинов» как часть статическая библиотека.Каждый «плагин» реализует поддержку определенного формата изображения, например.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 знает, как заставить это работать?

Это было полезно?

Решение

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

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

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

Другие советы

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

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

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

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

Пожалуйста:

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

Видеть это:config

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top