【Linux环境基础开发工具】编译器-gcc/g++

简介: 【Linux环境基础开发工具】编译器-gcc/g++

写在前面:

上一篇博客, 我们学习了vim编辑工具,学会了怎么写代码,


这篇文章,我将分享代码该怎么编译的问题。


目录


写在前面:


1. gcc和g++介绍


2. gcc是如何编译程序的


1. 预处理


2. 编译


3. 汇编


4. 链接


3. gcc的选项介绍


4. 我们使用的函数是哪来的


5. 我们的.o文件和库是如何链接的?


6. debug和release        


写在最后:


1. gcc和g++介绍

我们通过gcc和g++编译代码,gcc主要编译C语言,g++则可以编译C语言和C++,


gcc和g++的选项基本一致,所以我介绍gcc的选项,g++直接平替过去就行。


这里我们话不多说,直接演示一下:


比如说,我们写了一段代码:


我们可以用gcc来编译一下:



我们发现,使用gcc编译的时候,他会生成默认叫做a.out的可执行程序文件,


其实具体是什么名称或者说后缀并不重要,能不能执行,


只取决于他有没有可执行权限,我们在权限那篇文章已经讲过了。


当然我们也可以写C++代码,C++的后缀名有不少,


可以用.cpp,不过我更习惯用.cc作为我的后缀名:


比如说我现在写了一段C++代码,用g++编译一下:



编译的使用,默认形成的可执行程序也是a.out。


补充:


g++是可以直接编译C语言的,他就直接按照C语言的形式编译。


2. gcc是如何编译程序的

1. 预处理

预处理主要干这几件事:


a. 去注释


b. 头文件展开


c. 条件编译


d. 宏替换


这是我们文件先在包含的一段代码,存在注释,头文件,条件编译和宏替换。



我们需要使用gcc的一个选项:-E


以及一个选项 -o 指定我们形成的文件的名字。


对这段程序进行预处理操作:



我们成功形成了文件,打开看看:



我们可以看到,左边的使我们的源代码,右边是预处理之后的程序,


可以看到,预处理该干的事情都干了:



这个就是预处理的过程,我们学习C语言的阶段应该是学习过了。


补充内容:


我们为什么能在Windows或者说Linux下进行C/C++或者其他形式的开发呢?


我们系统中一定要提前或者后续安装上,C/C++开发相关的头文件,库文件。


C/C++开发环境不仅仅指的是vs,gcc,g++,更重要的是语言本身的头文件和库文件。


所以Linux是提前给我们装好的C/C++的头文件,


那么在哪里呢?



这个路径就是gcc,g++在Linux下默认搜索头文件的时候,搜索的路径。



我们能在这里找到我们常用的头文件。


我们可以vim一下进入stdio.h文件里面看看:



总共就是九百多行,我们刚刚展开的头文件,也是差不多这个行数。


其实他就是把这一段拷贝到了我们的源文件当中。


所以我们在下载所谓的VS2019这些编译器,选择开发包的时候,


就是在同步下载C/C++对应的头文件和库文件。


补充内容:


gcc是支持对文件进行文本级内容修改的,


比如说:



我们编译的时候,定义一个RUN的宏:



这个宏确实是定义进去了。


2. 编译

编译形成汇编代码:




这些其实就是汇编代码。


3. 汇编

再将汇编代码转成机器可以识别的形式,


说人话就是形成二进制:




我们就能看到这些意义不明的二进制乱码了。


当然,我们也可以用一些二进制查看工具:



可以查看一下二进制的内容:



4. 链接

最后我们就完成了:



获得了可执行程序。


3. gcc的选项介绍

-o 选项,


我们刚刚已经对-o 选项有了一个基本的了解,


实际上,他形成的自定义的文件名我们是可以随便修改的。


这里我就不举例子了,我命名的是mytest ,你们想叫什么都行。


只要在-o 后面跟上我们的可执行程序即可。


