gcc和g++的使用

linux编译器-gcc和g++的使用

gcc和g++的使用_第1张图片

文章目录

  • linux编译器-gcc和g++的使用
      • 预处理
      • 编译
      • 汇编
      • 链接
    • 函数库
      • 动态库和静态库
        • file 查看可执行程序
        • ldd 查看可执行程序格式
  • make和makefile
        • stat 查看文件或目录时间

在讲gcc和g++编译同时,我们复习一下程序翻译的大概过程,并以此为例切入使用gcc/g++;

程序翻译先后进行了预处理、编译、汇编和链接。

一般我们直接翻译(c语言)程序:gcc test.c -o test.o 【-o +文件名称 指名形成文件的名称】

(翻译test.c形成可执行程序文件test.o)现在可以细分为以下几个步骤:

步骤 大概过程 停止条件 目标文件后缀
预处理 头文件展开,去注释,宏替换,条件编译等等—预处理后代码还是c语言 -E -i
编译 把c语言变成汇编语言 -S -s
汇编 把汇编语言转化为二进制 -c(小写) -o
链接 编译器只是编译我们写的代码,还得把我们的代码和库里的代码链接形成可执行程序(你的代码+库)

记忆:ESc—键盘左上角退出键 对应文件:iso一般指国际标准化组织/感光度/ 镜像文件

预处理

gcc -E test.c -o test.i ->预处理test.c文件,-E含义:从现在开始,进行程序的翻译,做完预处理就停下

-o:指明形成的临时文件名称(.i)【把程序翻译的文件保存在临时文件里,不会显性在Linux中显示出来】

我原来的代码是这样子的

gcc和g++的使用_第2张图片

如果不带-o 目标文件直接编译的话会这样

gcc和g++的使用_第3张图片

编译的内容直接在系统中显示出来;但如果加了-o 目标文件的话,会生成个目标(临时)文件test.i,然后会把这些内容储存在目标文件里

gcc和g++的使用_第4张图片

我们可以vim查看

gcc和g++的使用_第5张图片

发现内容是跟显示在系统上是一样的!所以我们在翻译程序的时候,最好指定生成目标文件!

编译

gcc -S test.i -o test.s -S含义:从现在开始,进行程序的翻译,做完编译就停下

-S对应的目标文件后缀为.s

gcc和g++的使用_第6张图片

生成后我们vim查看test.s 可以看到现在就不是c语言了

gcc和g++的使用_第7张图片

汇编

**gcc -c test.s -o test.o ** -c含义:从现在开始,进行程序的翻译,做完汇编就停下

-c对应的目标文件后缀为.o

gcc和g++的使用_第8张图片

我们可以查看—发现更看不懂了

gcc和g++的使用_第9张图片

我们也可以通过od指令查看,发现的确是翻译成了二进制,但这个二进制目标文件不能被执行

gcc和g++的使用_第10张图片

链接

gcc test.o 后面不带指定文件则默认生成a.out;带目标文件则生成目标文件

gcc和g++的使用_第11张图片

gcc和g++的使用_第12张图片

最后我们跑起来

image-20221119110105153

,对于程序翻译的复习就到这。

函数库

我们实现的c程序里,使用了printf等等函数,头文件stdio.h也只是包含了声明,那具体实现是在哪里呢?系统把这些函数的实现都放在名为:libxxx.so.6的库文件中去,当实现函数时,就去这个库文件里面找,而这就是链接的作用。

函数库一般分为静态库和动态库。

静态库指当编译链接时,系统把库文件里的代码加入到可执行文件中,因此生成的可执行文件较大,但程序运行的时候就不需要库文件了。其后缀一般为.a

而动态库恰恰相反,当运行起来,函数实现时,系统会把链接文件加载到库,这样就节省了系统开销。

做个形象的比喻:当你需要干饭时,静态库就是在家自己给自己做菜然后吃饭-此时就不需要外面的饭菜提供;动态库就是去外面的饭店吃饭,省出家里做菜的空间。

动态库和静态库

动态库 Linux系统下库的命名(libxxx.so)-xxx为库的名称 windows系统下命名 优缺点
——— 后缀为.so 后缀为.dll 形成的可执行程序小,节省资源-磁盘,内存,网络
静态库 libxxx.a -xxx为库的名称
——— 后缀为.a 后缀为.lib 形成的可执行程序大;不受库升级或者被删除的影响

现在我们可以试着去验证,我创建了test.c文件并在里面写好了c语言代码

gcc和g++的使用_第13张图片

然后我们编译它

gcc和g++的使用_第14张图片

file 查看可执行程序

通过file可以看到它是动态链接的-那么我们知道在Linux系统下默认允许程序是链接的动态库!

ldd 查看可执行程序格式

可以看到这是动态库,名称为libc.so.6其中c为c库

所以我们区分库要去掉前缀lib 去掉后缀so,剩下的就是库名称:c

gcc和g++的使用_第15张图片

我们还可以通过查看知晓动态库

image-20221119115953143

我们还可以看看静态库:

gcc和g++的使用_第16张图片

可以看到链接静态库的可执行程序大小比链接动态库的大了十倍!

同样的我们可以查看知晓静态库

image-20221119120140219

