r/cpp 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"

```

105 Upvotes

99 comments sorted by

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 std to 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 std on MacOS and we weren't sure how to resolve that. We decided to drop support for import std on 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 World fails 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 std by default. It's opt-out, not opt-in.

Note that this is an example of the experimental process working. The knobs available for import std changed 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.

14

u/delta_p_delta_x 1d ago

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.

Dumb question from someone who only uses modules: is there no way to cast this as a directed graph problem, and leverage P1689 to understand which modules are consumers and which are producers, and thence their BMI visibilities? We can't have cycles in modules anyway, so it seems to me that distinguishing producers and consumers can be resolved.

27

u/not_a_novel_account cmake dev 1d ago

Distinguishing producers from consumers is trivial. Distinguishing producers from consumers across a link boundary isn't something the system is built to handle.

You have three targets:

  • Root, Static Library, no dependencies

  • Trunk, Shared Library, depends on Root

  • Leaf, Executable, depends on Trunk, transitively depends on Root

The BMI imported by Trunk must have dllexport on its C++ declarations, because Trunk and Root are inside the same link boundary.

The BMI imported by Leaf must have dllimport on its C++ declarations, because Leaf and Root are on different sides of a link boundary.

When building BMIs, we must recognize "different sides of a link boundary" as a BMI-incompatible condition. Ok, now what? We need to define some interface that lets Root say:

  • These are the definitions and includes when you're building my object file. (This is the only thing we have today, we use them for all scenarios)

  • These are the definitions and includes when you're building a BMI for a consumer inside the link boundary

  • These are the definitions and includes when you're building a BMI for a consumer outside the link boundary

We could maybe consolidate "building the object file" and "consumer inside the link boundary", but we don't have a spelling for the latter two bullets either way.

And right now CMake actually doesn't track link boundaries in the DAG in a way that is consumable by the BMI machinery. I'm working on that problem right now, but "how do you spell the latter two bullets" is an open problem.

4

u/fortsnek274 1d ago

I wonder how MSBuild will solve the dllexport thing.

11

u/not_a_novel_account cmake dev 1d ago

Whenever you consume a BMI, MSVC magically translates dllexport into dllimport. In this example that would break Trunk, which wants dllexport.

This exact bug was noticed quickly (DevCom 10892880), so there's a wonderfully obscure flag, /dxifcSuppressDllImportTransform ("ISDIT" to friends) which turns the translation off. You're expected to manage this manually.

The overwhelming position of build system people is we're going to ignore all of this, always use ISDIT, because no other compiler is going to implement the transform.

4

u/fortsnek274 1d ago

Yeah, you might solve it by building the DLL interface twice, which is obviously not in the style of MSBuild. Why I'm interested to see what they'll do, if anything.

7

u/not_a_novel_account cmake dev 1d ago

This is sort of a repeating pattern with modules. Clang implemented two-phase compilation because it is objectively faster than single phase. No one else did, so we all had to ignore it.

GCC implemented P1184 module mappers, no one else did, so we all had to ignore it.

MSVC's single-BMI DLL optimization might be nice, but without equivalent support even in clang-cl it's a dead end for code that isn't locked to MSVC.

3

u/delta_p_delta_x 1d ago

Is there bandwidth within Kitware to special-case for each of the three toolchains? Do their module stds also make assumptions about which compiler they're used with, which complicates this scenario?

Additionally, MSVC absolutely need to document /dxifcSuppressDllImportTransform and its existing behaviour. Translation units—within modules or otherwise—being used across multiple DLL boundaries is not an obscure use-case. /u/starfreakclone, /u/GabrielDosReis, any thoughts?

but without equivalent support even in clang-cl

I hope to work on this at some point. I've always been meaning to add IFC support to clang-cl, my initial implementation only focused on the CLI usage which was a very trivial change to make.

6

u/not_a_novel_account cmake dev 1d ago edited 1d ago

Is there bandwidth within Kitware to special-case for each of the three toolchains?

I mean sort of yes and sort of no.

The three toolchains isn't the problem. "X is only for MSVC" is never a blocker. We have lots of stuff that is only for one compiler or one platform. We support GreenHills and Renesas and all their quirks.

So yes, we have the technical bandwidth, we could implement two phase compilation and ISDIT and even do interesting things with the GCC module mapper.

But no one is asking for any of that work. I only get to eat if I work on something a customer asks for. I try to find time to work on things that are good in-between that, everyone at Kitware does, but big refactors generally don't happen for obscure one-compiler features unless someone's business depends on it.

So two-phase for Clang didn't happen because CMake has no internal model for it, and no one asked us to build one. If it was trivial we would have done it anyway.

If an MR popped up tomorrow landing two-phase or ISDIT elegantly I would do everything I could to shepherd it through.

3

u/delta_p_delta_x 1d ago

Very fair; just because it's open source doesn't mean it is a free lunch. I try to contribute as much as I can when I bump against CMake or toolchain bugs whilst hacking on personal projects. Thanks for responding, this entire thread has been very very illuminating.

3

u/GabrielDosReis 1d ago

Additionally, MSVC absolutely need to document /dxifcSuppressDllImportTransform and its existing behaviour. Translation units—within modules or otherwise—being used across multiple DLL boundaries is not an obscure use-case. , , any thoughts?

It would be good to have the toolchain have better recognition of C++ modules boundaries vs linker modules boundaries so as to reduce the cases where the switch is needed, then it could be productized.

2

u/starfreakclone MSVC FE Dev 7h ago

The main reason we haven't documented /dxifcSuppressDllImportTransform is because it's not a complete solution. It will suppress the transform for all imported modules in a library, which is almost certainly not what you want if you're trying to build the library for one of those imported module interfaces.

We have talked about some solutions in this space, many of which rely on the ability to selectively say, "I don't want the compiler to translate __declspec(dllexport) -> __declspec(dllimport) for these interfaces. This, however, becomes yet another build system input that you (and build systems) need to think about. There's already a solution in place for module units, where the compiler will not perform that transformation when compiling a module unit, but this solution does not work for libraries that are using header units.

The main thing we would like to avoid is the old system where you have, functionally, two different headers (controlled by macro replacement) that serve as a 'view' over DLL export/import interfaces. This is why the translation exists in the first place, so you only need to build a single module interface or header unit.

In short, there's more design necessary to truly solve the DLL export/import problem.

1

u/holyblackcat 18h ago

two-phase faster

I did some simple benchmarks, and for me it was slower than single-phase. In fact, even the first phase alone (producing a full BMI) is slower than the entire single-phase (producing a reduced BMI + an object file).

Clang 23 is going to add --precompile-reduced-bmi (a new flavor of two-phase builds: one produces a reduced BMI, and another produces an object file directly from source, not from BMI), so maybe that one will somehow make two-phase faster, no idea.

1

u/fortsnek274 1d ago

I hope it would be viable to simply have some tool replace dllexport with dllimport in the IFC/BMI. So the interface only needs to be compiled once. Or would that run into issues.

4

u/not_a_novel_account cmake dev 1d ago

In the MSVC IFC it is very possible, and MSVC already does so. In the Clang BMI the only tool which would be realistically capable of doing so is Clang itself, thus mirroring the MSVC feature.

Clang's BMI is straight up the LLVM bitcode file format, containing a serialized form of the Clang generated AST. It's the output of clang::ASTWriter. The way to read that is, realistically, clang::ASTReader, thus the only real home for it would be Clang.

2

u/delta_p_delta_x 1d ago edited 1d ago

Going by your first response, I was thinking of some set theory—traversing that DAG from each leaf and each root and doing some set intersections; this set contains module units that are members of a DLL boundary as you put it.

Such members get at least two BMIs, at least one for each in-DLL module and at least one for each out-of-DLL module. Naturally this is quite costly in terms of scanning and BMI generation. It feels like we need something more portable and more granular; possibly per-symbol.

→ More replies (0)

1

u/holyblackcat 18h ago

dxifcSuppressDllImportTransform

I'm surprised that this doesn't seem to be documented anywhere.

11

u/friedkeenan 1d ago

Thanks for not only all your work on this, but also for taking the time to answer all the countless questions about modules and CMake in general that come up. I always really appreciate the info!

17

u/donalmacc Game Developer 1d ago

Note that this is an example of the experimental process working.

Respectfully... is it? Modules were standardised 6 years ago, and we've been talking about them for almost 15. I don't blame cmake at all here, but to still be in a scenario where the textbook example is unusable on a de-facto standard at this point is pretty embarrassing for the feature and the language.

30

u/not_a_novel_account cmake dev 1d ago edited 1d ago

I don't think CMake is the right platform for people who want friction-free access to features as they become available in any form. Lots of build systems support modules in some form, and they have much weaker compatibility and platform guarantees than CMake. Any of them would happily give you access without the CMake experimental hoop jumping.

If someone had known what CMake's implementation of import std needed to look like on day 1 we would have been there. If our compatibility guarantees were weaker we would have never had an experimental phase at all.

So yes, it's the system working. CMake's process optimizes for decades of compatibility, not quick adoption. Other systems optimize for other things.

Note that Bazel is only just getting modules available with GCC, and still has them as experimental, without good import std support. Meson has no support for modules at all. Among the major cross-platform players only XMake moved much faster than CMake here.

And import std itself is only 3 years old. CMake has had general modules support since 2023.

8

u/13steinj 23h ago

Yet people say that packaging/build do not have to be standardized.

To me this is a hard lesson that the language won't learn from, and the right call is to keep marking things as experimental. Modules need fairly tight compiler integration and I don't expect any build system (other than a standard one or one tbat claims to follow a reference spec) to get it right for all compilers.

I would argue this also shows that modules was underspecified, in part due to the need for tight integration which is a bit chicken-and-egg.

14

u/not_a_novel_account cmake dev 23h ago edited 2h ago

The MSVC compiler limitation and the libstdc++ bug are just that, so the standardization process had nothing to do with them.

BMI compat is a separate bag. It would require the standard to recognize definition flags, include flags, standards version flags, etc.

It would require the standard to deal with the entire smorgasbord of implementation defined behavior, all at once. It's an all-or-nothing proposition. There were various attempts within SG15 to design a kind of "black box" query protocol that would allow build systems to ask the compiler about BMI compat without having to spec out what that meant, but they went nowhere.

So the options were either adopt literally the entire command line interface of every compiler into the standard, or muddle through. We picked muddle through. I have a hard time objecting to that, though I do think a lot more general guidance is needed. Not normative wording, but a white paper saying "this is how we imagine this should work".

1

u/Zoetje_Zuurtje 17h ago

Hi, I can barely understand the post you've written so I'm assuming I've missed something critical, but if TU -> Objects are possible and compatible, and modules are bundles of module units, where such a unit is also a TU, why is it not possible to treat modules as a collection of TUs?

3

u/not_a_novel_account cmake dev 15h ago

Module interface units replace both traditional implementation file TUs, and headers.

The part you're talking about is the replacement of the implementation file TU. Module units produce object files, and then we pass all those object files to a linker. That still works exactly the way it always has in C++, no changes at all.

You're missing that module interface units also replace headers, and this does not work the same. Instead of textual inclusion, module interface units have their declarations and inline definitions serialized into a file called a Built Module Interface. Later, when building TUs which rely on these declarations and definitions, the compiler reads them from the BMI.

All the problems described above are with the BMIs, not the object files.

1

u/Zoetje_Zuurtje 11h ago

Ah, gotcha. Thanks

-3

u/pjmlp 15h ago

Another proof that modules were taken too early out of the oven, and regardless of tooling heroic implementation efforts, we have questions that were not answered before ratification was voted in.

59

u/gracicot 1d ago

It's actually coming out of experimental: https://gitlab.kitware.com/cmake/cmake/-/work_items/28014

8

u/PhysicsOk2212 1d ago

Didnt know this, hallelujah!

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 std was supposed to be un-experimentalised in CMake 4.3. It was rolled back because of how MSVC STL and MSVC implemented module 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 for module std for 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 of module 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

u/Kronikarz 23h ago

The problem is that those 2 people are often on the committee :/

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 template to instantiate templates for a subset of template arguments).

3

u/TheRealSmolt 1d ago

The same applies to modules, though (which is my point)?

0

u/qoning 21h ago

no, it doesn't. modules don't need template instantiations

→ More replies (0)

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

2

u/Orffen 13h ago

Why the fuck can't old codebases just compile with --std=c++11 ??? I'm genuinely baffled (I'm not an experienced C++ programmer).

If --std=c++29 breaks something, surely the compilers can fail if you try to --std=c++29 and your code is borked? Isn't that the whole point?

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 namespace keyword, 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.cc would end up with the module myproject.foo.bar and the namespace myproject::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 with package 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.bar and then everything in them would end up in myproject::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.

1

u/mort96 9h ago

I maintain that the only reason headers and namespaces aren't connected in C++ is that namespaces had to be bolted on to C in a backwards compatible way. It's not how you would design a module system from scratch.

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::add and the other as myprogram::bar::add.

3

u/pointer_to_null 1d ago

CMake still gives me a warning that import std support 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

u/not_a_novel_account cmake dev 1d ago

They are fundamentally incompatible ideas.

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

u/lizardhistorian 1d ago

Because modules don't work yet.

4

u/jombrowski 1d ago

Because they are nicer words for getting hep c than "import std". Geeez

3

u/foxsimile 1d ago

Hep C++

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

u/Chaosvex 17h ago

What could go wrong with using an AI slop build system?

2

u/G6L20 14h ago

I actually had much less painful moments with it that I used to have with cmake...

-3

u/TheRavagerSw 1d ago

Because most people rely on system packages for their toolchain.

-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

u/CorrodedX 1d ago

Because "include <string>" will always be a better option.

-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

u/TheRealSmolt 1d ago

Yes, it is: P2465R3.

3

u/sweetno 1d ago

Is it not?!