我正在做一个快速增长的项目,保持目标文件的日期是没有选择的.wildcard命令之外的问题介于"我不想要递归的makefile"和"我不希望它手动列出"之间.这些对象应该进入一个单独的目录,该目录已经可以使用.注:我不是说用的makefile,我知道的基本知识,但一切都超出了......
所以我的问题是: 如何以递归方式扫描src文件夹并以智能方式执行此操作?
我已经用多个SRC变量做了这个但是这很难看,并且整个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"
Run Code Online (Sandbox Code Playgroud)
感谢答案#1,归结为如何解决这个问题:
$(BUILDDIR)/%.o: $(SOURCEDIR)/%.c
$(CC) $(CFLAGS) $(LDFLAGS) $(SOURCETREE) -c $< -o $@
Run Code Online (Sandbox Code Playgroud)
特别是在BUILDDIR = build和SOURCEDIR的情况下,必须用来自SOURCES的单个.c文件替换它们的路径:/
Ben*_*Ben 78
做你想做的最简单的选择可能只是使用shell转义并调用find
:
SOURCES := $(shell find $(SOURCEDIR) -name '*.c')
Run Code Online (Sandbox Code Playgroud)
这将为您提供包含路径的源文件列表.请注意,使用立即赋值:=
而不是递归赋值=
在这里很重要:您不希望每次SOURCES
被make检查时都运行shell转义(这比Makefile中的想法要多得多).我觉得有用的一般规则是始终使用立即赋值,除非我实际上需要递归扩展(这很少见;看起来这个例子中的所有赋值都可以是立即的).这意味着使用递归赋值也是一个有用的信号,需要仔细使用该变量.
回到你的问题.你接下来要做什么取决于你是否想在构建树中使用源代码树的镜像,或者构建目录是否应该包含所有源文件的目标文件的平面列表,或者是否需要单独的构建目录在树的每个源目录下.
假设您需要镜像构建树,您可以执行以下操作:
# 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 $@
Run Code Online (Sandbox Code Playgroud)
这并没有完全考虑到作业的完全复杂性,因为它不能确保构建树中的目录实际存在(在Makefile语法中这将是非常痛苦的).
我从$(BINARY)构建规则中删除了-I指令; 链接对象时你真的需要它们吗?我没有留下它们的原因是你不再只有一个源目录了,从对象列表中获取源dirs列表是非常重要的(就像在Makefile语法中那样,它是可行的但是真烦人).
Lig*_*ruk 48
递归通配符可以完全在Make中完成,无需调用shell或find命令.仅使用Make进行搜索意味着此解决方案也适用于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)
Run Code Online (Sandbox Code Playgroud)
文件夹名称中的尾部斜杠是必需的.这个rwildcard函数不像Make的内置通配符函数那样支持多个通配符,但是通过foreach的更多用法添加该支持将是直截了当的.
小智 14
我喜欢做以下事情.
SRCDIR = src
OBJDIR = obj
LIBDIR = lib
DOCDIR = doc
HDRDIR = include
CFLAGS = -g -Wall -O3
Run Code Online (Sandbox Code Playgroud)
STRUCTURE := $(shell find $(SRCDIR) -type d)
Run Code Online (Sandbox Code Playgroud)
CODEFILES := $(addsuffix /*,$(STRUCTURE))
CODEFILES := $(wildcard $(CODEFILES))
Run Code Online (Sandbox Code Playgroud)
# 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))
Run Code Online (Sandbox Code Playgroud)
compile: $(OBJFILES)
$(OBJDIR)/%.o: $(addprefix $(SRCDIR)/,%.c %.h)
$(CC) -c $< -o $@ $(CFLAGS)
Run Code Online (Sandbox Code Playgroud)
使用这种方法,您可以看到我仅使用STRUCTURE变量来获取SRCDIR目录中的文件,但它也可以用于其他目的,例如,一旦STRUCTURE仅存储内部子目录,则在OBJDIR内镜像SRCDIR.目录.在清洁操作之后它非常有用,例如:
clean:
-rm -r $(OBJDIR)/*
Run Code Online (Sandbox Code Playgroud)
注意:编译规则只适用于每个*.c都有相应的*.h文件(具有相同的基本名称,我的意思).