Comprehensive Analysis of Static and Dynamic Libraries! Make Your Linux More Efficient and Intelligent!

Linux | Red Hat Certified | IT Technology | Operations Engineer

👇 Join our technical exchange QQ group with 1000 members, note 【Public Account】 for faster approval

Comprehensive Analysis of Static and Dynamic Libraries! Make Your Linux More Efficient and Intelligent!

1. Basic Concepts of Static and Dynamic Libraries

A library is a collection of pre-written, reusable code that exists in binary form and can be loaded into memory by the operating system for execution. Libraries are divided into static libraries and dynamic libraries.

A static library (.a) is linked to the executable file during the program compilation and linking process (thus generally resulting in a larger file size) and does not depend on the static library at runtime;

A dynamic library (.so) is short for “Shared Object” and links the code at runtime, allowing multiple programs to share it.

Note:

An executable program may use many libraries, some of which are static and some dynamic. Our compiler defaults to using dynamic libraries, and only if the dynamic .so file cannot be found will it use the corresponding static library. We can also use the gcc -static option to force linking to static libraries.

gcc -static main.c -o main_static

2. Principles and Operations of Static Libraries

2.1 Principle Analysis

Comprehensive Analysis of Static and Dynamic Libraries! Make Your Linux More Efficient and Intelligent!

The principle of static libraries is to compile related source files into .o object files and then package them into a libXXX.a file.

When the main program’s main.c is compiled into main.o, it will automatically link with the static library to form an executable program. In this process, the ar command is used to generate the static library, such as ar -rc libmymath.a add.o sub.o, where the -rc option indicates that if the target static library file exists, it will be replaced; if it does not exist, it will be created.

Explanation:

The command ar -rc libmymath.a add.o sub.o adds the two object files add.o and sub.o to the static library libmymath.a. If the libmymath.a library file does not exist, a new one will be created; if it already exists, add.o and sub.o will be inserted into the library, and if there are files with the same name in the library, the new files will replace the old ones. Moreover, no prompt information will be displayed during the creation or updating of the library file.

2.2 Production Process

Taking the creation of a simple math library as an example, first write the source file, such as mymath.c, defining the mathematical operation functions, and mymath.h, declaring the functions. Then write the Makefile file with the following content:

# Define a variable lib, with the value being the static library file name libmymath.a
lib=libmymath.a
# This is a target rule, the target is to generate the static library libmymath.a
# This rule indicates that generating libmymath.a depends on the mymath.o file
$(lib): mymath.o    # Use the ar command to package the mymath.o file into the static library libmymath.a
    # $@ represents the target file, i.e., libmymath.a
    # $^ represents all the dependency files, i.e., mymath.o
    ar -rc $@ $^
# This is a target rule, the target is to generate the target file mymath.o
# This rule indicates that generating mymath.o depends on the mymath.c file
mymath.o: mymath.c    # Use the gcc compiler to compile the mymath.c file into the target file mymath.o
    # -c option indicates to only compile, not link
    # $^ represents all the dependency files, i.e., mymath.c
    gcc -c $^
# .PHONY declares some phony targets, phony targets are not real files, but actions
# Here, clean is declared as a phony target, even if there is a file named clean in the current directory, make will execute the clean corresponding command.
.PHONY: clean
# This is a phony target rule used to clean up generated intermediate files and static library files
# When executing make clean, all .o files and .a files in the current directory will be deleted
clean:    rm -f *.o *.a

Executing the Makefile will generate the static library. After that, the library files and header files can be organized into the corresponding directories for easy distribution and use.

2.3 Usage Methods and Path Issues

When using static libraries, attention must be paid to the path settings of header files and library files. If the header file path is not specified, gcc will search the system paths (such as /usr/include) and the current directory by default. The header file search path can be specified using the -I option, such as gcc main.c -I./lib/include. For library files, gcc will search the system paths (such as /lib64, /usr/lib) and the current directory by default. If not found, the -L option must be used to specify the library path, such as gcc main.c -L./lib/mymathlib. In addition, the -l option must be used to specify the library name to be linked (removing the prefix lib and the suffix .a) , such as gcc main.c -I./lib/include -L./lib/mymathlib -lmymath.

