C编译: makefile基础
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!
在编译一个大型项目的时候,往往有很多目标文件、库文件、头文件以及最终的可执行文件。不同的文件之间存在依赖关系(dependency)。比如当我们使用下面命令编译时:
$gcc -c -o test.o test.c
$gcc -o helloworld test.o
可执行文件helloworld依赖于test.o进行编译的,而test.o依赖于test.c。

依赖关系
在我们编译一个大型项目时,我们往往要很多次的调用编译器,来根据依赖关系,逐步编译整个项目。这样的方式是自下而上的,即先编译下游文件,再编译上游文件。
UNIX系统下的make工具用于自动记录和处理文件之间的依赖关系。我们不用输入大量的"gcc"命令,而只需调用make就可以完成整个编译过程。所有的依赖关系都记录在makefile文本文件中。我们只需要make helloworld,make会根据依赖关系,自上而下的找到编译该文件所需的所有依赖关系,最后再自下而上的编译。
(make有多个版本,本文将基于GNU make。make会自动搜索当前目录下的makefile, Makefile或者GNUmakefile)

依赖
基本概念
我们使用一个示例C语言文件:

#include <stdio.h> /*
* By Vamei
* test.c for makefile demo
*/
int main()
{
printf("Hello world!\n");
return 0;
}

下面是一个简单的makefile

# helloworld is a binary file
helloworld: test.o
echo "good"
gcc -o helloworld test.o test.o: test.c
gcc -c -o test.o test.c

观察上面的makefile
- #号起始的行是注释行
- target: prerequisite为依赖关系,即目标文件(target)依赖于前提文件(prerequisite)。可以有多个前提文件,用空格分开。
- 依赖关系后面的<Tab>缩进行是实现依赖关系进行的操作,即正常的UNIX命令。一个依赖关系可以附属有多个操作。
用直白的话说,就是:
- 想要helloworld吗?那你必须有test.o,并执行附属的操作。
- 如果没有test.o,那你必须搜索其他依赖关系,并创建test.o。
我们执行
$make helloworld
来创建helloworld。
make是一个递归创建的过程:
- Base Case 1: 如果当前依赖关系中没有说明前提文件,那么直接执行操作。
- Base Case 2: 如果当前依赖关系说明了目标文件,而目标文件所需的前提文件已经存在,而且前提文件与上次make时没有发生改变(根据最近写入时间判断),也直接执行该依赖关系的操作。
- 如果当前目标文件依赖关系所需的前提文件不存在,或者前提文件发生改变,那么以前提文件为新的目标文件,寻找依赖关系,创建目标文件。

虚线: 依赖关系检索
上面是make的核心功能。有了上面的功能,我们可以记录项目中所有的依赖关系和相关操作,并使用make进行编译。下面的内容都是在此核心内容上的拓展。
宏
make中可以使用宏(MACRO)。宏类似于文本类型的变量。比如下面的CC:

CC = gcc # helloworld is a binary file
helloworld: test.o
echo "good"
$(CC) -o helloworld test.o test.o: test.c
$(CC) -c -o test.o test.c

我们用CC来代表"gcc"。在makefile中,使用(CC)的方式来调用宏的值。make会在运行时,使用宏的值(gcc)来替代(CC)。
shell的环境变量可以直接作为宏调用。如果同一个自定义的宏同时也有同名环境环境变量,make将优先使用自定义宏。
(可以使用$make -e helloworld来优先使用环境变量)
类似于C语言的宏,makefile中的宏可以方便的管理一些固定出现的文本,并方便替换操作。比如我们未来使用ifort编译器时,只需要更改宏定义为:
CC = ifort
就可以了
内部宏
make中有内部定义的宏,可以直接使用。$@中包含有当前依赖关系的目标文件名,而$^包含当前目标的前提文件:

CC = gcc # helloworld is a binary file
helloworld: test.o
echo $@
$(CC) -o $@ $^ test.o: test.c
$(CC) -c -o $@ $^

内部宏 功能
$* 当前依赖关系中的目标文件名,不包括后缀。
$* 当前依赖关系中,发生改变的前提文件
$$ 字符"$"
如果目标或者前提文件是一个完整路径,我们可以附加D和F来提取文件夹部分和文件名部分,比如$(@F)表示目标文件的文件名部分。
后缀依赖
在makefile中使用
.SUFFIXES: .c .o
来说明.c和.o是后缀。
我们可以使用后缀依赖的方式,比如:

CC = gcc .SUFFIXES: .c .o .c.o:
$(CC) -c -o $@ $^ #-------------------------- # helloworld is a binary file
helloworld: test.o
echo $@
$(CC) -o $@ $^ test.o: test.c

我们定义.c和.o为后缀。并有后缀依赖关系.c.o:。前者为前提,后者为目标。(注意,与一般的依赖关系顺序不同)
上面的test.o和test.c有依赖关系,但没有操作。make会发现该依赖关系符合.c.o的后缀依赖,并执行该后缀依赖后面的操作。
如果项目很大型的时候,后缀依赖非常有用。符合后缀依赖的文件往往有类似的操作,我们可以将这些操作用后缀依赖表示,而避免重复输入。
其他
makefile的续行符为\
makefile中经常会定义下面依赖关系:
all:
如果make后没有跟随文件名,那么将执行该依赖关系。
clean:
常用于清理历史文件。
比如:

