Ce contenu n'est pas disponible dans la langue sélectionnée.

Chapter 2. Creating C or C++ Applications


Red Hat offers multiple tools for creating applications using the C and C++ languages. This part of the book lists some of the most common development tasks.

2.1. GCC in RHEL 9

Red Hat Enterprise Linux 9 is distributed with the GNU Compiler Collection (GCC) 11 as the standard compiler.

The default language standard setting for GCC 11 is C++17. This is equivalent to explicitly using the command-line option -std=gnu++17.

Later language standards, such as C++20 and so on, and library features introduced in these later language standards are still considered experimental.

2.2. Building code with GCC

Learn about situations where source code must be transformed into executable code.

2.2.1. Relationship between code forms

The C and C++ languages have three forms of code that are created through different stages of the build process. Understanding these relationships helps you work effectively with the GNU Compiler Collection (GCC).

Prerequisites

  • Understanding the concepts of compiling and linking

Possible code forms

The code forms of C and C++ languages:

  • 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:

    $ man gcc
    Copy to Clipboard Toggle word wrap
  • 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 that uses the .a file name extension. Static linking is not recommended. See Section 2.3.2, “Static and dynamic linking”.

Handling of code forms in GCC

Producing executable code from source code is performed in 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 gcc command for any of the required actions (compiling and linking). GCC automatically selects the actions and their sequence:

  1. Source files are compiled to object files.
  2. Object files and libraries are linked (including the previously compiled sources).

It is possible to run GCC so that it performs only compiling, only linking, or both compiling and linking in a single step. This is determined by the types of inputs and requested type of output(s).

Because larger projects require a build system which usually runs GCC separately for each action, it is better to always consider compilation and linking as two distinct actions, even if GCC can perform both at once.

2.2.2. Compiling source files to object code

To compile source files into object files without creating an executable, use GCC’s -c option.

Prerequisites

  • C or C++ source code file(s)
  • GCC installed on the system

Procedure

  1. Change to the directory containing the source code file(s).
  2. Run gcc with the -c option:

    $ gcc -c source.c another_source.c
    Copy to Clipboard Toggle word wrap

    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.

To debug C and C++ applications effectively, generate debugging information during compilation. Use GCC’s -g option to create this data. Debuggers use this data to map executable code to source lines for inspecting variables and logic.

Prerequisites

  • You have the gcc package installed.

Procedure

  1. Compile and link your code with the -g option to generate debugging information:

    $ gcc ... -g ...
    Copy to Clipboard Toggle word wrap
  2. Optional: Set the optimization level to -Og:

    $ gcc ... -g -Og ...
    Copy to Clipboard Toggle word wrap

    Compiler optimizations can make executable code hard to relate to the source code. The -Og option optimizes the code without interfering with debugging. However, be aware that changing optimization levels can alter the program’s behavior.

  3. Optional: Use -g for moderate debugging information, or -g3 to include macro definitions:

    $ gcc ... -g3 ...
    Copy to Clipboard Toggle word wrap

Verification

  • Test the code by using the -fcompare-debug GCC option:

    $ gcc -fcompare-debug ...
    Copy to Clipboard Toggle word wrap

    This option tests code compiled with and without debug information. If the resulting binaries are identical, the executable code is not affected by debugging options. By using the -fcompare-debug option significantly increases compilation time.

2.2.4. Code optimization with the GCC

A single program can be transformed into more than one sequence of machine instructions. You can achieve better performance, such as faster execution speed, greater resource efficiency, or smaller file size, if you allocate more resources to analyzing the code during compilation.

With the GNU Compiler Collection (GCC), you can set the optimization level using the -Olevel option. This option accepts a set of values in place of the level.

Expand
LevelDescription

0

Optimize for compilation speed - no code optimization (default).

1, 2, 3

Optimize to increase code execution speed (the larger the number, the greater the speed).

s

Optimize for file size.

