Bootstrap

2024年最全gcc编译以及Makefile与GDB调试_gcc编译器的调试(2),2024年最新大佬分享开发经验

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

2、创建静态库及动态库

静态库:

gcc -c add.c    //编译 add.c 源文件生成 add.o 目标文件

ar  crsv  libadd.a  add.o  //对目标文件*.o 进行归档, 生成 lib*.a,


此处 lib 必须要写的

然后就是在编译其他文件时,链接静态库。

gcc  -o mian  main.c  -L./  –ladd –I./

//不要忘记-L 后面的那个. (即在库文件的搜索路径中添加当前路径 -ladd 表示链接库文件 libadd.a/.so     -I./表示包含在当前目录中的头文件)

如果我们直接将编译完成的.o文件直接加入到了库的末尾,却并没有更新库的有效符号表。连接程序进行连接时,在静态库的符号索引表中无法定 位刚才加入的.o文件中定义的函数或者变量。这就需要在完成库成员追加以后让加入的所有.o文件中定义的函数(变量)有效,完成这个工作需要使用另外一个 工具“ranlib”来对静态库的符号索引表进行更新。

GNU工具中ar是用来制作库文件.a的,但同时还提供了一个ranlib,从手册上看ranlib相当于ar -s,为什么这样呢?

这是由于最早在Unix系统上ar程序是单纯用来打包多个.o到.a(类似于tar做的事情),而不处理.o里的符号表。Linker程序则需 要.a文件提供一个完整的符号表,所以当时就写了单独的ranlib程序用来产生linker所需要的符号信息。也就是说,产生一个对linker合 格的的.a文件需要做ar和ranlib两步 。

动态库:

gcc -fPIC -Wall -c add.c

gcc -shared -o libadd.so add.o

最后编译链接动态库: gcc -o main main.c -L. –ladd

在运行 main 前, 需要注册动态库的路径。常采用的方法有:

cp  libadd.so  /lib   //通常采用的方法, cp  lib*.so /lib  将其copy到系统的/lib文件夹下

创建动态链接库之后, 以后就可以使用该动态链接库了

**例如在 test.c 里面调用了原来库中的函数, 则执行 gcc  test.c –o test    –**ladd 就可以了。较方便

3、静态库与动态库的比较

动态库只在执行时才被链接使用, 不是直接编译为可执行文件, 并且一个动态库可以被多个程序使用故可称为共享库。

静态库将会整合到程序中,在程序执行时不用加载静态库。因此,静态库会使你的程序臃肿并且难以升级,但比较容易部署。而动态库使你的程序轻便易于升级但难以部署。

4、gcc — 优化选项

gcc 对代码进行优化通过选项“-On”来控制优化级别(n是整数)。

优化选项“-O1”:主要进行线程跳转和延迟退栈两种优化。

选项“-O2” 除了完成所有“ -O1” 级别的优化之外,还要进行一些额外的调整工作,如处理其指令调度等。

“-O3” 则还包括循环展开或其他一些与处理器特性相关的优化工作。

优化目标:

  • -O,-O1:效果是一样的,目的都是在不影响编译速度的前提下,尽量采用一些优化算法降低代码大小和可执行代码的运行速度。它主要对代码的分支,常量以及表达式等进行优化。
  • -O2 :该优化选项会牺牲部分编译速度,除了执行 -O1 所执行的所有优化之外,还会采用几乎所有的目标配置支持的优化算法,用以提高目标代码的运行速度。会尝试更多的寄存器级的优化以及指令级的优化,它会在编译期间占用更多的内存和编译时间。
  • -O3 :该选项除了执行-O2所有的优化选项之外,一般都是采取很多向量化算法,提高代码的并行执行程度,利用现代CPU中的流水线,Cache等。例如使用伪寄存器网络,普通函数的内联,以及针对循环的更多优化
  • -Os :O3的目标是宁愿增加目标代码的大小,也要拼命的提高运行速度,但是这个选项是在-O2的基础之上,尽量的降低目标代码的大小,这对于存储容量很小的设备来说非常重要。一般就是压缩内存中的对齐空白(alignment padding)。主要是对代码大小的优化,
  • -Og : 该标识会精心挑选部分与-g选项不冲突的优化选项,当然就能提供合理的优化水平,同时产生较好的可调试信息和对语言标准的遵循程度。

注意:虽然优化选项可以加速代码的运行速度,但对于调试而言将是一个很大的挑战,因为代码在经过优化之后,原先在源程序中声明和使用的变量很可能不再使用,控制流也可能会突然跳转到意外的地方, 循环语句也有可能因为循环展开而变得到处都有,所有这些对调试来讲都是不好的。所以在调试的时候最好不要使用任何的优化选项,只有当程序在最终发行的时候才考虑对其进行优化。

三、make工程管理器


1、简介

工程管理器指管理较多的文件,它是自动管理器能根据文件时间自动发现更新过的文件而减少编译的工作量,同时通过读入Makefile文件来执行大量的编译工作。(自动化)

