1. 前言

通过之前章节的学习,我们对Makefile有个基础的认识,现在开始自己动手写Makefile。

目前网络上有不少可以自动生成Makefile的工具,但很多项目其实没必要那么复杂,完全可以自己动手写出来。

而且对于初学者来说,自己动手写一遍Makefile可以顶看十遍高手写的Makefile,也可以加深对Makefile的理解,将来公司的Makefile有需要修改的时候自己就可以动手搞定,不需要依靠他人,何乐而不为?

2. 源代码介绍

在本教程中用于示例的代码很简单,仅仅是在main函数中调用了fun1及fun2函数,而fun1及fun2独立写在fun1.c及fun2.c里。代码如下:

//main.c
int main()
{  printf("hello world\n");  fun1();  fun2();
}
//fun1.c
void fun1()
{  printf("this is fun1\n");
}
//fun2.c
void fun2()
{  printf("this is fun2\n");
}  

3. 第一版Makefile

对于我们的示例代码,不通过Makefile编译其实也很简单:

gcc main.c fun1.c fun2.c -o app

我们知道,Makefile其实就是按规则一条条的执行。所以,我们完全可以把上面那条命令写成Makefile的一个规则。我们的目标是app,按此写法依赖是main.c fun1.c fun2.c,则最终的Makefile如下:

app: main.c fun1.c fun2.c  gcc main.c fun1.c fun2.c -o app  

但这个版本的Makefile有两个很重要的不足:

  1. 对于简单代码还好,而对于大型项目,具有成千上万代码来说,仅用一行规则是完全不够的,即使够的话也需要写很长的一条规则;
  2. 任何文件只要稍微做了修改就需要整个项目完整的重要编译。

基于此,我们在第一版的基础上优化出第二版。

4. 第二版Makefile

在第二版Makefile中,为了避免改动任何代码就需要重新编译整个项目的问题,我们将主规则的各个依赖替换成各自的中间文件,即main.c --> main.o,fun1.c --> fun1.o,fun2.c --> fun2.o,再对每个中间文件的生成各自写条规则比如对于main.o,规则为:

main.o: main.c
​    gcc -c main.c -o main.o  

这样做的好处是,当有一个文件发生改动时,只需重新编译此文件即可,而无需重新编译整个项目。完整Makefile如下:

app: main.o fun1.o fun2.o  gcc main.o fun1.o fun2.o -o app  main.o: main.c  gcc -c main.c -o main.o  fun1.o: fun1.c  gcc -c fun1.c -o fun1.o  fun2.o: fun2.c  gcc -c fun2.c -o fun2.o  

第二版Makefile同样具有一些缺陷:

  1. 里面存在一些重复的内容,可以考虑用变量代替;
  2. 后面三条规则非常类似,可以考虑用一条模式规则代替。

基于此,我们在第二版的基础上优化出第三版。

5. 第三版Makefile

在第三版Makefile中,我们使用变量及模式规则使Makefile更加简洁。使用的三个变量如下:

obj = main.o fun1.o fun2.o
target = app
CC = gcc  

使用的模式规则为:

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

这条模式规则表示:所有的.o文件都由对应的.c文件生成。在规则里,我们又看到了两个自动变量:$<和$@。其实自动变量有很多,常用的有三个:

$<:第一个依赖文件;

$@:目标;

$^:所有不重复的依赖文件,以空格分开​

obj = main.o fun1.o fun2.o
target = app
CC = gcc  $(target): $(obj)  $(CC) $(obj) -o $(target)  %.o: %.c  $(CC) -c $< -o $@  

第三版Makefile依然存在一些缺陷:

  1. obj对应的文件需要一个个输入,工作量大;
  2. 文件数目比较少时还好,文件数目一旦很多的话,obj将很长;
  3. 而且每增加/删除一个文件,都需要修改Makefile。

基于此,我们在第二版的基础上优化出第四版。

6. 第四版Makefile

在第四版Makefile中,我们隆重推出了两个函数:wildcardpatsubst

wildcard:

