Linux | Red Hat Certified | IT Technology | Operations Engineer
đ Join our technical exchange QQ group with a note of ăPublic Accountă for faster approval
1. Concept of Libraries
A library (Library) is a collection of pre-compiled code (functions, classes, data, etc.) that can be shared and reused by multiple programs. The core purpose of a library is code reuse, avoiding the need for developers to rewrite the same functionality (such as file operations, mathematical calculations, etc.).
Essentially, a library is a binary form of executable code that can be loaded into memory by the operating system for execution.
Based on the form of code reuse, libraries can be divided into two types:
Static Library: .a [Linux], .lib [Windows]Dynamic Library: .so [Linux], .dll [Windows]
Libraries are used during the linking step, which is essentially a collection of .o files. We can use specific tools to package these .o files into a library.
For convenience, here is a simple C language library we implementedâmyc:
// mystdio.h#pragma once#include <stdio.h>#define MAX 1024#define NONE_FLUSH (1<<0)#define LINE_FLUSH (1<<1)#define FULL_FLUSH (1<<2)typedef struct IO_FILE{ int fileno; int flag; char outbuffer[MAX]; int bufferlen; int flush_method;}MyFile;MyFile *MyFopen(const char *path, const char *mode);void MyFclose(MyFile *);int MyFwrite(MyFile *, void *str, int len);void MyFFlush(MyFile *);// mystdio.c#include "mystdio.h"#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <string.h>#include <stdlib.h>#include <unistd.h>static MyFile *BuyFile(int fd, int flag){ MyFile *f = (MyFile*)malloc(sizeof(MyFile)); if(f == NULL) return NULL; f->bufferlen = 0; f->fileno = fd; f->flag = flag; f->flush_method = LINE_FLUSH; memset(f->outbuffer, 0, sizeof(f->outbuffer)); return f;}MyFile *MyFopen(const char *path, const char *mode){ int fd = -1; int flag = 0; if(strcmp(mode, "w") == 0) { flag = O_CREAT | O_WRONLY | O_TRUNC; fd = open(path, flag, 0666); } else if(strcmp(mode, "a") == 0) { flag = O_CREAT | O_WRONLY | O_APPEND; fd = open(path, flag, 0666); } else if(strcmp(mode, "r") == 0) { flag = O_RDWR; fd = open(path, flag); } else { //TODO } if(fd < 0) return NULL; return BuyFile(fd, flag);}void MyFclose(MyFile *file){ if(file->fileno < 0) return; MyFFlush(file); close(file->fileno); free(file);}int MyFwrite(MyFile *file, void *str, int len){ // 1. Copy memcpy(file->outbuffer+file->bufferlen, str, len); file->bufferlen += len; // 2. Try to determine if flush conditions are met! if((file->flush_method & LINE_FLUSH) && file->outbuffer[file->bufferlen-1] == '\n') { MyFFlush(file); } return 0;}void MyFFlush(MyFile *file){ if(file->bufferlen <= 0) return; // Copy data from user to kernel file buffer int n = write(file->fileno, file->outbuffer, file->bufferlen); (void)n; fsync(file->fileno); file->bufferlen = 0;}// mystring.h#pragma onceint my_strlen(const char *s);// mystring.c#include "mystring.h"int my_strlen(const char *s){ const char *start = s; while(*s) { s++; } return s - start;}
Next, we will introduce how to package the original files into static and dynamic libraries and how to use them.
2. Static Libraries (Static Libraries)
File extension:.a (Archive)
Characteristics:
During compilation, the library’s code is directly copied into the final executable file.
The generated executable file is independent and does not rely on library files in the runtime environment.
Disadvantages: The file size is larger, and updating the library requires recompiling the program.
Creation tools: ar (Archiving tool) + ranlib (Generate index).
Usage scenarios: Suitable for scenarios that require high program independence.
2.1 Creating Static Libraries
Static libraries are packaged using the ar command:
ar -rc lib[LibraryName].a [ObjectFiles]
lib[LibraryName].a is the naming convention for static library files; the actual library name should omit the lib prefix and the .a extension.
Generally, having only the library file is not enough; we also need to provide the library’s header files to the user. Therefore, we can use the following Makefile to package the library and its header files together for the user:
SRC=$(wildcard *.c)OBJ=$(SRC:.c=.o)libmyc.a:$(OBJ) ar -rc $@ $^$(OBJ):$(SRC) gcc -c $^.PHONY:outputoutput: mkdir -p lib/include mkdir -p lib/mylib cp -f *.h lib/include cp -f *.a lib/mylib tar czf lib.tgz lib.PHONY:cleanclean: rm -rf *.o libmyc.a lib lib.tgz
2.2 Using Static Libraries
gcc/g++ will link the C standard library by default, but the myc library is a third-party library we created, so we need to specify linking to the myc library during compilation.
Assuming the user has received our lib.tgz package, and the user’s code (usercode.c) calls methods from our library:
Note: Use tar xzf lib.tgz to unpack and obtain the lib directory.
// usercode.c#include "mystdio.h"#include "mystring.h"#include <string.h>#include <unistd.h>int main(){ MyFile *filep = MyFopen("./log.txt", "a"); if(!filep) { printf("fopen error!\n"); return 1; } int cnt = 10; while(cnt--) { char *msg = (char*)"hello myfile!!!"; MyFwrite(filep, msg, strlen(msg)); MyFFlush(filep); printf("buffer: %s\n", filep->outbuffer); sleep(1); } MyFclose(filep); // FILE *fp const char *str = "hello bit!\n"; printf("strlen: %d\n",my_strlen(str)); return 0;}
2.2.1 Explicitly Specifying Library File and Header File Paths
During compilation, it is necessary to specify the path of the header files, the path of the library files to be linked, and the specified library file:
gcc -o [ExecutableProgram] [ObjectFiles] -I [HeaderFilePath] -L [LibraryPath] -l [LibraryName]
2.2.2 Installing Library Files to System Directories
We know that installation essentially means copying files to specified system directories. This way, when we do not explicitly specify the library file’s directory, the system can find it in the default directory.
Of course, in addition to copying, creating links is also acceptable.
/lib, /usr/lib: System-level libraries/usr/local/lib: User-installed third-party libraries
We can copy the libmyc.a file to one of the three libraries to complete the installation, at which point there is no need to specify the library’s path:
However, it is not recommended to install in system-level libraries; it is better to install user-installed third-party libraries in /usr/local/lib.
2.2.3 Installing Header Files to System Directories
/usr/include: System-level header files/usr/local/include: Header files of locally installed third-party libraries/usr/include/<LibraryName> or /usr/local/include/<LibraryName>: Subdirectories for specific software
We can copy our header files to the above directories to complete the installation, at which point there is no need to specify the header file’s path:
3. Dynamic Libraries
File extension: .so (Shared Object)
Characteristics:
Loaded dynamically into memory during program execution, allowing multiple programs to share the same library code.
The executable file size is small, and updating the library does not require recompiling the program.
Disadvantages: It depends on library files in the runtime environment (if missing, the program cannot run).
Creation tools: gcc/g++ with the -shared option.
Usage scenarios: Most system libraries (such as glibc) and general-purpose libraries (such as OpenSSL).
3.1 Creating Dynamic Libraries
// When compiling object files, the -fPIC option is required, fPIC: generates position-independent code (position independent code) gcc/g++ -c -fPIC [SourceFiles]// When generating library files, the -shared option is required, shared: indicates generating shared library format gcc/g++ -o lib[LibraryName].so [ObjectFiles] -shared
Similarly, lib[LibraryName].so is the naming convention; the actual library name should omit the lib prefix and the .so extension.
We can use the following Makefile to package the library and its header files:
SRC=$(wildcard *.c)OBJ=$(SRC:.c=.o)libmyc.so:$(OBJ) gcc -shared -o $@ $^$(OBJ):$(SRC) gcc -fPIC -c $^.PHONY:outputoutput: mkdir -p lib/include mkdir -p lib/mylib cp -f *.h lib/include cp -f *.so lib/mylib tar czf lib.tgz lib.PHONY:cleanclean: rm -rf *.o libmyc.so lib lib.tgz
3.2 Using Dynamic Libraries
We will use the same code as an example; the method of installing the library and header files to system directories is the same as for static libraries, so we will not repeat it. However, we need to say a few more words about explicitly specifying the library file path.
3.2.1 Explicitly Specifying Library File Path
If we do not install the library file in the system directory and explicitly specify the library file in a certain path:
We will find that the compilation passed, but:
When we run the generated executable program, we will find that the system explicitly cannot find the corresponding library.
This is because we only told the compiler, “this library exists,” so the compiler completed the compilation.
However, dynamic linking occurs when the program is running, and the system is responsible for linking, but the system does not know where to find this library.
To allow the operating system to find the corresponding dynamic library when running our program, we can choose the installation method (which is completely consistent with the installation of static libraries), or take the measures mentioned in the following points.
Note: Unlike static linking, the following measures (including installation) do not require recompiling the executable file.
3.2.2 Loading Paths into Environment Variables
# LD_LIBRARY_PATH: Temporarily specify additional library search paths.export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/path/to/libs
Using the ldd command, you can view the libraries linked to the executable program and their paths:
However, this method is only temporary; it will become invalid when you log in again or update the environment variables.
3.2.3 Configuration Files
/etc/ld.so.conf: System-level library path configuration file/etc/ld.so.conf.d: User library path configuration file directory
We can directly add the path of our library file to /etc/ld.so.conf, but we still recommend adding our configuration file in the user library path configuration file directory:
Here, using sudo echo to create the file does not work; it can only be created using an editor.
Then load the configuration file:
sudo ldconfig
The result is the same as in 2.2.2, so we will not display it here.
4. Summary and Supplement
gcc/g++ compilation command supplement:
[-I]: Specify the directory of header files.[-L]: Specify the path of library files.[-l]: Specify the library to link.[-shared]: Generate dynamic library.[-fPIC]: Generate position-independent code.[-static]: Use static linking.
Static libraries are packaged using the ar command:
ar -rc lib[LibraryName].a [ObjectFiles]
Compile the static library with the user’s target files to generate the executable program.
Dynamic libraries are packaged using gcc/g++, and the object files need to carry position-independent code:
// When compiling object files, the -fPIC option is required, fPIC: generates position-independent code (position independent code) gcc/g++ -c -fPIC [SourceFiles]// When generating library files, the -shared option is required, shared: indicates generating shared library format gcc/g++ -o lib[LibraryName].so [ObjectFiles] -shared
During compilation, gcc/g++ needs to know that this library exists (by providing the path or installing it in the system and specifying the library name). At runtime, the system needs to be able to find this library (it needs to be installed in the system)..
Third-party libraries must be specified for linking during compilation.
In compilation, our system may have both a dynamic version and a static version of a certain library installed. In this case, the compiler will use dynamic linking by default if it can. If static linking is required, the -static option must be included; once this option is included, dynamic linking is disabled. If a library only has a dynamic link version, linking will fail.
For course inquiries, add: HCIE666CCIE
â Or scan the QR code below â
What technical points and content would you like to see?
You can leave a message below to let us know!