交叉編譯
使用不同的交叉編譯工具鏈編譯原始碼,能在不同框架的處理器上執行。
如:
- X86
gcc -o hello hello.c
上述命令編譯出來的檔案能在 X86 上執行,因為 gcc 編譯工具鏈是給PC編譯的。
- ARM
arm-linux-gnueabihf-gcc -o hello hello.c
上述命令編譯出來的檔案能在 ARM 上執行。
簡要知識點 **
- 標頭檔案的作用:
- 宣告(declare)
- c檔案的作用
- 定義、實現(define)
- 標頭檔案定址
- 預設路徑:編譯器中的 include 目錄
- 可指定:
#include "xx/xx.h"
:由當前檔案路徑算起- 編譯時用 "-I" 選項指定
- c檔案內的外部函式在哪裡,如 printf 函式:
- 庫:
- 預設路徑:編譯器中的 lib 目錄
- 可指定:
- 編譯時用 "-I" 指定庫檔案
- 編譯時用 "-L"指定庫目錄
- 庫:
- 怎麼確定交叉編譯器中標頭檔案的預設路徑?
- 進入交叉編譯器的目錄,使用find命令直接查詢,如
- 執行"find -name "stdio.h""
- 進入交叉編譯器的目錄,使用find命令直接查詢,如
- 怎麼確定交叉編譯器中庫的預設路徑?
- 進入交叉編譯器的目錄,執行"find -name lib",進去看看, 有很多 .so 檔案的裡面就是要找的路徑。
一些概念
- 交叉編譯工具鏈中的 include 目錄和lib 目錄:
- include 存放標頭檔案
- 這些標頭檔案一般是函式宣告,還有一些變數宣告,名字空間,巨集定義,typedef 等等
- lib 存放obj檔案的(對gcc來說為.o)
- 也就是說,一些庫檔案,人家不想讓你看見原始碼,只是給了你中間生成的obj檔案
- include 存放標頭檔案
GCC編譯器
PC機上的編譯工具鏈有 gcc、ld、objcopy、objdump等等,他們編譯出來的程式能在 X86 平臺上執行。
要使編譯出來的的程式能在 ARM 上執行,就必須使用交叉編譯工具鏈 xxx-gcc、xxx-ld等(不同版本的編譯器的字首不一樣,如 arm-linux-gcc)。
GCC簡要使用
GCC編譯過程 **
一個C/C++檔案要經過預處理、編譯、彙編、連結等4個步驟才能變成一個可執行檔案。(日常交流中用 編譯 統稱以上四大步驟)
- 預處理,在預處理過程中,對原始碼檔案中的檔案包含(include)、 預編譯語句(如巨集定義define等)進行展開,生成.i檔案。 可理解為把標頭檔案的程式碼、巨集之類的內容轉換成更純粹的C程式碼,不過生成的檔案以.i為字尾。
- 編譯,把預處理後的.i檔案通過編譯成為組合語言,生成.s檔案,即把程式碼從C語言轉換成組合語言,這是GCC編譯器完成的工作。
- 彙編,將組合語言檔案經過彙編,生成目標檔案.o檔案,每一個原始檔都對應一個目標檔案。即把組合語言的程式碼轉換成機器碼,這是as彙編器完成的工作。
- 連結,最後將每個原始檔對應的.o檔案連結起來,就生成一個可執行程式檔案,這是連結器ld完成的工作。
- 連結分為兩種
- 動態連結
- GCC編譯時的預設選項。
- 指應用程式執行時才去載入外部的程式碼庫。
- 靜態連結
- 連結時使用選項
–static
- 它在編譯階段就會把所有用到的庫打包到自己的可執行程式中。
- 連結時使用選項
- 動態連結
- 連結分為兩種
常用的編譯選項
選項 | 描述 |
---|---|
-E | 預處理,開發過程中想快速確定某個巨集可以使用 “-E -dM” |
-c | 做了預處理、編譯、彙編,但是沒做連結 |
-o | 指定輸出檔案 |
-I | 指定標頭檔案目錄(大寫 i) |
-l | 指定連結到哪一個庫檔案(小寫 L) |
-L | 指定連結時庫檔案目錄 |
編譯多個檔案
- 一起編譯、連結:
如:
gcc -o hello main.c hello.c
- 分開編譯,統一連結:
如:
gcc -c -o main.o main.c
gcc -c -o hello.o hello.c
gcc -o hello main.o hello.o
製作、使用動態庫
- 製作、編譯:
gcc -c -o main.o main.c
gcc -c -o hello.o hello.c
gcc -shared -o libhello.so hello.o hello1.o // (*可以使用多個 .o 生成一個動態庫*)
gcc -o hello main.o -lhello -L <目錄路徑> // (*該路徑為 libhello.so 檔案所在目錄*)
- 執行
- 把 libhello.so 放到PC或板子的/lib目錄下,然後執行test程式。
- 如果不想把 libhello.so 放到/lib, 也可以放到自己新建的某個目錄,如 /mylib,然後執行:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/a
./hello
(其實就是修改 庫的環境變數。)
製作、使用靜態庫
gcc -c -o main.o main.c
gcc -c -o hello.o hello.c
ar crs libhello.a hello.o hello1.o // (*可以使用多個 .o 生成一個靜態庫*)
gcc -o hello main.o libhello.a // (*如果 .a 不在當前目錄下,需要指定它的絕對路徑或相對路徑*)
注意:不需要把 hello.a 靜態庫檔案拉到板子上
很有用的選項
gcc -E main.c // 檢視預處理結果,比如標頭檔案是哪個
gcc -E -dM main.c > h.txt // 把所有的巨集展開,儲存到 h.txt 檔案裡
gcc -Wp,-MD,yl.dep -c -c -o main.o main.c // 生成依賴檔案 yl.dep,後面 Makefile 會用到
參考
- 韋東山
- 野火
- gcc-gun
- 建議:想看庫檔案原始碼時,如printf、malloc之類的,可以進入glibc的官網地址學習