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

问题描述 投票:0回答:1

我习惯使用

dl_open()
库函数动态加载共享对象/DLL:

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

...并且这还运行 ELF 格式中标有

.init
的所有函数;或者在 C/C++ 代码中,标有
__attribute__((constructor))
:

__attribute__((constructor)) 到底是如何工作的?

但是 - 我只能确定这可以在 GCC 和 GNU/Linux 上运行(也许在任何可用的地方)。

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

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

c++ dll shared-libraries portability
1个回答
5
投票

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

我找到的最佳答案是

this

,它仍然依赖于平台。如果有更好的会更新。 针对特定平台

在 Windows 中是

DllMain

,但请务必阅读 动态链接库最佳实践 的部分,以了解在 glibc

 中调用什么是不安全的
在Linux中:

DllMain

可移植地加载库

由于 Boost 可在许多平台上使用,因此其

_dll 模块

可能被视为跨平台。虽然需要针对不同平台进行编译。 以下是 Boost.Dll 的

基本示例

,通过在插件中导入单个变量来实现。 标题

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

来源

#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() {} };

用法:请注意,
append_decorations

是寻求平台特定命名约定的方法。 例如:Linux 上的 libplugin.so 或 Windows 上的plugin.dll。

#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

要从插件创建对象,这里是
工厂示例

。 首先,创建一个工厂方法返回#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; }

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
未定义的行为

© www.soinside.com 2019 - 2024. All rights reserved.