zoukankan      html  css  js  c++  java
  • 【Makefile】3-Makefile书写规则


    前言

    • 本笔记主要记录Makefile一些概念要点。
    • 本笔记为提取性笔记,章节与《跟我一起写Makefile》同步,所以会看到有些小标题会跳过。

    概念

    Chapter 3:书写规则

    3.3 在规则中使用通配符

    • make 支持三个通配符:
      • *
        • 任意长度的任意字符
        • 长度为一的任意字符
      • ~以例子说明
        • ~/test
          • 表示当前用户的 $HOME 目录下的 test 目录
        • ~lzm/test
          • 表示用户为 lzm 的宿主目录下的 test 目录
          • 若用户没有宿主目录,则根据环境变量 HOME 而定。

    举例

    • 例子1
      • 变量 objects 表示当前目录下所有的 .o 文件。
    objects := $(wildcard *.o)
    
    • 例子2 *
      • :这里的变量 objects 表示的就是 *.o,因为就像 C语言 的宏。
    objects = *.o
    
    • 例子3 *
      • 列出当前所有 .c 文件对应的 .o 文件。
      • 下面的 *,是make的 * ,% 是makefile的 % ,具体看函数定义。
    $(patsubst %.c,%.o,$(wildcard *.c))
    

    3.4 文件搜索

    • VPATH 变量
      • Makefile 文件会在当前目录下寻找依赖文件和目标文件,在找不到的情况下就在 VPATH 变量中指定的路径去找。
    VPATH = src:../headers
    
    * 上面例子中就是 **VPATH** 的格式,用 **:** 隔开多个路径。
    
    • vpath 关键字
      • vpath 关键字比 VPATH 变量更加灵活, vpath 可以指定不同的文件在不同的搜索目录中。
      • 使用方法有三种:
        1. vpath 在 。为符合模式 的文件指定搜索目录 (多个目录可以用空格或者 : 分开)。
        2. vpath 清除符合模式 的文件的搜索目录。
        3. vpath 清除所有已被设置好了的文件搜索目录。
    vpath %.h include    //指定.h类型文件的搜索路径是include
    

    3.8 自动生成依赖性

    在 Makefile 中,我们的依赖关系可能会需要包含一系列的头文件,比如,如果我们的 main.c 中有一 句 #include "defs.h" ,那么我们的依赖关系应该是:

    main.o : main.c defs.h
    

    大多数的 C/C++ 编译器都支持一个“-M”的 选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系。例如,如果我们执行下面的命令:

    cc -M main.c
    

    其输出是:

    main.o : main.c defs.h
    

    ** 注:如果使用 GNU 的 C/C++ 编译器,得用 -MM 参数,不然,-M 参数会把一些标准库的头文件也包含进来。 **
    如:
    gcc -M main.c 的输出是:

    main.o: main.c defs.h /usr/include/stdio.h /usr/include/features.h 
                                /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h  
                                /usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h  
                                /usr/include/bits/types.h /usr/include/bits/pthreadtypes.h  
                                /usr/include/bits/sched.h /usr/include/libio.h  
                                /usr/include/_G_config.h /usr/include/wchar.h  
                                /usr/include/bits/wchar.h /usr/include/gconv.h  
                                /usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h  
                                /usr/include/bits/stdio_lim.h
    

    gcc -MM main.c 的输出则是:

    main.o : main.c defs.h
    

    原理 *

    • 隐晦规则(其中之一)
      • 会自动生成 gcc -c *.c 等语句。
        • 如果使用了该 隐晦规则 规则,在不改变 源文件 的情况下,改变其它(如头文件),再去运行 make 命令,是不会干活的。

    如果想使用 隐晦规则 + 依赖自动包含头文件,可以往下看。

    • gcc -MM main.c
      • 会在 makefile 的依赖上自动添加 main.c 包含的头文件。

    基于上面这个原理,我们可以把 main.c 包含的头文件 信息 自动识别出来并保存到 main.d 文件中。
    这时候,.d 文件就出来了。

    直接解析例子 **
    • 头文件改变,make也会干活。
    • 该脚本实现了,.c 文件编译过程中,产生 .d 文件。
    %.d : %.c
        @set -e;rm -f $@;  
        $(CC)  -MM $(CPPFLAGS) $< > $@.;  
        sed 's,$∗.o[ :]*,1.o $@ : ,g' < $@. > $@;  
        rm -f $@.
    

    参考

    • 源码解析
      • set -e;
        • 表示 直接在命令行模式上进行 sed 动作编辑,其实此为默认选项
      • rm -f $@;
        • 表示 删除所有目标文件,即是删除所有 .d 文件。
      • $(CC)  -MM $(CPPFLAGS) $< > $@.;
        • 表示 编译产生的一些标注库的头文件信息保存到 .d.xxx 随机文件中。
        • $@.
          • 表示后缀为随机的意思。
        • 假设 CC= gcc ,CPPFLAGS=空,即 gcc -MM main.c > main.d.xxxx
          • > 表示重定向的意思。
          • 即是把 main.c 所依赖的头文件信息写入 main.d.xxxx 文件。如
    main.o: main.c defs.h
    
        * **sed 's,$∗.o[ :]*,1.o $@ : ,g' < $@. > $@;**
            * 表示执行linux 命令 sed
            * **< $@.**
                * 该文件内容交给前面,让 sed 语句处理
            * **$∗.o[ :]***
                * 为匹配字段
                * 表示 main 后面 .o 接着的字串段
            * **$∗.o[ :]***
                * 为替换字段
            * **$@. > $@**
                * 输入给 .d 文件,即是 main.d,内容如下:
    
    main.o main.d : main.c defs.h
    
            * **rm -f $@.**
                * 删除 main.d.xxxx 的随机文件。
    
    • 生成 .d 文件后,Makefile 文件可以 include 该文件进入 Makefile 中,这样, .o .d 都是目标文件,后面有很多依赖的头文件,一旦头文件更新,目标文件便会更新
    sed 命令
    • 要点格式,具体百度
    • sed 为linux命令,用于替换。
    sed‘s:/usr/local:/usr:g’
    
    • s: 就是于把 : 当作分隔符 /
    sed‘s;/usr/local;/usr;g’
    
    • s; 就是于把 ; 当作分隔符 /

    参考

    书籍

    • 《GUN Makefile》
    • 《跟我一起写Makefile》
  • 相关阅读:
    RUNOOB.COM-python网络编程-(python3.5.0)
    windows查看服务
    计算机网络里的一些理解
    如果面试有傻逼问道oracle怎么启动的
    推荐一个学习数据库的地方
    电脑中的驱动程序是什么,是干什么的
    Raspberry Pi 4B 之 Python开发
    Ubuntu20.04+EdgexFoundry边缘计算微服务搭建-----遇到的问题-----make build 被墙问题
    Raspberry Pi 4B + Ubuntu 20.04 server for arm64 的wifi配置
    关于PicoNeo开发环境的Unity3D+AndroidSDK配置
  • 原文地址:https://www.cnblogs.com/lizhuming/p/13811184.html
Copyright © 2011-2022 走看看