代码之家  ›  专栏  ›  技术社区  ›  Yanis.F

Makefile变量行为

  •  0
  • Yanis.F  · 技术社区  · 8 年前

    在下面的Makefile中,我将根据目标规则是否为“test”修改$(SRC)的内容。这个规则应该用于单元测试。
    我的对象是用隐式规则构建的
    OBJ = $(SRC:.cpp=.o)

    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 不生成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_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)
    

    以下是输出 :
    制作

    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)
    

    2 回复  |  直到 8 年前
        1
  •  1
  •   Mischa    8 年前

    为了让make最初找到所有dep关系,它必须在初始扫描中展开vars,无论它们处于什么状态。所以呢 all : $(OBJ) 使用全局值进行评估,而不是在 test : all . 对不起的。Make的lazy eval不能很好地处理上下文相关的var赋值。

        2
  •  1
  •   Mischa    8 年前

    冒着过度杀戮的风险,我会这样写的。 个人准则:

    • 少用vars。他们有一个地方,但倾向于制作文件 可读。
    • 依赖隐含的规则/行动(例如。 %.o: %.cpp; ...
    • 与目标相关的变量设置仅适用于操作中使用的变量。
    • 制造 真正地 希望在cwd中构建目标和中间文件。 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 $@ $^