linux创建静动态库

1.gcc编译选项

-E : 预处理 .c -> .i
-S : 编译 .i /.c -> .s
-c : 汇编 .s -> .o
-g : 生成调试信息
-O : 优化级别
-O0
-O1
-O2
-O3
-Os
-I : 包含一个头文件搜索路径 -I/home/linux/include
-L : 包含一个库文件搜索路径 -L/home/linux/lib
-l : 连接一个库 , 库以lib开头, 以.so .a 结尾 , windows下以.dll

  1. gnu 二进制工具集 之 readelf

readelf可以显示elf格式可执行文件的信息
readelf -h test 查看test可执行程序的头信息
ELF 头:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
类别: ELF64
数据: 2 补码,小端序 (little endian)
版本: 1 (current)
OS/ABI: UNIX - System V
ABI 版本: 0
类型: EXEC (可执行文件)
系统架构: Advanced Micro Devices X86-64
版本: 0x1
入口点地址: 0x4004b0
程序头起点: 64 (bytes into file)
Start of section headers: 4520 (bytes into file)
标志: 0x0
本头的大小: 64 (字节)
程序头大小: 56 (字节)
Number of program headers: 9
节头大小: 64 (字节)
节头数量: 30
字符串表索引节头: 27

readelf -s test : 可以显示 程序中的符号

59: 00000000004004b0 0 FUNC GLOBAL DEFAULT 13 _start 程序入口点

61: 000000000040059d 225 FUNC GLOBAL DEFAULT 13 main // c 程序开始执行的地方

readelf -S test : 可以显示程序的段信息
[13] .text PROGBITS 00000000004004b0 000004b0
0000000000000242 0000000000000000 AX 0 0 16
[15] .rodata PROGBITS 0000000000400700 00000700
000000000000001a 0000000000000000 A 0 0 4
[24] .data PROGBITS 0000000000601038 00001038
0000000000000010 0000000000000000 WA 0 0 8
[25] .bss NOBITS 0000000000601048 00001048
0000000000000008 0000000000000000 WA 0 0 1

  1. size 列出目标文件每一段的大小以及总体的大小

size test : 默认输出形式 bsd
text data bss dec hex filename
1527 568 8 2103 837 test
size test -A : 默认输出形式 system v
test :
section size addr
.interp 28 4194872
.note.ABI-tag 32 4194900
.note.gnu.build-id 36 4194932
.gnu.hash 28 4194968
.dynsym 120 4195000
.dynstr 90 4195120
.gnu.version 10 4195210
.gnu.version_r 48 4195224
.rela.dyn 24 4195272
.rela.plt 96 4195296
.init 26 4195392
.plt 80 4195424
.text 578 4195504
.fini 9 4196084
.rodata 26 4196096
.eh_frame_hdr 52 4196124
.eh_frame 244 4196176
.init_array 8 6295056
.fini_array 8 6295064
.jcr 8 6295072
.dynamic 464 6295080
.got 8 6295544
.got.plt 56 6295552
.data 16 6295608
.bss 8 6295624
.comment 86 0
Total 2189

  1. 组合命令 nm 列出程序中的符号
    nm test : 列出程序中的符号
    0000000004006f0 T __libc_csu_fini
    0000000000400680 T __libc_csu_init
    000000000040059d T main
    0000000000400510 t register_tm_clones
    00000000004004b0 T _start
    0000000000601048 D TMC_END

ls -l test : 查看程序的大小
strip test :对程序瘦身 , 缩减程序的尺寸
linux@ubuntu1404:~/test$ ls -l test
-rwxrwxr-x 1 linux linux 8620 10月 25 09:35 test
linux@ubuntu1404:~/test$ strip test
linux@ubuntu1404:~/test$ ls -l test
-rwxrwxr-x 1 linux linux 6296 10月 25 10:03 test
linux@ubuntu1404:~/test$ nm test
nm: test:无符号

  1. objdump 用来反向编译
    objdump -d test >test.dis

  2. objcopy 格式转换工具
    elf 转bin
    objcopy -O binary test test.bin

  3. addr2line 根据地址找到地址所在的函数(符号)
    nm test
    000000000040059d T main

    addr2line 0x000000000040059d -e test -f
    main
    ??:? // 出现这个问题, 是编译时没有加 -g 选项

    重新生成test
    gcc test.c -o test -g
    nm test
    000000000040059d T main
    addr2line 0x000000000040059d -e test -f
    main
    /home/linux/test/test.c:3

  4. 制作库文件
    库分为 : 静态库 libxxx.a
    动态库 libxxx.so

    制作静态库流程:
    要制作库的文件中不能有main函数
    gcc -c print.c -o print.o
    ar -cr libprint.a print.o // 生成库
    gcc test.c -o test -L. -lprint // 连接库
    ./test

    制作动态库的流程:
    gcc -o libprint.so print.c -fPIC -shared // 生成动态库

    gcc test.c -o test -L. -lprint // 生成可执行程序

    sudo cp libprint.so /lib/ 把生成的动态库复制到系统的库路径内, 程序运行时自动去系统路径下去找动态库

    ./test

    ./test: error while loading shared libraries: libprint.so: cannot open shared object file: No such file or directory
    解决方法: 把共享库 xxx.so 复制到/lib
    第一个源文件 my_print.c

