【Linux】一篇文章搞定 静态库&动态库&静态链接&动态链接

1、查看可执行文件链接库

  • 查看一个可执行文件链接了哪些库

命令1:

ldd [可执行文件名]

例子:

[gongruiyang@localhost ClassLinunx]$ ldd test_func 
    linux-vdso.so.1 =>  (0x00007ffcefdea000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f3413200000)      <---这是动态链接 标准C库
    /lib64/ld-linux-x86-64.so.2 (0x00005644d3b99000)

命令2:

file [可执行文件名]

例子:

[gongruiyang@localhost ClassLinunx]$ file env
env: ELF 64-bit LSB executable, 
x86-64, 
version 1 (SYSV),
dynamically linked (uses shared libs),          <---动态链接
for GNU/Linux 2.6.32, BuildID[sha1]=733aa60281b8ad9560a07b28c43f1f2119e100b8, not stripped

2、动态链接与静态链接

链接库文件的时候有两种链接方式:静态链接、动态链接

  • 静态链接:在最终生成的可执行程序中写入了静态库文件中的所有函数指令,简单来说:程序编译链接的时候把静态库中的代码链接到可执行文件中,程序运行时不再需要静态库,多个程序同时使用时需要加载多份到内存
  • 动态链接:在最终生成的可执行程序中写入了动态库文件的函数符号表,简单来说:程序运行时才去链接动态库代码,多个程序可以共享使用,使用时只需要加载一份到内存

动态链接命令

gcc env.c -o env_dyana                          <----系统默认动态链接
gcc env.c -o env_dyana -shared -fPIC            <----显式指定动态链接

静态链接命令:gcc [源文件] -o [目标文件] -static

gcc env.c -o env_static -static                 <----显式指定静态链接

静态链接与动态链接对比

image.png

由图可知:显然同一个源文件动态链接产生的文件与静态链接产生的文件相比所占内存更小一些

结论:动态链接耗费内存更小哦!

3、静态库

静态库的基本操作指令

  • 静态库名:libXXX.a 例如:libfun.a中fun是静态库的名字
  • windows操作系统下静态库的后缀为.lib
  • 生成静态库
ar -rc lib[名字].a [依赖文件]

依赖文件是后缀名为[ .o ]的文件

  • 使用静态库
gcc main.c -o main -L [path(文件所在目录)]
gcc main.c -o main -l [库名字(去掉前后缀)]
  • 静态库的默认搜索路径

LD_LIBRARY_PATH这个环境变量中存储着库文件默认搜索路径

[gongruiyang@localhost TestLib]$ set | grep LD_LIBRARY_PATH
LD_LIBRARY_PATH=:/home/gongruiyang/.VimForCpp/vim/bundle/YCM.so/el7.x86_64

生成使用静态库示例

三个文件:main.c test.h test.c

  • main.c
#include <stdio.h>
#include "test.h"

int main()
{
    
    
  printf("Call function P().\n");
  P();

  return 0;                      
}
  • test.h
void P();
  • test.c
#include <stdio.h>          

void P()
{
    
    
  printf("Hello World!\n");
}
  1. 生成依赖文件
[gongruiyang@localhost TestLib]$ ls
main.c  test.c  test.h
[gongruiyang@localhost TestLib]$ gcc -c test.c -o test.o
  1. 生成静态库
[gongruiyang@localhost TestLib]$ ar -rc libfunc.a test.o
[gongruiyang@localhost TestLib]$ ls
libfunc.a  main.c  test.c  test.h  test.o
  1. 使用静态库编译文件

这里使用动态链接来链接静态库

[gongruiyang@localhost TestLib]$ gcc main.c -o test_func -L . -l func 
[gongruiyang@localhost TestLib]$ ls
libfunc.a  main.c  test.c  test_func  test.h  test.o
[gongruiyang@localhost TestLib]$ ./test_func 
Call function P().
Hello World!

这里使用静态链接来链接静态库

[gongruiyang@localhost TestLib]$ gcc main.c -o test_func -L . -l func -static
[gongruiyang@localhost TestLib]$ ls
libfunc.a  main.c  test.c  test_func  test.h  test.o
[gongruiyang@localhost TestLib]$ ./test_func 
Call function P().
Hello World!

看到这里你应该明白:

静态库既可以动态链接也可以静态链接

同理,动态库也是如此

结论:链接的两种方式与库的种类无关

4、动态库

动态库的基本操作指令

  • 动态库名:libXXX.solib.XXX.sa 例如:libc.so中c是动态库的名字
  • windows操作系统下动态库的后缀为.dll
  • 生成动态库
gcc -shared -fPIC XXX.c -o libXXX.so
  • 使用动态库
gcc main.c -o main -L [path(文件所在目录)]
gcc main.c -o main -l [库名字(去掉前后缀)]
  • 动态库默认搜索路径

LD_LIBRARY_PATH这个环境变量中存储着库文件默认搜索路径

[gongruiyang@localhost TestLib]$ set | grep LD_LIBRARY_PATH
LD_LIBRARY_PATH=:/home/gongruiyang/.VimForCpp/vim/bundle/YCM.so/el7.x86_64

生成使用动态库示例

三个文件:main.c test.h test.c

  • main.c
#include <stdio.h>
#include "test.h"

int main()
{
    
    
  printf("Call function P().\n");
  P();

  return 0;                      
}
  • test.h
void P();
  • test.c
#include <stdio.h>          

void P()
{
    
    
  printf("Hello World!\n");
}
  1. 生成动态库

使用函数实现文件test.c来作为依赖文件生成func动态库文件

[gongruiyang@localhost TestLib]$ gcc -shared -fPIC test.c -o libfunc.so
[gongruiyang@localhost TestLib]$ ls
libfunc.so  main.c  test.c  test.h
  1. 使用动态库编译文件

main.c文件调用了动态库func文件中得到函数

编译可执行程序时,要告诉编译器,我们链接的动态库是哪一个

如果我们不指定动态库会出现下面错误

[gongruiyang@localhost TestLib]$ gcc main.c -o test_func 
/tmp/ccsSChdZ.o:在函数‘main’中:
main.c:(.text+0x14):对‘P’未定义的引用
collect2: 错误:ld 返回 1

指定链接库会正常编译

[gongruiyang@localhost TestLib]$ gcc main.c -o test_func -L . -l func
[gongruiyang@localhost TestLib]$ ./test_func 
Call function P().
Hello World!

这里的[ -L . ]是指当前目录哦![ -l func ]是指动态库的名字时func(去掉前后缀的)

小提示:可以将自己的动态链接文件的目录放进环境变量LD_LIBRARY_PATH中,这样一来,编译该main.c文件就不需要加上路径咯!

猜你喜欢

转载自blog.csdn.net/weixin_45437022/article/details/109862351