Chapter 2. Creating C or C++ Applications
Red Hat offers multiple tools for creating applications by using the C and C++ languages. Learn about some of the most common development tasks.
2.1. GCC in RHEL 10 Copy linkLink copied to clipboard!
Red Hat Enterprise Linux 10 is distributed with the GNU Compiler Collection (GCC) 14 as the standard compiler.
The default language standard setting for GCC 14 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 remain experimental.
2.2. Building code with GCC Copy linkLink copied to clipboard!
Transform source code into executable code. Compile source files, link object code, and understand the relationship between different code forms. Optimize, harden, and debug your applications by using GCC.
2.2.1. Relationship between code forms Copy linkLink copied to clipboard!
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).
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 gccObject code, created by compiling the source code with a compiler. This is an intermediate form.
The object code files use the
.oextension.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
.sofile name extension.
Library archive files for static linking also exist. This is a variant of object code that uses the .a file name extension. Do not use static linking.
Producing executable code from source code is performed in two steps, which require different applications or tools:
- Source files are compiled to object files.
- Object files and libraries are linked (including the previously compiled sources).
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.
You can run GCC to compile only, link only, or perform both steps. This is determined by the types of inputs and requested type of output.
Because larger projects require a build system that 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 Copy linkLink copied to clipboard!
To create object code files from source files without creating an executable file immediately, instruct GCC to create only object code files as its output. This is a basic operation of the build process for larger projects.
Prerequisites
- C or C++ source code file(s)
- GCC installed on the system
Procedure
- In Terminal, open to the directory containing the source code file(s).
Run
gccwith the-coption:$ gcc -c source.c another_source.cObject files are created, with their file names reflecting the original source code files:
source.cresults insource.o.NoteWith C++ source code, replace the
gcccommand withg++for convenient handling of C++ Standard Library dependencies.
Additional resources
2.2.3. Enabling debugging of C and C++ applications with the GCC Copy linkLink copied to clipboard!
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
gccpackage installed.
Procedure
Compile and link your code with the
-goption to generate debugging information:$ gcc ... -g ...Optional: Set the optimization level to
-Og:$ gcc ... -g -Og ...Compiler optimizations can make executable code hard to relate to the source code. The
-Ogoption optimizes the code without interfering with debugging. However, be aware that changing optimization levels can alter the program’s behavior.Optional: Use
-gfor moderate debugging information, or-g3to include macro definitions:$ gcc ... -g3 ...
Verification
Test the code by using the
-fcompare-debugGCC option:$ gcc -fcompare-debug ...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-debugoption significantly increases compilation time.
2.2.4. Code optimization with the GCC Copy linkLink copied to clipboard!
Compiler optimization transforms your code for efficiency. Use GCC options to balance compilation overhead with execution speed or binary size suitable for your deployment. By selecting the appropriate optimization level, you can achieve faster execution speeds or smaller binary sizes tailored to your application’s deployment requirements.
With GCC, you can set the optimization level by using the -Olevel option. This option accepts a set of values in place of the level.
| Level | Description |
|---|---|
|
| Optimize for compilation speed - no code optimization (default). |
|
| Optimize to increase code execution speed (the larger the number, the greater the speed). |
|
| Optimize for file size. |
|
|
Same as a level |
|
| 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 gcc man page for more details.
2.2.5. Options for hardening code with the GCC Copy linkLink copied to clipboard!
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=3 ...-
For programs, add the
-fPIEand-piePosition Independent Executable options. -
For dynamically linked libraries, the mandatory
-fPIC(Position Independent Code) option indirectly increases security.
-
For programs, add the
- 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 ...- -
fhardened -
GCC 14 provides a new flag,
-fhardened, which in turn enables several other flags to improve the security of generated code without impacting the ABI. - -
fanalyzer -
GCC provides a flag,
-fanalyzer, which triggers warnings about potential issues in the source code, including security-related issues. Because-fanalyzerfrequently has false positives and negatives, it should be used to locate potential bugs that should be investigated further and not as a formal analysis tool. This flag greatly increases the time and memory taken during compilation. Use only on C code.
2.2.6. Linking code to create executable files Copy linkLink copied to clipboard!
To create an executable file, linking combines all object files and libraries. This is the final step when building a C or C++ application.
Prerequisites
- One or more object file(s)
- GCC must be installed on the system
Procedure
- Change to the directory containing the object code file(s).
Run
gcc:$ gcc ... objfile.o another_object.o ... -o executable-fileAn 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.
For more information, see Using libraries with GCC.
NoteWith C++ source code, replace the
gcccommand withg++for convenient handling of C++ Standard Library dependencies.
Additional resources
2.2.7. Example: Building a C program with the GCC (compiling and linking in one step) Copy linkLink copied to clipboard!
To build a basic C program, use GCC to compile source code directly into an executable. This single-step compilation command creates a foundation for developing simple applications on Red Hat Enterprise Linux.
Procedure
Create a directory
hello-c:$ mkdir hello-cChange to the created directory:
$ cd hello-cCreate file
hello.cwith the following contents:#include <stdio.h> int main() { printf("Hello, World!\n"); return 0; }Compile and link the code with GCC:
$ gcc hello.c -o helloworldThis compiles the code, creates the object file
hello.o, and links the executable filehelloworldfrom the object file.Run the resulting executable file:
$ ./helloworldHello, World!
Additional resources
2.2.8. Example: Building a C program with the GCC (compiling and linking in two steps) Copy linkLink copied to clipboard!
To build a simple C program, compile a source file into an object file and then link it to create an executable. This two-step process demonstrates the fundamentals of how to use the GNU Compiler Collection (GCC) compiler workflow for C development.
Procedure
Create a directory
hello-c:$ mkdir hello-cChange to the created directory:
$ cd hello-cCreate file
hello.cwith the following contents:#include <stdio.h> int main() { printf("Hello, World!\n"); return 0; }Compile the code with GCC:
$ gcc -c hello.cThe object file
hello.ois created.Link an executable file
helloworldfrom the object file:$ gcc hello.o -o helloworldRun the resulting executable file:
$ ./helloworld Hello, World!Optional: Change back to the parent directory:
$ cd ..Optional: Remove the
hello-cdirectory:$ rm -r hello-c
Additional resources
2.2.9. Example: Building a C++ program with the GCC (compiling and linking in one step) Copy linkLink copied to clipboard!
To build a minimal C++ program, use the following steps.
In this example, compiling and linking the code is done in one step.
Procedure
Create a directory
hello-cpp:$ mkdir hello-cppChange to the created directory:
$ cd hello-cppCreate file
hello.cppwith the following contents:#include <iostream> int main() { std::cout << "Hello, World!\n"; return 0; }Compile and link the code with
g++:$ g++ hello.cpp -o helloworldThis compiles the code, creates the object file
hello.o, and links the executable filehelloworldfrom the object file.Run the resulting executable file:
$ ./helloworldHello, World!Optional: Change back to the parent directory:
$ cd ..Optional: Remove the
hello-cppdirectory:$ rm -r hello-cpp
2.2.10. Example: Building a C++ program with the GCC (compiling and linking in two steps) Copy linkLink copied to clipboard!
To build a minimal C++ program by using a two-step process, first compile the source into an object file, and then link it to create the executable. This approach demonstrates modular building with the GNU Compiler Collection (GCC) compiler.
Procedure
Create a directory
hello-cpp:$ mkdir hello-cppChange to the created directory:
$ cd hello-cppCreate file
hello.cppwith the following contents:#include <iostream> int main() { std::cout << "Hello, World!\n"; return 0; }Compile the code with
g++:$ g++ -c hello.cppThe object file
hello.ois created.Link an executable file
helloworldfrom the object file:$ g++ hello.o -o helloworldRun the resulting executable file:
$ ./helloworldHello, World!Optional: Change back to the parent directory:
$ cd ..Optional: Remove the
hello-cppdirectory:$ rm -r hello-cpp
2.3. Creating libraries with GCC Copy linkLink copied to clipboard!
Learn about the steps to create libraries and the concepts the Linux operating system uses for libraries, including sonames, symbolic links, and library file naming conventions.
2.3.1. The soname mechanism Copy linkLink copied to clipboard!
To manage multiple compatible versions of a library, dynamically loaded libraries (shared objects) use the soname mechanism.
- 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
-
The soname mechanism resolves these problems by using naming conventions to indicate compatibility. A
foolibrary 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.
During the build, the linker searches for a symbolic link named libfoo.so that points to the library file. 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 by 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.
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
Replace somelibrary with the actual file name of the library that you want to examine.
- Finding a library name and version in a file name
As an example, consider a library which is present as a file
libevent-2.0.so.5.1.9. To find the actual components:-
Start by ignoring the standard library file name prefix
lib. -
Break the remainder into the two parts preceding and following the string
.so.. -
The first part is
event-2.0, which is the name of the library. -
The second part is
5.1.9. To find the X version component, take everything before first dot:5. -
The rest is the Y version component:
1.9.
-
Start by ignoring the standard library file name prefix
Therefore the library’s name is event-2.0, the X version component is 5, and Y is 1.9.
The soname of this library file is everything up to the Y component: libevent-2.0.so.5.
When a newer but still compatible version of the library is released, it uses the same soname, and the Y version component is increased. The new file name is libevent-2.0.so.5.1.10.
2.3.2. Creating dynamic libraries with the GCC Copy linkLink copied to clipboard!
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
- Change to the directory with library sources.
Compile each source file to an object file with the Position independent code option
-fPIC:$ gcc ... -c -fPIC some_file.c ...The object files have the same file names as the original source code files, but their extension is
.o.Link the shared library from the object files:
$ gcc -shared -o libfoo.so.x.y -Wl,-soname,libfoo.so.x some_file.o ...The used major version number is X and minor version number Y.
Copy the
libfoo.so.x.yfile 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/lib64Note that you need root permissions to manipulate files in this directory.
Create the symlink for the soname:
# ln -s libfoo.so.x.y libfoo.so.xCreate the symlink for the linker name:
# ln -s libfoo.so.x libfoo.so
Additional resources
2.3.3. Creating static libraries with the GCC and ar Copy linkLink copied to clipboard!
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.
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 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
Create intermediate object files with GCC.
$ gcc -c source_file.c ...Append more source files if required. The resulting object files share the file name but use the
.ofile name extension.Turn the object files into a static library (archive) using the
artool from thebinutilspackage.$ ar rcs libfoo.a source_file.o ...File
libfoo.ais created.Use the
nmcommand to inspect the resulting archive:$ nm libfoo.a- Copy the static library file to the appropriate directory.
When linking against the library, GCC will automatically recognize from the
.afile name extension that the library is an archive for static linking.$ gcc ... -lfoo ...
2.4. Using Libraries with the GCC Copy linkLink copied to clipboard!
Libraries are collections of re-usable code, which can make coding easier and more effective. Understand library naming conventions and the distinction between static and dynamic linking. Link applications with static or dynamic libraries by using the GCC, and optimize your code with Link Time Optimization (LTO).
2.4.1. Library naming conventions Copy linkLink copied to clipboard!
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
-loption as-lfoo:$ gcc ... -lfoo ...-
When creating the library, the full file name
libfoo.soorlibfoo.amust be specified.
Additional resources
2.4.2. Static and dynamic linking Copy linkLink copied to clipboard!
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.
Static linking has numerous disadvantages and should be avoided, particularly for whole applications and the glibc and libstdc++ libraries:
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.
However, 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 overhead introduced by position-independent code (PIC).
Security: Dynamically linked libraries that 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 seems 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.
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.
- Cases for static linking
Static linking might be a reasonable choice in some cases, such as:
- When using a library that is not enabled for dynamic linking.
-
When fully static linking is required for running code in an empty chroot environment or container. However, static linking by using the
glibc-staticpackage is not supported by Red Hat.
2.4.3. Link time optimization Copy linkLink copied to clipboard!
Link time optimization (LTO) optimizes code across all translation units of the program by using intermediate representation at link time. This results in smaller and faster executable files and libraries. Additionally, LTO analyzes package source code at compile time more thoroughly, which improves various GCC diagnostics for potential coding errors.
- Known issues
LTO has the following known issues:
Violating the One Definition Rule (ODR) produces a
-WodrwarningViolations of the ODR resulting in undefined behavior produce a
-Wodrwarning. This usually points to a bug in your program. The-Wodrwarning is enabled by default.LTO causes increased memory consumption
The compiler consumes more memory when it processes the translation units the program consists of. On systems with limited memory, disable LTO or lower the parallelism level when building your program.
GCC removes seemingly unused functions
GCC might remove functions it considers unused because the compiler is unable to recognize which symbols an asm() statement references. A compilation error might occur as a result. To prevent this, add
__attribute__((used))to the symbols you use in your program.Compiling with the
-fPICoption causes errorsBecause GCC does not parse the contents of asm() statements, compiling your code with the
-fPICcommand-line option can cause errors. To prevent this, use the-fno-ltooption when compiling your translation unit. More information is available at LTO FAQ {mdash}; Symbol usage from assembly language.Implementing symbol versioning by using the
.symverdirective in an asm() statement is not compatible with LTO. However, it is possible to implement symbol versioning using thesymverattribute. For example:__attribute__ ((_symver_ ("<symbol>@VERS_1"))) void <symbol>_v1 (void) { }
2.4.4. Library use with GCC Copy linkLink copied to clipboard!
A library is a reusable package of code. A C or C++ library consists of the library code and 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 GCC where the header files are, use the -I option:
$ gcc ... -Iinclude_path ...
Replace include_path with the actual path to the header file directory.
For example, to specify a relative path some/interesting/directory:
$ gcc ... -Isome/interesting/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.
-
Static libraries are available as archive files. They contain a group of object files. The archive file has a file name extension
To tell GCC where the archives or shared object files of a library are, use the -L option:
$ gcc ... -Llibrary_path -lfoo ...
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 you compile and link in a single
gcccommand, combine the compile-time and link-time options.
2.4.5. Linking static libraries with the GCC Copy linkLink copied to clipboard!
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.
Red Hat discourages use of static linking for security reasons. See Static and dynamic linking. Use static linking only when necessary, especially against libraries provided by Red Hat.
Prerequisites
- GCC must be installed on your system.
- You must understand static and dynamic linking.
- You have a set of source or object files forming a valid program, requiring some static library foo and no other libraries.
The foo library is available as a file
libfoo.a, and no filelibfoo.sois provided for dynamic linking.NoteMost libraries that are part of Red Hat Enterprise Linux are supported for dynamic linking only. The steps below only work for libraries that are not enabled for dynamic linking.
See Static and dynamic linking
Procedure
To link a program from source and object files, adding a statically linked library foo, which is to be found as a file
libfoo.a.- Change to the directory containing your code.
Compile the program source files with headers of the foo library:
$ gcc ... -Iheader_path -c ...Replace header_path with a path to a directory containing the header files for the foo library.
Link the program with the foo library:
$ gcc ... -Llibrary_path -lfoo ...Replace library_path with a path to a directory containing the file
libfoo.a.To run the program later:
$ ./programWarningThe
-staticGCC option related to static linking forbids all dynamic linking. Instead, use the-Wl,-Bstaticand-Wl,-Bdynamicoptions to control linker behavior more precisely. See Static and dynamic libraries with GCC.
2.4.6. Using a dynamic library with the GCC Copy linkLink copied to clipboard!
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.
Procedure
To link a program against a dynamic library foo:
$ gcc ... -Llibrary_path -lfoo ...To use a
run pathvalue stored in the executable file:The
run pathis 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 uses therun pathvalue to locate the library files.While linking with GCC, store the path library_path as
run path:$ gcc ... -Llibrary_path -lfoo -Wl,-run path=library_path ...The path library_path must point to a directory containing the file libfoo.so.
ImportantDo not add a space after the comma in the
-Wl,-run path=option.Run the program:
$ ./programOn Red Hat Enterprise Linux 10, the
run pathencoded in the program during linking is used only if the linked libraries are not found inLD_LIBRARY_PATH. You can use the-Wl,--disable-new-dtagsoption to restore the old behaviour in Red Hat Enterprise Linux 10, where the run path is searched before theLD_LIBRARY_PATH.
To use the
LD_LIBRARY_PATHenvironment variable:Another way to set search paths to locate libraries is to use the
LD_LIBRARY_PATHenvironment 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 and must be set for every program invocation.Set the
LD_LIBRARY_PATHenvironment variable:$ export LD_LIBRARY_PATH=library_path:$LD_LIBRARY_PATHRun the program:
$ ./program
Optional: Place the library into the default directories.
The runtime linker configuration specifies a number of directories as a default location of dynamic library files. To use this default behaviour, copy your library to the appropriate directory.
2.4.7. Static and dynamic libraries with GCC Copy linkLink copied to clipboard!
Combining static and dynamic linking balances portability and efficiency. The GNU Compiler Collection (GCC) automatically selects shared objects over static archives unless configured otherwise. That resolution order determines which library versions are linked and which linker and path options influence the outcome.
Static libraries are packaged as libname.a archive files. Dynamic libraries are packaged as libname.so shared objects. Together, those are the two shapes gcc must choose between when both linking modes are available for the same library name.
For each -lfoo option, gcc searches the library directories (including paths from -Lpath) for libfoo.so first and libfoo.a second. Depending on what gcc finds on the search path, linking proceeds in one of these ways:
- 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, or 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
-lfoooption. However, it is possible to specify the full path to filelibfoo.acontaining the library instead:$ gcc ... path/to/libfoo.a ...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
-Wloption The gcc option
-Wlis a special option for passing options to the underlying linker. Syntax of this option differs from the other gcc options. The-Wloption 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
-Bstaticoption to link libraries following this option statically, and-Bdynamicto link them dynamically. After passing-Bstaticand a library to the linker, the default dynamic linking behaviour must be restored manually for the following libraries to be linked dynamically with the-Bdynamicoption.Link a program with library first statically (
libfirst.a) and second dynamically (libsecond.so):$ gcc ... -Wl,-Bstatic -lfirst -Wl,-Bdynamic -lsecond ...Notegcc can be configured to use linkers other than the default ld.
2.5. Managing More Code with Make Copy linkLink copied to clipboard!
The GNU make utility, commonly abbreviated as make, is a tool for controlling the generation of executables from source files. The make utility 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 Copy linkLink copied to clipboard!
To create a usable form (usually executable files) from the source files of a particular project, perform several necessary steps. Record the actions and their sequence to be able to repeat them later.
Red Hat Enterprise Linux contains GNU make, a build system designed for this purpose.
- What is GNU
make -
GNU
makereads 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.
To run make with a specific target:
$ make target
- Makefile structure and syntax
- 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.
- Basic Makefile example
-
Consider the following
Makefilefor 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
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.
- Advanced Makefile with variables
- 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)
Adding more source files to such Makefile requires only adding them to the line where the SOURCE variable is defined.
- Installed documentation
-
Use the
manutility to view manual pages installed on your system:
$ man makeUse the
infoutility to view information pages installed on your system:$ info make
-
Use the
2.5.2. Example: Building a C program using a Makefile Copy linkLink copied to clipboard!
To build a sample C program by using a Makefile, follow the steps in this example.
Prerequisites
Procedure
Create a directory
hellomake:$ mkdir hellomakeChange to the created directory:
$ cd hellomakeCreate a file
hello.cwith the following contents:#include <stdio.h> int main(int argc, char *argv[]) { printf("Hello, World!\n"); return 0; }Create a file
Makefilewith 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)ImportantThe Makefile recipe lines must start with the tab character! When copying the text above from the documentation, the cut-and-paste process might paste spaces instead of tabs. If this happens, correct the issue manually.
Run
make:$ makegcc -c -Wall hello.c -o hello.o gcc hello.o -o helloThis creates an executable file
hello.Run the executable file
hello:$ ./helloHello, World!Run the Makefile target
cleanto remove the created files:$ make cleanrm -rf hello.o hello
Additional resources