[TOC]
# 简介
makefile就像个shell命令一样.也可以执行一些命令
一般来说,大多数的IDE都有这个命令,
比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。
可见,makefile都成为了一种在工程方面的编译方法。
~~~
sudo apt install make -y
~~~
# 语法规则
**一条规则:**
> 目标:依赖文件列表
>
> 命令列表
Makefile基本规则三要素:
1)目标:
* 通常是要产生的文件名称,目标可以是可执行文件或其它obj文件,也可是一个动作的名称
2)依赖文件:
* 用来输入从而产生目标的文件
* 一个目标通常有几个依赖文件(可以没有)
3)命令:
* make执行的动作,一个规则可以含几个命令(可以没有)
* 有多个命令时,每个命令占一行
~~~
all:test1 test2
echo "hello all"
test1:
echo "hello test1"
test2:
echo "hello test2"
~~~
~~~
make -f Makefile
~~~
# 命令格式
make是一个命令工具,它解释Makefile 中的指令(应该说是规则)。
make命令格式:
make \[ -f file \]\[ options \]\[ targets \]
1.\[ -f file \]:
* make默认在工作目录中寻找名为GNUmakefile、makefile、Makefile的文件作为makefile输入文件
* \-f 可以指定以上名字以外的文件作为makefile输入文件
2.\[ options \]
* \-v: 显示make工具的版本信息
* \-w: 在处理makefile之前和之后显示工作路径
* \-C dir:读取makefile之前改变工作路径至dir目录
* \-n:只打印要执行的命令但不执行
* \-s:执行但不显示执行的命令
3.\[ targets \]:
* 若使用make命令时没有指定目标,则make工具默认会实现makefile文件内的第一个目标,然后退出
* 指定了make工具要实现的目标,目标可以是一个或多个(多个目标间用空格隔开)。
# 工作原理
1. 若想生成目标, 检查规则中的依赖条件是否存在,如不存在,则寻找是否有规则用来 生成该依赖文件

2. 检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有任一个被更新,则目标必须更新

