赞
踩
目录
gcc可以让程序员通过它能够更好地控制整个编译过程。
1.预处理阶段(预处理器cpp)
生成i的文件
2.编译阶段(编译器egcs)
将预处理后的文件转换成汇编语言, 生成文件.s
3.汇编阶段(汇编器as)
有汇编变为目标代码(机器代码)生成 .o 的文件
4.链接阶段(链接器ld)
连接目标代码, 生成可执行程序.exe
如图所示:
gcc的常用项如图:
选项名 | 作用 |
-c | 通知gcc取消连接步骤,即编译源码并在最后生成目标文件 |
-Dmacro | 定义指定的宏,使它能够通过源码中的#ifdef进行检验 |
-E | 不经过编译预处理程序的输出而输送至标准输出 |
0 | 获得有关调试程序的详细信息,它不能与-o选项联合使用 |
-I | 在包含文件搜索路径的起点处添加指定目录 |
-l | 提示连接程序在创建最终可执行文件时包含指定的库 |
-shared | 生成共享目标文件。通常用在建立共享库时。 |
-static | 禁止使用共享连接。 |
-O、-O2、-O3 | 将优化状态打开,该选项不能与-g选项联合使用 -O0: 不进行优化处理 -O1或者-O: 优化生成代码。 -O2: 进一步优化 -O3:比 -O2 更进一步优化,包括 inline 函数 |
-S | 要求编译程序生成来自源代码的汇编程序输出 |
-v | 启动所有警报 |
-h | 预处理文件(标头文件) |
-Wall | 在发生警报时取消编译操作,即将警报看作是错误 |
-w | 禁止所有的报警 |
参考:
1.Linux基础——gcc编译、静态库与动态库(共享库)_daidaihema的博客-CSDN博客_gcc 动态库编译
区别如下:
静态库 | 动态库 | |
特点 | 在链接阶段,将汇编生成的.o文件和引用库一起生成可执行文件,这个方式称之为动态连接。 静态库:libxxxx.a 特点: 1.静态库对函数库的链接是放在编译时。 2.程序在运行时与函数库再无瓜葛 3.浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。 | 动态库:libxxx.so 1.动态库把对一些库函数的链接载入推迟到程序运行的时期。 2.可以实现进程之间的资源共享 3.方便程序升级。 4.可以真正做到链接载入完全由程序员在程序代码中控制(显示调用) |
优点 | 程序在运行时与函数库没有关系 | 1.动态库把对一些库函数的链接载入推迟到程序运行的时期。 2.可以实现进程之间的资源共享 3.方便程序升级。 4.可以真正做到链接载入完全由程序员在程序代码中控制(显示调用) |
缺点 | 1.空间浪费 2.静态库对程序的更新、部署和发布页会带来麻烦 | 运行时候需要连接库,不存在将报错 |
备注:inux下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。
參考:https://www.cnblogs.com/codingmengmeng/p/6046481.html
步骤1.书写示例代码:如下add.cpp和mult.cpp头文件和源文件
Add.cpp如下:
- #include "add.h"
-
- int add(int a,int b)
- {
- return a+b;
- }
-
- Mult,cpp如下:
-
- #include "mult.h"
- int mult(int a,int b)
- {
- return a*b;
- }
步骤:编译把两个源码文件生成目标文件
gcc -c .\add.cpp .\mult.cpp -I./
步骤,生成静态库:3.使用ar -rsv libxxx.a *.o制作静态库
ar -rsv libdemo.a .\add.o .\mult.o
步骤1:书写可执行程序.main.cpp如下
- #include <mult.h>
- #include <add.h>
-
- int main()
-
- {
- int a=2,b=3;
- cout<<mult(2,3)<<endl;
- cout<<add(2,3)<<endl;
- return 0;
- }
步骤2:链接静态库:g++ -o main .\main.cpp -L./ -ldemo
步骤3:验证:如下
步骤1和步骤2,和静态库一样,生成.o文件:
步骤3:生成动态库
g++ -shared -fPIC -o libdemo.so add.cpp mult.cpp
这个是经常遇见的,步骤1和静态库的使用步骤1相同
步骤2:生成可执行文件
g++ -o main .\mult.cpp -L. -ldemo
涉及到函数:
函数原型 | 说明 |
const char *dlerror(void) | 当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。 |
void *dlopen(const char *filename, int flag) | 用于打开指定名字(filename)的动态链接库,并返回操作句柄。调用失败时,将返回NULL值,否则返回的是操作句柄。 |
void *dlsym(void *handle, char *symbol) | 根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。由此地址,可以带参数执行相应的函数。 |
int dlclose (void *handle) | 用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。2.2在程序中使用动态链接库函数。 |
解析:
函数1:dlsym(void *handle, char *symbol)
filename:如果名字不以“/”开头,则非绝对路径名,将按下列先后顺序查找该文件。
(1)用户环境变量中的LD_LIBRARY_PATH的值;
(2)动态链接缓冲文件/etc/ld.so.cache
(3)目录/lib,/usr/lib
flag表示在什么时候解决未定义的符号(调用)。取值有两个:
1) RTLD_LAZY : 表明在动态链接库的函数代码执行时解决。
2) RTLD_NOW :表明在dlopen返回前就解决所有未定义的符号,一旦未解决,dlopen将返回错误。
函数2:dlsym(void *handle, char *symbol)
dlsym()的用法一般如下:
void(add)(int x,int y); 说明一下要调用的动态函数add
add=dlsym("xxx.so","add"); 打开xxx.so共享库,取add函数地址
add(89,369); 两个参数89和369调用add函数
步骤1:程序使用demo.cpp:
- #include "add.h"
- #include <stdio.h>
- #include <dlfcn.h>
- #include <cstdlib>
- extern "C"
- {
- typedef int (*fn)(int a,int b);
- }
-
-
- int main(int argc, char const *argv[])
- {
- void *handle = dlopen("libdemo.so",RTLD_LAZY);
- const char *err = dlerror();
- if(err !=NULL){
- perror("could not open shared object!");
- }
- if (NULL != handle) {
- printf("open sussess\n");
-
- }
-
- fn add_func = (fn)dlsym(handle,"add");
- cout<<add_func (23,34)<<endl;
-
- dlclose(handle);
- return 0;
- }
步骤2:编译
g++ -g -o demo demo.cpp -L./ -ldemo -ldl
步骤3:验证
./demo
如下:
nm可以查看库中有那些函数:列出.o .a .so中的符号信息,包括诸如符号的值,符号类型及符号名称等。所谓符号,通常指定义出的函数,全局变量等等。
https://www.cnblogs.com/itech/archive/2012/09/16/2687423.html
可以查看可执行文件或者库连接那些文件,及其连接是否正确
参考:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。