文章目录
- 一、显示命令"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"程序进行测试