目录
- 1.gcc/g++ Linux编译器
- 1.1. gcc与g++的安装
- 1.2. gcc与g++用法
- 1.2.1.gcc用法
- 1.2.2. g++用法
- 1.3. 程序翻译的过程
- 1.3.1. 前提知识:
- 1.3.2. 预处理(语言种类不变)
- 条件编译用途:
- 1.3.3. 编译(生成汇编语言)
- 1.3.4. 汇编(生成二进制文件)
- 1.3.5. 链接
- 2. 函数库
- 2.1. ldd 查看可执行文件的使用的函数库
- 3. 动静态库
- 3.1. 动静态库定义
- 3.2. 动静态库的优缺点
- 3.3. 如何切换使用动静态库
参考文章:编译器-gcc/g++与调试器-gdb的使用
1.gcc/g++ Linux编译器
1.1. gcc与g++的安装
g++与gcc的安装指令:
sudo提权/root 的权限下,才能进行安装
yum install gcc
yum install g++
1.2. gcc与g++用法
两者用法基本一致
1.2.1.gcc用法
注意:gcc只能编译C语言
(1)执行后会默认在该目录下形成一个 a.out 的文件
gcc + 文件名
(2)-o 后面+生成指定文件
-o 的位置随意,但是后面必须是新的指定文件
gcc -o 可执行文件a .c文件 //编译该.c文件,生成一个名为a的可执行文件
gcc .c文件 -o 文件名M //编译该.c文件,生成一个名为a的可执行文件
1.2.2. g++用法
注意:g++既可以编译C++,也可以编译C语言
(1)执行后会默认在该目录下形成一个 a.out 的文件
g++ + 文件名
(2)-o 后面+生成指定文件
-o 的位置随意,但是后面必须是新的指定文件
g++ -o A .cpp文件 //编译该.cpp文件,生成一个名为A的可执行文件
g++ .cpp文件 -o A //编译该.cpp文件,生成一个名为A的可执行文件
1.3. 程序翻译的过程
1.3.1. 前提知识:
语言的发展:二进制语言 ->汇编语言 - >C语言 - >C++,java,python
问题:
先有语言还是先有该语言对应的编译器呢?例如,先有汇编语言呢,还是先有用汇编语言写的编译器呢? 先有该语言。
假设现在有汇编语言,那么二进制语言、以及对应的二进制编译器(该编译器可以把汇编语言,翻译成二进制语言),都已经存在了。
因为编译器本身就是个软件,因此利用二进制编译器,来编写汇编语言组成的新编译器。
然后使用新的编译器(汇编语言编译器),去编译和完善自身的代码。
同样,第一个把c语言编译器,肯定是利用汇编语言所写能够让C语言变为汇编语言的编译器。这是语言和编译器的自举的过程。
编译器的自举是指能够直接或间接地编译自己的编译器。
实现自举的过程中,开发者需要用目标语言编写一个简易版本的编译器。接着利用已有的编译器(可能是另一个语言的编译器)来编译这个新编写的编译器。然后,使用新编译出来的编译器去编译和完善原先的源代码,不断迭代这个过程,直到编译器能足够处理自身语言的复杂性。
程序翻译的过程,就是从其他语言翻译为计算机能够识别二进制语言的过程,和上面的语言发展方向相反。
1.3.2. 预处理(语言种类不变)
预处理功能主要包括
- 头文件展开:将头文件部分内容拷贝到源文件,有对应的拷贝条件
- 宏替换
- 条件编译
- 去注释
预处理指令是以#号开头的代码行。
gcc –E test.c –o test.i
选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。
选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序
条件编译用途:
应用:
- 对软件的专业版、普通版,这些功能不同的版本进行裁剪,实现功能的不同。
- 防止头文件被重复包含
我们可以通过给编译器传递不同的宏值,来进行对代码的动态裁剪。
gcc test.c -o test -D VERSION1=1
1.3.3. 编译(生成汇编语言)
编译阶段,gcc/g++首先检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,将代码翻译成汇编语言。
gcc -S test.i -o test.s
用户可以使用-S选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。
-o选项是指目标文件,“ .s ”文件为已经过翻译的原始程序。
1.3.4. 汇编(生成二进制文件)
把上阶段的汇编文件,转为二进制(可重定位目标二进制文件)。
注意:该文件是不能够执行的**。**
gcc –c test.s –o test.o
-c选项可以得到汇编代码转化为“.o ”的二进制目标代码。
1.3.5. 链接
链接的主要任务就是将生成的各个“ .o ”文件进行链接,与系统中的库建立联系,生成可执行文件。
gcc/g++不带-E、-S、-c选项时,就默认生成预处理、编译、汇编、链接全过程后的文件。
gcc test.o –o test
若不用-o选项指定生成文件的文件名,则默认生成的可执行文件名为a.out。
2. 函数库
在我们编写代码时时常需要使用库函数中的函数,比如stdio.h中的printf函数,但当我们展开stdio.h文件后发现也只是有printf的函数声明,那么这些库函数的定义放在哪里了呢?
2.1. ldd 查看可执行文件的使用的函数库
查看的是动态链接,形成的可执行文件,依赖的共享库
ldd 可执行文件
就以stdio.h头文件举例,里面的库函数实现在了名为libc.so.6(C标准库)的库文件中。在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现printf函数了,而这也就是链接的作用。
平台要支持开发,就必须要提前在系统中安装 语言的标准头文件+库文件!
3. 动静态库
- 库分为动态库与静态库
- 在linux中,动态库文件以.so结尾, 静态库以.a结尾。
- 在windows中,动态库文件以.dll结尾, 静态库以.lib结尾。
动静态****库本质就是一个文件,里面包含了很多已经被编译好的代码。
3.1. 动静态库定义
静态库:
指编译链接时,把库文件的代码全部加入到可执行文件当中,因此生成的文件比较大,但在运行时也就不再需要库文件了,静态库一般以.a为后缀。
动态库:
在编译链接时并没有把库文件的代码加入到可执行文件当中,而是在程序运行时由链接文件加载库,这样可以节省系统的开销,动态库一般以.so为后缀。
3.2. 动静态库的优缺点
-
动态库(链接方式:动态链接)
- 优点:比较节省资源,不会出现太多的重复代码 。
- 资源:磁盘,内存,网络等资源(例如:写了一个项目,里面有多个文件,这里文件中调用了很多个库里面的函数,虽然调用了很多函数,但是实现就只有一个,不会造成代码冗余的问题)
- 缺点:对库的依赖性强,一旦库出现问题,那么所有使用了该库的程序全部都无法运行。
- 优点:比较节省资源,不会出现太多的重复代码 。
-
静态库(链接方式:静态链接)
- 优点:不依赖库(因为静态链接是将库文件代码直接拷贝到可执行文件中),可以在同类型平台中都直接运行。(同类型平台:都是Ubuntu)
- 缺点:体积比较大,比较浪费资源,会出现太多的重复代码 (资源:磁盘,内存,网络等资源。)
3.3. 如何切换使用动静态库
动态链接:gcc -o 可执行程序名称 源文件(gcc默认使用动态链接)
静态链接:gcc -o 可执行程序名称 源文件 -static
如果想要使用静态链接?就需要 先安装 静态库
C/C++静态库的安装:命令
sudo yum install glibc-static libstdc++-static
file查看可执行文件的链接方式