![Makefile 编译未更改的文件](https://linux22.com/image/23813/Makefile%20%E7%BC%96%E8%AF%91%E6%9C%AA%E6%9B%B4%E6%94%B9%E7%9A%84%E6%96%87%E4%BB%B6.png)
努力获取另一个目录中的目标文件,但该目录否则会反映源目录树。可以正常工作,但是该行缺少一块$(OBJ):
(对吗?),因此无论您是否更改源代码,它都会重新编译。看一看。
SRC_PATH=../src/
CC=g++
CFLAGS=-c -Wall
LDFLAGS=-lSDL -lSDL_gfx
INCL=-I $(SRC_PATH)include/
EXE=run
SRC=$(wildcard $(SRC_PATH)*.cpp $(SRC_PATH)game/*.cpp $(SRC_PATH)player/*.cpp)
OBJ=$(subst ../src, ../obj, $(SRC:.cpp=))
OBJ_O=$(addsuffix .o, $(OBJ))
all: $(SRC) $(EXE)
$(EXE): $(OBJ)
$(CC) $(LDFLAGS) $(OBJ_O) -o $@
$(OBJ):
$(CC) $(CFLAGS) $(INCL) -o $(addsuffix .o, $@) $(subst ../obj, ../src, $@).cpp
clean:
rm -rf run $(OBJ_O)
编辑
这按预期工作:不重新编译。而且,没有来回复杂的后缀,更容易阅读。请参阅下面的答案和评论。
SRC_PATH=../src/
CC=g++
CFLAGS=-c -Wall
LDFLAGS=-lSDL -lSDL_gfx
INCL=-I $(SRC_PATH)include/
EXE=run
SRC=$(wildcard $(SRC_PATH)*.cpp $(SRC_PATH)game/*.cpp $(SRC_PATH)player/*.cpp)
OBJ=$(subst ../src, ../obj, $(SRC:.cpp=.o))
all: $(SRC) $(EXE)
$(EXE): $(OBJ)
$(CC) $(LDFLAGS) $(OBJ) -o $@
../obj/%.o: ../src/%.cpp
$(CC) $(CFLAGS) $(INCL) -o $@ $<
clean:
rm -rf run $(OBJ)
答案1
有几个问题:
首先,您的 OBJ 变量并不引用已构建的文件列表。例如,当您有源文件 src/a.cpp 和 src/b.cpp 时,OBJ 将包含 obj/a 和 obj/b。所以使用OBJ_O而不是OBJ。
其次,构建 OBJ 文件的目标不会给出 .cpp 和 .o 文件之间的依赖关系。以这种方式编写创建 .o 文件的规则是一个问题,因为您无法在该行中提供依赖项信息。我将完全重写创建 .o 文件的规则:
../obj/%.o: ../src/%.cpp
$(CC) $(CFLAGS) $(INCL) -o "$@" "$<"
这会单独构建每个 .o 文件,并且每个 .o 文件都依赖于相应的 .cpp 文件。
../obj/**.o
这是从每个匹配的文件创建文件的规则../src/**.cpp
。
答案2
为了更清楚地说明:
主要问题正是线路$(OBJ):
问题是,如果../src/a.cpp
变量OBJ
包含源文件../obj/a
,并且规则$(OBJ):
意味着“使用以下配方来构建文件../obj/a
”。但这不是recipie所做的! (相反,它创建一个文件../obj/a.o
。)
这就是为什么 make 将始终执行该 recipie,因为它迫切需要创建该文件,../obj/a
因为该文件名被列为依赖项$(EXE): $(OBJ)