linux编程学习笔记(四) 编译工具和动态库
来源:互联网 发布:mysql驱动配置 编辑:程序博客网 时间:2024/04/29 10:37
原地址:http://blog.csdn.net/a8887396/article/details/8996297
1 gcc 通用选项
-o 输出的文件名-O -O1 -O2 -O3编译优化 -O默认情况下是最优化的
-g -g0 -g1 -g2 -g3 产生调试信息
-W两个选项all error
-Wall显示所有警告
-Werror 所有警告当错误
-w关闭警告
-E 预编译 直接会打印出来 所以一般和-o配合使用
gcc map.c -E -o map.i
-c只编译不连接
gcc map.c -c -o map.o
-S 汇编
gcc map.c -S -o map.s
编译过程 -E -c -S 自动调用连接器ld
-D 在命令行定义宏
- int printf(const char*,...);
- main()
- {
- printf("%d\n",NUM);
- }
- zhao@ubuntu:~/unix/two$ gcc gcc.c -DNUM=50
- zhao@ubuntu:~/unix/two$ ./a.out
- 50
还可以在代码中定义宏
-x 指定编译的语言类型
c
assembler
gcc -xassembler map.s
none 自动判定
gcc -xnone map.c
-std= 设置c语言标准
-std=c89
-std=c99
c99一些特性:
restrict 关键字 优化指针寻址
告诉编译器 所有修改该指针指向内存的操作都必须通过该指针,以便于编译器进行优化。
但判断有没有其他指针或其他方式修改该内存,是程序员的工作。
for(int i=0;i <10;i++) { } for中可以设置变量了
main 需要返回int,否则警告
补充 文件类型
.so动态库
.a静态库
.i 预编译文件
.o 二进制文件
.s 汇编文件
2 静态库的编译(.a)
不使用库的时候直接编译可执行程序gcc callku.c ku1.c ku2.c -omain
2.1编译成目标文件
-static 可选gcc -static -c 代码.c 生成.o文件
gcc -static -c ku1.c
gcc -static -c ku2.c
2.2归档成静态库
ar工具(创建归档文件)ar -r 静态库文件 被归档的文件
zhao@ubuntu:~/unix/two$ ar -r libku.a ku1.o ku2.o
ar: creating ku.a
ar -t 静态库文件 查看归档文件包含
zhao@ubuntu:~/unix/two$ ar -t libku.a
ku1.o
ku2.o
nm工具 (查看函数符号表)
nm 静态库或者动态库或者目标文件或者执行文件
zhao@ubuntu:~/unix/two$ nm libku.a 可以看到目标中包含的函数
ku1.o:
00000000 T add
ku2.o:
00000000 T sub
2.3使用静态库
gcc 代码 库归档gcc callku.c libku.a -omain
实际上是将静态库作为代码的一部分在编译
gcc callku.c -lku -L.
标准调用方式
如果其他组的人写了很多的文件,那么你使用他们的函数时要编译大量的代码
这时不如使用他们的库文件
2.4 使用静态库完成如下程序:
输入一个菱形的半径,打印一个菱形输入一个整数,封装成IOTool
菱形的打印封装成Graphics
计划:
1 实现输入
2 实现菱形
3 编译成静态库
4 调用静态库
IOTool.c
- #include <stdio.h>
- int inputInt(const char *info)
- {
- printf("%s:",info);
- int ret;
- scanf("%d",&ret);
- return ret;
- }
Graphics.c
- #include <stdio.h>
- void diamond(int r)
- {
- int x,y;
- for(y=0;y<=2*r;y++)
- {
- for(x=0;x<=2*r;x++)
- {
- if(y==x+r || y==x-r || y==-x+r || y==3*r-x)
- {
- printf("*");
- }
- else
- {
- printf(" ");
- }
- }
- printf("\n");
- }
- }
- main()
- {
- int r = inputInt("请输入菱形的半径");
- diamond( r);
- }
gcc -static -c Graphics.c
gcc -static -c IOTool.c
ar -r libdemo.a Graphics.o IOTool.o
gcc call_diaomond.c libdemo.a //这里要先写代码 后写库 交换会无法正确编译
zhao@ubuntu:~/unix/two$ ./a.out
请输入菱形的半径:3
*
* *
* *
* *
* *
* *
*
2.5总结
1什么是库?函数等代码封装的二进制已编译的归档文件
2 ar归档工具
3 采用库的方式管理代码优点:
容易组织代码
复用
保护代码版权
4 静态库的静态含义:
编译好的程序运行的时候不依赖库
库作为程序的一部分编译和连接
5 静态库本质:
就是目标文件的集合(归档)
6 -static 可选 (可以不写)
7 库命名规则:
lib库名.a.主版本号.副版本号.批号
lib库名.a
库的使用规则:
-l库名(不写lib) -L制定库所在路径
gcc call_diaomond.c -ldemo -L.
这样的调用方式需要你使用库的标准命名规则(lib库名.a)
3 动态库的编译
3.1 什么是动态库?
动态库是可以执行的,静态库不能执行(静态库只编译未连接)但动态库没有main,不能独立执行
动态库不会连接成程序的一部分
程序执行的时候,必须需要动态库文件。
3.2工具
ldd 查看程序需要调用的动态库文件ldd 只能查看可执行文件(ELF格式,file 查看文件格式
readelf -h 查看elf文件头格式
nm 查看库中的函数符号
3.3动态库的编译
3.1 编译-c -fpic(可选) position indenpendet code
gcc -c -fpic IOTool.c
gcc -c -fpic Graphics.c
3.2 连接
-shared
gcc -shared IOTool.o Graphics.o -o libdemo2.so
3.4 使用动态库
gcc 代码 动态库文件名gcc 代码 -l库名 -L动态库路径
gcc call_diaomond.c -ldemo2 -L.
问题:
1 执行程序怎么加载动态库?
找到动态库
加载动态库到内存
映射到用户的内存空间
系统对动态库查找规则:
/lib
/usr/lib
到环境变量LD_LIBRARY_PATH指定的路径查找
缓冲机制:
预先把/lib:/usr/lib:LD_LIBRARY_PATH中的动态库加载到缓存中
ldconfig -v 刷新缓存中的动态库
ldconfig -v | grep "libdemo2.so" 查看缓存中是否有需要的库
2 动态库没有作为程序的一部分,为何在连接时需要它?
连接器需要确定函数在动态库中的偏移位置
3 cannot open shared object file 解决方法:
zhao@ubuntu:~/unix/two$ gcc call_diaomond.c -ldemo2 -L.
zhao@ubuntu:~/unix/two$ ./a.out
./a.out: error while loading shared libraries: libdemo2.so: cannot open shared object file: No such file or directory
zhao@ubuntu:~/unix/two$ ldd a.out
linux-gate.so.1 => (0x00242000)
libdemo2.so => not found
libc.so.6 => /lib/libc.so.6 (0x00dc1000)
/lib/ld-linux.so.2 (0x0055a000)
编译时指定的路径是做为连接使用。
因为动态库使用时,只在上述3个位置中查找。(/lib /usr/lib LD_LIBRARY_PATH)
此时在将动态库拷贝到前两个路径之一去可解决。(需要管理员权限)
或者修改环境变量
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH (冒号隔开多个路径,只在当前terminal中有效)
zhao@ubuntu:~/unix/two$ gcc call_diaomond.c -ldemo2 -L.
-L 与 LD_LIBRARY_PATH的区别:
-L是在编译时将查找.so 或者 .a 连接生成需要的程序
LD_LIBRARY_PATH是环境变量, 程序运行时查找库
3.5 总结
动态库编译与使用方法:1编译
gcc -c -fpic IOTool.c
gcc -c -fpic Graphics.c
2连接
gcc -shared -olibdemo2.so IOTool.o Graphics.o
3 使用(注意动态库的路径)
gcc call_diaomond.c -ldemo2 -L.
3.6 综合应用
输入两个数 计算两个数的和要求:输入与计算两个数的和封装成动态库的调用
- //InputInt.c
- #include <stdio.h>
- void inputInt(int *a)
- {
- printf("请输入两个整数");
- scanf("%d%d",a,a+1);
- }
- // sum.c
- int sum(int a,int b)
- {
- return a+b;
- }
- // call_add.c
- #include <stdio.h>
- main()
- {
- int a[2];
- inputInt(a);
- printf("%d+%d=%d\n",a[0],a[1],sum(a[0],a[1]));
- }
gcc -fpic -c InputInt.c
gcc -fpic -c sum.c
gcc -shared -o libdemo3.so InputInt.o sum.o
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
gcc call_add.c -ldemo3 -L.
zhao@ubuntu:~/unix/two$ ./a.out
请输入两个整数
4 使用libdl.so库
调用动态库有两种方式:1 像前面一样 通过-l -L来由系统调用
2 手动调用动态库
动态库加载的原理
动态库中的函数的查找已经封装成库 libdl.so
dlopen 打开一个动态库
dlsym在打开动态库中找一个函数
dlclose 关闭动态库
dlerror 返回错误
#include <dlfcn.h>
Link with -ldl.
void *dlopen(const char *filename, int flag);
filename :动态库路径
flag :RTLD_LAZY 使用时加载 ,RTLD_NOW 立即加载
返回值 void* 返回动态库句柄
void *dlsym(void *handle, const char *symbol);
handle 已打开的动态库的句柄
symbol 函数名字
返回值: 返回函数指针
int dlclose(void *handle);
不是用库后 关闭动态库
char *dlerror(void);
- dldemo.c
- #include <dlfcn.h>
- main()
- {
- void *handle = dlopen("./libdemo2.so",RTLD_LAZY); //注意这里不能写静态库
- void (* func)(int) = dlsym(handle,"diamond");
- func(5);
- dlclose(handle);
- }
zhao@ubuntu:~/unix/two$ gcc dldemo.c -ldl
zhao@ubuntu:~/unix/two$ ./a.out
*
* *
* *
* *
* *
* *
* *
* *
* *
* *
*
总结:
1 编译连接动态库
2 使用动态库
3 怎么配置让程序调用动态库
4 掌握某些工具的使用: nm ldd lddconfig
objdump
strip 去掉多余信息
zhao@ubuntu:~/unix/two$ strip libdemo2.so
zhao@ubuntu:~/unix/two$ nm libdemo2.so
nm: libdemo2.so: no symbols
0 0
- linux编程学习笔记(四) 编译工具和动态库
- Linux环境编程编译工具与动态态库
- linux下编程学习--- 静态库和动态库的编译
- 自己在linux上编译、链接、动态库和静态库的学习笔记
- 自己在linux上编译、链接、动态库和静态库的学习笔记
- zynq学习笔记四:编译linux内核
- linux下编程动态库和静态库编译使用
- linux 系统编程学习笔记四
- 学习笔记之——静态编译和动态编译
- Linux编程学习之静态库和动态库
- linux动态库学习笔记
- Linux 命令和工具学习笔记
- Linux学习笔记四
- Linux学习笔记四
- Linux学习笔记四
- linux网络编程学习笔记之四 -----多线程并发服务端
- unix/linux编程实践教程------学习笔记(四)
- Linux shell编程学习笔记(四) 位置变量
- Google Guice 入门教程01 - 依赖注入(1)
- Class类的常用方法
- 基本函数库为Lua内置的函数库
- iOS 设置 setContentOffset 时序
- 在LDAP中CA、CRL的发布属性
- linux编程学习笔记(四) 编译工具和动态库
- 黑马程序员--高新技术(一)
- 手把手叫你玩转网络编程系列之三
- 解决configure: error: bzlib.h is required的问题
- RTPSession
- 有关采用Filter实现禁用缓存和使用缓存操作实现与分析
- Windows平台下如何使用Android NDK
- js 实现html滚动效果
- 挖掘视频网站【优酷】上被截断的视频的地址--001