文章總列表

嵌入式工程師瑞士刀 (3) 編譯器命令簡明解析,前處理器,定義,include搜尋路徑

緣起

我們團隊比Aerith妹妹還正的Tifa姊姊,有一次用編譯器指令,幫忙處理compile guard重名的問題!這篇總結一般查問題,需要和編譯打交道的命令


The problem

    #ifndef __SOME_HEADER_H__ // 這東西,跨檔案同名,會產生悲劇

    #define __SOME_HEADER_H__
    ...
    #endif


先找出建構指令

建構專案的指令稿會印出編譯指令,可以複製貼上到終端機單獨編譯某個檔案。清理build error一輪10秒。如果改壞這個功能,會有人氣噗噗。編譯命令看起來像這樣

    gcc -c hello.c -o hello.o

-c代表編譯,-o代表輸出檔案名稱,把hello.c編譯成hello.o。後者是object file,已經變成一堆指令了。一堆object透過連結器(linker)會變成執行檔,以後有空再寫

如果基礎設施不能產生編譯指令,也不能複製貼上執行,請拯救萬民於水火之中吧...


前處理器,C preprocessor

更細緻拆解編譯步驟:把-c改-E,挖掉-o讓輸出導向到檔案,觀察前處理器輸出

    gcc -E hello.c > hello_pre.c
    gcc -c hello_pre.c -o hello.o

下圖 b.c 紅框,因為沒有定義FUNC2,後續沒輸出。Tifa姊姊當時在header file塞奇怪的字串觀察前處理器輸出,很快就定位問題了。如果團隊用前處理器做些框架,前處理器輸出絕對是開發的好麻吉


從命令列塞定義(#define)

透過命令列塞定義#define很方便,下圖 -DFUNC2 等效 #define FUNC2,於是func2()跑出來了

這招用來管理"外界需求"很有效,切換平台,開關功能,選擇外部元件,都很適合

  • Switch platform
    • -DPLATFORM1
    • -DPLATFORM2
  • Switch feature
    • -DSOME_FEATURE_ENABLE
  • Switch component
    • -DEXT_COMPONENT1
    • -DEXT_COMPONENT2

Inclusion Search Path

另外軟體編譯時,可以用-I指定外部函式庫放哪裡,下圖多塞了-I/home當作範例。編譯選項-v可以額外觀察編譯器執行狀態

  1. 人人愛用的stdio.h放在/usr/include/stdio.h,剛好這樣就找得到

  2. 做相機的專案買了臉部辨識LIB。用 -I 指向header file root,這樣就能#include到了;或是做電動的公司,要吃微軟的DirectX函式庫。用-I指向header file root,找到定義


總結

編譯器選項非常多,會下面幾個日常就夠用了

  • -c 編譯
  • -E 前處理器輸出
  • -o 輸出檔案
  • -Dxxxx 定義xxx
  • -I inclusion search path


加分題

閱讀gcc manual page,弄懂每個選項,就會變成團隊的編譯器專家了


留言

這個網誌中的熱門文章

STM32 UART + DMA,使用HAL實作TX/RX,以及不定長度接收

幼犬書桌椅選擇心得 升降桌 兒童桌椅

CANON G3000 廢墨瓶改裝