Makefile中用foreach,eval,call實現將目標文件編譯到指定目錄

博主要建立一個工程目錄,但願將全部的.c文件都編譯成.o並存放到out/目錄下。以下:shell

.
├── d1
│   ├── aa.c
│   └── dd.c
├── main.c
├── Makefile
└── out

通過一夜的嘗試,最終使用了foreach函數實現了這個目標:數組

TARGET=test
ALL_SOURCES=$(shell find -name "*.c")

SOURCE_TO_OBJECT = ./out/$(subst .c,.o,$(notdir $(1)))
ALL_OBJECTS=$(foreach src,$(ALL_SOURCES),$(call SOURCE_TO_OBJECT,$(src)))

define CREATE_OBJECT_TARGET
$(call SOURCE_TO_OBJECT,$(1)) : $(1)
	gcc -c -o $$@ $$^
endef

all: $(TARGET)

clean:
	-rm $(ALL_OBJECTS)
	-rm $(TARGET)

$(TARGET):$(ALL_OBJECTS)
	gcc -o $@ $^

$(foreach src,$(ALL_SOURCES),$(eval $(call CREATE_OBJECT_TARGET,$(src))))

大概思路是這樣的:
首先,ALL_SOURCES=$(shell find -name "*.c"),我將當前目錄下的全部.c文件找到並賦值給ALL_SOURCE變量。
而後,ALL_OBJECTS=$(foreach src,$(ALL_SOURCES),$(call SOURCE_TO_OBJECT,$(src))),對每一個一ALL_SOURCE中的源文件進行處理,將每一個文件名去除路徑,並將後綴.c替換成.o,再加上./out前綴就成了目標文件名。注意:函數調用中不能隨意地加空格!!
SOURCE_TO_OBJECT是一個將源文件名轉換成目標文件名的函數。上面用$(call ...) 對它進行調用。函數

而後,我想爲每一個目標文件創建依賴關係,以下:code

./obj/main.o : main.c
    gcc -c -o $@ $^

./obj/aa.o : d1/aa.c
    gcc -c -o $@ $^

./obj/bb.o : d1/bb.c
    gcc -c -o $@ $^

文件個數少還好說,若是工程大了,上百個文件維護起來很吃力。因而想到要用 $(foreach ...) 函數來實現。建立這麼一個函數,用於生成目標與文件依賴關係:ip

define CREATE_OBJECT_TARGET
$(call SOURCE_TO_OBJECT,$(1)) : $(1)
	gcc -c -o $$@ $$^
endef

轉入的一個參數$(1)是源文件全路徑。
注意:其中的 gcc -c -o $$@ $$^,是雙 $ 符號。字符串

再用以下的$(foreach ...)函數達到對每個源文件都創建一個目標的目的:
$(foreach src,$(ALL_SOURCES),$(eval $(call CREATE_OBJECT_TARGET,$(src))))編譯

其中用到的命令有:test

  • notdir,從全路徑的文件名,提取出文件名稱。至關於shell的basename
  • subst,字符串替換
  • foreach,對數組中的每個元數作處理
  • call,調用自定義宏
  • eval,將字串應用到Makefile上下文
  • shell,執行shell腳本

其它經常使用的函數還有:變量

  • dir
  • addprefix
  • patsubst
  • strip
  • sort
  • wildcard

若是你們還有別的什麼更好的方法,歡迎留言。gcc

相關文章
相關標籤/搜索