那么,


我们对程序进行预处理的时候,使用的 -E 选项是什么意思呢?


作用:告诉gcc,从现在开始进行程序的翻译,将预处理工作做完后就不要往后走了。


那 -S 的选项又是什么意思呢?


从现在开始进行程序的翻译,将编译工作做完就停下来。


那 -c 的选项是什么呢?以此类推:


从现在开始进行程序的翻译,将汇编工作做完就停下来。


而汇编形成的test.o文件,又称为可重定位目标二进制文件,简称目标文件。


(其实Windows下的.obj文件就是目标文件)


而这个文件是不能独立执行的,需要通过链接才能执行。


最后进行gcc链接,


其实就是将可重定位目标二进制文件,和库进行链接形成可执行程序。


他们的选项:-E -S -c ,如果你记不住的话,可以看看键盘左上角的ESC键(记得c是小写就行)


4. 我们使用的函数是哪来的

比如说这段代码里的printf函数:



我们想要调用一个函数,我们使用函数名来调用,


我们需要看到函数的声明,printf这个函数的声明在stdio.h这个头文件里面,


那他的定义呢?或者说这个函数的实现呢?是谁给我们提供的?


实际上是有一个库来给我们提供方法的实现。


这里用的是C语言,所以其实就是C语言的标准库来提供实现。



我们通过这个 路径就能找到这个C语言标准库,


所以C语言标准库本质上其实就是一个文件。


而在Linux下,.so结尾的是动态库,.a结尾的是静态库。


而在Windows下:.dll后缀是动态库,.lib后缀是静态库。


一般来说,库是有自己的命名规则的:libname.so.xxx,


所以上面的libc,c就是名字,.6是他的版本。


方法的实现就是在库当中的,


库其实就是把源文件,经过一定的编译(翻译),然后打包,只给你一个文件即可。


总结:


头文件提供方法的声明,库文件提供方法的实现 + 你的代码 = 你的软件。


(不用我们重复造轮子,站在巨人的肩膀上)


5. 我们的.o文件和库是如何链接的?

有两种方法:


1. 动态链接


2. 静态链接


先说动态库,


动态库也叫做共享库,是多个程序共享的一个库,他们是构建了一种链接的关系。


比如说我们上面刚刚演示的那个C语言的库,如果我们把它删了,


那我们的这个可执行程序就无法执行:



我们用C语言写的可执行程序,默认调用的都是动态库,就都没办法执行了。


再来说静态库,


在使用静态库的时候,实际上是把静态库的内容也拷进了程序里面,


这样使用的时候就不需要通过链接去找库资源,以后也就不用依赖静态库了,


而是可以自己使用了。


现在我们写代码验证一下:



这是我们之前直接用gcc编译出来的可执行程序,


可以看出:


在Linux中,编译形成的可执行程序,默认采用的就是动态链接 -- 要求系统提供动态库


我们使用:gcc test.cc -o mytest_static -static


使用静态链接编译一个程序,



可以看见他没有动态链接,


我们通过 ll 查看更多信息:



可以明显看出静态链接的可执行程序体积变大了,


在Linux中,如果要按照静态链接的方式,形成可执行程序,需要添加-static选项,


也就是系统需要提供静态库才能使用。


不过我们Linux下默认只装了动态库,静态库需要自己安装。


输入:sudo yum install -y glibc-static


就能直接安装C语言的静态库。


输入:sudo yum install -y libstdc++-static


就能直接安装C++的静态库。


补充:


1. 如果我们没有静态库,能不能使用-static进行编译呢?不能


2. 如果我们没有动态库,但是有静态库,能不能直接gcc?能


gcc默认优先动态库,如果没有动态库也会用静态库编译,-static的本质:改变优先级


3. 其实我们使用的这些库,不一定是纯的全部动态或者静态链接,是混合的。


总结:


动静态库的优缺点:


