考虑以下Makefile
骨架:
HEADERS := $(shell find . -name "*.h" | sort)
SOURCES := $(shell find . -name "*.c" | sort)
OBJECTS := $(patsubst %.c, %.o, $(SOURCES))
executable: $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $(OBJECTS)
%.o: %.c
rm -f $@
$(CC) $(CFLAGS) -c -o $@ $< || { rm -f $@; exit 1; }
$(OBJECTS): Makefile $(HEADERS)
如果修改了以下任何文件,这些规则可确保重新编译OBJECTS
和executable
:
Makefile
本身这很好用。它还介绍了将新的源代码文件添加到项目目录的情况(假设新文件未使用cp -a
或mv
添加)。没有涉及的案例是删除文件。
删除时重新编译很有用,因为它会捕获剩余源代码中的剩余部分,因为它会从executable
中删除多余的数据。
从项目中删除源代码文件后,确保make
命令重建所有对象的简洁有效方法是什么?
答案可以通过$(shell ...)
使用任何常见的Linux命令。
答案 0 :(得分:1)
您可以创建一个列表文件(名称listfile
),其中包含标题和C
来源列表。如果您从源代码树中删除文件,则需要重新创建此listfile
。 listfile
应该是Makefile
中的依赖项。
HEADERS := $(shell find . -name "*.h" | sort)
SOURCES := $(shell find . -name "*.c" | sort)
OBJECTS := $(patsubst %.c, %.o, $(SOURCES))
executable: $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $(OBJECTS)
%.o: %.c
rm -f $@
$(CC) $(CFLAGS) -c -o $@ $< || { rm -f $@; exit 1; }
genlist:
find . -name \*.c -or -name \*.h > listfile
$(OBJECTS): Makefile $(HEADERS) listfile
.PHONY: genlist
删除后,您应该运行make genlist
。
当然你可以扩展这个想法:你将创建一个列表文件,每个make
将生成一个临时列表文件(例如使用mktemp
)并与&#34;官方& #34; listfile
。如果他们不同将覆盖&#34;官方&#34; listfile
- 删除后不必运行make genlist
。
答案 1 :(得分:1)
处理此问题的一种方法是使用现代自动生成的依赖项方法,例如described here。这些方法具有内置属性,可以正确处理已删除的文件。
如果您不想这样做,那么类似于@uzsolt建议的内容就是您需要做的事情,但如果您想避免需要明确地运行make genlist
,则必须发挥作用在make实现文件丢失之前:
HEADERS := $(shell find . -name "*.h" | sort)
SOURCES := $(shell find . -name "*.c" | sort)
OBJECTS := $(patsubst %.c, %.o, $(SOURCES))
executable: $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $(OBJECTS)
%.o: %.c
rm -f $@
$(CC) $(CFLAGS) -c -o $@ $< || { rm -f $@; exit 1; }
$(OBJECTS): Makefile $(HEADERS) sourcelist
sourcelist: FORCE
@for f in $(SOURCES) $(HEADERS); do echo "$$f"; done > $@.tmp
@[ `comm -23 $@ $@.tmp | wc -l` -eq 0 ] || mv $@.tmp $@
FORCE:
这里的想法是您将旧列表与新列表进行比较,并且只有在旧列表包含新列表不包含的内容时才修改列表。这确保除非删除某些内容,否则sourcelist
的时间戳不会更改,因此它不会强制对象文件过期。
答案 2 :(得分:1)
MadScientist提供的回复非常好(特别是使用现代自动生成的依赖方法)。
如果现代自动生成的依赖项方法不是一个选项,则使用echo
和cmp
的替代方法是使用make
使include
处理依赖项}和$(file ...)
(注意$(OBJECTS)
的额外依赖关系):
HEADERS := $(shell find . -name "*.h" | sort)
SOURCES := $(shell find . -name "*.c" | sort)
OBJECTS := $(patsubst %.c, %.o, $(SOURCES))
executable: $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $(OBJECTS)
%.o: %.c
rm -f $@
$(CC) $(CFLAGS) -c -o $@ $< || { rm -f $@; exit 1; }
$(OBJECTS): Makefile $(HEADERS) deps.mk
include deps.mk
deps.mk: $(HEADERS) $(SOURCES)
$(file >$@,$@: $(HEADERS) $(SOURCES))
$(file >>$@,$(HEADERS) $(SOURCES):)
这只是一个例子,行为的任何组合都是可能的。例如,如果您的要求是:
您可以使用MISSING
功能捕获filter-out
中已删除文件的列表:
HEADERS := $(shell find . -name "*.h" | sort)
SOURCES := $(shell find . -name "*.c" | sort)
OBJECTS := $(patsubst %.c, %.o, $(SOURCES))
executable: $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $(OBJECTS)
%.o: %.c
rm -f $@
$(CC) $(CFLAGS) -c -o $@ $< || { rm -f $@; exit 1; }
include missing.mk
ifneq (,$(MISSING))
$(MISSING):
endif
$(OBJECTS): Makefile $(HEADERS) $(MISSING)
missing.mk: $(MISSING) $(HEADERS) $(SOURCES)
$(file >$@,MISSING=$$(filter-out $$(HEADERS) $$(SOURCES),$(HEADERS) $(SOURCES)))
答案 3 :(得分:1)
每个人都建议生成辅助makefile。我非常支持这些建议。但是我更喜欢保持这个makefile的隔离生成。以下是将其保存在单个$(shell ...)命令中的解决方案:
THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST))
$(if $(shell find -name '*.h' -or -name '*.c' | \
awk '\
/.*\.h$$/ { h=h " " $$0 } \
/.*\.c$$/ { c=c " " $$0 } \
END { \
print "HEADERS :=" h; \
print "SOURCES :=" c \
}' > $(THIS_MAKEFILE).include.new && \
diff -q $(THIS_MAKEFILE).include.new $(THIS_MAKEFILE).include 2> /dev/null || mv $(THIS_MAKEFILE).include.new $(THIS_MAKEFILE).include),)
include $(THIS_MAKEFILE).include
OBJECTS := $(patsubst %.c, %.o, $(SOURCES))
executable: $(OBJECTS); $(CC) $(CFLAGS) -o $@ $(OBJECTS)
%.o: %.c; rm -f $@ && $(CC) $(CFLAGS) -c -o $@ $< || { rm -f $@; exit 1; }
$(OBJECTS): $(THIS_MAKEFILE) $(THIS_MAKEFILE).include $(HEADERS)
$(shell)
包含在$(if)
中以禁止其输出。
这个解决方案有一个$(shell)调用而不是两个,并且不依赖于相对较新的$(文件)GNU Make函数。
适合小型项目,但不能很好地扩展。