我必须构建一个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 all
之后直接make init
尝试:
$ 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两次。
答案 0 :(得分:2)
这是解决方案。我还添加了其他一些最佳实践&#34;你的代码。
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))))
答案 1 :(得分:0)
中的两种模式
%.o:%.c
仅匹配Makefile目录中的文件。我认为你应该可以使用
%.o: $(SRCDIR)/%.c