makefile编写与使用

简介: makefile编写与使用

makefile编写与使用

makefile简介

  makefile 是一种类似shell的脚本文件,需要make工具进行解释 makefile 内的语句,然后执行内部语句。Makefile的作用是去管理工程项目,比如一个项目有很多c文件,需要利用Makefile去统一进行编译或者其他操作。[1]

  makefile 命名为 makefile 或者 Makefile,如果取名为其他,那么执行时需要使用:

 make -f 自定义makefile文件名字

1. makefile 基本规则

makefile由一组规则组成,每条规则的格式是:

目标: 依赖
(tab)命令

其中格式内容的含义是:

​ 目标:想要生成的目标文件

​ 依赖:生成目标文件所需要的文件

​ 命令:通过执行该命令,将依赖文件生成目标文件

2. makefile 中的变量

2.1 自定义变量

  直接使用 = 赋值变量,使用 &(变量名) 来获取变量

name=lisi
person=$(name)

2.2 自带变量

  makefile 自己默认的一些变量,用户直接赋值。

#CPP编译器名称
CPP=g++
#C编译器名称
CC=gcc
#CPP预处理选项选项 -I 大哎(头文件路径)
CPPFLAGS=-I
#CPP编译器选项
CXXFLAGS=
#C编译器选项 -Wall -g -c
CPPFLAGS=
#链接器选项 -l 小艾尔(链接库名);-L 大艾尔(链接库所在文件夹)
LDFLAGS=

2.3 自动变量

  makefile 里面一些特定符号代表的特殊含义。

$@ :表示规则中的目标
$< :表示规则中的第一个条件
$^ :表示规则中的所有条件,如果有重复项会消除重复项。

模式规则

在makefile中 ,% 代表 一个或多个

3. makefile 函数

#1. wildcard  查找指定目录下的指定类型的文件
#查找当前文件夹下所有 .c 文件,赋值给src
#假如当前文件夹下有 fun1.c fun2.c,那么  src=fun1.c fun2.c
src=$(wildcard *.c)
#2. patsubst  匹配替换,将某个字符串中的某些字符替换为另一个字符
#下面就是将 src 中的 .c 文件替换为 .o 文件,并赋值给 obj
#假如 src=fun1.c fun2.c,那么 obj=fun1.o fun2.o
obj=$(patsubst %.c,%.o,$(src))

#还可以不用函数,使用下面这个
obj=$(src:.c=.o)
也就是把src里面的.c 替换为.o
#3. addprefix 添加前缀
preobj=$(addprefix objs/, $(obj))
.PHONY:todo
todo:
    @echo $(preobj)
#执行 make todo
#输出 objs/base.o
#4. filter 过滤器
files = $(wildcard *.*)
files := $(filter %.cpp %.c, $(files))
.PHONY:filter
filter:
    @echo $(files)
#执行 make filter
#输出 base.c base.cpp
#5. filter-out 反过滤器,和上面的相反,这个是去除匹配到的
files = $(wildcard *.*)
files := $(filter-out%.cpp %.c, $(files))
.PHONY:filter
filter:
    @echo $(files)
#执行 make filter
#输出 base.h base.hpp
#6. strip 去除字符串间多余空格
strips = a.c  b.c       d.c
strips :=$(strip $(strips))
.PHONY:strip
strip:
    @echo $(strips)
#执行 make strip
#输出 a.c b.c d.c
#7. subst 将字符串substs中的所有 .c 替换为 .o
substs = .c.c.o .o.c.c
substs := $(subst .c,.o,$(substs))
.PHONY:substs
substs:
    @echo $(substs)
#执行 make substs
#输出 .o.o.o .o.o.o
#8. abspath 将相对路径转换为绝对路径
RELATIVE_PATH = ./base.c 
ABSOLUTE_PATH = $(abspath $(RELATIVE_PATH)) 
.PHONY:abspath
abspath: 
    @echo "Relative path: $(RELATIVE_PATH)" 
    @echo "Absolute path: $(ABSOLUTE_PATH)"
