Chapter 15. Building Code with GCC This chapter describes situations where source code must be transformed into executable code. 15.1. Relationship between Code Forms Prerequisites Understanding of the concepts of compiling and linking Possible Code Forms When using the C and C++ languages, there are three forms of code: Source code written in the C or C++ language, present as plain text files. The files typically use extensions such as .c , .cc , .cpp , .h , .hpp , .i , .inc . For a complete list of supported extensions and their interpretation, see the gcc manual pages: Object code , created by compiling the source code with a compiler . This is an intermediate form. The object code files use the .o extension. Executable code , created by linking object code with a linker . Linux application executable files do not use any file name extension. Shared object (library) executable files use the .so file name extension. Note Library archive files for static linking also exist. This is a variant of object code which uses the .a file name extension. Static linking is not recommended. See Section 16.2, "Static and dynamic linking" . Handling of Code Forms in GCC Producing executable code from source code requires two steps, which require different applications or tools. GCC can be used as an intelligent driver for both compilers and linkers. This allows you to use a single command gcc for any of the required actions. GCC automatically selects the actions required (compiling and linking), as well as their sequence: Source files are compiled to object files. Object files and libraries are linked (including the previously compiled sources). It is possible to run GCC such that only step 1 happens, only step 2 happens, or both steps 1 and 2 happen. This is determined by the types of inputs and requested types of output. Because larger projects require a build system which usually runs GCC separately for each action, it is helpful to always consider compilation and linking as two distinct actions, even if GCC can perform both at once. Additional Resources Section 15.2, "Compiling Source Files to Object Code" Section 15.6, "Linking Code to Create Executable Files" 15.2. Compiling Source Files to Object Code To create object code files from source files and not an executable file immediately, GCC must be instructed to create only object code files as its output. This action represents the basic operation of the build process for larger projects. Prerequisites C or C++ source code file(s) GCC installed on the system Procedure Change to the directory containing the source code file(s). Run gcc with the -c option: Object files are created, with their file names reflecting the original source code files: source.c results in source.o . Note With C++ source code, replace the gcc command with g++ for convenient handling of C++ Standard Library dependencies. Additional Resources Section 15.5, "Hardening Code with GCC" Section 15.4, "Code Optimization with GCC" Section 15.8, "Example: Building a C Program with GCC" 15.3. Enabling Debugging of C and C++ Applications with GCC Because debugging information is large, it is not included in executable files by default. To enable debugging of your C and C++ applications with it, you must explicitly instruct the compiler to create debugging information. Enabling the Creation of Debugging Information with GCC To enable the creation of debugging information with GCC when compiling and linking code, use the -g option: Optimizations performed by the compiler and linker can result in executable code which is hard to relate to the original source code: variables may be optimized out, loops unrolled, operations merged into the surrounding ones etc. This affects debugging negatively. For an improved debugging experience, consider setting the optimization with the -Og option. However, changing the optimization level changes the executable code and may change the actual behaviour so as to remove some bugs. The -fcompare-debug GCC option tests code compiled by GCC with debug information and without debug information. The test passes if the resulting two binary files are identical. This test ensures that executable code is not affected by any debugging options, which further ensures that there are no hidden bugs in the debug code. Note that using the -fcompare-debug option significantly increases compilation time. See the GCC manual page for details about this option. Additional Resources Section 20.1, "Enabling Debugging with Debugging Information" Using the GNU Compiler Collection (GCC) - 3.10 Options for Debugging Your Program Debugging with GDB - 18.3 Debugging Information in Separate Files The GCC manual page: 15.4. Code Optimization with GCC A single program can be transformed into more than one sequence of machine instructions. An optimal result can be achieved if more resources are allocated for analysis of the code during compilation. Code Optimization with GCC With GCC, it is possible to set the optimization level using the -O level option. This option accepts a set of values in place of the level . Level Description 0 Optimize for compilation speed - no code optimization (default) 1 , 2 , 3 Increasing optimization effort for code execution speed s Optimize for resulting file size fast Level 3 plus disregard for strict standards compliance to allow for additional optimizations g Optimize for debugging experience For release builds, the optimization option -O2 is recommended. During development, the -Og option is more useful for debugging the program or library in some situations. Because some bugs manifest only with certain optimization levels, ensure to test the program or library with the release optimization level. GCC offers a large number of options to enable individual optimizations. For more information, see the following Additional Resources. Additional Resources Using GNU Compiler Collection - 3.11 Options That Control Optimization Linux manual page for GCC: 15.5. Hardening Code with GCC When the compiler transforms source code to object code, it can add various checks to prevent commonly exploited situations and thus increase security. Choosing the right set of compiler options can help produce more secure programs and libraries, without changes to the source code. Release Version Options The following list of options is the recommended minimum for developers targeting Red Hat Enterprise Linux: For programs, add the -fPIE and -pie Position Independent Executable options. For dynamically linked libraries, the mandatory -fPIC (Position Independent Code) option indirectly increases security. Development Options The following options are recommended to detect security flaws during development. Use these options in conjunction with the options for the release version: Additional Resources Defensive Coding Guide Red Hat Developer blog post - Memory Error Detection Using GCC 15.6. Linking Code to Create Executable Files Linking is the final step when building a C or C++ application. Linking combines all object files and libraries into an executable file. Prerequisites One or more object files GCC is installed on the system Procedure Change to the directory containing the object code files. Run gcc : An executable file named executable-file is created from the supplied object files and libraries. To link additional libraries, add the required options before the list of object files. See Chapter 16, Using Libraries with GCC . Note With C++ source code, replace the gcc command with g++ for convenient handling of C++ Standard Library dependencies. Additional Resources Section 15.8, "Example: Building a C Program with GCC" Chapter 16, Using Libraries with GCC 15.7. C++ Compatibility of Various Red Hat Products The Red Hat ecosystem includes several versions of the GCC compiler and linker, provided in Red Hat Enterprise Linux and Red Hat Developer Toolset. The C++ ABI compatibility between these is as follows: The system compiler based on GCC 4.8 and provided directly as part of Red Hat Enterprise Linux 7 supports only compiling and linking the C++98 standard (also known as C++03), and its variant with GNU extensions. Any C++98-compliant binaries or libraries built explicitly with the options -std=c++98 or -std=gnu++98 can be freely mixed, regardless of the version of the compiler used. Using and mixing the C++11 and C++14 language versions is supported only when using compilers from Red Hat Developer Toolset and only when all C++ objects compiled with the respective flag have been built using the same major version of GCC. When linking C++ files built with both Red Hat Developer Toolset and Red Hat Enterprise Linux toolchain, prefer the Red Hat Developer Toolset version of the compiler and linker. The default setting for compilers in Red Hat Enterprise Linux 6 and 7 and Red Hat Developer Toolset up to 4.1 is -std=gnu++98 . That is, C++98 with GNU extensions. The default setting for compilers in Red Hat Developer Toolset 6, 6.1, 7, 7.1, 8.0, 8.1, 9.0, 9.1, and 10 is -std=gnu++14 . That is, C++14 with GNU extensions. Additional Resources Application Compatibility GUIDE Knowledge base solution - What gcc versions are available in Red Hat Enterprise Linux? Red Hat Developer Toolset User Guide - C++ Compatibility 15.8. Example: Building a C Program with GCC This example shows the exact steps to build a sample minimal C program. Prerequisites Understanding the use of GCC Steps Create a directory hello-c and change to its location: Create a file hello.c with the following contents: #include <stdio.h> int main() { printf("Hello, World!\n"); return 0; } Compile the code with GCC: The object file hello.o is created. Link an executable file helloworld from the object file: Run the resulting executable file: Additional Resources Section 18.2, "Example: Building a C Program Using a Makefile" 15.9. Example: Building a C++ Program with GCC This example shows the exact steps to build a sample minimal C++ program. Prerequisites Understanding the use of GCC Understanding the difference between gcc and g++ Procedure Create a directory hello-cpp and change to its location: Create a file hello.cpp with the following contents: #include <iostream> int main() { std::cout << "Hello, World!\n"; return 0; } Compile the code with g++ : The object file hello.o is created. Link an executable file helloworld from the object file: Run the resulting executable file:

Commands:
man gcc
gcc -c source.c another_source.c
gcc ... -g
man gcc
man gcc
gcc ... -O2 -g -Wall -Wl,-z,now,-z,relro -fstack-protector-strong -D_FORTIFY_SOURCE=2
gcc ... -Walloc-zero -Walloca-larger-than -Wextra -Wformat-security -Wvla-larger-than
gcc ... objectfile.o another_object.o ... -o executable-file
mkdir hello-c cd hello-c
#include <stdio.h> int main() { printf("Hello, World!\n"); return 0; }
gcc -c hello.c
gcc hello.o -o helloworld
./helloworld Hello, World!
mkdir hello-cpp cd hello-cpp
#include <iostream> int main() { std::cout << "Hello, World!\n"; return 0; }
g++ -c hello.cpp
g++ hello.o -o helloworld
./helloworld Hello, World!