makefile - makefile 中的级联通配符

标签 makefile wildcard

我必须构建一个c 项目(实际上有点复杂)。该项目有一些 c 文件需要使用自制脚本进行预处理。这些文件的扩展名为.cd

所以我有这个文件结构:

/project
+ Makefile   
+ foo/
| + foo1.cd
| + foo2.cd
+ bar/
  + bar1.cd
  + bar2.cd

当然,我可以添加一个包含其他文件的新文件夹,例如 foobar。值得一提的是,我不能有两个同名的源文件......

也就是说,make 就可以了:

foo/foo1.cd --> foo/foo1.c
foo/foo1.c  --> obj/foo1.o
...
obj/foo1.o obj/bar1.o ... obj/bar2.o --> a.out

因为我有数百个文件。我使用通配符 %vpath 来告诉 make 应该在哪里找到它们。

为了说明我的问题,我编写了这个 Makefile:

OBJDIR = obj
SRCDIR = $(patsubst %/,%,$(sort $(dir $(wildcard ./*/))))

vpath %.c  $(SRCDIR)/
vpath %.cd $(SRCDIR)/
vpath %.o  $(OBJDIR)/

DEFS = $(wildcard ./*/*.cd)   # To be preprocessed
SRCS = $(patsubst %.cd,%.c,$(DEFS)) # Source files
OBJS = $(notdir $(SRCS:.c=.o))      # Objects files

all: a.out

preproc: $(SRCS)

a.out: $(OBJS)
    echo "$^" >> a.out

%.c: %.cd
    echo "$<" >> $@

%.o:%.c
    @if [ ! -f $< ]; then \
        echo "File $< not found" && false;\
    else\
        echo "File $< found ";\
        touch $(OBJDIR)/$@;\
    fi;

$(OBJS): | $(OBJDIR)

$(OBJDIR):
    -mkdir $(OBJDIR)

clean:
    -rm -f $(SRCS) a.out *.c *.o
    -rm -rf $(OBJDIR)

init: clean
    mkdir -p foo
    mkdir -p bar
    touch foo/foo1.cd
    touch foo/foo2.cd
    touch bar/bar1.cd
    touch bar/bar2.cd

首先我初始化我的示例:

$ make init
rm -f ./bar/bar2.c ./bar/bar1.c ./foo/foo2.c ./foo/foo1.c  a.out *.c *.o
rm -rf obj
mkdir -p foo
mkdir -p bar
touch foo/foo1.cd
touch foo/foo2.cd
touch bar/bar1.cd
touch bar/bar2.cd

然后我需要预处理我的文件:

$ make preproc
echo "bar/bar2.cd" >> bar/bar2.c
echo "bar/bar1.cd" >> bar/bar1.c
echo "foo/foo2.cd" >> foo/foo2.c
echo "foo/foo1.cd" >> foo/foo1.c

最后我构建了项目:

$ make
mkdir obj
File ./bar/bar2.c found
File ./bar/bar1.c found
File ./foo/foo2.c found
File ./foo/foo1.c found
echo "bar2.o bar1.o foo2.o foo1.o" >> a.out

问题是我需要运行 make 两次。一次进行预处理器,然后另一次构建项目。如果我尝试在 make init 之后直接 make all 我会得到:

$ make
echo "./bar/bar2.cd" >> bar2.c
mkdir obj
File bar2.c found
echo "./bar/bar1.cd" >> bar1.c
File bar1.c found
echo "./foo/foo2.cd" >> foo2.c
File foo2.c found
echo "./foo/foo1.cd" >> foo1.c
File foo1.c found
echo "bar2.o bar1.o foo2.o foo1.o" >> a.out

请注意,这次源文件被放置在根目录中,而不是其假定的位置。

我想找到一个不需要运行两次 make 的解决方案。

最佳答案

这是解决方案。我还在您的代码中添加了一些其他“最佳实践”。

OBJDIR := obj
SRCDIRS := foo bar

vpath %.cd $(SRCDIRS)

DEFS := $(wildcard $(addsuffix  /*.cd, $(SRCDIRS)))     # To be preprocessed
OBJS := $(addprefix $(OBJDIR)/, $(notdir $(DEFS:cd=o)))     # Objects files

.PHONY: all
all: a.out 

a.out: $(OBJS) Makefile
    echo $(OBJS) > $@

.PRECIOUS: %.c %/.

%.c: %.cd Makefile
    echo $< > $@

%/.:
    mkdir -p $@


define OBJ_DIR_RECIPE
$1/%.o: $2/%.c Makefile | $1/.
    echo File $$< found
    touch $$@
endef

$(foreach dir, $(SRCDIRS), $(eval $(call OBJ_DIR_RECIPE,$(OBJDIR),$(dir))))

关于makefile - makefile 中的级联通配符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25742938/

相关文章:

node.js - Nodejs glob 多种模式

lucene - Lucene 中的通配符

c - Makefile 混淆虚假 hack

PHP 错误 : libphp5. 所以: undefined symbol :_estrndup

eclipse - 将外部构建工具集成到 Eclipse 中的最佳方法是什么?

java - 泛型类和通配符的上限

c - Mac OS X 中的 makefile 缺少分隔符

Makefile:在for循环中调用多行变量

带有通配符的 Java 泛型在 Eclipse 中编译,但在 javac 中不编译

bash - 为什么通配符在 `sudo rm` 语句中不起作用?