8000 Add modules support by mikomikotaishi · Pull Request #3467 · SFML/SFML · GitHub
[go: up one dir, main page]

Skip to content

Conversation

@mikomikotaishi
Copy link
@mikomikotaishi mikomikotaishi commented Mar 26, 2025

Description

This pull request adds support for C++20 modules, which are enabled using SFML_BUILD_MODULES. It is now possible to import the SFML modules using import.

Obviously, being an optional feature, will not break for SFML users using pre-C++20, but would certainly be an appreciated feature for users of C++20 and later.

This PR is related to the issue #3143, which discusses the integration of C++20 and C++23 features. Though it does not discuss C++20 modules, I have gone ahead and created a wrapper for the C++ modules anyway.

C++ seems to mostly favour having module names and namespace names align (though it isn't a hard requirement). If so need be we could name the modules sf.* instead of sfml.*, but personally I think the more descriptive the name the better. (We could make this a build flag too.)

Tasks

  • Tested on Linux
  • Tested on Windows
  • Tested on macOS
  • Tested on iOS
  • Tested on Android

How to test this PR?

This PR can be tested by importing any of the following modules that now exist (wrapping around the existing headers):

  • sfml, in SFML.cppm (imports the below five modules if all five are built, otherwise only those that are built)
  • sfml.audio, in Audio.cppm
  • sfml.graphics, in Graphics.cppm (imports sfml.window)
  • sfml.network, in Network.cppm
  • sfml.system, in System.cppm (imported by the other modules, also re-exports macros from Config.hpp as constexpr)
  • sfml.window, in Window.cppm

Though the C++ ecosystem and tooling is still noticeably behind particularly for module parsing and module use, I have tested these modules in my own projects which seem to compile and run fine.

Of course, modules do not emit macros, and thus in migration the ratio between import and #include will not be 1:1, meaning adjustments must be made when migrating.

The following should work:

import std;

import sfml.graphics;
import sfml.window;

using sf::Event;
using sf::RenderWindow;
using sf::VideoMode;

int main()
{
    RenderWindow window(VideoMode({1280, 720}), "Minimal, complete and verifiable example");
    window.setFramerateLimit(60);

    while (window.isOpen())
    {
        while (const std::optional event = window.pollEvent())
        {
            if (event->is<Event::Closed>())
                window.close();
        }

        window.clear();
        window.display();
    }
}

Feel free to make any changes as necessary.

@eXpl0it3r
Copy link
Member

Thank you for contributing this! We've already a few people try/use SFML as modules, so it would be quite interesting to be able to add optional support.

I'll add a few review comments that should get the PR into a good state. The final decision on whether we actually want to support this already, is still outstanding however.

@mikomikotaishi
Copy link
Author

Thanks for the comments! I'll follow up with the requested changes in due time.

Copy link
Member
@ChrisThrasher ChrisThrasher left a comment

Choose a reason for hiding this comment

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

I’m open to this idea, but the current implementation needs some work before I can consider it.

@ChrisThrasher
Copy link
Member

Have you considered how this new modular build of SFML will fit into our existing unit test and CI infrastructure? To land a change of this size, we need some pretty substantial testing. I know from experience upgrading SFML to C++20 (in a separate unmerged branch) that upgrading all the CI tooling to support C++20 is actually pretty tricky. I’m curious how libfmt tackles this or if they simply don’t do any automated testing of their modular build.

@mikomikotaishi
Copy link
Author

Have you considered how this new modular build of SFML will fit into our existing unit test and CI infrastructure? To land a change of this size, we need some pretty substantial testing. I know from experience upgrading SFML to C++20 (in a separate unmerged branch) that upgrading all the CI tooling to support C++20 is actually pretty tricky. I’m curious how libfmt tackles this or if they simply don’t do any automated testing of their modular build.

There's one test on libfmt for modules, we could follow this format
https://github.com/fmtlib/fmt/blob/master/test/module-test.cc

@mikomikotaishi
Copy link
Author
mikomikotaishi commented Mar 28, 2025

Okay, I changed everything that was requested up to now, except for completely merging module re-exports of existing declarations in header files that @ChrisThrasher requested, and tests are still yet to be written. Seeing as these are still an experimental feature, I think for the time being it should be pulled and then as time progresses and more users give feedback more concrete changes can be made to the modules.

Seeing as the addition of modules is probably a worthwhile feature to mention, I suggest adding this somewhere to the changelogs.

## C++20 Modules Support

SFML 3 now adds support for C++20 modules, which can be imported using the `import` keyword. 

For example, to use modules, rather than `#include <SFML/Audio.hpp>`, use `import sfml.audio`.

| Modules         | Headers              |
| --------------- | -------------------- |
| `sfml`          |  N/A                 |
| `sfml.audio`    | `<SFML/Audio.hpp>`   |
| `sfml.graphics` | `<SFML/Graphics.hpp` |
| `sfml.network`  | `<SFML/Network.hpp>` |
| `sfml.system`   | `<SFML/System.hpp>`  |
| `sfml.window`   | `<SFML/Window.hpp>`  |

@mikomikotaishi
Copy link
Author

Hi, are there anything missing changes from my recent update that you want addressed before you are ready to accept and merge the pull request?

@kimci86
Copy link
Contributor
kimci86 commented Mar 29, 2025

Hi, are there anything missing changes from my recent update that you want addressed before you are ready to accept and merge the pull request?

I guess this should be automatically tested to some extent. Maybe having an example program using those modules would be enough.

@mikomikotaishi
Copy link
Author

Hi, are there anything missing changes from my recent update that you want addressed before you are ready to accept and merge the pull request?

I guess this should be automatically tested to some extent. Maybe having an example program using those modules would be enough.

Where would be an appropriate place for one?

@mikomikotaishi
Copy link
Author

Okay, after a bit of testing I have found that GCC still cannot compile modules correctly (Clang works just fine). I'm leaving a message in CMake that will prevent it from trying to compile if the compiler is GCC.

@ChrisThrasher
Copy link
Member
ChrisThrasher commented Mar 29, 2025

The SFML team is interested in knowing what it will take to provide a dual header-based and module-based interface to the library. That being said, using C++20 modules requires raising the C++ requirement, CMake requirement, and compiler requirements of the library as of the current major version of SFML, version 3. Most of the configurations we currently support are too old to compiler C++20 modules code.

Your PR if merged into SFML 3 would require some complicated infrastructure to raise those requirements if and only if a C++20 modules build is occurring. On top of that the testing infrastructure (both unit tests and CI) would have to adapt to the raised requirement. This entails a level of additional complexity that I have a hard time picturing merging into SFML 3.

The good news is that SFML 4 is likely going to target a toolset (C++ standard/CMake/compiler versions) that will allow the use of C++20 modules so such a PR as yours would fit much more neatly into that major version. However, SFML 4 work has not begun and we cannot tell you when it may begin. If you're willing to be patient and slowly iterate this PR with us, it has a chance to land early in the SFML 4 development cycle.

Whether you choose to keep working on this is up to you but you ought to know where our attitudes lie and the approximate timeline for a change as what you're proposing.

@mikomikotaishi
Copy link
Author
mikomikotaishi commented Mar 29, 2025

I understand, I was hoping to see it integrated to the next release (i.e. 3.1), but I could wait until 4 for this to be added. That being said, what kind of changes do you want from me to see this feature merged as soon as possible?

The SFML team is interested in knowing what it will take to provide a dual header-based and module-based interface to the library.

Could you elaborate a bit more on what you mean?

Most of the configurations we currently support are too old to compiler C++20 modules code.

I am a little bit confused - the code itself may be old but that doesn't stop users of C++20 and above from being able to import it as a module. For instance, see my project here, I have tested importing SFML which compiles fine and runs fine.

@mikomikotaishi
Copy link
Author
mikomikotaishi commented Mar 30, 2025

Update on module names: @eXpl0it3r , you asked earlier about whether the modules should be named sfml.system or SFML.System, etc. It seems the C++ standard does prefer lowercase modules, see here

@mikomikotaishi
Copy link
Author
mikomikotaishi commented Mar 30, 2025

Also, for convenience, what do you think of also having a module named only sfml that re-exports all five of the modules, so that files requiring all five can just write import sfml; and get all five modules? Obviously this will not replace the existing five individual modules, it is only a convenience feature (there would be six modules, sfml and the five sfml.* submodules).

@ChrisThrasher
Copy link
Member
ChrisThrasher commented Mar 30, 2025

Also, for convenience, what do you think of also having a module named only sfml that re-exports all five of the modules, so that files requiring all five can just write import sfml; and get all five modules? Obviously this will not replace the existing five individual modules, it is only a convenience feature (there would be six modules, sfml and the five sfml.* submodules).

Let's skip this idea for now, but I may want to come back to it later once we solve the bigger problems.

The SFML team is interested in knowing what it will take to provide a dual header-based and module-based interface to the library.

Could you elaborate a bit more on what you mean?

SFML 3's interface comes in the form of header files. SFML 4 will also ship with header files. SFML 4 will not be a module-only library. Therefore SFML 4, if it is to provide a C++20 modules interface, must support both interfaces. In other words, we are not getting rid of our header files in SFML 4. A C++20 modules interface has to coexist with those header files.

Most of the configurations we currently support are too old to compile C++20 modules code.

I am a little bit confused - the code itself may be old but that doesn't stop users of C++20 and above from being able to import it as a module. For instance, see my project here, I have tested importing SFML which compiles fine and runs fine.

As library authors, we make promises like this to users: "SFML 3 can be compiled from source on Ubuntu 22 using its default compiler and packages available from apt". That means we're saying GCC 11, the default compiler for Ubuntu 22, must be able to compile SFML 3. We do let ourselves write any code that breaks with GCC 11. What you're asking to do is adding code to SFML 3 which breaks support for these compilers. This is no small ask and it's why I can't support a PR like this prior to SFML 4.

@mikomikotaishi
Copy link
Author

OK, fair enough. I just hope that not too much will change in the meantime so the existing code here can be merged seamlessly when the time comes for SFML 4. I just wonder why it cannot be used as an optional extension for the time being.

SFML 3's interface comes in the form of header files. SFML 4 will also ship with header files. SFML 4 will not be a module-only library. Therefore SFML 4, if it is to provide a C++20 modules interface, must support both interfaces. In other words, we are not getting rid of our header files in SFML 4. A C++20 modules interface has to coexist with those header files.

The existing layout, with .cppm files that #include the headers and then re-export all contained definitions, will accomplish this exactly, and is probably the simplest and easiest to maintain solution.

@SFML SFML deleted a comment from Odex64 Apr 18, 2025
@ChuanqiXu9
Copy link

@mikomikotaishi I just noticed you contributed several nice patches for C++20 modules and I am maintaining https://arewemodulesyet.org/ . It'll be appreciated if you'd like to update https://arewemodulesyet.org so that I don't have to chase your trace : )

@mikomikotaishi
Copy link
Author

@mikomikotaishi I just noticed you contributed several nice patches for C++20 modules and I am maintaining https://arewemodulesyet.org/ . It'll be appreciated if you'd like to update https://arewemodulesyet.org so that I don't have to chase your trace : )

Hi @ChuanqiXu9, thank you for letting me know! I will make an effort to update it any time I make a new modules port

@mikomikotaishi
Copy link
Author

I was also interested in considering whether to add namespace sfml = sf; as an alias so that it aligns with the module names. The C++ standard recommends aligning module names with namespaces (it only does not for compatibility with pre-modular projects), so doing this would be effortless and supporting good practices.

@ChrisThrasher
Copy link
Member

I just wonder why it cannot be used as an optional extension for the time being.

I don't want SFML to have optional extensions that are untested and of unspecified quality. If a feature if merged, it needs to meet the same level of testing and quality as all other features. We're not going to just toss something into the repo and say "eh whatever you can use it if you want but no promises". It's a bad user experience if the library offers some good features that are well tested and others that are not well tested and may be broken.

I just hope that not too much will change in the meantime so the existing code here can be merged seamlessly when the time comes for SFML 4.

You should expect a lot to change about SFML by the time we reconsider this PR. I appreciate your enthusiasm to keep this PR updated, but I wanted to let you know that this will not be merged in the 3.x release series. On a long enough timeline we'll eventually offer a C++20 modules interface but I cannot promise you when that will happen. Maybe that will be in SFML 4, but nothing can be guaranteed at this time.

@mikomikotaishi
Copy link
Author

I understand. I will continue to keep this PR updated in the meantime, even if it will be a while before SFML 4 enters development.

@Ignis92
Copy link
Ignis92 commented Aug 12, 2025

@mikomikotaishi If it can be of any help, I used most of your files to quickly put together a wrapping static library for SFML that simply reinjects headers into their corresponding modules. You can look up the details in this minimal repo.

Regarding my environment, I'm using MSVC and I had some issues compiling, but that seemed to be more a general problem with the modules' ABI processing rather than something specifically related to SFML or my wrapper. Anyway, I was able to get it working only by changing to the preview version of VS2022, where what seems to be the fix has been sitting for almost 3 months now.

@mikomikotaishi
Copy link
Author

Hmm, interesting. Modules don't have a standardised intermediate form/ABI between compilers though that probably has nothing to do with it. I've been able to use these modules myself in some projects though so I wonder if something I did is specific to Clang, though module sources should be compiler-agnostic. Nonetheless I'm glad to hear there is some interest in using SFML modules.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

0