fast

Same as a level 3 setting, plus fast disregards strict standards compliance to allow for additional optimizations.

g

Optimize for debugging experience.

For release builds, use the optimization option -O2.

During development, the -Og option is useful for debugging the program or library in some situations. Because some bugs manifest only with certain optimization levels, 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.

2.2.5. Options for hardening code with the GCC

To add security checks during code compilation, you can use GNU Compiler Collection (GCC) compiler options. This helps produce more secure programs and libraries without changing source code.

Release version options

The following list of options is the recommended minimum for developers targeting Red Hat Enterprise Linux:

+

$ gcc ... -O2 -g -Wall -Wl,-z,now,-z,relro -fstack-protector-strong -fstack-clash-protection -D_FORTIFY_SOURCE=2 ...
Copy to Clipboard Toggle word wrap
  • 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

Use the following options to detect security flaws during development. Use these options in conjunction with the options for the release version:

+

$ gcc ... -Walloc-zero -Walloca-larger-than -Wextra -Wformat-security -Wvla-larger-than ...
Copy to Clipboard Toggle word wrap

Additional resources

2.2.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 file(s)
  • GCC must be installed on the system

Procedure

  1. Change to the directory containing the object code file(s).
  2. Run gcc:

    $ gcc ... objfile.o another_object.o ... -o executable-file
    Copy to Clipboard Toggle word wrap

    An executable file named executable-file is created from the supplied object files and libraries.

    To link additional libraries, add the required options after the list of object files.

    Note

    With C++ source code, replace the gcc command with g++ for convenient handling of C++ Standard Library dependencies.

To build a simple sample C program, you can use the GNU Compiler Collection (GCC). In this example, compiling and linking the code is done in one step.

Prerequisites

  • You must understand how to use GCC.

Procedure

  1. Create a directory hello-c and change to it:

    $ mkdir hello-c
    $ cd hello-c
    Copy to Clipboard Toggle word wrap
  2. Create file hello.c with the following contents:

    #include <stdio.h>
    
    int main() {
      printf("Hello, World!\n");
      return 0;
    }
    Copy to Clipboard Toggle word wrap
  3. Compile and link the code with GCC:

    $ gcc hello.c -o helloworld
    Copy to Clipboard Toggle word wrap

    This compiles the code, creates the object file hello.o, and links the executable file helloworld from the object file.

  4. Run the resulting executable file:

    $ ./helloworld
    Hello, World!
    Copy to Clipboard Toggle word wrap

To build a simple sample C program, you can use the GNU Compiler Collection (GCC). In this example, compiling and linking the code are two separate steps.

Prerequisites

  • You must understand how to use GCC.

Procedure

  1. Create a directory hello-c and change to it:

    $ mkdir hello-c
    $ cd hello-c
    Copy to Clipboard Toggle word wrap
  2. Create file hello.c with the following contents:

    #include <stdio.h>
    
    int main() {
      printf("Hello, World!\n");
      return 0;
    }
    Copy to Clipboard Toggle word wrap
  3. Compile the code with GCC:

    $ gcc -c hello.c
    Copy to Clipboard Toggle word wrap

    The object file hello.o is created.

  4. Link an executable file helloworld from the object file:

    $ gcc hello.o -o helloworld
    Copy to Clipboard Toggle word wrap
  5. Run the resulting executable file:

    $ ./helloworld
    Hello, World!
    Copy to Clipboard Toggle word wrap

To build a sample minimal C++ program, you can use the GNU Compiler Collection (GCC). In this example, compiling and linking the code is done in one step.

Prerequisites

  • You must understand the difference between gcc and g++.

