文章目录

  • 一、显示命令"echo"
  • 1、"-n"和"--just-print"
  • 2、"-s"、"--slient"和"--quiet"
  • 3、"-w"、"--print-directory"和"--no-print-directory"
  • 示例
  • 二、命令执行
  • 三、屏蔽报错
  • 1、"-"号
  • 2、".IGNORE"
  • 3、"make -i hello"和"make --ignore-errors hello"
  • 4、"make -k hello"和"make --keep-going hello"
  • 四、嵌套执行make
  • 五、"make -e all"
  • 六、定义命令包


一、显示命令"echo"

make命令在执行时,会默认将所有的在终端上打印出来
"@“字符用于控制命令的输出,可以禁止当前命令打印到终端上,仅输出执行的结果(不影响命令本身的执行)
如果一个命令在前面加了”@“符号,那么该命令的执行结果不会显示在终端上
如果没有”@"符号,则该命令的执行结果会显示在终端上

"echo"命令用于将一个文本字符串打印到标准输出,通常用于显示一个消息,以调试Makefile文件

hello:
	echo "Hello,World!"

这个例子将会打印以下内容

echo "Hello,World!"
Hello,World!

第一行echo "Hello,World!“为echo命令的打印
第二行Hello,World!为执行结果
如果加上”@"字符则会屏蔽第一行

Hello,World!

注意:“echo"命令与字符串之间需要有空格,否则会识别成整个字符串"echo"Hello,World!”"

make指令有一些命令选项关于打印

1、"-n"和"–just-print"

“-n"和”–just-print":仅显示要执行的命令,不真正执行。一般用来检查Makefile中的语法错误或查看make命令将要执行哪些命令,而不实际运行这些命令

hello:
	echo "Hello,World!"

使用"make -n hello"命令会显示如下(跳过了make执行的自动输出打印字符串)

echo "Hello,World!"

2、"-s"、"–slient"和"–quiet"

“-s”、"–slient"和"–quiet":仅显示错误信息,不输出命令执行结果。这个选项可以隐藏命令的执行结果,仅显示错误信息

hello:
	echo "Hello,World!"

使用"make -s hello"命令会显示如下(隐藏了echo打印结果)

Hello,World!

3、"-w"、"–print-directory"和"–no-print-directory"

“-w"和”–print-directory":在执行子目录的make命令时,显示目录信息
“–no-print-directory”:在执行子目录的make命令时,不显示目录信息

示例

all:
	echo "Hello,World!"
	touch output.txt

该规则会执行"echo"打印字符串"Hello,World!",并创建一个名为"output.txt"的空文件
"make all"运行↓

echo "Hello,World!"
Hello,World!
touch output.txt

"make -n all"运行↓(只显示要执行的命令,不实际执行)

echo "Hello,World!"
touch output.txt

"make all"运行↓(执行命令,但只输出错误结果)

Hello,World!

二、命令执行

在Makefile中,每一条命令会在单独的进程中运行,进程与进程之间的变量以及指令是不共享的
如果要让上一条命令的运行结果作为下一条命令的前置条件,需要在两个命令中用";"间隔

#错误示例
hello:
	cd /home/src
	pwd
#正确示例
hello:
	cd /home/src;pwd

前者会打印当前目录,后者才会打印"/home/src"

三、屏蔽报错

当每条命令运行完后,make会检查命令的返回码是否为0
如果为0则成功并开始下一条命令
如果不为0则判断遇到错误,male就会终止当前规则

有的命令虽然会返回报错,但不完全就是错误的,如"mkdir"命令
这个命令是创建一个目录,但如果这个目录已经存在了就会报错

1、"-"号

如果希望继续运行下去可以在命令前面增加一个"-"号,即不论返回结果是否正确都认为是成功执行

#运行中断
mkdir mydir
echo"created successfully"
#成功打印
-mkdir mydir
echo"created successfully"
#常见的clean
clean:
	-rm -f *.o

2、".IGNORE"

规则如果以".IGNORE"标记就会无视运行时候出现的错误

.IGNORE:
pull:
	git pull origin abc
	echo"pull successfully"

上述例子中pull了一个不存在的文件

.IGNORE:
install:
	mkdir -p /usr/local/myapp
	cp myapp /usr/local/myapp

上述例子,在"intall"目标中,尝试创建一个目录"/usr/local/myapp",并将"myapp"文件拷贝到该目录下。
当该目录已存在,则"mkdir"命令会返回一个错误,从而导致make命令终止执行,为了忽略该错误并继续执行命令,使用了."IGNORE"目标

3、“make -i hello"和"make --ignore-errors hello”

make时加上"-i"或"–ignore-errors"参数,运行时的所有错误都会忽略

4、“make -k hello"和"make --keep-going hello”

