Linux开发工具之【gcc/g++】
上文我们已经学习了vim
编辑器的相关操作和使用,已经可以在Linux
下编写代码了,有了代码就需要编译运行,此时就需要用到Linux
中的编译工具gcc/g++
了,其中gcc
是C语言
的编译器,g++
是C++
的编译器,下面我们一起来学习一下吧
1. Linux编译器gcc/g++使用
下面以gcc
为例来进行讲解,学会了gcc
,g++
也自然不在话下,这两个编译器的选项都是通用的,上手比较简单
1.1 目标文件
将代码编译链接生成可执行程序,默认生成可执行文件a.out
gcc/g++ 源文件
当然也可以通过-o
选项,来生成指定的可执行文件
-o 目标文件
:生成指定目标文件
gcc/g++ -o 目标文件 源文件
gcc/g++ 源文件 -o 目标文件
注意:-o
选项后必须跟要生成的目标文件,这个选项放在源文件前面或者后面都是可以的
1.2 预处理
在之前说到过,程序的翻译分为:预处理、编译、汇编、链接四个阶段,下面我们就通过gcc
的学习来具体看看每个阶段都做了些什么
首先是预处理,主要功能包括包括宏定义,文件包含,条件编译,去注释等,经过预处理后文件的后缀为.i
通过-E
选项,可以使编译器在执行完预处理后停下来,配合-o
生成指定文件
gcc/g++ -E 源文件 -o 目标文件(.i)
1.3 编译
第二步是编译,在这个阶段gcc/g++
会对代码进行语法分析、词法分析、语义分析、符号汇总等,然后将合法的代码转为汇编代码,经过编译后文件的后缀为.s
通过-S
选项,可以使编译器在执行完编译后就停下来,配合-o
生成指定文件
-S 源文件 -o 目标文件(.s) //也可以直接从.i文件开始执行
1.4 汇编
第三步是汇编,这个阶段是将汇编代码转化为二进制,并生成符号表,也就是把编译阶段生成的.s
文件转成目标文件,经过汇编后的文件后缀为.o
符号表相当于每个函数独自的地址,在Linux
中,C语言的符号表通常是 _函数名
,如 _Add
,C++的符号表通常为 _Z函数名长度+函数名+参数1+参数2
通过 -c
选项,可以使 编译器在执行完汇编阶段后就停下来,配合-o
生成指定文件
gcc/g++ -c 源文件 -o 目标文件(.o) //也可以从.i/.s文件开始执行
二进制文件是elf
格式,用vim
直接查看是乱码,可以用readelf
工具查看,没有的可以自行下载
1.5 链接
最后一步是链接,这个阶段会进行合并段表,符号表的合并和重定位等操作,会将程序运行所需的各种函数链接起来,包括与库函数的链接,Linux
中一般是动态链接,链接后生成可执行文件,默认为a.out
,也可以自己指定
gcc/g++ 源文件 -o 目标文件 //也可以从.i/.s/.c文件开始执行
以上就是gcc/g++
的全部讲解和操作了,希望对各位有帮助
2. 库
每种编程语言都有自己的库,比如c语言的stdio
、stdlib
等,我们在调用库函数时,就是在调用标准库中的函数,Linux下C语言的标准库都在/usr/include
路径下,这个文件就是C语言的动态库
2.1 动态库
动态库中的内容是被所有程序共享的,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so
”,如 libc.so.6
就是动态库。gcc
在编译时默认使用动态库。完成了链接之后,gcc
就可以生成可执行文件
Linux中默认使用动态链接,通过指令ldd
可以列出一个程序所需要的动态链接库(动态链接库也称共享链接库)
ldd 文件名 //查看文件链接情况
这里libc.so.6
就是动态链接的标志,其中lib
是前缀,.so
是后缀,去掉前后缀,最终为c
,即为文件最终调用的库
file命令查看文件详细信息
file 文件名 //查看文件的详细信息
动态链接主要依赖不同函数在库中的位置信息进行调用,只有一份代码库,比较节省空间
举个生活中的例子帮助记忆:
- 动态库就好像是网咖,全村的人都可以去网咖上网,还可以选择自己喜欢的机位和配置
2.2 静态库
静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a,如果想采用 静态链接的方式编译程序,需要在编译时加上 -static
选项”
没有静态库可以自行下载
yum install -y glibc-static //下载C语言静态库
yum install -y glibc-static libstdc++-static //下载c++语言静态库
静态库名称为libXXX.a
,其中lib是前缀,.a是后缀,去掉前后缀,就是最终调用的库
由于静态链接是直接讲所需代码拷贝到程序中,所以最终生成的文件相对动态链接会大很多
接着上面的例子:
- 静态库就像是你觉得村里的网吧太远了,自己买了一台电脑放到家里玩(调用某个库),不过如果买了很多台,家里就没地方放了(空间不足)
==总结==
- 库分为动态库和静态库,静态库让编译器对用户程序进行静态链接,动态库让编译器对用户程序进行动态链接
- 静态库和静态链接:链接的时候,如果是静态链接,找到静态库,拷贝静态库中的所需要的实现功能的代码到自己的可执行程序中
- 动态库和动态链接:链接的时候,如果是动态链接,找到动态库,拷贝动态库中的所需要的实现功能的代码的地址到自己的可执行程序中。
- 静态链接成功:程序不依赖任何库,可以独立运行
- 动态链接成功:程序依赖动态库,一旦动态库缺失,程序无法运行。一般的云服务器,默认的只有动态库
==优缺点==
动态库优点
- 可以实现不同进程间的资源共享
- 因为自身拷贝地址,相比静态库节省很大空间
- 不调用函数时可以不加载动态库
动态库缺点
- 需要调用函数,加载速度较慢
- 程序依赖动态库,一旦动态库缺失,程序无法运行
静态库优点
- 所需函数直接拷贝至程序中,运行速度快
- 程序不依赖任何库,可以独立运
静态库缺点
- 因为自身拷贝实现功能代码问题,浪费空间
3. 自动化构建工具make/Makefile
3.1 概念引入
- makefile带来的好处就是—“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
- make是一个命令工具,是一个解释makefile中指令的命令工具
- make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
3.2 Makefile文件
make
命令和Makefike
文件是配合使用的,Makefile
文件中用来编写任务,任务由依赖关系
+ 依赖方法
组成
那么什么是依赖关系和依赖方法呢?
比如源文件myfile.c
,通过gcc test.c -o myfile
命令编译后生成mytfile
文件,此时两个文件之间的依赖关系为 myfile:myfile.c
,而依赖方法就是 gcc myfile.c -o myfile
然后将依赖关系和依赖方法写入Makefile文件中
编写完成后,我们就得到了一个基本的自动化任务,输入 make myfile
就可以直接编译 myfile.c
文件,生成 myfile
注意:任务刷新策略
- 同一个自动化任务,执行成功后,如果相关文件最近没有发生改变,那么无法再次执行该任务
- 想要再次执行任务,需要对源文件做出修改,或者直接
touch
源文件就行了,两种行为都会修改文件的最近修改时间,使源目标文件不是最新时间
3.3 make指令
直接输入 make
指令时,会默认执行 Makefile
中的第一个自动化任务,当任务成功执行后,不再继续执行后续任务
而使用make 任务名
,则可以调用Makefile
文件中的任意任务,这里的任务名就是依赖关系中:
左侧的名字
3.4 .PHONY伪目标
.PHONY
是 Makefile
文件中的一个关键字,用于对某对象生成伪目标,这样可以无视任务刷新策略,重复执行任务
.PHONY
关键字,对于源文件编译来说,没什么意义,一般是用来修饰 clean
任务,生成清理任务,实现如下
小知识:make
指令的工作原理是去 Makefile
文件中查找任务执行,设计者为了保证适用性,命名为Makefile
和makefile
都是可以的
4. sudo提权
4.1 sudo使用
当普通用户想去执行某些操作时,会提示权限不够,需要使用root
身份,比如一个简单的下载软件操作,就有些麻烦了,为了解决这一情况,可以使用sudo
进行提权,也就是暂时借助root
的身份去完成某个命令
sudo 命令
当遇到权限拒绝的场景时,只需要使用sudo 命令
,然后输入密码,就可以暂时root
的身份无视权限完成指令了,这里不需要输入root
密码,而是输入普通用户的密码,这样可以做到保护root
的情况下执行指令
4.2 sudo配置
普通用户默认是没有赋予提权权限的,还是需要切到root
用户下进行配置
配置步骤:
- 切换到
root
用户下 - 打开
/etc/sudoers
文件 - 翻到最下面,找到指定区域,将需要提权的用户添加进去
//root用户下
vim /etc/sudoers //进入配置文件,按照下图修改即可
退出底行模式的时候需要使用wq!
指令,这是因为是系统级配置文件所以修改需要慎重,所以必须强制修改
Linux开发工具gcc/g++,到这里就介绍结束了,本篇文章对你由帮助的话,期待大佬们的三连,你们的支持是我最大的动力!
文章有写的不足或是错误的地方,欢迎评论或私信指出,我会在第一时间改正