Procedure

  1. Create a directory hello-cpp and change to it:

    $ mkdir hello-cpp
    $ cd hello-cpp
    Copy to Clipboard Toggle word wrap
  2. Create file hello.cpp with the following contents:

    #include <iostream>
    
    int main() {
      std::cout << "Hello, World!\n";
      return 0;
    }
    Copy to Clipboard Toggle word wrap
  3. Compile and link the code with g++:

    $ g++ hello.cpp -o helloworld
    Copy to Clipboard Toggle word wrap

    This compiles the code, creates the object file hello.o, and links the executable file helloworld from the object file.

  4. Run the resulting executable file:

    $ ./helloworld
    Hello, World!
    Copy to Clipboard Toggle word wrap

To build a minimal C++ program by using a two-step process, you can use the GNU Compiler Collection (GCC). First, compile the source into an object file, then link it to create the executable. This example demonstrates modular building with the GCC compiler.

Prerequisites

  • You must understand the difference between gcc and g++.

Procedure

  1. Create a directory hello-cpp and change to it:

    $ mkdir hello-cpp
    $ cd hello-cpp
    Copy to Clipboard Toggle word wrap
  2. Create file hello.cpp with the following contents:

    #include <iostream>
    
    int main() {
      std::cout << "Hello, World!\n";
      return 0;
    }
    Copy to Clipboard Toggle word wrap
  3. Compile the code with g++:

    $ g++ -c hello.cpp
    Copy to Clipboard Toggle word wrap

    The object file hello.o is created.

  4. Link an executable file helloworld from the object file:

    $ g++ hello.o -o helloworld
    Copy to Clipboard Toggle word wrap
  5. Run the resulting executable file:

    $ ./helloworld
    Hello, World!
    Copy to Clipboard Toggle word wrap

2.3. Using Libraries with the GCC

Learn about using libraries in code.

2.3.1. Library naming conventions

System libraries require consistent naming. A library known as foo is expected to exist as file libfoo.so or libfoo.a. This convention is automatically understood by the linking input options of the GNU Compiler Collection (GCC), but not by the output options:

  • When linking against the library, the library can be specified only by its name foo with the -l option as -lfoo:

    $ gcc ... -lfoo ...
    Copy to Clipboard Toggle word wrap
  • When creating the library, the full file name libfoo.so or libfoo.a must be specified.

2.3.2. Static and dynamic linking

When building C or C++ applications, you must use dynamic linking. Static linking reduces compatibility and prevents timely library security updates.

Comparison of static and dynamic linking

Static linking makes libraries part of the resulting executable file. Dynamic linking keeps these libraries as separate files.

Dynamic and static linking can be compared in several ways:

Resource use

Static linking results in larger executable files which contain more code. This additional code coming from libraries cannot be shared across multiple programs on the system, increasing file system usage and memory usage at run time. Multiple processes running the same statically linked program will still share the code.

Conversely, static applications need fewer runtime relocations, leading to reduced startup time, and require less private resident set size (RSS) memory. Generated code for static linking can be more efficient than for dynamic linking due to the performance cost of position-independent code (PIC).

Security
Dynamically linked libraries which provide ABI compatibility can be updated without changing the executable files depending on these libraries. This is especially important for libraries provided by Red Hat as part of Red Hat Enterprise Linux, where Red Hat provides security updates. Static linking against any such libraries is strongly discouraged.
Compatibility

Static linking might seem to provide executable files independent of the versions of libraries provided by the operating system. However, most libraries depend on other libraries. With static linking, this dependency becomes inflexible and as a result, both forward and backward compatibility is lost. Static linking is guaranteed to work only on the system where the executable file was built.

Warning

Applications linking statically libraries from the GNU C library (glibc) still require glibc to be present on the system as a dynamic library. Furthermore, the dynamic library variant of glibc available at the application’s run time must be a bitwise identical version to that present while linking the application. As a result, static linking is guaranteed to work only on the system where the executable file was built.

Support coverage
Most static libraries provided by Red Hat are in the CodeReady Linux Builder channel and not supported by Red Hat.
Functionality

Some libraries, notably the GNU C Library (glibc), offer reduced functionality when linked statically.

