先以單文件編譯爲例子 hello.cc:html
#include<iostream> using namespace std; int main() { cout << "Hello World" << endl; return 0; }
編譯加運行的命令ios
g++ 'hello.cc' -o 'hello' -Wall -g -O2 -std=c++17 && hello
其含義就是將hello.cc源文件編譯輸出爲hello這個可執行文件並運行, 獲得一個"Hello World"的輸出, 那麼這個簡單的 g++ 命令背後發生了什麼呢?c++
上述gcc命令其實依次執行了四步操做:shell
1.預處理(Preprocessing)macos
2.編譯(Compilation)測試
3.彙編(Assemble)ui
4.連接(Linking)spa
.c爲後綴的文件:c語言源代碼文件.net
.a爲後綴的文件:是由目標文件構成的庫文件code
.cpp爲後綴的文件:是c++源代碼文件
.h爲後綴的文件:頭文件
.o爲後綴的文件:是編譯後的目標文件
.s爲後綴的文件:是彙編語言源代碼文件
.m爲後綴的文件:Objective-C原始程序
.so爲後綴的文件:編譯後的動態庫文件
預處理階段作的事情: 宏的替換,還有註釋的消除,還有找到相關的庫文件,將#include文件的所有內容插入。若用<>括起文件則在系統的INCLUDE目錄中尋找文件,若用""括起文件則在當前目錄中尋找文件。預處理以後獲得的仍然是文本文件,但文件體積會大不少, 生成的文件是 -i 文件, 對hello.cc文件進行預處理的命令
g++ -E hello.cc -o hello.i
或者直接調用cpp命令
cpp hello.cc -o hello.i
-E
是指讓編譯器在預處理以後就退出,不進行後續編譯過程, -o
是指指定輸出文件名, 在處理成.i文件之後, 文件的體積會大的多, 變成了4w多行的文件
這裏的編譯不是指程序從源文件到二進制程序的所有過程,而是指將通過預處理以後的程序轉換成特定彙編代碼(assembly code)的過程。將.i預處理文件編譯爲彙編代碼的命令是cc1, 使用-S能夠直接從.cc文件到彙編代碼
g++ -S hello.cc -o hello.s
hello.s文件的部份內容
.section __TEXT,__text,regular,pure_instructions .build_version macos, 10, 14 sdk_version 10, 14 .globl _main ## -- Begin function main .p2align 4, 0x90 _main: ## @main .cfi_startproc ## %bb.0: pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 movq %rsp, %rbp .cfi_def_cfa_register %rbp subq $16, %rsp
彙編過程將上一步的彙編代碼轉換成機器碼(machine code),這一步產生的文件叫作目標文件,是二進制格式。gcc
彙編過程經過as
命令完成:
as hello.s -o hello.o
等價於
g++ -c hello.s -o hello.o
輸出的hello.o爲二進制文件
這一步會爲每個源文件產生一個目標文件。
連接過程將多個目標文件以及所需的庫文件(.so等)連接成最終的可執行文件(executable file)。
命令大體以下
ld -o test.out test.o inc/mymath.o ...libraries...
因此其實簡單的一行命令
g++ hello.cc
其中其實包含了好幾層流程
添加兩個文件 math.h
`int add(int a, int b);`
和math.cc
, 定義一下這個add方法
int add(int a, int b) { return a + b; };
而後在hello.cc
中調用一下這個add方法
#include<iostream> #include "math.h" using namespace std; int main() { cout << "Hello World" << endl; cout << add(1, 2) << endl; return 0; }
再直接運行
g++ hello.cc
試試, 發現收到以下報錯
Undefined symbols for architecture x86_64: "add(int, int)", referenced from: _main in hello-9842e2.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
看到說add(int, int)這個方法是未定義符號, 但是明明將math.h引入進來了啊, 實際上是由於沒有連接到math.cc生成的.o文件, 連接math.o再生成可執行文件試試
g++ -c hello.cc math.cc
這樣生成了hello.o math.o兩個二進制文件, 而後連接math.o和hello.o生成可執行文件
g++ hello.o math.o -o hello
再運行hello試試, 發現獲得了想要的輸出。或者還有一個更簡單的辦法
g++ hello.cc math.cc -o hello
通過我測試, 能夠直接獲得上面兩個命令合併的效果。
上面的命令, 在中大型項目中, 通常使用makefile
文件進行整合, makefile
文件的做用和寫法單獨寫一個文章。
https://www.cnblogs.com/ericl...
https://blog.csdn.net/csdn912...