扩展通配符,搜索指定文件。在此我们使用src = $(wildcard ./*.c),代表在当前目录下搜索所有的.c文件,并赋值给src。函数执行结束后,src的值为:main.c fun1.c fun2.c。

patsubst:

替换通配符,按指定规则做替换。在此我们使用

obj = $(patsubst %.c, %.o, $(src))

代表将src里的每个文件都由.c替换成.o。函数执行结束后,obj的值为main.o fun1.o fun2.o,其实跟第三版Makefile的obj值一模一样,只不过在这里它更智能一些,也更灵活。

除了使用patsubst函数外,我们也可以使用模式规则达到同样的效果,比如:

obj = $(src:%.c=%.o)

也是代表将src里的每个文件都由.c替换成.o。

几乎每个Makefile里都会有一个伪目标clean,这样我们通过执行make clean命令就是将中间文件如.o文件及目标文件全部删除,留下干净的空间。一般是如下写法:

.PHONY: clean
clean:
​        rm -rf $(obj) $(target)  

.PHONY代表声明clean是一个伪目标,这样每次执行make clean时,下面的规则都会被执行。

src = $(wildcard ./*.c)
obj = $(patsubst %.c, %.o, $(src))
#obj = $(src:%.c=%.o)
target = app
CC = gcc  $(target): $(obj)  $(CC) $(obj) -o $(target)  %.o: %.c  $(CC) -c $< -o $@  .PHONY: clean
clean:  rm -rf $(obj) $(target) 

7. 总结

Makefile其实也并不难,但关键的是一定要自己动手写,这样才会更加加深理解,否则也容易造成眼高手低。如果实在不知道从何下手,可以尝试按上面的教程,一步步写下来,也只需要写四个版本而已,写完了相信就有了初步的理解。

Makelife的使用相关推荐

  1. ARM开发工具软件命令详解---嵌入式回归第三篇

    先从bootloader开始,因为暂时目前这些都会是裸机程序相关! 本人这里是VMwarm10.0上安装的红帽linux虚拟机.从下面的截图中可以看出 裸机开发流程: 这里先做第三步(第一步第二步已提 ...

  2. 手把手教你ARC——iOS/Mac开发ARC入…

    http://www.onevcat.com/2012/06/arc-hand-by-hand/ 本文部分实例取自iOS 5Toturail一书中关于ARC的教程和公开内容,仅用于技术交流和讨论.请不 ...

最新文章

  1. 如何使用Jekyll+GitHub Pages搭建个人博客站点
  2. C++ Boost库初步使用 - 使用CFree
  3. 阿里云服务器 ,MySQL建库、建表
  4. html验证邮箱自动,html5+JavaScript进行邮箱地址验证
  5. IntelliJ IDEA中的神仙插件
  6. GIT 自动转换行符的案例
  7. spring的@primary和@qualifier注解解决一个接口多个实现的注入问题
  8. python数字类型及运算_Python基础教程:运算符以及数据类型解析
  9. HCL之SSH的配置与应用
  10. android 微信 导出,微信好友怎么导出excel?微信导出原来这么简单
  11. 达梦数据库高可用解决方案
  12. ipad上写代码???阿里云+vscode-server助你一臂之力
  13. 解决TortoiseSVN不显示状态图标(图文步骤详解)
  14. php 中%3cspan%3e,vue实战(4)——网站统计之——友盟百度统计
  15. vs code进行c/c++开发
  16. MTK_核心功能模块内部结构框图
  17. Scroller的用法
  18. unity 实现物体破碎效果的一些方法 - 细雨淅淅
  19. Android Studio4.0以上设置护眼背景色
  20. 矩阵的基础知识回顾:矩阵乘法,矩阵的逆,伴随矩阵,矩阵的转置,行列式,相似矩阵,实对称矩阵

热门文章

  1. 用于点云视频时空建模的点4D transformer网络(CVPR 2021)
  2. 直播回顾|大规模点云显示技术
  3. 3D视觉工坊——一个有趣有料的星球
  4. 18岁智商低的表现_吃手是宝宝聪明的信号?婴儿智商高的5个讯号,吃手只是其中一个...
  5. HTMl中内联边框是怎样实现连接的
  6. 第六课.模型评估与模型选择
  7. Fuzzy Hashing 算法工具ssdeep 使用
  8. Android源码下载总结
  9. android平板值得买吗,2021年一月更新1000-2000价位最全平板选购指南
  10. 10 款 VS Code 插件神器,第 7 款超级实用!