简体   繁体   English

静态编译和链接时保持共享库插件系统的结构

[英]Keeping the structure of a shared libraries plug-in system when compiling statically and linking

For the C++ library I am currently developing I have seen the advantages of a plug-in system based on shared libraries. 对于我目前正在开发的C ++库,我已经看到了基于共享库的插件系统的优点。 A feature will become available to the user of the library just if one of the shared libraries that are in a directory scanned at initialization time is offering that. 即使在初始化时扫描的目录中的共享库之一提供了该功能,库用户也可以使用该功能。

Using dlopen, the shared libraries will be searched for two symbols: one function that returns the string that names the feature they implement, and a create function that instantiates the class and returns a pointer to the basse class. 使用dlopen,将在共享库中搜索两个符号:一个函数返回名称为实现的功能的字符串,而create函数实例化该类并返回指向basse类的指针。 Something like this: 像这样:

In Library A 在图书馆A

#include "Instance.hpp"
extern "C" const char* type() {
  return "InstanceA";
}
//... class InstanceA definition, inherits from Instance
extern "C" Instance* create() {
    return new InstanceA();
}

The Core library will scan the plug-ins directory and keep a map string->pointerToCreateFunction in order to create new instances. Core库将扫描插件目录并保留映射字符串-> pointerToCreateFunction以便创建新实例。

This is really handy, and a pretty standard thing to do. 这真的很方便,并且是很标准的事情。 If the user code tries to instantiate an InstanceX but no shared library implement that type, an error will be given, everything will work perfectly. 如果用户代码尝试实例化InstanceX,但没有共享库实现该类型,则将给出错误,一切将正常进行。

But this framework will be used also for iOs development, and the App Store doesn't allow loading 3rd party shared objects. 但是,此框架也将用于iOs开发,并且App Store不允许加载第三方共享对象。 I would like to keep this modular plug-in structure even when loading a self contained version of the library that links statically the plugins. 即使加载静态链接插件的自包含版本的库时,我也希望保持这种模块化插件结构。 Note that at project management level this would be as easy as defining a variable in CMake that creates static versions of the plugins and links them statically. 请注意,在项目管理级别,这就像在CMake中定义一个变量那样简单,该变量创建插件的静态版本并进行静态链接。 This would also exclude the dynamic loading part of the code. 这也将排除代码的动态加载部分。

What I am missing is how to invert the mechanism: while for shared objects the core library will leverage on the file system to learn about the possible type of instances that can be used, I don't know how to "register" them without changing big part of the code, and without going in the static initialization fiasco. 我所缺少的是如何反转该机制:虽然对于共享库,核心库将利用文件系统来了解可以使用的实例的可能类型,但我不知道如何在不进行更改的情况下“注册”它们很大一部分代码,而无需进行静态初始化。 Looks like the only way to have that is subsituting the code that scans the types and the create function by including all the possible headers and having a big switch like 看起来唯一的方法就是通过包含所有可能的标头并进行类似的大开关来替换扫描类型和create函数的代码

Instance* theInstance;
if (instanceRequired == "instanceA") 
  theInstance = new InstanceA();
etc etc...

Do you have any thought on a way to avoid including all the headers and having to change the code in Core each time a new instance is added? 您是否有办法避免每次添加新实例时都包含所有标头并且不必在Core中更改代码?

I do such things through those pesky static objects that call register in ctor. 我通过调用ctor中的register的讨厌的静态对象来执行此类操作。

The ordering problem is dodged by making the map itself a local static, so getting constructed on the first client call, wherever it comes from. 通过使地图本身成为本地静态变量来规避排序问题,因此无论它来自何处,都可以在第一个客户端调用上进行构造。 (Threading and similar issues are dodged by restricting thread launch to until-main time, and by that time all important things are forced.) (通过将线程启动限制在主时间之前,然后在此之前,所有重要的事情都被强制执行,从而规避了线程和类似问题。)


class RegMap;  // the registry
RegMap& GetRegistry(); // the singleton access function; you can make a separate const/nonconst version or provide another wrapper for registering

//    implementation in core.cpp:
RegMap& GetRegistry()
{ 
    static RegMap m;
    return m;
}

//in client ctor:
GetRegistry().Register( key, func);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM