Linux动静态库

本文详细介绍了如何在Windows和Linux系统中查看动静态库,包括.dll/.lib、.so/.a的区别,以及如何通过ldd工具检查动态库依赖。还涵盖了静态库和动态库的制作过程,从源文件链接到生成静态lib.a和动态lib.so,并演示了静态与动态库的使用方法,涉及Makefile的编写和库路径设置技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 动静态库的查看

  • Windows中的动态库文件以.dll为后缀名、静态库以.lib为后缀;而Linux动态库文件后缀为.so 、静态库为.a

    库的真名:去掉lib前缀,去掉.a \ .so 后缀,剩下的就是库名。例如libc-2.17.so,库的真名就是c-2.17

  • ldd查看可执行程序包含的动态库。动态库系统中默认包含,因为许多shell程序都依赖动态库运行。程序在链接时默认使用动态库。

[test@VM-12-4-centos first]$ ldd main
        linux-vdso.so.1 =>  (0x00007ffebedab000)
        /$LIB/libonion.so => /lib64/libonion.so (0x00007f1bbd2e5000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f1bbcdfe000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f1bbcbfa000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f1bbd1cc000)      
[test@VM-12-4-centos first]$ file main
main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=d8c679773c4e5c5c3972a1a5ad579065387333ad, not stripped
  • 若将源文件以静态(-static)的方式链接,则会产生一个静态的可执行文件;使用静态链接需要安装相依赖的静态库
[test@VM-12-4-centos first]$ gcc main.c -o main_static -static
[test@VM-12-4-centos first]$ file main_static 
main_static: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=6de48a06365f646b6f73ebb0b9fb5d1863a5f0b9, not stripped

2. 动静态库的制作和使用

2.1 源文件直接使用,不生成库

[test@VM-12-4-centos first]$ ls && ls mylib/
main.c  Makefile  mylib
PrintHello.c  PrintHello.h  PrintWorld.c  PrintWorld.h
//PrintHello.h
#include <stdio.h>
extern void PrintHello();

//PrintHello.c
#include "PrintHello.h"
void PrintHello(){
    printf("hello\n");
}

//PrintWorld.h
#include <stdio.h>
extern void PrintWorld();

//PrintWorld.c
#include "PrintWorld.h"
void PrintWorld(){
    printf("world\n");
}

//main.c
#include "./mylib/PrintHello.h"
#include "./mylib/PrintWorld.h"
int main()
{
    PrintHello();
    PrintWorld();
    return 0;
}
# src = main.c ./mylib/PrintHello.c  ...
src = ./mylib/%.c             	
obj = main.o PrintHello.o PrintWorld.o  # 不加路径,当前目录下生成

# mytest:%.o                 # %通配符,将所有.o结尾的文件展开
main:$(obj)           	
	gcc -o $@ $^
%.o:%.c						# %c 依赖所有 .c (当前目录)
	gcc -c $<
%.o:$(src)          		
	gcc -c $<			   # < :将.c内容展开依次编译,没有-o指明,则生成同名的.o文件
	
.PHONY:clean
clean:
	rm -rf *.o main

运行结果

[test@VM-12-4-centos first]$ make
gcc -c main.c
gcc -c mylib/PrintHello.c                          
gcc -c mylib/PrintWorld.c                          
gcc -o main main.o PrintHello.o PrintWorld.o
[test@VM-12-4-centos first]$ ls
main  main.c  main.o  Makefile  mylib  PrintHello.o  PrintWorld.o
[test@VM-12-4-centos first]$ ./main
hello
world

2.2 生成静态库

2.2.1 静态库的生成

将所有源文件生成.o然后打包即可得到静态库。Makefile如下:

liba.a:PrintHello.o PrintWorld.o
	ar -rc $@ $^          # ar 归档命令(打包) r(replace) c(create)

%.o:%.c
	gcc -c $<
	
.PHONY:clean
clean:
	rm -rf *.o *.a

.PHONY:output
output:
	mkdir output
	cp -rf *.h output
	cp liba.a output

操作和结果

[test@VM-12-4-centos mylib]$ ls
Makefile PrintHello.c  PrintHello.h  PrintWorld.c  PrintWorld.h
[test@VM-12-4-centos mylib]$ make
gcc -c PrintHello.c
gcc -c PrintWorld.c
ar -rc liba.a PrintHello.o PrintWorld.o          # ar 归档命令(打包) r(replace) c(create)
[test@VM-12-4-centos mylib]$ ls
liba.a  Makefile  PrintHello.c  PrintHello.h  PrintHello.o  PrintWorld.c  PrintWorld.h  PrintWorld.o

[test@VM-12-4-centos mylib]$ make output # 发布
mkdir output
cp -rf *.h output
cp liba.a output
[test@VM-12-4-centos mylib]$ make clean
rm -rf *.o *.a
[test@VM-12-4-centos mylib]$ ls
Makefile  output  PrintHello.c  PrintHello.h  PrintWorld.c  PrintWorld.h
[test@VM-12-4-centos mylib]$ cd output/
[test@VM-12-4-centos output]$ ls
liba.a  PrintHello.h  PrintWorld.h

[test@VM-12-4-centos output]$ ar -tv liba.a  # 查看库依赖的.o
rw-rw-r-- 1001/1001   1496 Jun  3 23:43 2022 PrintHello.o
rw-rw-r-- 1001/1001   1496 Jun  3 23:43 2022 PrintWorld.o

2.2.2 静态库的使用

#include "./output/PrintHello.h"
#include "./output/PrintWorld.h"

int main()
{
    PrintHello();
    PrintWorld();
    return 0;
}
main:main.c
	gcc -o $@ $^ -I./output -L./output -l a  # -I 头文件路径; -L 库文件路径; -l 库名称

.PHONY:clean
clean:
	rm -rf *.o main
	 
# path = $(shell pwd)  # 使用绝对路径的写法
# main:main.c
# 	gcc -o $@ $^ -I$(path)/output -L$(path)/output -la  
# .PHONY:clean
# clean:
# 	rm -rf *.o main

gcc默认可以在当前目录下查找头文件和库,若包含子目录需指定:

-I指定头文件查找路径,选项和名字之间可以不带空格

-L指定自定义库搜索路径

-l指定链接库的名字(libc.so -> 名字变为c :去掉开头的lib.后的内容)

运行结果

[test@VM-12-4-centos first]$ ls
main.c  Makefile  mylib  output
[test@VM-12-4-centos first]$ make
gcc -o main main.c -I./output -L./output -l a 
[test@VM-12-4-centos first]$ ls
main  main.c  Makefile  mylib  output
[test@VM-12-4-centos first]$ ./main 
hello
world

2.3 生成动态库

2.3.1 动态库的生成

liba.so:PrintHello.o PrintWorld.o
	gcc -shared -o $@ $^    

%.o:%.c
	gcc -fPIC -c $<  # 添加-fPIC选项。
	
.PHONY:clean
clean:
	rm -rf *.o *.so output

.PHONY:output
output:
	mkdir output
	cp -rf *.h output
	cp liba.so output

操作和结果

[test@VM-12-4-centos mylib]$ ls
Makefile  PrintHello.c  PrintHello.h  PrintWorld.c  PrintWorld.h
[test@VM-12-4-centos mylib]$ make
gcc -fPIC -c PrintHello.c  
gcc -fPIC -c PrintWorld.c  
gcc -shared -o liba.so PrintHello.o PrintWorld.o    
[test@VM-12-4-centos mylib]$ make output
mkdir output
cp -rf *.h output
cp liba.so output
[test@VM-12-4-centos mylib]$ ls
liba.so  Makefile  output  PrintHello.c  PrintHello.h  PrintHello.o  PrintWorld.c  PrintWorld.h  PrintWorld.o
[test@VM-12-4-centos mylib]$ cd output/
[test@VM-12-4-centos output]$ ls
liba.so  PrintHello.h  PrintWorld.h
[test@VM-12-4-centos mylib]$ cp output -r ..

2.3.2 动态库的使用

代码和makefile与2.2.2 中一样,注意要将动态库加载到内存才可以让使用动态库的程序正常运行。直接操作:

[test@VM-12-4-centos first]$ make
gcc -o main main.c -I./output -L./output -l a
[test@VM-12-4-centos first]$ ls
main  main.c  Makefile  mylib  output
[test@VM-12-4-centos first]$ ./main
./main: error while loading shared libraries: liba.so: cannot open shared object file: No such file or directory # 运行时需要让系统知道动态库的位置,将自己的库加载到内存
  • 动态库在使用运行时需要告知系统动态库的路径:

    • 修改LD_LIBRARY_PATH环境变量中关于动态库的路径
    [test@VM-12-4-centos first]$ echo $LD_LIBRARY_PATH
    [test@VM-12-4-centos first]$ ls
    main  main.c  Makefile  mylib  output
    [test@VM-12-4-centos first]$ cd output/
    [test@VM-12-4-centos output]$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD 
    # 只在本bash进程可用。可以添加到bashrc
    [test@VM-12-4-centos output]$ echo $LD_LIBRARY_PATH
    :/home/test/process/Fork/first/output
    [test@VM-12-4-centos output]$ cd ..
    [test@VM-12-4-centos first]$ ls
    main  main.c  Makefile  mylib  output
    
    [test@VM-12-4-centos first]$ ldd main
            linux-vdso.so.1 =>  (0x00007ffdca650000)
            /$LIB/libonion.so => /lib64/libonion.so (0x00007f1f5c9ac000)
            liba.so => /home/test/process/Fork/first/output/liba.so (0x00007f1f5c691000) #此时链接到了自己的库
            libc.so.6 => /lib64/libc.so.6 (0x00007f1f5c2c3000)
            libdl.so.2 => /lib64/libdl.so.2 (0x00007f1f5c0bf000)
            /lib64/ld-linux-x86-64.so.2 (0x00007f1f5c893000)
    [test@VM-12-4-centos first]$ ./main 
    hello
    world
    
    • 也可在/etc/ld.so.conf.d/添加配置文件,这里命名成mylib.conf,文件内容即为库的路径。需要root。
    [root@VM-12-4-centos output]# echo /home/test/process/Fork/first/output > /etc/ld.so.conf.d/mylib.conf
    [root@VM-12-4-centos output]# ls /etc/ld.so.conf.d/mylib.conf -l
    -rw-r--r-- 1 root root 64 Jun  4 01:36 /etc/ld.so.conf.d/mylib.conf
    [root@VM-12-4-centos output]# cat /etc/ld.so.conf.d/mylib.conf 
    /home/test/process/Fork/first/output
    [root@VM-12-4-centos output]# ls
    liba.so  PrintHello.h  PrintWorld.h
    [root@VM-12-4-centos output]# ldconfig  # 在该库目录下执行,用来更新缓存
    
    [test@VM-12-4-centos first]$ ./main 
    hello
    world
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值