CppMicroServices 样例编译与 Bundle 机制笔记

发布时间:2026/11/4 19:36:40

CppMicroServices 样例编译与 Bundle 机制笔记 CppMicroServices 样例编译与 Bundle 机制笔记整理日期2026-07-23工程路径D:/CppMicroServices分支 development构建目录D:/CppMicroServices/buildVS 生成器Debug1. 工程自带的样例程序样例默认不编译由 CMake 开关US_BUILD_EXAMPLES控制默认 OFF定义在顶层CMakeLists.txt:259。1.1 入门示例 —doc/src/examples/getting_started/目标说明ServiceTime定义时钟服务接口的纯接口库不是 bundle无嵌入资源ServiceTime_SystemClock服务实现 bundleServiceTime_Consumer服务消费者 bundleGettingStarted.exe启动 Framework 并安装命令行传入的 bundle1.2 教程示例OSGi 经典字典教程—doc/src/tutorial/配套文档Example1.rst~Example7.rstBundle说明eventlistener服务事件监听dictionaryservice/frenchdictionary字典服务及第二个实现dictionaryclient/ 2 / 3三种服务消费方式直接查询 / 监听器 / ServiceTrackerspellcheckservice/spellcheckclient组合多个服务的拼写检查usTutorialDriver.exe交互式驱动命令行动态 start/stop 各 bundle2. 编译样例cdD:/CppMicroServices/build cmake-DUS_BUILD_EXAMPLESON.cmake--build.--configDebug--parallel4产物全部输出到build/bin/Debug/可执行usTutorialDriver.exe、GettingStarted.exe教程 bundle DLLeventlistener、dictionaryservice、frenchdictionary、dictionaryclient/2/3、spellcheckservice、spellcheckclient入门 bundle DLLServiceTimed、ServiceTime_SystemClockd、ServiceTime_Consumerd3. 运行验证3.1 usTutorialDriver.exe支持的命令h帮助、start id|name、stop id|name、status、shutdown。注意坑驱动按调试后缀找eventlistenerd.dll但教程 bundle 编译出来不带d后缀。解决在bin/Debug下复制一份带后缀的副本fornineventlistener dictionaryservice frenchdictionary dictionaryclient\dictionaryclient2 dictionaryclient3 spellcheckservice spellcheckclient;docp-n$n.dll${n}d.dlldone验证结果框架启动后正确安装全部 8 个 bundlestatus显示 INSTALLED依次start eventlistener→start dictionaryservice→start dictionaryclient后Starting to listen for service events. Ex1: Service of type IDictionaryService registered. Enter word:服务注册、事件监听、服务查询链路全部正常。3.2 GettingStarted.exe./GettingStarted.exe ServiceTime_SystemClockd.dll ServiceTime_Consumerd.dll# 输出: Elapsed: 1784713689727ms注意ServiceTimed.dll是纯接口库不是 bundle传给它会报Could not init zip archive for bundle at ...只传两个真正的 bundle 即可。4. manifest.json 的嵌入机制manifest.json及其他 bundle 资源会被嵌入到 DLL 文件本身CMake 的usFunctionEmbedResources(TARGET ... FILES manifest.json)调用资源编译器usResourceCompiler3资源编译器把资源文件打成一个zip 压缩包链接完成后POST_BUILDzip 直接追加到 DLL 文件末尾构建日志中可见Appending zip file .../res_0.zip to Tutorial-eventlistener为什么可行PE/ELF/Mach-O 加载器只按文件头部结构解析忽略尾部多余数据而 zip 的目录索引在文件末尾、从后往前解析——同一文件既是合法 DLL 又是合法 zip。静态构建时没有独立 DLL用usFunctionEmbedResources的ZIP_ARCHIVES参数把各静态bundle 的资源 zip 合并进最终可执行文件。5. 从 DLL 中解压嵌入资源DLL 本身就是合法 zip任何 zip 工具可直接解压# 查看内容unzip-leventlistener.dll# 80 eventlistener/manifest.json# 解压unzip-oeventlistener.dll-d输出目录警告98304 extra bytes at beginning or within zipfile属正常——这些多余字节是 DLL 的 PE 代码部分unzip 自动跳过其他工具7z x xxx.dll、Pythonzipfile.ZipFile(xxx.dll).extractall(...)、改名.zip后用图形工具打开资源带 bundle 名前缀目录如eventlistener/对应运行时BundleResourceAPI 的路径根解压出的文件数取决于该 bundle 嵌入的资源数。eventlistener 只嵌入了 manifest故只有 1 个文件{bundle.symbolic_name:eventlistener,bundle.activator:true}文件布局与切割eventlistener.dll ├── [0 ~ 98303] PE 格式 DLL 本体机器码unzip 跳过 └── [98304 ~ 末尾] zip 数据资源unzip 解压PE 部分不是压缩数据无法被解压如需单独切出纯 DLLhead-c98304eventlistener.dlleventlistener_pure.dll切割点因 DLL 而异可用 Python 精确获取importzipfile zzipfile.ZipFile(xxx.dll)print(z.infolist()[0].header_offset)# PE 部分长度一般无需切割——尾部 zip 数据不影响 DLL 的加载和执行。6. 可执行文件格式速查缩写全称中文平台PEPortable Executable可移植可执行格式Windows.exe/.dll/.sysELFExecutable and Linkable Format可执行与可链接格式Linux/BSD/Android可执行、.so、.oMach-OMach ObjectMach 对象格式macOS/iOS可执行、.dylibPE 由 COFF 演化而来也称 PE/COFF“Portable” 指跨 CPU 架构不是跨操作系统ELF 一个格式统一三种用途目标文件、可执行文件、共享库Mach-O 得名于苹果内核基于的 Mach 微内核CMU 开发共同点加载器从头部解析、忽略尾部数据——这是资源追加方案的基础7. InstallBundles 实现过程源码追踪核心思想安装阶段只读 DLL 尾部的 zip 元数据不加载 DLL 代码真正的 LoadLibrary 发生在Start()时。7.1 入口 — BundleContext::InstallBundlesframework/src/bundle/BundleContext.cpp:465只做 context 合法性检查转发给bundleRegistry.Install(location, ...)。7.2 并发控制 — BundleRegistry::Installframework/src/bundle/BundleRegistry.cpp:153注册表用multimaplocation, BundlePrivate记录已装 bundle分三种情况该路径已装过复用已有BundleResourceContainer不重新解析 zip已装 bundle 直接进结果只对新增条目走 Install0首次安装在initialBundleInstallMap登记占位 → 创建新容器 → 安装完成后notify_all唤醒等待线程他线程正在装同一路径引用计数 1条件变量等待wait_for100μs 轮询规避通知丢失竞态醒后按已安装路径处理7.3 打开 zip — BundleResourceContainerframework/src/bundle/BundleResourceContainer.cpp:43构造、:214InitMiniz构造时先检查文件存在不存在抛xxx does not existInitMiniz()两级尝试优先BundleObjFactory解析 PE/ELF/Mach-O若资源被链接进数据段则mz_zip_reader_init_mem从内存初始化回退mz_zip_reader_init_file把整个 DLL 文件当 zip 打开miniz 从尾部找 zip 目录自动跳过 PE 部分两者都失败 → 抛Could not init zip archiveInitSortedEntries()遍历 zip 条目按第一级目录名收集m_SortedToplevelDirs——每个顶层目录 一个 bundle 符号名7.4 创建 bundle — Install0framework/src/bundle/BundleRegistry.cpp:312对 zip 里每个顶层目录storage-CreateAndInsertArchive()创建BundleArchive分配 bundle id构造BundlePrivate包装成Bundle加锁插入(location, bundle)到注册表 multimap广播BUNDLE_INSTALLED事件异常时Purge()回滚已创建的 archive7.5 解析 manifest — BundlePrivate 构造函数framework/src/bundle/BundlePrivate.cpp:702从 archive 取/manifest.json资源流JSON 解析进BundleManifest校验bundle.symbolic_name必须存在且非空bundle.version若存在必须合法状态置STATE_INSTALLED优化若 zip 里只有 manifest 一个资源解析完立即关闭 zip 句柄时序总结路径检查 → 并发去重 → miniz 打开 DLL 尾部 zip → 按顶层目录逐个建档、解析 manifest、注册 → 广播 INSTALLED 事件8. 一个 DLL 可包含多个 Bundle判定依据框架只看尾部 zip 的顶层目录数Install0对每个顶层目录各创建一个独立的BundleArchiveBundlePrivate——这也是 API 叫复数 InstallBundles、返回std::vectorBundle的原因。TestBundleB.dll 尾部的 zip ├── TestBundleB/manifest.json ← bundle 1 │ dynamic.ptxt └── TestBundleImportedByB/manifest.json ← bundle 2 static.ptxt典型场景静态链接 bundle测试用例framework/test/bundles/libBWithStatic/CMakeLists.txtTestBundleImportedByB编译为静态库自己的资源 zip 先生成TestBundleB是共享库链接该静态库并用usFunctionEmbedResources的ZIP_ARCHIVES参数把静态 bundle 的 zip 合并进自己的 zip代码层面每个 bundle 各有usFunctionGenerateBundleInit生成的初始化代码和 Activator符号按US_BUNDLE_NAME区分如_us_create_activator_TestBundleB互不冲突Start()时框架按各 bundle 符号名分别查找入口。极端情况全静态构建静态编译时整个程序只有一个 exe所有bundle 的资源 zip 都合并进 exegetting_started CMakeLists 末尾的ZIP_ARCHIVES ${_static_bundles}。对 exe 自身路径调用一次InstallBundles即可装出全部 bundle——测试framework/test/gtest/BundleManifestTest.cpp:296DirectManifestInstallMulti验证了一个 location 装出 2 个 bundle。结论bundle 边界由 zip 顶层目录划分与 DLL 文件是一对多关系多 bundle 单 DLL 主要服务于静态链接和资源合并场景常规动态构建惯例仍是一个 DLL 一个 bundle。9. CPPMICROSERVICES_INITIALIZE_BUNDLE 宏旧版 2.x 时代的宏叫US_INITIALIZE_MODULEModule 时代3.0 更名后在当前代码中已不存在迁移时直接替换为CPPMICROSERVICES_INITIALIZE_BUNDLE编译定义US_MODULE_NAME改为US_BUNDLE_NAME。定义在framework/include/cppmicroservices/BundleInitialization.h:70。作用为 bundle 生成两个按US_BUNDLE_NAME命名的 C 导出函数用于框架与 bundle 间传递 BundleContextstd::atomicBundleContextPrivate*上下文变量;externCBundleContextPrivate*_us_get_bundle_context_instance_bundle名();// 框架读取externCvoid_us_set_bundle_context_instance_bundle名(BundleContextPrivate*);// 框架 Start 时注入Start()加载 DLL 后框架通过GetProcAddress找到 set 函数把 context 注入 bundle。使用位置核心 3 处位置说明cmake/BundleInit.cpp:25最主要入口——usFunctionGenerateBundleInit的模板被 configure 成每个 bundle 的cppmicroservices_init.cpp自动编入教程 bundle 都走这条路framework/src/bundle/CoreBundleContext.cpp:48框架自身system_bundle的初始化getting_started 的ServiceTimeImpl.cpp:42、ServiceTimeConsumer.cpp:60手写调用示例带参数形式CPPMICROSERVICES_INITIALIZE_BUNDLE(service_time_systemclock)另有文档/代码片段示范framework/doc/snippets/下 3 个 main.cpp、doc/src/examples/makefile/的 main.cpp 与 bundle.cpp及 getting_started.rst、Example1.rst、build_instructions.rst。两种使用方式CMake 自动生成推荐usFunctionGenerateBundleInit(TARGET xxx OUT srcs)宏从编译定义US_BUNDLE_NAMExxx取名手动调用非 CMake 构建如 makefile 示例在 bundle 某源文件末尾直接写CPPMICROSERVICES_INITIALIZE_BUNDLE10. 版本演进史共3 个大版本截至 2026-07上游最新正式版为v3.8.12本地VERSION文件与上游最新 tag 一致development 分支为 3.8.12 之后的开发版尚无 4.0 tag。大版本tag 范围核心特征1.xv1.0.0初代核心概念叫Module基础服务注册/查询2.xv2.0.0 ~ v2.1.1仍是 Module 时代US_INITIALIZE_MODULE宏属于此期完善资源嵌入、ServiceTracker3.xv3.0.0 → v3.8.12重大重构全面对齐 OSGi 规范Module 更名Bundle引入 Framework 生命周期FrameworkFactory/Init/Start、BundleContext3.4 起陆续加入 OSGi Compendium 服务声明式服务 DS、ConfigAdmin、LogService2.x → 3.x 是不兼容的破坏性升级API、宏、概念全部改名3.x 系列内部保持 API 兼容主要是增量功能和修复US_GLOBAL_VERSION_SUFFIX基于主版本号生成用于库文件命名隔离不同大版本11. 与 CTK Plugin Framework 的对比CppMicroServices 3.x 的 Framework 生命周期与 CTK非常类似——两者的祖师爷都是OSGi 规范CTK 的 ctkPluginFramework 是 OSGi R4 的 Qt/C 移植CppMicroServices 3.x 重构目标同样是对齐 OSGi。概念对照OSGi (Java)CTKCppMicroServices 3.xFrameworkctkPluginFrameworkFrameworkFrameworkFactoryctkPluginFrameworkFactoryFrameworkFactoryBundlectkPlugin叫 PluginBundleBundleContextctkPluginContextBundleContextBundleActivatorctkPluginActivatorBundleActivatorinstallBundle()installPlugin()InstallBundles()状态机INSTALLED→RESOLVED→STARTING→ACTIVE→STOPPING完全相同的状态集事件ctkPluginEvent / ctkServiceEventBundleEvent / ServiceEvent元数据MANIFEST.MF键值对manifest.json启动流程同构工厂创建 Framework → init()framework 自身成为 0 号 system bundle→拿 context 安装插件/bundle → start() → 各 Activator 的 start(context) 被回调。主要差异Qt 依赖CTK 深度绑定 Qt——插件必须是 QObject/Qt 插件服务接口用Q_DECLARE_INTERFACE事件走 signal/slot元数据为 Java 风格 MANIFEST.MF。CppMicroServices 是纯标准 C零框架依赖服务接口是普通抽象类用模板做类型安全的注册/查询打包方式CTK 插件也是共享库 内嵌 zip 资源思路类似但格式不同CppMicroServices 用 manifest.json且支持静态链接 bundleCTK 基本只支持动态插件规范覆盖CTK 移植了不少 OSGi 服务EventAdmin、ConfigAdmin、Metatype 等但近年维护放缓CppMicroServices 3.4 也在补 Compendium 服务社区更活跃主要由 The MathWorks 驱动粒度CppMicroServices 2.x 刻意轻量化无完整 Framework 概念3.x 才补齐生命周期向 CTK/OSGi 完整度靠拢结论有 CTK 经验如 MITK/医学影像开发可直接复用心智模型——把 Plugin 换成 Bundle、去掉 Qt 层即可。
延伸阅读

