Makefile变量行为异常

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

在下面的Makefile中,我将根据目标规则是否为“test”修改$(SRC)的内容。此规则应用于单元测试。
我的对象是使用隐式规则构建的
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}…
全部:minicalc;@:#。。。或“虚假:全部” 测试:MCT测试;ls$^&&/$^ minicalc:minicalc.o io.o main.o#minicalc.o在这里有微妙的冗余。 mctests:minicalc.o io.o mctests.o#。。。同样,mctests.o也是冗余的。 o:tests/src/main.cpp#名称差异强制执行下面的显式操作。 vpath%.cpp src CC=${CXX}#使用${CC}链接的MAKE环形交叉口修复 # ... 但是cc/gcc不能处理C++对象文件。 CXXFLAGS+=-Iinclude-g-Wall-Wextra mctests.o:cxflags+=-Itests/include mctests:LDLIBS+=-lcpptest#更准确地说,LDLIBS不是LDFLAGS mctests.o:${COMPILE.cpp}-o$@$^
冒着过度杀戮的风险,我会这样写。 个人指引:

  • 少用vars。它们有一个位置,但往往会降低文件的可读性
  • 依赖隐式规则/操作(例如,
    %.o:%.cpp;…
    ),直到强制不这样做
  • 依赖于目标的var设置仅适用于操作中使用的var
  • MAKE确实希望在cwd中构建目标文件和中间文件。 任何其他方案的弯头都是由接头制成的。这就是为什么您会看到这样的脚本:
    make-C${PLATFORM}/${CONFIG}…
全部:minicalc;@:#。。。或“虚假:全部” 测试:MCT测试;ls$^&&/$^ minicalc:minicalc.o io.o main.o#minicalc.o在这里有微妙的冗余。 mctests:minicalc.o io.o mctests.o#。。。同样,mctests.o也是冗余的。 o:tests/src/main.cpp#名称差异强制执行下面的显式操作。 vpath%.cpp src CC=${CXX}#使用${CC}链接的MAKE环形交叉口修复 # ... 但是cc/gcc不能处理C++对象文件。 CXXFLAGS+=-Iinclude-g-Wall-Wextra mctests.o:cxflags+=-Itests/include mctests:LDLIBS+=-lcpptest#更准确地说,LDLIBS不是LDFLAGS mctests.o:${COMPILE.cpp}-o$@$^
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 $@ $^