《GNU make》学习笔记(三)---Makefile的规则

3.2 规则语法

    Makefile中对“$”有特殊的含义(表示变量或者函数的引用),如果我们的规则如果需要“$”,需要书写两个连续的(“$$”)。

    规则的中心思想就是:目标文件的内容是由依赖文件文件决定,依赖文件的任何一处改动,将导致目前已经存在的目标文件的内容过期。


3.3依赖的类型--常规依赖和order-only依赖

     有时,我们需要定义一个这样的规则,在更新目标(目标文件已经存在)时只需要根据依赖文件中的部分来决定目标是否需要被重建,而不是在依赖文件的任何一个被修改后都重建目标。为了实现这个目的,我们需要对依赖进行分类,一类是这些依赖文件的更新需要对应更新目标文件,另一类是这些依赖的更新不会导致目标被重建。第二类的依赖我们就称他为:“order-only”依赖。

     “order-only”依赖使用管道符号“|”开始,作为目标的一个依赖文件。规则的依赖列表中管道符号“|”左边的是常规依赖文件,所有出现在管道符号右边的就是“order-only”依赖。

      TARGETS : NORMAL-PREREQUISITES | ORDER-ONLY-PREREQUISITES

     规则中常规依赖文件可以是空。允许对一个目标声明多行按正确顺序依次追加的依赖。需要注意:规则依赖文件中如果一个文件被同时声明为常规依赖和“order-only”依赖,那么此文件被作为常规依赖处理(因为常规依赖所实现的动作是“order-only”依赖所实现的动作的一个超集)。


3.4 文件名使用通配符

    Maekfile中表示一个单一的文件名时可使用通配符。可使用的通配符有:“*”、“?”和“[…]”。
    Makefile中统配符可以出现在以下两种场合:
1. 可以用在规则的目标、依赖中,此时make会自动将其展开;
2. 可出现在规则的命令中,其展开是在shell在执行此命令时完成。
    如果规则中的某一个文件的文件名包含作为统配符的字符(“*”、“.”字符),在使用文件时需要对文件名中的统配字符进行转义处理, 使用反斜线(\)来进行通配符的转义。
     波浪线之后跟一个单词(~word),其代表由这个“word”所指定的用户的宿主目录。例如“~john/bin”就是代表用户john的宿主目录下的bin目录。

    变量定义中使用的通配符不会被展开(因此在定义变量不能按照这这种方式,下一小节将会详细讨论)。如果Makefile有这样一句:“objects = *.o”。那么变量“objects”的值就是“*.o”,而不是使用空格分开的所有.o文件列表。如果需要变量“objects”代表所有的.o文件,则需要是用函数“wildcard”来实现(objects = $(wildcar *.o))。


3.5 目录搜寻

    在一个较大的工程中,一般会将源代码和二进制文件(.o文件和可执行文件)安排在不同的目录来进行区分管理。这种情况下,我们需要使用make提供的目录自动搜索依赖文件功能(在指定的若干个目录下搜索依赖文件)。书写makefile时,指定依赖文件的搜索目录。当工程的目录结构发生变化时,我们就可以不更改Makefile的规则,而只更改依赖文件的搜索目录。

    两种方法:VPATH特殊变量和关键字vpath。

3.5.1 一般搜索VPATH

    特殊变量VPATH可以指定依赖文件的搜索路径,在规则需要的文件在当前目录不存在时,make会在此变量所指定的目录下去寻找这些文件。

    “VPATH”变量所指定的是Makefile中所有文件的搜索路径,包括依赖文件和目标文件。

    变量“VPATH”的定义中,使用空格或者冒号(:)将多个目录分开。make搜索的目录顺序按照变量“VPATH”定义中顺序进行(当前目录永远是第一搜索目录)

3.5.2 选择性搜索vpath

     关键字vpath为不同类型的文件(由文件名区分)指定不同的搜索目录。

vpath 使用方法:

  • vpath <directories>            :: 当前目录中找不到文件时, 就从<directories>中搜索
  • vpath <pattern> <directories>  :: 符合<pattern>格式的文件, 就从<directories>中搜索
  • vpath <pattern>                :: 清除符合<pattern>格式的文件搜索路径
  • vpath                          :: 清除所有已经设置好的文件路径

举个例子:

      vpath %.h ../headers:../include

   Makefile中出现的.h文件,如果不能在当前目录下找到,则到目录“../headers”下和../include寻找。注意:这里指定的路径仅限于在Makefile文件内容中出现的.h文件。并不能指定源文件中包含的头文件所在的路径(在.c源文件中所包含的头文件需要使用GCC的命令行来说明)。

3.5.3 makefile的目录搜索机制

     make在解析Makefile文件执行规则时对文件路径保存或废弃所依据的算法如下

   为了更清楚地描述此算法,我们使用一个例子来说明。存在一个目录“prom”,“prom”的子目录“src”下存在“sum.c”和“memcp.c”两个源文件。在“prom”目录下的Makefile部分内容如下:

LIBS = libtest.a
VPATH = src
libtest.a : sum.o memcp.o
$(AR) $(ARFLAGS) $@ $^

  首先,如果在两个目录(“prom”和“src”)都不存在目标“libtest.a”,执行make时将会在当前目录下创建目标文件“libtest.a”。另外;如果“src”目录下已经存在“libtest.a”,以下两种不同的执行结果:
1) 当它的两个依赖文件“sum.c”和“memcp.c”没有被更新的情况下我们执行make,首先make程序会搜索到目录“src”下的已经存在的目标“libtest.a”。由于目标“libtest.a”的依赖文件没有发生变化,所以不会重建目标。并且目标所在的目录不会发生变化。
2) 当我们修改了文件“sum.c”或者“memcp.c”以后执行make。“libtest.a”和“sum.o”或者“memcp.o”文件将会被在当前目录下创建(目标完整路径名被废弃),而不是在“src”目录下更新这些已经存在的文件。此时在两个目录下(“prom”和“src”)同时存在文件“libtest.a”。但只有“prom/libtest.a”是最新的库文件。


3.5.6 库文件和搜索目录

 如果在命令中有“-lNNAM”的依赖文件名,那么Make的搜索步骤如下:

   1. make在执行规则时会在当前目录下搜索一个名字为“libNAME.so”的文件;

   2. 如果当前工作目录下不存在这样一个文件,则make程序会继续搜索使用“VPATH”或者“vpath”指定的搜索目录。

  3. 还是不存在,make程序将搜索系统默认目录,顺序是:“/lib”、“/usr/lib”和“PREFIX/lib”(在Linux系统中为“/usr/local/lib”,其他的系统可能不同)

  4.如果“libNAME.so”通过以上的途径最后还是没有找到的话,那么make程序将会按照以上的搜索顺序查找名字为“libNAME.a”的文件

   当然你可以在命令行中指定编译或者连接选项来指定动态连接还是静态连接。参数-static就是使用静态库。

   注意:如果依赖是库,make并不会自动去创建库

      例如:

foo : foo.c -lcurses
    cc $^ -o $@

   make不会创建libcurses.so。如果libcurses.so不存在会报错。




猜你喜欢

转载自blog.csdn.net/colorful_lights/article/details/80831294
GNU