For example, when statically linked, glibc does not support threads and any form of calls to the dlopen() function in the same program.

As a result of the listed disadvantages, static linking should be avoided at all costs, particularly for whole applications and the glibc and libstdc++ libraries.

Cases for static linking

Static linking might be a reasonable choice in some cases, such as:

  • Using a library which is not enabled for dynamic linking.
  • Fully static linking can be required for running code in an empty chroot environment or container. However, static linking using the glibc-static package is not supported by Red Hat.

2.3.3. Using a library with the GCC

A library is a package of code which can be reused in your program. A C or C++ library consists of two parts:

  • The library code
  • Header files

Compiling code that uses a library

The header files describe the interface of the library: the functions and variables available in the library. Information from the header files is needed for compiling the code.

Typically, header files of a library will be placed in a different directory than your application’s code. To tell the GNU Compiler Collection (GCC) where the header files are, use the -I option:

$ gcc ... -Iinclude_path ...
Copy to Clipboard Toggle word wrap

Replace include_path with the actual path to the header file directory.

The -I option can be used multiple times to add multiple directories with header files. When looking for a header file, these directories are searched in the order of their appearance in the -I options.

Linking code that uses a library

When linking the executable file, both the object code of your application and the binary code of the library must be available. The code for static and dynamic libraries is present in different forms:

  • Static libraries are available as archive files. They contain a group of object files. The archive file has a file name extension .a.
  • Dynamic libraries are available as shared objects. They are a form of an executable file. A shared object has a file name extension .so.

To tell GCC where the archives or shared object files of a library are, use the -L option:

+

$ gcc ... -Llibrary_path -lfoo ...
Copy to Clipboard Toggle word wrap

Replace library_path with the actual path to the library directory.

The -L option can be used multiple times to add multiple directories. When looking for a library, these directories are searched in the order of their -L options.

The order of options matters: GCC cannot link against a library foo unless it knows the directory with this library. Therefore, use the -L options to specify library directories before using the -l options for linking against libraries.

Compiling and linking code which uses a library in one step

When the situation allows the code to be compiled and linked in one gcc command, use the options for both situations mentioned above at once.

2.3.4. Linking static libraries with the GCC

To link static libraries, bundle them as archives that contain object files. After linking, they become part of the resulting executable file. Static linking overrides the default dynamic linking behavior.

Note

Red Hat discourages static linking for security reasons. See Section 2.3.2, “Static and dynamic linking”. Use static linking only when necessary, especially against libraries provided by Red Hat.

Prerequisites

  • GCC is installed on your system.
  • You have a specific static library (e.g., libfoo.a) and no dynamic version (libfoo.so) available.
Note

Most libraries in Red Hat support dynamic linking only. These steps apply to libraries not enabled for dynamic linking.

Procedure

  1. Compile the program source files with headers of the static library:

    $ gcc ... -Iheader_path -c ...
    Copy to Clipboard Toggle word wrap

    Replace header_path with the directory path containing the header files.

  2. Link the program with the static library:

    $ gcc ... -Llibrary_path -lfoo ...
    Copy to Clipboard Toggle word wrap

    Replace library_path with the directory path containing the file libfoo.a.

  3. Run the program:

    $ ./program
    Copy to Clipboard Toggle word wrap
Warning

The -static option forbids all dynamic linking. Use -Wl,-Bstatic and -Wl,-Bdynamic to control linker behavior more precisely. See Section 2.3.6, “Static and dynamic libraries with GCC”.

2.3.5. Using a dynamic library with the GCC

Dynamic libraries are available as standalone executable files, required at both linking time and run time. They stay independent of your application’s executable file.

Prerequisites

  • GCC must be installed on the system.
  • A set of source or object files forming a valid program, requiring some dynamic library foo and no other libraries.
  • The foo library must be available as a file libfoo.so.