CC = gcc .SUFFIXES: .c .o .c.o:
$(CC) -c -o $@ $^ #-------------------------- all: helloworld
@echo "ALL" # helloworld is a binary file
helloworld: test.o
@echo $@
$(CC) -o $@ $^ test.o: test.c clean:
-rm helloworld *.o

注意: echo前面的@和rm前面的-。@后的命令将不显示命令本身。-后面的命令将忽略错误(比如删除不存在的文件)。
总结
make的核心功能是根据依赖关系来实现编译管理。
make的其他功能是让用户可以更加便捷的写出makefile。
参考
http://oreilly.com/linux/excerpts/9780596100292/gnu-make-utility.html
C编译: makefile基础的更多相关文章
- Makefile基础---编译
首先写一个自己的库: #include "../MyAPI.h" #include <cstdlib> #include <ctime> int getRa ...
- Makefile基础学习
Makefile基础学习 理论知识 makefile关系到了整个工程的编译规则.一个工程中的源文件不计其数,并且按类型.功能.模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文 ...
- Makefile基础(三)
第一章:C语言之Makefile基础(一) 第二章:C语言之Makefile基础(二) 再来看一个简单的例子: [root@localhost linux_c]# cat Makefile foo = ...
- Makefile基础(二)
上一章:C语言之Makefile基础(一) 上一章的Makefile写的中规中矩,比较繁琐,是为了讲清楚基本概念,其实Makefile有很多灵活的写法,可以写的更简洁,同时减少出错的可能 一个目标依赖 ...
- 深入理解gradle编译-Android基础篇
深入理解gradle编译-Android基础篇 导读 Gradle基于Groovy的特定领域语言(DSL)编写的一种自动化建构工具,Groovy作为一种高级语言由Java代码实现,本文将对Gradle ...
- 引用 模块编译Makefile模板
本文转载自geyingzhen<模块编译Makefile模板> 引用 geyingzhen 的 模块编译Makefile模板 ifneq ($(KERNELRELEASE), ) // ...
- Linux环境下使用VSCode编译makefile文件的注意事项
Linux环境下使用VSCode编译makefile文件的注意事项 首先安装C/C++的两个依赖 在debug,launch会自动的生成下方的launch.json launch.json { // ...
- Linux学习二:Makefile基础
文首感谢http://www.chinaunix.net 作者:gunguymadman的分享 makefile关系到了整个工程的编译规则.一个工程中的源文件不计数,其按类型.功能.模块分别放在若干个 ...
- 5、Makefile基础知识汇总(转自陈皓总述)
一.Makefile里有什么? Makefile里主要包含了五个东西:显式规则.隐晦规则.变量定义.文件指示和注释. 1.显式规则.显式规则说明了,如何生成一个或多的的目标文件.这是由Makefile ...
随机推荐
- SIX GOD
SIX GOD是什么意思呢.?_百度知道 SIX GOD
- 推荐国内外优秀+免费CDN加速站点及公共cdn加速库
-----------------------------------------------------------------免费CDN加速站点 1.CloudFlare CloudFlare可能 ...
- sql: sybase与oracle中insert into select和select into的用法
1. sybase与oracle中insert into select和select into的用法 http://wjlvivid.iteye.com/blog/1921679 Sybase 一.首 ...
- AJAX实现类似百度的搜索提示,自动补全和键盘、鼠标操作
<script type="text/javascript"> $(document).ready(function(){ var highlightIndex = - ...
- MEAN栈开发
Nodejs之MEAN栈开发(二)----视图与模型 2016-06-02 08:30 by stoneniqiu, 92 阅读, 2 评论, 收藏, 编辑 上一节做了对Express做了简单的介绍, ...
- 基于visual Studio2013解决C语言竞赛题之1069链表查找删除
题目 解决代码及点评 /* 功能:建立一个链表,每个结点包括:学号.姓名.性别.年龄.输入一个年龄,如果链表中的结点所包含的年龄等于此年龄, 将此结点删除,输出最后的链表. 时 ...
- 最新OpenCV2.4.6与VS2010开发环境搭建
OpenCV2.4.6与VS2010开发环境搭建 由于很久没有用OpenCV了,之前用的是1.0版本和VC++6.0.现在已经到了VS2010+OpenCV2.4.6.安装使用之后,发现OpenCV的 ...
- 【zigbee】开启及清除NV_RESTORE信息的方法
1.NV_RESTORE宏的作用 问:coo和终端都已经组网成功 1.这时将coo断电,又一次上电,组网后终端的短地址是否不变? 2.这时终端断电,又一次上电,组网后终端的短地址是否不变? 3.这时C ...
- 机房收费系统总结之4——VB.NET 轻松解决判断文本框、组合框为空问题
纵观机房收费系统,判断文本框.组合框为空问题无非两种情况.第一种:判断窗体中所有文本框.组合框是否为空.第二种:判断一部分文本框.组合框是否为空.下面看看是如何实现这两种情况的. 第一种:判断窗体中所 ...
- [每日一题] OCP1z0-047 :2013-08-29 NULL............................................................168
转载请注明出处:http://blog.csdn.net/guoyjoe/article/details/10558305 正确答案:B 用函数可以针对各种数据类型时行操作,包括NULL值在内.其中有 ...