The road to hell is paved with good intentions and C++ modules (2023)
nibblestew.blogspot.com
nibblestew.blogspot.com
To sum the link behind that statement up: The default output format used by the GNU Compiler is for GNU Make, a ninja compatible format can be generated but is not the default. The blog author considers this default broken, GNU developers consider this behavior correct.
The suggested flag was not for a "ninja compatible format", but to exclude things from the makefile snippet that ninja doesn't understand (yet). It would exclude necessary information for modules to function.
Problem is, the new syntax used by the compiler's -MF output violates current-day expectations by both compilers and build tools as to what those snippets contain, and it'll be a while to sort out what the acceptable syntax would be. As noted, Clang doesn't use this file to propagate the information at all.
> gcc (and other compilers like clang) support emitting dependency information in the syntax of a Makefile.
But didn't quite make it to the second paragraph:
> (Ninja only supports the limited subset of the Makefile syntax emitted by compilers.)
Obviously Ninja can't parse and execute full Makefile syntax because then it would just be Make. But the actual information in depfiles doesn't require the full Makefile syntax; only a subset of it. And compilers output that subset, so Ninja can read it.
The issue is it's a de facto subset - a "depfile syntax" that exists by convention but the GNU authors have broken this format. As I said, unless there's a good reason to break it, that's just shitty behaviour.
My point is that I wouldn't jump to conclusions as to why they did that. I would dig further to see what the reasons were (which is not a simple google search) and what Ninja developers could do about that.
Another important point is that they didn't break Ninja compatibility in general, but only in the specific case of C++ modules; and they also didn't break compatibility with non-GNU implementations of Make.
That seems to be the problem, the information introduced for the module support[1] apparently cannot be handled with just the dependency lists alone and the changes suggested in the ticket would still leave the additional CXX_IMPORTS += M1.c++m syntax. One of the commenters on the ticket also wrote a specification for a json based dependency format[2].
[1]https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p16...
[2]https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p16...
Best designs are produced by small, tightly-knot, often one-person design teams. Examples: Unix, Clojure, SQLite, Boeing-747, Westminster Palace in London.
Sometimes a small team with a cohesive vision keeps on attracting like-minded people or matching ideas, and the project grows with contributions from a large number of people. The key part of every such success is the vetting process. Examples: Python, Ruby, FreeBSD and OpenBSD.
Worst designs with most glaring, painful, expensive, even tragic shortcomings are produced by large committees of very important people from huge, very (self-)important companies, agencies, departments, etc. Each of them has an axe to grind or, worse, a pet peeve. Examples: PL/I, Algol-68, the Space Shuttle (killed two crews because the escape system was removed from the quite sane initial design); to a lesser degree, it's also HTML, CSS, and, well, C++ to a large degree :( The disease has a name [1].
Sometimes a relatively small and cohesive team in a large honking corporation produces a nice, cohesive design, like this happened to Typescript, certain better parts of CSS, and some of the better parts of C++. This may sometimes make a false impression that "design by committee" sometimes works.
Not sure about Unix… it's gone through a lot at this point and obviously it's a committee now.
Of course, later the decoherence increased; I'd say that the adoption of Berkeley Sockets is one of the inflection points where severely different architectural principles came into play.
IDK about WASM though.
[1]: https://en.m.wikipedia.org/wiki/Joan_L._Mitchell#Career_and_...
Unlike C++, C also remained a simple language (which is definitely a side effect of the "conservatism" of the C committee).
The mental overload of some small things added every 10th year and in use 20 years later is how I like it.
If you crave excitement, there's Rust and Go. (And I say that in the vein of "may you live in exciting times". ;D)
Oh, and there's D if you want to immersively roleplay like you're in an alternate timeline, like Infinite Jest or something.
Hey, pass me more OOKoolaid.
No, it's fine; all the bottles say "Expires 2005", but it's still good.
And more importantly, not breaking old, old codebases, which is a very critical problem.
Obj-C++ and D don't have critical codebases, because there is just so much less code. Apple does what they want.
Like Stroustrup says, when a language is not used, it won't generate problem: I gues his quote is often quite overlooked, but it's very very true.
Compilers are a difficult topic.
I don't think they intended to make a mess, I think that C++ compilers are just massive things with massive codebases, and several different companies who have to agree on one language.
There are many non-trivial obstacles.
Some parts of the new std features were copied from Python, which is good, a semantic and naming a lot of people already know. Yet some weirdo decided to half copy the naming scheme of APL and we end up with functions named "iota". Seriously. What. The.
Don't get me started on features added in C++17 and deprecated 2 versions later.
Don't ask also why they decided to rename universal references by forwarding references while the former makes sense and the latter none, just because they were pissed to not have named it first.
All I want now, for the future of C++, is a Circle-like approach. I want to be able to selectively disable and replace legacy behavior and syntax, per file, so that at last we can have the language evolve.
They are currently suffering from not having proper field experience on many features before setting them into the standard.
But developers will follow compiler. I sure would use circle if it was not a proprietary compiler.
clang is even lagging behind in ISO vs GCC, because most compiler vendors that fork it, mostly care about the backend, while two former major contributors are now are focused on their own LLVM based languages.
Which is why, those that care about portable code can at best use C++14 or C++17, while many libraries still target C++11.
So how do expect those two compilers to set the direction C++ should be?
Yes, it's three: clang, gcc and msvc.
Just because HN folks don't used them, doesn't make them irrelevant in the set of companies and indivuals that seat at WG 21 table.
That is why I used the expression "tunnel vision for desktop and FOSS UNIX clones.".
I mean, err, international bureaucracy.
every proposal for C/C++ modules feels like it's by someone who has not used a working module system and doesn't believe it's truly possible to create
I almost feel like they should give up. IMO Rust and Zig have made C/C++ a legacy language. Except in some specific areas where Rust doesn't have mature libraries (GUIs & games mostly) you'd be silly to start a new project in C++.
Migrating existing C++ projects to modules likely isn't worth the enormous effort, and the days of starting new C++ projects are numbered... so why bother?
- scientific/numerical computing (super mature)
- domain-specific high performance computing (C++ is for better or worse extremely flexible)
- weird CUDA use cases (feels very native in C++)
- game dev as you mention
- probably much much more
C++ to me feels more like a meta-language where you go off to build your own kind of high performance DSL. Rust is much more rigid, which is probably a good thing for many “standard” use cases. But I’m sure there will always be a very very long tail of these niche projects where the flexibility comes in handy.
This Reddit comment captures my reasons pretty well: https://www.reddit.com/r/rust/comments/1arys3z/comment/kqoak...
Additionally while they keep being built on top of C++ compiler infrastructure, C++ isn't going away.
Plenty of industry are stuck on C++ < ISO C++20, just like they are stuck in Python 2, Java 8, .NET Framework 4.x,...
Industry moves at snail pace adopting new languages, or versions thereof.
better to lose a few libraries to modernization than the whole language community
I might be completely wrong here, but reading this reminded me of barrel files [1] in JS/TS projects, which are an absolute nightmare. I put together a little visualization a while back that demonstrated how much extra work is required to resolve the module graph if you forward exports, and it is orders of magnitude more than just importing something directly from the file where it is exported. If this is also the case for C++ modules, I'd like to buy the author a beer or six.
The road to hell is paved with good intentions and C++ modules - https://news.ycombinator.com/item?id=37891898 - Oct 2023 (2 comments)
Looks like still no, although Intel provides yet another partial implementation: https://en.cppreference.com/w/cpp/compiler_support/20
'A Ninja file is static, thus we need to know a) the compilation arguments to use and b) interdependencies between files. The latter can't be done for things like Fortran or C++ modules. This is why Ninja has a functionality called dyndeps. It is a way to call an external program that scans the sources to be built and then writes a simple Makefile-esque snippet describing which order things should be built in. This is a simple and understandable step that works nicely for Fortran modules but is by itself insufficient for C++ modules.'
...
'Let's start by listing the requirements [for modules]:
All command lines used must be knowable a priori, that is, without scanning the contents of source files
Any compiler may choose to name its module files however it wants, but said mapping must be knowable just from the compiler name and version, i.o.w. it has to be documented
Changing source files must not cause, by itself, a reconfiguration, only a rescan for deps followed by a build of the changed files
The developer must not need to tell which sources are which module types in the build system, it is to be deduced automatically without needing to scan the contents of source files (i.e. by using the proper file extension)
Module files are per-compiler and per-version and only make sense within the build tree of a single project
If module files are to be installed, those are defined in a way that does not affect source files with modules that do not need installing.
Fortran modules already satisfy all of these.'
Also, I never really liked cmake but this looks really bad.
The idea behind modules is that since they are part of the language, the compiler for the language understands modules and follows the dependencies. All module-related tooling, like incremental builds, is hooked through the compiler. You don't use make or external dependency generators.
If someone does need a dependency generator for whatever reason, the compiler has to provide that function. You give the compiler the proper option to spit out dependencies, point it at the root module of the program, and let it do its thing.
No argument from me :)
> The idea behind modules is that since they are part of the language, the compiler for the language understands modules and follows the dependencies. All module-related tooling, like incremental builds, is hooked through the compiler.
I am not sure I follow. The compiler still compiles one file each time it is run, so we need a first pass to determine the dependency tree and what can be compiled in which order, right? Even if that first pass uses the compiler itself (doing only enough parsing to see what is needed).
> You give the compiler the proper option to spit out dependencies, point it at the root module of the program, and let it do its thing.
Nowadays, gfortran can generate Makefile fragments with the dependencies, but it was not always the case. This is why there are a handful of small tools to do it and makedepf90 is one of them (it’s a small Fortran program with a rudimentary parser). There are also other compilers that don’t do it properly.
For quite some years, there had been no gfortran, only g95.