Linking a program against a dynamic library

To link a program against a dynamic library foo:

$ gcc ... -Llibrary_path -lfoo ...
Copy to Clipboard Toggle word wrap

When a program is linked against a dynamic library, the resulting program must always load the library at run time. There are two options for locating the library:

  • Using a rpath value stored in the executable file itself
  • Using the LD_LIBRARY_PATH variable at run time

Using a rpath Value Stored in the Executable File

The rpath 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 the rpath value to locate the library files.

While linking with the GNU Compiler Collection (GCC), to store the path library_path as rpath:

$ gcc ... -Llibrary_path -lfoo -Wl,-rpath=library_path ...
Copy to Clipboard Toggle word wrap

The path library_path must point to a directory containing the file libfoo.so.

Important

Do not add a space after the comma in the -Wl,-rpath= option.

To run the program later:

$ ./program
Copy to Clipboard Toggle word wrap

Using the LD_LIBRARY_PATH environment variable

If no rpath is found in the program’s executable file, the runtime linker will use the LD_LIBRARY_PATH environment variable. The value of this variable must be changed for each program. This value should represent the path where the shared library objects are located.

To run the program without rpath set, with libraries present in path library_path:

$ export LD_LIBRARY_PATH=library_path:$LD_LIBRARY_PATH
$ ./program
Copy to Clipboard Toggle word wrap

Leaving out the rpath value offers flexibility, but requires setting the LD_LIBRARY_PATH variable every time the program is to run.

Placing the Library into the Default Directories

The runtime linker configuration specifies several directories as a default location of dynamic library files. To use this default behaviour, copy your library to the appropriate directory.

A full description of the dynamic linker behavior is out of scope of this document. For more information, see the following resources:

  • Linux manual pages for the dynamic linker:

    $ man ld.so
    Copy to Clipboard Toggle word wrap
  • Contents of the /etc/ld.so.conf configuration file:

    $ cat /etc/ld.so.conf
    Copy to Clipboard Toggle word wrap
  • Report of the libraries recognized by the dynamic linker without additional configuration, which includes the directories:

    $ ldconfig -v
    Copy to Clipboard Toggle word wrap

2.3.6. Static and dynamic libraries with GCC

Combining static and dynamic linking balances portability and efficiency. GCC automatically selects shared objects over static archives unless configured otherwise. Understand this behavior to control exactly which library versions your application uses.

Prerequisites

  • Understanding static and dynamic linking

Introduction

gcc recognizes both dynamic and static libraries. When the -lfoo option is encountered, gcc will first attempt to locate a shared object (a .so file) containing a dynamically linked version of the foo library, and then look for the archive file (.a) containing a static version of the library. Thus, the following situations can result from this search:

  • Only the shared object is found, and gcc links against it dynamically.
  • Only the archive is found, and gcc links against it statically.
  • Both the shared object and archive are found, and by default, gcc selects dynamic linking against the shared object.
  • Neither shared object nor archive is found, and linking fails.

Because of these rules, the best way to select the static or dynamic version of a library for linking is having only that version found by gcc. This can be controlled to some extent by using or leaving out directories containing the library versions, when specifying the -Lpath options.

Additionally, because dynamic linking is the default, the only situation where linking must be explicitly specified is when a library with both versions present should be linked statically. There are two possible resolutions:

  • Specifying the static libraries by file path instead of the -l option
  • Using the -Wl option to pass options to the linker

Specifying the static libraries by file

Usually, gcc is instructed to link against the foo library with the -lfoo option. However, it is possible to specify the full path to file libfoo.a containing the library instead:

$ gcc ... path/to/libfoo.a ...
Copy to Clipboard Toggle word wrap

From the file extension .a, gcc will understand that this is a library to link with the program. However, specifying the full path to the library file is a less flexible method.

Using the -Wl option

