Skip to content

feat: Add C++ modules support#1530

Open
mikomikotaishi wants to merge 19 commits into
brainboxdotcc:devfrom
mikomikotaishi:dev
Open

feat: Add C++ modules support#1530
mikomikotaishi wants to merge 19 commits into
brainboxdotcc:devfrom
mikomikotaishi:dev

Conversation

@mikomikotaishi

@mikomikotaishi mikomikotaishi commented Dec 27, 2025

Copy link
Copy Markdown
Contributor

This pull request adds support for C++20 modules.

In order to accomplish this, some constants were changed to using external linkage.

I have also updated nlohmann/json to version 3.12.0, as the older version declares some symbols as internal. Updating nlohmann/json has been moved to #1596.

Code change checklist

  • I have ensured that all methods and functions are fully documented using doxygen style comments.
  • My code follows the coding style guide.
  • I tested that my change works before raising the PR.
  • I have ensured that I did not break any existing API calls.
  • I have not built my pull request using AI, a static analysis tool or similar without any human oversight.

@netlify

netlify Bot commented Dec 27, 2025

Copy link
Copy Markdown

Deploy Preview for dpp-dev ready!

Name Link
🔨 Latest commit ce88aff
🔍 Latest deploy log https://app.netlify.com/projects/dpp-dev/deploys/69b75fdc5f079200085fc488
😎 Deploy Preview https://deploy-preview-1530--dpp-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added documentation Improvements or additions to documentation build Issue or Pull Request related to the build process code Improvements or additions to code. labels Dec 27, 2025
@Jaskowicz1 Jaskowicz1 added the enhancement New feature or request label Dec 27, 2025
@mikomikotaishi
mikomikotaishi force-pushed the dev branch 3 times, most recently from e91eaa8 to 121eb9b Compare December 27, 2025 12:04

@Mishura4 Mishura4 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! Good stuff. Just gonna prefer the approach with including dpp.h in the module for maintainability, as discussed in https://discord.com/channels/825407338755653642/825411104208977952/1454456223952011427

@braindigitalis braindigitalis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some module related unit tests would be good. not repeating a thousand lines of code in dpp.cppm is an absolute must, as @Mishura4 also said.

@mikomikotaishi

mikomikotaishi commented Dec 27, 2025

Copy link
Copy Markdown
Contributor Author

I've looked at the src/unittest/ files but I'm not particularly familiar with how you've set up the unit testing framework. Are you just looking to run those same tests under import dpp; rather than #include <dpp/dpp.h>?

@braindigitalis

Copy link
Copy Markdown
Contributor

I think that in this case you might want to make a new .cpp under the unittests folder which imports dpp instead of #including it. it can have some test functions that are exported and called via standard approaches from the main unittest file.

@mikomikotaishi
mikomikotaishi force-pushed the dev branch 3 times, most recently from 1909f3f to 7f6fb23 Compare December 28, 2025 06:06
@mikomikotaishi

Copy link
Copy Markdown
Contributor Author

I think this should fix the errors we're encountering. It's with the build system configuration

@braindigitalis

Copy link
Copy Markdown
Contributor

you cant just do -DDPP_MODULES=ON for the entire CI matrix. Some CI's use older g++ (which we support) and some use C++17.

Comment thread docpages/example_code/using_modules.cpp Outdated
Comment thread docpages/example_programs/misc/using_modules.md Outdated
Comment thread docpages/example_code/using_modules.cpp Outdated
@mikomikotaishi

Copy link
Copy Markdown
Contributor Author

Then is it possible to disable the modules unit tests for C++17 CI tests?

@mikomikotaishi

Copy link
Copy Markdown
Contributor Author

@braindigitalis I think the modules CI should just be in a totally separate CI. It requires Ninja, as CMake can't build modules with Makefiles.

@braindigitalis

Copy link
Copy Markdown
Contributor

unit tests only run in one g++, which is g++-12. This is the one which is packaged. we cant and dont run unit tests on them all, as the unit tests connect to discord and we cant do this concurrently.

Comment thread .github/workflows/test-docs-examples.yml Outdated
@Jaskowicz1 Jaskowicz1 changed the title Add C++ modules support and update nlohmann::json feat: Add C++ modules support and update nlohmann::json Dec 29, 2025
@Jaskowicz1

Copy link
Copy Markdown
Contributor

Updated Title to match code standards

Comment thread .github/workflows/test-docs-examples.yml Outdated
Comment thread .github/workflows/test-docs-examples.yml Outdated
Comment thread src/unittest/test.cpp
@mikomikotaishi mikomikotaishi changed the title feat: Add C++ modules support and update nlohmann::json feat: Add C++ modules support Jun 29, 2026
@braindigitalis

braindigitalis commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

any chance we can trim it down so that its easier to review? perhaps by not introducing ninja as a dependency of docs build, not changing its compiler to clang, and keeping changes to a minimum in the cmakelists etc? right now there are 53 changed files.

@braindigitalis braindigitalis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left some thoughts :-) thanks for the continued effort on this!

Comment thread docpages/example_code/CMakeLists.txt
Comment thread docpages/example_code/CMakeLists.txt
Comment thread docpages/example_code/autocomplete.cpp Outdated
});

