Makefile从入门到上手 2

简介: Makefile从入门到上手

2、两个函数和 clean

①、2 个函数:

找到当前目录下所有后缀为 .c 的文件,赋值给 src

src = $(wildcard ./*.c) # 匹配当前工作目录下的所有.c 文件。将文件名组成列表,赋值给变量 src。 src = add.c sub.c mul.c div1.c

把 src 变量所有后缀为 .c 的文件替换成 .o

obj = $(patsubst %.c, %.o, $(src)) # 将参数 3 中,包含参数 1 的部分,替换为参数 2。 obj = add.o sub.o mul.c div1.o

用这两个函数修改 makefile 如下:

Makefile 第五版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c
obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o
ALL : a.out
hello.o : hello.c
  gcc -c hello.c -o hello.o -I ./
add.o : add.c
  gcc -c add.c -o add.o
sub.o : sub.c
  gcc -c sub.c -o sub.o
mul.o : mul.c
  gcc -c mul.c -o mul.o
div.o : div.c
  gcc -c div.c -o div.o
a.out : $(obj)
  gcc $(obj) -o a.out

执行 make 指令,如下所示:

②、clean

-rm -rf $(obj) a.out # “-” :作用是,删除不存在文件时,不报错。顺序执行结束。

每次要删除 .o 文件,很恶心,于是改写 makefile 如下:

加了 clean 部分

Makefile 第六版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c
obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o
ALL : a.out
hello.o : hello.c
  gcc -c hello.c -o hello.o -I ./
add.o : add.c
  gcc -c add.c -o add.o
sub.o : sub.c
  gcc -c sub.c -o sub.o
mul.o : mul.c
  gcc -c mul.c -o mul.o
div.o : div.c
  gcc -c div.c -o div.o
a.out : $(obj)
  gcc $(obj) -o a.out 
clean :
  -rm -rf $(obj) a.out

rm 前面的 - ,代表出错依然执行。比如,待删除文件集合是 5 个,已经手动删除了 1 个,就只剩下 4 个,然而删除命令里面还是 5 个的集合,就会有删除不存在文件的问题,不加这 - ,就会报错,告诉你有一个文件找不到。加了-就不会因为这个报错。

执行 make

由于没有文件变动, a.out 的时间戳晚于所有依赖文件,这里 make 就没干活

于是,执行时加新指令,先模拟执行 clean 部分:

确定没有问题,执行

3、三个自动变量和模式规则

①、三个自动变量

$@  # 在规则的命令中,表示规则中的目标。
$^  # 在规则的命令中,表示所有依赖条件。组成一个列表,以空格隔开,如果这个列表中有重复项,则去重
$<  # 在规则的命令中,表示第一个依赖条件。如果将该变量应用在模式规则中,它可将依赖条件列表中的依赖依次取出,套用模式规则。

用自动变量修改 makefile,如下:

Makefile 第七版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c
obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o
ALL : a.out
hello.o : hello.c
  gcc -c $< -o $@ -I ./
add.o : add.c
  gcc -c $< -o $@
sub.o : sub.c
  gcc -c $< -o $@
mul.o : mul.c
  gcc -c $< -o $@
div.o : div.c
  gcc -c $< -o $@
a.out : $(obj)
  gcc $^ -o $@
clean :
  -rm -rf $(obj) a.out

sub, add 这些指令中使用 $< 和 $^ 都能达到效果,但是为了模式规则,所以使用的 $<

执行 make,如下:

再来,**上面这个 makefile,可扩展性不行。**比如,要添加一个平方函数,就需要在 makefile 里面增加平方函数的部分。不科学, 所以,模式规则就来了

②、模式规则

<1>、模式规则
%.o : %.c
  gcc -c $< -o %@

修改 makefile,如下:

Makefile 第八版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c
obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o
ALL : a.out
%.o : %.c
  gcc -c $< -o $@
a.out : $(obj)
  gcc $^ -o $@
clean :
  -rm -rf $(obj) a.out

执行 make,如下:

这时,增加一个 square 函数, 并添加 square.c 文件如下:

square.c

int suqare(int a)
{
    return a*a;
}

head.h 做如下修改:

head.h

#ifndef _HEAD_H_
#define _HEAD_H_
int add(int , int );
int sub(int , int );
int div(int , int );
int mul(int , int );
int square(int );
#endif

hello.c 做如下修改:

hello.c

#include <stdio.h>
#include "head.h"
int main(int argc, char *argv[])
{
    int a = 10; int b = 5;
    printf("%d+%d=%d\n", a, b, add(a, b));
    printf("%d-%d=%d\n", a, b, sub(a, b));
    printf("%d/%d=%d\n", a, b, div(a, b));
    printf("%dx%d=%d\n", a, b, mul(a, b));
    printf("%d*%d=%d\n", a, a, mul(a, a));
  return 0;
}

直接执行 make:

增加函数的时候,不用改 makefile,只需要增加.c 文件,改一下源码,就行。很强势。

<2>、静态模式规则

继续优化 makefile,使用静态模式规则,就是指定模式规则给谁用,这里指定模式规则给 obj 用,以后文件多了,文件集合会有很多个,就需要指定哪个文件集合用什么规则

$(obj) : %.o : %.c
  gcc -c $< -o %@

修改后 makefile 如下:

Makefile 第八版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c
obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o
ALL : a.out
$(obj) : %.o : %.c
  gcc -c $< -o $@
a.out : $(obj)
  gcc $^ -o $@
clean :
  -rm -rf $(obj) a.out

运行如下:

4、伪目标

.PHONY: clean ALL

再来一个扩展,当前文件夹下有 ALL 文件或者 clean 文件时,会导致 makefile 瘫痪,如下所示, make clean 没有工作

用伪目标来解决, 添加一行 .PHONY: clean ALL

makefile 如下所示:

Makefile 第九版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c
obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o
ALL : a.out
$(obj) : %.o : %.c
  gcc -c $< -o $@
a.out : $(obj)
  gcc $^ -o $@
clean :
  -rm -rf $(obj) a.out
.PHONY : clean ALL

再来执行 make clean,就不会受到干扰了


目录
相关文章
|
9月前
|
编译器 Shell Linux
Makefile(3)进阶
Makefile(3)进阶
66 0
|
Java 编译器 Linux
Makefile教程(入门介绍)
Makefile教程(入门介绍)
130 0
|
Web App开发 存储 IDE
手把手教你使用LiteIDE配置Go语言开发环境
手把手教你使用LiteIDE配置Go语言开发环境
524 0
|
6月前
|
存储 Java Shell
CMake01快速上手
CMake01快速上手
|
NoSQL 测试技术 Shell
万字总结简化跨平台编译利器CMake,从入门到项目实战演练!(下)
万字总结简化跨平台编译利器CMake,从入门到项目实战演练!(下)
|
9月前
|
Linux 编译器 C语言
快速上手makefile自动化构建工具
快速上手makefile自动化构建工具
|
9月前
|
NoSQL JavaScript Java
Lua开发环境搭建和基础语法
Lua开发环境搭建和基础语法
178 1
|
9月前
|
JSON 开发工具 开发者
CMake进阶教程:深入FetchContent与ExternalProject模块
CMake进阶教程:深入FetchContent与ExternalProject模块
756 0
|
9月前
|
JSON Rust 编译器
Rust 笔记:开发环境搭建与 rust 工具介绍
Rust 笔记:开发环境搭建与 rust 工具介绍
529 0
|
Unix Linux 编译器
万字总结简化跨平台编译利器CMake,从入门到项目实战演练!(上)
万字总结简化跨平台编译利器CMake,从入门到项目实战演练!