一般而言链接动态库时只能找动态库,不能找静态库,由于Linux系统下大部分指令都需要用到动态库,所以系统会自带动态库,而静态库需要我们自己安装。

下面是c语言静态库安装指令

sudo yum install -y glibc-static

下面是c++静态库安装指令

sudo yum install -y libstdc+±static

好啦gcc和g++的使用就讲到这。

make和makefile

make是一个命令,makefile是一个文件。

1.make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命

令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一

种在工程方面的编译方法。
2.makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编
译,极大的提高了软件开发的效率。

我们先创建一个文件mycode.c,在里面写好程序

gcc和g++的使用_第17张图片

再创建一个文件,文件名为Makefile(makefile也可);然后在里面写

gcc和g++的使用_第18张图片

Makefile文件的第一行要写依赖关系【儿子:爸爸 —即儿子依赖爸爸—即前者依赖后者】

第二行要以table键开头!

第二行写依赖方法【儿子为什么要依赖爸爸呢?—以这个代码为例编译mycode.c形成mycode—mycode的产生得由mycode.c来决定!】

然后我们出去make一下,发现执行了依赖条件的代码,然后我们去运行可执行程序发现可以运行

image-20221119155601211

然后我们再加点东西进去

gcc和g++的使用_第19张图片

首先我们来看这个**clean:**这里也是一个依赖关系,但clean冒号后面没有接东西说明clean不依赖任何文件或程序。

然后它的依赖方法是删除mycode

我们出去执行,发现它确实能执行

gcc和g++的使用_第20张图片

但这次clean前面有个**.PHONY:clean** 这里又与上面mycode的依赖关系和方法有什么区别呢?

我们连续make,发现后面的都提示mycode已经是最新的了,不需要再编译了

gcc和g++的使用_第21张图片

但是我们连续make clean,就算mycode已经被删除了,还是能执行make clean,那是为什么呢?

gcc和g++的使用_第22张图片

别急,我们先来看这个—mycode.c的时间

gcc和g++的使用_第23张图片

stat 查看文件或目录时间

Access 文件访问的时间—新版的系统对更新频率做了修正,访问过一段时间或者访问了多次才会改变
Modify 内容修改时间—内容改变时间随之改变
Change 文件属性修改时间—文件属性改变时间随之改变(内容修改了文件属性也会变-比如文件大小等等)

然后我们改变一下mycode.c的内容

gcc和g++的使用_第24张图片

gcc和g++的使用_第25张图片

我们发现时间变了。

是否能make 是根据依赖关系两边的文件时间改变而决定的。

我们知道编译文件产生目标文件,所以编译文件修改时间在目标文件修改时间之前。比如编译mycode.c产生mycode,那么mycode.c的修改时间肯定在mycode的修改时间之前,如果是这样那么Makefile文件识别到这样就不需要在make了

如果make之后我们去修改了mycode.c,那么mycode.c文件的修改时间就在mycode修改时间之后。—编译文件修改时间在目标文件修改时间之后,这合理吗?所以Makefile要make一下。

我们可以实验去证明。另外我们知道。touch不仅可以创建文件,还可以刷新文件时间。

我们先make 文件mycode.c直到不能再make,然后我们touch刷新时间,之后我们发现又能make了!

gcc和g++的使用_第26张图片

峰回路转,我们得出结论,.PHONY的作用是不再用时间作为指标来执行make!

.PHONY:,冒号后面的是伪目标(或伪文件)—不再用时间作为指标来执行make!

所以我们可以试试在前面加.PHONY

gcc和g++的使用_第27张图片

我们出去make发现确实如此!

gcc和g++的使用_第28张图片

另:makefile默认情况下 从上到下自动执行第一个目标文件,这就是为什么后面的clean要我们另外执行的原因。

实际上形成目标文件mycode是要通过前面说到的对mycode.c进行预处理形成mycode.i,编译形成mycode.s,汇编形成mycode.o,最后链接才产生可执行文件mycode。所以依赖关系并不是按照从上到下,而是按照推导规则来的!

我们可以打乱顺序

gcc和g++的使用_第29张图片

然后去make

image-20221119165931226

我们发现make出来的顺序并不是按照在Makefile文件上从上到下那样的顺序,而是按照编译的逻辑顺序来的!

好啦对于make和makefile的介绍就到这里了。这里的各自推导规则有点难以理解,学习这里的小伙伴要有耐心噢。

最后我们来总总结一下这篇文章,

我们用翻译程序的过程来引出对g++/gcc的使用,翻译程序的过程有:预处理—编译—汇编—链接;前三者的停止条件为:ESc,对于产生的文件后缀为:iso;链接有链接动态库和静态库,linux下动态库为libxxx.so(后缀为.so,xxx为库的名称),静态库为libxxx.a(.a为后缀)

Windows下动态库后缀为.dll,静态库后缀为.lib ;

然后到make和makefile,makefile第一行是依赖关系,第二行是依赖方法,要以table键为起始;默认自动从上到下make第一个目标文件;依赖关系按照产生目标文件的程序逻辑走;.PHONY:伪目标 这个目标不以时间为标准来make;

看到这里的观众老爷们不妨点点观众点赞收藏走一波,你们的支持是我更新的不懈动力~~~

你可能感兴趣的:(linux,linux,运维)