1. makefile基本使用
Make工程管理器是一个用来管理多文件的文件转化管理工具
语法:
目标:依赖1 依赖2
规则(前面必须是Tab)
依赖1:
规则1
依赖2:
规则2
示例1:使用makefile输出helloworld
首先使用vim创建一个文本文件,命名为makefile。内容为:
all:
echo "hello world"
make 运行: 输出hello world ,make 默认执行第一个目标,如果要执行其他的,使用
make + 目标
示例2:在示例1的基础上添加一个新的目标
all:
@echo "hello world"
test:
@echo "nihao farsight"
使用make运行执行all ,要执行 test目标 使用make test
示例3:修改示例2,使得make也可以生成test目标
all:test
@echo "hello world"
test:
@echo "nihao farsight"
在"all:"后面添加了一个新的字段"test",这个字段就是“依赖关系”。"all:test"这个字段的意思就是:生成目标all需要依赖目标test。这样makefile在生成all之前会先去生成目标test,在生成目标test后才会去生成目标all。一个目标可以有多个依赖关系,若一个目标有多个依赖关系,则所有的依赖关系都写在冒号之后,用空格分隔。
因此编写一个makefile最重要的就是要弄懂需要生成的目标,以及生成这些目标需要的依赖关系。“目标”与“依赖”是使用makefile的重点,我们需要重点关注。
2. makefile在c语言中编译使用
源码文件:
main.c
************************************************
#include <stdio.h>
#include "my.h"
int main(int argc,char *args[]){
printf("add--%d\n",add(4,5));
printf("sub--%d\n",sub(5,4));
return 0;
}
my.h:
************************************************
#ifndef _MY_H
#define _MY_H
// 头文件定义,避免多次引入头文件 _MY_H是宏名字,可以自定义
extern int add(int a,int b);
extern int sub(int a,int b);
#endif
add.c
************************************************
#include <my.h>
int add(int a,int b){
return a+b+100;
}
sub.c
************************************************
#include <my.h>
int sub(int a,int b){
return a-b;
}
1. makefile基础使用:
all:
gcc add.c sub.c main.c -o main -I.
问题: 如果修改了add.c那么所有的文件都要重新编译,当文件比较少的时候没有问题,文件比较多,比如linux内核30万个文件,出问题,解决如下
all:main.o add.o sub.o # main.o foo.o依赖于main.o首先执行下面的main.o:main.c.....
gcc main.o add.o sub.o -o main
main.o:main.c
gcc main.c -c -o main.o -I.
add.o:add.c
gcc add.c -c -o add.o -I.
sub.o:sub.c
gcc sub.c -c -o sub.o -I.
clean:
rm *.o
Make工程管理器对参与编译的代码的管理原则是“若未改动则不参与”,若makefile发现这次参与编译的某些文件在上次编译后一直未被修改,则本次编译会自动忽略这些文件,从而减少编译时间。
那么如果修改了add.c那么编译make,只会编译add.c 根据上面makefile的原则
问题:如果新加了.c文件,那么都要重新编译,解决如下
1.1.1使用:wildcard 函数 和 patsubst 函数
src = $(wildcard ./*.c) # wildcard意义把该目录下的*.c赋值给src add.c sum.c main.c
obj = $(patsubst %.c,%.o,$(src)) # 函数意义,把$(src)下 add.c(%.c) 赋值给 add.o(%.o)
#all:main.o add.o sub.o # main.o foo.o依赖于main.o首先执行下面的main.o:main.c.....
all: $(obj)
# gcc main.o add.o sub.o -o main
gcc $(obj) -o main
main.o:main.c
gcc main.c -c -o main.o -I.
add.o:add.c
gcc add.c -c -o add.o -I.
sub.o:sub.c
gcc sub.c -c -o sub.o -I.
clean:
# rm *.o
rm $(obj)
1.1.2:自动变量使用:
$@: 在规则命令中,表示规则中目标
$^: 表示所有依赖条件
$<: 表示第一个依赖条件,如果该变量在模式规则中,它将依赖条件列表中依次取出,套用模式规则
src = $(wildcard ./*.c) # wildcard意义把该目录下的*.c赋值给src add.c sum.c main.c
obj = $(patsubst %.c,%.o,$(src)) # 函数意义,把$(src)下 add.c(%.c) 赋值给 add.o(%.o)
#all:main.o add.o sub.o # main.o foo.o依赖于main.o首先执行下面的main.o:main.c.....
all: main.out
main.out: $(obj)
# gcc main.o add.o sub.o -o main
# gcc $(obj) -o main
gcc $^ -o $@
main.o:main.c
gcc $< -c -o $@ -I.
add.o:add.c
gcc $< -c -o $@ -I.
sub.o:sub.c
gcc $< -c -o $@ -I.
clean:
# rm *.o
rm $(obj)
1.1.3: 模式规则:
%.o:%.c
gcc -c $< -o $@ -I.
问题:如果一个makefile中需要多个模式规则,上面默认的,无法指定其他模式规则,那么需要使用静态模式规则如下:
$(obj):%.o:%.c
gcc -c $< -o $@ -I.
src = $(wildcard ./*.c) # wildcard意义把该目录下的*.c赋值给src add.c sum.c main.c
obj = $(patsubst %.c,%.o,$(src)) # 函数意义,把$(src)下 add.c(%.c) 赋值给 add.o(%.o)
#all:main.o add.o sub.o # main.o foo.o依赖于main.o首先执行下面的main.o:main.c.....
all: main.out
main.out: $(obj)
# gcc main.o add.o sub.o -o main
# gcc $(obj) -o main
gcc $^ -o $@
# %.o:%.c #模式规则
$(obj):%.o:%.c ##使用静态模式规则
gcc -c $< -o $@ -I.
clean:
# rm *.o
rm $(obj)
1.1.4:makefile假目标
在makefile最后添加了一个clean目标用于清除生成的.o文件。但是添加了clean目标后会造成一个问题:若我们的C语言源文件内恰好有一个clean.c文件,则我们执行make clean的时候,makefile不会执行清除文件命令,而是会编译clean.c生成clean文件。
在实际的程序开发中也难免出现所定义的目标与已存在的文件重名的情况。针对于这种情况,makefile提供了“假目标(phony target)”这个用法。
假目标使用.PHONY关键字定义,注意.PHONY关键字都是大写。
.PHONY:clean
myArgs = -Wall -g
src = $(wildcard ./*.c) # wildcard意义把该目录下的*.c赋值给src add.c sum.c main.c
obj = $(patsubst %.c,%.o,$(src)) # 函数意义,把$(src)下 add.c(%.c) 赋值给 add.o(%.o)
#all:main.o add.o sub.o # main.o foo.o依赖于main.o首先执行下面的main.o:main.c.....
all: main.out
main.out: $(obj)
# gcc main.o add.o sub.o -o main
# gcc $(obj) -o main
gcc $^ -o $@ $(myArgs)
# %.o:%.c #模式规则
$(obj):%.o:%.c ##使用静态模式规则
gcc -c $< -o $@ -I. $(myArgs)
clean:
# rm *.o
rm $(obj)
1.2. makefile练习:
源码.c在src目录下,.h在头文件在inc下,.o在obj下如何写makefile
.PHONY:clean
myArgs = -Wall -g
inc_path= ./inc
src = $(wildcard ./src/*.c) # wildcard意义把该目录下的*.c赋值给src ./src/add.c ./src/sum.c
obj = $(patsubst ./src/%.c,./obj/%.o,$(src)) # 函数意义,把$(src)下 add.c(%.c) 赋值给 add.o(%.o) ./obj/add.o
#all:main.o add.o sub.o # main.o foo.o依赖于main.o首先执行下面的main.o:main.c.....
all: main.out
main.out: $(obj)
# gcc main.o add.o sub.o -o main
# gcc $(obj) -o main
gcc $^ -o $@ $(myArgs)
# %.o:%.c #模式规则
$(obj):./obj/%.o:./src/%.c ##使用静态模式规则
gcc -c $< -o $@ $(myArgs) -I $(inc_path)
clean:
# rm *.o
rm $(obj)
3 . makefile 变量、函数:
变量:
即时变量 A := xxx # A值确定在定义时
延时变量 B = xxx # B值 使用时候才确定
A := $(C)
B = $(C)
C = abc
all:
@echo A = $(A) # A值在确定的时候定义,A 为空
@echo B = $(B) # B abc 123 使用时候才确定
C += 123 # 变量累加
Makefile函数
1. foreach
2. filter 、filter-out
3. patsubst
A = a b c
# makefile define a list by space
B = $(foreach f,$(A),$(f).o)
# $ invoke function , f is a item
all:
@echo B=$(B)
# output result a.o b.o c.o
C = a b c d/
D = $(filter %/,$(C))
E = $(filter-out %/,$(C))
test1:
@echo $(D) # filter %/ result d/
@echo $(E) # filter not %d rssult a b c
F = $(wildcard *.c) # get current dictory file list
G = $(patsubst %.c,%.d,$(F)) # replace %.c to %.d
test2:
@echo F=$(F)
@echo G=$(G)
B=a.o b.o c.o # 替换列中的内容
d/ # 从列表中取出符合这个格式的值
a b c # 从 列表中取出不符合格式的值
F=a.c b.c # 获取本地目录符合要求的文件
G=a.d b.d # 替换 list