首页 > 其他分享 >Makefile 学习二:命令和变量

Makefile 学习二:命令和变量

时间:2022-11-06 16:00:15浏览次数:95  
标签:变量 make Makefile echo 命令 go world hello name

你必须非常努力,才能看起来毫不费力!

微信搜索公众号[ 漫漫Coding路 ],一起From Zero To Hero !

前言

在 Go 语言开发中,我们希望能够规范代码风格,每个成员在提交时可以一键格式化,同时检查是否有语法错误;我们希望能够一键运行单测,生成单测报告;我们希望能够一键编译、打包、发布项目,这就需要使用到 Make。Make 有很多种,我们常用的就是 GUN Make,有了 Make,我们将极大的提高项目开发、测试、发布的效率。

Make 最初是为 C、C++项目的编译、构建服务的,因此有很多为C、C++的特性,但是这些特性在 Go 开发中使用不到。毕竟每个人的时间有限,我们就只学习Go 开发中 Make 使用所必需的知识。

Make 的规则都在 Makefile 文件编写上,本篇文章,我们来学习 Makefile 命令和变量相关知识。

make 命令在 Windows 下不支持运行,需要在 Linux 或 Mac 环境下运行

命令

命令显示

运行 target 时,执行命令的同时,默认会输出命令到控制台

.PHONY: echo_test
echo_test:
	echo "hello"
	echo "world"
➜   make echo_test   
echo "hello"
hello
echo "world"
world

如果在命令前加上一个 @ 符号,则只执行命令,不显示命令

.PHONY: echo_test
echo_test:
	@echo "hello" # 这个命令不会显示
	echo "world"
➜   make echo_test
hello
echo "world"
world

@符号只对单个命令生效,如果想要对所有命令都生效,可以使用 -s 或者 --silent 参数,表示沉默:

➜   make -s echo_test 
hello
world

如果想要只显示命令,不执行命令,使用如下参数:make -n 或者 make --just-print

# .PHONY 表示这是一个伪目标
.PHONY: echo_test
echo_test:
	echo "hello"
	@echo "world"
➜ make -n echo_test
echo "hello"
echo "world"

命令执行

如果想要后一个命令基于前一个命令,需要在命令之间加上分号;而命令写在两行是单独执行的:

exec:
	cd /tmp
	pwd
➜   make -s exec
/Users/admin/makefile_study

通过上面的例子,可以看到第二个命令执行时,并没有在 /tmp 目录,说明前一个命令并没有影响到后一个命令。

我们把两个命令使用分号分隔

exec:
	cd /tmp; pwd
➜   make -s exec
/tmp

命令出错

在我们执行命令时,有可能命令会出错,影响后续命令的执行。对于有些错误,我们可以忽略,让命令继续执行下去。比如我们想新建个文件夹,如果文件夹本来就存在,新建就会出错,但我们需要的就是文件夹存在,这种错误可以忽略。

当前目录 test 文件夹不存在,新建文件夹和文件,并显示文件列表

exec:
	@mkdir test; cd test; touch a.txt; ls

第一次运行正常

➜ make exec
a.txt

第二次运行就会提示错误,但是同一行的命令会继续执行下去

➜ make exec
mkdir: test: File exists
a.txt

如果存在多行命令的话,前面一行的命令报错,后面的命令就不会继续执行了

exec:
	@mkdir test
	@echo "hello world"
➜ make exec
mkdir: test: File exists
make: *** [exec] Error 1

如果我们想忽略这个报错的话,可以有多种方式:

  1. 在命令前面加上一个减号 '-' ,表示忽略这个错误,继续执行下面的命令
exec:
	-@mkdir test
	@echo "hello world"
➜ make exec
mkdir: test: File exists
make: [exec] Error 1 (ignored)
hello world
  1. 对规则 加上 .IGNORE 标记,会忽略该规则中所有命令的错误
.IGNORE: exec
exec:
	@mkdir test
	@echo "hello world"
➜ make exec
mkdir: test: File exists
make: [exec] Error 1 (ignored)
hello world
  1. make 中加上 -i 或者 --ignore-errors 参数,那么此次运行的所有命令都会忽略错误
exec:
	@mkdir test
	@echo "hello world"
