[Linux: dynamic library and static library]

1 The concept of dynamic library and static library

  • Static library ( .a ): The program links the code of the library into the executable file when compiling and linking. The static library is no longer needed when the program is running.
  • Dynamic library ( .so ): The code of the dynamic library is only linked when the program is running, and multiple programs share the code of the library. An executable file linked with a dynamic library only contains a table of the entry addresses of the functions it uses, rather than the entire machine code of the object file where the external function is located.
  • Before the executable file starts running, the machine code of the external function is copied from the dynamic library on the disk to the memory by the operating system. This process is called dynamic linking .
  • Dynamic libraries can be shared among multiple programs, so dynamic linking makes executable files smaller and saves disk space. The operating system uses a virtual memory mechanism to allow a dynamic library in physical memory to be shared by all processes that use the library, saving memory and disk space.

 we can simply

 Take a look at our commonly used c/c++ libraries:

 What is the name of the library?

Let's take the bottom two in the above figure to illustrate:

libstdc++.so.6  libstdc++.so.6.0.19

Our rule is: remove the beginning lib, remove the content after .so or .a

So the library names we get here are: stdc++ 

Generally speaking, cloud servers only have dynamic libraries by default, and static libraries need to be installed by ourselves.

C/C++ static library installation command:

sudo yum install -y glibc -static
sudo yum install -y libstdc++ -static

2 Why use a library

With the library, programmers can save a lot of trouble when developing. For example, if we want to write a cout printing function to help print, it will waste a lot of unnecessary time, so we generally like to include the header when writing C/C++ code. file, the header file contains declarations of some commonly used interfaces, so what about the definitions?

In fact, the compiler we use for the definition of the interface has helped us package the function definition and install it in the default search path. When we only need to include the header file, we will find the target file of the interface definition in the default path when linking. , and then link.

The VS2019 we often use is called an integrated development environment, which includes editors, header files and libraries, which is why there will be syntax reminders when we write the interface in the header file when we include the header file, which is actually in the header file find the interface.


3 Make a static library

We first create 4 files, compile the .c file in the four files to generate the .o file, and hand over the .o file and .h file to the otherUsr directory:

 Then copy main.c:

 Now we run in otherUsr:

 Obviously, it can run successfully at this time. But we usually package the .o file into a library, and the packaging command is:

ar -rc libXXX.a *.o

 Let's try:

 At this time, we put libmymath.a in a directory named dir for standardization, and put *.o files in the include directory:

 At this time, in order to be able to find *.h files and packaged library files, we need to add 3 options to help the compiler find:

-I *.h的文件路径
-L 打包库的路径    //L后面空格可加可不加
-l 打包库名    //l后面空格可加可不加,注意库名不包括lib前缀和.a后缀

 This will run successfully:

 But why don't we have to be so troublesome when using C/C++ libraries? The reason is that the C/C++ library is installed in the specified path, so we don't need to specify the path. If we want to add our own library and header files to the system default configuration, we can use the following method:

 

 The system default header file installation path is: /usr/include

The default library installation path is: /lib64

At this point we run:

 We found that an error will still be reported, but it is not that the header file cannot be found, but a link error, why?

Because this is a third-party library configured by ourselves, we must specify the library name, otherwise the library will not be found. Try when we specify the library name:

 Apparently it worked.

In fact, this is the third-party library, the library provided to us at the non-language level and the non-operating system level . The library downloaded by ourselves is generally downloaded to the default search path of the system compiler for easy use.

Summary: Use of third-party libraries

  • To specify header files and library files.
  • If it is not installed in the default search path of the system gcc/g++, the user must specify options to inform the compiler: a: where is the header file b: where is the library file c: where is the library file name
  • Copy the header file and library file we downloaded to the default path of the test system, and you need to bring the name of the library file to find the library file.
  • Generally speaking, ordinary users need sudo to escalate their rights when they install the downloaded library to the default path of the system.

 4 Make a dynamic library

First of all, when generating a dynamic library, the -fPIC option should be added to the target file, which means that the position-independent code

(position ignore code) As for why this is the case, an explanation will be given at the end of the article.

[grm@VM-8-12-centos owner]$ gcc -fPIC -c *.c
[grm@VM-8-12-centos owner]$ ll
total 24
-rw-rw-r-- 1 grm grm   61 Apr  1 22:32 my_add.c
-rw-rw-r-- 1 grm grm   40 Apr  1 22:32 my_add.h
-rw-rw-r-- 1 grm grm 1240 Apr  2 10:53 my_add.o
-rw-rw-r-- 1 grm grm   61 Apr  1 22:33 my_sub.c
-rw-rw-r-- 1 grm grm   39 Apr  1 22:33 my_sub.h
-rw-rw-r-- 1 grm grm 1240 Apr  2 10:53 my_sub.o

 At this time, we don’t need the ar command for packaging, but directly use gcc to package, just need to bring the option -shared

[grm@VM-8-12-centos owner]$ gcc -shared -o libmymath.so *.o
[grm@VM-8-12-centos owner]$ ll
total 32
-rwxrwxr-x 1 grm grm 7952 Apr  2 10:56 libmymath.so
-rw-rw-r-- 1 grm grm   61 Apr  1 22:32 my_add.c
-rw-rw-r-- 1 grm grm   40 Apr  1 22:32 my_add.h
-rw-rw-r-- 1 grm grm 1240 Apr  2 10:53 my_add.o
-rw-rw-r-- 1 grm grm   61 Apr  1 22:33 my_sub.c
-rw-rw-r-- 1 grm grm   39 Apr  1 22:33 my_sub.h
-rw-rw-r-- 1 grm grm 1240 Apr  2 10:53 my_sub.o

This also explains why cloud servers are dynamic libraries by default.

