在前面的实践中,我们主要使用标准库模块。本文将引导您开发一个可供程序调用的自定义模块,从而真正进入模块化开发的应用场景。这种思想与传统的动态库开发有相似之处,大家可以对比理解。
自定义模块的编写与调用
首先,我们来看一个自定义模块的代码示例:
模块接口文件 (例如 exportdemo.cppm)
// exportdemo.cppm
export module demo;
import std;
namespace demo {
export int Add(int, int);
export class exportDemo {
public:
exportDemo();
void display();
};
}
模块实现文件 (例如 exportdemo.cpp)
// exportdemo.cpp
module demo;
import std;
namespace demo {
int Add(int a, int b) {
return a + b;
}
exportDemo::exportDemo() {}
void exportDemo::display() {
std::cout << "this is demo module!" << std::endl;
}
}
模块的声明与实现分离,类似于传统的头文件与源文件。下面是调用该模块的主程序:
主程序 (main.cpp)
// main.cpp
import std;
import demo;
int main() {
demo::exportDemo d;
d.display();
std::cout << "main app!" << "Add return:" << demo::Add(1, 2) << std::endl;
return 0;
}
使用命令行编译
接下来,我们通过命令行一步步编译这个项目。首先需要编译标准库模块,这是许多C++项目编译的基础步骤。
-
编译标准库模块接口单元:
g++ -std=c++23 -fmodules-ts -fsearch-include-path -c bits/std.cc
编译成功后,当前目录会生成 std.o 文件和 gcm 文件夹。
-
编译自定义模块:
首先尝试直接编译头文件命名的模块文件会遇到错误。根据编译器提示,模块声明不能放在传统的头文件(.h)中。因此,我们需要使用特定的扩展名,如 .cppm。
g++ -std=c++23 -fmodules-ts -c exportdemo.cppm
编译成功。这里留下一个思考题:模块文件是否可以命名为 exportdemo.ixx、exportdemo.ccm 或 exportdemo.cxxm?命名规则还有哪些限制?
-
编译并链接所有单元:
g++ -std=c++23 -fmodules-ts -o demo exportdemo.cpp main.cpp
编译成功后,生成可执行文件 demo。运行它:
./demo
# 输出:
# this is demo module!
# main app!Add return:3
结果表明整个编译流程成功,自定义模块功能正常。
使用CMake进行项目构建
对于更复杂的项目,使用构建工具如CMake进行管理是更佳选择。以下是 CMakeLists.txt 的内容:
cmake_minimum_required(VERSION 3.31.6)
# 启用对 `import std;` 的实验性支持
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD “0e5b6991-d74f-4b3d-a41c-cf096e0b2508”)
set(CMAKE_CXX_COMPILER “clang++”)
set(CMAKE_C_COMPILER “clang”)
set(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -stdlib=libc++”)
set(CMAKE_EXE_LINKER_FLAGS “${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++”)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_MODULE_STD 1)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(cmakeMouduleFirst LANGUAGES CXX)
add_executable(cmakeMouduleFirst)
target_sources(cmakeMouduleFirst
PRIVATE
main.cpp
exportdemo.cpp
PRIVATE FILE_SET demoMmodules TYPE CXX_MODULES FILES
exportdemo.cppm
)
该文件内容与之前的示例主要区别在于,通过 target_sources 的 FILE_SET 明确添加了C++模块文件(exportdemo.cppm)。接下来使用 CMake 和 Ninja 构建:
mkdir build && cd build
cmake -G Ninja ..
注意:如果使用过高版本的 CMake(如 4.0),可能会遇到工具链不匹配的错误。确保使用与 CMAKE_EXPERIMENTAL_CXX_IMPORT_STD GUID 匹配的 CMake 版本(本例中为 3.31.6)。构建成功后,编译并运行程序,结果与命令行编译一致。
总结
C++23的模块特性为代码组织带来了新的范式。学习新技术不必求快,循序渐进,理解其核心思想并加以实践即可。目前模块在产业界的广泛应用尚需时日,这为我们提供了充足的学习和实验窗口。在探索过程中,选择合适的编译工具链和构建系统至关重要。