gcc编译生成静态及动态链接库步骤

这两天在看《Linux C程序设计大全》,吴岳编著,清华大学出版社。这本书是在一个培训机构看到的,在网上查了下该书的相关信息。从目录而言,该书涵盖了Linux下C程序设计的较多内容,包括C语言基础(主要讲解C语法结构)、C语言开发环境(主要介绍VIM使用、GCC使用、makefile编写、gdb使用)、Linux进程操作、Linux文件操作、Linux网络编程这几部分。阅读了该书几个小章节,总体而言,书的部分内容较充实,但是存在较多编辑错误,部分样例实际运行时与书中内容不符。

这里使用该书P192-P199的例子,总结下gcc编译静态及动态链接库的方法及步骤。

程序清单如下:

test.c文件内容:
int add(int a, int b)
{
return a + b;
}

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

int mul(int a, int b)
{
return a * b;
}

int div(int a, int b)
{
return a / b;
}

test.h文件内容:
#ifndef _TEST_H_

#define _TEST_H_

extern int add(int a, int b);
extern int sub(int a, int b);
extern int mul(int a, int b);
extern int div(int a, int b);

#endif

main.c文件内容:
#include <stdio.h>
#include "test.h"

int main ()
{
int a, b;
printf("please input a and b\n");
scanf("%d%d", &a, &b);

printf("The add : %d\n", add(a, b));
printf("The sub : %d\n", sub(a, b));
printf("The mul : %d\n", mul(a, b));
printf("The div : %d\n", div(a, b));

return 0;
}

1. 首先总结使用gcc生成静态库及使用静态库的方法:
在此例中,test.c用于编译生成静态库libtest.a,test.h为libtest.a对应的头文件。

step 1: 生成test.o目标文件,使用如下命令:
[xgqin@xgqin-desktop so]$ ls
main.c test.c test.h
[xgqin@xgqin-desktop so]$ gcc -c test.c -o test.o
[xgqin@xgqin-desktop so]$ ls
main.c test.c test.h test.o
在第一步中使用gcc -c test.c -o test.o首先生成test.o目标文件。

step 2: 使用ar将test.o打包成libtest.a静态库,使用如下命令:
[xgqin@xgqin-desktop so]$ ar rcs -o libtest.a test.o
[xgqin@xgqin-desktop so]$ ls
libtest.a main.c test.c test.h test.o
step 3:生成libtest.a静态库后,可以使用ar t参数查看libtest.a文件中包含哪些文件:
[xgqin@xgqin-desktop so]$ ar t libtest.a
test.o
[xgqin@xgqin-desktop so]$
step 4: 编译main.c,并使用libtest.a静态库,链接时-l参数后不加空格指定所需链接的库,这里库名是libtest.a,但是只需要给出-ltest即可,ld会以libtest作为库的实际名字(例如-lm参数,实际表示链接libm库,也就是数学库):
[xgqin@xgqin-desktop so]$ gcc -o app_static main.c -L. -ltest
[xgqin@xgqin-desktop so]$ ls
app_static libtest.a main.c test.c test.h test.o

或使用如下方式编译main.c,并使用libtest.a静态库:
[xgqin@xgqin-desktop so]$ gcc -o app_static main.c libtest.a
[xgqin@xgqin-desktop so]$ ls
app_static libtest.a main.c test.c test.h test.o
step 5: 运行app_static:
[xgqin@xgqin-desktop so]$ ./app_static
please input a and b
4 2
The add : 6
The sub : 2
The mul : 8
The div : 2
[xgqin@xgqin-desktop so]$
step 6: 使用readelf 查看app_static的符号表,观察sub, add, mul, div等函数是否处于app_static的.text段中。注意,section headers中指出 .text代码段的编号是13,而再symbol table ‘.symtab’中则显示add, div, mul, sub均处于13段中,也就是.text代码段中。因此libtest.a静态库经过链接后对应的函数代码已加入app_static程序代码段中,此为静态链接。

