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包
    含进来,于是新的依赖关系生效了。

  • 相关阅读:
    一致性哈希算法
    Discourse 的标签(Tag)只能是小写的原因
    JIRA 链接 bitbucket 提示错误 Invalid OAuth credentials
    JIRA 如何连接到云平台的 bitbucket
    Apache Druid 能够支持即席查询
    如何在 Discourse 中配置使用 GitHub 登录和创建用户
    Apache Druid 是什么
    Xshell 如何导入 PuTTYgen 生成的 key
    windows下配置Nginx支持php
    laravel连接数据库提示mysql_connect() :Connection refused...
  • 原文地址:https://www.cnblogs.com/bigbigtree/p/2978135.html
Copyright © 2011-2022 走看看