Linux 应用开发 - Makefile 基础语法
2017-07-23 11:21
651 查看
Makefile 简介
Makefile是一个管理项目的配置文件,它主要有 2 个作用:
1. 组织工程文件,编译成复杂的程序
2. 安装及卸载程序
Makefile 是被
make这个程序执行的,当执行
make时,如果发现当前目录下有
Makefile或者
makefile文件,那么
make命令就会根据这个文件的内容来找到相关的文件,然后去执行编译,链接,安装,卸载等操作,这就实现了使用
make + Makefile来管理项目的功能。
这篇文章主要是介绍编写 Makefile 的基础语法,帮助你能够编写和理解一般的 Makefile 文件。
如何系统的学习 Makefile
想要系统的学习 Makefile,需要 2 个条件:1. Makefile 官网帮助文档:Makefile
3. 大量练习编写 Makefile:想要系统学习,必须自己练习
因为
make是
GNU开发的开源软件,所以官网的资料可以说是最好的,这也是开源的力量,这篇文章只是带你入门,想要精通还要自己努力。
make 的工作流程
在学习 Makefile 语法之前,我们先来学习下make是如何解析 Makefile 文件的,主要分为下面 4 个步骤:
1. 在当前目录下查找 Makefile 或者 makefile 的文件
2. 找到之后,解析并得到最终要生成的目标文件
3. 根据时间戳生成目标文件
4. 递归去寻找其他目标文件的依赖文件,并递归生成
只需要了解这个步骤即可,这是为帮助你理解执行
make后发生了什么事情,清楚自己在做些什么。
第一个 Makefile
我们先写一个最简单的 Makefile 来熟悉编译,执行,清理,安装,卸载Hello World的操作,以此来熟悉通用的过程。
编写 hello.c
这个程序打印Hello World,非常简单:
#include <stdio.h> int main(void) { printf("Hello World!\n"); return 0; }
编写 Makefile
这个 Makefile 其中包含的就是基本的gcc编译指令和一些
shell指令:
hello: gcc hello.c -o hello clean: rm ./hello install: cp ./hello /usr/local/bin/hello uninstall: rm /usr/local/bin/hello
注意:使用
Table键来缩进,否则会出现语法错误!
编译
现在有了 Makefile,我们就可以直接在终端键入make来编译啦:
make # make 之后打印的信息 gcc hello.c -o hello
我们看到只有一条打印信息,就是我们写的那条编译指令,联想到我们手动编译别人的软件时,我们也是键入
make然后屏幕就被一大串信息刷屏了,其实那些信息跟这个本质上是一样,也是 Makefile 中的指令。
执行
执行./hello:
./hello # 结果 Hello World!
可见这种方法更加简单了,不仅如此,还可以很容易清理可执行文件。
清理
还记得我们在 Makefile 中写了一个clean:吗,它下面还有一条删除文件的指令,我们在终端键入:
make clean # make clean 打印的信息 rm ./hello
可以看到
make clean帮助我们删除了
hello,是不是特别方便,以后再也不用敲那一大串
gcc编译命令和手动删除文件了,效率瞬间又提升了。
安装
还记得使用sudo make install来安装程序吗?我们也在终端键入下面的命令:
sudo make install # 提示输入 root 密码 [sudo] password for orange: cp ./hello /usr/local/bin/hello # 直接执行 hello hello # 输出 Hello World!
可以看出安装的过程其实就是拷贝程序的过程。
卸载
卸载使用sudo make uninstall,我们卸载
hello:
# 卸载 sudo make uninstall rm /usr/local/bin/hello # 再次执行 hello,提示没找到即已经删除 bash: /usr/local/bin/hello: No such file or directory
至此,我们已经了解使用一个简单的 Makefile 来编译,清理,安装,卸载程序的例子,下面就来学习一些常用的 Makefile 语法吧。
Makefile 基础语法
先来看看 Makefile 的编写规则。Makefile 编写规则
Makefile 由若干条规则组成,规则格式如下:目标(target): 依赖(prerequisites) 命令(command)
例如:
main : main.o gcc main.o -o main main.o : main.c gcc -c main.c -o main.o
其中
main是最后生成的目标文件,
main.o是依赖文件,
gcc main.o -o main是编译命令,要注意的是
main.o是由
main.c生成的,所以还需要一条编译
main.c生成
main.o的规则,这些依赖关系规则共同组成了最后的 Makefile。
Makefile 变量
Makefile 的变量分为 3 类:1. 用户自定义变量
2. 预定义变量
3. 环境变量
1. 用户自定义变量
定义格式如下:VAR_NAME = var_value
使用
$(VAR_NAME)来引用变量,比如:
file_name = hello.c hello: gcc $(file_name) -o hello
2. 预定义变量
Makefile 常见的预定义变量有下面这些:- AR:库文件维护程序,默认为
ar
- AS:汇编程序,默认为
as
- CC:C 编译器,默认为
cc
- CXX:C++ 编译器,默认为
g++
- ARFLAGS:库文件维护程序选项,无默认值
- ASFLAGS:汇编程序选项,无默认值
- CFLAGS:C 编译器选项,无默认值
- CXXFLAGS:C++ 编译器选项,无默认值
我们可以直接使用或者重新定义这些变量,来看个使用
CFLAGS和
CC的例子:
CFLAGS = -g CC = gcc hello: $(CC) $(CFLAGS) hello.c -o hello
这句编译指令就相当于
gcc -g hello.c -o hello,我们增加了
[-g]编译参数,来看看实际
make的效果:
make # make 后的效果 gcc -g hello.c -o hello
3. 环境变量
Makefile 常用的环境变量有下面这些:-
$*:不包含扩展名的目标文件名称
-
$<:第一个依赖文件名称
-
$?:所有时间戳比目标文件晚的依赖文件
-
$@:目标文件完整名称
-
$^:所有不重复的依赖文件
这里我们以
$^和
$@为例:
hello : hello.o gcc $^ -o $@ hello.o : hello.c gcc -c hello.c
看看
make的结果:
make # 一共执行了 2 条指令 gcc -c hello.c gcc hello.o -o hello
可以发现
$^ = hello.o,
$@ = hello,符合这两个预定义变量的定义。
Makefile 伪目标
先来看一个伪目标:.PHONY: install install: cp hello /usr/local/bin/hello
伪目标
install表示即使当前文件夹内有
install这个文件,但是
make执行的仍然是
Makefile内部的
install,不会使用外部的文件,相当于进行了一个内部封装。
Makefile 包含
一个 Makefile 可以包含另一个 Makefile,需要使用include指令,例如:
include dir/Makefile
这里我们包含了当前目录下
dir下的 Makefile 文件。
Makefile 嵌套
在大型的项目中,我们经常需要一个 Makefile 来嵌套调用另一个目录下的 Makefile,这是可以使用下面的指令:submake: cd dir && gcc hello.c -o hello
意思是先进入
dir,之后执行后面的编译指令。例如我们在
dir目录下新建
hello.c,在上一级目录下使用上面的命令作为 Makefile,我们来
make:
make # 结果 cd dir && gcc hello.c -o hello
Makefile 条件判断
在 Makefile 中也可以进行条件判断,格式如下:ifeq ... else ... endif
注意:前面不能用
table分隔,来看一个例子:
CC = gcc hello: ifeq ($(CC),gcc) gcc hello.c -o $@ else gcc hello.c -o hello2 endif
意思很容易理解,当
CC = gcc时编译的输出文件名为
hello,否则为
hello2,我们看看
make的结果:
# CC = gcc make gcc hello.c -o hello # CC != gcc make gcc hello.c -o hello2
可以看到输出文件名是不同的,说明判断是有效的。
Makeifle 管理命令
Makefile 有几个管理命令需要了解:-
[-C dir]:读入指定目录下面的 Makefile
-
[-f file]:读入当前目录下的
file文件为 Makefile
-
[-i]:忽略所有命令执行错误
-
[-l dir]:指定被包含的 Makefile 所在的目录
我们这里介绍下前面两个:
比如,我们在
dir目录下放了
hello.c和
Makefile2 个文件,使用下面的
shell命令来在上一级目录编译:
make -C dir/ # make 结果 make: Entering directory '/home/orange/Desktop/Makefile/hello/dir' gcc hello.c -o hello2 make: Leaving directory '/home/orange/Desktop/Makefile/hello/dir'
可以看到
make先进入这个
dir目录,之后编译,然后退出。
我们可以使用
[-f]指定一个文件作为 Makefile,例如:
make -f cdeveloper.mk gcc hello.c -o hello
cdeveloper.mk内容就是普通 Makefile 的内容,只是名字变了而已,当然名字你可以随意改,但是内容必须符合 Makefile 语法。
结语
通过这篇博客,我们学习了 Makefile 的基础语法,如果需要更加系统的学习建议你看 GNU Makefile 的官方文档 来学习,这是最好最权威的学习资料,看这些英文文档,不仅能够学到知识,还能锻炼英文水平,这是再好不过了事了,不过你需要有毅力,不能怕困难。最后,谢谢你的阅读,我们下次再见 :)
本文首发于我的微信公众号 CDeveloper,坚持技术原创,只说真话!
相关文章推荐
- Unix/Linux C++应用开发-C++基础概念"数组、指针和字符串"
- linux2.6内核Makefile简单语法与应用
- linux基础复习(7)串口应用开发
- linux驱动基础开发3——linux 内核配置机制(make menuconfig、Kconfig、makefile)讲解
- linux驱动基础开发3——linux 内核配置机制(make menuconfig、Kconfig、makefile)讲解
- linux系统开发 1 基础apt-get 进程 作业 环境变量 安装vsftpd vim gcc gdb Makefile
- Unix/Linux C++应用开发-C++基础概念"变量存储"
- linux基础复习(7)串口应用开发
- linux应用开发基础(一)GCC编译器、动态库、静态库使用
- 嵌入式Linux应用开发——Linux下的C编程基础
- Maemo Linux手机平台系列分析:(17) Maemo应用开发: GNU make 与makefile
- Linux驱动基础开发 Linux 内核配置机制(make menuconfig、Kconfig、makefile)讲解
- linux驱动基础开发3——linux 内核配置机制(make menuconfig、Kconfig、makefile)讲解
- 学习嵌入式Linux系统开发基础 第七课(makefile)
- 学习嵌入式Linux系统开发基础 第七课(makefile)
- linux驱动基础开发3——linux 内核配置机制(make menuconfig、Kconfig、makefile)讲解
- Linux 应用开发 - 必备的 gcc 基础
- linux驱动基础开发3——linux 内核配置机制(make menuconfig、Kconfig、makefile)讲解
- linux2.6内核Makefile简单语法与应用
- Linux 应用开发 - 15 个 gbd 调试基础命令