跟我一起写makefile(3)

指定目标

    一般来说,make的最终目标是makefile中的第一个目标,而其他目标一般是由这个目标连带出来的,这是make的默认行为。有一个make的环境变量叫“MAKECMDGOALS”,这个变量会存放你所指定的终极目标列表。这个变量可以让你使用在一些比较特殊的情形下。比如:

sources = foo.c bar.c

ifneq ($(MAKECMDGOALS), clean)\

include $(sources: .c=.d)

endif

基于上面这个例子,只要我们输入的命令不是“make clean”,那么makefile就会自动包含foo.d和bar.d这两个。

既然make可以指定所有makefile中的目标,那么也包括伪目标,于是我们可以根据这个性质来让我们的makefile根据指定的不同的目标来完成不同的事。在Unix中,软件发布时,makefile都包含了编译、安装、打包等功能。

all:这个伪目标是所有目标,功能是编译所有的目标。

clean:功能是删除所有被make创建的文件。

install:是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目录中。

print:列出改变过的源文件。

tar:把源程序打包备份,也就是一个tar文件。

dist:创建一个压缩文件,一般把tar文件压缩成gz文件。

TAGS:更新所有的目标,以备完整地重编译使用。

check和test:一般用来测试makefile的流程。

 

检查规则

    有时候,我们不想让我们的makefile中的规则执行起来,我们只想检查一下我们的命令。使用这样的参数-n, --just-print, --dry-run, --recon。不执行参数,只是打印命令。

    -t, --touch这个参数把目标文件的时间更新,但不更改目标文件。

    -q, --question这个参数是找目标。如果目标存在,那么什么也不会输出,也不会执行编译。如果目标不存在,会打印一条出错信息。

    -W <file>, --what-if=<file>, --assume-new=<file>, --new-file=<file>这个参数需要指定一个文件。make会根据规则推导来运行依赖于这个文件的命令。

    -b, -m是忽略和其它版本make的兼容性。

    -B, --always-make认为所有的目标都需要更新。

    -C <dir>, --directory=<dir>指定读取makefile的目录。如果有多个这个参数,make的解释是后面的路径以前面的作为相对路径,并以最后的目录作为被指定目录。

    --debug[=<options>]输出make的调试信息。它有几种不同的级别可供选择。a也就是all,输出所有的调试信息;b也就是basic,只输出简单的调试信息;v也就是verbose,在b的级别之上;i也就是implicit,输出所有的隐含规则;j也就是jobs,输出命令的详细信息;m也就是makefile,输出make读取、更新、执行makefile的信息。

    -d相当于--debug=a。

    -e,--environment-overrides指明环境变量的值覆盖makefile中定义的变量值。

    -f=<file>,--file=<file>, --makefile=<file>指定需要执行的makefile。

    -h,--help显示帮助信息。

    -i, --ignore-errors在执行时忽略所有的错误。

    -I <dir>, --include-dir=<dir>指定一个被包含makefile的搜索目标。

    -j <jobsnum>, --jobs=<jobsum>指同时运行的命令的个数。

-k, --keep-going出错了也不停止运行。

-l <load>, --load-average[=<load>], --max-load[=<load>]指定make运行命令的负载。

-o <file>, --old-file=<file>, --assume-old=<file>不重新生成的指定的<file>,即使这个目标的依赖文件新于它。

-p, --print-data-base输出makefile中的所有数据,包括所有的规则和变量。

-q, --question不运行命令,也不输出。仅仅是检查所指定的目标是否需要更新。如果是0则说明要更新,如果是2则说明有错误发生。

-r, --no-builtin-rules禁止make使用任何隐含的规则。

-R, --no-builtin-variables禁止make使用任何作用于变量上的隐含规则。

-s, --silent, --quiet在命令运行时不输出命令的输出。

-S, --no-keep-going, --stop取消-k选项的作用。

-v, --version输出make程序的版本、版权等信息。

-w, --print-directory输出运行makefile之前和之后的信息。

--no-print-directory禁止-w选项。

 

隐含规则

在我们使用makefile时,有一些我们会经常使用的东西。由于隐含规则,我们完全没有必要写下下面的规则:

foo.o: foo.c

             cc -c foo.c $(CFLAGS)