#include <stdio.h>

void cout(const char * message)
{
    fprintf(stdout, "%s\n", message);
}

源文件2: my_math.c

int add(int a, int b)
{
    return a + b;
}

int subtract(int a, int b)
{
    return a - b;
}

使用gcc,为这两个源文件生成目标文件:

gcc -c my_print.c my_math.c
我们就得到了 my_print.o 和 my_math.o。

归档目标文件,得到静态库。
我们使用 ar 将目标文件归档:

ar crv libmylib.a my_print.o my_math.o
我们就得到了libmylib.a,这就是我们需要的静态库。

上述命令中 crv 是 ar的命令选项:

c 如果需要生成新的库文件,不要警告
r 代替库中现有的文件或者插入新的文件
v 输出详细信息
通过 ar t libmylib.a 可以查看 libmylib.a 中包含的目标文件。

可以通过 ar --help 查看更多帮助。

注意:我们要生成的库的文件名必须形如 libxxx.a ,这样我们在链接这个库时,就可以用 -lxxx。
反过来讲,当我们告诉编译器 -lxxx时,编译器就会在指定的目录中搜索 libxxx.a 或是 libxxx.so

生成对应的头文件
头文件定义了 libmylib.a 的接口,也就是告诉用户怎么使用 libmylib.a。

新建my_lib.h, 写入内容如下:

#ifndef __MY_LIB_H__
#define __MY_LIB_H__

int add(int a, int b);
int subtract(int a, int b);

void cout(const char *);
#endif

测试我们的静态库
在同样的目录下,建立 test.c:


int main(int argc, char *argv[])
{
    int c = add(15, -21);
    cout("I am a func from mylib ...");
    return 0;
}

这个源文件中引用了 libmylib.a 中的 cout 和 add 函数。

编译test.c:

gcc test.c -L. -lmylib
将会生成a.out,通过 ./a.out 可以运行该程序。说明我们的静态库能正常工作。

上面的命令中 -L. 告诉 gcc 搜索链接库时包含当前路径, -lmylib 告诉 gcc 生成可执行程序时要链接 libmylib.a。

通过makefile自动化
上面的步骤很繁琐,还是写个简单的makefile吧,内容如下:

.PHONY: build test

build: libmylib.a

libmylib.a: my_math.o my_print.o
ar crv $@ my_math.o my_print.o

my_math.o: my_math.c
gcc -c my_math.c

my_print.o: my_print.c
gcc -c my_print.c

test: a.out

a.out: test.c
gcc test.c -L. -lmylib
makefile写好后,运行 make build 将会构建 libmylib.a, 运行 make test 将会生成链接 libmylib.a 的程序。
***创建并使用动态库
  第一步:编辑源文件,test.h test.c main.c。其中main.c文件中包含main函数,作为程序入口;test.c中包含main函数中需要用到的函数。
  vi test.h test.c main.c
  第二步:将test.c编译成目标文件。
  gcc -c test.c
  前面两步与创建静态库一致。
  第三步:由。o文件创建动态库文件。
  gcc -shared -fPIC -o libtest.so test.o
  第四步:在程序中使用动态库。
  gcc -o main main.c -L. -ltest
  当静态库和动态库同名时,gcc命令将优先使用动态库。
  第五步:执行。
  LD_LIBRARY_PATH=. ./main
动态库除了在默认的的路径/lib 和 /usr/lib 下还可以通过"在配置文件/etc/ld.so.conf中指定动态库搜索路径",“环境变量的方式”和“在编译目标代码时指定该程序的动态库搜索路径(通过gcc 的参数"-Wl,-rpath,"指定)”三种,他们的优先级也不一样;

如果你在 windows 上使用 mingw,和Linux下生成静态库的方法是一样的。
领卓教育

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值