我习惯使用
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 解决方案。
我找到的最佳答案是
this,但请务必阅读 动态链接库最佳实践 的部分,以了解在 glibc
中调用什么是不安全的在Linux中:
DllMain
可移植地加载库
可能被视为跨平台。虽然需要针对不同平台进行编译。 以下是 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
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
是未定义的行为。