Makefile书写命令(四)

每条规则中的命令和操作系统Shell的命令行是一致的。make会按照顺序一条条的执行命令,每条命令的开头必须以tab键开头的,那么make会认为是一条空命令
我们在UNIX下可能会使用不同的shell,但是make的命令默认是被/bin/sh–UNIX的标准shell解释执行的。除非你特别指定一个其他的shell。

显示命令

通常make会把需要执行的明林个在命令执行前输出到屏幕上,当我们用@字符在命令行前,那么这个命令不被make显示出来,最具代表性的是如下

@echo 正在编译。。。

当make命令执行时,会输出正在编译字体到屏幕上,但是不会输出命令,如果没有@字符,则make会输出如下的内容

echo 正在编译。。。
正在编译。。。

如果make执行时,带入make参数-n或者--just-print,那么指示显示命令,并不会执行,这个功能很有利于我们调试我们的Makefile
而make参数-s或者--slient则是全面禁止命令的显示

命令执行

当依赖目标新于目标target时,make回一条条的执行其后的命令,如果我们想要让上一条命令的结果应用在下一条命令,我们应该使用分号分离这两条命令。例如一条命令是cd,另一条命令如果希望是在cd之后再去执行,我们就要把命令写成两行或者写成一行,但是用分号隔开

#第一种情况
exec:
        cd /paul/tmp
        pwd
#第二种情况
exec:
        cd /paul/tmp;pwd

当我们执行make exec时,第一个例子的cd没有作用,pwd会打印当前的Makefile目录,而第二个例子中,cd就起作用了,pwd会打印出/paul/tmp
make一般使用环境变量shell中所定义的系统shell来执行命令,默认情况下使用UNIX的标准shell–/bin/sh来执行命令。

命令出错

当命令运行完之后,make会检测每个命令的返回码,如果命令返回成功,那么make会执行下一条命令,当规则中所有的命令成功返回后,这个规则就算是成功完成了。如果一个规则中的某个命令出错了,那么make就会终止执行当前规则,这有可能终止所有规则的执行。
为了做到这一点,忽略命令的出错,我们可以在Makefile的命令行前加一个减号-,标记为不管命令处不出错都认为是成功的。

clean:
        -rm -f *.o

还有一个全局的方法,给make加上-i或者--ignore-errors参数,那么Makefile重所有命令都会忽略错误。而如果这个规则是以.INGNORE作为目标的,那么这个规则中的所有命令都将忽略错误。

嵌套命令

在做一些大工程中,我们会把我们不同模块或者不同功能的源文件放在不同的目录中,我们可以在每个目录中都书写一个该目录的Makefile文件,这有利于我们让我们的Makefile变得更加简洁,同时也可以节省我们编译的时间,因为可以省去编译其他没有改变的模块的时间
例如:我们有一个子目录叫做subdir,这个目录下有一个Makefile文件,来指明这个目录的编译规则,那么我们总的Makefile文件可以这样写

subsystem:
        cd subdir && $(MAKE)

等价于

subsystem:
            $(MAKE) -c subdir

定义$(MAKE)宏变量的意思是,也许我们的make需要一些参数,所以定义成一个变量比较利于维护,这两个例子的意思都是先进入subdir目录,然后执行make命令
我们可以把这个makefile叫做总控Makefile,总控Makefile中的变量可以传递到下一级的Makefile文件中,但是不会覆盖下层Makefile中所定义的变量,除非指定了-e参数
如果我们要传递变量到下一级的Makefile,那么你可以使用这样的声明

export <variable...>

相反,如果不想让某些变量传递到下一级的Makefile中,那么我们可以这样申明

unexport <variable...>

例如

exprot variable = value
#等价于
variable = value
export variable
#等价于
exprot variable := value
#等价于
variable:=value
exprot variable

如果我们需要将所有的变量都传递过去,直接写一个exprot即可。
注意SHELL和MAKEFILES,这两个变量,不管你是否export,总是要传递到下一层的Makefile中,特别是MAKEFILES变量,其中包含了make的参数信息,如果我们执行总控Makefile是有make参数或者是上层的Makefile中定义了这个变量,那么MAKEFILES变量将会是这些参数,并且传递到下层Makefile中,这是一个系统级的环境变量。

定义命令包

如果Makefile中出现一些相同命令序列,我们可以为这些相同命令序列定义一个变量,定义这种命令序列的语法以define开始,以endef结束

define run-yacc
        yacc $(firstword $^)
        mv y.tab.c $@
endef

这里的run-yacc是这个命令包的名字,不能喝Makefile中的变量重名。在defineendef中的两行就是命令序列。这个命令包中的第一个命令是yacc,编译。因为yacc总是为生成一个y.tab.c的文件,所以第二行的命令就是把这个文件改名字,如果我们想要使用,可以直接像调用变量一样的使用,如下

main.c:main.y
        $(run-yacc)

参考资料

教你写Malefile

猜你喜欢

转载自blog.csdn.net/weixin_42580207/article/details/81261141
今日推荐