gcc是一个编译工具,我们平时写的c/c++代码要想变成可执行文件,必须要经过预处理、编译、汇编、连接等步骤。gcc工具就完成这些动作。
一gcc编译过程
二、gcc常用参数
1.编译过程常用参数
参数 | 解释 |
---|---|
-c | 只编译不连接,生成目标文件.o |
-S | 只编译不汇编,编译后停止 |
-E | 只预处理 |
-g | 包含调试信息的编译 |
-o file | 指定输出文件。无论是预处理、编译、汇编、链接都可以使用. |
-I[dir] | 指定搜索头文件路径 |
举例:
将hello.c只做预处理为hello.i
将预处理后的hello.i文件编译成hello.s汇编文件
将hello.s汇编文件编译成hello.o的目标文件
将hello.o文件编译成最后的可执行文件,并执行
2.库选项
linux下静态链接库和动态链接库
.a[libname.a] 静态库格式
.so[libname.so] 动态库格式
参数 | 解释 |
---|---|
-ststic | 静态编译 |
-shared | 1.生成动态库 2.进行动态编译 |
-L dir | 库文件搜索中添加路径 |
-fPIC | 生成使用相对位置无关的目标代码,然后通常用于使用gcc的=static选项从该PIC目标文件生成动态库文件 |
3.警告选项
参数 | 解释 |
---|---|
-w | 关闭所有警告 |
-Wall | 发出gcc提供的所有有用的警告 |
-pedantic | 发出ansi c的所有警告 |
4.优化选项
参数 | 解释 |
---|---|
-o/-o1 | 编译器会试图减少目标码的大小和执行时间 |
-o2(常用) | 多优化一些。除了设计空间和速度的交换的优化选项,执行几乎所有的选项 |
-o3 | 优化的更多 |
-o0 | 不优化 |
三、gdb调试工具
1.进入调试模式
下面是事先写好的为了调试用的代码
带调试信息的编译,进入调试模式。进入调试模式后命令行的开头变成(gdb)
2.断点
先使用list命令,查看源代码。看将断点打在哪里
①打断点
b(break) 函数名
b(break) 行号
b(break) 文件名:行号
b(break) 行号if条件
②查看断点
ib(info break)
③删除断点
d(delete) 短点号
3.运行
r (run) 运行到断点处会停下来
c (continue) 运行到断点处会停下来
q (quit) 退出gdb调试
4.单步调试
n(next) 运行到函数处直接跳过,而不进入函数体内
s(step) 进到函数体内
f(finsh) 跳出当前函数体
5.打印值/监控
p (printf) 打印出当前变量的值
wi 会弹出一个类似windows下的图像框,更方便的观察调试步骤
使用wi命令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ON7aX6KZ-1625276433959)(\images\linux\21.png)]
四、make命令的介绍
在linux中常常使用make命令来编译程序,特别是大程序。而make命令所执行的动作依赖Makefile
1.Makefile作用
i.工程文件组织,编译成复杂的程序
ii.安装及卸载我们的程序。
2.Makefile编写规则
Makefile由若干条规则构成
形式:
targets(目标):prerequisites(依赖) …
command(命令)
例如:
hello:main.c fun1.c fun.c
gcc main.c fun1.c fun2.c -o hello
//这就是一个Makefile文件包含的一系列规则
//第二行是table键的缩进,不能以空格键缩进
来个稍微复杂的
3.Makefile变量
①用户自定义变量
有点类似于c语言中的宏定义
定义的变量引用$(变量名)
上面是原内容。我们定义一个myobject的变量,让它等于debug.o add.o mux.o下面再使用时用$(变量名)即可
变量中有一些特殊的赋值操作:
= :普通的赋值
:= :立即赋值
?= :判断赋值
+= :追加赋值
立即赋值:立即把变量的当前值,赋值给别的变量
判断赋值:判断被赋值的对象是否为空,如果是,执行赋值操作,如果不为空,不执行赋值操作
追加赋值:拼接字符串的效果,把一个变量,添加到另一个变量的后面
②预定义变量
相当于系统自带的变量
变量 | 解释 |
---|---|
AR | 库文件维护程序的名称,默认值为ar |
AS | 汇编程序的名称。默认值为as |
CC | c编译器的名称,默认值为cc |
CXX | c++编译器的名称,默认值为g++ |
ARFLAGS | 库文件维护程序选项,无默认值 |
ASFLAGS | 汇编程序选项,无默认值 |
CFLAGS | c编译器选项 |
CxxFLAGS | c++编译器选项 |
③自动变量及环境变量
变量 | 解释 |
---|---|
$* | 不包含扩展名的目标文件名称 |
$< | 第一个依赖文件名称 |
$? | 所有时间戳比目标文件晚的依赖文件 |
$@ | 目标文件完整名称 |
$^ | 所有不重复的依赖文件 |
4.make工作流程
1、make会在当前目录下找名字叫“Makefile”或者“makeflie”的文件
2、如果找到,它会找文件中的第一个目标文件(target)并把这个文件最为最终的目标文件
3、根据时间戳生成目标文件
4、递归去寻找目标文件依赖文件,并且递归生成
5.Makefile管理命令
命令 | 解释 |
---|---|
-C dir | 读入指定目录下面的Makefile |
-f file | 读入当前目录下的file文件为Makefile |
-i | 忽略所有命令执行错误 |
-I dir | 指定被包含的Makefile所在目录 |
五、静态库与动态库的制作
前面已经介绍了在linux中动态库用libxx.a,静态库用libxx.so表示。
静态库: 是在程序编译的时候会被链接到当前的程序当中
动态库: 程序在运行过程中会被加载到程序当中
1、动态库的制作
①首先准备三个文件,这里以add.c、add.h、main.c为例
这里只做简单的动态库的封装的演示,代码比较简单。
封装的对象为:add.c 即功能实现的过程
②将add.c转换成xxx.o文件
gcc -c add.c -o add.o
转换后xx.o已经是二进制文件
③制作静态库ar cr指令
ar cr libadd.a add.o
//libxx.o库文件已生成
静态库制作完成,下面是将静态库添加到工程中
④编译
gcc -static main.c -L./ -l add -o add
//第一个add为库文件的名字,第二个add为生成目标对象的名字
上述命令解释:
-static:声明这是一个静态库
-L:后面跟libxx.o库文件的路径(该命令的路径为当前目录)
-l(小写L):后面跟库文件名
执行add的结果正确,使用的是静态库。
2、动态库的制作
①制作库的源码(这里还是以上述三个文件为例)
main.c、add.c、add.h
②将add.c转换成add.o
gcc -c add.c -o add.o
③制作动态库
gcc -shared -fpic add.o -o libadd.so
//动态库libadd.so生成
④编译
gcc main.c -L./ -l add -o main
//-L:后面跟库路径
//-l:后面跟动态库的名字
⑤运行
这里需要把我们制作的动态库文件libxx.so放到系统/usr/lib目录下。才能运行我们的代码。否则会报错找不到动态库文件。
提取码:g4hp