The best way to compile modules C++20 sources?

Here is an example source code:

import <iostream>;
import <limits>;
  
int main()
{
    int min{std::numeric_limits<int>::max()};
    int max{std::numeric_limits<int>::min()};
    bool any{false};
    int x;
    while (std::cin >> x)
    {
        any = true;
        if (x < min)
            min = x;
        if (x > max)
            max = x;
    }
  
    if (any)
        std::cout << "min = " << min << "\nmax = " << max << '\n';
}

What I am doing is to use below command to compile it:

  1. clang++ -std=c++20 -xc++-system-header --precompile iostream
  2. clang++ -std=c++20 -xc++-system-header --precompile limits
  3. clang++ -std=c++20 -fmodule-file=iostream.pcm -fmodule-file=limits.pcm main.cpp -o myapp

This seems very inefficiency, and I would like to learn any better ways, or better with a CMakeLists.txt example. Please kindly help.

Thank you!

1 Like

I am using below cmakelists.txt file, it’s not good, but at least it works… any optimization are welcome!

cmake_minimum_required(VERSION 3.25 FATAL_ERROR)
project(myapp VERSION 0.1 LANGUAGES CXX)

# set the c++ standard to 20
# set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "TRUE")
# add_compile_options(-fmodules-ts)
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)

# compile a list of system modules
function(compile_system_header SYSTEM_FILE)
    if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
        execute_process(
            COMMAND
                clang++ -std=c++20 -xc++-system-header --precompile
                ${SYSTEM_FILE}
            WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
        )
    else()
        execute_process(
            COMMAND
                g++ -fmodules-ts -std=c++20 -c -x c++-system-header
                ${SYSTEM_FILE}
            WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
        )
    endif()
endfunction()
compile_system_header(iostream)
compile_system_header(limits)

set(CMAKE_BUILD_TYPE Debug)
add_executable(${PROJECT_NAME} list0201.cpp)

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    target_compile_options(
        ${PROJECT_NAME}
        PRIVATE
            -fmodule-file=${CMAKE_BINARY_DIR}/iostream.pcm
            -fmodule-file=${CMAKE_BINARY_DIR}/limits.pcm
    )
else()
    target_include_directories(
        ${PROJECT_NAME}
        PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/std
    )
    target_compile_options(${PROJECT_NAME} PRIVATE -fmodules-ts)
endif()

# build command:
# 1. use g++:
#    cmake -G Ninja -S . -B build -DCMAKE_CXX_COMPILER=/usr/bin/g++
#    cmake --build build
# cmake --build build  0.08s user 0.03s system 97% cpu 0.111 total
# 2. use clang++:
#    cmake -G Ninja -S . -B build -DCMAKE_CXX_COMPILER=/usr/local/bin/clang++
#    cmake --build build
# cmake --build build  0.04s user 0.03s system 95% cpu 0.079 tota 
1 Like

CC @ChuanqiXu

On the one hand, for named modules, cmake has support for for it: https://www.kitware.com/import-cmake-the-experiment-is-over/

On the other hand, for header units, cmake doesn’t support it either. So the short answer may be, to use C++20 Modules and avoid header units.

Also personally, (not representing clang community), I don’t like header units and I feel things will get chaos if we abused them.

1 Like