Che*_*evy 11 makefile gnu-make auto-generate
所以我遵循了高级自动依赖生成论文 -
Makefile:
SRCS := main.c foo.c
main: main.o foo.o
%.o: %.c
$(CC) -MMD -MG -MT '$@ $*.d' -c $< -o $@
cp $*.d $*.tmp
sed -e 's;#.*;;' -e 's;^[^:]*: *;;' -e 's; *\\$$;;' \
-e '/^$$/d' -e 's;$$; :;' < $*.tmp >> $*.d
rm $*.tmp
clean::
-rm *.o *.d main
-include $(SRCS:.c=.d)
Run Code Online (Sandbox Code Playgroud)
main.c:
#include "foo.h"
int main(int argc, char** argv) {
foo() ;
return 0 ;
}
Run Code Online (Sandbox Code Playgroud)
foo.h:
#ifndef __FOO_H__
#define __FOO_H__
void foo() ;
#endif
Run Code Online (Sandbox Code Playgroud)
- 它就像一个魅力.
但是当foo.h成为生成的文件时 -
Makefile文件:
...
HDRS := foo.h
$(HDRS):
mk_header.sh $*
clean::
-rm $(HDRS)
...
Run Code Online (Sandbox Code Playgroud)
mk_header.sh:
#!/bin/bash
UP=$(tr "[:lower:]" "[:upper:]" <<< $1)
cat <<EOF > $1.h
#ifndef __${UP}_H__
#define __${UP}_H__
void $1() ;
#endif
EOF
Run Code Online (Sandbox Code Playgroud)
我第一次运行make,main.d尚未生成,因此foo.h不被视为先决条件,因此未生成:
$ ls
foo.c main.c Makefile mk_header.sh*
$ make
cc -MMD -MG -MT 'main.o main.d' -c main.c -o main.o
cp main.d main.tmp
sed -e 's;#.*;;' -e 's;^[^:]*: *;;' -e 's; *\\$;;' \
-e '/^$/d' -e 's;$; :;' < main.tmp >> main.d
rm main.tmp
cc -MMD -MG -MT 'foo.o foo.d' -c foo.c -o foo.o
cp foo.d foo.tmp
sed -e 's;#.*;;' -e 's;^[^:]*: *;;' -e 's; *\\$;;' \
-e '/^$/d' -e 's;$; :;' < foo.tmp >> foo.d
rm foo.tmp
cc main.o foo.o -o main
$ ls
foo.c foo.d foo.o
main* main.c main.d main.o
Makefile mk_header.sh*
Run Code Online (Sandbox Code Playgroud)
仅在第二次调用时make,foo.h生成,因此另一个构建级联.
$ make
./mk_header.sh foo
cc -MMD -MG -MT 'main.o main.d' -c main.c -o main.o
cp main.d main.tmp
sed -e 's;#.*;;' -e 's;^[^:]*: *;;' -e 's; *\\$;;' \
-e '/^$/d' -e 's;$; :;' < main.tmp >> main.d
rm main.tmp
cc main.o foo.o -o main
$ ls
foo.c foo.d foo.h foo.o
main* main.c main.d main.o
Makefile mk_header.sh*
Run Code Online (Sandbox Code Playgroud)
只有在那之后才make意识到:
$ make
make: `main' is up to date.
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:是否有办法扩展上述文件所建议的配方,以允许生成的头文件,而不会消除通过在包含*.d片段时不必重新评估整个make树而实现的性能增益?
Che*_*evy 12
问题是*.d必须在所有标头生成完成后执行Makefile-fragments生成.以这种方式,可以使用make依赖项强制正确的顺序:
SRCS := main.c foo.c
HDRS := foo.h
main: main.o foo.o
%.o: %.c | generated_headers
$(CC) -MMD -MG -MT '$@ $*.d' -c $< -o $@
cp $*.d $*.tmp
sed -e 's;#.*;;' -e 's;^[^:]*: *;;' -e 's; *\\$$;;' \
-e '/^$$/d' -e 's;$$; :;' < $*.tmp >> $*.d
rm $*.tmp
-include $(SRCS:.c=.d)
$(HDRS):
mk_header.sh $*
generated_headers: $(HDRS)
clean:
-rm $(HDRS) *.o *.d main
.PHONY: clean generated_headers
Run Code Online (Sandbox Code Playgroud)
笔记:
我使用仅限订单的依赖项.
此解决方案具有相当的可扩展性:每个生成标头规则只需要是generated_headers .PHONY目标的先决条件.假设标题生成规则被正确写入,一旦正确生成,满足generated_headers目标应该是无操作.
无法编译单个对象,即使该对象不需要任何生成的头,也不能首先生成项目的所有生成的头.虽然这在技术上是合理的,但您的开发人员会抱怨.
所以你应该考虑有一个FAST_AND_LOOSE标志,这将关闭此功能:
%.o: %.c | $(if $(FAST_AND_LOOSE),,generated_headers)
...
Run Code Online (Sandbox Code Playgroud)
因此,开发人员可以发出:
make FAST_AND_LOOSE=1 main.o
Run Code Online (Sandbox Code Playgroud)