c++cmakec++-modulesc++23

How to use CMake to build a project with C++23 standard library module(import std)?


As we know, C++23 support Standard Library Modules. Until May 2023, MSVC support it but we need add Standard Library Modules manually as Microsoft blog mentioned.

But how to use import std in CMake project? The MS blog doesn't mentioned it. And these files can't work.(The std.ifc file is obtained from microsoft blog tutorial:cl /std:c++latest /EHsc /nologo /W4 /MTd /c "%VCToolsInstallDir%\modules\std.ixx"(use in msvc x64 native console))

CMakeList.txt

CMAKE_MINIMUM_REQUIRED(VERSION 3.26)

set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a")
set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP ON)

set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${CMAKE_PROJECT_NAME})


set(CMAKE_CXX_STANDARD 23)

project(1-1)

add_executable(${CMAKE_PROJECT_NAME})
target_sources(${CMAKE_PROJECT_NAME}
    PUBLIC
    FILE_SET all_my_modules TYPE CXX_MODULES FILES
    main.cpp
    std.ifc
)

main.cpp

import std;
using namespace std;

int main(){
    cout<<"Hello\n";
}

And MSVC shows:

[build] main.cpp(1,11): error C2230: Could not find module "std" 
[build] main.cpp(5,5): error C2065: "cout" : Undeclared identifier 

I can use copy %VCToolsInstallDir\modules\std.ixx to project folder and change std.ifc to std.ixx, but is there a more elegant way to achieve it to avoid building std module every time? I think it's because .ifc is not a source file,how to deal with it in CMake?


Solution

  • Note that Visual Studio keeps changing how this works, I will try and update the answer as things progress.

    As a prerequisite you need to set CMAKE_CXX_STANDARD to use C++23:

    [...]
    set(CMAKE_CXX_STANDARD 23)
    
    add_executable(demo)
    target_sources(demo
      PRIVATE
        demo.cpp
    )
    

    This will set the VS configuration property C/C++->Language->C++ Language Standard to /std:c++latest. Visual Studio 17.6 now also provides a property C/C++->Language->Build ISO C++23 Standard Library Modules which needs to be to Yes and will then automatically build the standard library modules on /std:c++latest as part of your project build.

    This option used to be activated by default, but Visual Studio recently changed that default to No, so you now need to activate that option manually. CMake is currently considering to provide an option for controlling this property.

    For older versions of Visual Studio, you will have to compile the std named module yourself before importing it.

    Since CMake does not support importing pre-compiled modules at the moment, the easiest way to get things running is therefore to simply include the primary module interface for the standard library in your project.

    Be sure to first read this answer to understand the current prerequisites and limitations of the C++20 modules in CMake.

    CMakeLists.txt

    [...]
    add_executable(demo)
    
    file(COPY
      # you don't want to hardcode the path here in a real-world project,
      # but you get the idea
      "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.36.32532/modules/std.ixx"
      DESTINATION
      ${PROJECT_BINARY_DIR}/stdxx
    )
    
    target_sources(demo
      PRIVATE
      FILE_SET CXX_MODULES FILES
      ${PROJECT_BINARY_DIR}/stdxx/std.ixx
      PRIVATE
      demo.cpp
    )
    

    demo.cpp

    import std;
    
    int main()
    {
        std::cout << "Hello World\n";
    }
    

    CMake rightfully prevents you from including module sources outside of your source tree in the build. So we will copy the module interface file to our binary tree for building.

    As usual, having the same primary module interface appear more than once in a program is not allowed. Structure your build accordingly so that you don't accidentally end up with std.ixx being compiled twice.