更多相关文章

2026/11/3 20:28:40

API Fuzzer 完整专业释义

目录 一、基础定义 二、核心适用接口类型 三、API Fuzzer 核心工作流程 四、关键专属术语(API Fuzz 特有) 五、主流 API Fuzzer 工具分类 1. 开源专用 API 模糊工具 2. 企业级接口安全平台 3. RPC 专用 Fuzzer 六、API Fuzzer 与普通二进制 Fuz…

2026/11/3 22:23:10

C# CAD二次开发中如何退出窗口

在 C# AutoCAD 二次开发中,退出已加载的 Windows 窗口(如 WinForms 或 WPF 窗体)的核心方法是调用窗体的 Close() 方法或设置 DialogResult 属性。具体实现取决于窗口的显示方式(模态或非模态)以及是否需要与 AutoCAD …

2026/11/2 5:33:49

Ubuntu 20.04系统卡死诊断与解决方案

1. 问题现象与初步诊断遇到Ubuntu 20.04系统完全卡死的情况,连鼠标指针都无法移动,这是典型的系统僵死(hard hang)现象。与普通的程序无响应不同,这种全局性冻结通常意味着内核层或硬件交互出现了严重问题。根据我处理…

2026/11/5 11:39:15

PostgreSQL数据类型选择指南与性能优化实践

