0
点赞
收藏
分享

微信扫一扫

Linux gcc 环境, gdb 调试 与 makefile 自动化构建


目录

  • ​​传统艺能😎​​
  • ​​回顾🤔​​
  • ​​-E 指令🤔​​
  • ​​-S 指令🤔​​
  • ​​-c 指令​​
  • ​​动态链接与静态链接🤔​​
  • ​​- static 选项🤔​​
  • ​​gdb 调试🤔​​
  • ​​coding 技巧🤔​​
  • ​​make/Makefile🤔​​
  • ​​概念🎉​​
  • ​​项目构建🎉​​

传统艺能😎

小编是双非本科大一菜鸟不赘述,欢迎大佬指点江山

🎉🎉🎉倾力打造转码社区微信公众号🎉🎉🎉

Linux gcc 环境, gdb 调试 与 makefile 自动化构建_linux

Linux gcc 环境, gdb 调试 与 makefile 自动化构建_linux_02

回顾🤔

说到 Linux 编译原理还得说说文件底层,为什么机器只认识二进制文件呢?其实并不是机器只认识二进制,而是机器的各种硬件比如磁盘,cpu他们只认识二进制,因为需要通电工作,而电在机器中分辨为高电平(1)和低电平(0),自然识别出来就是二进制的 0,1。

在之前就从 C 语言预处理出发谈及了程序执行原理,如雷贯耳的预处理,编译,汇编,链接在 Linux 环境下也是一样的,尤其是 gcc 环境,这四个大步骤只是一个粗略认知,细节是非常深奥复杂的涉及到编译原理这一大学科。==gcc 是 Linux 中仅支持 C 语言编译的环境,我们现在的环境是 g++,也就是 C++ 环境 ==。

gcc 条件我用的并不是太多,毕竟接触了 C++,gcc 有一个改名指令,因为输出目标文件默认为 a.out ,如果想自己命名可使用 -o 指令:

gcc test.c -o newname

-E 指令🤔

当然,我编写程序运行出来都是一步到位,要是想单独研究中间预处理这些个过程该怎么办呢?我们可以依靠 -E 指令完成:

gcc -E test.c -o test.i

-E 是指:强制程序进行翻译时只到预处理步骤结束就终止, -o 是因为预处理完了形成的大量汇编内容会输出到屏幕上,不方便查看,所以我们 -o 重定向到 .i 文件。根据之前的经验,为了更好的展现预处理的作用,我针对预处理的功能只在源文件中添加了宏定义,头文件,注释。

我们 vim 打开源文件,Esc 进行底行模式输入 vs test.i 就可以进入 .c 和 .i 文件的分屏模式:

Linux gcc 环境, gdb 调试 与 makefile 自动化构建_makefile_03

这张图也展现了预处理中头文件展开这项工作,预处理出来的文本是能看懂的,所以结果本质上还是C语言,但是他是干净的C语言,很明显这是知道了系统下路径才可以进行头文件引用,C 语言也并不是随随便便包一句 #include <stdio.h> 就可以搞定了,他必须有C语言的库才行。

其实头文件并不是什么必需品,不需要创建了项目一来就敲个头文件上去,本质上我们不是需要头文件而是依赖某些头文件所声明的方法,比如 stdio 声明了输入输出接口,但是我不包含就不需要:

Linux gcc 环境, gdb 调试 与 makefile 自动化构建_gdb_04


简单的一句代码不包含头文件一样能编译通过对吧。

-S 指令🤔

gcc -S test.i -o test.s

同样的,-S 是指:强制程序进行翻译时只到编译步骤结束就终止。所有的 .s 后缀文件都是汇编文件。

-c 指令

gcc -c test.s -o test.o

-c 是指:强制程序进行翻译时只到汇编结束就终止。.o 后缀文件就是 .obj 文件,它是每个程序的源文件在编译器 Debug 目录下生成的可重定位目标文件,说白了就是链接前的最后一个步骤文件。

(前三步其实很好记,记住你键盘左上角的 Esc 键,只需要 s 变大写即可)

以上这些文件其实都是在对源文件 test.c 进行操作,但是比如 printf 他是如何被运作出来的,我们都知道 printf 是C语言函数,但是我在我的文件里的 printf 它只是一句苍白的单词?这就抛出了一个问题:代码里面的 printf 是如何和C语言库函数 printf 进行关联的?

答案是链接,这一步并不需要我们指令去展现,他也不是执行它是在产生关系。因为前面三步走完系统会自动链接。如果说头文件是方法,那么库文件就是提供方法的实现,以供链接来实现可执行程序,他们就如同 .h 和 .c 的关系 。

动态链接与静态链接🤔

常见的动态库包括 Linux 的 .so 库,Windows 的 .dll 库;静态库包括 Linux 的 .a 库,Windows 的 .lib 库。对应的库又产生了两种不同的链接方式:动态链接和静态链接。

Linux gcc 环境, gdb 调试 与 makefile 自动化构建_gcc_05

动态链接的本质就是我写我自己的代码,但是要实现需要借助外部库,我只需要在链接阶段将库的地址关联进来即可。我们使用者就好像是一群限制自由的高中生,但是外部库就想一个网吧我们回是不是需要他,当然需要的也不只是我一个人,所以这个网吧就相当于是被我们所有人共享的一个库。

而静态库就相当于时代进步了,自家有了高大上的电脑了,随时随地也能在家开黑,就不需要借助网吧这种外部库。虽然咱自家的电脑硬件上和网吧没关系,但是功能上并无差别,将原本库里面的代码拷贝到可执行程序,形成属于我自己的方法,这就是静态链接

