C++20 Modules 尝鲜 Ⅱ

C++20引入Module特性后,目前C++三大主流编译器MSVC、GCC、Clang都已经相应支持。但是C++的跨平台编译工具CMake还未原生支持Module的自动化构建,虽然可以自定义函数功能解决编译问题,但如果Module交叉、多层嵌套,自己来编写函数解决依赖问题,显得较复杂。所幸至CMake 3.25起,已经初步支持Module的自动化构建,在CMakeLists.txt加入相应API代码即可。

1
2
3
4
5
6
# CMake 3.25
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046")
# CMake 3.26
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
# CMake 3.27
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "aa1f7df0-828a-4fcd-9afc-2dc80491aca7")

仍以《C++高级编程》第五版中第一章中25_ConstAirlineTicket源码为例,编写对应的CMake编译文件如下:

CMakeLists.txt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
cmake_minimum_required(VERSION 3.26)
set(CMAKE_C_COMPILER /usr/bin/clang)
set(CMAKE_CXX_COMPILER /usr/bin/clang++)
set(CMAKE_CXX_FLAGS " -Wall -Werror -O3 -DNDEBUG ")

project(25_ConstAirlineTicket)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) # turn on the dynamic depends for ninja
set(CMAKE_CXX_EXTENSIONS OFF)

add_compile_options(-stdlib=libc++)
add_compile_options(-fmodules)
add_compile_options(-fbuiltin-module-map)
add_compile_options(-fimplicit-module-maps)
add_compile_options(-fexperimental-library)

add_library(AirlineTicket)
target_sources(AirlineTicket
PUBLIC
FILE_SET cxx_modules TYPE CXX_MODULES FILES
BASE_DIRS
"${CMAKE_CURRENT_SOURCE_DIR}"
FILES
AirlineTicket.cppm
)

# Program name and sources
set (TARGET App)
set (SOURCES AirlineTicket.cpp AirlineTicketTest.cpp)

add_executable(${TARGET} ${SOURCES})
target_link_libraries(${TARGET} AirlineTicket)
target_link_options(${TARGET} PUBLIC -stdlib=libc++ -fexperimental-library -fuse-ld=lld)

# mkdir build & cd build
# cmake -G "Ninja" ..
# cmake -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_BUILD_TYPE=Release -G Ninja

由于目前CMake的Module测试功能还不支持生成Unix Makefiles,加-GNinja生成后编译。

注意,CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API得和相应版本Cmake的UUID匹配,否则会报如下错误代码。

1
2
CMake Error at CMakeLists.txt:23 (target_sources): 
target_sources File set TYPE may only be "HEADERS"

好消息,CMake 3.28正式支持C++20 Module特性自动化构建,无需设置MAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API变量。

此外Clang库文件中已经支持 std::format() ,加入-fexperimental-library 即可。

FILE_SET是CMake 3.23新引入的一个功能。

1
2
3
4
target_sources(<target>
[<INTERFACE|PUBLIC|PRIVATE>
[FILE_SET <set> [TYPE <type>] [BASE_DIRS <dirs>...] [FILES <files>...]]...
]...)

其中,TYPE类型有:HEADERS、CXX_MODULES、CXX_MODULE_HEADER_UNITS,看来是专为Module特性引入的。

为了Module文件编写规范化,减少编译过程中错误,一个推荐的 Module 规范结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module;
#include <standard library header>
#include "library not ready for modularization"
...
export module top.middle.bottom;

import modularized.standard.library.component;
import other.modularized.library;
...

#include "module internal header" // beware!!!

non-exported declarations;
...
export namespace top {
namespace middle {
namespace bottom {
exported declarations;
...
}}}

文章目录