Linux下Makefile的编写
2015-06-11 10:59
651 查看
在GCC编译中知道
编译流程:
预处理->编译->汇编->链接
每个编译的环节都会产生不同类型的文件,对于C程序:
预处理 -> .i文件
(-E)
编译 -> .s文件
(-S)
汇编 -> .o文件 => .a文件 .so文件
(-c)
链接 -> 可执行文件
每个环节都有自己的依赖,即若想生成.o文件,那么需要.s、.i、.c文件。
那么 对于庞大的工程项目,比如内核源码中存在成千上万个源文件,那么编译的时候,如何实现自动化编译,即源头文件与头文件或者静、动态库之间找到彼此的依赖关系进行编译,最终生成目标文件。
大多数的Winodws的程序员不需要深入了解自动化编译流程,因为Windows的IDE(Integrated Development Environment)已经做了相关的工作,比如VC,VB等。而Linux下没有这样的IDE,通常需要程序员做用脚本自行书写。
要做一个好的professional程序员,尤其是linux程序员,至少需要懂得设计该脚本 - Makefile。
Makfile是一种纯文本的编译脚本,在其中可以指定需要编译哪些文件,哪些先编译,哪些后编译,哪些需要重新编译,最终需要生成怎么样的应用程序。
make是一种命令,它用来解释Makefile脚本,并根据脚本中的指定内容,进行操作。
使用make命令执行Makefile文件。
在默认情况下,make会执行当前目录下的Makefile文件。若当前目录下找不到相关的Makefile文件,则会出现错误:
make: *** No targets specified and no makefile found. Stop.
Makefile文件的命名可以为“Makefile"或"makefile"。
如果使用非标准命名的makefile,必须用命令开关"-f" 或 “-file”。参数 “-f <name>” 或 “--file <mane>”告诉make 读入name 作为makefile文件。
Makefile带来的好处——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
另一个好处,某工程有10万个源文件,如果其中某一个源文件发生改变,不需要重新编译整个工程,但是我们生成应用程序前需要将所有的源文件生成.o文件。makefile会根据文件更新时间而判断,是否需要重新编译源文件成.o文件,在生成应用程序时,只需要将所有的.o文件做链接即可。
Makefile的简单练习
有三个源程序
编写完后,保存,在当前目录下执行make命令,生成可执行程序test。
当执行make的时候,make程序从当前目录读入makefile开始处理第一个非"."的规则,这称作缺省目标。
上述的makefile中,缺省目标是all,由于目标all缺少depend,所以这个规则中的命令会被直接执行。
在执行make的时候,也可以指定目标执行,如make clean,那么make会直接读入执行目标clean,跳过all。
若执行make all,那么与make 功能相同。
Makefile的组成
Makefile里主要包含了五种类型的语句:
显式规则、隐式规则、变量定义、文件指示、注释
注:Makefile中可以直接调用shell命令。
显式规则: 显式规则说明了如何生成一个或多的的目标文件。这是由Makefile 的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令
隐式规则: 由于make有自动推导的功能,所以隐式的规则可以让程序员比较简略地书写Makefile,这是由make所支持,例如,makefile发现.o文件,程序就会自动去找.c文件,并编译成.o文件。
变量的定义: 在Makefile中可定义一系列的变量,变量一般都是字符串,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上
文件指示: 包括了三个部分。
在一个Makefile中引用另一个Makefile
根据某些情况指定执行Makefile中的有效部分
定义一个多行的命令。
注释: Makefile注释使用"#",若Makefile需要用到“#”,则需要做转义“\#”。
规则解释如何编译文件,make根据依赖关系执行产生或更新目标;规则也说明如何和何时执行动作。有的规则看起来很复杂,但都符合下述模式。
<target>:<depend>
command1
command2
……
target是一个目标文件,可以是可执行文件或.o文件,也可以是执行动作。
depend目标的依赖,目标若需要成立,必须有依赖。一个target可以拥有多个depend 。
command是make执行动作,一个目标依赖关系中可以包含多个命令,但是每个command不能是空格或者其它的字符,只可以一个制表符Tab键。
注:若target缺少depend ,那么command会直接被执行。
Makefile自动检测更新
工程若干个源文件中,某一个文件发生了改变,我们希望只重新编译被修改的那一个文件,其它的文件不重新编译。
make在执行时,会确认所有target是否都是最新的,若target的某一个depend的时间比target新,那么make会重新根据依赖关系来执行相应的命令。
make在解释Makefile时,若目标是.o文件,那么他会自动的去寻找相应的.c文件, 并隐式的进行编译。
如下:
使用隐式规则,目标的依赖为三个.o文件,fun1.o, fun2.o,main.o, make自动推导,找到相应.c文件生成找到.o文件。
在Makefile中通常指定需要编译的.c文件,我们可以将多个.c文件名保存在变量SRCS中,再定义另一个变量OBJS使其保存.o文件名。
我们可以直接使用变量的替换方式,将SRCS中的".c"字符串替换成".o",赋值OBJS变量。
SRCS = fun1.c fun2.c main.c
OBJS = $(SRCS:.c=.o)
那么变量OBJS值为fun1.o fun2.o main.o
在定义一个变量之后,我们可以继续在变量后面加上新的值。追加的语法与C语言中复合运算的“+=”类似。
如:
CFLAGS = -Wall
CFLAGS += -O2
那么最终CFLAGS的值为 -Wall -O2
Makefile通用版本
wildcard : 扩展通配符
patsubst :替换通配符
notdir : 去除路径
一般我们可以使用“$(wildcard *.c)”来获取工作目录下的所有的.c文件列表
可以使用“$(patsubst %.c,%.o,$(wildcard *.c))”,首先使用“wildcard”函数获取工作目录下的.c文件列表;
之后将列表中所有文件名的后缀.c替换为.o。这样我们就可以得到在当前目录可生成的.o文件列表。
$^ 代表所有的依赖对象
编译流程:
预处理->编译->汇编->链接
每个编译的环节都会产生不同类型的文件,对于C程序:
预处理 -> .i文件
(-E)
编译 -> .s文件
(-S)
汇编 -> .o文件 => .a文件 .so文件
(-c)
链接 -> 可执行文件
每个环节都有自己的依赖,即若想生成.o文件,那么需要.s、.i、.c文件。
那么 对于庞大的工程项目,比如内核源码中存在成千上万个源文件,那么编译的时候,如何实现自动化编译,即源头文件与头文件或者静、动态库之间找到彼此的依赖关系进行编译,最终生成目标文件。
大多数的Winodws的程序员不需要深入了解自动化编译流程,因为Windows的IDE(Integrated Development Environment)已经做了相关的工作,比如VC,VB等。而Linux下没有这样的IDE,通常需要程序员做用脚本自行书写。
要做一个好的professional程序员,尤其是linux程序员,至少需要懂得设计该脚本 - Makefile。
Makfile是一种纯文本的编译脚本,在其中可以指定需要编译哪些文件,哪些先编译,哪些后编译,哪些需要重新编译,最终需要生成怎么样的应用程序。
make是一种命令,它用来解释Makefile脚本,并根据脚本中的指定内容,进行操作。
使用make命令执行Makefile文件。
在默认情况下,make会执行当前目录下的Makefile文件。若当前目录下找不到相关的Makefile文件,则会出现错误:
make: *** No targets specified and no makefile found. Stop.
Makefile文件的命名可以为“Makefile"或"makefile"。
如果使用非标准命名的makefile,必须用命令开关"-f" 或 “-file”。参数 “-f <name>” 或 “--file <mane>”告诉make 读入name 作为makefile文件。
Makefile带来的好处——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
另一个好处,某工程有10万个源文件,如果其中某一个源文件发生改变,不需要重新编译整个工程,但是我们生成应用程序前需要将所有的源文件生成.o文件。makefile会根据文件更新时间而判断,是否需要重新编译源文件成.o文件,在生成应用程序时,只需要将所有的.o文件做链接即可。
Makefile的简单练习
有三个源程序
#sample makefile script CC=gcc SRCS=fun1.c fun2.c main.c EXEC=test all: $(CC) $(SRCS) -o $(EXEC)
编写完后,保存,在当前目录下执行make命令,生成可执行程序test。
当执行make的时候,make程序从当前目录读入makefile开始处理第一个非"."的规则,这称作缺省目标。
上述的makefile中,缺省目标是all,由于目标all缺少depend,所以这个规则中的命令会被直接执行。
在执行make的时候,也可以指定目标执行,如make clean,那么make会直接读入执行目标clean,跳过all。
若执行make all,那么与make 功能相同。
Makefile的组成
Makefile里主要包含了五种类型的语句:
显式规则、隐式规则、变量定义、文件指示、注释
注:Makefile中可以直接调用shell命令。
显式规则: 显式规则说明了如何生成一个或多的的目标文件。这是由Makefile 的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令
隐式规则: 由于make有自动推导的功能,所以隐式的规则可以让程序员比较简略地书写Makefile,这是由make所支持,例如,makefile发现.o文件,程序就会自动去找.c文件,并编译成.o文件。
变量的定义: 在Makefile中可定义一系列的变量,变量一般都是字符串,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上
文件指示: 包括了三个部分。
在一个Makefile中引用另一个Makefile
根据某些情况指定执行Makefile中的有效部分
定义一个多行的命令。
注释: Makefile注释使用"#",若Makefile需要用到“#”,则需要做转义“\#”。
规则解释如何编译文件,make根据依赖关系执行产生或更新目标;规则也说明如何和何时执行动作。有的规则看起来很复杂,但都符合下述模式。
<target>:<depend>
command1
command2
……
target是一个目标文件,可以是可执行文件或.o文件,也可以是执行动作。
depend目标的依赖,目标若需要成立,必须有依赖。一个target可以拥有多个depend 。
command是make执行动作,一个目标依赖关系中可以包含多个命令,但是每个command不能是空格或者其它的字符,只可以一个制表符Tab键。
注:若target缺少depend ,那么command会直接被执行。
#makefile rule example A:B @echo "A" B:C @echo "B" C:D @echo "C" D: @echo "D" G: @echo "G"分别执行make、make B、make G。 查看结果,并分析结果。
Makefile自动检测更新
工程若干个源文件中,某一个文件发生了改变,我们希望只重新编译被修改的那一个文件,其它的文件不重新编译。
make在执行时,会确认所有target是否都是最新的,若target的某一个depend的时间比target新,那么make会重新根据依赖关系来执行相应的命令。
#sample makefile script CC=gcc OBJS=fun1.o fun2.o main.o EXEC=test all:$(OBJS) $(CC) $(OBJS) -o $(EXEC) fun1.o:fun1.c $(CC) -c fun1.c fun2.o:fun2.c $(CC) -c fun2.c main.o:main.c $(CC) -c main.c clean: rm -rf $(EXEC)由于make有自动推导的功能,所以隐式的规则可以让程序员比较简略地书写Makefile。
make在解释Makefile时,若目标是.o文件,那么他会自动的去寻找相应的.c文件, 并隐式的进行编译。
如下:
使用隐式规则,目标的依赖为三个.o文件,fun1.o, fun2.o,main.o, make自动推导,找到相应.c文件生成找到.o文件。
#sample makefile script CC=gcc OBJS=fun1.o fun2.o main.o EXEC=test all:$(OBJS) $(CC) $(OBJS) -o $(EXEC) clean: rm -rf $(EXEC)Makefile的变量替换
在Makefile中通常指定需要编译的.c文件,我们可以将多个.c文件名保存在变量SRCS中,再定义另一个变量OBJS使其保存.o文件名。
我们可以直接使用变量的替换方式,将SRCS中的".c"字符串替换成".o",赋值OBJS变量。
SRCS = fun1.c fun2.c main.c
OBJS = $(SRCS:.c=.o)
那么变量OBJS值为fun1.o fun2.o main.o
#sample makefile script CC=gcc SRCS=fun1.c fun2.c main.c OBJS=(SRCS:.c=.o) EXEC=test all:$(OBJS) $(CC) $(OBJS) -o $(EXEC) clean: rm -rf $(EXEC)Makefile的变量追加
在定义一个变量之后,我们可以继续在变量后面加上新的值。追加的语法与C语言中复合运算的“+=”类似。
如:
CFLAGS = -Wall
CFLAGS += -O2
那么最终CFLAGS的值为 -Wall -O2
Makefile通用版本
# makefile example CC=gcc CFLAGS = -Wall -O2 CFLAGS += -I./ -L./ LFLAGS = -lpthread -lm SRCS = fun1.c \ fun2.c \ main.c OBJS=$(SRCS:.c=.o) EXEC=test all:$(OBJS) $(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LFLAGS) clean: rm -rf $(EXEC) $(OBJS)常用通配符
wildcard : 扩展通配符
patsubst :替换通配符
notdir : 去除路径
一般我们可以使用“$(wildcard *.c)”来获取工作目录下的所有的.c文件列表
可以使用“$(patsubst %.c,%.o,$(wildcard *.c))”,首先使用“wildcard”函数获取工作目录下的.c文件列表;
之后将列表中所有文件名的后缀.c替换为.o。这样我们就可以得到在当前目录可生成的.o文件列表。
src=$(wildcard *.c ./sub/*.c) dir=$(notdir $(src)) obj=$(patsubst %.c,%.o,$(dir) ) all: @echo $(src) @echo $(dir) @echo $(obj) @echo "end"编译目录下所有的C文件
CC = gcc LD = gcc CFLAGS = -Wall -c -I. LDFLAGS = -lpthread SRCS=$(wildcard *.c) OBJS=$(patsubst %.c,%.o,$(SRCS)) TARGET = huzl_test .PHONY: all clean all: $(TARGET) $(TARGET): $(OBJS) $(LD) $(LDFLAGS) $^ -o $@ %o: %c $(CC) $(CFLAGS) $< -o $@ clean: @rm -f *.o $(TARGET)“$<”和“$@”是自动化变量,“$<”表示规则中的第一个依赖文件,“$@”表示规则中的目标文件
$^ 代表所有的依赖对象
相关文章推荐
- Linux升级Ruby
- linux中的IIC设备驱动
- DDoS deflate - Linux下防御/减轻DDOS攻击
- Linux内核中的Kconfig、Makefile、.config
- Linux上iptables防火墙的基本应用教程(优秀)
- CentOS6.5 (64bit) 光盘内部FTP源
- linux驱动模块
- Linux 文件内容查看命令
- Linux上ssh免密码登录
- 以下内容参考了抚琴煮酒的《构建高可用Linux服务器》第六章内容
- 收集的 Linux CAT用法
- Linux dkpg命令
- Linux启动报错UNEXPECTED INCONSISTENCY; RUN FSCK MANUALLY
- 嵌入式 Linux线程同步读写锁rwlock示例
- linux set
- Linux rpm安装MySQL
- Linux apt-get命令
- centos yum php 5.5
- 怎么将unbuntu Linux iOS 文件从U盘或者移动硬盘启动?用win32diskimager_cn
- CentOS 升级autoconf