使用Makefile清理子目录

使用Makefile清理子目录,makefile,gnu-make,Makefile,Gnu Make,是否可以从父目录执行makeclean,它也递归地清理所有子目录,而不必在每个子目录中包含makefile 例如,当前在我的Makefile中,我有如下内容: SUBDIRS = src, src1 .PHONY: clean subdirs $(SUBDIRS) clean: $(SUBDIRS) rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c $(SUBDIRS): $(MAKE) -C $(SUBDIRS) clean

是否可以从父目录执行makeclean,它也递归地清理所有子目录,而不必在每个子目录中包含makefile

例如,当前在我的Makefile中,我有如下内容:

SUBDIRS = src, src1

.PHONY: clean subdirs $(SUBDIRS)

clean: $(SUBDIRS)
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c

$(SUBDIRS):
    $(MAKE) -C $(SUBDIRS) clean 
但是,这要求我在src和src1中都有一个Makefile。否则,我会得到错误

No rule to make target clean

由于我只想在每个子目录中运行命令“rm-rf*.o~core.depend..cmd*.ko*.mod.c”,因此在每个子目录中都必须包含一个Makefile,并使用完全相同的行进行清理,这似乎是多余的。没有办法在每个子目录中运行相同的clean命令吗?

我同意您可以在子目录上运行rm命令。但类似于以下内容的内容允许仅使用单个makefile进行递归make:

SUBDIRS = . src src1
SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS))

clean: $(SUBDIRSCLEAN)

clean_curdir:
    rm -rfv *.o *~ core .depend .*.cmd *.ko *.mod.c

%clean: %
    $(MAKE) -C $< -f $(PWD)/Makefile clean_curdir
SUBDIRS=。src src1
细分清除=$(添加后缀清除,$(细分清除))
清理:$(子磁盘清理)
清洁剂:
rm-rfv*.o*~core.depend.*.cmd.*.ko.*.mod.c
%清洁:%
$(MAKE)-C$<-f$(PWD)/Makefile clean\u curdir

没有外部程序的帮助,您无法使用。最好的是一个shell脚本,它在每个子目录中执行递归和调用(请看我对@robert的回复中的注释),类似这样的脚本可以完成工作(不依赖于GNU make特性)

当然,您可以将此序列(在target
cleanrec
中)放入
Makefile

cleanrec:
    ROOT=`/bin/pwd`; \
    for dir in `find . -type d -print`; \
    do \
        make -C "$${dir}" -f "$${ROOTDIR}"/Makefile clean; \
    done

并将
clean
目标保存为本地清理单个目录。原因是Makefile只有静态信息来进行生成,您必须获得一些外部帮助才能知道每个目录中有哪些子目录。因此,如果您要获得外部帮助,最好使用一个好的工具,如find(1)sh(1)而不是使用递归,您可以使用
find
来获得目录列表,并进行一次迭代来生成通配符:

SUBDIR_ROOTS := foo bar
DIRS := . $(shell find $(SUBDIR_ROOTS) -type d)
GARBAGE_PATTERNS := *.o *~ core .depend .*.cmd *.ko *.mod.c
GARBAGE := $(foreach DIR,$(DIRS),$(addprefix $(DIR)/,$(GARBAGE_PATTERNS)))

clean:
    rm -rf $(GARBAGE)
答案的变化:

这是latex文件的一个示例。由于文件类型名称上的括号,垃圾类型上的第一个模式有双引号。没有它,
rm
无法删除它们。其他模式不需要引号

第二个
目录\u TO \u CLEAN
使用与要清理的目录列表相反的内容,即,要不清理的目录列表。当您只有一个或两个目录(如
.git
images
)时,这将非常有用,因为您不希望清理这些目录,但希望清理其他所有目录

ALL_MOD = $(shell find . -maxdepth 1 -type d )
ALL_MOD_CLEAN = $(addsuffix .clean, $(ALL_MOD))

.PHONY: $(ALL_MOD_CLEAN) $(ALL_MOD) default all clean

$(ALL_MOD_CLEAN): 
    $(E) "cleaning $(basename $@)"
    if [ -e $(basename $@)/Makefile ] ; then \
            $(MAKE) -C $(basename $@) clean ;\
    fi 

clean: $(ALL_MOD_CLEAN)
    $(E) "cleaning complete: " $(ALL_MOD)

将“.”添加到后缀中,并使用$(basename…)而不是原始目标,否则每次只需清理项目,就会重新生成所有文件

您可能只需要使用clean命令递归删除文件。请参阅:这或只是在clean over
$(SUBDIRS)
中循环,并手动在每个文件中运行
rm
。实际上,如果您仔细编写顶级makefile(或编写一个包含的单独的
clean.mk
makefile),那么您可以在该配方中使用
$(MAKE)-C$@-f clean.mk clean
。(注意
$@
而不是
$(SUBDIRS)
-C
只接受一个参数而不是一个列表。)您将在中断过程递归部分的子基上获得SUBDIRS变量的副本。只有在你有相同的子目录(名称相同)的情况下,该计划才会起作用。你如何在src或src1中递归一次。。。如何知道有多少子目录,并构造变量
子目录的新版本。运行
make--debug
将显示发生了什么。如果硬编码列表不起作用,类似于
find
的功能可能会检测子目录。
# Exclude directory from find . command
# https://stackoverflow.com/questions/4210042/exclude-directory-from-find-command
GARBAGE_TYPES         := "*.gz(busy)" *.aux *.log *.pdf *.aux *.bbl *.log *.out *.synctex.gz *.fls
DIRECTORIES_TO_CLEAN  := $(shell find -not -path "./.git**" -not -path "./images**" -type d)
GARBAGE_TYPED_FOLDERS := $(foreach DIR, $(DIRECTORIES_TO_CLEAN), $(addprefix $(DIR)/,$(GARBAGE_TYPES)))

clean:
    $(RM) -rf $(GARBAGE_TYPED_FOLDERS)
    # echo $(GARBAGE_TYPED_FOLDERS)
ALL_MOD = $(shell find . -maxdepth 1 -type d )
ALL_MOD_CLEAN = $(addsuffix .clean, $(ALL_MOD))

.PHONY: $(ALL_MOD_CLEAN) $(ALL_MOD) default all clean

$(ALL_MOD_CLEAN): 
    $(E) "cleaning $(basename $@)"
    if [ -e $(basename $@)/Makefile ] ; then \
            $(MAKE) -C $(basename $@) clean ;\
    fi 

clean: $(ALL_MOD_CLEAN)
    $(E) "cleaning complete: " $(ALL_MOD)