g++编译入门
本文为您介绍g++的编译用法;通过从最简单的单文件编译,到多文件编译,再到动态库、静态库的编译及使用;
例子都经过实际编译并运行,可谓全网最良心之作呐,放心拷贝粘贴学习!
1、g++的编译单文件
c++的程序编译的过程如下:
1.预编译
->2.编译
->3.汇编
->4.链接
以个Test.cpp
为例说明整个编译过程
Test.cpp
文件如下
#include <iostream>
#define MAX_NUM 10
// 定义宏
int main() {
// 输出Hello world
std::cout<<"Hello world!"<<std::endl;
// 输出Max+n
int n = 100;
std::cout<<"MAX_NUM+n:"<<MAX_NUM+n<<std::endl;
return 0;
}
1)预编译
宏的替换,还有注释的消除,还有找到相关的库文件
g++ -E Test.cpp > Test.i
只做预处理,生成一个Test.i
的文件,该文件多了很多内容,我们省略前面1万+行
,只看最下面对我们的写的源码做了什么处理;
Test.i
内容如下
int main() {
std::cout<<"Hello world!"<<std::endl;
int n = 100;
std::cout<<"MAX_NUM+n:"<<10 +n<<std::endl;
return 0;
}
这就是预处理做的我们能理解的事,其他的有空自己再慢慢深挖。
2)编译
将预处理后的文件转换为汇编文件,里面为汇编指令
g++ -S Test.i
当然也可以直接将源代码cpp处理 g++ -S Test.cpp
,两者编译后的输出结果一模一样
编译后,将得到一个Test.s
的文件,前面0行开始截取部分内容如下:
.file "Test.cpp"
.text
.section .rodata
.type _ZStL19piecewise_construct, @object
.size _ZStL19piecewise_construct, 1
_ZStL19piecewise_construct:
.zero 1
.local _ZStL8__ioinit
.comm _ZStL8__ioinit,1,1
.LC0:
.string "Hello world!"
.LC1:
.string "MAX_NUM+n:"
.text
.globl main
.type main, @function
main:
.LFB1522:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
leaq .LC0(%rip), %rsi
leaq _ZSt4cout(%rip), %rdi
call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@PLT
movq %rax, %rdx
movq _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rax
movq %rax, %rsi
movq %rdx, %rdi
call _ZNSolsEPFRSoS_E@PLT
movl $100, -4(%rbp)
leaq .LC1(%rip), %rsi
leaq _ZSt4cout(%rip), %rdi
call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@PLT
movq %rax, %rdx
movl -4(%rbp), %eax
addl $10, %eax
movl %eax, %esi
movq %rdx, %rdi
call _ZNSolsEi@PLT
movq %rax, %rdx
movq _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rax
movq %rax, %rsi
movq %rdx, %rdi
call _ZNSolsEPFRSoS_E@PLT
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
...
显然,上面的是机器无关的汇编指令
3)汇编
将汇编文件转为目标文件
g++ -c Test.s # 当然也可以直接使用`g++ -c Test.cpp`从源文件直接输出
汇编执行后,将生成Test.o
的目标文件(二进制文件)
4)链接
将目标文件和库文件整合为一个可执行文件
g++ Test.o -L usr/include/iostream
-L后为库文件目录
命令执行后,将生成一个a.out
,我们可以运行一下该文件,前面的代码正常运行,如下所示:
$ ./a.out
Hello world!
MAX_NUM+n:110
使用-o可以为可执行文件命名
g++ Test.o -o Test -L usr/include/iostream
# 同理可以直接对源码输出`g++ Test.cpp -o Test -L usr/include/iosream`
执行后,将输出Test
的可执行文件
5)一步到位编译
# 直接编译
g++ Test.cpp -o Test
# 执行结果
./Test
Hello world!
MAX_NUM+n:110
直接输出Test
可执行文件
g++常用的参数
-c 生成.o目标文件
-o可执行文件命名
-shared 指定生成动态链接库
-static 指定生成静态链接库
-L 要链接的库所在目录
-l 指定链接时需要的库,隐含命名规则,即自动在前加lib,在后加.a或.so确定库文件名
-std 设置C语言版本 g++ -std=c11 Test.cpp -o Test
2、g++编译多文件
前面我们知道如何编译一个c++代码,如果多个c++文件组织在一起如何用g++编译呢?
我们基于前面测试项目,再创建一个文件HelloToolsClass.cpp
,现在我们有两个文件了:Test.cpp
及HelloToolsClass.cpp
其中HelloToolsClass.cpp
为完整的类声明及定义为一体文件,内如如下;
class HelloTools{
public:
void print(int a, int b)<