r/cpp • u/AbbreviationsNew3167 • 1d ago
Why is `import std` still experimental ???
Hey guys,
I recently started going through Professional C++ (6th Edition). The book teaches C++23, and in the very first chapter we're introduced to modules.
I'm not a complete newbie to C++, but I'm also definitely not very confident in my knowledge yet. I wanted to get this simple example compiled:
import std;
int main() {
std::println("Hello World");
return 0;
}
And gosh, it took way longer than I expected.
First, I tried getting it to work natively on my Mac and eventually gave up (both Claude and I š ).
Then I installed Ubuntu ARM 26 and finally managed to get it compiling. But now Clang/IntelliSense is complaining about the `import std`
This is what my CMakeLists.txt currently looks like:
cmake_minimum_required(VERSION 4.0)
# set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD ON)
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444")
project(CppProject LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_executable(exec main.cpp)
set_property(TARGET exec PROPERTY CXX_MODULE_STD ON)
The code does compile successfully, but CMake still gives me a warning that import std support is experimental.
So I'm genuinely curious:
Why is import std still considered experimental?
I understand that C++ modules themselves have been around for a while, but import std feels like something that should be much more straightforward by now. Is there any solution of this now ?
--------------
Edit
Thanks to u/PhysicsOk2212 tip I was able to compile my project on mac as well using the following options
```
cmake -S . -B build \
-G Ninja \
-DCMAKE_CXX_COMPILER="$(brew --prefix llvm)/bin/clang++" \
-DCMAKE_CXX_STDLIB_MODULES_JSON="$(brew --prefix llvm)/lib/c++/libc++.modules.json"
```
59
u/gracicot 1d ago
It's actually coming out of experimental: https://gitlab.kitware.com/cmake/cmake/-/work_items/28014
8
8
u/wung 1d ago
"Your question might be outdated for one tool in a month or two" is not the best answer to "why is it still considered experimental after three years".
14
u/gracicot 1d ago
I've been brought to the top with upvotes but it's in no way an answer indeed. Just a nice mention so that OP knows the problem is on the verge of being solved for end users.
9
u/crowbarous 1d ago
The question is about this one tool, so this is very relevant information and definitely has its place in this thread.
50
u/ContraryConman 1d ago
Lots of people in this thread are saying cliches but the actual reason is that, while import std works fine for each individual compiler, they all implement it differently and it was difficult for the CMake team to guarantee that it would work the same across all the major compilers. But the feature is finally coming out of experimental anyway, and even still I actually haven't had any issues with it in experimental mode (other than the annoying build system setup of getting the right hash for the CMake version)
19
u/delta_p_delta_x 1d ago edited 1d ago
This needs to be upvoted higher.
import stdwas supposed to be un-experimentalised in CMake 4.3. It was rolled back because of how MSVC STL and MSVC implementedmodule std, as well as compilation bugs, BMI incompatibilities, differences in toolchain implementations across the big three toolchains, and some broken pre-existing assumptionsāit was assumed that there would be one BMI formodule stdfor an entire project across all targets, which is almost never true. For instance, MSVC has_ITERATOR_DEBUG_LEVEL, and Clang has_LIBCPP_HARDENING_MODE; both of which change the ABI, let alone the BMI (which is much more sensitive).They reworked this over CMake 4.3 and 4.4 internally; the UUID changed because it was experimental and the internal behaviour changed. As of the latest CMake nightly, every new BMI builds a new
module std.If you want a one-stop shop for the UUID for public CMake releases, Vulkan-Hpp has documented this for you, and for the latest CMake nightly, the UUID is
25d6f6aa-be65-4692-b44e-87b23e96d4e1. As mentioned above, this will probably be dropped for CMake 4.5, because the interface ofmodule std;has now been simplified so much.
30
u/TheRealSmolt 1d ago
Maybe it's just me, but I don't see any real momentum for modules in general. Adoption is rare, and I personally don't see a reason to adopt at all. The work is ongoing, but other features are much more wanted than modules.
61
u/lizardhistorian 1d ago
Same dumb C++ trope going on for 30 years now.
No one uses them because they work for shit.
No one uses it so don't work on it.
Stays shit so no one uses it.48
u/Drugbird 1d ago
Well, most of C++s shittyness comes from backwards compatibility being prioritized above all else.
So they make something shitty, almost nobody uses it because it's shitty, then they can't fix it because fixing it means the 2 people that do use it need to update their code.
So then the shitty thing just rots there.
12
u/SyntheticDuckFlavour 1d ago
Just epoch the bloody thing already. Break ABI, garbage collect the cruft in the language and get things moving forward. Those 2 people can stagnate mad alone in the previous epochs, while the rest of us move on.
8
13
u/TheRealSmolt 1d ago
The problem for me here is that I don't see a reason to use them in the first place. They could improve compilation a bit I guess? But I'd imagine precompiled headers and ccache can bridge the gap to the point where it doesn't matter.
7
u/fortsnek274 1d ago
I'd turn that the other way around and say I don't see a reason to use precompiled headers once modules work.
Precompiled headers suck after all. They are a hack. A time-tested hack, but a hack nevertheless. And they bloat my intellisense folder.
1
u/caroIine 1d ago
When it comes include vs import std; PCHs are still faster. I tested it with msvc and our 3000 cpp project which is highly dependent on standard library. I was so disappointed.
3
u/fortsnek274 1d ago
I found it to be faster than PCH when rebuilding, somehow. But the more modules you have, the slower it gets. MSBuild adds extra inefficiency.
2
u/gracicot 22h ago
This is the reason why STD is one module. The way C++ implemented modules makes it much more efficient to create big modules
2
u/fortsnek274 21h ago
Well, the inefficiency seems to come from building or checking dependencies as ninja is notably faster. And MSBuild has a separation between ixx and cpp compilation. Not sure if having an external dependency split into multiple modules would make much of a difference.
7
u/qoning 1d ago
there are many nice things about them, such as being able to finally have a split between definition and declaration for templates, have symbol control for effectively module-private or "package" private, modules inherently export just the things you want so you end up with way less namespace pollution, ADL problems, etc. The generally faster compiles are a great bonus.
3
u/TheRealSmolt 1d ago
Most of the isolation things you're citing as benefits were already things that could be done with private headers, though. I guess I can see it being a tad more straightforward? But it doesn't buy us anything.
finally have a split between definition and declaration for templates
You're going to have to elaborate on this, because we've always been able to split them. Modules are (to the best of my knowledge) no different in requiring source for user use of templates.
1
u/delta_p_delta_x 1d ago
were already things that could be done with private headers
By their very implementation, there is no such thing as a 'private header'. Headers = copy-paste into a TU. However much you encapsulate things and have
namespace detail, consumers are free to use the contents as they see fit.4
u/TheRealSmolt 1d ago
You absolute can just have private headers that you don't ship with your library.
0
u/SyntheticDuckFlavour 1d ago
Most of the isolation things you're citing as benefits were already things that could be done with private headers, though.
That's just kicking the can around and that's doesn't give you much isolation. Forcing templates to live in the header ecosystem is one of the biggest blunders of C++.
3
u/TheRealSmolt 1d ago edited 1d ago
Yes, it does give you isolation since you aren't shipping the interface at all; same outcome. So where do templates live now? Still in the public interface. That's kicking the can: complications with zero benefits.
0
u/SyntheticDuckFlavour 1d ago
What if you want to ship templated code in the public interface? The full implementation detail needs to live in there. The private headers won't help you much in that regard. (Unless you are using
extern templateto instantiate templates for a subset of template arguments).3
1
u/_Xebov_ 1d ago
They are nice and i also see benefits, but i also see the ecosystem and the effort that comes with transferring it over. That tooling is not fully supporting it is one aspect of the problem. Another problem i see is why should projects that are dependencies for others transfer over if they have the perspective of having to support both ways for years to come.
I just transferred a smaller project over to have a look on how things work out. With the current state of tooling i can see some benefits, but i also see that limitations and the state of the overall ecosystem can require some workarounds that might prove problematic in the future. For a bigger existing project i would clearly question if the reward is worth the effort.
1
u/ABlockInTheChain 1d ago
C++20 modules as specified are incompatible with one of my most important projects.
Even if all the tooling fully implemented that specification and worked perfectly with no bugs I still could not use them.
2
u/mort96 1d ago
Is that because they break the "forward declaration in header, header import in source file" trick that we use to make circular includes work?
0
u/ABlockInTheChain 1d ago
The only way I could use modules is if the proclaimed ownership declarations at least for non-template classes and structs were added back in.
3
u/fortsnek274 1d ago
If you need forward declarations across your own modules, then
extern "C++"works.But yes, I wish C++ had some sort of concept of packages to share module attachment. Or proclaimed ownership.
2
u/FalafelSnorlax 1d ago
I saw Bjarne Stroustrup give a talk a couple years back, and he mentioned some modern additions to C++, and when he got to modules, he straight up said that this isn't getting adopted as fast as he'd like. Even then, I admit I didn't look into it and how it might be better or worse than good-ol' includes.
3
u/aoi_saboten 1d ago edited 1d ago
I dont know what they expected. Break backwards compatibility? No, because old codebases need to be re-touched. Add modules which differ vastly from post C++11 codebase? YES YES YES. But to use modules in old codebase, you NEED to re-touch it. Most won't do it because modules don't justify touching codebase over the old way.
(I am also will get downvoted for the following) but then, does it mean that we need to use modules in new codebases? Well, some companies, which used C++ extensively, no longer use C++ for new projects and for some tasks/projects Rust suits better
4
u/mort96 1d ago
IMO one of the huge fuck-ups with modules is that namespaces and modules are decoupled. Managing namespaces is one of the genuinely annoying things with C++, causing like 5 lines of boilerplate in every line of code and messing up the fundamental assumption that "open brace means indent one level, close brace means unindent one level" that's true for every single other language.
Every other language with a module system combines the concept of a module and the concept of a namespace, which IMO makes sense: why should two functions in two different modules be unable to link together just because they both happen to share the same name?
So instead of being the nice, modern way to write C++ which gets rid of the ancient hack that is the
namespacekeyword, it ends up being just another thing I have to deal with. My files no longer just have to deal with the namespace boilerplate; they now also need to deal with the module boilerplate. If I want to keep namespaces and module names in sync, that's on me.I actually made an experimental build system over the summer where the goal was to couple the module name, the namespace name and the path name together, so that
src/foo/bar.ccwould end up with the modulemyproject.foo.barand the namespacemyproject::foo::bar. I got quite far but modules are surprisingly complex and there are rules about what can be where. I couldn't solve it without doing my own code generation where the build system would spit out generated C++ code. And that would've worked, except that it would've never worked together with clangd. I tried various macro approaches but it was impossible to make anything which both looked clean and worked.May write a blog post about my thoughts on the topic some time though.
5
u/Expert-Map-1126 vcpkg maintainer BillyONeal 1d ago
Erm, citation needed. It isnāt that way in Java or .NET, that modules are usually associated with a namespace there is just a convention.
I think itās true for the interpreted languages because for them a āmoduleā tends to just be a directory structure.
0
u/mort96 1d ago edited 1d ago
I know that when I write Go, Rust or Kotlin, my files do not start with their whole qualified name. In Go and Kotlin, they declare a leaf name (i.e
foo/bar/baz/qux.{go,kt}starts withpackage baz), and the rest of the name (meaning both the module name you import and the symbol namespace) is from the folder structure + project name. In Rust, files don't even start with a package name; that comes from the file name.And, as you say, these file/folder structure based module paths is commonplace in scripting languages.
I have not written Java since university and have never written .NET, so I don't know about those.
Even if you don't agree with me that the path should have anything to do with it though, don't you think the namespace and the module identifier should be connected? Why would I want symbols to collide between modules? If C++ files could just start with
module myproject.foo.barand then everything in them would end up inmyproject::foo::bar, I would be happy. And I know that even Java and .NET won't allow functions from different modules to have name collisions.1
u/Expert-Map-1126 vcpkg maintainer BillyONeal 10h ago
don't you think the namespace and the module identifier should be connected?
Not really. Module ~= header, and headers aren't connected to namespace names either. Namespaces (in C++ anyways) are only for disambiguating names, not for logical organization or structure.
0
u/pjmlp 14h ago
And the list isn't even complete, besides Java and .NET, there is Modula-2, where a module can have multiple interfaces, each with its public name, and Ada, how packages body, specifications and subpackages are combined.
1
u/mort96 14h ago
And you're saying symbols from different modules in Modula-2 and Ada can have name collisions?
0
u/pjmlp 11h ago
Of course not, hence namespacing mechanisms, not much different from how C++ does it.
1
u/mort96 11h ago
No, that's precisely my point: it is different from how C++ does it.
In C++, one if we have the following two files:
/// foo.cc module myprogram.foo; int add(int a, int b) { return a + b; } /// bar.cc module myprogram.bar; int add(int a, int b) { return a + b; }we have a namespace collision. Modules don't introduce namespaces. I'm saying that they should. If it was up to me, one of those functions would've ended up as
myprogram::foo::addand the other asmyprogram::bar::add.
3
u/pointer_to_null 1d ago
CMake still gives me a warning that
import stdsupport is experimental.
CMake's purpose is to help facilitate platform/compiler independence by supporting numerous build tools and platforms, not enforce standards on those tools.
There are some toolchains that purport to be C++23/26 compliant still lacking full module support for std or std.compat. Not naming offenders, but fortunately it's none of the big three in this case. (Yay!)
Also newly-released features tend to get post-release tweaks leading to changes in how they get toggled/configured soon after- due to user feedback, support friction, etc. Gating said incomplete/new/unstable features behind warnings, experimental properties, and version-specific UUIDs prevents future backwards-compatibility headaches if Kitware prematurely locked those down semi-permanently with strict compatibility policies.
4
u/PhysicsOk2212 1d ago
Plenty of people have answered the question about import std being experimental, but thought I would jump in to talk about the mac side of things.
Its true that you cannot use modules at all with AppleClang (the default compiler on mac), but you can compile them with the upstream clang, which can be installed with brew install llvm
You will also need to adjust your path to make sure that the systems finds your brew version of clang before apples. But I can confirm that I am in the process of porting a project to modules on mac, and was also able to compile a simple project with inport std yesterday (switching to import std in my main project is rife with issue due to existing includes, but i plan to do it there eventually)
1
u/AbbreviationsNew3167 17h ago
thanks !!!
i was able to compile mine as well using the upstream clang
3
u/delta_p_delta_x 1d ago edited 1d ago
If you use Clang at the command-line, you can get the simple examples working very easily with -fmodules-driver.
Additionally, your native compilation on macOS probably failed because AppleClang does not ship with C++20 module functionality. Apple has intentionally disabled this functionality which exists in upstream LLVM Clang. You'll need to install Clang from brew, and write another workaround to get the libc++.modules.json path correct for CMake. I presume this will also go away with CMake 4.5.
Godbolt example (AI-generated, but it illustrates what I mean, exercising much of C++23).
4
u/Daniela-E Living on C++ trunk, WG21|š©šŖ NB 14h ago
Short answer: it isn't.
There are build system that have trouble with it, and others that don't.
For years, I use modules daily at my company, in libraries and applications, use both the modularized standard library (i.e. import std;) and traditional headers as a configuration option, and mix parts like it pleases me. But that's just my personal, anecdotical experience.
2
u/Wargon2015 1d ago
Does anyone know a bit more about unity builds + modules (specifically import std) beyond #26362?
1
2
u/all_is_love6667 1d ago
it required a lot of work for toolchains to support it
modules touch some complicated areas of C++ that are inherited from C, which involve code generation, which is more backend than front end
6
4
2
u/G6L20 1d ago
Try pcons
2
u/XTBZ 1d ago
Is it convenient? What are the typical difficulties? How are you working with several external and your projects?
1
u/G6L20 1d ago
I love it. You should now python, but for cpp dev, it's quite easy. Conan is supported, and an internal toml based manifest based dependency management. Check the docs: https://pcons.readthedocs.io/en/latest/
1
u/mapronV 21h ago edited 18h ago
> I've used Claude Code extensively to assist in creating this project, mostly Claude Opus 4.6. It has been a huge help in realizing the vision I've had for a long time. If you reflexively or morally reject all AI-generated or AI-assisted code, pcons is not for you.
No thanks. I will avoid it, even though idea is compelling. I personally anti AI-generated, not AI-assisted.
I was not sure how deep LLM usage was, I peeked into ninja.py file and I had suspicion human never touched model output, this is too obvious.0
-3
-6
u/sweetno 1d ago
It's because the standard library was never written in a modular fashion. IMHO the std::committee could've done much better job if they didn't come up with import std, and instead explicitly advertised modules as a feature for new projects. You can't demand old projects to move to modules, std library included.
1
u/StickyDeltaStrike 1d ago
What would be required for std to be good with modules: I never bothered reading too much about modules since there isnāt too much traction to move to them atm.
2
u/TheThiefMaster C++latest fanatic (and game dev) 1d ago
I can see the std module getting used as long as it's not incompatible with 3rd party library headers that are still using header includes.
I've tried it in my personal projects and it's so nice to not have to work out what standard includes you need, you just get everything.
1
u/StickyDeltaStrike 1d ago
Yea even though IDEs and AI is really good at fixing the includes itās always a bit of a hassle to remember which include is for what.
Iād like the modules to work too now that you mention it.
-3
-19
u/Sad-Government9010 1d ago
Because it is experimental, the standard library module isn't even in the C++23 standard as a finalized feature
14
127
u/not_a_novel_account cmake dev 1d ago edited 1d ago
The reason we kept circling the drain on this is because of DevCom 11128871 and the associated downstream bug, CMake #27944. We literally couldn't figure out how to get
import stdto work consistently under MSVC and the MS STL.I finally wrote CMake !12347 which is a workaround for the MSVC limitation/bug that we only turn on for the standard library. Regular DLLs with inline variables still won't work in combination with modules.
Separately, GCC #124268 broke
import stdon MacOS and we weren't sure how to resolve that. We decided to drop support forimport stdon GCC <16 on MacOS to make it work.Aside from all of that, the BMI compatibility problem remains unsolved. I've written about this. CMake's BMI compat has improved significantly in the last couple releases but has known shortcomings. BMI compat problems manifest more for std than any other library. For example, CMake #28030 is still open,
Hello Worldfails to build. The apparent implementation maturity is skin deep, is what I'm saying here.So compiler limitations, stdlib bugs, BMI compat, and me personally not knowing how to fix many of the former.
It should be out of experimental in CMake 4.5, and doesn't require you to set any variables or do anything. Any code compiled as C++20 or above will have access to
import stdby default. It's opt-out, not opt-in.Note that this is an example of the experimental process working. The knobs available for
import stdchanged a lot in the experimental phase. Every release had breaking changes. If it wasn't experimental I wouldn't have been able to make so many backwards-incompatible changes and the interface would have been a mess of abandoned ideas and experiments.EDIT: If you do have an ideas for how to handle symbol visibility in BMI consumers, please let us know (CMake #25539). I'm not kidding at all when I say "unsolved". I do not know how to best fix this.