在例子中说明makefile写法
直接举例说明。有如下源程序。
/* main.c */
#include "mytool1.h"
#include "mytool2.h"
int main(int argc,char **argv)
{
mytool1_print("hello");
mytool2_print("hello");
}
/* mytool1.h */
#ifndef _MYTOOL_1_H
#define _MYTOOL_1_H
void mytool1_print(char *print_str);
#endif
/* mytool1.c */
#include "mytool1.h"
void mytool1_print(char *print_str)
{
printf("This is mytool1 print %s ",print_str);
}
/* mytool2.h */
#ifndef _MYTOOL_2_H
#define _MYTOOL_2_H
void mytool2_print(char *print_str);
#endif
/* mytool2.c */
#include "mytool2.h"
void mytool2_print(char *print_str)
{
printf("This is mytool2 print %s ",print_str);
}
一般的编译步骤:
gcc -c main.c
gcc -c mytool1.c
gcc -c mytool2.c
gcc -o main main.o mytool1.o mytool2.o
这样我们就生成了我们需要的可运行的main文件。
但是当我们的工程很大的时候,有时候修改了几个源文件,我们得按照上面的一般编译步骤重新敲命令就很麻烦了,所以需要利用makefile来维护。
makefile有两种标准写法。
makefile基础认识
先有个感性的认识。
第一种形如:
main:main.o mytool1.o mytool2.o
gcc -o main main.o mytool1.o mytool2.o
main.o:main.c mytool1.h mytool2.h
gcc -c main.c
mytool1.o:mytool1.c mytool1.h
gcc -c mytool1.c
mytool2.o:mytool2.c mytool2.h
gcc -c mytool2.c
备注一下:
其实上面的依赖关系中,*.h文件都可以去掉。因为规则中并无*.h文件。举例说明如下:
mytool1.c文件中#include "mytool1.h"文件,即便makefile中mytool1.o不写上依赖mytool1.h,当mytool1.h文件内容改变时候,由于mytool1.c文件包含了mytool1.h文件,所以mytool1.c文件内容实际也是改变了的,所以依然会执行生成mytool1.o文件的规则。
第二种形如:
OBJS = main.o mytool1.o mytool2.o
CC = gcc
CFLAGS = -Wall -O -g
main:$(OBJS)
$(CC) $(OBJS) -o main
main.o:main.c mytool1.h mytool2.h
$(CC) $(CFLAGS) -c $< -o main.o
mytool1.o:mytool1.c mytool1.h
$(CC) $(CFLAGS) -c $< -o $@
mytool2.o:mytool2.c mytool2.h
$(CC) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
rm *.o main
makefile写法
一般的格式是:
目标文件 : 依赖文件
tab键缩进 编译规则
目标文件 : 依赖文件
tab键缩进 编译规则
当倚赖的对象在目标修改后修改的话,就要去执行规则一行所指定的命令。
(注意一定要是tab键缩进,否则会报错如下)
Makefile有三个非常有用的变量。分别是$@,$^,$<代表的意义分别是:
$@ -- 目标文件
$@ -- 目标文件
$^ -- 所有的依赖文件
$< -- 第一个依赖文件
$+ -- $+和$^类似,也是所有的依赖文件,只是它不取出重复的依赖目标
如果我们使用上面三个变量,那么我们可以简化我们的Makefile文件为:
# 这是简化后的Makefile
main:main.o mytool1.o mytool2.o
gcc -o $@ $^
main.o:main.c mytool1.h mytool2.h
gcc -c $<
mytool1.o:mytool1.c mytool1.h
gcc -c $<
mytool2.o:mytool2.c mytool2.h
gcc -c $<
经过简化后,我们的Makefile是简单了一点,不过人们有时候还想简单一点。这里我们学习一个Makefile的缺省规则。.c.o:
gcc -c $<
这个规则表示所有的 .o文件都是依赖与相应的.c文件的。
例如mytool.o依赖于mytool.c这样Makefile还可以变为:
gcc -c $<
这个规则表示所有的 .o文件都是依赖与相应的.c文件的。
例如mytool.o依赖于mytool.c这样Makefile还可以变为:
# 这是再一次简化后的Makefile
main:main.o mytool1.o mytool2.o
gcc -o $@ $^
.c.o:
gcc -c $<
makefile一些函数
addprefix 加前缀函数
patsubst 替换通配符
notdir 去除路径
wildcard 扩展通配符
函数wildcard得到指定目录下所有的C语言源程序文件名的方法,这下好了,不用手工一个一个指定需要编译的.c文件了,方法如下:
SRC = $(wildcard *.c)
等于指定编译当前目录下所有.c文件,如果还有子目录,比如子目录为inc,则再增加一个wildcard函数,象这样:
SRC = $(wildcard *.c) $(wildcard inc/*.c)
SRC = $(wildcard *.c)
等于指定编译当前目录下所有.c文件,如果还有子目录,比如子目录为inc,则再增加一个wildcard函数,象这样:
SRC = $(wildcard *.c) $(wildcard inc/*.c)
例子:
建立一个测试目录,在测试目录下建立一个名为sub的子目录
$ mkdir test
$ cd test
$ mkdir sub
在test下,建立a.c和b.c 两个文件,在sub目录下,建立sa.c和sb.c 两个文件
建立一个简单的Makefile
src=$(wildcard *.c ./sub/*.c)
dir=$(notdir $(src))
obj=$(patsubst %.c,%.o,$(dir) )
all:
@echo $(src)
@echo $(dir)
@echo $(obj)
@echo "end"
执行结果分析:
第一行输出:
a.c b.c ./sub/sa.c ./sub/sb.c
wildcard把 指定目录 ./ 和 ./sub/ 下的所有后缀是c的文件全部展开。
建立一个测试目录,在测试目录下建立一个名为sub的子目录
$ mkdir test
$ cd test
$ mkdir sub
在test下,建立a.c和b.c 两个文件,在sub目录下,建立sa.c和sb.c 两个文件
建立一个简单的Makefile
src=$(wildcard *.c ./sub/*.c)
dir=$(notdir $(src))
obj=$(patsubst %.c,%.o,$(dir) )
all:
@echo $(src)
@echo $(dir)
@echo $(obj)
@echo "end"
执行结果分析:
第一行输出:
a.c b.c ./sub/sa.c ./sub/sb.c
wildcard把 指定目录 ./ 和 ./sub/ 下的所有后缀是c的文件全部展开。
第二行输出:
a.c b.c sa.c sb.c
notdir把展开的文件去除掉路径信息
第三行输出:
a.o b.o sa.o sb.o
在$(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o,
任何输出。
或者可以使用
obj=$(dir:%.c=%.o)
效果也是一样的。
这里用到makefile里的替换引用规则,即用您指定的变量替换另一个变量。
它的标准格式是
$(var:a=b) 或 ${var:a=b}
它的含义是把变量var中的每一个值结尾用b替换掉a。
makefile一些细节问题
符号“=”、“:=”、“?=”、“+=”的区别
= 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值
举个例子说明:
1、“=”
make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。看例子:
x = foo
y = $(x) bar
x = xyz
在上例中,y的值将会是 xyz bar ,而不是 foo bar 。
2、“:=”
“:=”表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。
x := foo
y := $(x) bar
x := xyz
在上例中,y的值将会是 foo bar ,而不是 xyz bar 了。
make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。看例子:
x = foo
y = $(x) bar
x = xyz
在上例中,y的值将会是 xyz bar ,而不是 foo bar 。
2、“:=”
“:=”表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。
x := foo
y := $(x) bar
x := xyz
在上例中,y的值将会是 foo bar ,而不是 xyz bar 了。