赞
踩
简单来讲这个模块是干什么用的:大型系统一般不是由单个可执行程序代码组成的,而是夹杂了很多动态库,linux下的就是so文件,如何把这些so里面的类导出来,可执行程序如何动态的加载他们,比如一共写了6个so,只想动态的加载其中3个,运行过程中甚至想卸载掉其中的几个用以释放相关的资源,这个模块就是干这个工作的。
要想导出,必须得首先注册,来看怎么注册的,他提供了一个宏
#define CLASS_LOADER_REGISTER_CLASS(Derived, Base) \
CLASS_LOADER_REGISTER_CLASS_INTERNAL_1(Derived, Base, __COUNTER__)
这个宏接收两个参数,即两个父子类的类型,看下这个宏的具体实现
#define CLASS_LOADER_REGISTER_CLASS_INTERNAL(Derived, Base, UniqueID) \
namespace { \
struct ProxyType##UniqueID { \
ProxyType##UniqueID() { \
apollo::cyber::class_loader::utility::RegisterClass<Derived, Base>( \
#Derived, #Base); \
} \
}; \
static ProxyType##UniqueID g_register_class_##UniqueID; \
}
#define CLASS_LOADER_REGISTER_CLASS_INTERNAL_1(Derived, Base, UniqueID) \
CLASS_LOADER_REGISTER_CLASS_INTERNAL(Derived, Base, UniqueID)
// register class macro
#define CLASS_LOADER_REGISTER_CLASS(Derived, Base) \
CLASS_LOADER_REGISTER_CLASS_INTERNAL_1(Derived, Base, __COUNTER__)
#endif // CYBER_CLASS_LOADER_CLASS_LOADER_REGISTER_MACRO_H_
注意:__COUNTER__是编译器内置变量,编译器每次遇见会自动+1。
代码解释:声明一个类ProxyType132132,后面数字不会重复,依次递增,保证唯一,并静态实例化该类,作用是编译期间就会实例化,也就意味着他的构造函数早早的就被调用了(so加载期间),核心句就是调用命名空间utility下的模板函数RegisterClass对父子类型进行注册。这个注册是怎么理解的?说白了就是实例化一个模板类ClassFactory,这个ClassFactory其实就是so和可执行程序的桥梁,两边都会使用到,这个ClassFactory模板类实例里面包含了将来想实例化的父子类的信息。
ClassLoaderManager里面有个模板函数CreateClassObj,举例说明:
std::shared_ptr<ComponentBase> base =
class_loader_manager_.CreateClassObj<ComponentBase>(class_name);
Cyber RT模块加载流程简介
如果想深入理解还是推荐阅读源代码。
这么好的代码,能不能把他独立出来,将来自己写个项目的时候集成该功能,那不是美滋滋,说干就干,一开始我想着反正有C++源代码了,写个CMakelist.txt吧,后来想想直接用bazel不是更好,顺便学习了一下从0构建bazel。
免积分下载
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。