Hi Cmakers,
This is a question about compiling C++ code with modules.
I’ve built an example that is based on some existing C++ code I have. The class is called sm::range . I have made a CMakeLists to compile an executable target, use_range. The executable uses sm::range compiled as a module.
Here’s the CMakeLists.txt:
cmake_minimum_required(VERSION 3.28)
project(modules_test1 LANGUAGES CXX)
set(CMAKE_CXX_FLAGS “-g -Wfatal-errors”)
include_directories(BEFORE ${PROJECT_SOURCE_DIR})
set_source_files_properties (sm/range PROPERTIES LANGUAGE CXX)
add_executable(use_range use_range.cpp)
target_sources(use_range PUBLIC FILE_SET CXX_MODULES FILES sm/range)
target_compile_features(use_range PUBLIC cxx_std_20)
Find this at GitHub - sebsjames/modules_test1: Testing C++20 standard modules
I have adapted my C++ header file sm/range (original non-module code) with the necessary module; and export keywords.
The project compiles (after not a little work)!
However, I am not sure whether or not I am seeing the promised benefit of C++ modules in terms of build times, because if I trivially change the use_range.cpp code, and recompile, the recompilation seems to take as long as the initial compilation.
Here’s the process. Clean:
[12:40:13 build] cmake --build . --target clean [1/1] Cleaning all built files... Cleaning... 12 files.
Build:
[12:41:14 build] time cmake --build . --target all --verbose
Change Dir: '/home/seb/src/modules_test1/build'
Run Build Command(s): /usr/bin/ninja -v all
[1/6] /usr/bin/c++ -I/home/seb/src/modules_test1 -g -Wfatal-errors -std=gnu++20 -E -x c++ /home/seb/src/modules_test1/use_range.cpp -MT CMakeFiles/use_range.dir/use_range.cpp.o.ddi -MD -MF CMakeFiles/use_range.dir/use_range.cpp.o.ddi.d -fmodules-ts -fdeps-file=CMakeFiles/use_range.dir/use_range.cpp.o.ddi -fdeps-target=CMakeFiles/use_range.dir/use_range.cpp.o -fdeps-format=p1689r5 -o CMakeFiles/use_range.dir/use_range.cpp.o.ddi.i
[2/6] /usr/bin/c++ -I/home/seb/src/modules_test1 -x c++ -g -Wfatal-errors -std=gnu++20 -E -x c++ /home/seb/src/modules_test1/sm/range -MT CMakeFiles/use_range.dir/sm/range.o.ddi -MD -MF CMakeFiles/use_range.dir/sm/range.o.ddi.d -fmodules-ts -fdeps-file=CMakeFiles/use_range.dir/sm/range.o.ddi -fdeps-target=CMakeFiles/use_range.dir/sm/range.o -fdeps-format=p1689r5 -o CMakeFiles/use_range.dir/sm/range.o.ddi.i
[3/6] /usr/bin/cmake -E cmake_ninja_dyndep --tdi=CMakeFiles/use_range.dir/CXXDependInfo.json --lang=CXX --modmapfmt=gcc --dd=CMakeFiles/use_range.dir/CXX.dd @CMakeFiles/use_range.dir/CXX.dd.rsp
[4/6] /usr/bin/c++ -I/home/seb/src/modules_test1 -x c++ -g -Wfatal-errors -std=gnu++20 -MD -MT CMakeFiles/use_range.dir/sm/range.o -MF CMakeFiles/use_range.dir/sm/range.o.d -fmodules-ts -fmodule-mapper=CMakeFiles/use_range.dir/sm/range.o.modmap -MD -fdeps-format=p1689r5 -x c++ -o CMakeFiles/use_range.dir/sm/range.o -c /home/seb/src/modules_test1/sm/range
[5/6] /usr/bin/c++ -I/home/seb/src/modules_test1 -g -Wfatal-errors -std=gnu++20 -MD -MT CMakeFiles/use_range.dir/use_range.cpp.o -MF CMakeFiles/use_range.dir/use_range.cpp.o.d -fmodules-ts -fmodule-mapper=CMakeFiles/use_range.dir/use_range.cpp.o.modmap -MD -fdeps-format=p1689r5 -x c++ -o CMakeFiles/use_range.dir/use_range.cpp.o -c /home/seb/src/modules_test1/use_range.cpp
[6/6] : && /usr/bin/c++ -g -Wfatal-errors CMakeFiles/use_range.dir/use_range.cpp.o CMakeFiles/use_range.dir/sm/range.o -o use_range && :
real 0m0.641s
user 0m0.567s
sys 0m0.110s
Run the program:
[12:41:18 build] ./use_range
Range is [-1, 50]
[-1, 50]
Edit the program (changing a constant value 50.0f to 100.0f):
[12:41:21 build] emacs ../use_range.cpp
Re-build:
[12:41:35 build] time cmake --build . --target all --verbose
Change Dir: '/home/seb/src/modules_test1/build'
Run Build Command(s): /usr/bin/ninja -v all
[1/5] /usr/bin/c++ -I/home/seb/src/modules_test1 -g -Wfatal-errors -std=gnu++20 -E -x c++ /home/seb/src/modules_test1/use_range.cpp -MT CMakeFiles/use_range.dir/use_range.cpp.o.ddi -MD -MF CMakeFiles/use_range.dir/use_range.cpp.o.ddi.d -fmodules-ts -fdeps-file=CMakeFiles/use_range.dir/use_range.cpp.o.ddi -fdeps-target=CMakeFiles/use_range.dir/use_range.cpp.o -fdeps-format=p1689r5 -o CMakeFiles/use_range.dir/use_range.cpp.o.ddi.i
[2/5] /usr/bin/cmake -E cmake_ninja_dyndep --tdi=CMakeFiles/use_range.dir/CXXDependInfo.json --lang=CXX --modmapfmt=gcc --dd=CMakeFiles/use_range.dir/CXX.dd @CMakeFiles/use_range.dir/CXX.dd.rsp
[3/5] /usr/bin/c++ -I/home/seb/src/modules_test1 -x c++ -g -Wfatal-errors -std=gnu++20 -MD -MT CMakeFiles/use_range.dir/sm/range.o -MF CMakeFiles/use_range.dir/sm/range.o.d -fmodules-ts -fmodule-mapper=CMakeFiles/use_range.dir/sm/range.o.modmap -MD -fdeps-format=p1689r5 -x c++ -o CMakeFiles/use_range.dir/sm/range.o -c /home/seb/src/modules_test1/sm/range
[4/5] /usr/bin/c++ -I/home/seb/src/modules_test1 -g -Wfatal-errors -std=gnu++20 -MD -MT CMakeFiles/use_range.dir/use_range.cpp.o -MF CMakeFiles/use_range.dir/use_range.cpp.o.d -fmodules-ts -fmodule-mapper=CMakeFiles/use_range.dir/use_range.cpp.o.modmap -MD -fdeps-format=p1689r5 -x c++ -o CMakeFiles/use_range.dir/use_range.cpp.o -c /home/seb/src/modules_test1/use_range.cpp
[5/5] : && /usr/bin/c++ -g -Wfatal-errors CMakeFiles/use_range.dir/use_range.cpp.o CMakeFiles/use_range.dir/sm/range.o -o use_range && :
real 0m0.617s
user 0m0.532s
sys 0m0.083s
Re-run to verify the program changed
[12:41:41 build] ./use_range Range is [-1, 100] [-1, 100]
Note 1: I see that there are 6 processes in the first build output and only 5 in the second. The process that does not appear in the second build is this one:
/usr/bin/c++ -I/home/seb/src/modules_test1 -x c++ -g -Wfatal-errors -std=gnu++20 -E -x c++ /home/seb/src/modules_test1/sm/range -MT CMakeFiles/use_range.dir/sm/range.o.ddi -MD -MF CMakeFiles/use_range.dir/sm/range.o.ddi.d -fmodules-ts -fdeps-file=CMakeFiles/use_range.dir/sm/range.o.ddi -fdeps-target=CMakeFiles/use_range.dir/sm/range.o -fdeps-format=p1689r5 -o CMakeFiles/use_range.dir/sm/range.o.ddi.i
Which as far as I can tell is a preprocessing step that creates a preprocessed version of the code for the module.
I timed each of the 6 build steps and this is not one that takes a long time; it’s not an actual compilation.
Note 2: I wonder if I need to separate my sm/range into two files, say sm/range with the original C++ code implementation and sm/range.ixx (or .cppm) with the module interface?
So: Is there a reason that a recompile after editing use_range.cpp is not significantly faster than the clean-build?
Thanks for reading such a long post and best wishes,
Seb James