The gcc option -Wl is a special option for passing options to the underlying linker. Syntax of this option differs from the other gcc options. The -Wl option is followed by a comma-separated list of linker options, while other gcc options require space-separated list of options.

The ld linker used by gcc offers the options -Bstatic and -Bdynamic to specify whether libraries following this option should be linked statically or dynamically. After passing -Bstatic and a library to the linker, the default dynamic linking behaviour must be restored manually for the following libraries to be linked dynamically with the -Bdynamic option.

To link a program, link library first statically (libfirst.a) and second dynamically (libsecond.so):

$ gcc ... -Wl,-Bstatic -lfirst -Wl,-Bdynamic -lsecond ...
Copy to Clipboard Toggle word wrap
Note

gcc can be configured to use linkers other than the default ld.

2.4. Creating libraries with the GCC

Learn about the steps to creating libraries and the necessary concepts used by the Linux operating system for libraries.

2.4.1. Library naming conventions

System libraries require consistent naming. A library known as foo is expected to exist as file libfoo.so or libfoo.a. This convention is automatically understood by the linking input options of the GNU Compiler Collection (GCC), but not by the output options:

  • When linking against the library, the library can be specified only by its name foo with the -l option as -lfoo:

    $ gcc ... -lfoo ...
    Copy to Clipboard Toggle word wrap
  • When creating the library, the full file name libfoo.so or libfoo.a must be specified.

2.4.2. The soname mechanism

To manage multiple compatible versions of a library, dynamically loaded libraries (shared objects) use the soname mechanism.

Prerequisites

  • You must understand dynamic linking and libraries.
  • You must understand the concept of ABI compatibility.
  • You must understand library naming conventions.
  • You must understand symbolic links.

Problem introduction

A dynamically loaded library (shared object) exists as an independent executable file. This makes it possible to update the library without updating the applications that depend on it. However, the following problems arise with this concept:

  • Identification of the actual version of the library
  • Need for multiple versions of the same library present
  • Signalling ABI compatibility of each of the multiple versions

The soname mechanism

To resolve this, Linux uses a mechanism called soname.

A foo library version X.Y is ABI-compatible with other versions with the same value of X in a version number. Minor changes preserving compatibility increase the number Y. Major changes that break compatibility increase the number X.

The actual foo library version X.Y exists as a file libfoo.so.x.y. Inside the library file, a soname is recorded with value libfoo.so.x to signal the compatibility.

When applications are built, the linker looks for the library by searching for the file libfoo.so. A symbolic link with this name must exist, pointing to the actual library file. The linker then reads the soname from the library file and records it into the application executable file. Finally, the linker creates the application that declares dependency on the library using the soname, not a name or a file name.

When the runtime dynamic linker links an application before running, it reads the soname from application’s executable file. This soname is libfoo.so.x. A symbolic link with this name must exist, pointing to the actual library file. This allows loading the library, regardless of the Y component of a version, because the soname does not change.

Note

The Y component of the version number is not limited to just a single number. Additionally, some libraries encode their version in their name.

Reading soname from a file

To display the soname of a library file somelibrary:

$ objdump -p somelibrary | grep SONAME
Copy to Clipboard Toggle word wrap

Replace somelibrary with the actual file name of the library that you want to examine.

2.4.3. Creating dynamic libraries with the GCC

To build and install a dynamic library from the source code, you can use the GNU Compiler Collection (GCC). Dynamically linked libraries, also known as shared objects, help you conserve resources by reusing code and increase security by making library updates easier.

Prerequisites

  • You must understand the soname mechanism.
  • GCC must be installed on the system.
  • You must have source code for a library.