#执行 
make abspath
#输出 
Relative path: ./base.c 
Absolute path: /home/user/base.c
#9. word 系列函数
word=$(word 3, a b c)    #获取字符串中第3个单词
words=$(words a b c) #返回有多少个单词
firstword=$(firstword a b c)
lastword=$(lastword a b c)
curdir = $(shell pwd)
.PHONY:wordsys
wordsys:
    @echo "3 word is $(word)"
    @echo "total word is $(words)"
    @echo "first word is $(firstword)"
    @echo "lastword word is $(lastword)"

#执行
make wordsys
#输出
3 word is c
total word is 3 
first word is a
lastword word is c
#10. shell 执行shell命令,并将结果赋值给变量
curdir = $(shell ls)
.PHONY:lldir
lldir:
    @echo "curdir is $(curdir)"

#执行
make lldir
#输出 文件列表
#11. 日志打印函数
$(info "infoing...")
$(warning "warning...")
$(error "erroring...")

#在解析Makefile 的时候会输出,如果是error会暂停执行
#输出
"infoing..."
Makefile:3: "warning..."
Makefile:4: *** "erroring...".  Stop.

4. 伪目标

  伪目标的作用是为了让 makefile 不去检查当前目标是否为最新,不管是不是最新都执行这个目标的命令。

#格式
# 伪目标
.PHONY:clean
clean:
        rm -rf $(target) $(obj)

  需要伪目标的原因就是,make 在解析 makefile 时,它首先去执行第一条规则,这条规则称为终极规则。假如这条规则里面的 依赖有更新,那么就会去找依赖对应的规则去执行,然后再执行最终规则。假如依赖都是最新,那么不会执行最终规则。可以看到如下提示:

#执行
make
#输出
make: 'xxx' is up to date.
# 表示当前最终规则是最新的,不需要执行最终规则

####假如如果当前目录下有同名clean文件####
#一定要添加 .PHONY 表示 clean 目标是一个伪目标,表示不需要检查文件是否存在或者已更新,会直接去执行这个伪目标的命令
#如果不添加,由于clean 这个目标的规则没有依赖,所以认为它的依赖是最新的,然后检查是否存在clean文件,发现确实存在一个没有更新的名为 clean 的文件,最终导致clean不会执行.
#例如直接写下面这样,不添加 .PHONY , 并且存在一个名为 clean 的文件:
clean:
        rm -rf $(target) $(obj)

#执行
make clean
#输出以下内容,无法执行目标命令。
make: 'clean' is up to date.

5. 特殊变量

5.1 MAKECMDGOALS 变量

#全局变量
.PHONY:show args
show args:
    @echo "\$$@ = $@"
    @echo "MAKECMDGOALS = $(MAKECMDGOALS)"

#执行
make show
#输出
$@ = show
MAKECMDGOALS = show

#执行
make show args
#输出
$@ = show
MAKECMDGOALS = show args
$@ = args
MAKECMDGOALS = show args

5.2 MAKEFILE_LIST 变量

获取包含的 Makefile 列表

name1 := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
include tttfile
name2 := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
show:
    @echo $(name1)
    @echo $(name2)
#执行
make -f mmmfile
#输出
mmmfile
tttfile

6. include 命令

包含另一个Makefile 文件,让另一个 Makefile 文件 在本文件中展开,另一个文件的变量能够在本文件内直接使用

# mmmfile 文件
CFLAGS= abc
#Makefile 文件
include mmmfile
.PHONY:all
all:
    @echo $(CFLAGS)
#执行
make all
#输出
abc

7. export 命令

可以在Makefile中导出 全局变量 ,并用在shell环境中

export nums=10
.PHONY:expnum
expnum:
    @echo $(nums)
#执行
make expnum
#输出
10

8. 获取make 后附带的变量值

.PHONY:expval
expval:
    @echo $(a)
#执行 make expnum a='showtime'
#输出 showtime

基础综合案例

用到四个基础文件 file1.c、file2.c 、head.h、hello.c,一个 makefile 文件

其中文件file1.c 如下:

#include"head.h"