总的看下来就知道动态链接的优点就在于共享,任何身份都可以进行访问,也就是系统中只要存在一个 C 语言标准库就可以满足成百上千的命令,就可以节省资源 ;当然惠及越大必然代价越大,一旦库缺失将面临几乎所有指令崩溃的窘境。因此静态库就优点就显而易见了,他不依赖任何库程序可独立执行,缺点就是浪费资源。

- static 选项🤔

原本 Linux 默认生成文件类型都是动态链接方式,但是我们可以自己改变他的链接方式:

gcc test.c -o mytest2 -static

这个指令生成的 mytest2 就是一个静态链接文件,对比一下就看得出浪费空间这个缺点发挥的是淋漓尽致,将近 100 倍要是大项目现在可能已经寄了:

Linux gcc 环境, gdb 调试 与 makefile 自动化构建_makefile_06

gdb 调试🤔

gdb 是 Linux 中一个重要主流的调试手段,只需要 gdb + 可执行程序名即可进入调试模式:

gdb exename

但是你会发现此时还无法调试甚至报了个错:未发现调试符号

Linux gcc 环境, gdb 调试 与 makefile 自动化构建_gdb_07

为什么会报这个错呢?其实,默认形成的可执行程序没法调试!!不知道各位还记不记得C语言程序发布有两种形式:debug 和 release,我们在 vs 的环境中默认是 debug 所以支持随时随地的调试,但是 Linux 默认是 release,要调试就需要 -g 选项来修改一下:

gdb exename -o exename -g

这样就能转换出一个 debug 版本的文件:

Linux gcc 环境, gdb 调试 与 makefile 自动化构建_gcc_08

coding 技巧🤔

  1. 进入调试模式是空的,所以我们首先需要的是展现代码,先bia一个 list 指令,可简写为 l 来展示全部代码段,l + 0 是从第 0 行显示, l + main 是从 main 开始显示。
  2. 断点:正式调试需要打断点,语法为:== breakpoint + 对应行数==,breakpoint 显得过于繁琐可简写为== b + 行数 ==即可,查看断点信息 info b ,这里随便打了 2 个断点为例:
  3. Linux gcc 环境, gdb 调试 与 makefile 自动化构建_服务器_09

  4. 删除断点用 delete + 断点编号,可简写为 d + 断点编号;
  5. 查看、打印数据:如果想查看此时某个数据,我们采用== print + 对象命令打印显示,可简写为 p + 对象== 。
  6. 逐语句执行: step 指令,可简写为 s,相当于 vs 里 F11 键的作用。
  7. 逐过程执行:区别于逐语句,逐过程把函数当成一个大步骤直接走完不进入,我们采用 next 指令,可简写为 n ,相当于 vs 里的 F10 键的作用。
  8. 监视值:display + 对象参数名,可以在往后调试的每一次步骤中常显示,类似于 vs 中的监视窗口,取消常显示 :undisplay。
  9. 跳转:如果在一个循环内,我调试几步发现没有毛病想跳出循环又不改动里面内容,我们直接 until + 行数 可跳转到对应行。
  10. 断点间执行: c ,即 continue ,运行到下一个断点处停止。
  11. 运行程序: r ,相当于 vs 里的 F5 键 。

make/Makefile🤔

概念🎉

make/Makefile 是 Linux 项目自动化构建工具,会不会写从侧面可以反映你是否具备完成大型工程的能力。

一个工程中的源文件不计其数,按照类型、功能、模块分别放在若干个目录中,makefile 定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,makefile 带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,极大的提高了效率。

make 是一个解释 makefile 中指令的命令工具,一般来说,大多数的 IDE 都有这个命令,比如:Visual C++的 nmake,Linux下 GNU 的 make 。所以 make 是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。

项目构建🎉

项目的构建牵扯到项目的结构,一个项目里面包含了多个 .c ,.h 或者 .cpp ,到底先编译谁?需要链接哪些库?库和头文件去哪里找?这些问题我们压根儿就不关心,vs 下之所以一个 F5 就能运行是因为 vs 自动的给咱维护好了,但是 Linux 下就没有这么幸运了,我们面对多文件体系的办法就是使用 makefile ,在存放源文件,头文件的目录中 touch 一个 Makefile ,之所以能用 touch 就表明此时 Makefile 还是一个普通文件,他里面会包含两个东西:

  1. 依赖关系
  2. 依赖方法

通俗点讲我们要生成可执行文件的依赖关系就是源文件 test.c,依赖方法就是 gcc test.c -o test.c ,至此我们就可以打开 Makefile 进行添加:

Linux gcc 环境, gdb 调试 与 makefile 自动化构建_linux_10

注意第一行是依赖关系,下一行不能一来就写依赖方法,要以 Tab 键开头!之后在指令中键入 make 即可,make 指令相当于 vs 下的生成解决方案。那么相应的清理解决方案怎么办呢?我们照样打开 Makefile ,添加进语句:

Linux gcc 环境, gdb 调试 与 makefile 自动化构建_linux_11

这里 clean 是个孤儿没有依赖关系所以后面不需要跟,好了就可以出来 make claen 一下就可以了。这里的 .PHONY 是一个 makefile 中的关键字,他后面跟的叫做伪目标,这个写不完了,写一篇讲吧,

今天就到这里,润了家人们。


举报

相关推荐

0 条评论