linux-gcc簡要知識點 **

李柱明發表於2020-11-09


交叉編譯

使用不同的交叉編譯工具鏈編譯原始碼,能在不同框架的處理器上執行。
如:

  • X86
gcc -o hello hello.c

上述命令編譯出來的檔案能在 X86 上執行,因為 gcc 編譯工具鏈是給PC編譯的。

  • ARM
arm-linux-gnueabihf-gcc -o hello hello.c

上述命令編譯出來的檔案能在 ARM 上執行。

簡要知識點 **

  1. 標頭檔案的作用:
    1. 宣告(declare)
  2. c檔案的作用
    1. 定義、實現(define)
  3. 標頭檔案定址
    1. 預設路徑:編譯器中的 include 目錄
    2. 可指定:
      1. #include "xx/xx.h" :由當前檔案路徑算起
      2. 編譯時用 "-I" 選項指定
  4. c檔案內的外部函式在哪裡,如 printf 函式:
    1. 庫:
      1. 預設路徑:編譯器中的 lib 目錄
      2. 可指定:
        1. 編譯時用 "-I" 指定庫檔案
        2. 編譯時用 "-L"指定庫目錄
  5. 怎麼確定交叉編譯器中標頭檔案的預設路徑?
    1. 進入交叉編譯器的目錄,使用find命令直接查詢,如
      • 執行"find -name "stdio.h""
  6. 怎麼確定交叉編譯器中庫的預設路徑?
    1. 進入交叉編譯器的目錄,執行"find -name lib",進去看看, 有很多 .so 檔案的裡面就是要找的路徑。

一些概念

  1. 交叉編譯工具鏈中的 include 目錄和lib 目錄:
    1. include 存放標頭檔案
      1. 這些標頭檔案一般是函式宣告,還有一些變數宣告,名字空間,巨集定義,typedef 等等
    2. lib 存放obj檔案的(對gcc來說為.o)
      1. 也就是說,一些庫檔案,人家不想讓你看見原始碼,只是給了你中間生成的obj檔案

GCC編譯器

 PC機上的編譯工具鏈有 gcc、ld、objcopy、objdump等等,他們編譯出來的程式能在 X86 平臺上執行。
 要使編譯出來的的程式能在 ARM 上執行,就必須使用交叉編譯工具鏈 xxx-gcc、xxx-ld等(不同版本的編譯器的字首不一樣,如 arm-linux-gcc)。

GCC簡要使用

GCC編譯過程 **

 一個C/C++檔案要經過預處理、編譯、彙編、連結等4個步驟才能變成一個可執行檔案。(日常交流中用 編譯 統稱以上四大步驟

  1. 預處理,在預處理過程中,對原始碼檔案中的檔案包含(include)、 預編譯語句(如巨集定義define等)進行展開,生成.i檔案。 可理解為把標頭檔案的程式碼、巨集之類的內容轉換成更純粹的C程式碼,不過生成的檔案以.i為字尾。
  2. 編譯,把預處理後的.i檔案通過編譯成為組合語言,生成.s檔案,即把程式碼從C語言轉換成組合語言,這是GCC編譯器完成的工作。
  3. 彙編,將組合語言檔案經過彙編,生成目標檔案.o檔案,每一個原始檔都對應一個目標檔案。即把組合語言的程式碼轉換成機器碼,這是as彙編器完成的工作。
  4. 連結,最後將每個原始檔對應的.o檔案連結起來,就生成一個可執行程式檔案,這是連結器ld完成的工作。
    • 連結分為兩種
      • 動態連結
        • GCC編譯時的預設選項。
        • 指應用程式執行時才去載入外部的程式碼庫。
      • 靜態連結
        • 連結時使用選項 –static
        • 它在編譯階段就會把所有用到的庫打包到自己的可執行程式中。

常用的編譯選項

選項 描述
-E 預處理,開發過程中想快速確定某個巨集可以使用 “-E -dM”
-c 做了預處理、編譯、彙編,但是沒做連結
-o 指定輸出檔案
-I 指定標頭檔案目錄(大寫 i)
-l 指定連結到哪一個庫檔案(小寫 L)
-L 指定連結時庫檔案目錄

編譯多個檔案

  1. 一起編譯、連結:
    如:
gcc -o hello main.c hello.c
  1. 分開編譯,統一連結:
    如:
gcc -c -o main.o main.c
gcc -c -o hello.o hello.c
gcc -o hello main.o hello.o

製作、使用動態庫

  1. 製作、編譯:
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 檔案所在目錄*)
  1. 執行
    1. libhello.so 放到PC或板子的/lib目錄下,然後執行test程式。
    2. 如果不想把 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 會用到

參考