Makefile 如果目标名称具有目录部分,则生成目录
我有这个makefile代码:Makefile 如果目标名称具有目录部分,则生成目录,makefile,wildcard,gnu-make,Makefile,Wildcard,Gnu Make,我有这个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/$
$(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)
但它什么也没做
我还想到了更通用的,这会更好,但结果相同:
%.s: | $(@D)
我该怎么写呢
一种解决方法是每次调用mkdir(将其包含在%.A.s和%.so.s规则中),但这会增加对mkdir的不必要调用,不是吗?您不能仅使用模式规则向给定的目标集添加先决条件。模式规则不是这样工作的:它们是规则:它们必须有一个与之相关联的配方。没有配方的模式规则实际上会删除该模式规则(请参阅) 您可以创建两组模式规则,一组用于所有目标,另一组用于仅以
tcp/
开头且具有额外先决条件的目标,但您必须编写两次整个模式规则,包括一个配方,而不仅仅是模式行
或者只需将
mkdir
放入配方中即可。已经存在的目录上的mkdir
甚至不会引起注意。您不能仅使用模式规则向给定的目标集添加先决条件。模式规则不是这样工作的:它们是规则:它们必须有一个与之相关联的配方。没有配方的模式规则实际上会删除该模式规则(请参阅)
您可以创建两组模式规则,一组用于所有目标,另一组用于仅以tcp/
开头且具有额外先决条件的目标,但您必须编写两次整个模式规则,包括一个配方,而不仅仅是模式行
或者只需将
mkdir
放入配方中即可。已经存在的目录上的mkdir
甚至不会引起注意。我不喜欢模式规则。他们太武断了,不合我的口味。
(实际发生的情况取决于硬盘上可能有哪些文件。)
不能仅使用模式规则向给定的目标集添加先决条件 如果你使用的话,你可以。这是一个好得多的成语。在这里,我们用您希望模式规则应用到的源的实际列表作为模式规则的前缀。这是一个很好的地方,您可以使用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,在构建(即“运行”tcp/a.a
的配方)之前,它必须首先构建tcp
。这很有效。我们没有告诉make关于dir/b.a
的目录,因此失败了。请注意,.a
文件的配方仍处于普通模式规则中。这只是为了说明。我一定会改变这个
是的,在这种情况下,tcp/
的模式规则是过度的。考虑一下,在创建<代码> TCP/A.A/COD>之前,您可能首先需要创建一个<代码> Auto/A.SRC(例如)。
易于扩展
targets := tcp/a.a tcp/b.a tcp/c.a
${targets}: tcp/%.a: auto/%.src | tcp ; # Static pattern rule!
[顺便说一句,在原始makefile中,存档和共享对象应该依赖于
.o
文件,而不是源(???)]我不喜欢模式规则。他们太武断了,不合我的口味。
(实际发生的情况取决于硬盘上可能有哪些文件。)
不能仅使用模式规则向给定的目标集添加先决条件 如果你使用的话,你可以。这是一个好得多的成语。在这里,我们用您希望模式规则应用到的源的实际列表作为模式规则的前缀。这是一个很好的地方,您可以使用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,在构建(即“运行”tcp/a.a
的配方)之前,它必须首先构建tcp
。这很有效。我们没有告诉make关于dir/b.a
的目录,因此失败了。请注意,.a
文件的配方仍处于普通模式规则中。这只是为了说明。我一定会改变这个
是的,在这种情况下,tcp/
的模式规则是过度的。考虑一下,在创建<代码> TCP/A.A/COD>之前,您可能首先需要创建一个<代码> Auto/A.SRC(例如)。
易于扩展
targets := tcp/a.a tcp/b.a tcp/c.a
${targets}: tcp/%.a: auto/%.src | tcp ; # Static pattern rule!
[顺便说一句,在原始makefile中,存档和共享对象应该依赖于
.o
文件,而不是源(??)此答案仅显示实现@bobbogo答案的工作makefile
此Makefile是Makefile树的一个叶,因此此处未定义的所有变量都由上层Makefiles导出
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 ###########################################################
################################################################################
这个答案只是为了显示一个实现@bobbogo答案的工作Makefile 此Makefile是Makefile树的一个叶,因此此处未定义的所有变量都由上层Makefiles导出
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-p
来确保你在并行构建过程中不会失败。非常明显,你应该使用mkdir-p
来确保你在并行构建过程中不会失败。关于你的BTW问题:见最后一个扩展。那些是程序集文件。两者的区别在于CFLAGS\u SO
具有-fpic
,而CFLAGS\u A
没有。因此,我将从.a.s文件中汇编.a.o对象文件,这些文件将被归档到.a库中。从.so.s文件中,我将汇编.so.o对象文件,这些文件将被编译成.so库。如果我传递整个对象列表,而不是仅传递以tcp开头的对象,它是否仍然有效(忽略那些与模式不匹配的对象,即不以tcp开头的对象)?:$(OBJS):tcp/%.a:| tcp;#静态模式
@CacahueteFrito不合理地说,每个源文件名都必须与目标模式匹配<代码>文件.o:%.c:%.auto…不起作用。静态模式规则和模式规则有相同的问题:静态模式规则是一个exp