我们在Linux环境下开发程序,少不了要自己编写Makefile,一个稍微大一些的工程下面都会包含很多.c的源文 件。
如果我们用gcc去一个一个编译每一个源文件的话,效率会低很多,但是如果我们可以写一个Makefile,那么只需要执行一个make就OK了,这 样大大提高了开发效率。
但是Makefile的语法规则众多,而且缺乏参考资料,对于初学者来说,写起来还是有一定的难度,往往令很多人望而生畏。
下面我 们介绍一个比较通用而且简洁的Makefile,大家只要对它稍作修改就可以用在你们自己的工程里了。
现在假设我们有一个工程叫my_project,工程源码目录下面有app1.c,app2.c,app3.c以及main.c这五个源文件。我们现在需要编译出app1.o,app2.o,app3.o以及main.o,然后再把这些.o文件链接成为一个ELF格式的可执行程序叫做my_app。我们先看一个最简单的Makefile如何编写:
my_app : main.o, app1.o, app2.o, app3.o, app4.o
gcc –o my_app main.o app1.o, app2.o, app3.o, app4.o
main.o : main.c
gcc –c main.c
app1.o : app1.c
gcc –c app1.c
app2.o : app2.c
gcc –c app2.c
app3.o : app3.c
gcc –c app3.c
clean :
rm main.o app1.o, app2.o, app3.o, app4.o
这是一个傻瓜式的Makefile,不灵活,而且不具备可复制性,想象一个如果我们的工程下面有50个源文件,那岂不是要一个一个写出来。
我们的目标是写一个Makefile,只要稍作修改就可以在各个工程之间通用。
下面这个Makefile就可以满足这个要求:
- SRCS = $(wildcard *.c)
- OBJS = $(SRCS:.c = .o)
- CC = gcc
- INCLUDES = -I/×××
- LIBS = -L/×××
- CCFLAGS = -g -Wall -O0
- my_app : $(OBJS)
- $(CC) $^ -o $@ $(INCLUDES) $(LIBS)
- %.o : %.c
- $(CC) -c $< $(CCFLAGS)
- clean:
- rm *.o
- .PHONY:clean
大家看这个Makefile和前一个比起来是不是简洁很多,当然理解起来不如上一个那么直观。
实际上编写 Makefile就是为了提高我们的工作效率,而不是增加我们的工作量。
因此Makefile为我们提供了很多强大的功能,比如定义变量,使用通配符等 等。只要合理利用,就可以达到事半功倍的效果。
下面我们一条一条分析这个Makefile:
SRCS = $(wildcard *.c)
这条语句定义了一个变量SRCS,它的值就是当前面目录下面所有的以.c结尾的源文件。
OBJS = $(SRCS:.c = .o)
这里变量OBJS的值就是将SRCS里面所有.c文件编译出的.o目标文件
CC = gcc
变量CC代表我们要使用的编译器
INCLUDES = -I/×××
LIBS = -L/×××
这里指定除了编译器默认的头文件和库文件的路径之外需要额外引用的头文件路径以及库的路径(×××表示路径)。
CCFLAGS = -g -Wall -O0
CCFLAGS变量存放的是编译选项
my_app : $(OBJS)
$(CC) $^ -o $@ $(INCLUDES) $(LIBS)
my_app依赖于所有的.o文件,$^代表$(OBJS),$@代表my_app
%.o : %.c
$(CC) -c $< $(CCFLAGS)
将所有的.c源代码编译成.o目标文件,这样写是不是很省事?
clean:
rm *.o
在执行make clean之后删除所有编译过程中生成的.o文件。
.PHONY:clean
每次执行make clean时都要执行rm *.o命令
这个Makefile就具备灵活的通用性,我们只要对它稍作修改就可以用在自己的工程里面。当然Makefile还有很多强大的功能,需要我们进一步学习。
分享到:
相关推荐
今天小编就为大家分享一篇关于C++关于Makefile的详解含通用模板,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
本光盘为《嵌入式Linux应用开发详解》一书的配套光盘,读者可自由取其源代码做学习,研究之用。本光盘的代码不能保证完全符合读者的需要,在使用本光盘中的任何代码之后,若发生任何软件、硬件错误,或由此造成损失...
7.1.5 编写一个更通用的派遣函数 7.1.6 跟踪IRP的利器IRPTrace 7.2 缓冲区方式读写操作 7.2.1 缓冲区设备 7.2.2 缓冲区设备读写 7.2.3 缓冲区设备模拟文件读写 7.3 直接方式读写操作 7.3.1 ...
7.1.5 编写一个更通用的派遣函数 7.1.6 跟踪IRP的利器IRPTrace 7.2 缓冲区方式读写操作 7.2.1 缓冲区设备 7.2.2 缓冲区设备读写 7.2.3 缓冲区设备模拟文件读写 7.3 直接方式读写操作 7.3.1 ...
本示例从 Internet 上的随机 wordpress ansible playbook 创建一个 Wordpress 应用程序。 多进程方法 如果您想创建 Docker 容器并以与传统虚拟环境类似的方式使用它们。 为了做到这一点,我们采用了与 Docker 容器...
2.informix-4gl 7.2编写的通用菜单函数 3.Makefile工具的使用 4.vi用法集锦 5.SCO核心参数详细说明 6.SCO Unix 制作系统应急盘“Out of inodes”错误的处理 7.SCO TCP/IP网络管理---TCP/IP的启动 8.SCO TCP/IP网络...
10.5.5 添加一个Qt/Embedded应用到QPE 第11章 Java虚拟机的移植 11.1 Java虚拟机概述 11.1.1 Java虚拟机的概念 11.1.2 J2ME 11.1.3 KVM 11.2 Java虚拟机的移植 11.2.1 获得源码 11.2.2 编译环境的建立 ...
Crifan的电子书的使用说明 ...详解 应用 Python 字符串和字符编码 正则表达式 教程 旧 新 应用举例 Python re模块 旧 新 信息安全 概览 移动端 安卓 辅助工具 Xposed Nox模拟器 工控 自动化 工具 Makefile 测试 概览 W
同学们在努力编制一个新式的内核程序,而John编写了一个新的编辑器和终端仿真程序。他使用Tcl作为这两种工具的命令语言,这样用户就可以定义菜单或者对那些程序进行定制。那时还处在使用X10的时代,他计划编写一个...
9.2.2 通用文件模型 259 9.2.3 arm linux的设备文件 264 9.3 文件i/o操作 265 9.3.1 不带缓存的文件i/o操作 265 9.3.2 标准i/o开发 276 9.4 嵌入式linux串口应用开发 279 9.4.1 串口概述 279 ...
它最初是为处理NAT场景而创建的,早在2004-2005年,它还可以充当通用的实时数据报中继以及IPv4和IPv6网络之间的网关实时协议(RTP)会话。 RTPproxy支持许多高级功能,并且可以通过众多第4层协议进行控制,包括Unix...