makefile的基本练习
假设有如下目录结构:(目录结构图)
完成以下操作:
1、通过纯命令编写Makefile文件,并发现使用纯命令的不足;
2、在Makefile中,添加变量,简化参数的重复书写;
3、尝试在多目录环境下,优化一个通用的Makefile文件;
4、思考:makefile在实际的工程还有哪些应用。
1、程序源码
1.1、main.c
#include "add/add.h"
#include "sub/sub.h"
#include "mul/mul.h"
#include "div.h"
int main(int argc, const char *argv[])
{
int a=1,b=2;
printf("a=[%d],b=[%d]\n",a,b);
printf("a+b=[%d]\n", add(1,2));
printf("a-b=[%d]\n", sub(1,2));
printf("a*b=[%d]\n", mul(1,2));
printf("a/b=[%d]\n", divide(1,2));
return 0;
}
1.2、add/add.h
#ifndef _ADD_H
#define _ADD_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int add(int a, int b);
#endif
1.3、add/add.c
#include "add.h"
int add(int a, int b){
return a+b;
}
1.4、sub/sub.h和sub/sub.c
分别声明和定义了函数 sub实现两个整数相减。
1.5、mul/mul.h和mul/mul.c
分别声明和定义了函数 mul实现两个整数相乘。
1.6、div.h和div.c(和main.c同目录)
分别声明和定义了函数divide实现两个整数相除。
2、使用gcc纯写Makefile
all:main.o
gcc main.o add.o sub.o mul.o div.o -o a.out
main.o:add.o sub.o mul.o div.o
gcc -c main.c -o main.o
add.o:add/add.c
gcc -c add/add.c -o add.o
sub.o:sub/sub.c
gcc -c sub/sub.c -o sub.o
mul.o:mul/mul.c
gcc -c mul/mul.c -o mul.o
div.o:div.c
gcc -c div.c -o div.o
clean:
rm -f *.o *.out
问题: 在书写的过程中,文件名称非常多,很容易就写少写或错写文件名称。于是,考虑引入变量来优化此脚本。
3、引入变量并调整参数的顺序
3.1、+=运算
在变量后追加,并在追加内容前后添加空格。例如 var+=a,则var为 a;再执行var+=b,则var的值为 a b
3.2、$@与$^
A:B C
执行指令
$@ 的值为A
$^ 的值为B C
3.3、Make预置或规定的几个变量
RM:默认为 rm -f
CC:默认为cc,一般改为gcc
CFLAGS:c程序编译时期的参数,默认为空
3.4、调整 gcc 参数的顺序
gcc -c aaa.c -o aaa.o 和 gcc -c -o aaa.o aaa.c的执行效果一样
3.5、优化后的Makefile文件如下
RM+=*.out *.o
CC=gcc
OUT=a.out
CFLAGS+=-c -o
all:add.o sub.o mul.o div.o main.o
${CC} -o ${OUT} $^
main.o:main.c
${CC} ${CFLAGS} $@ $^
add.o:add/add.c
${CC} ${CFLAGS} $@ $^
sub.o:sub/sub.c
${CC} ${CFLAGS} $@ $^
mul.o:mul/mul.c
${CC} ${CFLAGS} $@ $^
div.o:div.c
${CC} ${CFLAGS} $@ $^
clean:
${RM}
4、通用Makefile
4.1、两个重要的内置函数
1、wildcard 函数 wildcard 通配符
格式:
1)${wild card *.c} 查出的是当前目录下所有以.c结尾的文件
2)${wild card */*.c} 查出的是所有的二级目录下所有以.c结尾的文件
2、patsubst(patter substitute) 替换-可类比函数replaceAll
格式:
$(patsubst 参数1,参数2,参数3)
参数1:匹配格式
参数2:被替换成什么格式
参数3:要被处理的字符串,若有多个参数,以空格分隔
例如: ${patsubst %.c,%.o,1.c main.c test.c 2.c} 得到的结果为 1.o main.o 2.o
4.2、神技:通配符 %
自己体会,很牛。 结果下述的 %.o:%.c和 all:${OBJS}这两行体会
4.3、优化后的文件
CC=gcc
OUT=a.out
CFLAGS+=-c -o
OBJS=${patsubst %.c,%.o,${wildcard */*.c} ${wildcard *.c}}
all:${OBJS}
${CC} -o ${OUT} $^
%.o:%.c
${CC} ${CFLAGS} $@ $^
clean:
${RM} ${OBJS} ${OUT}
print:
@echo ${OBJS}
5、心得
Makefile的具体作用是什么,我理解为两点:
1)简化编译过程:特别是在复杂的工程中,避免出错;
2)提升编译效率:与文件时间戳相结合,如果重复执行make(不要执行make clean),只有时间戳被更新(被修改)的文件才会进行重新编译。换言之,没有更新的文件,就无需重新编译,以提升编译的效率。