-I: Specify header file search path
-L: Specify library path
-l: Specify library name
Test the target file generation after the static library is deleted, the program can still run. The library file name and the name of the introduced library: remove the prefix lib, remove the suffix .so, .a, such as: libc.so -> c

2.4 The Role of errno

The library often provides a global variable errno to indicate runtime errors. For example, in the division function of the math library, when the divisor is 0, errno can be set to indicate an error, making it easier for the caller to determine the correctness of the result and obtain the reason for the error.

2.5 Library Installation

The installation of a library essentially involves placing the library files and header files in system-searchable paths, which can be achieved by copying files or creating soft links. For example, copy the header files to /usr/include and the library files to /lib64, after which you only need to use the -l option to specify the library name during compilation. However, it is not recommended to arbitrarily install third-party libraries in system paths to avoid polluting the system libraries.

3. Principles and Operations of Dynamic Libraries

3.1 Principles and Commands

The creation of dynamic libraries also starts with compiling source files into .o files, but the -fPIC option must be added during compilation to generate position-independent code, allowing the library to be loaded at any position in virtual memory. The command to generate a dynamic library is gcc -shared -o libmymethod.so *.o, where the -shared option tells gcc to generate a shared library.

Explanation:

Assuming there are two object files add.o and sub.o in the current directory, executing the command gcc -shared -o libmymethod.so *.o will link add.o and sub.o into a dynamic link library named libmymethod.so.

3.2 Separation of Static and Dynamic Libraries in Practice

In actual development, static and dynamic libraries can be managed separately. By writing a Makefile, both static and dynamic libraries can be generated, such as:

# Define dynamic library variable, value is the dynamic library file name
libmymethod.so
dynamic-lib=libmymethod.so
# Define static library variable, value is the static library file name
libmymath.a
static-lib=libmymath.a
# Declare all as a phony target, phony targets are not real files, used to define a set of operations.
.PHONY: all
# all target, depends on the generation of dynamic and static libraries, executing make or make all will build these two libraries
all: $(dynamic-lib) $(static-lib)
# Rule for building static library libmymath.a, depends on mymath.o file
$(static-lib): mymath.o    # Use ar tool to package mymath.o into static library libmymath.a
    # $@ represents the target file, i.e., libmymath.a
    # $^ represents all the dependency files, i.e., mymath.o
    ar -rc $@ $^
# Rule for generating mymath.o from mymath.c
mymath.o: mymath.c    # Use gcc compiler to compile mymath.c into target file mymath.o
    # -c option indicates to only compile, not link
    gcc -c $^
# Rule for building dynamic library libmymethod.so, depends on mylog.o and myprint.o files
$(dynamic-lib): mylog.o myprint.o    # Use gcc compiler to generate shared library (dynamic library) libmymethod.so
    # -shared option is used to generate shared library
    # $@ represents the target file, i.e., libmymethod.so
    # $^ represents all the dependency files, i.e., mylog.o and myprint.o
    gcc -shared -o $@ $^
# Rule for generating mylog.o from mylog.c
mylog.o: mylog.c    # Use gcc compiler to compile mylog.c into target file mylog.o, generating position-independent code
    # -fPIC option is used to generate position-independent code, making the generated target file usable for creating shared libraries
    gcc -fPIC -c $^
# Rule for generating myprint.o from myprint.c
myprint.o: myprint.c    # Use gcc compiler to compile myprint.c into target file myprint.o, generating position-independent code
    # -fPIC option is used to generate position-independent code, making the generated target file usable for creating shared libraries
    gcc -fPIC -c $^
