Linux高级编程--03.make和makfile
Makefile语法基础
在Linux下,自动化编译工具是通过make命令来完成的(一些工具厂商也提供了它们自己的make命令,如gmake等),make命令的基本格式如下:
make [-f makefile] [label]
它可以通过-f参数指定输入文件,当省略-f参数时,默认输入文件名为Makefile,由于我们通常不用这个-f参数,往往就用默认的Makefile文件名。
Makefile是一个文本文件,它是基于一定的语法规则的,它的基本执行规则定义如下:
target : [prerequisites]
command
- target :标签,用于标志当前构建的规则,它也可以是文件。
- prerequisites :依赖项,在构建该标签的时候先执行的规则
- command make :需要执行的命令。(任意的Shell命令)
注意:Makefile的target是顶格写的,而Command需要加一个Tab键。
例如,我们编写一个简单的Makefile:
clean:
@echo "clean"
all:
@echo "all"
当我们直接执行make命令的时候,输出如下:
$make
clean
$make all
all
$make clean
clean
从中我们可以看到:默认情况下构建第一个标签。可以通过在命令行参数中通过参数构建指定标签。
然后我们再来看看依赖性是如何工作的,这次我们修改一下Makefile,让all标签依赖于clean标签:
clean :
@echo "clean"
all : clean
@echo "all"
再次执行make all的时候,发现会先执行clean标签:
$make all
clean
all
用Makefile来构建项目
通过对Makefile的语法有一个简单的了解后,下面就可以用Makefile简化我们的构建操作了。还是针对前面的那个stack的例子吧,首先我们来实现一个最简单的例子:
all :
gcc -o run main.c stack.c
这样直接通过make命令就可以实现对gcc -o run main.c stack.c
整条命令的执行了。
更加一步,我们想实现增量编译,则要实现如下规则:
- 如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
- 如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
这个时候就需要前面的依赖性出马了:
run : stack.o main.o
gcc -o run main.o stack.o
stack.o : stack.c
gcc -c stack.c
main.o : main.c
gcc -c main.c
run默认依赖于stack.o和main.o,因此,当构建run的时候,就会先构建stack.o和main.o,输出方式如下:
make
gcc -c stack.c
gcc -c main.c
gcc -o run main.o stack.o
当我们只改了其中某个文件的时候,例如stack.c,这是由于main.c没有变化,因此不会重新编译main.o,只会重新构建stack.o和run,从而实现我们的增量编译的目的。(这个其实才是make比shell或脚本语言编写的批处理方式要强大的地方)
make
gcc -c stack.c
gcc -o run main.o stack.o
通过自动推导改进Makefile
通过上面的例子可以看到,虽然我们可以实现增量编译,但是整个Makefile过程是非常复杂的,需要对每个.o文件编写编译脚本。如果项目文件较多,并且有增删的话,则编写Makefile文件非常麻烦。
为了改进这个问题,makefile提供了一个自动推导的功能,通过它可以简化我们的编写过程。例如,前面的例子可以简化如下:
CC = gcc
objs = stack.o main.o
run : $(objs)
$(CC) -o run $(objs)
这里我们引入了两个变量,第一个行的CC制定了编译器为gcc(如果不指定则是默认的cc),第二行制定了我们的obj文件。
这样,只需要执行make命令即可生产我们的程序:
make
gcc -c -o stack.o stack.c
gcc -c -o main.o main.c
gcc -o run stack.o main.o
可以看到,make命令会自动推导出如何根编出.o文件来。如果我们的项目文件变化了,只需要改objs变量即可,非常方便。
不过,有的时候我们可能觉得这中自动推导的方式不够用,需要手动控制编译选项,这个时候我们可以自己指定推导规则:
CC = gcc
objs = stack.o main.o
run : $(objs)
$(CC) -o run $(objs)
$(objs): %.o: %.c
$(CC) -c -g $< -o $@
上面的例子中,指明了我们的目标从$objs
中获取, %.o
表明要所有以“.o”结尾的目标,也就是 stack.o main.o
,也就是变量$objs
集合的模式,而依赖模式“%.c”则取模式 %.o
的“%”,也就是“stack main”,并为其加下“.c”的后缀,于是,我们的依赖目标就是 stack.c main.c
。而命令中的 $<
和“$@”则是自动化变量, $<
表示所有的依赖目标集(也就是 stack.c main.c
), $@
表示目标集(也就是stack.o main.o
)。于是,上面的规则展开后等价于下面的规则:
stack.o : stack.c
$(CC) -c -g stack.c -o stack.o
main.o : main.c
$(CC) -c -g main.c -o main.o
试想,如果我们的 %.o
有几百个,那种我们只要用这种很简单的“静态模式规则”就可以写完一堆规则,实在是太有效率了。“静态模式规则”的用法很灵活,如果用得好,那会一个很强大的功能。如果想进一步的了解,可以参考跟我一起写 Makefile这篇文章。
Linux高级编程--03.make和makfile的更多相关文章
- linux高级编程基础系列:线程间通信
linux高级编程基础系列:线程间通信 转载:原文地址http://blog.163.com/jimking_2010/blog/static/1716015352013102510748824/ 线 ...
- Linux高级编程--10.Socket编程
Linux下的Socket编程大体上包括Tcp Socket.Udp Socket即Raw Socket这三种,其中TCP和UDP方式的Socket编程用于编写应用层的socket程序,是我们用得比较 ...
- Linux高级编程--05.文件读写
缓冲I/O和非缓冲I/O 文件读写主要牵涉到了如下五个操作:打开.关闭.读.写.定位.在Linux系统中,提供了两套API, 一套是C标准API:fopen.fclose.fread.fwrite.f ...
- linux高级编程
系统调用 01.什么是系统调用? 02.Linux系统调用之I/O操作(文件操作) 03.文件描述符的复制:dup(), dup2() 多进程实现多任务 04.进程的介绍 05.Linux可执行文件结 ...
- Linux高级编程--02.gcc和动态库
在Linux环境下,我们通常用gcc将C代码编译成可执行文件,如下就是一个简单的例子: 小实验:hello.c #include <stdlib.h> #include <stdio ...
- Linux高级编程--01.vi命令
VI是Linux/Unix下标配的一个纯字符界面的文本编辑器.由于不支持鼠标功能,也没有图形界面,相关的操作都要通过键盘指令来完成,需要记忆大量命令.因此很多人不大喜欢它,但同时由于键盘的方式往往比鼠 ...
- linux高级编程补充知识
F: 计算机系统结构: ------------------------------- 应用程序 ----------------- | 库函数 -------------------------- ...
- Linux高级编程--11.信号
基本概念 信号在Linux中是一个比较常见的概念,例如我们按Ctrl+C中断前台进程,通过Kill命令结束进程都是通过信号实现的.下面就以Ctrl+C为例简单的说明信号的处理流程: 用户按下Ctrl- ...
- Linux高级编程--08.线程概述
线程 有的时候,我们需要在一个基础中同时运行多个控制流程.例如:一个图形界面的下载软件,在处理下载任务的同时,还必须响应界面的对任务的停止,删除等控制操作.这个时候就需要用到线程来实现并发操作. 和信 ...
随机推荐
- tensorflow之曲线拟合
视频链接:https://morvanzhou.github.io/tutorials/machine-learning/ML-intro/ 1.定义层 定义 add_layer() from __f ...
- lintcode-418-整数转罗马数字
418-整数转罗马数字 给定一个整数,将其转换成罗马数字. 返回的结果要求在1-3999的范围内. 说明 什么是 罗马数字? https://en.wikipedia.org/wiki/Roman_n ...
- 阿里云服务器内部dns可能出错
今天部署一个阿里云服务器,所有配置项都改好了,就是连接不上本机. 反复查找,防火墙端口和网卡接口都配置对了,selinux也关闭了,但就是连接不上阿里云内网的ip. 由于连接是本机,把ip填写为127 ...
- PHP执行原理
简单解释:PHP执行原理 客户端向服务器发送一个请求,如果请求的是一个HTML页面,服务器直接将HTML页面发送到客户端给浏览器解析,如果请求的是PHP页面,则服务器会运行PHP页面然后生成标准的HT ...
- Sql Server统计报表案例
场景:查询人员指定年月工作量信息 USE [Test] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER procedure [dbo ...
- 【Linux笔记】Linux中inittab剖析
Linux完成内核(Kernel)引导后,会由init初始化进程调用/etc/inittab配置文件(ps -aux | less,init进程号为始终为1,是所有系统进程的起点,init进程也有一个 ...
- collection 多态 会自动转型为子类 继承多态需要显示转型
- 包装类 integer 当做 list的参数时候 会出现无法删除成功的现象
- 题解 P2955 【[USACO09OCT]奇数偶数Even? Odd? 】
很明显这题是个假入门! 小金羊一不小心点进题解发现了内幕 能看的出来都WA过Unsigned long long int 做题可以用Python,Python的变量虽然 强悍的不行! 但是我们可以用字 ...
- [BZOJ1503][NOI2004]郁闷的出纳员 无旋Treap
1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec Memory Limit: 64 MB Description OIER公司是一家大型专业化软件公司,有着数以万计的员 ...