**总结:**
* 分析各个目标和依赖之间的关系
* 根据依赖关系自底向上执行命令
* 根据修改时间比目标新,确定更新
* 如果目标不依赖任何条件,则执行对应命令,以示更新
# 例子
测试程序: `test.c add.c sub.c mul.c div.c`
**最简单的Makefile**
~~~
test:test.c add.c sub.c mul.c div.c
gcc test.c add.c sub.c mul.c div.c -o test
~~~
缺点:效率低,修改一个文件,所有文件会被全部编译
**第二个版本Makefile**
~~~
test:test.o add.o sub.o mul.o div.o
gcc test.o add.o sub.o mul.o div.o -o test
test.o:test.c
gcc -c test.c
add.o:add.c
gcc -c add.c
sub.o:sub.c
gcc -c sub.c
mul.o:mul.c
gcc -c mul.c
div.o:div.c
gcc -c div.c
~~~
# Makefile中的变量
在Makefile中使用变量有点类似于C语言中的宏定义,使用该变量相当于内容替换,使用变量可以使Makefile易于维护,修改内容变得简单变量定义及使用。
**自定义变量**
1. 定义变量方法:
变量名=变量值
2. 引用变量:
~~~
$(变量名)或${变量名}
~~~
3. makefile的变量名:
* makefile变量名可以以数字开头
* 变量是大小写敏感的
* 变量一般都在makefile的头部定义
* 变量几乎可在makefile的任何地方使用
~~~
# 变量
OBJS=add.o sub.o mul.o div.o test.o
TARGET=test
${TARGET}:${OBJS}
gcc test.o add.o sub.o mul.o div.o -o test
test.o:test.c
gcc -c test.c -o test.o
add.o:add.c
gcc -c add.c -o add.o
sub.o:sub.c
gcc -c sub.c -o sub.o
mul.o:mul.c
gcc -c mul.c -o mul.o
div.o:div.c
gcc -c div.c -o div.o
clean:
rm -rf ${OBJS} ${TARGET}
~~~
除了使用用户自定义变量,makefile中也提供了一些变量(变量名大写)供用户直接使用,我们可以直接对其进行赋值。
> CC = gcc#arm-linux-gcc
>
> CPPFLAGS :C预处理的选项 如:-I
>
> CFLAGS: C编译器的选项 -Wall -g -c
>
> LDFLAGS : 链接器选项 -L -l
# 自动变量
* `$@`: 表示规则中的目标
* `$<`: 表示规则中的第一个条件
* `$^`: 表示规则中的所有条件, 组成一个列表, 以空格隔开,如果这个列表中有重复的项则消除重复项。
**注意:自动变量只能在规则的命令中中使用**
~~~
# 变量
OBJS=add.o sub.o mul.o div.o test.o
TARGET=test
CC=gcc
${TARGET}:${OBJS}
gcc test.o add.o sub.o mul.o div.o -o test
test.o:test.c
${CC} -c $^ -o $@
add.o:add.c
${CC} -c $^ -o $@
sub.o:sub.c
${CC} -c $^ -o $@
mul.o:mul.c
${CC} -c $^ -o $@
div.o:div.c
${CC} -c $^ -o $@
clean:
rm -rf ${OBJS} ${TARGET}
~~~
# 模式规则
把一些相同的变量替换
模式规则示例:
> %.o:%.c
>
> $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
~~~
# 变量
OBJS=add.o sub.o mul.o div.o test.o
TARGET=test
CC=gcc
${TARGET}:${OBJS}
gcc test.o add.o sub.o mul.o div.o -o test
%.o:%.c
${CC} -c $^ -o $@
clean:
rm -rf ${OBJS} ${TARGET}
~~~
# Makefile中的函数
makefile中的函数有很多,在这里给大家介绍两个最常用的。
> 1. wildcard – 查找指定目录下的指定类型的文件
>
> src = $(wildcard *.c) //找到当前目录下所有后缀为.c的文件,赋值给src
>
> 2. patsubst – 匹配替换
>
> obj = $(patsubst %.c,%.o, $(src)) //把src变量里所有后缀为.c的文件替换成.o
在makefile中所有的函数都是有返回值的。
~~~
# 获取当前目录下的所有.c文件
SRC=${wildcard *.c}
# 将SRC中所有出现的.c替换成.o
OBJS=${patsubst %.c, %.o, ${SRC}}
TARGET=test
CC=gcc
${TARGET}:${OBJS}
gcc ${OBJS} -o ${TARGET}
%.o:%.c
${CC} -c $^ -o $@
~~~
# Makefile中的伪目标
clean用途: 清除编译生成的中间.o文件和最终目标文件
make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令
解决方案:
Ø伪目标声明: **.PHONY:clean**
声明目标为伪目标之后,makefile将不会该判断目标是否存在或者该目标是否需要更新
**clean命令中的特殊符号:**
* “-”此条命令出错,make也会继续执行后续的命令。如:“-rm main.o”
* “@”不显示命令本身,只显示结果。如:“@echo clean done”
~~~
SRC=${wildcard *.c}
OBJS=${patsubst %.c, %.o, ${SRC}}
TARGET=test
CC=gcc
${TARGET}:${OBJS}
gcc ${OBJS} -o ${TARGET}
%.o:%.c
@${CC} -c $^ -o $@
#声明clean为伪目标,伪目标不去判断文件是否存在或者已经更新
#无条件执行命令
.PHONY:clean
clean:
-rm -rf ${OBJS}
~~~
执行
~~~
make -f Makefile clean
~~~
- c语言
- 基础知识
- 变量和常量
- 宏定义和预处理
- 随机数
- register变量
- errno全局变量
- 静态变量
- 类型
- 数组
- 类型转换
- vs中c4996错误
- 数据类型和长度
- 二进制数,八进制数和十六进制数
- 位域
- typedef定义类型
- 函数和编译
- 函数调用惯例
- 函数进栈和出栈
- 函数
- 编译
- sizeof
- main函数接收参数
- 宏函数
- 目标文件和可执行文件有什么
- 强符号和弱符号
- 什么是链接
- 符号
- 强引用和弱引用
- 字符串处理函数
- sscanf
- 查找子字符串
- 字符串指针
- qt
- MFC
- 指针
- 简介
- 指针详解
- 案例
- 指针数组
- 偏移量
- 间接赋值
- 易错点
- 二级指针
- 结构体指针
- 字节对齐
- 函数指针
- 指针例子
- main接收用户输入
- 内存布局
- 内存分区
- 空间开辟和释放
- 堆空间操作字符串
- 内存处理函数
- 内存分页
- 内存模型
- 栈
- 栈溢出攻击
- 内存泄露
- 大小端存储法
- 寄存器
- 结构体
- 共用体
- 枚举
- 文件操作
- 文件到底是什么
- 文件打开和关闭
- 文件的顺序读写
- 文件的随机读写
- 文件复制
- FILE和缓冲区
- 文件大小
- 插入,删除,更改文件内容
- typeid
- 内部链接和外部链接
- 动态库
- 调试器
- 调试的概念
- vs调试
- 多文件编程
- extern关键字
- 头文件规范
- 标准库以及标准头文件
- 头文件只包含一次
- static
- 多线程
- 简介
- 创建线程threads.h
- 创建线程pthread
- gdb
- 简介
- mac使用gdb
- setjump和longjump
- 零拷贝
- gc
- 调试器原理
- c++
- c++简介
- c++对c的扩展
- ::作用域运算符
- 名字控制
- cpp对c的增强
- const
- 变量定义数组
- 尽量以const替换#define
- 引用
- 内联函数
- 函数默认参数
- 函数占位参数
- 函数重载
- extern "C"
- 类和对象
- 类封装
- 构造和析构
- 深浅拷贝
- explicit关键字
- 动态对象创建
- 静态成员
- 对象模型
- this
- 友元
- 单例
- 继承
- 多态
- 运算符重载
- 赋值重载
- 指针运算符(*,->)重载
- 前置和后置++
- 左移<<运算符重载
- 函数调用符重载
- 总结
- bool重载
- 模板
- 简介
- 普通函数和模板函数调用
- 模板的局限性
- 类模板
- 复数的模板类
- 类模板作为参数
- 类模板继承
- 类模板类内和类外实现
- 类模板和友元函数
- 类模板实现数组
- 类型转换
- 异常
- 异常基本语法
- 异常的接口声明
- 异常的栈解旋
- 异常的多态
- 标准异常库
- 自定义异常
- io
- 流的概念和类库结构
- 标准io流
- 标准输入流
- 标准输出流
- 文件读写
- STL
- 简介
- string容器
- vector容器
- deque容器
- stack容器
- queue容器
- list容器
- set/multiset容器
- map/multimap容器
- pair对组
- 深浅拷贝问题
- 使用时机
- 常用算法
- 函数对象
- 谓词
- 内建函数对象
- 函数对象适配器
- 空间适配器
- 常用遍历算法
- 查找算法
- 排序算法
- 拷贝和替换算法
- 算术生成算法
- 集合算法
- gcc
- GDB
- makefile
- visualstudio
- VisualAssistX
- 各种插件
- utf8编码
- 制作安装项目
- 编译模式
- 内存对齐
- 快捷键
- 自动补全
- 查看c++类内存布局
- FFmpeg
- ffmpeg架构
- 命令的基本格式
- 分解与复用
- 处理原始数据
- 录屏和音
- 滤镜
- 水印
- 音视频的拼接与裁剪
- 视频图片转换
- 直播
- ffplay
- 常见问题
- 多媒体文件处理
- ffmpeg代码结构
- 日志系统
- 处理流数据
- linux
- 系统调用
- 常用IO函数
- 文件操作函数
- 文件描述符复制
- 目录相关操作
- 时间相关函数
- 进程
- valgrind
- 进程通信
- 信号
- 信号产生函数
- 信号集
- 信号捕捉
- SIGCHLD信号
- 不可重入函数和可重入函数
- 进程组
- 会话
- 守护进程
- 线程
- 线程属性
- 互斥锁
- 读写锁
- 条件变量
- 信号量
- 网络
- 分层模型
- 协议格式
- TCP协议
- socket
- socket概念
- 网络字节序
- ip地址转换函数
- sockaddr数据结构
- 网络套接字函数
- socket模型创建流程图
- socket函数
- bind函数
- listen函数
- accept函数
- connect函数
- C/S模型-TCP
- 出错处理封装函数
- 多进程并发服务器
- 多线程并发服务器
- 多路I/O复用服务器
- select
- poll
- epoll
- epoll事件
- epoll例子
- epoll反应堆思想
- udp
- socket IPC(本地套接字domain)
- 其他常用函数
- libevent
- libevent简介