makefile的基本练习

发布于:2024-10-10 ⋅ 阅读:(12) ⋅ 点赞:(0)

假设有如下目录结构:(目录结构图)

完成以下操作:

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),只有时间戳被更新(被修改)的文件才会进行重新编译。换言之,没有更新的文件,就无需重新编译,以提升编译的效率。