makefile个人理解
makefile
makefile抽象层面的理解
学习某一样东西之前一定要明确学习的目的,即学习了这项工具能解决一些什么问题,其优势是什么?
makefile的优势就是能够动态根据文件的新旧来决定是否编译对应的文件,倘若每次编译一个项目都重新编译,特别是大项目的时候,岂不是很浪费时间?makefile能自动根据依赖关系解决这个问题,对于已经编译过的文件不再重新编译,而只选择编译尚未编译(或者新)的文件。
那么如何实现自动编译新文件呢?makefile是如何识别哪些是新的文件哪些是旧的文件的呢?
这就是makefile的核心--依赖关系
makefile中的语句就是为描述各种依赖关系而建立的。
例如下面这个例子
main:arithmetic.o main.o myprint.o
main.o:main.c
gcc -c main.c -o main.o
arithmetic.o:arithmetic.c
gcc -c arithmetic.c -o arithmetic.o
myprint.o:myprint.c
gcc -c myprint.c -o myprint.o
翻译过来,用通俗的话说就是:
- 如果main的修改时间在arithmetic.o main.o myprint.o的修改时间之前,那么就更新arithmetic.o main.o myprint.o (实际上就是确保main是最新的,如果不是,就更新冒号右边的文件。下面的语句也是类似的)
- 保证main.o是最新的
- 保证arithmetic.o是最新的
- 保证myprint.o是最新的
那么如何更新这个文件呢?就通过冒号:
下面一行的语句(有时可省略)来进行更新的操作(gcc编译出新文件覆盖掉旧文件)
显然,如果每一个源程序都需要一一给出依赖关系那么这个工作量无疑是巨大的。为此makefile提供了一些更简便的操作方法来管理,如提供变量,嵌入shell语句等。这些操作方法使得makefile管理文件变得简单的同时,也使得makefile的学习成本增加。但是只要理解了上面makefile的基本原理,那么makefile中的其他高级操作不过是对这种建立依赖关系的方法进行了扩充,只要多背几条语句/语法规则即可。
makefile简单例子
下面,通过一个具体的实例来说明更新的过程。
main.c
#include <stdio.h>
#include "arithmetic.h"
#include "myprint.h"
int main()
{
int a=1;
int b=1;
printf("a+b=%d\n",add(a,b));
myprint();
printf("hello world!\n");
return 0;
}
myprint.h
#ifndef __MYPRINT
#define __MYPRINT
#include <stdio.h>
void myprint(void);
#endif
myprint.c
#include "myprint.h"
void myprint(void)
{
printf("my print\n");
}
arithmetic.h
#ifndef __ARITHMETIC
#define __ARITHMETIC
int add(int a ,int b);
#endif
arithmetic.c
#include "arithmetic.h"
int add(int a ,int b)
{
return a+b;
}
makefile
版本1
main:arithmetic.o main.o myprint.o
main.o:main.c
gcc -c main.c -o main.o
arithmetic.o:arithmetic.c
gcc -c arithmetic.c -o arithmetic.o
myprint.o:myprint.c
gcc -c myprint.c -o myprint.o
.PHONY:clean
clean:
rm -rf *.o
版本2
main:arithmetic.o main.o myprint.o
main.o:main.c
gcc -c $^ -o $@
arithmetic.o:arithmetic.c
gcc -c $^ -o $@
myprint.o:myprint.c
gcc -c $^ -o $@
.PHONY:clean
clean:
rm -rf *.o
版本3
main:arithmetic.o main.o myprint.o
%.o:%.c
gcc -c $^ -o $@
.PHONY:clean
clean:
rm -rf *.o
版本4
OBJS = main.o\
myprint.o\
arithmetic.o
main:$(OBJS)
%.o:%.c
gcc -c $^ -o $@
.PHONY:clean
clean:
rm -rf *.o
语法讲解:
%.o
:表示当前目录下所有的.o文件
%.c
:表示当前目录下所有的.c文件
$^
:表示目标文件,即:
左边的文件
$@
:表示所有的依赖文件,即:
右边的所有文件
.PHONY:clean
:命令行输入make clean
时会执行clean中的语句,但不会生成clean目标
一些常用的结论:
可以将所有的目标-依赖语句(不包括前面部分的变量初始化语句)都抽象称为如下的表示
目标文件:依赖文件
执行语句
那么所有的
执行语句
执行与否取决于目标文件和依赖文件的更新时间的比较(为了简化思考可以直接认为是一定会执行的)执行语句
实际上就是shell命令
一般能理解并能手动写出版本4的makefile就足够用了。上面例程是仿照下面的博客做的,并加入了自己的一些理解和修改,感谢下面博客博主的热心分享。
具体的语法这里也不再给出具体说明,因为这些资源网络上各处都有。更重要的是对makefile思想以及抽象层面上的理解。
实战:对实际的代码进行分析
要分析的代码:
KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
obj-m := kernel_hello.o
modules:
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
@make clear
clear:
@rm -f *.o *.cmd *.mod.c
@rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f
@rm -f .*ko.cmd .*.o.cmd .*.o.d
@rm -f *.unsigned
clean:
@rm -f hello.ko
分析:
等号的区别
var ?= will_not_excute
var = first_assign
var = second_assign
result1 = $(var)
result2 := $(var)
result3 += $(var)
result3 += $(var)
var = final_assign
main:
@echo var final val: $(var)
@echo result1: $(result1)
@echo result2: $(result2)
@echo result3: $(result3) 结果:
$ make
var final val: final_assign
result1: final_assign
result2: second_assign
result3: final_assign final_assign
从代码的执行结果分析,可以得出几点结论.
?=
只有该变量在整个makefile都没有被赋值的时候才进行赋值:=
右边部分调用$(var)
会得到var上一次的值=
右边部分调用$(var)
会得到var在整个makefile中最后的值+=
不用多说,就是追加操作
@
语句表示不把正在执行的语句打印出来(但仍然会打印语句执行的结果)
main:
echo will display this statement
@echo will not display this statement $ make
echo will display this statement
will display this statement
will not display this statement
$(MAKE)
解析出来就是"make"-C
指明跳转到内核源码目录下读取那里的MakefileM=$(PWD)
表明然后返回到当前目录继续读入、执行当前的Makefile这两个参数怎么理解呢?
一般来说,一些大的工程会有几百个文件夹,而且每个文件夹里面都可能存在Makefile,这些Makefile记录着它所在文件夹下的源文件的编译步骤,但仅仅这样是不够的,这些Makefile只是做着自己当前目录下的事情,它们之间还需要进行一定程度的交流,那么,顶层Makefile就出现了,这个顶层Makefile不断地通过
-C M=
参数执行其管理的子Makefile,就像一个统筹全局的军师.有了顶层Makefile那么不管多大工程都能顺利编译出来了,而且还对一些模块进行了解耦,方便管理与修改.
makefile个人理解的更多相关文章
- Linux下对于makefile的理解
什么是makefile呢?在Linux下makefile我们可以把理解为工程的编译规则.一个工程中源文件不计数,其按类型.功能.模块分别放在若干个目录中,makefile定义了一系列的规则来指定,那些 ...
- Makefile 13——理解make的解析行为
make是以从上到下的顺序读入Makefile中的内容的.然而,处理Makefile中的语句却并非完全从上到下. 大体上,make处理一个Makefile分为两个阶段.第一个阶段包含: 1.make读 ...
- Makefile学习(一)----初步理解
一.我对makefile的理解: 经过一段时间对makefile的学习,我理解的makefile就是将程序员手动编译源文件的过程用一个脚本执行,这对于小型项目来说,程序员手动执行和用makefile来 ...
- Makefile 编译生成多个可执行文件
CC = gcc CXX = g++ CFLAGS = -O -DDBG -D_REENTRANT -Wall -DUSE_PTHREAD -pthread LDFLAGS = -ldl -lnsl ...
- (二)u-boot2013.01.01 for TQ210:《Makefile分析》
当时写的时候看的是2012-10版本的,但是略对比了一遍和2013.01.01没什么改动,所以这不影响对2013.01.01版本的makefile的理解.本文比较侧重于语法句意的分析,框 ...
- 一个通用的Makefile (转)
据http://bbs.chinaunix.net/thread-2300778-1-1.html的讨论,发现还是有很多人在问通用Makefile的问题,这里做一个总结.也作为以后的参考. ...
- linux 下makefile
linux下c编程中makefile是必须会的,我刚开始学,将我对makefile的理解记录下来. 通常我们在windows下编写c程序,有各种ide工具为我们执行makefile工作但在linux下 ...
- OpenWRT添加模块 Makefile和Config.in
添加模块编译 在网上找了一下,很多关于编译Openwrt系统的资料,不过这些事情芯片厂商提供的开发包都已经办得妥妥了,但是没有找到系统介绍的资料,添加一个包的介绍有不多,其中有两个很有参考价值: ht ...
- Ubuntu下比较通用的makefile实例
本文转自http://blog.chinaunix.net/uid-20608849-id-360294.html 笔者在写程序的时候会遇到这样的烦恼:一个项目中可能会有很多个应用程序,而新建一个应 ...
随机推荐
- Pytorch | BERT模型实现,提供转换脚本【横扫NLP】
<谷歌终于开源BERT代码:3 亿参数量,机器之心全面解读>,上周推送的这篇文章,全面解读基于TensorFlow实现的BERT代码.现在,PyTorch用户的福利来了:一个名为Huggi ...
- windows下检出项目和提交项目
1.git status:查看工作区的状态 2.git add 文件名:建立跟踪 3.git commit:提交变更 4.git push:发布本地操作 5.解决 The requested UR ...
- Adam那么棒,为什么还对SGD念念不忘 (2)—— Adam的两宗罪
在上篇文章中,我们用一个框架来回顾了主流的深度学习优化算法.可以看到,一代又一代的研究者们为了我们能炼(xun)好(hao)金(mo)丹(xing)可谓是煞费苦心.从理论上看,一代更比一代完善,Ada ...
- 7种最常见的Hadoop和Spark项目
7种最常见的Hadoop和Spark项目 如果您的Hadoop项目将有新的突破,那么它必定与下边介绍的七种常见项目很相像. 有一句古老的格言是这样说的,如果你向某人提供你的全部支持和金融支持去做一些不 ...
- [转]SpringBoot整合Swagger2以及生产环境的安全问题处理
1.创建springboot项目 https://www.cnblogs.com/i-tao/p/8878562.html 这里我们使用多环境配置: application-dev.yml(开发环境) ...
- QuartusII 13.0的完美破解
网络上破解QuartusII 13.0软件的方法都不行,最后经过本人总结测试(独创),最终实现了QuartusII 13.0的破解,破解方法如下: 网上常规操作之后,会得到一个“license.dat ...
- Vue中的scoped及穿透方法(修改第三方组件局部的样式)
何为scoped? 在vue文件中的style标签上,有一个特殊的属性:scoped.当一个style标签拥有scoped属性时,它的CSS样式就只能作用于当前的组件,也就是说,该样式只能适用于当前组 ...
- ZR1158
ZR1158 http://www.zhengruioi.com/contest/446/problem/1158 给定限制的问题大多数都是容斥或者二分,或者二分之后容斥 首先,这个问题的第一步我们还 ...
- gulp4.0基本配置,超简单!
最近复习了一下gulp,目前是4.0版本. 下图是基本目录结构,文件里面的内容可以随意添加,超详细简洁啊! 直接上代码(依赖未完全使用): 项目的所有依赖都可以安装,每个都有详细的注释. const ...
- 2019-3-1-C#-double-好用的扩展
title author date CreateTime categories C# double 好用的扩展 lindexi 2019-3-1 9:19:5 +0800 2018-05-15 10: ...