-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Add C++ modules support #2291
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Add C++ modules support #2291
Conversation
|
Great work. I also thought about this. The approach is very similiar to what was done to https://github.com/nlohmann/json with nlohmann/json#4799. Then, I noticed ... Is this temporary approach with a file with This approach is not using modules natively but rather as an interface to the original way. Does this method work without disadvantages? |
|
This is the best way to my knowledge to support modules on top of a header-only or header/source library, allowing continued support for older versions while providing newer features as an option. I'm not aware of any disadvantages to it besides a being additional translation unit to compile, but if I am wrong please correct me. The only glaring difference in API is that detail symbols are hidden as they are not exported, but in my opinion that's probably better not to expose detail symbols and flood IDE suggestions with implementation details. |
|
What about compiled libraries? Is it possible to have the traditional method and modules installed in parallel? I am thinking of repositories that ship compiled This is relevant here, https://aur.archlinux.org/packages/cpp-httplib-compiled . |
|
Yes I believe it's possible to use shared/static libraries with modules, all of my modular projects compiled to shared libraries that an executable consumes |
|
@mikomikotaishi, thanks for the fine pull request! It's fantastic, but my concern is that someone needs to update @sum01 @jimmy-park @Tachi107 do you have any thought about this pull request? |
|
I could create a Python script, or some other kinds of automated means of updating, which you could run every time it is updated. Until then I would be OK with maintaining this file, as it is a simple process. Such a script would probably comb through the file and add any symbols not part of a detail or internal namespace, or prefixed with an underscore, etc. However, I am curious why it is not feasible to update the file manually. In case it isn't clear how, one can update the file by adding a |
|
I have also seen some repositories use bots to push some commits too. Potentially one such bot could be set up to automatically populate the module with new changes each time there is a mismatch. I don't know anything about how to set this up, but I have seen this before and it could potentially be a solution (but I think the simplest one is just to run a Python script each time any update to the library happens). |
|
Anyway, I think this could be one such way of automatically updating the module. |
|
@mikomikotaishi thanks for the additional explanation. I am ok with the following your suggestion.
We could automatically generate |
|
OK, that makes sense to me. (I don't know anything about how to run GitHub Actions or write scripts for it however, so I'm afraid the most I can do is create a script for this.) |
|
I'm not sure why there were failing workflows as I didn't change anything in the core library |
|
Never mind, it seems the failing CI is happening upstream too. |
|
If the file can be run during the build process (and if the output consists of machine-generated files, it should *only* run during build time), then the destination directory should be configurable (maybe defaulting to the the current working directory). Even better, if the output is a single file, the script should allow the user to specify the output file itself (full path).
This is because downstreams (like Debian, which is what I maintain the meson build scripts for) may have some requirements on where build products should be stored.
|
|
@Tachi107 CMake needs to know what the output directory is ahead of time to compile the module. How do you propose to solve this? |
|
@yhirose I think there is one possible solution to allow both the directory to be user-specified while still supporting CMake module building, which is probably just to have the Python script generate the CMake file too. I don't know if this is too convoluted or awkward of a design though, so please do tell me your thoughts. |
|
Hi Miko,
On Tue Dec 9, 2025 at 10:46 PM CET, Miko wrote:
@Tachi107 CMake needs to know what the output directory is ahead of time to compile the module. How do you propose to solve this?
You should use CMake's add_custom_command() function to invoke the
script and pass it the output file path
https://cmake.org/cmake/help/latest/command/add_custom_command.html
Meson has a similar function, but I can do that myself after this gets
merged.
|
Tachi107
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some feedback now that I have been able to look at the whole code :)
|
Is there a reason to try and add module support when the library itself is C++11? Not to mention, Cmake v3.28 adds built-in module support, which isn't being used either. |
|
This library being C++11 does not require programmes depending on it being C++11. I support the modules. |
|
Indeed, some people who use C++20 and onward may wish to consume the library with the module rather than the header. This is precisely what modules are designed to improve for compilations, as re-including the same large header in multiple locations massively increases build times whereas modules are built only once and then imported/linked. |
|
I understand you can use older standards on newer ones, but I mean trying to add support where it isn't "supported" seems unnecessary. As for having to re-compile, why not use pre-compiled headers (Cmake v3.16 feature), or the compiled version of this library? |
|
Precompiled headers are not a standard language feature, they are just a compiler trick. Modules provide a very specific API and very specific features for library encapsulation. For example, we may want to avoid including httplib's macros or avoid adding detail/implementation symbols into scope, which overwhelms autocomplete on IDEs with irrelevant symbols. Even splitting the library into a header/source division still leaves a very large header that gets recompiled each time. As for the question of "support", this specific wrapper style (a module which includes the header and then re-exports the symbols) is how most libraries built with C++11/14/17 provide module support (such as Boost, Poco, etc.) This is the simplest way to do it to my knowledge, and it's not a hastily tacked-on hack. You can see in other libraries this is how originally header-libraries are wrapped for modules. |
|
Hi, sorry for the silence on this issue. I've been busy with an exam, but I'll return to this and send a solution today or tomorrow. |
|
@yhirose Hi, I am sorry but I am completely lost as to how to actually generate a module correctly from the header. I was considering using |
|
I personally would rather manually maintain the module file for the time being, but if someone more skilled at parsing C++ wants to take a crack at this please feel free. |
|
@mikomikotaishi Thanks for your willingness. However, I am now thinking of closing this pull request for the maintenance reason I commented on before. I would like to confirm that you will commit to updating modules/httplib.cppm whenever new external symbols are added or existing symbols are removed/renamed by contributors. I am not going to wait for this update to happen. This update must be done by you before I release a new version. Otherwise, httplib.h will be shipped with an incompatible, out-of-date httplib.cppm. If you accept this responsibility from now on, I will reconsider it. |
|
@mikomikotaishi could you test it on three platforms (macos, ubuntu, Windows)? |
Things are building correctly for me and I'm able to use the module on MSVC, GCC and Clang, so I think things are good |
|
Could you show me how you compile it with clang++, g++, and vc++? I'll try on my machines when I have time. |
|
I'm relying on CMake to build it, because compiling libraries by manually calling the compiler rather than including it by header or using a build system is difficult and something I have little experience with. If you are interested in what I did:
This runs the
This performs the actual build. All of the compiler configuration is handled by the generated build system files. |
Tachi107
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some more comments :)
This would create issues for people who have hardcoded |
3f96601 to
1fb3651
Compare
|
On Thu Jan 15, 2026 at 2:15 AM CET, Miko wrote:
Moving forward that's fine, but I do think there are tangible benefits
to using fstrings over string concatenation (looking around online
I often see such claims of performance benefits), and I do find it to
be easier to read.
Generally speaking, I do agree with that. But also, this is really
a quick&dirty script which hasn't been touched much during the years;
moreover, f-strings are not supported in older versions of Python, which
may create troubles for people trying to build this in old environments
such as Debian 9, which is still supported (until 2027) via the ELTS
service.
I don't think we should prevent updating our code to break compatibility
with operating systems released in 2017 :)
But it's something which is always nice to keep in mind when making
small changes that, while good practice, don't need to be done.
|
|
On Thu Jan 15, 2026 at 2:22 AM CET, Miko wrote:
OK, I've forced `HTTPLIB_BUILD_MODULES` to only be legal when CMake is 3.28 or higher.
Thanks, but this is not what I meant :/
My comment was about the suspicion that the CMake build script should
opt in to some new policy behaviour with either cmake_policy or
cmake_minimum_required, but I'm just not sure. I'll wait for someone
actually maintaining the CMake support for cpp-httplib to comment on
this matter. Or, if you're sure it's not needed, just tell me!
In any case, those checks aren't really needed because the build would
fail anyway upon invocation of an unrecognized CMake command by older
CMake installations.
|
1fb3651 to
a18ccca
Compare
|
OK, I'll instead put it behind an include call |
|
@yhirose Anything else in need of addressing? |
I think I haven't been understood :/ Please look at the documentation of |
|
Cannot you (@Tachi107) just give a diff instead of letting him guess what you want? This is not constructive. @mikomikotaishi, is very responsive and puts a lot of effort into it for more then five weeks. |
|
On Wed Jan 21, 2026 at 9:34 PM CET, Matheus Gabriel Werny wrote:
Cannot you ***@***.***) just give a diff instead of letting him guess what you want? This is not constructive.
I would! As mentioned before, I am myself not sure this is needed, and
has already asked people maintaning the CMake build system to comment.
While I have some experience with CMake myself, here in the cpp-httplib
project I only maintain the Meson build scripts. Hence, what I'm doing
here is just providing some feedback, but someone else should have the
final say.
|
|
Hi, I'm sorry but I don't have very much knowledge of CMake and its features or how to correctly apply the desired solution. I would have thought an include would be sufficient to prevent version incompatibilities, but if not a diff would be highly appreciated, I am willing to take suggestions of anyone more familiar with CMake than I am. |
|
I'd guess he was talking about adding |
a18ccca to
e87fffc
Compare
Co-authored-by: Andrea Pappacoda <andrea@pappacoda.it>
e87fffc to
f2f8151
Compare
|
I'd guess he was talking about adding cmake_minimum_required(3.28) into the modules file and setting CMP0155 to the new policy?
Yes, something like that. Note though that setting the minimum version to 3.28 already implies using the new policy behaviour.
|
This pull request adds support for C++20 modules through CMake. It is enabled by the
HTTPLIB_BUILD_MODULESoption (which requiresHTTPLIB_COMPILEto be enabled, though it probably doesn't have to - I only forced this requirement because it seems to make the most sense to force the library to compile if modules are to be compiled).