C++ 20 Modules Update

If you are interested in C++20 modules support in CMake, please have a look at this blog post:

https://www.kitware.com/import-cmake-c20-modules/

It would be great to get feedback from users on this work.

Thanks.
-Bill

4 Likes

This is great, thank you for putting all the info in one place!
I have been dabbling for some time with modules with Vs2022 and CMake!

I was wondering does this mean that those instructions are generator agnostic? I ask because it is not mentioned and I wonder if I can now use ninja on windows with modules.

Thank you again!

Yes, that is tested and should work.

Since the article mentions ninja explicitely, what about make ?

Thank you!!!

No support yet. No plan either.

Edited to add: I should clarify that Makefile support would be good, we just have no concrete plans at the moment.

Hi, I was trying to use the ninja generator (with MSVC) and C++ module and following the blog post, but something is wrong.
Maybe it is a bug with Visual Studio, but the CMake bundled with Visual Studio doesn’t recognize CXX_MODULES for FILE_SET.
When I generate, I get

target_sources File set TYPE may only be “HEADERS”

I verified the CMake version that is bundled with visual studio and its

cmake version 3.25.2-msvc4

Should I open a bug? or am I missing something?

My mistake. I have updated the blog to say 3.26 or newer.

1 Like

I figured as much thanks alot!

I guess the doc should also be updated to add the version where those are added.

Another thing to add to the post would be that the target_source should not be an executable, as it will refuse the FILESET. At least that is my understanding so far. I have opened an issues with CMake and vcpkg ( the error is coming from vcpkg.cmake). I was using CMake 3.26.0-rc4

I see you opened CMake Issue 24537 for that, but it just isn’t true. Something else is going wrong with your attempt to try this feature.

CMake 3.25.2 should work, but needs a different CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API value.

I have updated the blog to note that the API value will change with CMake versions.

Hey,

Problem

I was trying to run simple project with C++20 modules with CMake but I get the following compilation error from ninja:

missing compilation database and failed to contruct one by --p1689-targeted-file-name, --p1689-targeted-output

Do you see where is the issue?

Details

I pushed the project here: Files · 9f9346c41795a14f18266c727fa3621d4be9ccba · WRCIECH / cpp-20-modules-with-cmake-and-clang · GitLab

CMake and Ninja version:

cmake --version
cmake version 3.26.0-rc5

ninja --version
1.11.1

The full error after typing cmake --build --preset=macos:

[1/8] Scanning /Users/wojciech/dev/private/test_modules/cpp-20-modules-with-cmake-and-clang/main.cxx for CXX dependencies
FAILED: CMakeFiles/hello.dir/main.cxx.o.ddi CMakeFiles/hello.dir/main.cxx.o.modmap 
/Users/wojciech/dev/private/test_modules/llvm/build/bin/clang-scan-deps -format=p1689 -- /Users/wojciech/dev/private/test_modules/llvm/build/bin/clang++   -std=c++20 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk -x c++ /Users/wojciech/dev/private/test_modules/cpp-20-modules-with-cmake-and-clang/main.cxx -c -o CMakeFiles/hello.dir/main.cxx.o -MT CMakeFiles/hello.dir/main.cxx.o.ddi -MD -MF CMakeFiles/hello.dir/main.cxx.o.ddi.d > CMakeFiles/hello.dir/main.cxx.o.ddi
missing compilation database and failed to contruct one by --p1689-targeted-file-name, --p1689-targeted-output
[2/8] Scanning /Users/wojciech/dev/private/test_modules/cpp-20-modules-with-cmake-and-clang/foo.cxx for CXX dependencies
FAILED: CMakeFiles/foo.dir/foo.cxx.o.ddi CMakeFiles/foo.dir/foo.cxx.o.modmap 
/Users/wojciech/dev/private/test_modules/llvm/build/bin/clang-scan-deps -format=p1689 -- /Users/wojciech/dev/private/test_modules/llvm/build/bin/clang++   -std=c++20 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk -x c++ /Users/wojciech/dev/private/test_modules/cpp-20-modules-with-cmake-and-clang/foo.cxx -c -o CMakeFiles/foo.dir/foo.cxx.o -MT CMakeFiles/foo.dir/foo.cxx.o.ddi -MD -MF CMakeFiles/foo.dir/foo.cxx.o.ddi.d > CMakeFiles/foo.dir/foo.cxx.o.ddi
missing compilation database and failed to contruct one by --p1689-targeted-file-name, --p1689-targeted-output
ninja: build stopped: subcommand failed.

I was able to build with these changes:

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3d97e6b..412cc0d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,4 +16,5 @@ target_sources(foo
         foo.cxx
 )
 
-add_executable(hello main.cxx)
\ No newline at end of file
+add_executable(hello main.cxx)
+target_link_libraries(hello foo)
diff --git a/clang_modules.cmake b/clang_modules.cmake
index 24544f3..2dd4244 100644
--- a/clang_modules.cmake
+++ b/clang_modules.cmake
@@ -1,15 +1,12 @@
-set(CMake_TEST_CXXModules_UUID "a246741c-d067-4019-a8fb-3d16b0c9d1d3")
-
 set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
 string(CONCAT CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE
-        "${CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS}"
-        " -format=p1689"
-        " --"
-        " <CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS>"
-        " -x c++ <SOURCE> -c -o <OBJECT>"
-        " -MT <DYNDEP_FILE>"
-        " -MD -MF <DEP_FILE>"
-        " > <DYNDEP_FILE>")
+  "${CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS}"
+  " -format=p1689 --p1689-targeted-file-name=<SOURCE> --p1689-targeted-output=<OBJECT> "
+  " --p1689-makeformat-output=<DEP_FILE>"
+  " --"
+  " <DEFINES> <INCLUDES> <FLAGS> -x c++ <SOURCE>"
+  " -MT <DYNDEP_FILE> -MD"
+  " > <DYNDEP_FILE>")

Thank you for quick response.

After making these changes I get the following error:

clang-scan-deps: Unknown command line argument '--p1689-makeformat-output=CMakeFiles/hello.dir/main.cxx.o.ddi.d'.  Try: '/Users/wojciech/dev/private/test_modules/llvm/build/bin/clang-scan-deps --help'

and indeed --p1689-makeformat-output doesn’t seem to exist in clang-scan-deps:

 /Users/wojciech/dev/private/test_modules/llvm/build/bin/clang-scan-deps --help
USAGE: clang-scan-deps [options] The command line flags for the target of which the dependencies are to be computed.

OPTIONS:

Generic Options:

  --help                              - Display available options (--help-hidden for more)
  --help-list                         - Display list of available options (--help-list-hidden for more)
  --version                           - Display the version of this program

Tool options:

  --compilation-database=<string>     - Compilation database
  --dependency-target=<string>        - The names of dependency targets for the dependency file
  --deprecated-driver-command         - use a single driver command to build the tu (deprecated)
  --eager-load-pcm                    - Load PCM files eagerly (instead of lazily on import).
  --format=<value>                    - The output format for the dependencies
    =make                             -   Makefile compatible dep file
    =p1689                            -   Generate standard c++ modules dependency P1689 format
    =experimental-full                -   Full dependency graph suitable for explicitly building modules. This format is experimental and will change.
  -j <uint>                           - Number of worker threads to use (default: use all concurrent threads)
  --mode=<value>                      - The preprocessing mode used to compute the dependencies
    =preprocess-dependency-directives -   The set of dependencies is computed by preprocessing with special lexing after scanning the source files to get the directives that might affect the dependencies
    =preprocess                       -   The set of dependencies is computed by preprocessing the source files
  --module-files-dir=<string>         - The build directory for modules. Defaults to the value of '-fmodules-cache-path=' from command lines for implicit modules.
  --module-name=<string>              - the module of which the dependencies are to be computed
  --optimize-args                     - Whether to optimize command-line arguments of modules.
  --p1689-targeted-file-name=<string> - Only supported for P1689, the targeted file name of which the dependencies are to be computed.
  --p1689-targeted-output=<string>    - Only supported for P1689, the targeted output of which the dependencies are to be computed.
  --resource-dir-recipe=<value>       - How to produce missing '-resource-dir' argument
    =modify-compiler-path             -   Construct the resource directory from the compiler path in the compilation database. This assumes it's part of the same toolchain as this clang-scan-deps. (default)
    =invoke-compiler                  -   Invoke the compiler with '-print-resource-dir' and use the reported path as the resource directory. (deprecated)
  -v                                  - Use verbose output.

Should I use newer build of LLVM than this: Release p1689r5-cmake-ci-20221201: [C++20] [Modules] [ClangScanDeps] Allow clang-scan-deps to without sp… · mathstuf/llvm-project · GitHub?

Yes, that is the version I am using. git status
HEAD detached at p1689r5-cmake-ci-20221215
Mine has those flags: (maybe a build issue or not running the right one?)

 --p1689-makeformat-output=<string>  - Only supported for P1689. Print the make-style dependency output to the specified output. This is a helper for build systems to do duplicate scanning.
  --p1689-targeted-file-name=<string> - Only supported for P1689, the targeted file name of which the dependencies are to be computed.
  --p1689-targeted-output=<string>    - Only supported for P1689, the targeted output of which the dependencies are to be computed.
1 Like

The issue was that I was using p1689r5-cmake-ci-20221201 LLVM branch (this one is linked in the article from first post - I think it makes sense to correct it) but I should use p1689r5-cmake-ci-20221215 LLVM branch.

With the second one everything compiles fine.

Thanks, sorry about that. I have updated the article to have the new link.

@bill.hoffman Sorry by the tag, but I’ve followed the steps of your post and don’t work if you use the official clang branch. By example I installed the clang-17 and the clang-tools suite from PPA and everything is fine there. But when I use your clang.cmake file from post. The string

""${CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS}"
  " -format=p1689 --p1689-targeted-file-name=<SOURCE> --p1689-targeted-output=<OBJECT> "
  " --p1689-makeformat-output=<DEP_FILE>"
  " --"
  " <DEFINES> <INCLUDES> <FLAGS> -x c++ <SOURCE>"
  " -MT <DYNDEP_FILE> -MD"
  " > <DYNDEP_FILE>""

Is useless right now at least for me, because clang-scan-deps now don’t use the --p1689-targeted-file-name=

This is the output of console when try to create the dependencies for build

clang-scan-deps-17: Unknown command line argument '--p1689-targeted-file-name=/mnt/c/Repositories/DeSiGNAR/berti/cmakemodules/main.cpp'.  Try: '/usr/bin/clang-scan-deps-17 --help'

Have you tested with clang after the new merge of clang-tools ?. Because I want to test the modules with cmake for a data structure library, but the order of build is the thing that is prevents go forward.

Thanks by your help, your post was very useful to understand the issues.

Btw another guy create a tool called xmake and this is capable of get the module dependencies in a good way. Part of my tests compile correctly there.

1 Like

The instructions in Bill’s post are specific to the branch of Clang linked from the post, which predates upstream Clang support. Upstream Clang 16+ will have the needed features, but the command-line arguments to clang-scan-deps changed from the prototype branch linked in Bill’s post. Also, they were added in the LLVM/Clang development branch for Clang 17, and backported to the Clang 16 release branch, after the initial Clang 16 branch was created. There may be PPAs for Clang 17 that predate the support.

In CMake MR 8285 I taught CMake about the upstream LLVM/Clang flags for module dependency scanning, thus reducing the number of variables one needs to set to try it. This update will be included in CMake 3.26.0-rc6 and later.

For whatever version of CMake you’re using, see Help/dev/experimental.rst in its source tree for instructions to use its experimental features.