1 編譯鏈接過程分為 預處理--->編譯---->匯編---->鏈接。如下圖所示
2 預處理都做了什么
(1)將所有的#define刪除並展開所有的宏
(2)處理所有的條件預編譯指令比如#if #ifdef
(3)處理#Incldue預編譯指令,將包含的文件插入到預編譯的文件中。采用頭文件的目的是可以供多個不同的cpp源程序使用。自己定義的通常用“”,如果包含庫文件的一般是“<>”.
(4)過濾所有的注釋符號
(5)添加行號和文件標識。方便再編譯器產生調試用的行號信息等
(6)保留所有的#pragma編譯器指令。
3 編譯
(1)將預處理完成的文件進行一系列的詞法分析,語法分析等產生匯編代碼文件。
g++ -S hello.i -o hello.s可以通過打開helloword.s查看匯編代碼。
4 鏈接
(1)將鏈接的模塊獨立地編譯然后組裝起來,這就是鏈接啦
(2)最基本的靜態鏈接過程如下圖所示
(3)庫也就是一組目標文件的包,將代碼編譯成目標文件以后打包存放。
(4)靜態鏈接
對函數庫的鏈接放在編譯時期完成的是靜態鏈接。目標文件和相關的函數庫被合成一個可執行文件。通常為libxxx.a
例子:
代碼如下

1 //main.cpp 2 3 #include "add.h" 4 #include "sub.h" 5 #include "iostream" 6 using namespace std; 7 //演示靜態鏈接 8 int main(){ 9 cout<<"1+2="<<add(1,2)<<endl; 10 cout<<"1-2="<<sub(1,2)<<endl; 11 return 0; 12 }

1 #include "sub.h" 2 int sub(int a,int b){ 3 return a-b; 4 }

1 //sub.h 2 #ifndef _SUB_H_ 3 #define _SUB_H_ 4 int sub(int a, int b); 5 #endif

1 //add.cpp 2 #include "add.h" 3 int add(int a, int b){ 4 return a+b; 5 }

1 //add.h 2 #ifndef _ADD_H_ 3 #define _ADD_H_ 4 int add(int a, int b); 5 #endif
(4-1)先將cpp編譯成.o文件
g++ -c add.cpp
g++ -c sub.cpp 注意 動態和靜態鏈接都是由.o文件船艦
(4-2).o---->.a文件 ar cr libmymath.a sub.o add.o 這樣會生成libmymath.c文件如下圖所示
注意:庫文件規范一般就是以lib開頭 然后靜態庫名 .a后綴名
r:在庫中插入模塊
c:創建一個庫
(4-3)使用靜態庫
g++ -o main main.cpp -L -lmymath這樣生成main文件
(5)動態鏈接
(5-1)靜態鏈接是在編譯時期,那么動態可以推遲到運行時期。擴展名.so
(5-2)生成方法
g++ -fPIC -shared -o libmymath.so add.cpp sub.cpp
編譯參數解析:
-fPIC:編譯為位置獨立的代碼
-Lpath:path目錄搜索庫文件 -L便是當前目錄
-Ipath:表示path目錄中搜索文件
-ltest:編譯器查找動態鏈接庫時候有隱含的命名規則則名字前面lib 后綴.so
注意:運行的時候g++ -o main main.cpp -L. -lmymath鏈接正常但是執行會出錯。主要是找不到.so。因為程序運行
會在/usr/lib和/lib中找相應的動態庫文件。解決方法:將libmymath.so復制到目錄/user/lib中
(6)靜態鏈接和動態鏈接各自的特點
6-1:程序運行的時候,操作系統會看內存是否有庫函數的拷貝,有的話就不會鏈接載入,這樣節省勒內存資源。靜態庫則不同,每個程序都會將這個庫函數拷貝到自己的代碼段中,這樣就占用了內存資源。
6-2 用靜態庫,如果庫發生了變化,使用的庫需要重新編譯。動態庫則不會,提供的接口不會變化,只是重新用新生成的動態庫替換就ok
加油----->一天快結束了。。