如果目标名称有目录部分,则生成一个目录
Generate a directory if a target name has a directory part
我有这个 makefile 代码:
$(DIRS):
@echo " MKDIR build/tmp/base/socket/$@"
$(Q)mkdir -p $@/
%.a.s:
@echo " CC build/tmp/base/socket/$@"
$(Q)$(CC) $(CFLAGS_A) -S $< -o $@
%.so.s:
@echo " CC build/tmp/base/socket/$@"
$(Q)$(CC) $(CFLAGS_SO) -S $< -o $@
%.o: %.s
@echo " AS build/tmp/base/socket/$@"
$(Q)$(AS) $< -o $@
tcp/client.a.s: $(TCP_CLIENT_SRC) $(TCP_CLIENT_INC)
tcp/client.so.s: $(TCP_CLIENT_SRC) $(TCP_CLIENT_INC)
tcp/server.a.s: $(TCP_SERVER_SRC) $(TCP_SERVER_INC)
tcp/server.so.s: $(TCP_SERVER_SRC) $(TCP_SERVER_INC)
我想在名称中有前导 tcp/
的所有目标的先决条件中添加一个 | tcp
,但我希望能够在一行中完成.我不想将其手动附加到需要它的每一行。
我想添加这条新规则:
tcp/%.s: | tcp
但它什么也没做。
我也想到了更通用的,会更好,但结果相同:
%.s: | $(@D)
我应该怎么写?
一个解决方法是每次都调用 mkdir(将其包含在 %.a.s 和 %.so.s 规则中),但这会增加对 mkdir 的不必要调用,不是吗?
您不能只使用模式规则将先决条件添加到一组给定的目标。这不是模式规则的工作方式:它们是 规则 :它们必须有与之关联的配方。没有配方的模式规则实际上 删除 该模式规则(参见 Canceling Implicit Rules)。
您可以创建两组模式规则,一组用于所有目标,另一组仅用于以 tcp/
开头且具有额外先决条件的目标,但您必须将整个模式规则编写两次,包括食谱,而不仅仅是图案线。
或者直接将 mkdir
放入食谱中。已经存在的目录上的 mkdir
甚至不会被注意到。
我不喜欢模式规则。它们对我的口味来说太武断了。
(实际发生的情况取决于您的硬盘上可能有哪些文件。)
You cannot just add a prerequisite to a given set of targets using a pattern rule
好吧,如果你使用 static pattern rules 就可以了。这是一个更好的成语。在这里,我们在模式规则前加上您希望应用模式规则的实际来源列表。这很好,您可以使用 make 的 noddy 模式匹配来描述依赖关系。
素描:
%.a: ; date >$@ # Pattern rule
tcp: ; mkdir -p $@ # Explicit rule
tcp/a.a: tcp/%.a: | tcp ; # Static pattern rule!
.PHONY: all
all: tcp/a.a
all: c.a
all: dir/b.a
all: ; : $@ Success
我们有:
$ make all
mkdir -p tcp
date >tcp/a.a
date >c.a
date >dir/b.a
/bin/sh: dir/b.a: No such file or directory
make: *** [Makefile:3: dir/b.a] Error 1
这里我们告诉 make 在构建之前(即 "runs the recipe for")tcp/a.a
,它必须先构建 tcp
。这样可行。我们没有告诉 make 关于 dir/b.a
的目录,所以失败了。请注意,.a
文件的配方仍处于普通模式规则中。这只是通过阐述的方式。我肯定会改变这个。
是的,在这种情况下,tcp/
的模式规则过于夸张。考虑一下,在创建 tcp/a.a
之前,您可能首先需要创建一个 auto/a.src
(例如)。
tcp/a.a: tcp/%.a: auto/%.src | tcp ; # Static pattern rule!
易于扩展。
targets := tcp/a.a tcp/b.a tcp/c.a
${targets}: tcp/%.a: auto/%.src | tcp ; # Static pattern rule!
[顺便说一下,在您的原始 makefile 中,您的存档和共享对象应该依赖于 .o
文件,而不是源代码 (???)]
这个答案只是为了展示一个有效的 Makefile 实现@bobbogo 的答案。
这个Makefile是Makefile树的叶子,所以这里没有定义的所有变量都由上层Makefile导出。
Makefile
:
#! /usr/bin/make -f
################################################################################
# *AUTHOR*
# FULL NAME "Alejandro Colomar Andrés"
################################################################################
################################################################################
DIRS = \
$(CURDIR)/tcp
OBJ = \
$(CURDIR)/tcp/client.o \
$(CURDIR)/tcp/server.o \
$(CURDIR)/foo.o
SRC = \
$(SRC_DIR)/base/socket/tcp/client.c \
$(SRC_DIR)/base/socket/tcp/server.c \
$(SRC_DIR)/base/socket/foo.c
DEP = $(OBJ:.o=.d)
BOTH_OBJ = $(subst .a.o,.a.o ,$(join $(OBJ:.o=.a.o),$(OBJ:.o=.so.o)))
BOTH_ASM = $(subst .a.s,.a.s ,$(join $(OBJ:.o=.a.s),$(OBJ:.o=.so.s)))
NEEDDIR = $(DEP) $(BOTH_ASM)
################################################################################
PHONY := all
all: $(BOTH_OBJ)
@:
$(DIRS): $(CURDIR)/%:
@echo " MKDIR build/tmp/base/socket/$*"
$(Q)mkdir -p $@
$(NEEDDIR): | $(DIRS)
$(CURDIR)/%.d: $(SRC_DIR)/base/socket/%.c
@echo " CC -M build/tmp/base/socket/$*.d"
$(Q)$(CC) $(CFLAGS_A) -MG -MT"$@" \
-MT"$(CURDIR)/$*.a.s" -MT"$(CURDIR)/$*.so.s" \
-M $< -MF $@
$(CURDIR)/%.a.s: $(SRC_DIR)/base/socket/%.c $(CURDIR)/%.d
@echo " CC build/tmp/base/socket/$*.a.s"
$(Q)$(CC) $(CFLAGS_A) -S $< -o $@
$(CURDIR)/%.so.s: $(SRC_DIR)/base/socket/%.c $(CURDIR)/%.d
@echo " CC build/tmp/base/socket/$*.so.s"
$(Q)$(CC) $(CFLAGS_SO) -S $< -o $@
$(CURDIR)/%.o: $(CURDIR)/%.s
@echo " AS build/tmp/base/socket/$*.o"
$(Q)$(AS) $< -o $@
include $(DEP)
PHONY += clean
clean:
$(Q)rm -rf *.o *.s *.d
################################################################################
# Declare the contents of the PHONY variable as phony.
.PHONY: $(PHONY)
################################################################################
######## End of file ###########################################################
################################################################################
输出:
MKDIR build/tmp/base/socket/tcp
CC -M build/tmp/base/socket/foo.d
CC -M build/tmp/base/socket/tcp/server.d
CC -M build/tmp/base/socket/tcp/client.d
CC build/tmp/base/socket/tcp/client.a.s
AS build/tmp/base/socket/tcp/client.a.o
CC build/tmp/base/socket/tcp/client.so.s
AS build/tmp/base/socket/tcp/client.so.o
CC build/tmp/base/socket/tcp/server.a.s
AS build/tmp/base/socket/tcp/server.a.o
CC build/tmp/base/socket/tcp/server.so.s
AS build/tmp/base/socket/tcp/server.so.o
CC build/tmp/base/socket/foo.a.s
AS build/tmp/base/socket/foo.a.o
CC build/tmp/base/socket/foo.so.s
AS build/tmp/base/socket/foo.so.o
我有这个 makefile 代码:
$(DIRS):
@echo " MKDIR build/tmp/base/socket/$@"
$(Q)mkdir -p $@/
%.a.s:
@echo " CC build/tmp/base/socket/$@"
$(Q)$(CC) $(CFLAGS_A) -S $< -o $@
%.so.s:
@echo " CC build/tmp/base/socket/$@"
$(Q)$(CC) $(CFLAGS_SO) -S $< -o $@
%.o: %.s
@echo " AS build/tmp/base/socket/$@"
$(Q)$(AS) $< -o $@
tcp/client.a.s: $(TCP_CLIENT_SRC) $(TCP_CLIENT_INC)
tcp/client.so.s: $(TCP_CLIENT_SRC) $(TCP_CLIENT_INC)
tcp/server.a.s: $(TCP_SERVER_SRC) $(TCP_SERVER_INC)
tcp/server.so.s: $(TCP_SERVER_SRC) $(TCP_SERVER_INC)
我想在名称中有前导 tcp/
的所有目标的先决条件中添加一个 | tcp
,但我希望能够在一行中完成.我不想将其手动附加到需要它的每一行。
我想添加这条新规则:
tcp/%.s: | tcp
但它什么也没做。
我也想到了更通用的,会更好,但结果相同:
%.s: | $(@D)
我应该怎么写?
一个解决方法是每次都调用 mkdir(将其包含在 %.a.s 和 %.so.s 规则中),但这会增加对 mkdir 的不必要调用,不是吗?
您不能只使用模式规则将先决条件添加到一组给定的目标。这不是模式规则的工作方式:它们是 规则 :它们必须有与之关联的配方。没有配方的模式规则实际上 删除 该模式规则(参见 Canceling Implicit Rules)。
您可以创建两组模式规则,一组用于所有目标,另一组仅用于以 tcp/
开头且具有额外先决条件的目标,但您必须将整个模式规则编写两次,包括食谱,而不仅仅是图案线。
或者直接将 mkdir
放入食谱中。已经存在的目录上的 mkdir
甚至不会被注意到。
我不喜欢模式规则。它们对我的口味来说太武断了。 (实际发生的情况取决于您的硬盘上可能有哪些文件。)
You cannot just add a prerequisite to a given set of targets using a pattern rule
好吧,如果你使用 static pattern rules 就可以了。这是一个更好的成语。在这里,我们在模式规则前加上您希望应用模式规则的实际来源列表。这很好,您可以使用 make 的 noddy 模式匹配来描述依赖关系。
素描:
%.a: ; date >$@ # Pattern rule
tcp: ; mkdir -p $@ # Explicit rule
tcp/a.a: tcp/%.a: | tcp ; # Static pattern rule!
.PHONY: all
all: tcp/a.a
all: c.a
all: dir/b.a
all: ; : $@ Success
我们有:
$ make all
mkdir -p tcp
date >tcp/a.a
date >c.a
date >dir/b.a
/bin/sh: dir/b.a: No such file or directory
make: *** [Makefile:3: dir/b.a] Error 1
这里我们告诉 make 在构建之前(即 "runs the recipe for")tcp/a.a
,它必须先构建 tcp
。这样可行。我们没有告诉 make 关于 dir/b.a
的目录,所以失败了。请注意,.a
文件的配方仍处于普通模式规则中。这只是通过阐述的方式。我肯定会改变这个。
是的,在这种情况下,tcp/
的模式规则过于夸张。考虑一下,在创建 tcp/a.a
之前,您可能首先需要创建一个 auto/a.src
(例如)。
tcp/a.a: tcp/%.a: auto/%.src | tcp ; # Static pattern rule!
易于扩展。
targets := tcp/a.a tcp/b.a tcp/c.a
${targets}: tcp/%.a: auto/%.src | tcp ; # Static pattern rule!
[顺便说一下,在您的原始 makefile 中,您的存档和共享对象应该依赖于 .o
文件,而不是源代码 (???)]
这个答案只是为了展示一个有效的 Makefile 实现@bobbogo 的答案。
这个Makefile是Makefile树的叶子,所以这里没有定义的所有变量都由上层Makefile导出。
Makefile
:
#! /usr/bin/make -f
################################################################################
# *AUTHOR*
# FULL NAME "Alejandro Colomar Andrés"
################################################################################
################################################################################
DIRS = \
$(CURDIR)/tcp
OBJ = \
$(CURDIR)/tcp/client.o \
$(CURDIR)/tcp/server.o \
$(CURDIR)/foo.o
SRC = \
$(SRC_DIR)/base/socket/tcp/client.c \
$(SRC_DIR)/base/socket/tcp/server.c \
$(SRC_DIR)/base/socket/foo.c
DEP = $(OBJ:.o=.d)
BOTH_OBJ = $(subst .a.o,.a.o ,$(join $(OBJ:.o=.a.o),$(OBJ:.o=.so.o)))
BOTH_ASM = $(subst .a.s,.a.s ,$(join $(OBJ:.o=.a.s),$(OBJ:.o=.so.s)))
NEEDDIR = $(DEP) $(BOTH_ASM)
################################################################################
PHONY := all
all: $(BOTH_OBJ)
@:
$(DIRS): $(CURDIR)/%:
@echo " MKDIR build/tmp/base/socket/$*"
$(Q)mkdir -p $@
$(NEEDDIR): | $(DIRS)
$(CURDIR)/%.d: $(SRC_DIR)/base/socket/%.c
@echo " CC -M build/tmp/base/socket/$*.d"
$(Q)$(CC) $(CFLAGS_A) -MG -MT"$@" \
-MT"$(CURDIR)/$*.a.s" -MT"$(CURDIR)/$*.so.s" \
-M $< -MF $@
$(CURDIR)/%.a.s: $(SRC_DIR)/base/socket/%.c $(CURDIR)/%.d
@echo " CC build/tmp/base/socket/$*.a.s"
$(Q)$(CC) $(CFLAGS_A) -S $< -o $@
$(CURDIR)/%.so.s: $(SRC_DIR)/base/socket/%.c $(CURDIR)/%.d
@echo " CC build/tmp/base/socket/$*.so.s"
$(Q)$(CC) $(CFLAGS_SO) -S $< -o $@
$(CURDIR)/%.o: $(CURDIR)/%.s
@echo " AS build/tmp/base/socket/$*.o"
$(Q)$(AS) $< -o $@
include $(DEP)
PHONY += clean
clean:
$(Q)rm -rf *.o *.s *.d
################################################################################
# Declare the contents of the PHONY variable as phony.
.PHONY: $(PHONY)
################################################################################
######## End of file ###########################################################
################################################################################
输出:
MKDIR build/tmp/base/socket/tcp
CC -M build/tmp/base/socket/foo.d
CC -M build/tmp/base/socket/tcp/server.d
CC -M build/tmp/base/socket/tcp/client.d
CC build/tmp/base/socket/tcp/client.a.s
AS build/tmp/base/socket/tcp/client.a.o
CC build/tmp/base/socket/tcp/client.so.s
AS build/tmp/base/socket/tcp/client.so.o
CC build/tmp/base/socket/tcp/server.a.s
AS build/tmp/base/socket/tcp/server.a.o
CC build/tmp/base/socket/tcp/server.so.s
AS build/tmp/base/socket/tcp/server.so.o
CC build/tmp/base/socket/foo.a.s
AS build/tmp/base/socket/foo.a.o
CC build/tmp/base/socket/foo.so.s
AS build/tmp/base/socket/foo.so.o