For the sake of standardization, we put the *.h files into the include directory, then put the dynamic library generated by packaging into the lib directory, and then package it:

 Copy the package to otherUsr and unzip it:

 We compile and link according to the way we implemented the static library before:

[grm@VM-8-12-centos otherUsr]$ gcc -o mytest main.c -I include -L lib -l mymath
[grm@VM-8-12-centos otherUsr]$ ll
total 28
drwxrwxr-x 2 grm grm 4096 Apr  2 10:59 include
drwxrwxr-x 2 grm grm 4096 Apr  2 11:02 lib
-rw-rw-r-- 1 grm grm  187 Apr  1 22:48 main.c
-rwxrwxr-x 1 grm grm 8432 Apr  2 11:14 mytest
-rw-rw-r-- 1 grm grm 2359 Apr  2 11:08 owner.tgz
[grm@VM-8-12-centos otherUsr]$ ./mytest
./mytest: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory

We found that the executable file was generated, but it was found that the file could not be found when running. Why is this? Didn't we already specify the name and path of the library? Why can't I find it?

We can think about it in reverse: Who did we tell the path and name of the library when we used the -L and -l options?

Is it the operating system? Obviously not, we just told the compiler, but did not tell the operating system, that is, the operating system cannot find where the library is. So why is the static library ok?

Recall the principle of the static library, the static library directly copies the binary code of the library imported by the user into the executable program, so the operating system can find it directly, but the dynamic library does not.

We can check it with the ldd command:

So how does the operating system find the dynamic library? There are mainly three ways:

  • 1 through the environment variable LD_LIBRARY_PATH

We can first check what is in the environment variable?

[grm@VM-8-12-centos otherUsr]$ echo $LD_LIBRARY_PATH
:/home/grm/.VimForCpp/vim/bundle/YCM.so/el7.x86_64

Then we import the library path into that environment variable:

[grm@VM-8-12-centos otherUsr]$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/grm/lesson14/otherUsr/lib
[grm@VM-8-12-centos otherUsr]$ echo $LD_LIBRARY_PATH
:/home/grm/.VimForCpp/vim/bundle/YCM.so/el7.x86_64:/home/grm/lesson14/otherUsr/lib

I don’t know if you have noticed that when we imported the environment variable, we did not specify the name of the library, but only went to the directory path where the library is stored. This is for the convenience of importing other libraries into this directory and using them correctly.

At this point we view through ldd:

 Let's run it and try:

 Obviously it can be done. But there is a big problem with this: that is, the configured environment variables will be automatically destroyed when we exit, so this method is only a temporary solution.

  • 2 Soft link scheme

We introduced soft links earlier, and here is a better solution through soft links:

[grm@VM-8-12-centos otherUsr]$ sudo ln -s /home/grm/lesson14/otherUsr/lib/libmymath.so  /lib64/libmymath.so

This way also allows the operating system to find the library:

 And in this way, when we don't delete the soft link, it is permanently saved . If you don't want it, just delete the soft link directly.

  • 3 Profile schemes

First, we use the unlink command to remove the soft link relationship, and then ldd checks:

At this time, there are no soft links, and then we use the configuration file scheme:

First look at the contents of the /etc/ld.so.conf.d directory:

 Then we escalate to create our own file, and write to the file the path where our library is located:

[grm@VM-8-12-centos otherUsr]$ sudo touch /etc/ld.so.conf.d/mystudy.conf
[grm@VM-8-12-centos otherUsr]$ sudo vim /etc/ld.so.conf.d/mystudy.conf 
[grm@VM-8-12-centos otherUsr]$ cat /etc/ld.so.conf.d/mystudy.conf 
/home/grm/lesson14/otherUsr/lib

When opening the file with vim, you must elevate the right, otherwise it may not be saved.

At this time, in order to make the configuration file take effect immediately, you need to use the ldconfig command:

[grm@VM-8-12-centos otherUsr]$ sudo ldconfig
[grm@VM-8-12-centos otherUsr]$ ldd mytest
	linux-vdso.so.1 =>  (0x00007ffed5dfb000)
	libmymath.so => /home/grm/lesson14/otherUsr/lib/libmymath.so (0x00007f853583b000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f853546d000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f8535a3d000)
[grm@VM-8-12-centos otherUsr]$ ./mytest
10 + 20 = 30
10 + 20 = -10

At this time, it will be able to run successfully.


5 Understanding of dynamic and static libraries

5.1 Understanding of static libraries

We know that the static library directly copies the binary code into the executable file, so when several of our processes use the same static library, we will inevitably copy multiple copies of the same binary code, so the size of the file will definitely increase , we consume more resources when downloading. (So ​​generally we don't use static libraries)

But it doesn't matter if we delete the static library after we generate the executable file, because we have copied the binary code of the static library into the executable file, and the executable file can still run normally.

5.2 Understanding of dynamic libraries

The dynamic library will not directly copy the binary code of the library to the executable file, but look for it when linking, then we only need to load a copy of the library code into the memory, map it through the page table, and then look for it when we execute it. Just go to the corresponding process address space to find it. Which area does the code of this library correspond to in the process address space? The answer is the Commons. The binary code of the library is stored in the shared area, but this will face a problem: different processes have different operating degrees, and the third-party libraries that need to be used are different, so the free space in the shared space of each process is doomed It is uncertain, how to find the libraries corresponding to different processes?

At this time, the method of using absolute addressing is no longer feasible, then we have to adopt the method of relative addressing, record the offset, and find the virtual address of the library through the offset. This means that when the loaded library is in the shared area, you can load it however you want. We search for it through the offset.

When making a dynamic library, the -fPIC option should be added to generate the target file, which means that it is position-independent code

(position ignore code) is for this reason.

Guess you like

Origin blog.csdn.net/m0_68872612/article/details/129903483