Makefile问题:聪明的方式来扫描.c文件的目录树

我正在做一个项目,增长速度非常快,保持对象文件的date是没有select的。 通配符命令之外的问题存在于“我不想recursionmakefile”和“我不想让它手动列出”之间。 该对象应该进入一个单独的目录,这已经工作。 注:我不是用来制作文件,我知道的基本知识,但一切超越…

所以我的问题: 如何recursion扫描一个src文件夹,并以聪明的方式做到这一点?

我已经做了多个SRCvariables,但这是丑陋的,整个makefile越来越多的目录混乱。

我目前使用的是:

OS = Linux VERSION = 0.0.1 CC = /usr/bin/gcc CFLAGS = -Wall -g -D_REENTRANT -DVERSION=\"$(VERSION)\" LDFLAGS = -lm `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0` BUILDDIR = build SOURCEDIR = src HEADERDIR = src SOURCES = $(wildcard $(SOURCEDIR)/*.c) OBJECTS = $(patsubst $(SOURCEDIR)/%.c, $(BUILDDIR)/%.o, $(SOURCES)) NAME = cinnamon BINARY = cinnamon.bin ECHO = echo RM = rm -rf MKDIR = mkdir INSTALL = install .PHONY: all clean setup all: $(BINARY) $(BINARY): $(BUILDDIR)/$(OBJECTS) $(CC) $(CFLAGS) $(LDFLAGS) -I$(HEADERDIR) -I$(SOURCEDIR) $(OBJECTS) -o $(BINARY) $(BUILDDIR)/%.o: $(SOURCEDIR)/%.c $(CC) $(CFLAGS) $(LDFLAGS) -I$(HEADERDIR) -I$(SOURCEDIR) -c $< -o $@ setup: $(MKDIR) -p $(BUILDDIR) install: $(INSTALL) -m 755 -o 0 -g 0 -d $(DESTDIR)/usr/local/bin/ $(INSTALL) -m 755 -o 0 -g 0 $(BINARY) $(DESTDIR)/usr/local/bin/$(BINARY) $(INSTALL) -m 755 -o 0 -g 0 -d $(DESTDIR)/usr/local/$(NAME)/ui/ $(INSTALL) -m 644 -o 0 -g 0 ./ui/*.ui $(DESTDIR)/usr/local/$(NAME)/ui/ # $(INSTALL) -m 755 -o 0 -g 0 -d $(DESTDIR)/usr/local/$(NAME)/model/ # $(INSTALL) -m 644 -o 0 -g 0 ./model/*.model $(DESTDIR)/usr/local/$(NAME)/model/ clean: $(RM) $(BINARY) $(OBJECTS) distclean: clean help: @$(ECHO) "Targets:" @$(ECHO) "all - buildcompile what is necessary" @$(ECHO) "clean - cleanup old .o and .bin" @$(ECHO) "install - not yet fully supported" 

感谢回答#1归结为如何解决这个问题:

 $(BUILDDIR)/%.o: $(SOURCEDIR)/%.c $(CC) $(CFLAGS) $(LDFLAGS) $(SOURCETREE) -c $< -o $@ 

特别是在BUILDDIR = build和SOURCEDIR的情况下,必须用来自SOURCES的单个.c文件(包括它们的path)来replace:/

做你想做的最简单的select可能只是使用shell转义并调用find

 SOURCES := $(shell find $(SOURCEDIR) -name '*.c') 

这会得到一个包含path的源文件列表。 请注意,使用立即赋值:=而不是recursion赋值=在这里非常重要:每次使用make检查SOURCES 都不希望运行shell转义(发生的事情比Makefiles中的要多得多)。 我觉得有用的一般规则是总是使用立即赋值,除非我实际上需要recursion扩展(这很less见;看起来在这个例子中的所有赋值都可以立即生效)。 这就意味着使用recursion赋值也是一个有用的信号,即variables需要谨慎使用。

回到你的问题。 你接下来要做什么取决于你是否想要在你的构build树中使用源代码树的镜像,或者构build目录是否应该包含所有源文件的对象文件的平面列表,或者是否需要单独的构build目录在树的每个源目录下。

假设你想要镜像的构build树,你可以做如下的事情:

 # Get list of object files, with paths OBJECTS := $(addprefix $(BUILDDIR)/,$(SOURCES:%.c=%.o)) $(BINARY): $(OBJECTS) $(CC) $(CFLAGS) $(LDFLAGS) $(OBJECTS) -o $(BINARY) $(BUILDDIR)/%.o: %.c $(CC) $(CFLAGS) $(LDFLAGS) -I$(HEADERDIR) -I$(dir $<) -c $< -o $@ 

这并没有完全考虑到作业的完整复杂性,因为它不能确保构build树中的目录确实存在(在Makefile语法中这样做会很痛苦)。

我从$(BINARY)构build规则中删除了-I指令; 链接对象时你真的需要它们吗? 我没有离开它们的原因是,你不再有一个源代码目录,从对象列表中获取源代码列表是非常简单的(就像Makefile语法中的那么多,真烦人)。

recursion通配符可以纯粹在Make中完成,而不用调用shell或find命令。 仅使用Make进行search意味着此解决scheme也适用于Windows,而不仅仅是* nix。

 # Make does not offer a recursive wildcard function, so here's one: rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)) # How to recursively find all files with the same name in a given folder ALL_INDEX_HTMLS := $(call rwildcard,foo/,index.html) # How to recursively find all files that match a pattern ALL_HTMLS := $(call rwildcard,foo/,*.html) 

文件夹名称中的尾部斜杠是必需的。 这个rwildcard函数不像Make的内置通配符函数那样支持多个通配符,但是增加这个支持对于foreach来说更简单一些。

我喜欢做以下事情。

为项目的每个目录创buildvariables

 SRCDIR = src OBJDIR = obj LIBDIR = lib DOCDIR = doc HDRDIR = include CFLAGS = -g -Wall -O3 

recursion获取SRCDIR的内部结构

 STRUCTURE := $(shell find $(SRCDIR) -type d) 

获取结构variables中的所有文件

 CODEFILES := $(addsuffix /*,$(STRUCTURE)) CODEFILES := $(wildcard $(CODEFILES)) 

只筛选出特定的文件

 # Filter Only Specific Files SRCFILES := $(filter %.c,$(CODEFILES)) HDRFILES := $(filter %.h,$(CODEFILES)) OBJFILES := $(subst $(SRCDIR),$(OBJDIR),$(SRCFILES:%.c=%.o)) # Filter Out Function main for Libraries LIBDEPS := $(filter-out $(OBJDIR)/main.o,$(OBJFILES)) 

现在是时候创build规则了

 compile: $(OBJFILES) $(OBJDIR)/%.o: $(addprefix $(SRCDIR)/,%.c %.h) $(CC) -c $< -o $@ $(CFLAGS) 

使用这种方法,可以看到我只使用STRUCTUREvariables来获取SRCDIR目录中的文件,但也可以将其用于其他目的,例如,一旦STRUCTURE仅存储内部子文件夹,在OBJDIR中镜像SRCDIR,目录。 经过如下清理操作后,它非常有用:

 clean: -rm -r $(OBJDIR)/* 

注意:编译规则只适用于每个* .c有相应的* .h文件(具有相同的基本名称,我的意思是)。

这个问题的另一个好的解决scheme似乎是 – 实现一个非recursion的makefile,如这里所描述的。 http://www.xs4all.nl/~evbergen/nonrecursive-make.html 。 这种方法非常好,因为它看起来具有相当的可扩展性 – 开发人员可以使用源文件在目录中添加依赖信息,而无需担心整个makefile。