因为这已经是约定好的事了。make和我们约定好了用c编译器cc生成.o文件的规则,这就是隐含规则。

1.编译C程序的隐含规则。

<n>.o的目标的依赖目标会自动推导为<n>.c并且其生成命令是$CC -c $(CPPFLAGS) $(CFLAGS)

2.C++

<n>.o的目标的依赖目标会自动推导为<n>.cc或是<n>.C,并且其生成命令是$(CXX) -c $(CPPFLAGS) $(CFLAGS)

3.pascal

<n>.o的目标的依赖目标会自动推导为<n>.p,并且其生成命令是$(PC) -c $(PFLAGS)

7.汇编

<n>.o的目标的依赖目标会自动推导为<n>.s,默认用编译器as,并且生成命令为$(AS) $(ASFLAGS)。<n>.s的目标的依赖目标会自动推导为<n>.S,默认用C预编译器cpp,生成命令是$(AS) $(ASFLAGS)

8.链接object

<n>目标依赖于<n>.o,通过运行C的编译器来运行链接程序生成,命令是$(CC) $(LDFLAGS) <n>.o $(LOADLIBS) $(LDLIBS)

 

隐含规则使用的变量

在隐含规则中的命令中,基本上都是使用了一些预先设置的变量。

1.关于命令的变量

AR 函数库打包程序,默认为ar。

AS 汇编语言编译程序。默认为as。

CC C语言编译程序,默认为cc。

CXX C++语言编译程序,默认是g++。

CPP C语言的预处理器,默认是$(CC) -E。

RM 删除文件命令,默认为rm -f。

 

2.关于命令参数的变量

ARFLAGS AR命令的参数,默认是rv。

ASFLAGS 汇编语言编译器参数。

CFLAGS C语言编译器参数。

CXXFLAGS c++编译器参数。

CPPFLAGS c预处理器参数。

LDFLAGS 链接器参数。

 

隐含规则链

有些时候,一个目标可能被一系列的隐含规则所作用。这一系列的隐含规则叫做隐含规则链。

比如,一个.o文件的生成,可能会是先被Yacc的.y文件生成.c,然后再被c的编译器生成。如果.c存在,那么就直接调用c的编译器的隐含规则。如果没有.c文件,但有一个.y文件,那么Yacc的隐含规则会被调用,生成.c文件,然后再调用c编译的隐含规则达到目标。这种.c的文件叫做中间目标。

默认情况下,对于中间目标,它和一般的目标有两个地方不同:1.除非中间的目标不存在,才会引发中间规则;2.只要目标成功生成,所产生的中间目标文件会被以rm -f 删除。

通常,一个被makefile指定为目标或是依赖目标的文件不能被当作中介。然而你可以明显地说明一个文件是中介目标,你可以使用伪目标.INTERMEDIATE来强制声明。你也可以阻止make自动删除中间目标,使用.SECONDARY来强制声明。

 

定义模式规则

目标的的定义需要有%字符,%的意义是表示一个或多个任意的字符。

例如 %.o: %.c; <command ...>,含义是指出了怎么从所有的.c文件生成相应的.o文件的规则。一旦依赖目标中的%模式被确定,那么make会被要求去匹配当前目录下所有的文件名。例子:、

%.o: %.c

                      $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

表示了,把所有的.c文件都编译成.o文件。

例子:

%.tab.c %tab.h: %.y

                bison -d $<

这条规则告诉make把所有的.y文件都以bison -d <n>.y执行,然后生成<n>.tab.c和<n>.tab.h。

 

自动化变量

在上述的模式规则中,目标和依赖文件都是一系列的文件,那么我们如何书写一个命令来完成从不同的依赖文件中生成相应的目标?因为在每一次的对模式规则的解析时,都会是不同的目标文件和依赖文件。

自动化变量就是完成这个功能的。

$@ 表示规则中的目标文件集。

$% 仅当目标是函数库文件中,表示规则中的目标成员名。例如,一个目标是foo.a(bar.o),那么$%就是bar.o,$@ 就是foo.a。如果目标不是函数库文件(unix下是.a,windows下是.lib),那么其值为空。

$< 依赖目标中的第一个目标名字。如果依赖目标是以模式(即%)定义的,那么$<将是符合模式的一系列的文件集。

$? 所有比目标新的依赖目标的集合。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值