/* The interaction create event is fired when someone issues your commands */
bot.on_slashcommand([&bot](const dpp::slashcommand_t & event) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to change all the examples, it makes the PR much harder to review, so many files to go through.

@mikomikotaishi mikomikotaishi Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved these changes into a separate PR, #1604

Comment thread library/CMakeLists.txt
bytes.a
tls_syntax.a
hpke.a
$<BUILD_INTERFACE:mlspp.a>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really really not liking that we changed this. it took a LOT of effort to make this always build everywhere. with static and dynamic linking, on a ton of different systems. some of which CI doesnt test (e.g. static builds)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$<BUILD_INTERFACE:> is build-time transparent, during build it expands into mlspp.a and produces the same linker command.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then if it does the same why change it?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@braindigitalis BUILD_INTERFACE only expands when building the library artifacts ; it's usually as a counterpart to INSTALL_INTERFACE which only expands when bringing the library from an install directory

Up until modules that was functionally the_ same as PRIVATE / PUBLIC but with modules actually PRIVATE is included when bringing module files (as they are translation units that need to be built privately into a public binary artifact, like .cpp files), even when linking an installed library. So BUILD_INTERFACE prevents this and is only used when building the library itself.

So adding BUILD_INTERFACE is correct here, even if I am not sure the author knew why.

@@ -0,0 +1,141 @@
/************************************************************************************

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesnt actually test modules, just verifies they can be linked. but, i guess, theres nothing else we can do to test that, as it is a compile-time thing.

@mikomikotaishi

Copy link
Copy Markdown
Contributor Author

OK; will look in to this.

@braindigitalis

Copy link
Copy Markdown
Contributor

all builds failed. nlohmann doesnt need touching in this pr any more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file should not be picked up as changed at all in this pr. please merge master into the branch

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

Comment thread include/dpp/dpp.cppm
Comment thread library/CMakeLists.txt
# Installation

include(GNUInstallDirs)
install(TARGETS dpp LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did this get removed, is it somewhere else now?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This install does still take place; it's done in cmake/CPackSetup.cmake, which has a richer install rule anyway; keeping it library/CMakeLists.txt just reinstalls the library a second time (with less information)

Comment thread README.md Outdated
Comment thread .github/workflows/ci.yml

@Mishura4 Mishura4 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example doesn't seem to build on Windows. Can we add it to CI somehow?
Also, please fix merge conflicts.


set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic")

# Create gcm.cache directory and symlink to the main build's dpp.gcm

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I can see that, but why?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clang obtains the BMI paths through -fprebuilt-module-path which indicates where to scan, but GCC has no such option, and places its BMIs in gcm.cache/, which is why the lookup location is populated with the symlink to the actual interface.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary? I've not had to do this with any of my other projects

Comment thread docpages/example_code/CMakeLists.txt Outdated
Comment thread library/CMakeLists.txt
bytes.a
tls_syntax.a
hpke.a
$<BUILD_INTERFACE:mlspp.a>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@braindigitalis BUILD_INTERFACE only expands when building the library artifacts ; it's usually as a counterpart to INSTALL_INTERFACE which only expands when bringing the library from an install directory

Up until modules that was functionally the_ same as PRIVATE / PUBLIC but with modules actually PRIVATE is included when bringing module files (as they are translation units that need to be built privately into a public binary artifact, like .cpp files), even when linking an installed library. So BUILD_INTERFACE prevents this and is only used when building the library itself.

So adding BUILD_INTERFACE is correct here, even if I am not sure the author knew why.

@Jaskowicz1 Jaskowicz1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple comments, nothing to really reject for though

Comment thread docpages/example_code/using_modules.cpp Outdated
Comment thread docpages/example_programs/misc/using_modules.md
Comment thread include/dpp/etf.h Outdated
@@ -0,0 +1 @@
\warning D++ modules are currently only supported by D++ on g++ 15, clang/LLVM 17, and MSVC 17.6 or above. Additionally, your program has to support C++20.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to nitpick, could we word this to be D++ modules are currently experimental and are only supported by D++ on g++ 15, clang/LLVM 17, and MSVC 17.6 or above. Additionally, your program has to support C++20.

@@ -1 +1 @@
\warning D++ Coroutines are currently only supported by D++ on g++ 13, clang/LLVM 14, and MSVC 19.37 or above. Additionally, your program has to support C++20.
\warning D++ coroutines are currently only supported by D++ on g++ 13, clang/LLVM 14, and MSVC 19.37 or above. Additionally, your program has to support C++20.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove this change, doesn't really match the capitalisation across the board but also better to keep changes to a minimum

DONT_RUN_VCPKG: true

- name: Build module example
run: cmake --build build --target using_modules_example --config Release --parallel 2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this target exist? I can't see it anywhere in this PR. If it does exist, it's not being built for Windows.

This is causing CI to fail

@Mishura4 Mishura4 Jul 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I asked for examples to be built in CI but yes the CI needs to be fixed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah i'm happy with that, it's just the fact that the using_modules_example target doesn't look like it exists

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Issue or Pull Request related to the build process code Improvements or additions to code. documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants