makefile - GNU 制作 : Generating automatic dependencies with generated header files

标签 makefile auto-generate gnu-make

所以我关注了Advanced Auto-Dependency Generation纸 -

生成文件:

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)

主文件:
#include "foo.h"

int main(int argc, char** argv) {
  foo() ;
  return 0 ;
}

foo.h:
#ifndef __FOO_H__
#define __FOO_H__

void foo() ;

#endif

- 它就像一个魅力。

但是当 foo.h成为生成的文件——

生成文件:
...

HDRS := foo.h

$(HDRS):
    mk_header.sh $*

clean::
    -rm $(HDRS)
...

mk_header.sh:
#!/bin/bash
UP=$(tr "[:lower:]" "[:upper:]" <<< $1)

cat <<EOF > $1.h
#ifndef __${UP}_H__
#define __${UP}_H__

void $1() ;

#endif
EOF

第一次跑 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*

仅在 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*

只有在那之后make意识到:
$ make
make: `main' is up to date.

所以我的问题是:有没有一种方法可以扩展上面论文中建议的配方,以允许生成头文件,而不会消除由于在包含 *.d 时不必重新评估整个 make 树而实现的性能提升。碎片?

最佳答案

问题在于*.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

备注:
  • 我使用 order-only dependency .
  • 这个解决方案是相当可扩展的:每个生成头规则,只需要是 generated_headers 的先决条件。 .PHONY目标。假设header生成规则写得正确,一旦生成正确,满足generated_headers目标应该是一个空操作。
  • 不能编译单个对象,即使该对象不需要任何生成的头文件,而不会生成 全部 首先生成项目的标题。虽然这在技术上是合理的,但您的开发人员会提示。

    所以你应该考虑拥有一个 FAST_AND_LOOSE标志,这将关闭此功能:
    %.o: %.c | $(if $(FAST_AND_LOOSE),,generated_headers)
        ...
    

    因此,开发人员可能会发出:
    make FAST_AND_LOOSE=1 main.o
    
  • 关于makefile - GNU 制作 : Generating automatic dependencies with generated header files,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5229561/

    相关文章:

    makefile - 什么 makefile 延迟评估规则控制这种行为?

    makefile - 大型项目的 FORTRAN Makefile

    c++ - 构建 GLib 时出错

    makefile - MinGW Make 导致 StackDumps

    linux - 改进从命令行向 .bashrc 添加别名的功能

    database - 如何使用具有起始值的自动生成功能生成 hibernate ID

    Makefile 忽略段错误

    linux - Makefile 变量替换显然没有完成,即使 := is used in declaration

    c++ - 使文件无法打开 header

    c# - 禁用designer.cs中的自动更改