# Declare clean as a phony target, used to clean up generated files.
.PHONY: clean
# clean target, executing make clean will delete all .o, .a, .so files and mylib directory
clean:    rm -rf *.o *.a *.so mylib
# Declare output as a phony target, used to organize and output library files and header files.
.PHONY: output
# output target, executing make output will create mylib directory structure and copy header files, static libraries, and dynamic library files to the corresponding locations
output:    # Create mylib/include directory, if the directory already exists, do not report an error
    mkdir -p mylib/include    # Create mylib/lib directory, if the directory already exists, do not report an error
    mkdir -p mylib/lib    # Copy all .h header files to mylib/include directory
    cp *.h mylib/include    # Copy all .a static library files to mylib/lib directory
    cp *.a mylib/lib    # Copy all .so dynamic library files to mylib/lib directory
    cp *.so mylib/lib

This allows for clear management of different types of libraries, improving project maintainability.

3.3 Dynamic Library Loading Issues

After generating the executable program, there may be cases where the dynamic library cannot be found at runtime. This is because the system loader cannot find the dynamic library path at runtime, even if the library path was specified during compilation, it must be re-informed to the system at runtime.

Comprehensive Analysis of Static and Dynamic Libraries! Make Your Linux More Efficient and Intelligent!

3.4 Methods to Solve Loading Issues

Comprehensive Analysis of Static and Dynamic Libraries! Make Your Linux More Efficient and Intelligent!Comprehensive Analysis of Static and Dynamic Libraries! Make Your Linux More Efficient and Intelligent!

There are several methods to solve dynamic library loading issues. You can copy the dynamic library to the system’s default library path (such as /usr/lib64);

You can also create a soft link in the system’s default library path, such as sudo ln -s /home/whb/108/Lesson24/test/mylib/lib/libmymethod.so /lib64/libmymethod.so;

Additionally, you can add the library’s path to the environment variable LD_LIBRARY_PATH, but this method will not persist after closing the shell. If you want it to be permanent, you need to write the environment variable into the system startup configuration file (such as ~/.bash_profile);

Moreover, you can create a configuration file in the /etc/ld.so.conf.d directory, add the dynamic library path, and then execute ldconfig to reload.

3.5 Introduction to the ncurses Library

Comprehensive Analysis of Static and Dynamic Libraries! Make Your Linux More Efficient and Intelligent!

ncurses is a terminal-based graphics library that can be used to control the terminal interface. In CentOS systems, it can be installed using the command sudo yum install ncurses-devel. After installation, developers can utilize its rich features to create interactive terminal applications, enhancing user experience.

4. Underlying Principles of Dynamic Loading

4.1 Dynamic Library Loading Mechanism

When the CPU executes code and calls a library function, it first searches in the shared area. If the library file is not loaded into memory, it will trigger a page fault, and the system will load the dynamic library file and establish a mapping relationship with the page table. After that, the program executes in the process address space. The system will manage the loading status of multiple dynamic libraries to ensure the program runs correctly.

How the process sees the dynamic library:

Comprehensive Analysis of Static and Dynamic Libraries! Make Your Linux More Efficient and Intelligent!

How processes share libraries:

Comprehensive Analysis of Static and Dynamic Libraries! Make Your Linux More Efficient and Intelligent!

4.2 Detailed Explanation of Process Address Space

After the program is compiled, it already has the concept of addresses internally, using flat addressing mode (0 – 4GB) where the addresses are logical addresses, also known as virtual addresses. When compiling into an executable program, a table storing the addresses of each segment is generated, with the header address being the address of the main function, from which the CPU starts execution. During execution, the instructions read by the CPU may contain data or virtual addresses. If the virtual address has no mapping relationship in the page table, a page fault will occur, loading the required content into memory and establishing the mapping.

4.3 Dynamic Library Address Handling

Since there may be multiple dynamic libraries, it is difficult to ensure that each library is loaded at a fixed position, so relative addressing is used. The -fPIC option in gcc allows the compiler to use offsets to address functions in the library, and when the library is loaded, the library functions are found using the starting address plus the offset, enabling the library to be loaded at any position in virtual memory!

For course inquiries, add: HCIE666CCIE

↓ Or scan the QR code below ↓

Comprehensive Analysis of Static and Dynamic Libraries! Make Your Linux More Efficient and Intelligent!

What technical points and content would you like to see?

You can leave a message below to let us know!

Leave a Comment