Procedure

  1. Change to the directory with library sources.
  2. Compile each source file to an object file with the Position independent code option -fPIC:

    $ gcc ... -c -fPIC some_file.c ...
    Copy to Clipboard Toggle word wrap

    The object files have the same file names as the original source code files, but their extension is .o.

  3. Link the shared library from the object files:

    $ gcc -shared -o libfoo.so.x.y -Wl,-soname,libfoo.so.x some_file.o ...
    Copy to Clipboard Toggle word wrap

    The used major version number is X and minor version number Y.

  4. Copy the libfoo.so.x.y file to an appropriate location, where the system’s dynamic linker can find it. On Red Hat Enterprise Linux, the directory for libraries is /usr/lib64:

    # cp libfoo.so.x.y /usr/lib64
    Copy to Clipboard Toggle word wrap

    Note that you need root permissions to manipulate files in this directory.

  5. Create the symlink structure for soname mechanism:

    # ln -s libfoo.so.x.y libfoo.so.x
    # ln -s libfoo.so.x libfoo.so
    Copy to Clipboard Toggle word wrap

Additional resources

2.4.4. Creating static libraries

To create static libraries, bundle object files into an archive by using the ar utility. Use the resulting .a file for static linking and for distributing self-contained libraries without external dependencies.

Note

Red Hat discourages the use of static linking for security reasons. Use static linking only when necessary, especially against libraries provided by Red Hat. See Section 2.3.2, “Static and dynamic linking” for more details.

Prerequisites

  • GCC and binutils must be installed on the system.
  • You must understand static and dynamic linking.
  • Source file(s) with functions to be shared as a library are available.

Procedure

  1. Create intermediate object files with GCC.

    $ gcc -c source_file.c ...
    Copy to Clipboard Toggle word wrap

    Append more source files if required. The resulting object files share the file name but use the .o file name extension.

  2. Turn the object files into a static library (archive) using the ar tool from the binutils package.

    $ ar rcs libfoo.a source_file.o ...
    Copy to Clipboard Toggle word wrap

    File libfoo.a is created.

  3. Use the nm command to inspect the resulting archive:

    $ nm libfoo.a
    Copy to Clipboard Toggle word wrap
  4. Copy the static library file to the appropriate directory.
  5. When linking against the library, GCC will automatically recognize from the .a file name extension that the library is an archive for static linking.

    $ gcc ... -lfoo ...
    Copy to Clipboard Toggle word wrap

2.5. Managing More Code with Make

The GNU make utility, commonly abbreviated make, is a tool for controlling the generation of executables from source files. make automatically determines which parts of a complex program have changed and need to be recompiled. make uses configuration files called Makefiles to control the way programs are built.

2.5.1. GNU make and Makefile overview

To build executable programs and libraries from source code, and to record and repeat the steps if required, Red Hat Enterprise Linux contains the GNU’s Not Unix (GNU) make command.

GNU make

GNU make reads Makefiles which contain the instructions describing the build process. A Makefile contains multiple rules that describe a way to satisfy a certain condition (target) with a specific action (recipe). Rules can hierarchically depend on another rule.

Running make without any options makes it look for a Makefile in the current directory and attempt to reach the default target. The actual Makefile file name can be one of Makefile, makefile, and GNUmakefile. The default target is determined from the Makefile contents.

Makefile details

Makefiles use a relatively simple syntax for defining variables and rules, which consists of a target and a recipe. The target specifies what is the output if a rule is executed. The lines with recipes must start with the TAB character.

Typically, a Makefile contains rules for compiling source files, a rule for linking the resulting object files, and a target that serves as the entry point at the top of the hierarchy.

Consider the following Makefile for building a C program which consists of a single file, hello.c.

all: hello

hello: hello.o
        gcc hello.o -o hello

hello.o: hello.c
        gcc -c hello.c -o hello.o
Copy to Clipboard Toggle word wrap

This example shows that to reach the target all, file hello is required. To get hello, one needs hello.o (linked by gcc), which in turn is created from hello.c (compiled by gcc).

The target all is the default target because it is the first target that does not start with a period (.). Running make without any arguments is then identical to running make all, when the current directory contains this Makefile.

Typical makefile

