Makefile小结

预处理:gcc -E hello.c -o hello.i
    1.展开宏定义(#define)
    2.处理所有条件预编译指令(#if、#ifdef、#else、#else if、#endif)
    3.处理#include预编译指令,将被包含的文件插入到该项预编译指令当中(递归执行)
    4.删除所有的注释
    5.保留所有#progrma编译器指令,因为编译器需要使用它们
编译:编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。
    gcc -S hello.i -o hello.s
汇编:汇编器是将汇编代码转变成机器可以执行的代码
    gcc -c hello.s -o hello.o
链接:生成可执行文件(地址和空间分配、符号决议、重定位)
    ld -static /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.9/crtbeginT.o -L/usr/lib/gcc/x86_64-linux-gnu/4.9 -L/usr/lib -L/lib hello.o --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/4.9/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o

Makefile书写规则

targets : prerequisites
    command \
	command
    ...

一、文件搜索

  1. VPATH = src:…/headers (当前目录、src、…/headers)

  2. vpath %.h …/headers make在“…/headers”目录下搜索所有以 .h 结尾的文件。(如果某文件在当前目录没有找到的话)

二、伪目标

.PHONY : clean
clean :
    rm *.o temp

三、静态模式

foo.o : foo.c
	$(CC) -c $(CFLAGS) foo.c -o foo.o
	
bar.o : bar.c
	$(CC) -c $(CFLAGS) bar.c -o bar.o

等价于下面

objects = foo.o bar.o

all : $(objects)

objects : %.o : %.c
	$(CC) -c $(CFLAGS) %< -o %@

四、显示命令

  1. @echo

  2. -n 或 --just-print ,那么其只是显示命令,但不会执行命令

  3. -s 或 --silent 或 --quiet 则是全面禁止命令的显示

五、命令执行

当前目录,而不是 /home/hchen目录

exec:
	cd /home/hchen
	pwd

/home/hchen目录

exec:
	cd /home/hchen; pwd
  1. 用;分割
  2. -(在Tab键之后),标记为不管命令出不出错都认为是成功的
  3. -i 或是 --ignore-errors 参数,那么,Makefile中所有命令都会忽略错误
  4. -k 或是 --keep-going ,这个参数的意思是,如果某规则中的命令出错了,那么就终止该规则的执行,但继续执行其它规则

六、变量

定义变量:

  1. = 右侧中的变量不一定非要是已定义好的值,其也可以使用后面定义的值
  2. := 前面的变量不能使用后面的变量,只能使用前面已定义好了的变量
  3. FOO ?= bar,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做

变量值的替换:
我们可以替换变量中的共有的部分,其格式是 $(var:a=b) 或是 ${var:a=b} ,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符”。

foo := a.o b.o c.o
bar := $(foo:.o=.c)

这个示例中,我们先定义了一个 $(foo) 变量,而第二行的意思是把 $(foo) 中所有以 .o 字串“结尾”全部替换成 .c ,所以我们的 $(bar) 的值就是“a.c b.c c.c”。与下面静态模式的替换效果一样。

foo := a.o b.o c.o
bar := $(foo:%.o=%.c)

七、条件判断

ifeq、ifneq、ifdef、ifndef

八、函数

$( )
就是函数名, 为函数的参数,参数间以逗号 , 分隔,而函数名和参数之间以“空格”分隔。函数调用以 $ 开头,以圆括号或花括号把函数名和参数括起。
字符串处理函数:
字符串替换函数:   ( s u b s t < f r o m > , < t o > , < t e x t > ) 模 式 字 符 串 替 换 函 数 : (subst <from>,<to>,<text>) 模式字符串替换函数: (subst<from>,<to>,<text>)(patsubst ,, )       
( p a t s u b s t 去 空 格 函 数 :         (patsubst %.c,%.o,x.c.c bar.c) x.c.o bar.o 去空格函数:     (patsubst(strip )
去掉字符串开头和结尾的空格
查找字符串函数:   ( f i n d s t r i n g < f i n d > , < i n > )                   在 字 符 串 < i n > 中 查 找 < f i n d > 字 符 串 。 如 果 找 到 返 回 < f i n d > , 未 找 到 返 回 空 字 符 串 过 滤 函 数 :           (findstring <find>,<in>)           在字符串<in>中查找<find>字符串。如果找到返回<find>,未找到返回空字符串 过滤函数:      (findstring<find>,<in>)<in><find><find>(filter <pattern…>, )
          以模式过滤 字符串中的单词,保留符合模式的单词。可以有多个模式
反过滤函数:     ( f i l t e r − o u t < p a t t e r n . . . > , < t e x t > )                   去 除 符 合 < p a t t e r n > 模 式 的 单 词 , 可 以 有 多 个 < p a t t e r n > 模 式 排 序 函 数 :           (filter-out <pattern...>,<text>)           去除符合<pattern>模式的单词,可以有多个<pattern>模式 排序函数:      (filterout<pattern...>,<text>)<pattern><pattern>(sort )   升序
取单词函数:     ( w o r d < n > , < t e x t > ) 取 < t e x t > 第 n 个 单 词                     (word <n>,<text>) 取<text>第n个单词            (word<n>,<text>)<text>n(wordlist ,, )         取 从到的单词
单词个数统计函数:  ( w o r d s < t e x t > ) 首 单 词 函 数 :         (words <text>) 首单词函数:     (words<text>)(firstword )
文件名操作函数:
取目录函数:      ( d i r < n a m e s . . . > )                                     从 文 件 名 序 列 < n a m e s > 中 取 出 目 录 部 分 取 文 件 名 函 数 :       (dir <names...>)                   从文件名序列 <names> 中取出目录部分 取文件名函数:    (dir<names...>)<names>(notdir <names…>)
          从文件名序列 中取出非目录部分
取后缀函数:     ( s u f f i x < n a m e s . . . > )                     从 文 件 名 序 列 < n a m e s > 中 取 出 各 个 文 件 名 的 后 缀 部 分 取 前 缀 函 数 :         (suffix <names...>)           从文件名序列 <names> 中取出各个文件名的后缀部分 取前缀函数:     (suffix<names...>)<names>(basename <names…>)
          从文件名序列 中取出各个文件名的前缀部分
加后缀函数:     ( a d d s u f f i x < s u f f i x > , < n a m e s . . . > )                     把 后 缀 < s u f f i x > 加 到 < n a m e s > 中 的 每 个 单 词 后 面 加 前 缀 函 数 :         (addsuffix <suffix>,<names...>)           把后缀 <suffix> 加到 <names> 中的每个单词后面 加前缀函数:     (addsuffix<suffix>,<names...>)<suffix><names>(addprefix ,<names…>)
          把前缀 加到 中的每个单词后面
连接函数:     $(join ,)
          把 中的单词对应地加到 的单词后面
origin函数:告诉变量从哪里来
shell函数
自动化变量
$@:目标文件名
$^:所有依赖的文件列表,使用空格分隔。如果目标文件是静态库文件,它所代表的只能是所有的库成员(.o文件)名。如果在依赖目标中有多个重复的,那么这个变量会去除重复的依赖目标,只保留一份。
$+:这个变量很像 $^ ,也是所有依赖目标的集合。只是它不去除重复的依赖目标
$<:第一个依赖的文件名
$?:所有比目标文件更新的依赖文件列表,空格分隔。如果目标文件是静态库文件,代表的是库文件
$%:当目标文件是一个静态库文件时,代表静态库的一个成员名

九、实例

作者:程序员良许
链接:https://www.zhihu.com/question/55488701/answer/600769671
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

VERSION = 1.0.0     #程序版本号  
​
SOURCE = $(wildcard ./src/*.c)  #获取所有的.c文件  
OBJ = $(patsubst %.c, %.o, $(SOURCE))   #将.c文件转为.o文件  
INCLUDES = -I./h    #头文件路径  
​
LIBS = -ldylib      #库文件名字  
LIB_PATH = -L./lib  #库文件地址  
​
DEBUG = -D_MACRO    #宏定义  
CFLAGS = -Wall -c   #编译标志位  
​
TARGET = app  
CC = gcc  
​
$(TARGET): $(OBJ)     
    @mkdir -p output/   #创建一个目录,用于存放已编译的目标  
    $(CC) $(OBJ) $(LIB_PATH) $(LIBS) -o output/$(TARGET).$(VERSION)  
​
%.o: %.c  
    $(CC) $(INCLUDES) $(DEBUG) $(CFLAGS) $< -o $@  
​
.PHONY: clean  
clean:  
    rm -rf $(OBJ) output/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值