【Linux】makefile 使用学习,小白入门~

Title:makefile 学习

0 吐槽

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

1 Basic Concept

1.1 是什么

make是GNU里的一个utility,可实现方便的自动化编译,在unix和linix都可以写;
首先要写一个文本叫 makefile,然后调用命令make,terminal即会按makefile的内容对工程或源文件进行 re-compile or link;

makefile作用是对bash等命令进行方便地一键重用,故可以用makefile进行compile、link、simulation、执行程序等都可以,反正要执行什么 bash 指令自定义写进去就完事儿了;

makefile中写的内容,表示的是 how、when对什么文件进行什么操作,从而让我们后续可以方便的 “一键remake”。

1.2 OS概念复习

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

一般默认 make是Unix OS下;

若是windows下,得看IDE——Delphi是用make,VC++用nmake;
windows下要想make就得下载MinGW编译器了.

1.3 怎么用make

  • ①terminal中敲 make,OS会自动按顺序寻找文件 GNUmakefilemakefileMakefile

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

    make -f <...makefile>

1.4 makefile 与 shell

  • makefile和shell的区别

    作用:shell是为了重用terminal内的命令服务的,是系统程序员与OS内核的交互接口;makefile是用于工程compile/link用的;makefile内可写shell命令、调用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. 要注意 =号的空格无碍;tab很关键,和python一样;
  2. make 触发执行makefile后,make会检查 各prerequisite的更新日期,若比target新,就重新执行此句的命令
  3. makefile会把第一个target作为编译目标,然后逐层迭代的判断是是否需要更新所需的 prerequisites. 其他没被牵扯到的target或者label,需要自己调用 make label 来单独执行。
  4. 若target不是实体存在的文件而是个虚名,那它称呼为**label**,label后面的prerequisites不用加文件名,因为target是个label的话压根就没有实体文件给你比日期,写文件也没啥用;
    一般label后面的prerequisites也写label;那此时若make target就会先去make prerequisites里的label,嵌套执行,就当成函数好了.
  5. .o 文件与自身相关的 .h.c 文件的prerequisites可省略,因为会自动补充;
  6. 养成好习惯,自己写一个 clean label,用于删除上一次调用make后产生的所有中间、执行文件,日后用 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永远不会生成,故此语句必执行
    

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

    all: do1 do2 do3	# 四个label
    
    do1: A B C
    	...balabala...
    do2: E F
    	...balabala...
    do3:
    	...balabala...
    
  • makefile中 .PHONY 的学习

    考虑以上makefile的case,会出现这样的问题:
    若在写完makefile后,本地恰巧出现了个文件或文件夹的名称也叫做 A ! 那按makefile的规则,由于A被检测到文件存在,且prerequisite B、C并不是比 A 要新的话,此行makefile就不会执行了

    总结:makefile中的target字段本该是无实体文件的抽象label,却因本地存在同名文件/文件夹,使此行makefile无法如意执行。

    Solution在A前面加上 .PHONY (可以理解为关键字),声明此A就是label、不是实体文件,别去检索当前路径下是否存在同名文件啦!之后,即使makefile目录下有同名文件A,makefile也会按label进行处理此target.

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

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

2.3 细节的其他makefile语法

  • target和prerequisite的数量

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

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

  • 行注释 #

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

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

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

  • 宏定义 Macro define

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

    即多行版本的宏定义

    define 宏名
    	...
    	...
    endef
    
  • include

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

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

  • 正则表达式,

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

  • Reference

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值