➜ make -i exec
mkdir: test: File exists
make: [exec] Error 1 (ignored)
hello world

定义命令模板

有时候可能有一些常用的功能,我们可以将其抽出来做成一个模板,供其他command 调用。定义模板的语法为:define ,接模板的名字;中间是命令,最后以 endef 结尾。

define template-name
...commands...
endef

使用命令模板,就像使用普通变量一样:

define my_template
@echo "this is a template"
endef

.PHONY: test
test: 
   $(my_template)
➜  make test 
this is a template

自动变量

使用命令模板,经常需要使用自动常量,这种变量和 shell 中的 位置参数变量 类似,常用的有这几个:

$@  表示目标文件
$^  表示所有的依赖文件
$<  表示第一个依赖文件
$?  表示比目标还要新的依赖文件列表
.PHONY: test
test: hello.go world.go
	@echo $@ # test
	@echo $^ # hello.go world.go
	@echo $< # hello.go
	@echo $? # hello.go world.go

我们就定义一个模板,输出 target 和 所有的 prerequisites,然后再使用这个模板:

define my_template
@echo $@ $^
endef

.PHONY: hello
hello: hello.go
	$(my_template)

.PHONY: world
world: world.go
	$(my_template)
➜  make hello
hello hello.go
➜  make world
world world.go

变量

变量的声明和使用

和其他编程语言一样,Makefile 也可以定义变量,在 target、prerequisites、command中都可以使用。变量名由字母、数字和下划线组成(可以是数字开头),大小写敏感。

定义变量时,变量名 和 值 之间使用 "=" 连接,"=" 两侧空格不敏感;使用变量时,可以使用 $+变量名的形式,更推荐的方式还是使用 $(变量名) 将变量包裹起来。

name= tom
age = 18
info:
	echo $name
	echo $(age)
➜   make info
echo tom
tom
echo 18
18

可以将变量使用在 target 中:

MyTarget = info
$(MyTarget):
	go build hello.go
	go build world.go
➜  make info
go build hello.go
go build world.go

也可以将变量使用在 prerequisite 中:

files = hello.go
info: $(files)
	go build $(files)
➜ make info
go build hello.go

Makefile 中的变量,会在使用的时候 展开,直接使用你定义的值来替代,你完全可以这样使用这样的骚操作,但是并不推荐:

type = go
build:clean
	go build hello.$(type)
	go build world.$(type)


.PHONY: clean
clean:
	-@rm -f hello world
➜  make build
go build hello.go
go build world.go

使用其他变量

我们可以一个变量中使用其他变量

name = tom
age = 18
detail = $(name) $(age)

info:
	@echo $(detail)
➜  make info
tom 18

在我们平常编程过程中,被引用的变量,一定要定义在前面,但是在 Makefile 中没有这个限制,你可以引用后面定义的变量(也可以理解为懒加载,只有用到时才会展开,此时整个文件已经都加载完了,因此不在乎使用的变量定义在前或者在后):

detail = $(name) $(age)
name = tom
age = 18

info:
	@echo $(detail)
➜  make info
tom 18

如果可以引用之后的变量,就可能出现递归的情况,比如下面的示例,a 引用 b,b 引用 a,当然 makefile 是会检测到这种递归的。

a = $(b)
b = $(a)

info:
	@echo $(b)
