Joking aside, we owe a great deal to Richard Stallman. He is truly the 'Godfather' or founding father of the FOSS (Free and Open-Source Software) movement.
Among his most impactful contributions is the GCC (GNU Compiler Collection), along with its essential derivatives such as G++.
This page is about the GCC compiler.
Before diving into some interesting things related to the GCC compiler, let's bring a tribute to the man who created Softwareland as we know it per today. Without Richard, the landscape would have been a lot different. And I mean: a lot...
I saw this nice summary of the FOSS pillars (taken from here):
The Pillars of Free Software: The Four Essential Freedoms
Central to Stallman’s philosophy and the GNU Project are the four essential freedoms that define free software:
Freedom 0: The freedom to run the program as you wish, for any purpose. This freedom underscores the fundamental right of users to utilize software without restriction, whether for personal, educational, commercial, or any other endeavor.
Freedom 1: The freedom to study how the program works, and change it so it does your computing as you wish. This requires access to the source code, enabling users to understand, adapt, and improve the software to meet their specific needs.
Freedom 2: The freedom to redistribute copies so you can help your neighbor. This promotes the sharing of software, fostering a collaborative environment where knowledge and tools can be disseminated freely.
Freedom 3: The freedom to distribute copies of your modified versions to others. This allows for the continuation and expansion of the collaborative effort, ensuring that improvements and adaptations benefit the entire community.
These freedoms are not mere suggestions; they are the bedrock upon which the free software movement is built. Stallman’s unwavering commitment to these principles has been instrumental in shaping the ethical and practical landscape of software development and distribution.
I couldn't say better (of course, I couldn't...)
I recently tested the new Raspberry Pi OS called Trixie and I saw they are using a very recent version of the GCC compiler version:
pi@trixie2:~/mystuff/immediatec/src $ gcc-14 --version
gcc-14 (Debian 14.2.0-19) 14.2.0
Copyright (C) 2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
But what if you want to use an older version of GCC, say, version 10?
It's possible to have more than one GCC compiler on your Linux (so, also Raspberry Pi) distro. Here's how to do it.
First of all, as you can see on the command I gave before, I had to type gcc-14 to know the version of the default GCC compiler for Trixie.
But if GCC version 14 is the default GCC compiler for Trixie, why did I have to type gcc-14 and not just gcc? Well, I already installed gcc-10 too and made that one the default GCC compiler.
So, if I type gcc --version, I get the following on my Raspberry Pi system:
pi@trixie2:~/mystuff/immediatec/src $ gcc --version
gcc (Debian 10.2.1-6) 10.2.1 20210110
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
This is the - currently default - GCC compiler version 10.
Of course, I could also have typed gcc-10 --version. That would have returned exactly the same result.
To add an older compiler, you first have to decide what compiler you want. In my case, I wanted the same compiler that was use on the Raspberry Pi OS Bullseye. The GCC compiler version used for Bullseye was 10.2.1-6.
The less intruding way is to download all related .deb files from the Debian snapshot archive or Debian packages site.
The latter on (Debian package site) is the easiest one to me.
Best practice: create a directory on the computer where you put all GCC 10 related files (before you copy them to the Raspberry Pi).
Go to the package site and go to the bottom of the page. Then click the arm64 link which will bring you to the download page itself. Select an FTP site of your choice and the download should start. Always verify the checksum if you have the chance to do so.
Here is a list (including links) of all the .deb files you need to get the complete GCC version 10 compiler:
gcc-10-base (arm64, Bullseye)
gcc-10 (arm64, Bullseye)
g++-10 (arm64, Bullseye)
cpp-10 (arm64, Bullseye)
libgcc-10-dev (arm64, Bullseye)
libstdc++-10-dev (arm64, Bullseye)
libasan6 (arm64, Bullseye)
libtsan0 (arm64, Bullseye)
Once all of the above .deb files are downloaded, move/copy them to a dedicated directory on the Raspberry Pi.
If all are available on the Raspberry Pi, run the following two commands from within that dedicated directory:
sudo dpkg -i *.deb
sudo apt -f install
The first command will install all the .deb files, the second command will fix any remaining dependency, should there be one or more...
Once the GCC 10 compiler is installed, it can be used next to the default GCC 14 compiler.
You can each and every time run the command gcc-10 ... or gcc-14 ... but that's a bit cumbersome.
You can also run the update-alternative command (just like you can for different flavours of Java). Therefore, you first have to install the two compiler versions like so:
sudo update-alternatives --install /user/bin/gcc gcc /usr/bin/gcc-10 10
sudo update-alternatives --install /user/bin/gcc gcc /usr/bin/gcc-14 14
sudo update-alternatives --config gcc
The last command is to choose your default GCC compiler. You will see a list and numbers. Choose the number next to the compiler you want as default.
sudo update-alternatives --install /user/bin/g++ g++ /usr/bin/g++-10 10
sudo update-alternatives --install /user/bin/g++ g++ /usr/bin/g++-14 14
sudo update-alternatives --config g++
The last command is to choose your default G++ compiler. You will see a list and numbers. Choose the number next to the compiler you want as default.
It looks like this when running the --config command:
pi@trixie2:~/mystuff/immediatec/src $ sudo update-alternatives --config g++
There are 2 choices for the alternative g++ (providing /usr/bin/g++).
Selection Path Priority Status
------------------------------------------------------------
0 /usr/bin/g++-14 14 auto mode
* 1 /usr/bin/g++-10 10 manual mode
2 /usr/bin/g++-14 14 manual mode
Press <enter> to keep the current choice[*], or type selection number:
You can keep the current choice by pressing Enter or you can change it by typing a number. Here, it can be 0, 1 or 2.
Same mechanism is used for the GCC compiler above.
To know if the GCC compiler is using 64-bit mode, run the following command:
gcc-10 -dM -E - < /dev/null | grep __SIZEOF_INT128__
or
gcc-14 -dM -E - < /dev/null | grep __SIZEOF_INT128_
You should see #define __SIZEOF_INT128__ 16 if it does.
I recently had problems to find out which include files were taken into account when looking at one of the immediateC files named icg.h
To be able to do that, you can ask the GCC compiler to only preprocess the file and not compile it. You do have to specify a -o parameter but you have to reroute it to /dev/null. If you don't pass the -o flag, GCC just spits out pages of gibberish.
Since the output is not sent to stdout but to stderr, you have to apply the special 2> construction if you want to get the output written to a file.
The complete command is:
gcc -E -H <file> -o /dev/null 2> <output_file>
Example:
gcc -E -H icg.h -o /dev/null 2> header_flow.txt
Once the file is generated, you can nicely see what include files are used and how they're related to each other. Every new include level is represented by a . (dot) like so:
pi@trixie2:~/mystuff/immediatec/src $ gcc -E -H /usr/local/include/icg.h -o /dev/null 2> output.txt
. /usr/include/signal.h
.. /usr/include/features.h
... /usr/include/features-time64.h
.... /usr/include/aarch64-linux-gnu/bits/wordsize.h
.... /usr/include/aarch64-linux-gnu/bits/timesize.h
... /usr/include/aarch64-linux-gnu/sys/cdefs.h
.... /usr/include/aarch64-linux-gnu/bits/wordsize.h
.... /usr/include/aarch64-linux-gnu/bits/long-double.h
... /usr/include/aarch64-linux-gnu/gnu/stubs.h
.... /usr/include/aarch64-linux-gnu/bits/wordsize.h
.... /usr/include/aarch64-linux-gnu/gnu/stubs-lp64.h
.. /usr/include/aarch64-linux-gnu/bits/types.h
First level has one dot, second level two dots and so on...
This way, it's very easy to see how the include tree is going for the given file.
Note that the file you pass to the gcc command can be a header file or a C file.