[xgqin@xgqin-desktop so]$ readelf -a app_static
....
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
....
[13] .text PROGBITS 0000000000400520 00000520
0000000000000274 0000000000000000 AX 0 0 16
[14] .fini PROGBITS 0000000000400794 00000794
0000000000000009 0000000000000000 AX 0 0 4
[15] .rodata PROGBITS 00000000004007a0 000007a0
0000000000000062 0000000000000000 A 0 0 8
....
[29] .strtab STRTAB 0000000000000000 00001fb8
000000000000027b 0000000000000000 0 0 1
Symbol table '.symtab' contains 72 entries:
Num: Value Size Type Bind Vis Ndx Name
....
49: 00000000004006c4 20 FUNC GLOBAL DEFAULT 13 add
....
53: 0000000000400701 19 FUNC GLOBAL DEFAULT 13 div
....
64: 0000000000400610 179 FUNC GLOBAL DEFAULT 13 main
65: 00000000004006ee 19 FUNC GLOBAL DEFAULT 13 mul
....
70: 00000000004006d8 22 FUNC GLOBAL DEFAULT 13 sub
....
注:《Linux C程序设计大全》中给出的三种链接静态库的方法在实际使用时均出现报错,如下所示:
[xgqin@xgqin-desktop so]$ gcc main.c -llibtest.a -o app
/usr/bin/ld: cannot find -llibtest.a
collect2: error: ld returned 1 exit status
[xgqin@xgqin-desktop so]$ gcc main.c -ltest.a -o app
/usr/bin/ld: cannot find -ltest.a
collect2: error: ld returned 1 exit status
[xgqin@xgqin-desktop so]$ gcc main.c -ltest -o app
/usr/bin/ld: cannot find -ltest
collect2: error: ld returned 1 exit status
[xgqin@xgqin-desktop so]$ gcc -L. main.c -o app
/tmp/ccEpq6Fp.o: In function `main':
main.c:(.text+0x37): undefined reference to `add'
main.c:(.text+0x57): undefined reference to `sub'
main.c:(.text+0x77): undefined reference to `mul'
collect2: error: ld returned 1 exit status
[xgqin@xgqin-desktop so]$ gcc main.c -static ./libtest.a -o app
/usr/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
[xgqin@xgqin-desktop so]$

具体出错原因,个人推测应与ld相关。

2. 再总结使用gcc生成动态库及使用动态库的方法:

step 1: 生成test.o目标文件,使用如下命令。此处需要添加-fPIC参数,该参数用于生成位置无关代码已共生成动态库使用:
[xgqin@xgqin-desktop so]$ gcc -c -o test.o -fPIC test.c
[xgqin@xgqin-desktop so]$ ls
app_static libtest.a main.c test.c test.h test.o
[xgqin@xgqin-desktop so]$ file test.o
test.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

step 2: 使用-shared参数生成动态库,使用如下命令:
[xgqin@xgqin-desktop so]$ gcc -shared -o libmyshare.so test.o
[xgqin@xgqin-desktop so]$ ls
app_static libmyshare.so libtest.a main.c test.c test.h test.o
[xgqin@xgqin-desktop so]$ file libmyshare.so
libmyshare.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=0x4053caa2d2d48b9b026576a69929a4a44abedcb0, not stripped

上述两个命令可以合在一块,如下所示:
[xgqin@xgqin-desktop so]$ gcc -shared -fPIC -o libmyshare.so test.c
[xgqin@xgqin-desktop so]$ file libmyshare.so
libmyshare.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=0x4053caa2d2d48b9b026576a69929a4a44abedcb0, not stripped

step 3: 编译main.c,使用libmyshare.so动态库:
[xgqin@xgqin-desktop so]$ gcc -o app_share main.c -L. -lmyshare
[xgqin@xgqin-desktop so]$ ls
app_share app_static libmyshare.so libtest.a main.c test.c test.h test.o
[xgqin@xgqin-desktop so]$ ldd app_share
linux-vdso.so.1 => (0x00007fff3972c000)
libmyshare.so => not found
libc.so.6 => /lib64/libc.so.6 (0x0000003039600000)
/lib64/ld-linux-x86-64.so.2 (0x0000003039200000)
使用ldd命令查看app_share使用的动态库,发现提示libmyshare无法找到,如果直接执行app_share,则出现如下错误:
[xgqin@xgqin-desktop so]$ ./app_share
./app_share: error while loading shared libraries: libmyshare.so: cannot open shared object file: No such file or directory
查看相关资料后,提示与LD_LIBRARY_PATH相关,首先使用export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH将当前目录加入LD_LIBRARY_PATH变量中。
再次运行ldd app_share,如下:
[xgqin@xgqin-desktop so]$ gcc -o app_share main.c -L. -lmyshare
[xgqin@xgqin-desktop so]$ ldd app_share
linux-vdso.so.1 => (0x00007fff26b70000)
libmyshare.so => not found
libc.so.6 => /lib64/libc.so.6 (0x0000003039600000)
/lib64/ld-linux-x86-64.so.2 (0x0000003039200000)
[xgqin@xgqin-desktop so]$ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
[xgqin@xgqin-desktop so]$ echo $LD_LIBRARY_PATH
.:
[xgqin@xgqin-desktop so]$ ldd app_share
linux-vdso.so.1 => (0x00007fff55dbe000)
libmyshare.so => ./libmyshare.so (0x00007fb8c3b18000)
libc.so.6 => /lib64/libc.so.6 (0x0000003039600000)
/lib64/ld-linux-x86-64.so.2 (0x0000003039200000)
[xgqin@xgqin-desktop so]$ ./app_share
please input a and b
4 2
The add : 6
The sub : 2
The mul : 8
The div : 2
注:注意观察export前后的两次ldd执行时,libmyshare.so的指向情况。