make时加上"-k"或"–keep-going"参数,运行时出现错误会跳过该规则继续执行后续规则命令

四、嵌套执行make

在Makefile中,可以在一个命令部分中嵌套执行另一个Makefile文件中的规则
这种机制往往用在一些大工程中,将不同模块或者不同功能的源文件放在不同的目录,每个目录中写一个Makefile文件,将主目录的Makefile作为起始文件

#目录结构
project
|
|------Makefile
|
|------moudle1
|    ﹂一一Makefile
|------moudle1
|    ﹂一一Makefile
all:
	make -C moudle1
	make -C moudle2

上述示例中,会进入当前目录下的子目录"/moudle1"与"/moudle2"执行子目录下的Makefile文件

$(make)是Makefile中定义/使用变量的语法,可以调用"make"命令并传递相应的参数

all:
	$(make) -C moudle1
	$(make) -C moudle2

Makefile中定义的变量默认是局部变量,只在当前的Makefile文件中起作用,如果要将变量传递到下层Makefile文件,可以使用"export"命令将变量导出到环境变量中,在下层Makefile文件中再重新导入变量
语法↓

#下述格式等价
export variable = value

variable = value
export variable

export variable := value

variable := value
export variable

#下述格式等价
export variable += value

variable += value
export variable
#/project/Makefile
#将变量导入环境变量
CC=gcc
export CFLAGS=-Wall -O2
all:
	$(MAKE) -C module1
	$(make) -C moudle2

在子目录的Makefile中,可以通过"$(CFLAGS)"来使用环境变量

#/project/moudle1/Makefile
#子目录中使用环境变量
all:
	$(CC)$(CFLAGS) -c foo.c
	$(CC)$(CFLAGS) -c bar.c
	$(CC)$(CFLAGS) -o myapp foo.o bar.o
#/project/moudle2/Makefile
#子目录中使用环境变量
all:
	$(CC)$(CFLAGS) -c baz.c
	$(CC)$(CFLAGS) -o myapp baz.o

此外还可以用"-e"参数
如果不想让变量传递到下层Makefile,则可以使用"unexport"

"SHELL"与"MAKEFLAGS"变量不管是否"export"都会传递到下层
"SHELL"变量是在终端中定义的变量,这些变量通常只在当前shell环境中起作用
"MAKEEFLAGS"变量是一个系统级的环境变量,属于MAKE工具中一个特殊的环境变量,用来传递Make工具的命令行选项和参数给下一层的make命令行工具

之前提到的"-w"参数在进入与离开子目录时会提供记录,例如

make: Entering directory `/project/moudle2'.
make: Leaving directory `/project/moudle2'

五、“make -e all”

“-e"参数指定了启用环境变量覆盖Makefile中的变量,也就是说如果使用”-e"参数,make命令中定义的变量可以被环境变量覆盖

CC = gcc
CFLAGS=-Wall -g
all:
	$(CC)$(CFLAGS) -o myapp main.c foo.c bar.c

在上述例子中,Makefile定义了两个变量"CC"和"CFLAGS",并在"all"目标中使用了这俩个变量来编译可执行文件"myapp"
如果以"make"命令执行,"CC"和"CFLAGS"的值会被Makefile中的值覆盖

当设置了环境变量来覆盖Makefile中的变量,通过"-e"启用

#设置环境变量CC的值为clang
export CC=clang
make -e all

在上述例子中,通过"export"命令将环境变量"CC"设置为"clang",接着使用"-e"参数,命令行中的环境变量会覆盖Makefile中定义的变量。
在编译过程中,将使用"clang"而不是Makefile中的"gcc"来编译程序

六、定义命令包

在Makefile中,定义命令包可以将多个命令组合成一个标志符,命令包名称尽量不要与Makefile中的变量重名

<targer-name>:<pre-requisites>
	[<TAB><command-1>]
	[<TAB><command-2>]
	[<TAB><command-2>]

<targer-name>:目标文件
<pre-requisites>:目标文件依赖的文件或目标,可以为空

build:compile link
compile:
	gcc -c -o main.o main.c
	gcc -c -o foo.o foo.c
	gcc -c -o bar.o bar.c
link:
	gcc -o myapp main.o foo.o bar.o

上述示例中,执行"make build"就能直接生成"myapp"可执行文件

"define"和"endef"也被用于定义多行代码块

define run-away
	rm -f *.o
	rm -f myapp
endef

all:
	gcc -c -o main.o main.c
	gcc -c -o foo.o foo.c
	gcc -c -o bar.o bar.c
	gcc -o myapp main.o foo.o bar.o
run:
	./myapp
clean:
	$(run-away)

上述示例中,执行"make clean"就能清除所有可执行文件,执行"make run"即可启动"myapp"程序进行测试