14、编写一个通用的Makefile
编译test_Makefile的方法:
a. gcc -o test a.c b.c
对于a.c: 预处理、编译(C文件转换成汇编)、汇编(汇编转换成机器码)
对于b.c:预处理、编译、汇编
最后链接
优点:命令简单
缺点:如果文件很多,即使你只修改了一个文件,但是所有的文件文件都要重新"预处理、编译、汇编"
效率低
b. 写Makefile
核心:规则
目标:依赖1 依赖2(目标指根据依赖生成文件名字)
命令
a.o : a.c
gcc -c -o a.o a.c
%.o:%.c //这里的%是通配符
gcc -c -o $@ $< //$@表示目标 $<表示第一个依赖 %^表示所有的依赖
(gcc还要加上-Wp,-MD,名字.d 用来生成依赖文件,否则.h文件改变后,执行make的时候gcc不会发现文件变化了,这样就不执行gcc指令)
命令执行的条件:
i. "依赖"文件 比 "目标"文件 新
ii.没有"目标"这个文件
一、各级子目录的Makefile:
它最简单,形式如下:
obj-y += file.o
obj-y += subdir/
"obj-y += file.o"表示把当前目录下的file.c编进程序里,
"obj-y += subdir/"表示要进入subdir这个子目录下去寻找文件来编进程序里,是哪些文件由subdir目录下的Makefile决定。
注意: "subdir/"中的斜杠"/"不可省略
二、顶层目录的Makefile:
它除了定义obj-y来指定根目录下要编进程序去的文件、子目录外,主要是定义工具链、编译参数、链接参数──就是文件中用export导出的各变量。导出的目的是给个子目录下makefile使用
export AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP
//链接的时候指定优化选项和目录(目录是告诉编译器去哪里找那些头文件,$(shell pwd)表示执行pwd指令获得当前目录),使用arm-linux-gcc来编译的时候,编译器是去/usr/local/arm/4.3.2/arm-none-linux-guneabi/libc/usr/include目录下找头文件,可以通过-I(i的大小)头文件目录来指定头文件或者通过-L 指定库文件目录
CFLAGS := -Wall -O2 -g //-Wall表示列出所有警告 -O2表示优化选项 -g表示,等号的前面“:”表示立即变量,没有这个:,赋值过程会被延时,使用的时候财货确定下来,有无冒号的原因具体见gcc文档
CFLAGS += -I $(shell pwd)/include
//LDFLAGS 表示链接参数
LDFLAGS := -lm -lfreetype
三、顶层目录的Makefile.build:(在数码相框的makefile那节的doc目录中有详细介绍,(子目录下的makefile是最先执行))
这是最复杂的部分,它的功能就是把某个目录及它的所有子目录中、需要编进程序去的文件都编译出来,打包为built-in.o
详细的讲解请看视频。
举例说明Makefile.build
PHONY := __build //PHONY 假象目标,肯定会执行
__build: //声明最开始的目标
obj-y := //先赋空值
subdir-y :=
include Makefile //因为Makefile中含有obj-y等变量值
# obj-y := a.o b.o c/ d/ //下面用#开始的四条语句是举例怎么从obj-y中取得所有子目录
# $(filter %/, $(obj-y)) : c/ d/ //filter表示把$(obj-y)中不符合%/的移除,保留复合%/的
# __subdir-y : c d
# subdir-y : c d
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y))) //$(patsubst pattern,replacement,text) 在text中用replacement代替pattern
subdir-y += $(__subdir-y)
# c/built-in.o d/built-in.o //subdir_objs := c/built-in.o d/built-in.o
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o)
# a.o b.o//下面六行语句的目前是为了生成依赖文件,这样.h文件改变后在执行make才会让编译器知道.h文件也改变了
cur_objs := $(filter-out %/, $(obj-y))
dep_files := $(foreach f,$(cur_objs),.$(f).d)
dep_files := $(wildcard $(dep_files))
ifneq ($(dep_files),)
include $(dep_files)
endif
PHONY += $(subdir-y)
__build : $(subdir-y) built-in.o //顶层目录的makefile执行到这里的时候会先去获得subdir-y,其获得规则在下面,同理built-in.o,这里的$(subdir-y) 仅为了生成所有的built-in.o,其后的built-in.o才是最后的依赖文件
$(subdir-y):
make -C $@ -f $(TOPDIR)/Makefile.build //$@表示进入各级子目录,使用顶层目录下的Makefile.build来生成各级子目录的built-in.o
built-in.o : $(cur_objs) $(subdir_objs)//依赖的是当前目录下.o文件和各级子目录下built-in.o
$(LD) -r -o $@ $^
dep_file = .$@.d //没有冒号,表示延时赋值,在下面使用的时候才赋值,这样$@才有值
%.o : %.c
$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $<
.PHONY : $(PHONY)
14、编写一个通用的Makefile的更多相关文章
- 编写一个通用的Makefile文件
1.1在这之前,我们需要了解程序的编译过程 a.预处理:检查语法错误,展开宏,包含头文件等 b.编译:*.c-->*.S c.汇编:*.S-->*.o d.链接:.o +库文件=*.exe ...
- Linux C编程学习之开发工具3---多文件项目管理、Makefile、一个通用的Makefile
GNU Make简介 大型项目的开发过程中,往往会划分出若干个功能模块,这样可以保证软件的易维护性. 作为项目的组成部分,各个模块不可避免的存在各种联系,如果其中某个模块发生改动,那么其他的模块需要相 ...
- 一个通用的Makefile (转)
据http://bbs.chinaunix.net/thread-2300778-1-1.html的讨论,发现还是有很多人在问通用Makefile的问题,这里做一个总结.也作为以后的参考. ...
- 一个通用的makefile(一)
最近在编写Android编译系统时,需要遍历每一个目录下每一个文件夹下的makefile,网上的方法有些繁琐 :就直接贴上自己遍历子目录深度为1:(for temporary)(之后会继续更新) 下 ...
- 一步一步写一个简单通用的makefile(四)--写一个通用的makefile编译android可执行文件
通常要把我们自己的的代码编译成在android里面编译的可执行文件,我们通常是建一个文件夹 . ├── Android.mk ├── Application.mk ├── convolve.cl ├─ ...
- 一个通用的Makefile(二)
1.各级子目录的Makefile: obj-y += file.o obj-y += subdir/ “obj-y += file.o” 表示把当前目录下的file.c编进程序里. “obj-y += ...
- 一个通用的Makefile框架
先做一个简单的记录,后续有时间再慢慢完善补充细节. 先上一个整体图片: 其中,最重要的文件就是:program_template.mk. 下面是program_template.mk最重要的内容: $ ...
- 一个通用的makefile
# ESDK the makefile setting file - chenwg@20131014 # you can modify "PC = 1" such as " ...
- 我所使用的一个通用的Makefile模板
话不多说,请看: 我的项目有的目录结构有: dirls/ ├── include │ └── apue.h ├── lib │ ├── error.c │ ├── error.o │ ...
随机推荐
- HTTP请求具体解释
1. HTTP请求格式 做过Socket编程的人都知道,当我们设计一个通信协议时,"消息头/消息体"的切割方式是非经常常使用的.消息头告诉对方这个消息是干什么的,消息体告诉对方怎么 ...
- java poi操作excel示例代码
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io ...
- 洛谷P1439 最长公共子序列(LCS问题)
题目描述 给出1-n的两个排列P1和P2,求它们的最长公共子序列. 输入输出格式 输入格式: 第一行是一个数n, 接下来两行,每行为n个数,为自然数1-n的一个排列. 输出格式: 一个数,即最长公共子 ...
- 通过PXE安装Linux实况
通过PXE安装Linux实况 网卡引导操作系统的过程我们可以把它称为PXE(Pre-bootExecutionEnvironment),十几年前,在搞无盘NT时候,我们为了使网卡支持PXE引导要特意购 ...
- HDU 2689 Tree
Tree Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- JAVA配置环境
- C/C++(数据结构栈的实现)
栈的实现 特点FILO(先进后出) 假设栈的空间为8 top == 0 不能出栈,已到栈底 top == 8 不能入栈,已到栈顶 top始终指向一个待插入的位置 push操作,1.写入数据,2.top ...
- Highcharts柱形范围图使用示例
功能需求:统计三种不同的状态在一天的时间段里面所占的范围 第一步:引入highcharts.js和highcharts-more.js文件 引入文件文件源码:下载https://img.hcharts ...
- Maven学习详解(13)——Maven常用命令大全与pom文件讲解
一.Maven常用命令 1.1.Maven 参数 -D 传入属性参数 -P 使用pom中指定的配置 -e 显示maven运行出错的信息 -o 离线执行命令,即不去远程仓库更新包 -X 显示ma ...
- MySQL具体解释(13)------------事务
一. 什么是事务 事务就是一段sql 语句的批处理.可是这个批处理是一个atom(原子) .不可切割,要么都运行,要么回滚(rollback)都不运行. 二.为什么出现这样的技术 为什么要使用事务这个 ...