2、Makefile基本语法及格式

target: dependency_files //目标项:依赖项

< TAB >command           //必须以 tab 开头, command为编译命令

编写好Makefile之后,就可以直接使用  make 编译了。若写了clean,可make clean 清理,重新编译。

如下:

特殊处理与伪目标:

.PHONY 是 Makefile 文件的关键字, 表示它后面列表中的目标均为伪目标。伪目标通常用在清理文件、 强制重新编译等情况下。

eg:

.PHONY:clean

clean:

rm main  main.o

变量、 函数与规则

1、引言

随着软件项目的变大、变复杂,源文件也越来越多,如果采用前面的方式makefile 文件,将会使makefile也变得复杂而难于维护。故通过make支持的变量定义、规则和内置函数,可以写出通用性较强的makefile文件,使得同一个makefile文件能够适应不能的项目是重要的。

2、变量: 用来代替一个文本字符串

变量名:=变量值     简单变量展开(类似于 C++的赋值)   //通常采用这种形式

使用变量的一般方法: ( 变量名 ) = ? ? ? 赋值     ? ? ? = (变量名)=??? 赋值        ???= (变量名)=???赋值    ???=(变量名) 引用

例如:–下

变量分为: 用户自定义变量, 预定义变量( CFLAGS), 自动变量, 环境变量

自动变量: 指在使用的时候, 自动用特定的值替换。

常见的有: $@ 当前规则的目标文件(重点)

$^ 当前规则的所有依赖文件, 以空格分隔(重点)

eg:用自动变量      CFLAGS:= -Wall -O2 –fpic

预定义变量: 内部事先定义好的变量, 但是它的值是固定的, 并且有

些的值是为空的。

AR: 库文件打包程序默认为 ar             CC: c 编译器默认为 cc

CPP: c 预编译器, 默认为$(CC) –E        CFLAGS: c 编译器选项, 无默认

CXXFLAGS: c++编译器选项

规则分为: 普通规则, 隐含规则, 模式规则

隐含规则:  //*.o 文件自动依赖*.c 或*.cc 文件, 所以可以

省略main.o:main.cpp 等

模式规则: 通过匹配模式找字符串, %匹配 1 或多个任意字符串    %.o: %.cpp 任何目标文件的依赖文件是与目标文件同名的并且扩展名为.cpp 的文件

函数:

  1. wildcard 搜索当前目录下的文件名, 展开成一列所有符合由其参数描述的文件名,文件间以空格间隔。 SOURCES = $(wildcard *.cpp)把当前目录下所有’.cpp’文件存入变量 SOURCES 里。

2、 字符串替换函数:(patsubst 要查找的子串,替换后的目标子串, 源字符串)。 将源字符串(以空格分隔)中的所有要查找的子串替换成目标子串。 如

OBJS = ( p a t s u b s t (patsubst %.cpp,%.o, (patsubst(SOURCES))   可以和上一步对应起来看。即把 SOURCES 中’.cpp’ 替换为’.o’ 。

3、(addprefix 前缀, 源字符串)函数把第二个参数列表的每一项前缀加上第一个参

数值

3、如下为一个较为通用的Makefile:

SOURCES:=$(wildcard *.c)

OBJS:= ( p a t s u b s t (patsubst %.c,%.o, (patsubst(SOURCES))

ELF:=main

CC:=gcc

CFLAGS:=-g -Wall

( E L F ) : (ELF): (ELF):(OBJS)

gcc $^ -o $@

.PHONY:clean

clean:

rm $(OBJS) $(ELF)

四、Gdb程序调试


1、gdb 常用命令
  • 首先程序编译时加 -g 选项才可打开调试选项
  • eg:gcc –o filename –Wall filename.c –g //进入调试
  • gdb filename //进入调试
    • l    //显示代码 (list)
    • b  4    //在第四行设置断点 相当于 Windows 的 F9 (break)           //若为 b  main  则表示断点打在main处
    • r    //运行   相当于 Windows 的 F5 (run)
    • n //下一步不进入函数 相当于 Windows 的 F10  (next)
    • s //表示单步进入函数, 相当于 Windows 的 F11 (step)
    • p  I  //打印变量 I 相当于 Windows 的 Watch 窗口(print)
    • c     //运行到最后(continue)
    • bt   // 用于查看当前堆栈
    • f   4    // 进入第 4 层堆栈
  • q     //退出 相当于 Windows 的   Shift+F5 (quit)

五、其他补充


  1. 在 linux 中利用 system(“clear”);实现类似于 windows 里面的清屏函数 system(“cls”);

  2. LINUX 中可以通过下面的方式可以实现 system(“pause”);功能:

printf(“Press any key to continue…”);

getchar();

getchar(); //要用两个 getchar()函数

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

;

getchar(); //要用两个 getchar()函数



[外链图片转存中...(img-tjezvjad-1715672164013)]
[外链图片转存中...(img-TWU5K9c2-1715672164013)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

;