动态库是共享库,有效的节省资源(磁盘空间,内存空间,网络空间等)


静态库,不依赖库,程序可以独立运行,但是体积大,比较消耗资源。


6. debug和release        

debug版本是我们平时写的版本,release版本是上线版本,


而debug版本可以被追踪调试


那debug为啥能被调试呢?


因为在形成可执行程序的时候,添加了debug信息。


我们可以在使用gcc的时候加入 -g 选项添加调试信息:


gcc test.cc -o mytest_debug -g

可以看见他的可执行程序也变大了一点点,


其实就是里面添加了调试信息。


这里再介绍一个指令来查看我们可执行程序二进制的构成,


来观察我们往里面添加的调试信息:


我们输入:


readelf -S mytest | grep -i debug

查看mytest的调试信息,可以观察到是啥都没有的,


而输入:


readelf -S mytest_debug | grep -i debug


我们可以直观的看到这些调试信息。


写在最后:

以上就是本篇文章的内容了,感谢你的阅读。


如果感到有所收获的话可以给博主点一个赞哦。


如果文章内容有遗漏或者错误的地方欢迎私信博主或者在评论区指出~


相关文章
|
5天前
|
Oracle Java 关系型数据库
Linux环境安装配置JDK11
Linux环境安装配置JDK11
30 0
|
8天前
|
Linux 开发工具 C语言
Linux 安装 gcc 编译运行 C程序
Linux 安装 gcc 编译运行 C程序
31 0
|
8天前
|
人工智能 Unix Linux
Linux的学习之路:1、发展史与编译环境的搭建
Linux的学习之路:1、发展史与编译环境的搭建
13 0
|
2月前
|
JSON Kubernetes Linux
Linux环境签发CA证书和K8s需要的证书
Linux环境签发CA证书和K8s需要的证书
29 0
|
23天前
|
搜索推荐 NoSQL Linux
Linux开发工具——vim篇
Linux开发工具——vim篇
|
23天前
|
Ubuntu Linux 编译器
【Linux】4. 开发工具的使用(yum/vim)
【Linux】4. 开发工具的使用(yum/vim)
44 2
|
19天前
|
存储 算法 Linux
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
42 6
|
3天前
|
编解码 Linux
FFmpeg开发笔记(十二)Linux环境给FFmpeg集成libopus和libvpx
在《FFmpeg开发实战》一书中,介绍了如何在Linux环境下为FFmpeg集成libopus和libvpx,以支持WebM格式的Opus和VP8/VP9编码。首先,下载并安装libopus。接着,下载并安装libvpx。最后,在FFmpeg源码目录下,重新配置FFmpeg,启用libopus和libvpx,编译并安装。通过`ffmpeg -version`检查版本信息,确认libopus和libvpx已启用。
15 1
FFmpeg开发笔记(十二)Linux环境给FFmpeg集成libopus和libvpx
|
3天前
|
编解码 Linux
FFmpeg开发笔记(十)Linux环境给FFmpeg集成vorbis和amr
在Linux环境下,为FFmpeg添加对AAC、MP3、OGG和AMR音频格式的支持,需安装libogg、libvorbis和opencore-amr库。首先,从官方源下载各库的最新源码,如libogg-1.3.5、libvorbis-1.3.7和opencore-amr-0.1.6,然后解压并依次执行`./configure`、`make`和`make install`进行编译安装。接着,在FFmpeg源码目录中,使用`./configure`命令重新配置,并重新编译安装FFmpeg。最后,验证FFmpeg版本信息确认已启用ogg和amr支持。
15 0
FFmpeg开发笔记(十)Linux环境给FFmpeg集成vorbis和amr
|
7天前
|
Linux 开发工具 C语言
【linux基础(七)】Linux中的开发工具(下)--make/makefile和git
【linux基础(七)】Linux中的开发工具(下)--make/makefile和git

热门文章

最新文章