7

我已经实现了一个非常基本的“插件系统”作为静态库的一部分。每个“插件”都实现了对特定图像格式的支持,例如 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

4 回答 4

2

由于它是一个静态库,您可以考虑让管理器注册插件(而不是插件自己注册)。头文件可以定义一些 preproc 符号(即 JPEG_PLUGIN)来控制管理器是否根据头文件的包含来注册插件:

#include "JpegPlugin.h"

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

JpegPlugin.h 不一定需要包含 JpegPlugin 的定义。它可能是这样的:

#ifndef JPEG_PLUGIN_HEADER
#define JPEG_PLUGIN_HEADER

#if 0 // 将此更改为 1 以使用插件
#define JPEG_PLUGIN
#include "Jpeg_PluginCls.h"
#万一

#万一
于 2009-05-17T02:28:02.623 回答
2

我不知道这是否是您解决此问题的方式的解决方案,但是我们在对象工厂的静态注册方面遇到了类似的问题,在 Visual Studio 中,我们通过声明与 __declspec(dllexport) 相关的类来解决它,这是必要的即使涉及的库不是 dll。但如果没有这个,链接器将省略未引用的类。

我们工作的注册表解决方案有点不同,不涉及堆栈分配的对象。我从 CPP 单元中取出零件,这也是我发现 __declspec 方法 iirc 的地方。

[编辑] 我们还必须#include从代码的某些部分声明注册类。

于 2009-05-17T02:49:52.867 回答
1

这是Harald Scheirich 的回答的后续。

我做了一些实验,似乎 MSVC++ 2005 的发布模式(但不是调试模式)将打开/OPT:REF链接器的标志,根据LINK 文档,这将导致从最终 EXE 中删除任何未引用的符号。而且,网页__declspec(selectany)似乎表明全局对象的构造函数不被视为对对象的引用(恕我直言,但你有它)。所以我的猜测是,这个问题在调试版本中“消失”了——对吗?

因此,我认为 Harald 的使用建议__declspec(dllexport)是将符号标记为“引用”的便捷方式,因为它是在源代码中指定的。如果出于某种原因您想避免导出符号,我怀疑您可以通过使用/INCLUDE:mysymbol链接器标志或关闭/OPT:REF标志来完成同样的事情。

于 2009-05-17T10:15:57.023 回答
0

请:

  1. 添加静态库项目作为对 exe 项目的引用
  2. 将“链接库依赖项”和“使用链接库依赖项作为输入”都设置为 true。

看到这个: 配置

当“使用链接库依赖项作为输入”设置为“是”时,项目系统在 .obj 文件中为依赖项目生成的 .lib 链接。所以所有的符号都被保留了。

于 2016-10-26T16:40:26.547 回答