简介
「GCC」GNU Compiler Collection,GNU编译器套件
- 由GNU开发的语言编译器
- 原先只支持编译C语言。如今已成为了一个编译集,支持C、C++、Java等语言的编译
「gcc」小写的gcc,代表的是GCC编译集中C语言的编译器
「g++」GCC编译集中C++的编译器。如果不装g++,一些C++的库可能会没有,可能会编译不过
编译过程
编译过程: | 过程 | 说明 | 会出现的错误 | | —- | —- | —- | | 预处理(Preprocessing) | 生成.i文件 | 宏定义错误 | | 编译(Compilation) | 生成.s文件 | 代码错误,比如语法错误等 | | 汇编(Assembly) | 生成.o文件 | | | 链接(Linking) | 生成可执行文件 | 找不到资源、找不到库文件 |
说明:在linux的gcc中,可以对每个步骤分别做处理。而在Windows当中,一般只能控制到预处理、编译和链接部分,汇编一般只有相对硬件开发才会涉及到。
语法
gcc用于编译C语言的代码
- g++用于编译C++的代码
-o(指定输出文件名,生成可执行文件)
此文件名可以没有后缀(test
),也可加后缀(test.out
)。此输出文件即为可执行文件(类比windows的test.exe
)
-c(只编译不链接,生成.o文件)
说明:一个项目若包含很多个文件时,经常会用到这个命令,只编译其中一个cpp,不链接其他的cppgcc -c main.c
//只编译main.c,不链接。生成了main.o文件
gcc main.o -o main
//再链接。生成了执行文件
-E(预编译)
预编译:把所有的头文件、宏全部拼到一个.c文件中gcc -E main.c>main.e
//gcc -E main.c之后,在命令行打印出的内容很多,可以使用>把内容输出到文件main.e中
vim main.e
//打开文件,查看预编译的结果
-S(只编译,不汇编)
gcc -S main.c
//只编译,不汇编。生成了一个main.s
vim main.s
//打开看一下结果,main.s即是汇编代码
-g(生成调试信息)
-g即表示生成Debug版本的可执行文件
若没有-g,即默认情况(gcc main.c -o main
)是release版本 ```shell gcc -g main.c -o main_d //gcc main.c -o main_d表示编译main.c,结果文件名为main_d(可执行文件) //-g表示这是一个有调试的版本
<a name="ljLEQ"></a>
# 编译
<a name="y9m3H"></a>
## 多文件编译
- src 文件目录
- person
- person.h
- person.cpp
- text.cpp 此文件中使用了person.h
```shell
g++ main.cpp
main.cpp:2:20: fatal error: Person.h: No such file or directory
comilation terminated.
//预编译出错。提示找不到Person.h,所以我们要指定头文件路径(-I),如果多个路径,再加-I../Person2
g++ main.cpp -o main -I../Person
/tmp/cct3XXsz.o: In function 'main':
main.cpp:(.text+0x26): undefined reference to `Person::Person()`
collect2: error: Id returned 1 exit status
//编译出错。找不到Person的实现,即找不到.cpp文件
g++ main.cpp ../Person/Person.cpp -o main -I../Person
//指定Person.cpp,把它一起编译了
Linux静态编译
静态编译:静态编译会把所有的库都编译到一个文件中,这样把执行文件放到任何环境中都能运行,它并不要求运行环境。
动态编译:动态编译不把依赖库一起编译到可执行文件中。故动态编译会依赖很多库,很依赖于运行环境,如果环境中没有依赖库,就会运行失败。
例如:
g++ main.cpp -o main //编译成动态的可执行文件
ldd main //查看main的所有引用
linux-vdso.so.1 => (....) //可以看到它引用了很多库
g++ main.cpp -o main_static -static //编译成静态的可执行文件
ldd main_static //查看引用
not a dynamic executable //可以看到静态版本没有引用动态的可执行文件
综上:
- 不建议用静态的方式来编译
- 一方面编译静态库的时间很长(跨平台项目本身编译的时间就很长,1分钟和10分钟的区别),另一方面静态库编译出来的可执行文件很大
- 静态库带来的运行的简单,但编译非常麻烦。
- 当然有一些应用场景,为了运行时的简单,选择静态编译也可以的。
Linux动态编译和调用
动态编译:
调用:g++ Person.cpp -fpic -shared -o libPerson.so
//-fpic表示.cpp中的函数与代码位置不相关-->可以通过头文件中的名字找到函数所在的位置
//-shared表示这是一个动态库
//-o指定生成文件的名称
//文件名以lib开头,.so结尾,所以中间的Person才是这个库的名字,即此动态库最终文件名为Person.so
执行:执行的时候会报错误,没有指定这个库的文件路径g++ main.cpp -o main -I../Person -L../Person -lPerson
//-L指定动态链接库的路径,如果不指定默认到系统环境变量的lib路径下找
//-l指定动态链接库的名称,即上面指定libPerson.so中间的Person
两种解决方案:
- 将.so拷贝到系统的path下面
- 执行脚本的方式,在命令行输入
export LD_LIBRARY_PATH=../Person