Makefile编写规则:
刚开始跟这些Makefile的时候发现会报错误Makefile:2: missing separator. Stop.
在make命令后出现这种错误提示,是提示第2行没有分隔符。
例如:

target:prerequisitescommand     (command前为空格)

改为:

target:prerequisitescommand     (command前为[tab])

就可以了。 在Makefile文件中,命令必须以【tab】键开始。

如果已在命令行前使用了TAB键,仍提示这个错误。,则需要设置VIM的配置文件
$ vim /etc/vimrc

不要用空格代替制表符
set noexpandtab
【保存并退出】

Makefile编写

  1. 源代码介绍在本教程中用于示例的代码很简单,仅仅是在main函数中调用了fun1及fun2函数,而fun1及fun2独立写在fun1.c及fun2.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");
}

2.第一版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有两个很重要的不足:对于简单代码还好,而对于大型项目,具有成千上万代码来说,仅用一行规则是完全不够的,即使够的话也需要写很长的一条规则;任何文件只要稍微做了修改就需要整个项目完整的重要编译。基于此,我们在第一版的基础上优化出第二版。

3.第二版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同样具有一些缺陷:里面存在一些重复的内容,可以考虑用变量代替;后面三条规则非常类似,可以考虑用一条模式规则代替。基于此,我们在第二版的基础上优化出第三版。

4.第三版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。
基于此,我们在第二版的基础上优化出第四版。

5.第四版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)

参考文档
链接:https://blog.csdn.net/fireroll/article/details/46334005
链接:https://www.zhihu.com/question/23792247/answer/600773044

Makefile 编写入门相关推荐

  1. linux Makefile编写的整理

    最近将Makefile的编写进行了整理和提炼了一下,大致分为五个步骤: 编译总共为五个部分  1.设置编译环境 set compile environment  2.获取要编译的源文件,以及把源文件转 ...

  2. Linux下Makefile编写语法

    原创 Linux下Makefile编写语法 2016-07-29 08:31:53 Datrilla 阅读数 1386更多 分类专栏: Linux Makefile 版权声明:本文为博主原创文章,遵循 ...

  3. Gulp:插件编写入门

    之前挖了个坑,准备写篇gulp插件编写入门的科普文,之后迟迟没有动笔,因为不知道该肿么讲清楚Stream这货,毕竟,gulp插件的实现不像grunt插件的实现那么直观. 好吧,于是决定单刀直入了.文中 ...

  4. [动态库]动态库生成和使用以及Makefile编写

    转自:https://www.cnblogs.com/ljtknowns/p/5647793.html 文件目录结构如下 1 dynamiclibapp.c 2 Makefile 3 comm/inc ...

  5. linux环境cpp/c文件的makefile编写(caffe举例)

    编译单个cpp文件 方法一.g++ 文件名.cpp,生成一个名为 "文件名.out" 的可执行文件 方法二.g++ -c 文件名.cpp -o 新文件名.o:生成一个被命名成 &q ...

  6. linux 生成和使用动态链接库和静态链接库的Makefile编写

    引用 Jesse Rei 的 linux 生成和使用动态链接库和静态链接库的Makefile编写 生成和使用动态链接库和静态链接库的Makefile编写 1. 概述 介绍linux下生成和使用动态链接 ...

  7. Linux C编程Makefile编写初步-转

    Linux C编程Makefile编写初步 假设我们有下面这样的一个程序,源代码如下:  /* main.c */  #include "mytool1.h"  #include  ...

  8. Linux kernel: USB driver编写入门(二)

    前面一篇文章Linux kernel: USB driver编写入门(一)介绍了一个最简单的USB驱动的最基本框架,本文将加入probe和disconnect函数,用于响应该设备插入和拔出. 继续在那 ...

  9. Ubuntu下使用gcc和makefile编写c语言程序

    文章目录 前言 一.gcc编写c语言程序 1.hello world的输出 2.简单程序的编译与运行 3.windows环境下的编译运行结果对比 二.makefile编写c语言程序 总结 前言 本文通 ...

最新文章

  1. Vijos1683 有根树的同构问题
  2. c hello world_C和C++使用对方编译的动态链接库
  3. 机器学习系列(5)_从白富美相亲名单看特征选择与预处理(上)
  4. 成功解决r2_score函数输出值始终为0的情况
  5. Hello Blazor:(8)启用深色模式
  6. Codeforces Round #661-C Boats Competition
  7. 确认无疑,.NET 6是迄今为止最快的.NET
  8. sqlite字符串连接(追加写入)
  9. java JDBC入门及案例演示
  10. Android2.1--如何在android模拟器上安装与删除.APK文件
  11. pycharm中同时注释多行代码
  12. 北京地铁挤,最挤昌平线
  13. 光储直流微电网能量管理。 系统主要由光伏发电模块、mppt控制模块、混合储能系统模块、直流负载模块、改进前的soc限值管理控制模块
  14. 腾讯广点通广告投放-Web转化数据API自归因文档对接
  15. JAVA音程_下列选项中哪个音程是减三和弦?
  16. 微信开源PhxQueue:高可用、高可靠、高性能的分布式队列**
  17. 欧奈尔的杯柄形态理论(技术干货)
  18. java 开源 cms系统_基于Java的开源CMS系统选择(转)
  19. 26. SAP ABAP OData Gateway 框架里 /IWFND, /IWBEP 这些缩写代表了什么含义?
  20. 金融直播有哪些好处?直播平台有哪些?

热门文章

  1. px4添加遥控器开关快捷校准磁罗盘
  2. CAN控制器-配置过滤器
  3. Win10下配置Docker
  4. TensorFlow Object Detection API入门例子 (小浣熊检测下)
  5. 短信验证码和语音验证码该如何选择?
  6. 浅谈互联网时代下融媒技术现状
  7. 利用MATLAB解决非线性规划(NLP)问题
  8. HUAWEI Mate 40 Pro 详细配置
  9. 正阅读微信小说分销系统-教程-如何申请模板消息
  10. 语音技术IP电话的原理结构