• makefile 使用学习,小白入门~


    Title:makefile 学习

    0 吐槽

    发现自己一年没更新博客了,掏出存货来刷一下存在感 ( ̄▽ ̄)“…
    主要原因 是:① 忙于实习;② 懒于撰稿;③ 完美主义越来越强,note回看就修订觉得发不出手、过半个月回看又修订还是发不出手,结果懒得发了… ( ̄▽ ̄)”
    先随手发;之后本地修订后,再回来改线上的吧~

    1 Basic Concept

    1.1 是什么

    make是GNU里的一个utility,可实现方便的自动化编译,在unix和linix都可以写;
    首先要写一个文本叫 makefile,然后调用命令make,terminal即会按makefile的内容对工程或源文件进行 re-compile or link;
    makefile中写的内容,表示的是 how、when对什么文件进行remake,从而让我们后续可以方便的 “一键remake”。

    • windows下的make

      一般默认make是Unix OS下;

      若是windows下,得看IDE——Delphi是用make,VC++用nmake;

      windows下要想make就得下载MinGW编译器了( ̄▽ ̄)".

    1.2 compile 和 link

    makefile可以compile也可以link.

    1. 源码compile(检查语法,有函数声明即可通过)后得到中间文件(windows是.obj、UNIX是.o);
    2. 对中间文件进行打包得到库文件(windows是.lib、UNIX是.a Archive File);
    3. 把它们link(合成一坨一个可执行文件)——链接函数和全局变量等,找不到函数实现就会出现link error——得到可执行文件(windows是.exe、UNIX无后缀);

    1.3 怎么用make

    • ①用make,会自动按顺序寻找文件 GNUmakefile、makefile、Makefile,若当前目录没有makefile,那会自动创建一个。

    • ②手动指定执行makefile文件(很少用,一般直接make)

      make -f <...makefile>

    1.4 makefile 与 shell

    • makefile和shell的区别

      作用:shell是为了重用terminal内的命令服务的;makefile是用于工程compile/link用的;makefile内可调用shell脚本,如:+ ./xxx.sh

      写法

      1. shell内 =号不允许有空格,makefile内 =号空格无碍;
      2. shell内开头要写 #!/bin/bash,后缀名是.sh
      3. shell内是自上而下执行,有数组、循环等;makefile内执行shell命令是一行独立一个进程,若想一个进程统一执行,得在末尾用 \ 表同一行。
      4. shell内通配符:*;makefile内通配符:%
      5. shell内变量用 {},命令串用 ();makefile中访问变量用 $()${} 都行;
    • shell与cshell的区别

      linux下提供了很多种shell: (简称sh)、C-Shelll(简称csh)、Korn Shell(简称ksh)和Bourne Again Shell (简称bash)。

      1. Bourne Shell,文件后缀 .sh,是Unix的默认shell,也是其他shell的基础;性能好,但用户交互低;
      2. C shell,文件后缀 .csh,语法类似C,提供了 .sh 没有的用户交互功能——命令补全、命令别名等;与 .sh 不兼容;
      3. Korn Shell:文件后缀 .ksh,结合了 .sh.csh的优点,并向下兼容了 .sh
      4. Bourne Again Shell,即bash,是Linux的默认shell,结合了以上 .sh.csh.ksh 的优点,并向下兼容了 .sh最强

    2 语法

    2.1 基本格式⭐️

    目标target:   所需prerequisites
    (TAB) command (任意的Shell命令)
    	
    label:
    (TAB) command...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 要注意 =号的空格无碍;tab很关键,和python一样;
    2. 若target不是实体存在的文件,而是个虚名label,那么makefile不会自动执行,需要make + label 名 才会主动去执行。
    3. make 触发执行makefile后,make会检查 各prerequisite的更新日期,若比target新,就重新执行此句命令。
    4. makefile会把第一个target作为编译目标,然后逐层迭代的判断是是否需要更新所需的 prerequisites. 其他的target或者label,需要自己调用 make label 来单独执行。
    5. .o 文件与自身相关的 .h.c 文件的prerequisites可省略,因为会自动补充;
    6. 养成好习惯,自己写一个 clean label,删除所有中间、执行文件,日后用 make clean 就能起到复位的作用;
      • clean label内,务必用 rm -rf 而不是 rm,不然报错一句,后续clean都不执行了!

    2.2 常用Case ⭐️

    • makefile的触发条件

      ① prerequisite比target要新;

      ② 或者 prerequisite不存在;

      所以,若target的A不是实物,永远不会生成,则此语句每次make都 必会被调用

      B = ?
      C = ?
      	# B和C是具体的文件,A只是抽象的程序tag无对应实体文件
      A: B C
      	B -o C	#和A没关系,A永远不会生成,故此语句必执行
      
      • 1
      • 2
      • 3
      • 4
      • 5

      也可以有多个抽象的程序块,如下:

      all: do1 do2 do3
      
      do1: A B C
      	...balabala...
      do2: E F
      	...balabala...
      do3:
      	...balabala...
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • makefile中 .PHONY 的学习

      考虑以上makefile的case情况,若在倒霉的、在写完makefile后,忘了,本地出现了一个文件或文件夹的名称也叫做 A ! 那完犊子,按makefile的规则,A被检测到,且prerequisite B、C并不是比 A 要新的话,这个makefile就不会执行了

      总结:makefile中的无文件抽象target因本地同名文件/文件夹的存在,无法“抽象”,使得makefile无法如意愿执行。

      Solution在A前面加上 .PHONY (类似关键字的感觉),声明此A是抽象的,别去检索是否存在同名文件啦!

      即:(makefile目录下,有同名文件A,也会执行!)

      B = ?
      C = ?
      
      .PHNONY:  A 	#声明A是phony抽象的
      A: B C
      	B -o C	#和A没关系,A永远不会生成,故此语句必执行
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      .PHONY 只是一个声明,不会影响后续label的执行的。

    2.3 细节语法

    • target和prerequisite的数量

      至少一个target:target是一个东西或事件、自定义函数名。最好加个注释说明一下是啥;

      可以0~n个prerequisite:prerequisite是前置文件,可用通配符 *

    • 行注释 #

    • 行续写,于行尾/ , 表多行代码用一个进程执行;

      makefile内写的程序默认一行一个进程执行,故需要将程序串行执行,得自己加 /

      :注释也可用 / 进行续写;使用 / 后会读取“空行”,故下一行别接注释!

    • 宏定义 Macro define

      • 定义等号=pi=3.14可嵌套大小敏感
      • 使用$(宏名)
      • 常用系统宏:
        • $@,当前target
        • $<,第一个条件的名字
        • $?, 所有条件中 比 当前target更newer的 民名字
        • $^, 所有条件的名字
        • $(MAKE),就是预设的 make命令
    • define

      即多行版本的宏定义

      define 宏名
      	...
      	...
      endef
      
      • 1
      • 2
      • 3
      • 4
    • include

      导入别的makefile(类似导入库),文件名语法可用正则表达和shell.

      若多个导入的makefile库内,出现 target冲突,取最后一行定义为准

    • 正则表达式,

      如:通配符等—— *, [], ?,@, @好像是让系统回话功能闭嘴,干净。

    • Reference

      此博客不错:Makefile教程(绝对经典,所有问题看这一篇足够了)—— GUYUEZHICHENG

  • 相关阅读:
    Kali 无法联网的解决方案,优雅的配置桥接模式
    Ubuntu20.04 搭建L2TP+IPsec环境
    数字图像处理笔记(一)基础内容
    通过Nacos配置刷新进行RabbitMQ消费者在线启停
    六、Echart图表 之 tooltip提示框组件配置项大全
    RabbitMQ(五) | MQ集群搭建、部署、仲裁队列、集群扩容
    【JavaEE】多线程(Part3线程安全)
    前端页面设计 | 博客系统
    PCL RANSAC分割提取多个空间圆
    【Linux成长史】Linux编辑器-gcc/g++使用
  • 原文地址:https://blog.csdn.net/Hide_in_Code/article/details/125890413