A minimal RHEL install does not ship a C compiler. Run gcc on a fresh cloud image and you get command not found, with no make and no headers either, because Red Hat leaves the build toolchain to one package group. Installing it takes one dnf command. Which GCC you get depends on the major release, though: GCC 14 on RHEL 10, GCC 11 on RHEL 9 and GCC 8 on RHEL 8, and that decides whether modern C++ code compiles at all.
This guide shows you how to install GCC on RHEL with the Development Tools group, compile C and C++ test programs, add GCC Toolset for a newer compiler, and fix the two errors you’re most likely to hit. We tested it on fresh, fully updated Rocky Linux 10.2, 9.8 and 8.10 VMs with SELinux enforcing in October 2026, and confirmed the GCC versions on AlmaLinux 10, 9 and 8.
GCC version on each release
Each RHEL major release keeps the same system GCC for its whole life, so the versions below are what dnf gives you on RHEL, Rocky Linux and AlmaLinux alike. Red Hat ships newer compilers beside it as GCC Toolset instead of upgrading the default.
| Release | System GCC | make | gdb | binutils | Newest GCC Toolset | Development Tools group |
|---|---|---|---|---|---|---|
| RHEL 10 | GCC 14 | 4.4 | 16 | 2.41 | gcc-toolset-15 | 261 packages, 680 MB |
| RHEL 9 | GCC 11 | 4.3 | 16 | 2.35 | gcc-toolset-15 (12 to 15 available) | 346 packages, 1.0 GB |
| RHEL 8 | GCC 8 | 4.2 | 8.2 | 2.30 | gcc-toolset-15 (9 to 15 available) | 241 packages, 744 MB |
The compiler column matters more than it looks. GCC 8 has only experimental C++2a support, and GCC 11 accepts -std=c++20 but has no <format> header. A project that builds cleanly on RHEL 10 can therefore fail on the two older releases without a single change to the code. The package counts come from fully updated 2 vCPU VMs, where the install took 57 to 93 seconds from the public mirrors. On a system that is behind on updates, the same transaction also upgrades the packages it depends on, which is why the steps below update first.
Pick the install that matches the job:
gcc gcc-c++ maketo compile your own code- the Development Tools group for autotools builds and RPM packaging
gcc-toolset-15on top of either for C++20 and newer on RHEL 9 or 8
Install GCC on RHEL with the Development Tools group
Every package in the group comes from the default BaseOS and AppStream repositories, so no extra repository is involved and the steps are the same on a subscribed RHEL host and on a rebuild. You need:
- RHEL, Rocky Linux or AlmaLinux 10, 9 or 8 (RHEL registered with
subscription-manager, which is what enables BaseOS and AppStream) - a user with sudo rights
- outbound access to the package mirrors
Bring the system up to date first. The group pulls in hundreds of packages, and on an outdated system the same transaction also upgrades whatever it depends on, which makes it slower and harder to read.
sudo dnf -y upgrade
Next, run dnf group list and confirm Development Tools appears under Available Groups. RPM Development Tools appears in the same list, and it is a different and much smaller group for packaging work, so make sure you pick the right name.
Install the group. The older dnf groupinstall spelling still works on all three releases, so scripts that use it do not need changing.
sudo dnf group install -y "Development Tools"
The group and its dependencies came to 261 packages and 680 MB on disk:
Transaction Summary
==========================================================================================
Install 261 Packages
Total download size: 197 M
Installed size: 680 M
That size surprises people who expected a compiler and make. Most of it comes from the group’s default packages, which pull in a long tail of Perl and font dependencies:
systemtapandvalgrindfor tracing and memory checksasciidocandsource-highlightfor documentation buildsgit,patchutilsanddiffstatfor working with source trees
If you only compile your own code, sudo dnf install gcc gcc-c++ make gives you a working toolchain in 11 packages and 245 MB on the same Rocky Linux 10 system. You can still add the group later without any conflict, so starting small costs nothing.
Check what the group installed
The group splits its packages into mandatory ones, which always install, default ones, which install unless you exclude them, and optional ones, which do not install unless you ask. The definition differs slightly between releases (RHEL 8 adds ctags, elfutils-libelf-devel and perl-Sys-Syslog to the defaults, for example), so print it on your own system.
dnf group info "Development Tools"
The mandatory list is the build toolchain itself, shown here from Rocky Linux 10:
Group: Development Tools
Description: A basic development environment.
Mandatory Packages:
autoconf
automake
binutils
bison
flex
gcc
gcc-c++
gdb
glibc-devel
libtool
make
pkgconf
pkgconf-m4
pkgconf-pkg-config
redhat-rpm-config
rpm-build
rpm-sign
strace
Default Packages:
asciidoc
byacc
diffstat
git
intltool
jna
ltrace
patchutils
perl-Fedora-VSP
perl-generators
pesign
source-highlight
systemtap
valgrind
valgrind-devel
Optional Packages:
cmake
expect
rpmdevtools
Look at where CMake sits. It is optional, so the group does not install it, and plenty of C and C++ projects need it before they will even configure. Add it with sudo dnf install cmake whenever a project ships a CMakeLists.txt.
Now check the compiler itself, because its version decides which language standards you can build against.
gcc --version
You get the GCC 14 system compiler on Rocky Linux 10:
gcc (GCC) 14.3.1 20251022 (Red Hat 14.3.1-4)
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.
The same command printed gcc (GCC) 11.5.0 20240719 (Red Hat 11.5.0-14) on Rocky Linux 9 and gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-29) on Rocky Linux 8. It’s worth checking the rest of the toolchain once as well, because a configure script that rejects an old autoconf or make reports it in terms that are easy to misread.
make --version | head -1; gdb --version | head -1; ld --version | head -1; autoconf --version | head -1; git --version
These are the Rocky Linux 10 results:
GNU Make 4.4.1
GNU gdb (Rocky Linux) 16.3-3.1.el10_2
GNU ld version 2.41-63.el10
autoconf (GNU Autoconf) 2.71
git version 2.52.0
Rocky Linux 9 printed the same gdb and git releases, with an older make, ld and autoconf, and Rocky Linux 8 came out older on all five.
Compile a test program
A one-file program proves the compiler, the C library headers and the linker work together. The examples edit files with vim, and minimal RHEL images only ship vi from vim-minimal, so install the full editor first (or use vi in its place):
sudo dnf install -y vim-enhanced
Make a scratch directory for the test files.
mkdir -p ~/hello && cd ~/hello
Create hello.c in it. The program prints the __VERSION__ macro, so its output also tells you which GCC compiled it, which stops being obvious once a second compiler is installed.
vim hello.c
Paste this C program:
#include <stdio.h>
int main(void) {
printf("Hello from %s\n", __VERSION__);
return 0;
}
Build it with warnings on and run it. -Wall reports the mistakes that otherwise compile silently, so keep it on for test builds.
gcc -Wall -O2 hello.c -o hello && ./hello
A clean build prints no warnings, and the program reports the compiler that produced it:
Hello from 14.3.1 20251022 (Red Hat 14.3.1-4)
For C++, test with a C++20 feature, because that’s exactly where the three releases split. Create hello.cpp.
vim hello.cpp
This program formats its output with std::format from the <format> header:
#include <iostream>
#include <format>
int main() {
std::cout << std::format("C++ standard: {}\n", __cplusplus);
}
Compile it as C++23 and run it. The -std flag is required here, because GCC 11 and GCC 14 default to C++17 with GNU extensions (GCC 8 to C++14).
g++ -std=c++23 hello.cpp -o hellocpp && ./hellocpp
On RHEL 10 the system compiler handles it and prints the C++23 value of __cplusplus:
C++ standard: 202302
On RHEL 9 and RHEL 8 the same file fails, each release with its own error. Neither one means the code is wrong, because both come from the system compiler being older than the language standard, so the fix in both cases is GCC Toolset rather than a code change.
fatal error: format: No such file or directory
This is what GCC 11 on Rocky Linux 9 printed for hello.cpp:
hello.cpp:2:10: fatal error: format: No such file or directory
2 | #include <format>
| ^~~~~~~~
compilation terminated.
The message reads like a missing package, so the natural reaction is to search for a -devel RPM that provides format. There is not one. The C++ library that ships with GCC 11 does not implement std::format, which arrived with GCC 13, so install GCC Toolset as shown in the next section.
g++: error: unrecognized command line option ‘-std=c++23’
GCC 8 on Rocky Linux 8 does not know the flag at all:
g++: error: unrecognized command line option ‘-std=c++23’; did you mean ‘-std=c++03’?
Dropping to C++20 fails the same way, with unrecognized command line option ‘-std=c++20’; did you mean ‘-std=c++2a’?. That suggested -std=c++2a only turns on the experimental slice of C++20 that GCC 8 had in 2018, so it will not build modern code either. Use GCC Toolset here too.
Get a newer GCC with GCC Toolset
GCC Toolset installs a newer GCC and binutils under /opt/rh/gcc-toolset-N/ (on RHEL 8 the toolset also brings its own GDB) and leaves the system compiler alone. That separation is the point: anything that calls plain gcc, RPM builds included, keeps the release’s own compiler, and you opt in to the newer one per shell or per command. On the day we tested, GCC Toolset 15 was the newest on all three releases, and RHEL 9 and 8 still carried the older toolsets too.
dnf list --available 'gcc-toolset-*-gcc'
Rocky Linux 9 showed four toolsets, while Rocky Linux 8 showed seven, going back to GCC Toolset 9. The annobin-plugin lines are compiler plugins that ship alongside each toolset:
gcc-toolset-12-annobin-plugin-gcc.x86_64 11.08-2.el9 appstream
gcc-toolset-12-gcc.x86_64 12.2.1-7.7.el9_4 appstream
gcc-toolset-13-annobin-plugin-gcc.x86_64 12.92-1.el9 appstream
gcc-toolset-13-gcc.x86_64 13.3.1-2.3.el9 appstream
gcc-toolset-14-annobin-plugin-gcc.x86_64 12.88-1.el9 appstream
gcc-toolset-14-gcc.x86_64 14.2.1-13.el9 appstream
gcc-toolset-15-gcc.x86_64 15.2.1-7.1.el9_8 appstream
Install the newest one. It came to 11 packages on Rocky Linux 10, 13 on Rocky Linux 9 and 17 on Rocky Linux 8, where the toolset also brings its own GDB.
sudo dnf install -y gcc-toolset-15
How you switch to it depends on the release, and RHEL 10 is where most older guides go wrong.
Use GCC Toolset on RHEL 9 and RHEL 8
On RHEL 9 and 8 the toolset is a Software Collection, so scl runs one command with the toolset first in PATH.
scl enable gcc-toolset-15 -- g++ -std=c++23 hello.cpp -o hellocpp && ./hellocpp
The file that failed on both releases now builds with GCC 15:
C++ standard: 202302
For a whole shell session, source the toolset’s enable script instead. Your PATH then starts with the toolset directory until you close the shell, so every build in that shell uses GCC 15 without any prefix.
source /opt/rh/gcc-toolset-15/enable
Check which compiler the shell picks up now. If which still shows /usr/bin/gcc, the script was executed instead of sourced, and the PATH change ended with the subshell it ran in.
which gcc && gcc --version | head -1
Both releases now print the toolset compiler:
/opt/rh/gcc-toolset-15/root/usr/bin/gcc
gcc (GCC) 15.2.1 20260123 (Red Hat 15.2.1-7)
The switch lasts only for the shell you sourced the script in, so source it again in every new session that needs the newer compiler.
Use GCC Toolset on RHEL 10
RHEL 10 dropped scl for GCC Toolset. On our Rocky Linux 10 VM gcc-toolset-15 installed cleanly, yet scl enable failed with scl: command not found and /opt/rh/gcc-toolset-15/enable did not exist, which matches Red Hat’s RHEL 10 GCC Toolset documentation. The package installs a wrapper called gcc-toolset-15-env instead, and you put the command to run after it.
gcc-toolset-15-env g++ --version | head -1
The wrapper runs the toolset compiler, while plain g++ stays on GCC 14:
g++ (GCC) 15.2.1 20260123 (Red Hat 15.2.1-7)
Run gcc-toolset-15-env bash to get a Bash shell with the toolset first in PATH (with no arguments the wrapper starts plain sh). In a build script, source /usr/lib/gcc-toolset/15-env.source instead, which is the file the wrapper reads itself. Red Hat’s documentation also marks C++20 and newer as experimental in GCC Toolset 15, with no ABI guarantee for what you build with them, so check that before you ship a C++23 binary to customers.
The toolset does not replace the system C++ runtime either. A binary built with GCC 15 on Rocky Linux 8 still linked against /lib64/libstdc++.so.6, because the toolset links the newer library features into the binary statically. We removed gcc-toolset-15 afterwards and the C++23 binary still ran, so the result works on a plain RHEL 8 host without the toolset.
Install headers for libraries you link against
The Development Tools group gives you the compiler and the C library headers, plus a few -devel packages that its own tools depend on. openssl-devel is one of them: kernel-devel, which the group installs, requires it on RHEL 10 and 9. Most other libraries are not covered, and the compiler error never names the package you are missing. This test program prints the libcurl version it was built against:
vim curl.c
Add the source:
#include <curl/curl.h>
#include <stdio.h>
int main(void){ printf("%s\n", curl_version()); return 0; }
Compile it straight after the group install.
gcc curl.c -o curl-test -lcurl
GCC stops at the include line, and you’ll see the same error for any missing header:
curl.c:1:10: fatal error: curl/curl.h: No such file or directory
1 | #include <curl/curl.h>
| ^~~~~~~~~~~~~
compilation terminated.
To find the package behind a missing header, ask dnf which package owns that path.
dnf provides '*/curl/curl.h'
Rocky Linux 10 names libcurl-devel in AppStream, and on Rocky Linux 8 the same package comes from BaseOS. Every release lists older builds as well (and i686 builds on 9 and 8), which is harmless because dnf install picks the newest. This is the newest x86_64 entry:
libcurl-devel-8.12.1-4.el10_2.7.x86_64 : Files needed for building applications with libcurl
Repo : appstream
Matched from:
Filename : /usr/include/curl/curl.h
Install it and rebuild.
sudo dnf install -y libcurl-devel && gcc curl.c -o curl-test -lcurl && ./curl-test
The output shows how far apart the releases are on the libraries underneath. Rocky Linux 10 printed this:
libcurl/8.12.1 OpenSSL/3.5.8 zlib/1.3.1.zlib-ng brotli/1.1.0 libidn2/2.3.7 libpsl/0.21.5 libssh/0.12.0/openssl/zlib nghttp2/1.68.0 OpenLDAP/2.6.10
On Rocky Linux 9 the same program reported libcurl 7.76.1 on the same OpenSSL 3.5.8, while Rocky Linux 8 reported libcurl 7.61.1 on OpenSSL 1.1.1k. That gap matters if you build on one release and deploy on another. We copied a binary linked against OpenSSL on RHEL 9 to the RHEL 8 VM, and it refused to start with libssl.so.3: cannot open shared object file, so build on the oldest release you deploy to. Some -devel packages live in the CRB repository rather than AppStream. On Rocky Linux and AlmaLinux the EPEL setup guide shows how to enable CRB along with EPEL, and on a registered RHEL system Red Hat’s equivalent is sudo subscription-manager repos --enable codeready-builder-for-rhel-$(rpm -E %rhel)-$(arch)-rpms.
Build software from source
The real test of a toolchain is an autotools build, because one configure and make pass exercises the compiler, the macros and the linker together. GNU Hello is small enough to build in seconds and uses the same build system as most older C projects. The command reads the newest version from the GNU download page, so it keeps working when the next release lands.
cd ~
VER=$(curl -s https://ftp.gnu.org/gnu/hello/ | grep -oE 'hello-[0-9.]+\.tar\.gz' | sort -V | tail -1)
echo "$VER"
At the time of testing the newest release was 2.12.3:
hello-2.12.3.tar.gz
Download, configure and build it. The -j"$(nproc)" flag runs one make job per CPU core.
curl -sLO "https://ftp.gnu.org/gnu/hello/${VER}" && tar xf "${VER}" && cd "${VER%.tar.gz}"
./configure --quiet && make -j"$(nproc)"
On the 2 vCPU lab VMs, configure and make together took 10 to 12 seconds on every release. Run the binary from the build directory.
./hello
It prints the greeting it was written to print:
Hello, world!
If configure stops with a message about a missing library instead, that’s the header problem from the previous section in a different form, and the -devel package for that library is the fix. For your own projects the next pieces are usually version control and a language runtime. Git, Python and Java each have a guide for the same releases, and Go uses this GCC for cgo builds. If you are still learning the language itself, our C and C++ book picks are where we’d start.
Here are the toolchain check and the test programs on the Rocky Linux 10 lab VM:

It shows the gcc version check and the compiled hello program running.
Remove the Development Tools group
Removing the group takes out what the group install pulled in, as long as nothing else depends on it. On Rocky Linux 10 the removal dropped 255 of the 261 packages in 8 seconds, and gcc was gone afterwards.
sudo dnf group remove -y "Development Tools"
Anything you installed by name stays behind. gcc-toolset-15 and vim-enhanced both survived the removal on all three VMs, while openssl-devel went with the group because it had come in with it, so remove the leftovers by name if you want a clean system. That’s also why we’d keep compilers off production servers in the first place. Install the group on a build host or in a container, ship the binary or the RPM, and leave the runtime servers without a toolchain.