文章目录
Linux 编译器 gcc 与 g++
gcc 演示
解决 static 报错问题
gdb 的使用
Linux 项目自动化构建工具 -make/Makefile
简写 makefile 文件
末尾
Linux 编译器 gcc 与 g++
我们习惯用 gcc 编译 C 语言代码, g++ 编译 C++ 的代码
gcc 也可以编译 Go 语言程序之类的, gcc 可以根据文件后缀来判断当前程序所用的语言
以 test.c 为例:
gcc -E test.c -o test.i 预处理: 完成宏替换, 去掉注释, 头文件包含等工作
gcc -S test.i -o test.s 编译: 把 C 语言代码转化成汇编语言的代码
gcc -c test.s -o test.o 汇编: 把汇编语言的代码转成机器语言 (二进制序列)
gcc test.o -o mytest 链接: 生成可执行程序 (默认是动态链接)
gcc 演示
下面对每步进行演示
1**VIM test.c**
2gcc -E test.c -o test.i
-E 作用: 预处理, 但不生成文件
-o 的作用: 把生成的内容输出到文件, 此外有给文件起名的作用
gcc -E test.c -o test.i 里的 - o 就是把预处理的内容输出到 test.i 里, 不然直接打印到屏幕上了
cat -n test.i
test.i 的内容
3gcc -S test.i -o test.s
-S: 编译 , 不生成文件
-o 把生成的内容放入 test.s
cat -n test.s
生成的汇编代码如下:
4gcc -c test.s -o test.o
-c 汇编不生成文件
-o 把生成的内容放入 test.o
cat -n test.o
看不懂对吧, 我也看不懂, 可以转为二进制文件看
xxd test.o
看不懂对吧 我也看不懂
5gcc test.o -o mytest
这一步写成 gcc test.o -o mytest.exe 效果一样, Linux 不是根据扩展名来给文件归类的, 反正都是可执行文件, 具有 x 权限
gcc test.o : 链接 生成可执行文件.
mytest 文件就不看了, 和上面的 test.o 差不多, 也是二进制文件
链接: 分为动态链接和静态链接, 默认是动态链接
ldd 和 file 可以判断链接类型
ldd mytest
.so 可以判断动态链接,.a 判断是静态链接
libc.so.6 就是个动态库, libc.a 就表示是个静态库
file mytest
英文时间: dynamically linked== 动态链接
既然有动态链接 肯定就有静态链接 两者区别又是什么?
动态链接用到的是静态库, 运行时加载库.
静态链接则是直接包含库, 所以静态链接生成的文件会很大
怎么生成静态链接的可执行文件?
加 - static
举例: gcc test.c -o mytest-s -static(如果报错了拉到下一个块解决报错)
生成的 mytest-s 就是静态链接的, 看看具体信息
file mytest-s
英文时间: statically linked== 静态链接
再比较下动态和静态库的大小
静态链接生成的文件大小是动态链接生成的 100 倍左右
不过静态链接也有优点, 没有那么依赖配置环境, 拿过来就能用.
不加 - static 默认是动态链接
解决 static 报错问题
报错信息:
- /usr/bin/ld: cannot find -lc
- collect2: error: ld returned 1 exit status
原因: 少了静态库... 搞了半天才解决
解决: sudo yum install glibc-static
把库给装上就完事了
补充: gcc -w 不生成任何警告
gcc -Wall 生成所有警告
我们默认是报警告的, 所有默认是 gcc -Wall
test.cpp test.cc test.cxx 都表示 c++ 文件
gcc 编译器可以根据文件后缀判断文件的编程语言
英文时间: pwd==print work directory
gdb 的使用
什么是 gdb?
简单来说就是调试器, 比如 vs 里的调试器
gdb 可执行程序
作用: 进入调试
如 gdb mytest
** 如果报错:** 重新生成可执行文件, gcc 命令加上 - g, 不加默认 release 版本
例 gcc mytest -g
报错原因: 文件里没有调试信息, 也就是我们常说的 release 版本
gdb 界面输入命令报错信息: No symbol table is loaded. Use the "file" command.
-g 可加入调试信息 ,release 版本无调试信息, 不可被调试
检查当前文件是否具有调试信息
readelf -S mytest |grep debug
效果如图:(不打印则说明没有 debug 信息)
小知识: 为什么会有 debug 和 release?
debug 是给我们开发时用的, release 一般是给用户用的
调试信息也占空间啊
如果只有 debug 版本, 用户又不用调试, 调试信息又多占了程序空间
所以对用户来说对 debug 的需求不强 (没有)
如果只有 release 版本, 自己感受一下出了 bug 没有调试器的感觉 [doge]
quit(q) 或者 ctrl+d: 退出 gdb
l : 显示十行代码 按回车显示十行后的代码
但不一定是开头十行
list (l) 行号: 显示行号所在的代码
l 函数名 : 显示函数的代码
b 行号: 给某行加断点 (b== Breakpoint )
如 b 7
b 函数名: 在函数入口加断点
info b: 列出所有断点
r : 开始调试 两次 r 重新调试 r ==run
n : 逐过程 (不会进入函数) n ==next
p 变量: 打印变量的值, 但只显示一次
print 表达式: 打印表达式的值 (变量也算入表达式)
display 变量: 长显示, 每次 n 都会打印
比如 display sum 长显示 sum, 每次 n 都会显示 sum 的值
undisplay 编号 取消长显示 注意是编号不是变量名
c (continue): 跳到下一个断点
d 编号 : 删除断点
s 逐语句 : 会进入函数
bt : 显示调用堆栈
until 行号 跳转到函数里的任意位置
和断点有一些冲突
循环体:
- for( i=0;i<=top;i++)
- {
- (断点) sum+=i;// 断点启用时 (走到这行了用 until) until 未能跳出循环
- }
finish 跑完当前函数 (官方点: 执行到当前函数返回, 然后停下来等待命令 非 main 函数)
c until finish : 跳转三剑客了属于是
Enb=enable y 表示断点可用
disable 断点编号 : 禁用断点
为啥要禁用断点呢, 我不用直接删掉不就行了
答: 保留调试痕迹, 方便多次调试
delete breakpoint ,delete breakpoints : 删掉全部断点
set var 变量: 改变调试时变量的值
比如 set var i=100, 用的比较少
注: 改变变量的值不是 VS 里的条件断点, 而是直接改变往后运行
Linux 项目自动化构建工具 -make/Makefile
make: 这是一条指令
makefile/Makefile: 这是一个文件
依赖关系
- gcc test.c -o test.exe
- test.c
- test.exe
test.exe 的生成依赖于 test.c
touch makefile/touch Makefile
makefile 里面写的是依赖关系和相应的操作
mytest:test.o 表示 mytest 依赖于 test.o 生成, 表现出依赖关系
gcc test.o -o mytest gcc 前面必须是 Tab 不能是四个空格
test.o:test.s 表示 test.o 依赖于 test.s 生成, 表现出依赖关系
gcc -c test.s -o test.o
test.s:test.i 表示 test.s 依赖于 test.i 生成, 表现出依赖关系
gcc -S test.i -o test.s
test.i:test.c 表示 test.i 依赖于 test.c 生成, 表现出依赖关系
gcc -E test.c -o test.i
解释一下这个 make 吧 , 相当于一次性执行了多条命令, 降低了我们的调试的成本
如果文件很多 写 gcc 一个一个编译链接过去成本太高
或者是软件迭代的时候, 进行测试等操作时一个一个写 gcc 成本太高了
项目管理有生成文件的, 自然就有删除文件的
删除文件时 makefile 这么写:
.PHONY:clean 又是什么东西???
.PHONY 很像一个声明, 声明一下 clean, 或者说修饰一下 clean
.PHONY 定义伪目标, 被修饰的 clean 总是被执行
总是被执行? 那肯定就有总是不被执行了
默认: 总是不被执行
下面的 make 就是总是不被执行, 即只能被执行一次, 也一直提示 make: `mytest' is up to date.
同时对比 clean
看到这还有一个问题
为什么生成文件时只需要输入 "make" 而我在删除文件时却要输入 "make clean"?
因为 make 就是从 makefile 文件由上往下走, 执行第一条命令
这么说很晦涩, 举个例子
全称就应该写 make mytest, 只不过 mytest 相关命令写在 clean 前面, 所以可以简写为 make
如果把 clean 写在第一行, 那 make 命令执行的就是删除功能了, 有兴趣可以试试
此外 make 命令不会检查文件是否存在, 找不到操作的文件就直接报错退出了
简写 makefile 文件
mytest:test.o
gcc $^ -o $@ $@依赖于 $^, 类似于代指
- test.o:test.s
- gcc -c $^ -o $@
- test.s:test.i
- gcc -S $^ -o $@
- test.i:test.c
- gcc -E $^ -o $@
末尾
如果有帮助的话麻烦点个赞鼓励一下!
来源: https://blog.csdn.net/m0_53005929/article/details/122401045