Driving Compilers
fabiensanglard.net
fabiensanglard.net
[1]: Clang, on the other hand, is not the case (at least the modern one). The `clang` program is a compiler driver and compiler AND assembler for majority of the platforms.
This framing is more likely to cause confusion than not, I think. `clang` is a compiler driver. `clang -cc1` is the compiler, and `clang -cc1as` is the assembler. They may all be the same executable, but the distinction between the tools is basically the first thing that happens. (Also note that the -cc1/-cc1as option has to be the very first option, it's not recognized in any other position).
Other projects are included in LLVM. Clang is the C/C++ compiler. There is a C standard library, an OpenCL standard library, a C++ standard library (all inventively named lib<language>). There is also a library to support compiler builtins called compiler-rt, and a library to support OpenMP called openmp, and an implementation of C++ parallel executors in pstl. There is also a linker (lld) and a debugger (lldb). There is also a machine code optimizer called bolt, and yet another compiler framework called MLIR. Finally, there are several different Fortran compilers all called flang (don't ask).
Llvm is everywhere. There’s a good chance llvm compiled some or all of the software you’re using to read this comment.
I mean, that's not the reason Rust is as fast as C. It's because Rust semantically doesn't include mandatory slower things.
The compiler it uses is an implementation detail.
um, gcc does all those things.
- in the process
- in a fork of the process
- in a child process
The outcome to me is the same.
> is one of my favorite things to tell newbie compiler engineers.
Being ignorant is cute until its your job to be an engineer and fix problems.
All `gcc` does is parse come command-line options and then invoke other programs to do the actual job of preprocessing, compiling, assembling, and linking.
[1]: https://github.com/fabiensanglard/dc/blob/1b9cbd081fcc530488...
I do. There isn't a viable competitor to productivity tools like Office 365 (and no, LibreOffice and Thunderbird, while decent, do not cut it), ease of gaming (I'd rather play games natively, than fiddle with Wine), HiDPI support, PowerShell, Visual Studio (sue me: it's better than gcc + painful array of binutils + perf), etc.
Maybe it's Stockholm syndrome, but I have Arch installed too (on its own dedicated drive to boot), and I use it a lot less than I do Platform™.
One comment though:
> The compiler ingests one .c and outputs one .o. It has a low memory footprint. The linker on the other side, must use all the .o files at once to generate the executable. Keeping all these .o in memory would stress the system too much on big projects.
This is a really weak argument that does not make a lot of sense.
The major advantage of separate object files is avoiding recompilation of modules that haven’t changed.
In fact, compilers like Jonathan Blow’s Jai seem to get massive performance improvements by treating everything as a single compilation unit and avoiding writing a bunch of object files only to call the linker on all of them.
My own tips after writing a custom build system for C++
- the order of objects and -l flags to the linker matters! I remember being very surprised / frustrated by this.
- Sanitizers are built into compilers and trivial to use. Learn to use AddressSanitizer simply with -fsanitize=address! Ironically I think many people don't use it because their build system doesn't have good build variants (dbg, opt, asan), or they don't know how to configure the build system. Plain make generally isn't good enough.
- Some flags have to be passed to both the compiler and link steps, and others don't. I mostly figured this out by trial and error, and the error messages aren't great.
- You can compile and link in one driver invocation (c++ -o), or you can build each object separately and link (c++ -c).
I thought the former might be faster, and it seems simpler, but there doesn't seem to be any real advantage (edit: this post explains why -- it's literally subprocessing, which you can do better from a shell or build system). The latter is more common because it supports parallel and incremental builds.
Some options, I think -ftime-trace for Clang, which outputs JSON compile time traces, don't even respect the first style of building.
- Spending some time with a plain shell script and the compiler isn't a bad way to learn. Now I can finally read all those crappy long error commands from big build systems. The most common and useful flags are -I to add to the #include path and -D to define a preprocessor symbol.
---
edit after skimming the whole thing: This is really excellent, should be titled "Compilers: The Missing Manual".
I have actually looked at the manuals, e.g. https://gcc.gnu.org/onlinedocs/gcc-13.1.0/gcc/Invoking-GCC.h... but they seem to be missing the high level conceptual overview.
They also seem to be missing the name "driver", which is important, even though I have encountered a page about that before. It seems to be in a separate "GCC Internals" doc:
https://gcc.gnu.org/onlinedocs/gcc-4.3.2/gccint/Driver.html#...
Other notes: I should have been using the -v flag to the driver all along! That's a little embarrassing.
Also it's good to realize that g++ and gcc are both drivers, and the former sets the -I path to the location of the C++ stdlib and so forth.
Looks like lots of great examples of 'readelf' as well, which I'll go over again.
It is kind of crazy how people generally pick this up piecemeal over so many years ... A big problem in my mind is that it's usually wrapped in GNU make or CMake or IDE configs, which add their own line noise on top of the raw driver invocations. Which in turn have a ton of logic before the actual tools are invoked.
This took so long for me to actually find out... and then beat most build systems into submission because they have no ability to configure priority of linkage.
One small copy correction: In the linker (4/5), you mentioned "Let's compile hello.c and peek inside hello.o.". But you are actually peeking the a.out.