背景:
前端時間搞了個底板,用的是恩智浦的imx8平臺,安裝了Ubuntu系統,各種驅動安裝涉及linux開發,我這方面太弱勢,抱大腿學了點皮毛。想寫個功能demo,發現Makefile都不會,太悲劇。
用window開發透過ide不需要過多關注底層原理,基本都是ide給你自動生成連線關係。這次我得打破舒適區,拿下Makefile就從這次做起。
基礎知識:
GCC(GNU Compiler Collection,GNU編譯器套件),是由GNU開發的程式語言編譯器。它是以GPL許可證所發行的自由軟體,也是 GNU計劃的關鍵部分。我在linux下用的make命令就是去執行了gcc編譯編譯命令(unix下是cc,當然你也可以是其他編譯器的),當你輸入make指令的時候,它會自動查詢當前目錄下的Makefile或者makefile(注意大小寫,首字母大小寫都可以),然後執行裡面的內容。其實本質上Makefile就是個指令碼,透過make命令來執行它。但是這個指令碼真的很關鍵呀,兄弟們兒!它能告訴系統我這個檔案依賴哪些檔案,我要輸出的名字是什麼,標頭檔案去哪裡找,有沒有指定的庫,甚至於如何克服不同路徑帶來的安裝問題等等。我目前也就學了7788,也不敢亂說,不過就我現在的理解,它真的很強大,我後悔沒有早點搞明白這個東西,導致自己對底層的編譯過程一頭霧水。
學習過程:
我的學習過程很簡單,去網上找教程發現大多數都羅七八嗦的,太費時間了,我需要快速上手,所以就大概看了一下(5分鐘),然後就找了個阿里的sdk,看其中的Makefile檔案,把這個Makefile檔案看懂了,我至少能把用法學個大概,可以解決我現在的困難(自己寫工程的Makefile)。廢話不多說,下面是我今天整理出來的Makefile檔案加備註版本,一個字一個字摳出來的,有問題可以留言,咱們可以交流,向大家學習。
Q := @ #此種形式都是定義,給變數賦值,後面的值賦給前面的TOP_DIR := $(shell pwd) #pwd獲取當前目錄,然後賦值DEMOS_DIR := demosOUT_DIR := outputCC := gcc #定義編譯器,GCC(GNU Compiler Collection,GNU編譯器套件),是由GNU開發的程式語言編譯器。它是以GPL許可證所發行的自由軟體,也是 GNU計劃的關鍵部分。BLD_LDFLAGS := $(LDFLAGS) -lpthread #LDFLAGS可以用來link動態庫或者靜態庫的,用在gcc選項上,後面可以加-L指定庫目錄,加-l指定庫名稱,這裡的-lpthread,告訴編譯器去連線libpthread.so動態庫,如果gcc選項裡指定了-static,則代表連線靜態庫。SRC_DIR := $(shell find . -type d \( ! -name demos \)) #這裡的d型別是目錄(directory),但是刪去了demos這個目錄HDR_DIR := $(SRC_DIR)BLD_CFLAGS += $(addprefix -I,$(HDR_DIR))#這裡給HDR_DIR加了一個-I字首,然後再新增到BLD_LDFLAGS的後面,用在gcc選項上,作用是指定標頭檔案目錄SRC_FILES := $(shell find $(SRC_DIR) -not -path "*/demos/*.c" -name "*.c")#這裡是按照SRC_DIR中的路徑去搜索名字中帶.c的檔案,但是要去掉SRC_DIR中帶*/demos/*.c條目OBJ_FILES := $(SRC_FILES:.c=.o)#把SRC_FILES中的.c換成.o,然後賦值給OBJ_FILESOBJ_FILES := $(addprefix $(OUT_DIR)/,$(OBJ_FILES))#在OBJ_FILES中加output/字首PROG_TARGET := $(subst _,-,$(patsubst %.c,%,$(wildcard demos/*_demo.c)))#wildcard以demos/*_demo.c為模板輸出,*代表任意,patsubst是篩選替換,把第一次的輸出中包含.c結尾的去掉.c,subst是替換,把第二次輸出條目中的_替換為-all: prepare $(PROG_TARGET) #all是目標,它依賴於:後面的兩個專案,這兩個專案在下面都做了定義prepare: $(Q)mkdir -p output #prepare沒有依賴,它的內容是依次建立output目錄$(PROG_TARGET): $(OBJ_FILES) #PROG_TARGET的依賴是OBJ_FILES,上文都有定義 $(Q)echo "+ Linking $(OUT_DIR)/$(notdir $@) ..."#echo是列印輸出提示資訊或者結果,這裡輸出編譯最終的檔案,其中$@代表目標(aim),也就是PROG_TARGET $(Q)mkdir -p $(dir $@)#這裡是建立路徑,也就是demos $(Q)$(CC) -o $@ \ #編譯命令,後面是編譯引數,-o代表指定輸出的名字,名字包括$@和後面的patsubst生成的.o檔案 $(patsubst $(OUT_DIR)/%,%,$(addsuffix .c,$(subst $(notdir $@),$(subst -,_,$(notdir $@)),$@))) \#上面這句中addsuffix第二個引數其實就把-換回了_,addsuffix加了.c的尾綴,patsubst是去掉(OUT_DIR)/ $(BLD_CFLAGS) $^ $(BLD_LDFLAGS)#上面這句加了標頭檔案,依賴,最後還添加了連結庫 $(Q)mv $@ $(OUT_DIR)#上面這句是移動輸出檔案到output資料夾裡#下面的這個定義並沒有執行,因為Makefile檔案中多個gcc命令的時候,只執行第一個。$(OUT_DIR)/%.o: %.c $(Q)echo ": Compiling $< ..." $(Q)mkdir -p $(OUT_DIR)/$(dir $<) $(Q)$(CC) -o $@ -c $< $(BLD_CFLAGS)#下面的clean可以透過make clean執行,清理生成的檔案clean: $(Q)rm -rf $(OUT_DIR)
為了看懂上面的Makefile,我看了好多部落格,有幾個比較詳細推薦的,可以給大家參考一下:
linux程式設計入門(六)-編寫Makefile檔案 :https://www.jianshu.com/p/442e71755643
Makefile選項CFLAGS,LDFLAGS,LIBS:https://www.cnblogs.com/fire909090/p/11160219.html
一文入門makefile:https://zhuanlan.zhihu.com/p/56489231
以上,等等,感謝網友們的無私奉獻!