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

2

10

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?

Thesaurus answered 17/5, 2023 at 3:55 Comment(4)
What is the problem you get with the CMakeLists.txt and main.cpp files you show? What happens? What errors do you get?Tweeze
@Someprogrammerdude the std module can't find. I add it in question now.Thesaurus
"But how to use import std.io in CMake project?" You don't. std.io is not a C++23 module. There are std and std.compat; that's it.Ellord
@NicolBolas I'm sorry for wrong expression, I just want to ask std.Thesaurus
C
9

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.

Cobbie answered 17/5, 2023 at 16:15 Comment(7)
Could I understand there is no method to use pre-compiled module in cmake now?Thesaurus
@LeenHawk That is correct. There's still a couple of unresolved issues in that area that tooling vendors will need to figure out. See e.g. P2577 for details. Build2 already supports this through a proprietary metadata file format (which then also only works for build2, naturally), but all the other build systems will likely depend on SG15 to release a standardized format before supporting this.Cobbie
@LeenHawk And finally, as suspected, the whole endeavour just became a lot easier with the last Visual Studio update. I updated the answer accordingly.Cobbie
Dear sir, do you know hot to use c++20 modules with cmake 3.28 and msvc? It seems there are some breaking changes between cmake 3.27 and 3.28 and msvc couldn't found std module again...Thesaurus
Came here just to ask for the same. I tried CMake 3.28-rc4 with both Ninja and MSVC2022 generators, but import std didn't workOozy
@LeenHawk Visual Studio keeps changing the defaults here. I will try and keep this answer updated, but be aware that whatever method you are using right now will probably keep breaking frequently with updates in the near future.Cobbie
@Cobbie A very fair assumption to make on the Windows + MSVC toolchain (both on development and CI platforms) is that the environment is pre-loaded with vcvarsall.bat. Then, we may use "$ENV{VCTOOLSINSTALLDIR}\modules\std.ixx" instead of hard-coding the entire path.Binate
B
1

With CMake 3.30, this is straightforward, as described in the blog post:

CMakeLists.txt

cmake_minimum_required(VERSION 3.30 FATAL_ERROR)

# UUID to enable CMake's `import std` handling
# it may potentially change with CMake versions
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "0e5b6991-d74f-4b3d-a41c-cf096e0b2508") 

project(main LANGUAGES CXX)

set(CMAKE_CXX_MODULE_STD 1) # this is important

add_executable(main main.cpp)

# Must be C++23 until CMake merges `import std` as a C++20 extension
target_compile_features(main PRIVATE cxx_std_23) 

main.cpp

import std;

auto main() -> int
{
  std::println("Hello world!");
}

No special CMake command-line is needed.

Binate answered 8/6 at 11:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.