嵌入式工程師瑞士刀 (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可以額外觀察編譯器執行狀態
- 人人愛用的stdio.h放在/usr/include/stdio.h,剛好這樣就找得到
- 做相機的專案買了臉部辨識LIB。用 -I 指向header file root,這樣就能#include到了;或是做電動的公司,要吃微軟的DirectX函式庫。用-I指向header file root,找到定義
總結
編譯器選項非常多,會下面幾個日常就夠用了
- -c 編譯
- -E 前處理器輸出
- -o 輸出檔案
- -Dxxxx 定義xxx
- -I inclusion search path
加分題
閱讀gcc manual page,弄懂每個選項,就會變成團隊的編譯器專家了
留言