在下面的Makefile中,我根据目标规则是否为“ test”来修改$(SRC)的内容。该规则应该用于单元测试。
我的对象是使用隐式规则构建的
OBJ = $(SRC:.cpp=.o)
但是在构建对象时,即使SRC变量发生更改,它也始终使用其默认值。这是Makefile:
CC = g++
SRC_DIR = src
SRC_TEST_DIR = tests/src
INC_DIR = include/
test: INC_DIR += tests/include/
SRC_MAIN = $(SRC_DIR)/main.cpp
test: SRC_MAIN = $(SRC_TEST_DIR)/main.cpp
SRC = $(SRC_MAIN) \ # <=== The value that changes in SRC
$(SRC_DIR)/minicalc.cpp \
$(SRC_DIR)/io.cpp
OBJ = $(SRC:.cpp=.o)
CPPFLAGS += -I$(INC_DIR) -g -Wall -Wextra
test: LDFLAGS += -lcppunit
OUT = minicalc
test: OUT = tests/tests
all: $(OBJ)
# DEBUG :
@echo SRC: '$(SRC)'
@echo OBJ: '$(OBJ)'
$(CC) $(OBJ) -o $(OUT) $(LDFLAGS)
test: all
ls $(OUT) && ./$(OUT)
以下是输出:
make
使用默认值SRC给出预期输出:
g++ -Iinclude/ -g -Wall -Wextra -c -o src/main.o src/main.cpp
g++ -Iinclude/ -g -Wall -Wextra -c -o src/minicalc.o src/minicalc.cpp
g++ -Iinclude/ -g -Wall -Wextra -c -o src/io.o src/io.cpp
SRC: src/main.cpp src/minicalc.cpp src/io.cpp
OBJ src/main.o src/minicalc.o src/io.o
g++ src/main.o src/minicalc.o src/io.o -o minicalc
但是make test
即使在SRC中也不会生成test / src / main.o:
g++ -Iinclude/ -g -Wall -Wextra -c -o src/main.o src/main.cpp
g++ -Iinclude/ -g -Wall -Wextra -c -o src/minicalc.o src/minicalc.cpp
g++ -Iinclude/ -g -Wall -Wextra -c -o src/io.o src/io.cpp
SRC: tests/src/main.cpp src/minicalc.cpp src/io.cpp
OBJ: tests/src/main.o src/minicalc.o src/io.o
g++ tests/src/main.o src/minicalc.o src/io.o -o tests/tests -lcppunit
g++: error: tests/src/main.o: No such file or directory
make: *** [Makefile:41: all] Error 1
all
需要$(OBJ)
,但是创建的对象与$(SRC)
变量的内容不对应
不通过手动操作来使用隐式.cpp.o规则:
相同的Makefile,但用规则$(OBJ)
代替了create_obj
CC = g++
SRC_DIR = src
SRC_TEST_DIR = tests/src
INC_DIR = include/
test: INC_DIR += tests/include/
SRC_MAIN = $(SRC_DIR)/main.cpp
test: SRC_MAIN = $(SRC_TEST_DIR)/main.cpp
SRC = $(SRC_MAIN) \
$(SRC_DIR)/minicalc.cpp \
$(SRC_DIR)/io.cpp
OBJ = $(SRC:.cpp=.o)
CPPFLAGS += -I$(INC_DIR) -g -Wall -Wextra
test: LDFLAGS += -lcppunit
OUT = minicalc
test: OUT = tests/tests
all: create_obj
# DEBUG :
@echo SRC: '$(SRC)'
@echo obj: '$(OBJ)'
$(CC) $(OBJ) -o $(OUT) $(LDFLAGS)
create_obj:
@echo Crafting Files:
@$(foreach file, $(SRC), \
echo $(file),; \
$(CC) -c $(file) -o $(file:.cpp=.o) $(CPPFLAGS) $(LDFLAGS); \
)
test: all
ls $(OUT) && ./$(OUT)
以下是输出:
make
:
Crafting Files:
src/main.cpp,
src/minicalc.cpp,
src/io.cpp,
SRC: src/main.cpp src/minicalc.cpp src/io.cpp
OBJ: src/main.o src/minicalc.o src/io.o
g++ src/main.o src/minicalc.o src/io.o -o minicalc
make test
Crafting Files:
tests/src/main.cpp,
src/minicalc.cpp,
src/io.cpp,
SRC: tests/src/main.cpp src/minicalc.cpp src/io.cpp
OBJ tests/src/main.o src/minicalc.o src/io.o
g++ tests/src/main.o src/minicalc.o src/io.o -o tests/tests -lcppunit
ls tests/tests && ./tests/tests
tests/tests
OK (0)
为什么更改源时却不更改对象的隐式构建,而手动执行却可以?
答案 0 :(得分:1)
为了使make最初找到所有dep关系,它必须在初始扫描中将vars扩展到此时的任何状态。因此,all : $(OBJ)
是用全局值评估的,而不是在test : all
的上下文中重新评估的。抱歉。 Make的惰性评估在与上下文相关的var分配中不能很好地发挥作用。
答案 1 :(得分:1)
冒着过度杀伤的危险,这就是我写的方式。 个人准则:
%.o: %.cpp; ...
),直到被迫不这样做为止。make -C${PLATFORM}/${CONFIG} ...
all : minicalc ;@: # ... or ".PHONY: all" test : mctests ; ls $^ && ./$^ minicalc : minicalc.o io.o main.o # minicalc.o is subtly redundant here. mctests : minicalc.o io.o mctests.o # ... likewise mctests.o is redundant. mctests.o : tests/src/main.cpp # Name difference forces an explicit action below. vpath %.cpp src CC = ${CXX} # Roundabout fix for MAKE using ${CC} for linking # ... but cc/gcc cannot handle C++ object files. CXXFLAGS += -Iinclude -g -Wall -Wextra mctests.o : CXXFLAGS += -Itests/include mctests : LDLIBS += -lcpptest # More accurately LDLIBS not LDFLAGS mctests.o :; ${COMPILE.cpp} -o $@ $^