gpt4 book ai didi

c++ - 如何可移植地加载动态库并运行其初始化代码?

转载 作者:行者123 更新时间:2023-12-02 02:42:46 26 4
gpt4 key购买 nike

使用 GCC 并在 Linux 上,或者可能在任何有 glibc 可用的地方,我可以使用 dl_open() 库函数动态加载共享对象/DLL:

void *dlopen(const char *filename, int flags);

...并且这还运行所有以 ELF 格式标记为 .init 的函数;或者在 C/C++ 代码中,用 __attribute__((constructor)) 标记:

How exactly does __attribute__((constructor)) work?

我的问题是:我怎样才能以更便携的方式做同样的事情?我对向其他编译器和其他平台的可移植性感兴趣。

注意:我标记了这个 C++,因为这就是我正在使用的,但显然 C-ish 解决方案是可以接受的 - 因为我上面描述的是 C-ish 解决方案。

最佳答案

加载库时初始化

编辑:再次回顾问题,发现我没有回答初始化部分。

我找到的最佳答案是 this仍然依赖于平台的一种。如果有更好的会更新。

针对特定平台

在 Windows 中是 DllMain但请务必阅读 Dynamic link library best practice 的部分查看 DllMain 中调用什么是不安全的

在 Linux 中:

__attribute__ ((constructor))
__attribute__ ((destructor))

可移植地加载库

由于 Boost 可在许多平台上使用,其 _dll module可能被认为是跨平台的。虽然需要针对不同平台进行编译。

以下是basic example通过在插件中导入单个变量来获取 Boost.Dll。

标题

#include <boost/config.hpp>
#include <string>

class BOOST_SYMBOL_VISIBLE my_plugin_api {
public:
virtual std::string name() const = 0;
virtual float calculate(float x, float y) = 0;

virtual ~my_plugin_api() {}
};

来源

#include <boost/config.hpp> // for BOOST_SYMBOL_EXPORT
#include "../tutorial_common/my_plugin_api.hpp"

namespace my_namespace {

class my_plugin_sum : public my_plugin_api {
public:
my_plugin_sum() {
std::cout << "Constructing my_plugin_sum" << std::endl;
}

std::string name() const {
return "sum";
}

float calculate(float x, float y) {
return x + y;
}

~my_plugin_sum() {
std::cout << "Destructing my_plugin_sum ;o)" << std::endl;
}
};

// Exporting `my_namespace::plugin` variable with alias name `plugin`
// (Has the same effect as `BOOST_DLL_ALIAS(my_namespace::plugin, plugin)`)
extern "C" BOOST_SYMBOL_EXPORT my_plugin_sum plugin;
my_plugin_sum plugin;

} // namespace my_namespace

用法:注意append_decorations是寻求特定于平台的命名约定的方法。

例如:Linux 上的 libplugin.so 或 Windows 上的plugin.dll。

#include <boost/dll/import.hpp> // for import_alias
#include <iostream>
#include "../tutorial_common/my_plugin_api.hpp"

namespace dll = boost::dll;

int main(int argc, char* argv[]) {

boost::dll::fs::path lib_path(argv[1]); // argv[1] contains path to directory with our plugin library
boost::shared_ptr<my_plugin_api> plugin; // variable to hold a pointer to plugin variable
std::cout << "Loading the plugin" << std::endl;

plugin = dll::import<my_plugin_api>( // type of imported symbol is located between `<` and `>`
lib_path / "my_plugin_sum", // path to the library and library name
"plugin", // name of the symbol to import
dll::load_mode::append_decorations // makes `libmy_plugin_sum.so` or `my_plugin_sum.dll` from `my_plugin_sum`
);

std::cout << "plugin->calculate(1.5, 1.5) call: " << plugin->calculate(1.5, 1.5) << std::endl;
}


要从插件创建对象,这里是 factory example 。首先,制作一个工厂方法返回boost::shared_ptr<my_plugin_aggregator> .

#include <boost/dll/alias.hpp> // for BOOST_DLL_ALIAS   
#include "../tutorial_common/my_plugin_api.hpp"

namespace my_namespace {

class my_plugin_aggregator : public my_plugin_api {
float aggr_;
my_plugin_aggregator() : aggr_(0) {}

public:
std::string name() const {
return "aggregator";
}

float calculate(float x, float y) {
aggr_ += x + y;
return aggr_;
}

// Factory method
static boost::shared_ptr<my_plugin_aggregator> create() {
return boost::shared_ptr<my_plugin_aggregator>(
new my_plugin_aggregator()
);
}
};


BOOST_DLL_ALIAS(
my_namespace::my_plugin_aggregator::create, // <-- this function is exported with...
create_plugin // <-- ...this alias name
)

} // namespace my_namespace

加载创建者方法并创建对象。

#include <boost/dll/import.hpp> // for import_alias
#include <boost/function.hpp>
#include <iostream>
#include "../tutorial_common/my_plugin_api.hpp"

namespace dll = boost::dll;

int main(int argc, char* argv[]) {

boost::dll::fs::path shared_library_path(argv[1]); // argv[1] contains path to directory with our plugin library
shared_library_path /= "my_plugin_aggregator";
typedef boost::shared_ptr<my_plugin_api> (pluginapi_create_t)();
boost::function<pluginapi_create_t> creator;

creator = boost::dll::import_alias<pluginapi_create_t>( // type of imported symbol must be explicitly specified
shared_library_path, // path to library
"create_plugin", // symbol to import
dll::load_mode::append_decorations // do append extensions and prefixes
);

boost::shared_ptr<my_plugin_api> plugin = creator();
std::cout << "plugin->calculate(1.5, 1.5) call: " << plugin->calculate(1.5, 1.5) << std::endl;
std::cout << "plugin->calculate(1.5, 1.5) second call: " << plugin->calculate(1.5, 1.5) << std::endl;
std::cout << "Plugin Name: " << plugin->name() << std::endl;
}

注意:当creator时被破坏,动态库也被卸载。取消引用 plugin库卸载后是未定义的行为

关于c++ - 如何可移植地加载动态库并运行其初始化代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63297022/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com