使用Makefile編譯帶源碼路徑的工程

昨天編譯一個工程,Makefile放在工程目錄,.cpp文件放在/source目錄下,頭文件.h放在/include目錄下。遇到了幾個問題,一番修改,終於改好,整理如下:

出問題的Makefile如下:

INC = -I./include
CFLAGS := -O0 -g $(INC)

SOURCE = $(wildcard ./source/*.cpp)
CPPFILES = $(notdir $(SOURCE))
OBJ = $(patsubst %.cpp, %.o, $(CPPFILES))
EXE = main

$(EXE):$(OBJ)
        g++ -std=c++11 -o $@ $^

%.o:%.cpp
        g++ -std=c++11 -o $@ -c  $^ -I. $(CFLAGS)

.PHONY:clean
clean:
        -rm $(EXE) *.o

編譯結果:

make: *** No rule to make target `func1.o', needed by `main'. Stop.

無法生成目標文件main.o,是因爲編譯器找不到源文件,因爲編譯器默認是在當前目錄下尋找源文件。但我們在Makefile中,通過notdir函數將源文件的目錄清除掉了。在以上Makefile中“EXE = main”後面加個打印:

PRINT:
        @echo "CPPFILES:"
        @echo $(CPPFILES)

然後執行make或make PRINT,得到結果如下圖所示,可見用於編譯的源文件都是不帶路徑的。

解決方法1 保留源碼路徑

既然上面一小節的錯誤是由於編譯器找不到源碼路徑,那如果我們把源碼路徑保留下來呢?看下面這個Makefile:

INC = -I./include
CFLAGS := -O0 -g $(INC)

SOURCE = $(wildcard ./source/*.cpp)
#CPPFILES = $(notdir $(SOURCE))
#OBJ = $(patsubst %.cpp, %.o, $(CPPFILES))
OBJ = $(patsubst %.cpp, %.o, $(SOURCE))
EXE = main

#PRINT:
#       @echo "CPPFILES:"
#       @echo $(CPPFILES)

$(EXE):$(OBJ)
        g++ -std=c++11 -o $@ $^

%.o:%.cpp
        g++ -std=c++11 -o $@ -c  $^ -I. $(CFLAGS)

.PHONY:clean
clean:
        -rm $(EXE) *.o                     

執行make,結果如下:

編譯成功,各cpp文件對應的.o文件都放在了源碼路徑下,最終的可執行文件放在當前路徑。

解決方法2 使用VPATH

方法1中保留了源碼路徑,那麼如果希望編譯出來的.o文件也放在當前路徑下怎麼辦?仍然是要去掉源碼路徑,那麼這時候編譯器去哪裏找源碼呢?這時候可以考慮用VPATH。VPATH用於設置全局訪問路徑。make可識別一個特殊變量“VPATH”,通過"VPATH"可以指定依賴文件的搜索路徑。變量“VPATH”的定義中,使用空格或者冒號“:”將多個目錄分開,例如 VPATH = include:source。make搜索目錄的順序爲:當前目錄、VPATH中定義的目錄順序。

Makefile如下:

VPATH = ./source

INC = -I./include
CFLAGS := -O0 -g $(INC)

SOURCE = $(wildcard ./source/*.cpp)
CPPFILES = $(notdir $(SOURCE))
OBJ = $(patsubst %.cpp, %.o, $(CPPFILES))
#OBJ = $(patsubst %.cpp, %.o, $(SOURCE))
EXE = main

#PRINT:
#       @echo "CPPFILES:"
#       @echo $(CPPFILES)

$(EXE):$(OBJ)
        g++ -std=c++11 -o $@ $^

%.o:%.cpp
        g++ -std=c++11 -o $@ -c $^ $(CFLAGS)

.PHONY:clean
clean:
        -rm $(EXE) *.o

執行make,結果如下:

並且,編譯生成的.o文件也都生成在了當前目錄下:

解決方法3 使用vpath

vpath比VPATH更爲靈活,它可以爲不同類型的文件指定不同的搜索目錄。使用方法:
vpath PATTERN DIRECTORIES
爲符合"PATTERN"的文件指定搜索路徑“DIRECTORIES”,多個路徑可以使用空格或者冒號":"分開。
如 vpath %.c src1 src2  或 vpath %.h inc1:inc2

使用vpath的Makefile文件如下:

vpath %.cpp ./source

INC = -I./include
CFLAGS := -O0 -g $(INC)

SOURCE = $(wildcard ./source/*.cpp)
CPPFILES = $(notdir $(SOURCE))
OBJ = $(patsubst %.cpp, %.o, $(CPPFILES))
#OBJ = $(patsubst %.cpp, %.o, $(SOURCE))
EXE = main

#PRINT:
#       @echo "CPPFILES:"
#       @echo $(CPPFILES)

$(EXE):$(OBJ)
        g++ -std=c++11 -o $@ $^

%.o:%.cpp
        g++ -std=c++11 -o $@ -c $^ $(CFLAGS)

.PHONY:clean
clean:
        -rm $(EXE) *.o

編譯結果與VPATH結果一致。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章