我有一些像这样的规则
foo_%: $(BIN_DIR) $(LIB_DIR) $(OBJ_DIR)
gcc stuff
目录变量如下:
BIN_DIR := $(BUILD_DIR)/$@/$(TARGET)/bin
制定目录的规则:
$(BIN_DIR) $(LIB_DIR) $(OBJ_DIR):
mkdir -p $@
我希望(扩展的)foo_%
部分替换目录名称中的$@
,但现在$@
将被替换为任何内容。
现在我可以在BIN_DIR var中用$@
替换%
:
BIN_DIR := $(BUILD_DIR)/%/$(TARGET)/bin
但是这省略了我想要包含的foo_
部分。
最后的方法是在每条规则中包含三个mkdir -p
语句,但我不愿意!
答案 0 :(得分:1)
扩展无法工作,因为在处理语法时会扩展规则中的先决条件和目标列表。换句话说,静态地,在编译时" makefile规则。而$@
参数是动态的;当评估规则树时,它会在makefile"运行时"中获取值。那时,它不能代替目标和先决条件。
由于这只是为了确保某些目录存在,您可以将make -p
移动到配方中,并像这样执行。请注意,我们仍需将BIN_DIR :=
分配更改为非展开式BIN_DIR =
分配:
TARGET := target
LIB_DIR := lib_dir
OBJ_DIR := obj_dir
BUILD_DIR := build_dir
BIN_DIR = $(BUILD_DIR)/$@/$(TARGET)/bin
foo: | $(LIB_DIR) $(OBJ_DIR) # see text below for explanation of | symbol
mkdir -p $(BIN_DIR)
echo other steps
$(LIB_DIR) $(OBJ_DIR):
mkdir -p $@
在这里,我们使用制作规则处理来创建$(LIB_DIR)
和$(OBJ_DIR)
。但$(BIN_DIR)
只是通过在食谱中运行mkdir -p
来以行人方式处理。 $@
的扩展在这里起作用,因为BIN_DIR
是一个传统的未展开式make变量,当它被替换时会经历扩展。在处理规则语法时,它仍然是静态扩展的,但重点是它保留了插入$@
配方行的未展开make -p
。因为$@
在配方行中,所以它有效。它只是在目标或先决条件列表中不起作用。
我使用|
符号将$(LIB_DIR)
$(OBJ_DIR)
指定为仅限订单的先决条件。 Read about this in the GNU Make manual。仅订单的先决条件仅在缺少时才会更新。如果它们已经存在,则会被忽视。
如果我们不允许这些目录仅按顺序排列,那么每当它们的时间戳发生变化时,它们就会触发重建目标,使其比目标更新。
最好不要将目录命名为先决条件,只需将恰当的mkdir -p
放入配方即可。就像在,简单地说:
TARGET := target
LIB_DIR := lib_dir
OBJ_DIR := obj_dir
BUILD_DIR := build_dir
BIN_DIR = $(BUILD_DIR)/$@/$(TARGET)/bin
foo:
mkdir -p $(LIB_DIR) $(OBJ_DIR) $(BIN_DIR)
echo other step
执行命令
$ make mkdir -p lib_dir obj_dir build_dir/foo/target/bin echo other steps other steps