另一种编译main.c,并链接libmyshare.so的方式如下(该方式通过./libmyshare.so直接指定使用当前目录下的libmyshare.so文件:
[xgqin@xgqin-desktop so]$ gcc -o app_share main.c ./libmyshare.so
[xgqin@xgqin-desktop so]$ ldd app_share
linux-vdso.so.1 => (0x00007fff066c3000)
./libmyshare.so (0x00007f945b6b0000)
libc.so.6 => /lib64/libc.so.6 (0x0000003039600000)
/lib64/ld-linux-x86-64.so.2 (0x0000003039200000)
[xgqin@xgqin-desktop so]$ ./app_share
please input a and b
4 2
The add : 6
The sub : 2
The mul : 8
The div : 2
[xgqin@xgqin-desktop so]$
本文中使用到的readelf属于binutils工具集,感兴趣的读者可以访问google或者百度。

gcc编译生成静态及动态链接库步骤的更多相关文章

  1. GCC与静态库、动态库

    GCC 常用指令 1 man gcc gcc工作流程例如: gcc hello.c 1234567891011121314 //***第一步***gcc -E hello.c >hello.i ...

  2. gcc创建静态库和共享库

    静态库和动态(共享)库静态库:编译程序在编译使用库提供的功能代码的程序时将代码复制到该程序然后编译成可执行程序,这种库成为静态库共享库:共享库比静态库的处理方式更加灵活,因而其产生的可执行文件更小,其 ...

  3. RedHat 5下安装gcc编译环境的具体步骤

    RedHat 5下安装gcc编译环境的具体步骤 在RHEL5系统中默认不安装linux系统中的开发编译环境(gcc),此软件包安装时依赖其他包较多 在以前使用RHEL4时可以通过如下命令安装: rpm ...

  4. GCC编译过程与动态链接库和静态链接库

    1. 库的介绍 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 本质上来说库是一种可执行代码的二进制形式,可 ...

  5. gcc/g++实战之动态链接库与静态链接库编写

    函数库一般分为静态库和动态库两种. 静态库: 是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了.其后缀名一般为”.a”. 动态库: 与之相反, ...

  6. Linux下gcc编译生成动态链接库*.so文件并调用它【转载】

    动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一 ...

  7. Linux下gcc编译生成动态链接库*.so文件并调用它 是转载的

    动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一 ...

  8. Linux下gcc编译生成动态链接库*.so文件并调用它

    动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一 ...

  9. Linux下gcc编译生成动态链接库*.so文件并调用它(注:执行Test程序后无需用export 命令指定.so库文件路径:方法在文中下方;)

    动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一 ...

随机推荐

  1. ASP.NET各种技巧

    1.动态添加文件框 前台页面关键部分: <script type="text/javascript"> //添加一个选项 function AddFileCtrol() ...

  2. java调用摄像头了

    http://www.cnblogs.com/cnweiblog/p/4602207.html

  3. python之enumerate

    http://eagletff.blog.163.com/blog/static/116350928201266111125832/一般情况下,如果要对一个列表或者数组既要遍历索引又要遍历元素时,可以 ...

  4. list变set去重,set交集

    set 取交集 并集 删除没有的元素  不会报错 remove 会报错 https://www.cnblogs.com/alex3714/articles/5717620.html

  5. 配置管理-SpringCloudConfig

    1.搭建配置管理服务 添加依赖 <dependencies> <dependency> <groupId>org.springframework.cloud< ...

  6. windows 解决缺失.dll的问题

    1.缺失MSVCR120.dell和MSVCP120.dll,如图: 这种问题是因为没有Microsoft Visual C++ 2013运行库的问题,自行百度在Microsoft官网下载即可,注意需 ...

  7. 【PHP】什么时候使用Try Catch(转)

    几条建议: 如果无法处理某个异常,那就不要捕获它.  如果捕获了一个异常,请不要胡乱处理它.  尽量在靠近异常被抛出的地方捕获异常.  在捕获异常的地方将它记录到日志中,除非您打算将它重新抛出.  按 ...

  8. Python知识点入门笔记——特色数据类型(集合)

    集合是一种不重复的无序集 集合用花括号来定义{} 集合和字典一样,里面的顺序是无序的,{1,2,3}和{3,2,1}是相等的 集合的元素不可重复,也就是说{1,2,2,3}是不存在的,应该写为{1,2 ...

  9. Volatile小结

    1)Java 中能创建 Volatile 数组吗? 能,Java 中可以创建 volatile 类型数组,不过只是一个指向数组的引用,而不是整个数组.我的意思是,如果改变引用指向的数组,将会受到 vo ...

  10. Python学习笔记(五)之Python操作Redis、mysql、mongodb数据库

    操作数据库 一.数据库 数据库类型主要有关系型数据库和菲关系型数据库. 数据库:用来存储和管理数的仓库,数据库是通过依据“数据结构”将数据格式化,以记录->表->库的关系存储.因此数据查询 ...