GCC
GNU Compiler Collection
package (rpm) | description | contents |
---|---|---|
gcc | GNU Compiler Collection (including C support) | gcc front ends for C language (cc is symbolic link to gcc )
|
glibc | GNU implementation of C Standard Library | libc.so.6 and other standard libraries |
gcc-c++ | GNU C++ support for GCC | g++ front ends for C++ language (c++ exactly to same file as g++ )
|
libstdc++ | GNU implementation of C++ Standard Library | libstdc++.so.6 |
gcc-gfortran | GNU Fortran support for GCC | gfortran front ends for Fortran language
|
cpp | GNU C Preprocessor | cpp (don't confuse with C++)
|
binutils | GNU collection of Binary Utilities | as (assembler), ar (archives), ld (linker), etc.
|
Documentation
GCC online documentation and GCC manual
- 3 GCC Command Options
- 3.1 Option Summary or A.1 Option Index
- 3.2 Options Controlling the Kind of Output
- 3.9 Options to Request or Suppress Warnings
- 3.12 Options That Control Optimization
- 3.14 Options Controlling the Preprocessor
- 3.16 Options for Linking
- 3.17 Options for Directory Search
- 3.18 Options for Code Generation Conventions
- 3.19 GCC Developer Options
glibc manual: multi pages, all-in-one page
binutils docs
- ld(1) linker: multi pages, all-in-one page
- ar(1) archive: no docs pages
gcc 5 | 2015-04 | default mode for C is now | -std=gnu11 | instead of | -std=gnu89 | gcc [5, 6) | gnu11, gnu++98 |
gcc 6 | 2016-04 | default mode for C++ is now | -std=gnu++14 | instead of | -std=gnu++98 | gcc [6, 8) | gnu11, gnu++14 |
gcc 8 | 2018-05 | default mode for C is now | -std=gnu17 | instead of | -std=gnu11 | gcc [8, 11) | gnu17, gnu++14 |
gcc 11 | 2021-04 | default mode for C++ is now | -std=gnu++17 | instead of | -std=gnu++14 | gcc [11, 15) | gnu17, gnu++17 |
gcc 15 | 2025-04 | default mode for C is now | -std=gnu23 | instead of | -std=gnu17 | gcc [15] | gnu23, gnu++17 |
General
simple.c |
---|
#include <stdio.h>
int main()
{
printf("Hello\n");
return 0;
}
|
muke.h | muke.c | program.c |
---|---|---|
#ifndef MUKE_H
#define MUKE_H
void print_hello(void);
#endif
|
#include <stdio.h>
#include "muke.h"
void print_hello(void)
{
printf("Hello from muke\n");
}
|
#include "muke.h"
int main()
{
print_hello();
return 0;
}
|
You can download all files from here muke_gcc.tar.gz.
When you invoke gcc(1), it normally does preprocessing, compilation, assembly and linking (always in that order). File name suffix determines what kind of compilation is done (only C language for example): .c
C source code that must be preprocessed and .h
C (or C++) header file to be turned into a precompiled header.
# "all in one" building C program (preprocessing, compilation, assembly and linking)
$ gcc simple.c # created a.out file
# store the usual "temporary" intermediate files permanently (try with -v
option, aka verbose)
$ gcc -save-temps simple.c # created a-simple.i, a-simple.s, a-simple.o and a.out files (in this order)
- C source file simple.c is preprocessed to a-simple.i (preprocessed C source code file).
- Preprocessed source file a-simple.i is compiled to a-simple.s (assembler source code file).
- Assembler source file a-simple.s is assembled to a-simple.o (object file, ELF LSB relocatable).
- Object file a-simple.o is linked to a.out (final executable program file, ELF LSB executable, dynamically linked).
# "manually" invoking each step
# try with -v
option; print the commands executed to run the stages of compilation.
$ gcc -E simple.c > simple.i # standard output redirect to simple.i file
# 1. '-E' Stop after the preprocessing stage; do not run the compiler. The output is preprocessed source code.
$ gcc -S simple.c # created simple.s file
# 2. '-S' Stop after the stage of compilation; do not assemble. The output is an assembler code file.
$ gcc -c simple.c # created simple.o file
# 3. '-c' Compile or assemble the source files, but do not link. The output is an object file.
$ gcc simple.o # created a.out file
# 4. Object file is linked to final executable program file.
$ file simple.i simple.s simple.o a.out simple.i: C source, ASCII text simple.s: assembler source, ASCII text simple.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=7160d69f809ef189994bd519e400d1df81b1e1b8, for GNU/Linux 3.2.0, not stripped
Linux tools for analyzing the contents of Executable and Linkable Format (ELF) object files: nm(1), objdump(1) and readelf(1) (all provided by binutils package) or elfutils purely for Linux (written by Ulrich Drepper from RedHat). More info about GNU Binutils. See also The 101 of ELF files on Linux: Understanding and Analysis.
gcc
with -x
option can specify explicitly the language for the following input files (rather than letting the compiler choose a default based on the file name suffix). See also What is the difference between g++ and gcc?.
gfortran => gcc -x f95 -l gfortran -shared-libgcc program.f -v g++ => gcc -x c++ -l stdc++ -shared-libgcc program.cpp -v
Libraries
- Program Library HOWTO
- Developing C and C++ applications in RHEL 9
- Shared libraries with GCC on Linux
Object code (.o
extension) is created by compiling the source code with a compiler. This is an intermediate form. Executable code (without extension) is created by linking object code and libraries with a linker. It is possible to run gcc
so that it performs only compiling, only linking, or both compiling and linking in a single step.
# compile and linking in one step $ gcc -o program0 program.c muke.c # created program0 file # compiling and linking in two steps $ gcc -c program.c muke.c # createdmuke.o
andprogram.o
files, compiling the source with a compiler $ gcc -o program1 program.o muke.c # created program1 file, linking object code and libraries with a linker # files program0 and program1 are absolutely identical, see also #build-id section about comparing programs
In this example program
use C Standard Library function printf(3) (in muke.c source file) provided by libc.so shared (object) library. Linux tool ldd(1) print shared object (shared libraries) dependencies.
NOTE ldd
can execution of the program (not safe) and therefore never employ ldd
on an untrusted executable. A safer alternative when dealing with untrusted executables is $ objdump -p /path/to/program | grep NEEDED
. However, that this alternative shows only the direct dependencies of the executable, while ldd
shows the entire dependency tree of the executable.
NOTE libtree(1) print shared object dependencies as a tree (provided by libtree-ldd RPM package).
$ ldd program0 linux-vdso.so.1 (0x00007ffecaf83000) libc.so.6 => /lib64/libc.so.6 (0x00007f679241d000) # function printf(3) provided by libc.so.6 /lib64/ld-linux-x86-64.so.2 (0x00007f6792614000) $ objdump -p program0 | grep NEEDED NEEDED libc.so.6 $ file program0 program0: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID, for GNU/Linux 3.2.0, not stripped
Normally when we compile a program, we would have one object file per piece of source code, and then these would be linked into a single executable binary. While this is a perfectly valid way to compile programs, some issues can come into play when compiling large programs, or when reusing functions in multiple programs, which we can manage this with libraries.
We have a choice of using dynamic or static linking when building applications with fully compiled languages. Dynamic libraries are available as shared objects (.so
extension) for dynamic linking. They are a form of an executable file. Static libraries are available as archive files (.a
extension) for static linking. They contain a group of object files. Static linking means that the library code is copied into your executable file at compile time, while dynamic linking means that the library code is loaded into memory at run time. Static linking makes libraries part of the resulting executable file. Dynamic linking keeps these libraries as separate files. Static linking is not recommended.
# creating static library (archive file libmuke.a) for static linking, not recommended
$ gcc -c muke.c # created muke.o file
$ ar rcs libmuke.a muke.o # ar(1)
$ file libmuke.a
libmuke.a: current ar archive
$ ldd libmuke.a
not a dynamic executable
$ nm libmuke.a # or try: ar tv libmuke.a
muke.o:
0000000000000000 T print_hello
U puts # NOTE gcc (by default) optimize function printf(3) into puts(3)
# static linking
$ gcc -static -o program2 program.c libmuke.a # static library libc.a is provided by glibc-static RPM package
$ file program2
program2: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID, for GNU/Linux 3.2.0, not stripped, too many notes (256)
$ ldd program2
not a dynamic executable
# program2 statically linked with libmuke.a and libc.a, useful only in specific cases
# static archive library (libmuke.a) is just a collection of *.o files which were compiled separately (muke.o) $ gcc -o program3 program.c libmuke.a $ file program3 program3: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID, for GNU/Linux 3.2.0, not stripped $ ldd program3 linux-vdso.so.1 (0x00007fff8b3db000) libc.so.6 => /lib64/libc.so.6 (0x00007fd7617c5000) /lib64/ld-linux-x86-64.so.2 (0x00007fd7619c8000) # program3 with libmuke.a which contains object code muke.o and which is dynamically linked with libc.so # files program3 and program0 (or program1) are absolutely identical
# creating dynamic library (shared object libmuke.so) for dynamic linking
$ gcc -c -fPIC muke.c # created muke.o (position-independent code) file
$ gcc -shared -o libmuke.so muke.o
$ file libmuke.so
libmuke.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID, not stripped
$ ldd libmuke.so
linux-vdso.so.1 (0x00007ffeb6a9d000)
libc.so.6 => /lib64/libc.so.6 (0x00007f9d16c08000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9d16e10000)
# dynamic linking
$ gcc -o program4 program.c libmuke.so
$ file program4
program4: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID, for GNU/Linux 3.2.0, not stripped
$ ldd program4
linux-vdso.so.1 (0x00007ffc5a3c3000)
libmuke.so => not found # why 'not found' see below
libc.so.6 => /lib64/libc.so.6 (0x00007fa32c8b5000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa32cab8000)
Using a dynamic library
Dynamic libraries are available as standalone executable files, required at both linking time and run time. They stay independent of your application executable file.
# linking with a dynamic (shared) library $ gcc program.c -lmuke #-l
search the library namedmuke
(libmuke.{so,a}) when linking usr/bin/ld: cannot find -lmuke: No such file or directory collect2: error: ld returned 1 exit status $ gcc program.c -L. -lmuke #-L
add directory . (current) to the list of directories to be searched for-l
gcc
recognizes both dynamic and static libraries and (by default) prefers dynamic linking. When the -lmuke
option is encountered, gcc
will first attempt to locate a shared object (libmuke.so file) containing a dynamically linked version of the muke
library, and then look for the archive file (libmuke.a file) containing a static version of the library.
$ ./a.out ./a.out: error while loading shared libraries: libmuke.so: cannot open shared object file: No such file or directory $ ldd a.out | grep muke libmuke.so => not found
Dynamic loader cannot find the shared library (file libmuke.so is not in the standard location). When a program is linked against a dynamic library, the resulting program must always load the library at run time. There are many options for locating (available at run time) the library:
- using
rpath
value stored in the executable file
Therpath
is a special value saved as a part of an executable file when it is being linked. Later, when the program is loaded from its executable file, the runtime linker will use therpath
value to locate the library files. More info about rpath.
$ gcc program.c -L. -lmuke -Wl,-rpath=. # gcc link option:-Wl,option
pass option as an option to the linker (gcc
invokesld
linker on the fly) # do not add a space after the comma in the-Wl,option
# ld (linker) option:-rpath
add directory . (current) to the runtime library search path $ ldd a.out | grep muke libmuke.so => ./libmuke.so (0x00007f8edab00000)
- using
LD_LIBRARY_PATH
environment variable
If norpath
is found in the program's executable file, the runtime linker will use theLD_LIBRARY_PATH
environment variable. This value should represent the path where the shared library objects are located.
$ gcc program.c -L. -lmuke $ ldd a.out | grep muke libmuke.so => not found $ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH $ ldd a.out | grep muke libmuke.so => ./libmuke.so (0x00007f5af34af000) $ unset LD_LIBRARY_PATH $ ldd a.out | grep muke libmuke.so => not found $ cp libmuke.so /tmp $ export LD_LIBRARY_PATH=/tmp:$LD_LIBRARY_PATH $ ldd a.out | grep muke libmuke.so => /tmp/libmuke.so (0x00007fbf468d4000)
- placing library into the default directories
More info ld.so(8), ldconfig(8) and ld(1).
$ ld --verbose | grep -i SEARCH
SEARCH_DIR("=/usr/x86_64-redhat-linux/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/x86_64-redhat-linux/lib"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");
# libraries recognized by the dynamic linker (file /etc/ld.so.conf and dir /etc/ld.so.conf.d/)
$ ldconfig -v # or -p
Others
build-id
build-id
Unique Identification of Binaries
- https://sourceware.org/binutils/docs/ld/Options.html (
ld
linker--build-id
option) - Developer Guide in RHEL 6 (section build-id)
Each executable or shared library built with gcc
is assigned a unique identification 160-bit SHA-1 string, generated as a checksum of selected parts of the binary. This allows two builds of the same program on the same host to always produce consistent build-ids and binary content.
gcc
(by default) invokes linker (ld
over gcc internal collect2
utility) with --build-id
option (try gcc -v
to see). Option --build-id
request the creation of a .note.gnu.build-id
ELF note section, an identifier (by default 160-bit SHA1 hash) that uniquely identifies the output file.
$ file /usr/bin/bash /usr/bin/bash: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=e3b0fdf454b9c1914e86f32d900a6ee5daa185f1, for GNU/Linux 3.2.0, stripped $ readelf --notes /usr/bin/bash # readelf from binutils $ eu-readelf --notes='.note.gnu.build-id' /usr/bin/bash # eu-readelf from elfutis (more featureful) Note section [ 3] '.note.gnu.build-id' of 36 bytes at offset 0x388: Owner Data size Type GNU 20 GNU_BUILD_ID Build ID: e3b0fdf454b9c1914e86f32d900a6ee5daa185f1
$ gcc -o programAB program.c muke.c
$ gcc -o programBA muke.c program.c
# file size of programAB and programBA is identical, but files are different (i.a. different build-id
)
$ eu-readelf --notes='.note.gnu.build-id' programAB | grep 'Build ID'
Build ID: 83c61d5f9739752fcfadcf80199a271b919f5b69
$ eu-readelf --notes='.note.gnu.build-id' programBA | grep 'Build ID'
Build ID: 4eec135d9fe7c70d29d9203bcd9f0855d17edaca
# SHA-1 checksum of the binaries is different, object code parts (program.o and muke.o) in different order
GCC discovery options
- discovery options
$ echo 'int main(){return 0;}' | gcc -x c -v - #-Q
$ gcc -Q --help=common $ diff <(gcc -Q --help=optimizers) <(gcc -Q --help=optimizers -O2) # NOTE insteaddiff
trysdiff -s
$ diff <(gcc -Q --help=warnings) <(gcc -Q --help=warnings -Wextra)
- preprocessor macros
- https://gcc.gnu.org/onlinedocs/cpp/Predefined-Macros.html
- https://sourceforge.net/p/predef/wiki/Home/
- https://en.cppreference.com/w/c/preprocessor/replace
See also GCC dump preprocessor defines.
$ gcc -E -dM -x c /dev/null # or to same: gcc -E -dM - < /dev/null # or: echo | gcc -dM -E - # is to same as $ cpp -dM /dev/null # or to same: cpp -dM < /dev/null # or: echo | cpp -dM $ echo '#include <unistd.h>' | gcc -E -dM -x c - | grep -i POSIX_VERSION #define _POSIX_VERSION 200809L $ echo '#include <sqlite3.h>' | gcc -E -dM -x c - | grep -i SQLITE_VERSION #define SQLITE_VERSION_NUMBER 3045001 #define SQLITE_VERSION "3.45.1" $ echo '#include <limits.h>' | gcc -E -dM -x c - | grep -i PATH_MAX #define PATH_MAX 4096 #define _POSIX_PATH_MAX 256 $ gcc -E -dM -x c /dev/null | grep -i BYTE_ORDER #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ $ gcc -E -dM -x c /dev/null | grep -i CHAR_BIT #define __CHAR_BIT__ 8 $ gcc -E -dM -x c /dev/null | grep -i STDC_IEC_559 # since C23 deprecated #define __STDC_IEC_559__ 1 # IEC 60559 floating point arithmetic (IEEE 754 standard) #define __STDC_IEC_559_COMPLEX__ 1 # IEC 60559 compatible complex arithmetic $ gcc -E -dM -x c /dev/null | grep -i STDC_VERSION #define __STDC_VERSION__ 201710L $ gcc -E -dM -x c++ /dev/null | grep -i cplusplus #define __cplusplus 201703L $ gcc -E -dM -x c++ --std=c++14 /dev/null | grep -i cplusplus #define __cplusplus 201402L
NOTE GNU gcc uses GNU dialects (extensions) of ISO standards as default standard:
gcc
default for C code is-std=gnu17
. This is GNU dialect of ISO C17-std=c17
.g++
default for C++ code is-std=gnu++17
. This is GNU dialect of 2017 ISO C++ standard-std=c++17
.gfortran
default for Fortran code is-std=gnu
. This is GNU Fortran dialect, which specifies a superset of the latest Fortran standard.
- dependencies
See also How to print dependencies from llvm / clang (equivalent of gcc -MD)?
$ gcc -M simple.c $ g++ -M simple.cxx
x86 Options
-march=cpu-type
generate instructions for the machine type cpu-type
. Specifying -march=cpu-type
implies -mtune=cpu-type
, except where noted otherwise.
cpu-type=x86-64
is generic CPU with 64-bit extensions (on the x86 family of computers).cpu-type=native
selects the CPU to generate code for at compilation time by determining the processor type of the compiling machine. Using-march=native
enables all instruction subsets supported by the local machine (hence the result might not run on different machines). Using-mtune=native
produces code optimized for the local machine under the constraints of the selected instruction set.
On Fedora gcc
(by default) configured (compiled) with: --with-tune=generic --with-arch_32=i686
which meansgcc
= gcc -march=x86-64 -mtune=generic
. For better performance (but running only on current machine) use gcc -march=native
.
$ cat /proc/cpuinfo | grep -m1 'model name' model name : AMD Ryzen 5 5600G with Radeon Graphics $ gcc --help=target -Q | grep -E 'march=|mtune=' -march= x86-64 -mtune= generic $ diff <(gcc --help=target -Q) <(gcc --help=target -Q -march=native) | grep -E 'arch|tune' < -march= x86-64 > -march= znver3 < -mtune= generic > -mtune= znver3
pkgconf
pkgconf
is a program which helps to configure compiler and linker flags for development libraries. It is similar to pkg-config
from freedesktop.org without depending on GLib. On Fedora/RHEL pkgconf(1) fully replaced pkg-config(1).
$ pkgconf --list-all
$ pkgconf --path fuse # fuse
simply as an example
/usr/lib64/pkgconfig/fuse.pc
$ pkgconf --cflags --libs fuse
-I/usr/include/fuse -D_FILE_OFFSET_BITS=64 -lfuse -pthread
$ gcc fuse_example.c $(pkgconf --cflags --libs fuse)
Code Checkers
- GCC StaticAnalyzer command
gcc
with-fanalyzer
option. Only C is currently supported (C++ support maybe in GCC 16).
- Cppcheck (source on GitHub) and the list of checks. Static analysis tool for C/C++ code. Provided by cppcheck package.
- Clang-Tidy and the list of checks. Command
clang-tidy
provided by clang-tools-extra package.
- Clang Static Analyzer for running from the command line. Command
scan-build
provided by clang-analyzer package.
- CodeChecker all in one solution (source on GitHub). Not necessary if you use individual commands/programs separately.
Notes
- 2024-10 Compiler Options Hardening Guide for C and C++ (source on GitHub).
- 2025-02 Recommended compiler and linker flags for GCC
- docasne na tomto mieste, neskor presunut na Cpp, resp. C wiki stranku
- 2024-10 C++ Core Guidelines (source on GitHub), pripadne Google C++ Style Guide.
- 2025-04 LinuxNetworkProgramming
- 2025-04 Алгоритмика
- 2025-04 Everything you need to know about pointers in C
- 2025-04 GNU Hello (good example how parsing arguments)
- 2025-06 Advanced Memory Debugging In C: A Deep Dive Into Valgrind And Addresssanitizer
- 2025-06 Build your own <insert-technology-here>
- 2025-06 C++ Developer Roadmap
- 2025-07 Understanding Memory Allocation in C++