目录
Makefile 可以简单的认为是一个工程文件的编译规则,描述了整个工程的编译和链接等规则。其中包含了哪些文件需要编译,哪些文件不需要编译,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重建等等。编译整个工程需要涉及到的,在 Makefile 中都可以进行描述。换句话说,Makefile 可以使得我们的项目工程的编译变得自动化,不需要每次都手动输入一堆源文件和参数。
makefile 1.0
在linux下编写Makefile脚本帮助开发者编译管理工程 Makefile的用途与优势 1.可以让开发者实现编译管理复杂工程 2.使用MakeFile编译工程,可以大大节省编译时间(企业级工程) 3.MakeFile脚本编写时,开发者应该注重高重用性 一次编写终生受益
Makefile脚本编写基础: 项目管理脚本命名: Makefile makefile 文件类型:常规文件 文件类型 .mk(可缺省)
Makefile 脚本三要素:目标、依赖、命令 # 理想、能力、行动力 #代表单行注释
示例1: vi test.c
int main() { while(1); return 0; } gcc test.c -o app
vi Makefile
#makefile 三要素 #目标:依赖 依赖 依赖 Tab键 命令(易错必须是TaB 不可以是空格) app:test.c
gcc test.c -o app
Makefile 编写成功后,如何使用? make(命令)----find--->Makefile--执行--->编译结果
make 回车
示例2:
mkdir project
cd project
mkdir include
mkdir library
mkdir source
touch Makefile
cd source touch Makefile
cd include/
touch demo.h int ADD(int,int); int SUB(int,int); int MUL(int,int); int DES(int,int);
touch add.c sub.c mul.c des.c main.c
cd source/ add.c sub.c mul.c des.c main.c
vi main.c
#include <demo.h>
int main()
{
printf(%d,ADD(1,2));
return 0;
}
#-I 路径m gcc add.c sub.c des.c mul.c main.c -I../include -o app ./app tree
vi makefile app:add.c sub.c mul.c des.c main.c (不允许用*.c,makefile 脚本语言不支持通配符,终端支持) gcc *.c -I../include -o app
编译XX系统可以花了10个小时 ld链接器:将工程资源进行组合链接,变成可执行程序
add.c---->add.o sub.c---->sub.o mul.c---->mul.o des.c---->des.o main.c---->main.o _START--------id success--->app(ELF) 工程源码 可重新定位的核心二进制 临时文件
编译浪费时间,怎么节省时间呢? Makefile 节省编译时间:空间换时间,将第一次安装过程中.o二进制文件保留,下次编译时,被修改的.c源码需要重新生成.o,未修改的可直接重用.o,可以大大节省第二次编译时间
makefile 2.0
gcc中-c和-o是编译时可选的参数
-加-c, (compile)只编译生成中间同名目标文件,不链接 -加-o,(output)指定输出文件名,该文件为可执行文件,不加-o会默认生成a.out
示例: #include <stdio.h> .... gcc while.c -c -o app 产生.o 文件
可以使用gcc -c 将二进制文件创建并保留到当前目录
vi makefile
app:add.o sub.o mul.o main.o
gcc *.o -o app
add.o:add.c
gcc -I../include -c add.c
sub.o:sub.c
gcc -I../include -c sub.c
mul.o:mul.c
gcc -I../include -c mul.c
des.o:des.c
gcc -I../include -c des.c
main.o:main.c
gcc -I../include -c main.c
使用方法: make 这个makefile 已经具备节省时间得功能,只编译更改的文件:比如 改动其中一个文件 重新make
如果没有改动 make,则显示is up to date
Makefile 原理
默认的情况下,make执行的是Makefile中的第一个规则,此规则的第一个目标称之为“最终目的”或者“终极目标”。从上至下建立依赖关系 分析目标,自底向上 执行任务 makefile 怎么知道哪个文件更新呢? 文件上的时间标签 FILE 最近访问时间 最近修改时间(修改文件内容) 最近改动时间(改动的文件Inode 文件属性) makefile 文件依赖项: add.o add.c #目标修改时间要比依赖文件的修改时间新 检测到依赖比目标新,执行命令更新目标 gcc -I../include -c add.c 永远保持目标文件修改时间最新
makefile 3.0
最大限度的提高makefile的可用性与重用性 1.makefile 变量定义和使用(常见变量) 2.特殊变量的使用 3.makefile内建语法规则 4.makefile内置函数 5.伪目标 6.功能目标
1.makefile 变量定义和使用(常见变量) 如:变量一般是大写 没有类型 1)默认情况下变量存储为字符串数据(定义时无需指定类型) 2)变量名尽可能定义为大写(变量 名可以由大写字母、下划线、数字 变量的首字符不允许数字) 3)需要使用变量的值必须对变量进行取值操作,取值符为$(如:NAME=aaa $NAME)
vi makefile NAME="2021-10-27"
output:
echo $(NAME) #为了防止识别异常
make
INCLUDE_PATH=../include # 存储头文件位置 #常见变量
-g 调试信息 -c 生成.o文件 -Wall 严格编译有点问题就报错)
CFLAGS=-I$(INCLUDE_PATH) -g -c -Wall #用于存储编译时选项 #-E生成预处理信息 -D编译时定义宏 -o1 -o2 -o3编译时优化(优化代码) CPPFLAGS=-E -D -O1 -O2 -O3 #存储预处理选项 #-L 库路径 -l 指定库名 比如:libpthread.so 真实库名一般叫pthread LIBRARY_PATH= ../library LDFLAGS= -L$(LIBRARY_PATH) -lpthread #存储库选项 TARGET=app #存储目标名 cc=gcc #存储编译器名(版本) gcc c g++ c++
INSTALL_PATH=/usr/bin #程序安装路径
特殊变量 三个 $@ $^ $< 每个特殊变量都表示一个目标中的某一部分,不同目标含义不同 #$@目标名 $^依赖 $<依赖项中第一个 示例: apk:a.c b.c c.c d.c $@: 代表apk $^:代表a.c b.c c.c d.c $<:代表a.c
app:e.c f.c g.c h.c $@:代表app $^:代表e.c f.c g.c h.c $< :代表e.c
wildcard #获取工程目录下的文件名 .x后缀文件
一 、作用
获取工程目录下的文件名
二、格式
$(wildcard PATTERN...) 。
在Makefile中,它被展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表。如果不存在任何符合此模式的文件,函数会忽略模式字符并返回空。需要注意的是:这种情况下规则中通配符的展开和上一小节匹配通配符的区别。
示例:
一般我们可以使用“$(wildcard *.c)”来获取工作目录下的所有的.c文件列表。
patsubst函数用于将文件模式进行替换
一、作用
替换文件后缀。
二、格式
$(patsubst 原模式, 目标模式, 文件列表):
示例:
$(patsubst %.c,%.o,$(wildcard *.c)) # 首先使 用“wildcard”函数获取工作目录下的.c文件列表;之后将列表中所有文件名的后缀.c替换为.o。
SRCFILE=$(wildcard *.c) #调用函数返回值为SRCFILE DESFILE=$( patsubst %.c,%.o,$(SRCFILE) ) output: echo $(SRCFILE) #()为了防止识别异常 echo $(DESFILE) #使用内建语法完成迭代处理 $(TARGET):$(DESFILE) $(cc) $^ -o $@ %.o:%.c $(cc) $(CFLAGS) $<
其中:
这句话的意思就是 %.o : %.c 也就是说,所有的.o文件,依赖于对应的.c文件 比如有三个a.c b.c c.c 那么就会有 a.o b.o c.o a.o : a.c b.o : b.c c.o : c.c 这是makefile依赖的一种简写方法。makefile的依赖关系有很多种写法。这是其中一种
注意事项:要注释上面的output,然后再make
功能目标,没有依赖,完成特定任务,执行功能目标, make output clean: rm $(DESFILE) -rf rm $(TARGET) -rf install: #安装 sudo mv $(TARGET) $(INSTALL_PATH) disclean:#卸载 sudo rm $(INSTALL_PATH)$(TARGET) -rf #千万不要写错,比如TARGET写成TRAGET sudo rm /usr/bin/ -rf 会把整个目录下的内容全部删掉 make clean make output make install #修饰符 @可以隐藏修饰的命令本身, 只显示结果 -如果被修饰的命令出错,可以向后执行,如果不修饰,遇到错误则退出 output:
- @ echo $(SRCFILE) #()为了防止识别异常 - @echo $(DESFILE)
source中的makefile :管理编译源码 工程目录下的makefile : 使用此makefile 调度运行source中的makefile完成代码管理编译。 vi makefile #使用次makefile 用户管理执行source_makefile #-c 去哪里执行 makestart:./source make -C ./source #执行source 下的make makeclean:./source
make clean -C ./source