makefile 配方特定变量和 $@ 评估

makefile recipe specific variables and $@ evaluation

我正在尝试设置一个包含调试和发布目标的生成文件。 有一些特定于目标的变量,主要是文件夹名称,在不同情况下设置正确,但不适用于 $@ 自动变量。以下代码:

SRC_DIR = src
OBJ_ROOT_DIR = obj
REL_DIR = release
DBG_DIR = debug
TGT_DIR = $(REL_DIR)
SRC_LIST = main.cc prime.cc
SRC_SUFF = cc
SRCS = $(patsubst %.cc, $(SRC_DIR)/%.$(SRC_SUFF), $(SRC_LIST))
OBJ_DIR = $(OBJ_ROOT_DIR)/$(TGT_DIR)
OBJS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(SRC_LIST))

all:                        $(OBJS)

release:                    all

debug:                      TGT_DIR = $(DBG_DIR)
debug:                      OBJ_DIR = $(OBJ_ROOT_DIR)/$(TGT_DIR)
debug:                      OBJS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(SRC_LIST))
debug:                      $(OBJS)

$(OBJS):$(OBJ_DIR)/%.o:     $(SRC_DIR)/%.$(SRC_SUFF)
                            @echo "TGT_DIR: $(TGT_DIR) OBJ_DIR: $(OBJ_DIR) OBJS: $(OBJS)"
                            @echo "Compiling $< to $@ ..."
                            @echo "... done !"
                            @echo "."

运行 make release 产生以下预期输出:

TGT_DIR: release OBJ_DIR: obj/release OBJS: obj/release/main.o obj/release/prime.o Compiling src/main.cc to obj/release/main.o ... ... done ! .

TGT_DIR: release OBJ_DIR: obj/release OBJS: obj/release/main.o obj/release/prime.o Compiling src/prime.cc to obj/release/prime.o ... ... done !

Wheras 使 调试导致 出现以下意外情况:

TGT_DIR: debug OBJ_DIR: obj/debug OBJS: obj/debug/main.o obj/debug/prime.o Compiling src/main.cc to obj/release/main.o ... ... done ! .

TGT_DIR: debug OBJ_DIR: obj/debug OBJS: obj/debug/main.o obj/debug/prime.o Compiling src/prime.cc to obj/release/prime.o ... ... done !

我想不通,为什么 $@ 在第二种情况下没有计算出所需的调试版本。虽然变量似乎设置正确。执行配方时如何获得正确的目录名称? 提前致谢!

你有很多选择/方法来做到这一点。

  1. 一种快速的方法是检查 MAKECMDGOALS 的内容(这些是 make 之后的词,例如发布或调试)。注意:可能不止一个 - 但如果您的 makefile 很简单并且只有一个,则以下将起作用:

例如:

ifneq ($(MAKECMDGOALS),debug)
  TGT_DIR = $(DBG_DIR)
  OBJ_DIR = $(OBJ_ROOT_DIR)/$(TGT_DIR)
  OBJS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(SRC_LIST))
endif
  1. 另一种选择是使用二次扩展,我只是想放一个link:secondary expansion

  2. 另一个选择是在你的规则中设置一些变量,然后导出它们并再次调用 make(递归),也许是这样的:

例如(不完整):

# Note you can just export the ones you want but... for ease of the example:
.EXPORT_ALL_VARIABLES

debug: TGT_DIR = $(DBG_DIR)
debug: OBJ_DIR = $(OBJ_ROOT_DIR)/$(TGT_DIR)
debug: OBJS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(SRC_LIST))
debug:
    $(MAKE) do_build

do_build: $(OBJS)

...etc...

在你第一次调用它的地方,在调试规则中设置一些变量。在第二个中,它直接调用 do_build 并且已经设置了变量。递归 make 通常不受欢迎 - 但我发现很多时候它是完成某些事情的最简单方法。

我可能会错误地选择选项 1。因为它很简单。有更多的方法可以做到这一点,但这在某种程度上取决于你想如何滚动——我只是设置了一些选项来保持你的 makefile 结构或多或少相同......