使用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结果一致。

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