# Importing C++20 module as external DLL in msvc 2022

**URL:** https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763
**Category:** Code
**Tags:** comp:msvc
**Created:** [January 3, 2024, 12:00pm UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763 "2024-01-03T12:00:21Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![forry](https://discourse.cmake.org/user_avatar/discourse.cmake.org/forry/32/3356_2.png) [@forry](https://discourse.cmake.org/u/forry)
#### Post date: [January 3, 2024, 12:00pm UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763/1 "2024-01-03T12:00:21Z")

</div>

Hi,  
I have a testing solution done with one cmake list that simulates the creation of a module as a shared library, installing it, and then an executable that will find and consume it. Before “file sets” it worked fine. I have just listed those .ixx as interface sources for install\_interface.

Now with file sets, the build and install of the module dll works fine. The .ixx files are under /include/ as before but the importing part of the cmake results in an error:  
`CMake Error in CMakeLists.txt: Target "ExternalDllModule__ExternalDllModule@synth_435c1b58afb7" contains C++ modules intended for BMI-only compilation. This is not yet supported by the Visual Studio generator.`  
The target executable gets created anyway but can’t find the symbols in the modules. When I manually add the .ixx files from /include to the project, then it works. I can see the target\_sources in the generated config file that should add those but it is adding them as **interface** instead of public.

Also, there was an error that wanted me to add `target_compile_features(ExternalDllModule PUBLIC cxx_std_20)` even when there already was `set_property(TARGET ExternalDllModuleApp PROPERTY CXX_STANDARD 20)`. But that was a minor inconvenience.

So, what am I doing wrong?

The relevant part of a larger example project:

```cmake
cmake_minimum_required(VERSION 3.28)
cmake_policy(VERSION 3.28)

project(Modules
    VERSION 0.0.0
    LANGUAGES CXX)

include(GnuInstallDirs)

add_compile_options(/experimental:module) # needed for STL modules
#
# 3rd party dll module creation
#

add_library(ExternalDllModule SHARED)
target_sources(ExternalDllModule
    PRIVATE 
        ExternalDllModule/mod.class.cpp
        ExternalDllModule/mod.func.cpp
    PUBLIC FILE_SET CXX_MODULES BASE_DIRS ExternalDllModule FILES
        ExternalDllModule/mod.ixx
        ExternalDllModule/mod.class.ixx
        ExternalDllModule/mod.func.ixx  
)
set_property(TARGET ExternalDllModule PROPERTY CXX_STANDARD 20)
target_compile_features(ExternalDllModule PUBLIC cxx_std_20)
target_compile_definitions(ExternalDllModule
        PRIVATE
            "DLLMODULE_EXPORT=__declspec(dllexport)"
        INTERFACE
            "DLLMODULE_EXPORT=__declspec(dllimport)"
    )
install(TARGETS ExternalDllModule EXPORT ExternalDllModule_export FILE_SET CXX_MODULES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(EXPORT ExternalDllModule_export NAMESPACE ExternalDllModule:: DESTINATION lib/cmake/ExternalDllModule FILE ExternalDllModuleConfig.cmake)

#
# 3rd party dll module consumption
# You need to install the ExternalDllModule first
#

find_package(ExternalDllModule QUIET)
if(ExternalDllModule_FOUND)
    add_executable(ExternalDllModuleApp)
    target_sources(ExternalDllModuleApp
        PRIVATE 
            DllModule/main.cpp
    )

    target_link_libraries(ExternalDllModuleApp PRIVATE ExternalDllModule::ExternalDllModule)
    set_property(TARGET ExternalDllModuleApp PROPERTY CXX_STANDARD 20)
endif()

```

The old version with the source files but without the “file sets” changes is here [GitHub - forry/examples-cppmodules: C++20 modules examples.](https://github.com/forry/examples-cppmodules)

---

<div class="post-metadata">

### Author: ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)
#### Post date: [January 5, 2024, 6:19am UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763/2 "2024-01-05T06:19:13Z")

</div>

I have prepared a MR that should work:

> <https://github.com/forry/examples-cppmodules/pull/2/files#diff-1e7de1ae2d059d21e1dd75d5812d5a34b0222cef273b7c3a2af62eb747f9d20a>

---

<div class="post-metadata">

### Author: ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)
#### Post date: [January 5, 2024, 10:17am UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763/3 "2024-01-05T10:17:46Z")

</div>

I see a different problem on my CI:

```cmd
[1/82] Scanning D:\a\examples-cppmodules\examples-cppmodules\SingleFileModule\main.cpp for CXX dependencies
[2/82] Scanning D:\a\examples-cppmodules\examples-cppmodules\TwoFileModule\main.cpp for CXX dependencies
[3/82] Scanning D:\a\examples-cppmodules\examples-cppmodules\TwoFileModule\mod.cpp for CXX dependencies
[4/82] Scanning D:\a\examples-cppmodules\examples-cppmodules\SingleFileModule\mod.ixx for CXX dependencies
mod.ixx
[5/82] Scanning D:\a\examples-cppmodules\examples-cppmodules\TwoFileModule\mod.ixx for CXX dependencies
mod.ixx
[6/82] Scanning D:\a\examples-cppmodules\examples-cppmodules\PartitionModule\mod.func.cpp for CXX dependencies
[7/82] Scanning D:\a\examples-cppmodules\examples-cppmodules\PartitionModule\main.cpp for CXX dependencies
[8/82] Generating CXX dyndep file CMakeFiles\SingleFileModule.dir\CXX.dd
[9/82] Generating CXX dyndep file CMakeFiles\TwoFileModule.dir\CXX.dd
[10/82] Scanning D:\a\examples-cppmodules\examples-cppmodules\PartitionModule\mod.ixx for CXX dependencies
mod.ixx
[11/82] Scanning D:\a\examples-cppmodules\examples-cppmodules\PartitionModule\mod.class.ixx for CXX dependencies
mod.class.ixx
[12/82] Scanning D:\a\examples-cppmodules\examples-cppmodules\PartitionModule\mod.func.ixx for CXX dependencies
mod.func.ixx
[13/82] Scanning D:\a\examples-cppmodules\examples-cppmodules\Conflicts\main.cpp for CXX dependencies
[14/82] Building CXX object CMakeFiles\TwoFileModule.dir\TwoFileModule\mod.ixx.obj
mod.ixx
[15/82] Building CXX object CMakeFiles\SingleFileModule.dir\SingleFileModule\mod.ixx.obj
mod.ixx
[16/82] Building CXX object CMakeFiles\TwoFileModule.dir\TwoFileModule\main.cpp.obj
FAILED: CMakeFiles/TwoFileModule.dir/TwoFileModule/main.cpp.obj 
C:\PROGRA~1\MICROS~2\2022\ENTERP~1\VC\Tools\MSVC\1438~1.331\bin\Hostx64\x64\cl.exe /nologo /TP -external:I"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.38.33130\ATLMFC\include" -external:I"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.38.33130\include" -external:I"C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt" -external:I"C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\shared" -external:I"C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\um" -external:I"C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\winrt" -external:I"C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\cppwinrt" -external:W0 /DWIN32 /D_WINDOWS /EHsc /O2 /Ob2 /DNDEBUG -std:c++20 -MD /experimental:module /showIncludes @CMakeFiles\TwoFileModule.dir\TwoFileModule\main.cpp.obj.modmap /FoCMakeFiles\TwoFileModule.dir\TwoFileModule\main.cpp.obj /FdCMakeFiles\TwoFileModule.dir\ /FS -c D:\a\examples-cppmodules\examples-cppmodules\TwoFileModule\main.cpp
D:\a\examples-cppmodules\examples-cppmodules\TwoFileModule\main.cpp(2): fatal error C1011: cannot locate standard module interface. Did you install the library part of the C++ modules feature in VS setup?
[17/82] Building CXX object CMakeFiles\SingleFileModule.dir\SingleFileModule\main.cpp.obj
FAILED: CMakeFiles/SingleFileModule.dir/SingleFileModule/main.cpp.obj 
C:\PROGRA~1\MICROS~2\2022\ENTERP~1\VC\Tools\MSVC\1438~1.331\bin\Hostx64\x64\cl.exe /nologo /TP -external:I"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.38.33130\ATLMFC\include" -external:I"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.38.33130\include" -external:I"C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt" -external:I"C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\shared" -external:I"C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\um" -external:I"C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\winrt" -external:I"C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\cppwinrt" -external:W0 /DWIN32 /D_WINDOWS /EHsc /O2 /Ob2 /DNDEBUG -std:c++20 -MD /experimental:module /showIncludes @CMakeFiles\SingleFileModule.dir\SingleFileModule\main.cpp.obj.modmap /FoCMakeFiles\SingleFileModule.dir\SingleFileModule\main.cpp.obj /FdCMakeFiles\SingleFileModule.dir\ /FS -c D:\a\examples-cppmodules\examples-cppmodules\SingleFileModule\main.cpp
D:\a\examples-cppmodules\examples-cppmodules\SingleFileModule\main.cpp(2): fatal error C1011: cannot locate standard module interface. Did you install the library part of the C++ modules feature in VS setup?
[18/82] Scanning D:\a\examples-cppmodules\examples-cppmodules\Conflicts\mod.ixx for CXX dependencies
mod.ixx
[19/82] Scanning D:\a\examples-cppmodules\examples-cppmodules\PartitionModule\mod.class.cpp for CXX dependencies
ninja: build stopped: subcommand failed.

```

---

<div class="post-metadata">

### Author: ![forry](https://discourse.cmake.org/user_avatar/discourse.cmake.org/forry/32/3356_2.png) [@forry](https://discourse.cmake.org/u/forry)
#### Post date: [January 5, 2024, 11:20am UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763/4 "2024-01-05T11:20:36Z")

</div>

Hi,  
thank you. It is very educative, I’ve picked up a few tricks. But I couldn’t understand what would make the difference. There are just so many changes 🙂 . So I have cloned it, and added the ` target_compile_features(ExternalDllModule PUBLIC cxx_std_20)` and it is still behaving the same in the end.

To be clear. I’m configuring it without the “test”, then installing it, and then configuring it with the “test” checked, but the .ixx files don’t get added to the sources of the test app resulting in compile time errors. While the cmake reports the same error in the generate phase as before.

I would say this is a bug since now, I wouldn’t use the FILE\_SET CXX\_MODULES since it doesn’t help in this case. And this case is when it is only ever helpful.

---

<div class="post-metadata">

### Author: ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)
#### Post date: [January 5, 2024, 11:27am UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763/5 "2024-01-05T11:27:18Z")

</div>

The [WindowsToolchain](https://github.com/MarkSchofield/WindowsToolchain) is just an smart way used on the CI action, **I like to build fast with ninja**. 😉

---

<div class="post-metadata">

### Author: ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)
#### Post date: [January 5, 2024, 5:11pm UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763/6 "2024-01-05T17:11:54Z")

</div>

Here, you may found working examples, not on CI, but on **OSX** with `clang++ v17.0.7`:

> <https://github.com/ClausKlein/cppstd20-code/blob/feature/build-all-modules/modules/CMakeLists.txt>

---

<div class="post-metadata">

### Author: ![forry](https://discourse.cmake.org/user_avatar/discourse.cmake.org/forry/32/3356_2.png) [@forry](https://discourse.cmake.org/u/forry)
#### Post date: [January 8, 2024, 10:14am UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763/7 "2024-01-08T10:14:28Z")

</div>

Thanks,  
but as I’ve said in the OP I’m interested in the MSVC. And I can’t even compile your huge repo there – `1>D:\projects\claus\cppstd20-code\modules\mod3\mod3order.cppm(17,18): error C7621: module partition 'Order' for module unit 'Mod3' was not found`  
But anyway, I’m not seeing the find\_package directive for modules anywhere, so this is not what I want. I guess that feature is not yet supported with CXX\_MODULES as the above cmake error states and you need to just do it by hand.

---

<div class="post-metadata">

### Author: ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)
#### Post date: [January 8, 2024, 5:12pm UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763/8 "2024-01-08T17:12:22Z")

</div>

Sorry for your problems, but it builds with the Windows toolchain file on my CI:

> <https://github.com/ClausKlein/cppstd20-code/actions/runs/7450790143/job/20270484763>

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [January 18, 2024, 11:39pm UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763/9 "2024-01-18T23:39:15Z")

</div>

Using external modules from Visual Studio is not yet supported. I hope to get back to [this MR](https://gitlab.kitware.com/cmake/cmake/-/merge_requests/8893) but I don’t have a timeline right now.

---

<div class="post-metadata">

### Author: ![forry](https://discourse.cmake.org/user_avatar/discourse.cmake.org/forry/32/3356_2.png) [@forry](https://discourse.cmake.org/u/forry)
#### Post date: [January 19, 2024, 9:37am UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763/10 "2024-01-19T09:37:09Z")

</div>

I don’t know if that MR is about what I need. I don’t want to import .ifc. I install/export a shared library (dll) but instead of public header files, I have .ixx module interface files. I then want the consuming cmake, after calling the `find_package` and `target_link_library`, to have them as files to compile. I guess that it is not as easy when using other filename extensions or generators.

But other than that I don’t know why I would use the file set for modules instead of just:

```cmake
target_sources(tgt PUBLIC some.ixx)

```

Which have worked fine in that scenario. So if that is not supported and without a clear timeline it’s fine, I just want to be sure.

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [January 19, 2024, 11:59am UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763/11 "2024-01-19T11:59:18Z")

</div>

Modules must belong to a single target and making them “compiled” by putting them into multiple targets as plain `SOURCES` is a recipe for violating the ODR (one definition rule). CMake needs to know which files provide modules in order to properly account for usage by other targets (the visibility) as well as the “home” target (for anchoring into a single place for its `.obj` (compiled) part while also having usage semantics for other targets for its `.ifc` (BMI) part). Only Visual Studio has the magic that would allow for `target_sources(PUBLIC)` to work because MSBuild itself understands C++ modules; other generators do not. CMake tends to only provides generator-specific behaviors with generator-specific specification (`VS_USER_PROPS`, `XCODE_ATTRIBUTE_`) or with extra information that is conditionally used (e.g., `BYPRODUCTS`, `OPTIMIZE_DEPENDENCIES`) but doesn’t fundamentally change the semantics CMake guarantees (i.e., other generators can implement this but the build still works without it).

---

<div class="post-metadata">

### Author: ![forry](https://discourse.cmake.org/user_avatar/discourse.cmake.org/forry/32/3356_2.png) [@forry](https://discourse.cmake.org/u/forry)
#### Post date: [January 19, 2024, 12:55pm UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763/12 "2024-01-19T12:55:21Z")

</div>

I kind of understand the second part. It may be a misunderstanding on my side, I also look at c++20 module interface units as a replacement for header files thus when making a package/module/library I assumed that instead of interface headers that are included and thus compiled by the consumer I would use module interface for the same reason and the distribution of the BMI files is somewhat possible but not the main goal.  
It might be I’m missing something, but I think when a source code has an `import module;` statement it needs to know where the BMI for that module is or perhaps know where the module interfaces are and compile them beforehand. These module interfaces (partitions and all) will just say that these symbols are dll imported and that’s it. But even if the primary module interface has an implementation in its private part I can’t imagine how you can get an ODR.  
What would then be a good solution for making a shared library as a c++20 module and distributing it as pre-compiled binary using cmake as we do with dlls?

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [January 19, 2024, 9:47pm UTC](https://discourse.cmake.org/t/importing-c-20-module-as-external-dll-in-msvc-2022/9763/13 "2024-01-19T21:47:56Z")

</div>

> [@forry](#):
>
> I don’t know if that MR is about what I need. I don’t want to import .ifc

That is the file that `import foo;` ends up reading for MSVC. You want this to import it. The object file is compiled with the original target and ships in the associated library. The consuming project _also_ needs to create a `.ifc` file for the module in order to import it. Shipping BMI files is not portable because one made with, say, `-std=c++20` is not compatible with consuming code that uses `-std=c++23` (maybe this particular flag is fine with MSVC, but it is not true in general).

> [@forry](#):
>
> What would then be a good solution for making a shared library as a c++20 module and distributing it as pre-compiled binary using cmake as we do with dlls?

Use `FILE_SET` to store your module files and let the above MR make it work for Visual Studio; it works for Ninja generators already.
