zoukankan      html  css  js  c++  java
  • makefile(摘自linux_c编程一站式学习)

    GNU make 的官方手册建议这样写:


    all: main
    main: main.o stack.o maze.o
    gcc $^ -o $@
    clean:
    -rm main *.o
    .PHONY: clean
    sources = main.c stack.c maze.c
    include $(sources:.c=.d)
    %.d: %.c
    set -e; rm -f $@; \
    $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
    rm -f $@.$$$$

    sources 变量包含我们要编译的所有.c 文件,$(sources:.c=.d)是一个变量替换语法,把sources 变
    量中每一项的.c替换成.d,所以include这一句相当于:


    include main.d stack.d maze.d


    类似于C语言的#include 指示,这里的include表示包含三个文件main.d、stack.d和maze.d,这三
    个文件也应该符合Makefile的语法。如果现在你的工作目录是干净的,只有.c文件、.h文件
    和Makefile ,运行make 的结果是:


    $ make
    Makefile:13: main.d: No such file or directory
    Makefile:13: stack.d: No such file or directory
    Makefile:13: maze.d: No such file or directory
    set -e; rm -f maze.d; \
    cc -MM maze.c > maze.d.$$; \
    sed 's,\(maze\)\.o[ :]*,\1.o maze.d : ,g' < maze.d.$$ >
    maze.d; \
    rm -f maze.d.$$
    set -e; rm -f stack.d; \
    cc -MM stack.c > stack.d.$$; \
    sed 's,\(stack\)\.o[ :]*,\1.o stack.d : ,g' < stack.d.$$ >
    stack.d; \
    rm -f stack.d.$$
    set -e; rm -f main.d; \
    cc -MM main.c > main.d.$$; \
    sed 's,\(main\)\.o[ :]*,\1.o main.d : ,g' < main.d.$$ >
    main.d; \
    rm -f main.d.$$
    cc
    -c -o main.o main.c
    cc
    -c -o stack.o stack.c
    cc
    -c -o maze.o maze.c
    gcc main.o stack.o maze.o -o main


    一开始找不到.d文件,所以make 会报警告。但是make 会把include的文件名也当作目标来尝试更
    新,而这些目标适用模式规则%.d: %c,所以执行它的命令列表,比如生成maze.d的命令:


    set -e; rm -f maze.d; \
    cc -MM maze.c > maze.d.$$; \
    sed 's,\(maze\)\.o[ :]*,\1.o maze.d : ,g' < maze.d.$$ >
    maze.d; \
    rm -f maze.d.$$
     
    注意,虽然在Makefile中这个命令写了四行,但其实是一条命令,make 只创建一个Shell进程执行这
    条命令,这条命令分为5个子命令,用;号隔开,并且为了美观,用续行符\拆成四行来写。执行步骤为:


    1. set -e命令设置当前Shell进程为这样的状态:如果它执行的任何一条命令的退出状态非零则
    立刻终止,不再执行后续命令。


    2. 把原来的maze.d删掉。


    3. 重新生成maze.c的依赖关系,保存成文件maze.d.1234(假设当前Shell进程的id是1234)。注
    意,在Makefile中$有特殊含义,如果要表示它的字面意思则需要写两个$,所以Makefile中的
    四个$传给Shell变成两个$,两个$在Shell中表示当前进程的id,一般用它给临时文件起名,
    以保证文件名唯一。


    4. 这个sed 命令比较复杂,就不细讲了,主要作用是查找替换。maze.d.1234的内容应该
    是maze.o: maze.c maze.h main.h,经过sed 处理之后存为maze.d,其内容是maze.o maze.d:
    maze.c maze.h main.h。


    5. 最后把临时文件maze.d.1234删掉。
    不管是Makefile本身还是被它包含的文件,只要有一个文件在make 过程中被更新了,make 就会重新
    读取整个Makefile以及被它包含的所有文件,现在main.d、stack.d和maze.d都生成了,就可以正常
    包含进来了(假如这时还没有生成,make 就要报错而不是报警告了),相当于在Makefile中添了三
    条规则:


    main.o main.d:main.c main.h stack.h maze.h
    maze.o maze.d: maze.c maze.h main.h
    stack.o stack.d: stack.c stack.h main.h


    如果我在main.c中加了一行#include "foo.h",那么:


    1、main.c的修改日期变了,根据规则main.o main.d: main.c main.h stack.h maze.h要重新生
    成main.o和main.d。生成main.o的规则有两条:


    main.o: main.c main.h stack.h maze.h
    %.o: %.c
    # commands to execute (built-in):
    $(COMPILE.c) $(OUTPUT_OPTION) $<


    第一条是把规则main.o main.d: main.c main.h stack.h maze.h拆开写得到的,第二条是隐含规
    则,因此执行cc命令重新编译main.o。生成main.d的规则也有两条:


    main.d: main.c main.h stack.h maze.h
    %.d: %.c
    set -e; rm -f $@; \
    $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
    rm -f $@.$$$$
    因此main.d的内容被更新为main.o main.d: main.c main.h stack.h maze.h foo.h 。


    2、由于main.d被Makefile包含,main.d被更新又导致make 重新读取整个Makefile,把新的main.d包
    含进来,于是新的依赖关系生效了。

  • 相关阅读:
    kvm介绍
    正式班D24
    正式班D23
    正式班D21
    正式班D20
    正式班D19
    正式班D18
    正式班D17
    正式班D16
    正式班D15
  • 原文地址:https://www.cnblogs.com/bigbigtree/p/2978135.html
Copyright © 2011-2022 走看看