Makefile变量行为异常
在下面的Makefile中,我将根据目标规则是否为“test”修改$(SRC)的内容。此规则应用于单元测试。Makefile变量行为异常,makefile,Makefile,在下面的Makefile中,我将根据目标规则是否为“test”修改$(SRC)的内容。此规则应用于单元测试。 我的对象是使用隐式规则构建的 OBJ=$(SRC:.cpp=.o) 但在构建对象时,即使SRC变量发生更改,它也始终使用其默认值。以下是生成文件: CC = g++ SRC_DIR = src SRC_TEST_DIR = tests/src INC_DIR = include/ test: INC_DIR += te
我的对象是使用隐式规则构建的
OBJ=$(SRC:.cpp=.o)
但在构建对象时,即使SRC变量发生更改,它也始终使用其默认值。以下是生成文件:
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)
但是,maketest
不会构建test/src/main.o,即使它在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: 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,但被规则
create\u OBJ
以下是输出结果: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
进行测试
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)
为什么我的对象的隐式构建在更改我的源时不发生更改,而手动执行此操作?为了使make最初能够找到所有dep关系,它必须在初始扫描中以VAR处于的任何状态展开VAR。因此,
all:$(OBJ)
使用全局值进行评估,而不是在test:all
的上下文中重新评估。很抱歉Make的lazy eval不能很好地处理上下文相关的var分配。为了让Make最初找到所有dep关系,它必须在初始扫描中以var处于的任何状态展开var。因此,all:$(OBJ)
使用全局值进行评估,而不是在test:all
的上下文中重新评估。很抱歉Make的lazy eval不能很好地处理上下文相关的var赋值。冒着过度杀伤力的风险,下面是我应该如何编写它的。
个人指引:
- 少用vars。它们有一个位置,但往往会降低文件的可读性
- 依赖隐式规则/操作(例如,
),直到强制不这样做%.o:%.cpp;…
- 依赖于目标的var设置仅适用于操作中使用的var
- MAKE确实希望在cwd中构建目标文件和中间文件。
任何其他方案的弯头都是由接头制成的。这就是为什么您会看到这样的脚本:
make-C${PLATFORM}/${CONFIG}…
冒着过度杀戮的风险,我会这样写。 个人指引:
- 少用vars。它们有一个位置,但往往会降低文件的可读性
- 依赖隐式规则/操作(例如,
),直到强制不这样做%.o:%.cpp;…
- 依赖于目标的var设置仅适用于操作中使用的var
- MAKE确实希望在cwd中构建目标文件和中间文件。
任何其他方案的弯头都是由接头制成的。这就是为什么您会看到这样的脚本:
make-C${PLATFORM}/${CONFIG}…
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
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)
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 $@ $^