C ++ Micro Services库提供了一个通用资源系统,可以将任意文件嵌入到模块的共享库中(由于使用的ZIP格式,每个资源的大小限制为2GB)。
支持以下功能:
- 将任意数据嵌入到共享或静态模块或可执行文件中;
- 数据以压缩格式(zip)嵌入,具有可配置的压缩级别;
- 资源通过模块实例访问,为每个模块提供单独的资源查找和访问;
- 资源在树层次结构中进行管理,对文件系统上的原始子父母关系进行建模;
- ModuleResource类提供了访问资源信息和遍历资源树的高级API;
- ModuleResourceStream类提供了一个STL输入流派生类,以便在第三方库中无缝地使用嵌入式资源数据。
以下约定和限制适用:
- 资源条目存储在不区分大小写的名称中。 在区分大小写的文件系统中,添加相同名称但大小写不同的资源会导致错误;
- 在运行时按名称查找资源是区分大小写的;
- CppMicroServices库将从文件末尾开始在共享库内搜索有效的zip文件。 如果模块中还嵌入了其他zip文件(例如,作为通过Windows RC编译器或使用其他技术嵌入的附加资源),它将在第一个有效的zip文件中停止并将其用作资源容器;
1 将资源嵌入到模块中(Embedding Resources in a Module)
- 通过使用可执行文件usResourceCompiler可将资源嵌入到模块的共享或静态库(或可执行文件)中。它将创建一个所有输入文件的ZIP压缩文件,并将其附加到模块文件中。
- 如果你使用CMake,请考虑使用提供的#usFunctionEmbedResources CMake宏来处理usResourceCompiler可执行文件的调用,并设置正确的文件依赖性。否则,你还需要确保链接到共享模块或可执行文件的静态模块集合也位于你的共享模块或可执行文件的usResourceCompiler调用的输入文件列表中。
- 以下是创建模块并嵌入资源数据的完整示例:
set(module_name "org_me_mymodule")
set(srcs mymodule.cpp)
usFunctionGenerateModuleInit(srcs)
usFunctionGetResourceSource(TARGET mymodule OUT srcs)
add_library(mymodule ${srcs})
target_link_libraries(mymodule CppMicroServices)
set_property(TARGET mymodule APPEND PROPERTY COMPILE_DEFINITIONS US_MODULE_NAME=${module_name})
set_property(TARGET mymodule PROPERTY US_MODULE_NAME ${module_name})
usFunctionEmbedResources(TARGET mymodule
FILES hello.txt
)
2 在运行时访问资源(Accessing Resources at Runtime)
- 每个模块通过(提供返回ModuleResource对象的方法的)Module类来实现对其嵌入资源的访问。ModuleResourceStream类提供了一个std :: istream兼容对象来访问资源内容。
- 以下示例展示了如何从每个当前加载的模块(其路径由module属性指定)检索资源:
// Get all loaded modules
std::vector<Module*> modules = ModuleRegistry::GetLoadedModules();
// Check if a module defines a "service-component" property
// and use its value to retrieve an embedded resource containing
// a component description.
for(std::size_t i = 0; i < modules.size(); ++i)
{
Module* const module = modules[i];
std::string componentPath = module->GetProperty("service-component").ToString();
if (!componentPath.empty())
{
ModuleResource componentResource = module->GetResource(componentPath);
if (!componentResource.IsValid() || componentResource.IsDir()) continue;
// Create a std::istream compatible object and parse the
// component description.
ModuleResourceStream resStream(componentResource);
parseComponentDefinition(resStream);
}
}
- 这个例子可以通过使用OSGi流行的“扩展模式”来增强,以动态地反应模块的加载和卸载。
3 运行时开销(Runtime overhead)
资源系统具有以下运行时特性:
- 在一个模块的静态初始化期间,其ZIP归档头数据(如果有的话)被解析并存储在内存中;
- 查询Module或ModuleResource对象的资源信息将不会提取嵌入的资源数据,因此此时的运行时和内存开销最小;
- 创建一个ModuleResourceStream对象将为未压缩的资源数据分配内存并使其膨胀。内存将在ModuleResourceStream对象被销毁后释放。