A more typical Makefile uses variables for generalization of the steps and adds a target "clean" - remove everything but the source files.

CC=gcc
CFLAGS=-c -Wall
SOURCE=hello.c
OBJ=$(SOURCE:.c=.o)
EXE=hello

all: $(SOURCE) $(EXE)

$(EXE): $(OBJ)
        $(CC) $(OBJ) -o $@

%.o: %.c
        $(CC) $(CFLAGS) $< -o $@

clean:
        rm -rf $(OBJ) $(EXE)
Copy to Clipboard Toggle word wrap

Adding more source files to such Makefile requires only adding them to the line where the SOURCE variable is defined.

2.5.2. Example: Building a C program using a Makefile

To automate C program builds and manage compilation dependencies efficiently, use a Makefile. Create a script that streamlines repetitive tasks to establish a consistent and reliable build process.

Prerequisites

  • You must understand the concepts of Makefiles and make.

Procedure

  1. Create a directory hellomake:

    $ mkdir hellomake
    Copy to Clipboard Toggle word wrap
  2. Change to the hellomake directory:

    $ cd hellomake
    Copy to Clipboard Toggle word wrap
  3. Create a file hello.c with the following contents:

    #include <stdio.h>
    
    int main(int argc, char *argv[]) {
      printf("Hello, World!\n");
      return 0;
    }
    Copy to Clipboard Toggle word wrap
  4. Create a file Makefile with the following contents:

    CC=gcc
    CFLAGS=-c -Wall
    SOURCE=hello.c
    OBJ=$(SOURCE:.c=.o)
    EXE=hello
    
    all: $(SOURCE) $(EXE)
    
    $(EXE): $(OBJ)
            $(CC) $(OBJ) -o $@
    
    %.o: %.c
            $(CC) $(CFLAGS) $< -o $@
    
    clean:
            rm -rf $(OBJ) $(EXE)
    Copy to Clipboard Toggle word wrap
    Important

    The Makefile recipe lines must start with the tab character! When copying the text above from the documentation, the cut-and-paste process may paste spaces instead of tabs. If this happens, correct the issue manually.

  5. Run make:

    $ make
    Copy to Clipboard Toggle word wrap
    $ gcc -c -Wall hello.c -o hello.o
    $ gcc hello.o -o hello
    Copy to Clipboard Toggle word wrap

    This creates an executable file hello.

  6. Run the executable file hello:

    $ ./hello
    Copy to Clipboard Toggle word wrap
    Hello, World!
    Copy to Clipboard Toggle word wrap
  7. Run the Makefile target clean to remove the created files:

    $ make clean
    Copy to Clipboard Toggle word wrap
    # rm -rf hello.o hello
    Copy to Clipboard Toggle word wrap

2.5.3. Documentation resources for make

To find more information about make, see the resources listed in this section.

Installed documentation

  • Use the man and info tools to view manual pages and information pages installed on your system:

    1. View the make manual page:

      $ man make
      Copy to Clipboard Toggle word wrap
    2. View the make information page:

      $ info make
      Copy to Clipboard Toggle word wrap

Online documentation

Red Hat logoGithubredditYoutubeTwitter

Apprendre

Essayez, achetez et vendez

Communautés

À propos de la documentation Red Hat

Nous aidons les utilisateurs de Red Hat à innover et à atteindre leurs objectifs grâce à nos produits et services avec un contenu auquel ils peuvent faire confiance. Découvrez nos récentes mises à jour.

Rendre l’open source plus inclusif

Red Hat s'engage à remplacer le langage problématique dans notre code, notre documentation et nos propriétés Web. Pour plus de détails, consultez le Blog Red Hat.

À propos de Red Hat

Nous proposons des solutions renforcées qui facilitent le travail des entreprises sur plusieurs plates-formes et environnements, du centre de données central à la périphérie du réseau.

Theme

© 2026 Red Hat
Retour au début