int sum(int a, int b)
{
   
        return a+b;
}

其中文件file2.c 如下:

#include"head.h"

int mul(int a,int b)
{
   
        return a*b;
}

其中文件head.h如下:

#include<stdio.h>
int sum(int a,int b);
int mul(int a,int b);

其中调用文件 hello.c 如下:

#include"head.h"

int main()
{
   
        printf("1+2=%d\n",sum(1,2));
        printf("2*2=%d\n",mul(2,2));
        return 0;
}

makefile文件:

src=$(wildcard ./*.c)
obj=$(patsubst %.c,%.o,$(src))
target=hello
CC=gcc
CPPFLAGS=-I ./
# 最终目标
$(target):$(obj)
        $(CC) -o $@ $^
%.o:%.c
        $(CC) -o $@ -c $< $(CPPFLAGS)

# 伪目标
.PHONY:clean
clean:
        rm -rf $(target) $(obj)

执行

#执行,它会自动去执行终极目标的命令 $(CC) -o $@ $^
make
#输出以下表示成功
gcc -o file2.o -c file2.c -I ./
gcc -o hello.o -c hello.c -I ./
gcc -o file1.o -c file1.c -I ./
gcc -o hello file2.o hello.o file1.o
#执行可执行文件
./hello
#输出以下,成功
1+2=3
2*2=4

#指定执行清除指令
make clean
#输出以下表示成功
rm -rf hello ./file2.o ./hello.o ./file1.o

参考链接

makefile 官网

目录
相关文章
|
运维 监控 Java
nacos常见问题之获取配置文件的时候报错user not found如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
2533 2
|
缓存 运维 Java
nacos常见问题之点击下线提示报错如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
517 2
|
网络协议 Java Nacos
Nacos报错问题之jar 包启动就报错误如何解决
Nacos是一个开源的、易于部署的动态服务发现、配置管理和服务管理平台,旨在帮助微服务架构下的应用进行快速配置更新和服务治理;在实际运用中,用户可能会遇到各种报错,本合集将常见的Nacos报错问题进行归纳和解答,以便使用者能够快速定位和解决这些问题。
|
安全 Java 应用服务中间件
Nacos报错问题之鲲鹏上启动报错如何解决
Nacos是一个开源的、易于部署的动态服务发现、配置管理和服务管理平台,旨在帮助微服务架构下的应用进行快速配置更新和服务治理;在实际运用中,用户可能会遇到各种报错,本合集将常见的Nacos报错问题进行归纳和解答,以便使用者能够快速定位和解决这些问题。
|
弹性计算 网络协议 IDE
Nacos报错问题之集群开启鉴权无法注册如何解决
Nacos是一个开源的、易于部署的动态服务发现、配置管理和服务管理平台,旨在帮助微服务架构下的应用进行快速配置更新和服务治理;在实际运用中,用户可能会遇到各种报错,本合集将常见的Nacos报错问题进行归纳和解答,以便使用者能够快速定位和解决这些问题。
1136 1
|
运维 Nacos 开发者
nacos常见问题之IDEA启动raft报错如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
238 0
|
运维 Linux Nacos
nacos常见问题之远程访问不报错放到服务器上nacos连接超时如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
2274 1
|
11月前
|
Java 数据库连接
nacos2.0.3报错No Datasource Set
nacos2.0.3报错No Datasource Set com.mysql.cj.exceptions.CJException: Public Key Retrieval is not allowed
nacos2.0.3报错No Datasource Set
|
Nacos 开发者
nacos报错 Server check fail, please check server 127.0.0.1 ,port 9848 is available , error ={}
在配置文件中指定的Nacos服务器地址未被项目使用,程序仍尝试连接到127.0.0.1。开发者寻求帮助排查问题,已花费多天未果。
|
12月前
|
关系型数据库 MySQL Nacos
nacos启动报错 load derby-schema.sql error
这篇文章描述了作者在使用Nacos时遇到的启动错误,错误提示为加载derby-schema.sql失败,作者通过将数据库从Derby更换为MySQL解决了问题。
nacos启动报错 load derby-schema.sql error