➜  make info
Makefile:4: *** Recursive variable `b' references itself (eventually).  Stop.

懒加载

上面也提到过,Makefile 中的变量是懒加载的,只有在使用的时候,才会将变量的值展开,也就是说后面定义的变量值会将之前的覆盖:

name = tom
age = 18
detail = $(name) $(age)

info:
	@echo $(detail)
age = 22
➜  make info
tom 22  # 被后面的值覆盖了

当然,我们可以强制指定当前的变量值,即使用 " := " 来定义变量:

name = tom
age = 18
detail := $(name) $(age)

.PHONY: info
info:
	@echo $(detail)

age = 22
➜ make info
tom 18 # 使用的是定义detail 时 age 的值

如果当前没有变量值,展开就是空值:

name = tom

# 此时还没有定义 age 变量
detail := $(name) $(age)  

.PHONY: info
info:
	@echo $(detail)

age = 22
➜  make info
tom # age 是空值

追加变量值

我们可以对已有的变量进行修改,重新赋值或者追加,我们可以使用 += 来追加:

name = tom
name += john

.PHONY: info
info:
	@echo $(name)
➜  make info
tom john

需要注意的是,追加时,变量的赋值方式会延续初次定义的符号,使用 = 或者 := 来保持是否需要懒加载

name = tom
name += john  # 等同于 name = tom john
name := tom
name += john  # 等同于 name := tom john

因此在引用其他变量时就需要注意:

name = tom

# 等同于 name = tom $(a_name)
name += $(a_name)

.PHONY: info
info:
	@echo $(name)  # tom john

a_name = john

上述例子保持了懒加载,而下面这个则不会使用懒加载:

name := tom

# 等同于 name := tom $(a_name)
name += $(a_name)

.PHONY: info
info:
	@echo $(name) # tom

a_name = john

总结

本篇文章我们一起学习了Makefile 命令和变量相关的知识点,主要有:

  • 命令显示:使用 @ 符号控制命令是否打印
  • 命令执行:使用 符号使得后一个命令基于前一个命令执行
  • 命令出错:使用 - 符号来忽略命令执行中产生的错误
  • 位置变量:可以获取命令中的参数,结合命令模板使用会更加易用
  • 变量使用:包括变量的声明、使用以及懒加载机制

更多

个人博客: https://lifelmy.github.io/

微信公众号:漫漫Coding路

标签:变量,make,Makefile,echo,命令,go,world,hello,name
From: https://blog.51cto.com/u_12260130/5827299

相关文章

  • linux命令日常使用
    jps是jdk提供的一个查看当前java进程的小工具,全称是JavaVirtualMachineProcessStatusTool输出jvm参数jps-v scp命令,用于文件复制scp/d/software/a.ja......
  • golang的变量介绍与使用
    变量变量的使用步骤:声明、赋值、使用packagemainimport"fmt"funcmain(){ //1.变量的声明 varageint //2.变量的赋值 age=18 //3.变量的使用 fmt.Pr......
  • 计算机快捷键和Dos基础命令
    计算机快捷键任务管理器→ctrl+shift+esc打开任务管理器shift+delete→永久删除基础的DOS命令打开CMD的方式开始+系统+命令提示符Win键+R输入cmd打开控制台(推荐......
  • 关于变量的一些小知识 (纯新手)
    首先就是变量有好几种,第一字面变量就是常数123这种,然后就是变量名,我们自己定义的什么num啊这些,但是呢同一个变量名是可以赋值多个的,比如我这个,也是没有问题的2就是有个cons......
  • Makefile.win recipe for target '项目1.exe' failed
    在运行代码的时候出现了这个问题,查阅了许多资料,有的说是编译器的问题,有的说是重复定义变量名称的问题,在对代码检查后发现不是这两者的问题是我前面数组定义有问题,将数组定义......
  • 执行Maven的test命令报错
    参考网址:https://blog.csdn.net/weixin_46688566/article/details/126470742解决方案在pom.xml文件中加入以下依赖:<plugin><groupId>org.eclipse.m2e</groupId>......
  • 详解数据预处理和特征工程-数据预处理-编码与哑变量 & 二值化与分段【菜菜的sklearn课
    视频作者:菜菜TsaiTsai链接:【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili处理分类型特征:编码与哑变量多标签和特征在数据收集完毕的时候,都......
  • 第2-1-2章 传统方式安装FastDFS-附FastDFS常用命令
    目录3安装配置3.1安装GCC3.2安装libevent3.3安装libfastcommon3.4安装FastDFS3.5安装fastdfs-nginx-module3.5安装Nginx3.6配置FastDFSTracker3.5.1配置Tracker3......
  • 记录一下常用的git命令
     ##1、撤销修改后的文件1.本地*修改*了一些文件(并没有使用gitadd到暂存区),想放弃修改-单个文件/文件夹:```shellgitcheckout--filename```-所有文......
  • shell-文件查找命令笔记三
    文件查找-find命令格式:find[路径][选项][操作]选项-name根据文件名查找-iname根据文件名查找,忽略大小写-perm根据文件权限查找find/etc-perm777-prun......