1. PostgreSQL数据类型概述PostgreSQL作为一款功能强大的开源关系型数据库,其数据类型系统之丰富远超大多数同类产品。我在实际项目中最常遇到的问题是:面对十几种数字类型、多种字符串类型以及各种特殊类型时,开发团队往往凭直觉选择&#x…

2026/11/5 11:34:12

Simulink S-function执行时序与状态管理原理详解

简介:本资源是面向MATLAB/Simulink初学者与控制系统建模学习者的S-Function入门实践包,聚焦自定义系统函数开发这一核心能力,解决标准库无法覆盖的特定数学运算与动态逻辑建模需求。压缩包共4个文件(2个M文件实现核心算法逻辑&…

2026/11/5 11:34:12

低空经济三维智能感知与实时调度技术解析

1. 低空经济三维空间智能感知与管控体系概述低空经济作为新兴经济形态,正在全球范围内快速发展。根据国际航空运输协会(IATA)预测,到2030年,全球城市空中交通市场规模将达到1.5万亿美元。在这一背景下,《低…

2026/11/5 11:34:12

链表数据结构与PTA解题技巧详解

1. 链表基础与数据结构课程实践 链表作为线性表的链式存储结构,是数据结构课程中承前启后的关键内容。在山东理工大学(SDUT)的数据结构与算法课程体系中,链表章节通常安排在顺序表之后、树结构之前,这种教学顺序设计体…

2026/11/5 11:34:12

Simulink S-Function核心机制与两个经典C示例解析

简介:本资源是面向MATLAB/Simulink初学者与控制系统建模学习者的S-Function入门实践包,聚焦自定义系统函数开发这一核心能力,解决标准库无法覆盖的特定数学运算与动态逻辑建模需求。压缩包共4个文件(2个M文件实现核心算法逻辑&…

2026/11/5 11:34:12

Mantle系统架构:云存储局部性与扩展性的突破

1. 项目概述:Mantle系统架构演进的技术突围在云存储技术高度成熟的今天,百度沧海存储团队完成的Mantle系统设计堪称一次教科书级别的技术突围。这个被SOSP25收录的存储系统创新案例,完美诠释了如何在看似饱和的技术领域实现突破——不是通过堆…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