如何基于C++20 modules开发共享库?相关规范问题咨询
C++20 Modules 共享库开发(MSVC环境)正确实现方案
目前C++标准尚未对模块与动态链接的交互规则做统一约定,主流编译器中MSVC已经给出了生产可用的实现方案,具体规则如下:
核心逻辑
模块与传统头文件的本质差异是:模块接口单元仅会被编译1次生成二进制模块接口(BMI)文件,预处理器指令在编译模块阶段就已经生效,因此传统头文件通过宏切换__declspec(dllexport)/__declspec(dllimport)的方案完全不适用于模块。
MSVC 17.4及以上版本已经实现了自动转换逻辑:编译模块时标记为dllexport的符号,在消费者导入模块时会被编译器自动识别为dllimport,无需开发者手动处理。
完整实现步骤
1. 动态库侧代码示例
模块接口文件 math.ixx
export module math; // 对外导出的函数统一加__declspec(dllexport) export __declspec(dllexport) int add(int a, int b) { return a + b; } // 对外导出的类统一加__declspec(dllexport) export class __declspec(dllexport) Calculator { public: int mul(int a, int b) const; };
模块实现文件 math_impl.cpp
module math; int Calculator::mul(int a, int b) const { return a * b; }
动态库编译配置
- 开启C++20及以上标准:
/std:c++20或/std:c++latest - 模块接口文件添加
/interface编译选项,编译器会自动生成.ifc后缀的BMI文件 - 链接生成DLL时会同步生成对应的
.lib导入库
2. 消费者侧使用示例
业务代码 main.cpp
import math; #include <iostream> int main() { std::cout << add(1, 2) << std::endl; Calculator cal; std::cout << cal.mul(3, 4) << std::endl; return 0; }
消费者编译配置
- 开启与动态库侧一致的C++标准
- 配置BMI搜索路径:将动态库生成的
.ifc文件所在目录添加到/ifcSearchDir参数中,或通过/reference math=xxx/math.ifc直接指定对应模块的BMI路径 - 链接时添加动态库对应的
.lib导入库 - 运行时将动态库生成的
.dll文件放到可执行文件同目录即可
注意事项
- 最低支持版本为Visual Studio 2022 17.4,更低版本的MSVC未实现自动转换逻辑,会出现链接错误
- 不要在模块接口单元中使用宏判断切换
dllexport/dllimport,编译模块时的预定义会被固化到BMI文件中,消费者导入时会识别到错误的链接标记 - 上述规则为MSVC平台的专属实现,Clang、GCC的模块动态链接规则存在差异,跨平台场景需要单独适配对应编译器的规则
内容的提问来源于stack exchange,提问作者Touloudou
相关产品推荐
相关产品推荐

