makefile--模式规则(七)

原创博文,转载请标明出处--周学伟http://www.cnblogs.com/zxouxuewei/

上一节讲到目录创建成功,目标文件没有生产到对应目录下,这里我们先给目标文件加上对应目录,这样的话产生对应的目标文件会直接生成到对应目录。我们先给库文件目标和可执行文件目标加上路径,如下:

    lib : $(OBJDIR) $(LIBDIR)/$(SRC_LIB)  

    bin : $(OBJDIR) $(BINDIR)/$(SRC_BIN)  

    $(OBJDIR) :
    >[email protected] "   MKDIR $(notdir [email protected])..."
    >[email protected] -p [email protected]  

    ifneq ($(SRC_BIN),)
    $(BINDIR)/$(SRC_BIN) : $(SRC_OBJ)
    >---$(CC) -o [email protected] $^ $(LDFLAGS)
    endif  

    ifneq ($(SRC_LIB),)
    $(LIBDIR)/$(SRC_LIB) : $(SRC_OBJ)
    >---$(AR) rcs [email protected] $^
    >---cp [email protected] $(SRC_BASE)/libs
    endif

此时再执行make,完成后查看build目录树:

    build/
    └── unix_dbg
        ├── bin
        │   └── target_bin
        ├── lib
        │   ├── libipc.a
        │   └── libtools.a
        └── obj
            ├── ipc
            ├── main
            └── tools

可以看到,生成的目标是在对应目录下。我们乘胜追击,把.o文件也将其修改了。我们之前的每个模块Makefile大致是这样写的:

    SRC_BASE = ../..                                                                               

    CFLAGS +=
    CPPFLAGS += -I. -I./inc -I$(SRC_BASE)/include                                                  

    # SRC_OBJ = $(patsubst %.c, %.o, $(wildcard *.c))
    SRC_FILES = $(wildcard src/*.c)
    SRC_OBJ = $(SRC_FILES:.c=.o)
    SRC_LIB = xx.a                                                                             

    include $(SRC_BASE)/Makefile.rule

其中SRC_OBJ在此处给出,然后再在Makefile.rule中使用,此处的.o文件会在.c文件相同目录下生成,所以我们现在需要将.o文件加 上路径,由于取得路径是在Makefile.rule里面,所以我们可以统一在Makefile.rule里面给变量SRC_OBJ赋值,大致如下:
SRC_OBJ = $(patsubst %.c, $(OBJDIR)/%.o, $(notdir
$(SRC_FILES)))                                                                                                                        
 
    这里用到函数patsubst、notdir,关于函数会在后面讲到。这样.o文件作为目标生成之后就会生成到相应目录里面了。
    此时再编译:

    # make
    make[1]: Entering directory `/home/Myprojects/example_make/version-2.9/src/ipc‘
    make[1]: *** No rule to make target `../../build/unix_dbg/obj/ipc/ipc.o‘, needed by `../../build/unix_dbg/lib/libipc.a‘.  Stop.
    make[1]: Leaving directory `/home/Myprojects/example_make/version-2.9/src/ipc‘
    make: *** [ipc] Error 2
    #

发现出错了,并且是在生成目标文件ipc.o时没有成功,查看build目录树也没有生成.o文件。为什么会生成失败呢?
我们没有给出生成.o目标的规则,之前可以生成是因为make有通过隐含规则来自动推导的能力(这个之前有讲到,链接过去)。在我们没有修改之前,生成.o通过隐含规则来完成:

    %.o: %.c
    #  commands to execute (built-in):
    >---$(COMPILE.c) $(OUTPUT_OPTION) $<

因为所有的.o目标符合该规则,所以会自动推导生成.o文件。我们现在在..o前面加上路径后没有符合生成.o的隐含模式规则了,所以就没有生成该文件,导致编译出错。那怎么办呢?没有隐含模式规则,我们可以自己写符合生成该目标的模式规则。
  
 模式规则类似于普通规则,只是在模式规则中,目标文件是一个带有模式字符“%”的文件,使用模式来匹配目标文件。在目标文件名中“%”匹配的部分称为
“茎”。使用模式规则时,目标文件匹配之后得到“茎”,依赖根据“茎”产生对应的依赖文件,这个依赖文件必须是存在的或者可被创建的。
所以,我们增加一条模式规则如下:

    $(OBJDIR)/%.o : %.c
    >---$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o [email protected]

该模式规则中目标文件是$(OBJDIR)/%.o,那么现在有了符合生成我们需要的.o文件的规则了,编译一下:

    # make
    make[1]: Entering directory `/home/Myprojects/example_make/version-2.9/src/ipc‘
    make[1]: *** No rule to make target `../../build/unix_dbg/obj/ipc/ipc.o‘, needed by `../../build/unix_dbg/lib/libipc.a‘.  Stop.
    make[1]: Leaving directory `/home/Myprojects/example_make/version-2.9/src/ipc‘
    make: *** [ipc] Error 2
    #

发现还是不对,不是已经增加了模式规则了吗,为何还是没有生成.o文件。

我们这里先说说静态模式规则:
    一个规则中可以有多个目标,规则所定义的命令对所有的目标有效。一个具有多目标的规则相当于多个规则。 规则的命令对不同的目标的执行效果不同,
因为在规则的命令中可能使用了自动化变量 “[email protected]” 。
多目标规则意味着所有的目标具有相同的依赖文件。多目标通常用在以下两种情况:虽然在多目标的规则中, 可以根据不同的目标使用不同的命令
(在命令行中使用自动化变量 “[email protected]” )。但是, 多目标的规则并不能做到根据目标文件自动改变依赖文件
(像上边例子中使用自动化变量“[email protected]”改变规则的命令一样) 。需要实现这个目的是,要用到make的静态模式。
    静态模式规则是这样一个规则:规则存在多个目标, 并且不同的目标可以根据目标文件的名字来自动构造出依赖文件。静态模式规则比多目标规则更通用, 它不需要多个目标具有相同的依赖。但是静态模式规则中的依赖文件必须是相类似的而不是完全相同
的。静态模式规则语法如下:

    <targets ...>: <target-pattern>: <prereq-patterns ...>
    <commands>
    ....

比如下面是一个静态模式规则:

    objects = foo.o bar.o  

    all: $(objects)  

    $(objects): %.o: %.c
    $(CC) -c $(CFLAGS) $< -o [email protected]

该规则描述了所有的.o文件的依赖文件为对应的.c文件,对于目标“foo.o” ,取其茎“foo”替代对应的依赖模式“%.c”中的模式字符“%”之后可得到目标的依赖文件“foo.c”。这就是目标“foo.o”的依赖关系 “foo.o: foo.c”,规则的命令行描述了如何完成由“foo.c”编译生成目标“foo.o” 。命令行中“$<”和“[email protected]”是自动化变量,“$<” 表示规则中的第一个依赖文件, “[email protected]” 表示规则中的目标文件。上边的这个规则描述了以下两个具体的规则:

    foo.o : foo.c
    >---$(CC) -c $(CFLAGS) foo.c -o foo.o
    bar.o : bar.c
    >---$(CC) -c $(CFLAGS) bar.c -o bar.o

(注:该示例与其相关描述摘抄于互联网,描述很不错,估计比我讲的详细)

那静态模式规则和普通的模式规则(非静态模式规则)有什么去区别呢?两者都是用目标模式和依赖模式来构建目标的规则中的文件依赖关系,两者不同的地方是 make 在执行时使用它们的时机。
静态模式规则只能用在规则中明确指出的那些文件的重建过程中。不能用在除此之外的任何文件的重建过程中,并且它对指定的每一个目标来说是唯一的。如果一个目标存在于两个规则,并且这两个规则都定义了命令, make 执行时就会提示错误。
非静态模式规则可被用在任何和它相匹配的目标上,当一个目标文件同时符合多个目标模式时,make将会把第一个目标匹配的模式规则作为重建它的规则。

那有没有想过如果我们指定了模式规则后,那还有隐含规则呢,那怎么选择执行哪一个模式规则呢?Makefile中明确指定的模式规则会覆盖隐含模式规
则。就是说如果在Makefile中出现了一个对目标文件合适可用的模式规则,那么make就不会再为这个目标文件寻找其它隐含规则,而直接使用在
Makefile中出现的这个规则。在使用时,明确规则永远优先于隐含规则。

我们继续说之前的那个问题,我们定义了模式规则后还是没有生成.o文件,我们现在将其改为静态规则再试试就看,如下:

    $(SRC_OBJ) : $(OBJDIR)/%.o : %.c
    >---$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o [email protected]

执行后:

    # make
    make[1]: Entering directory `/home/Myprojects/example_make/version-2.9/src/ipc‘
    make[1]: *** No rule to make target `ipc.c‘, needed by `../../build/unix_dbg/obj/ipc/ipc.o‘.  Stop.
    make[1]: Leaving directory `/home/Myprojects/example_make/version-2.9/src/ipc‘
    make: *** [ipc] Error 2
    #

发现提示没有文件ipc.c,这说明没有生成.o的原因是没有.c文件,我很好奇的是为何使用非静态模式为何不提示呢?(还没搞懂,再研究研究,知道的可以给个提示哈~~)
    缺少依赖文件,为何没有*.c文件,仔细想想我们的.o文件没有和.c文件在同一目录。在我们工程中,将源代码和二进制文件(.o
文件和可执行文件)安排在不同的目录来进行区分管理。这种情况下,我们可以使用 make
提供的目录搜索依赖文件功能。该功能在下一节讲述,这一节说的够多了,有点累了。可惜最终还是没有给出一个可用的Makefile,在下一节将会给出。

时间: 2024-10-29 19:10:10

makefile--模式规则(七)的相关文章

从头开始写项目Makefile(八):模式规则

[版权声明:转载请保留出处:blog.csdn.net/gentleliu.Mail:shallnew at 163 dot com] 上一节讲到目录创建成功,目标文件没有生产到对应目录下,这里我们先给目标文件加上对应目录,这样的话产生对应的目标文件会直接生成到对应目录.我们先给库文件目标和可执行文件目标加上路径,如下: lib : $(OBJDIR) $(LIBDIR)/$(SRC_LIB) bin : $(OBJDIR) $(BINDIR)/$(SRC_BIN) $(OBJDIR) : >[

Makefile 隐含规则,模式规则,常见变量

 隐含规则复杂的Makefile一般会使用隐含规则内的变量来简化编译处理.将隐含规则中使用的变量分成两种:一种是命令相关的,如“CC”:一种是参数相关的,如“CFLAGS”.这些变量都是大写表示. 常用的命令变量有:CC C语言编译程序.默认命令是“cc”CXX C++语言编译程序.默认命令是“g++”CPP C程序的预处理器(输出是标准输出设备).默认命令是“$(CC) –E”RM 删除文件命令.默认命令是“rm –f” 参数相关的变量:CFLAGS C语言编译器参数CXXFLAGS C++语

跟我一起写Makefile:书写规则

书写规则 规则包含两个部分,一个是依赖关系,一个是生成目标的方法. 在Makefile中,规则的顺序是很重要的,因为,Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么.一般来说,定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标.如果第一条规则中的目标有很多个,那么,第一个目标会成为最终的目标.make所完成的也就是这个目标. 好了,还是让我们来看一看如何书写规则. 规则举例 foo.o

makefile 隐含规则

 隐含规则 ---- 在我们使用Makefile时,有一些我们会经常使用,而且使用频率非常高的东西,比如,我们编译C/C++的源程序为中间目标文件(Unix下是[.o]文件,Windows下是[.obj]文件).本章讲述的就是一些在Makefile中的"隐含的",早先约定了的,不需要我们再写出来的规则. "隐含规则"也就是一种惯例,make会按照这种"惯例"心照不喧地来运行,那怕我们的Makefile中没有书写这样的规则.例如,把[.c]文件编译

Makefile隐含规则和用到的默认变量

如果要使用隐含规则生成你需要的目标,你所需要做的就是不要写出这个目标的规则.那么,make会试图去自动推导产生这个目标的规则和命令,如果make可以自动推导生成这个目标的规则和命令,那么这个行为就是隐含规则的自动推导.隐含规则是make事先约定好的一些东西 例如,我们有下面的一个Makefile: foo : foo.o bar.o cc –o foo foo.o bar.o $(CFLAGS) $(LDFLAGS) 并没有写foo.o和bar.o的规则,make会自动推出 有许多的隐含规则都是

F3D模式规则详解

F3D有两个版本,长期版还有短期版 长期版规则 1.购买时候分配 第一队 20% to 奖金池, 56%分给所有人, 30% 持有p3d的人第二队 35% to 奖金池, 43%分给所有人, 8% 持有p3d的人第三队 20% to 奖金池, 30%分给所有人, 6% 持有p3d的人第四队 35% to 奖金池, 43%分给所有人, 0% 持有p3d的人 固定的分配10% to 推荐人, 2% to 开发合约的团队, 1% 用作合约的手续费, 1% to 空投池 2.结束之后的奖金分配 第一队

设计模式——行为型模式之中介者模式(七)

中介者模式 中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性.这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护.中介者模式属于行为型模式. 介绍 意图:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 主要解决:对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应

单例(Singleton pattern)模式的七种写法

转载请注明出处:http://www.cnblogs.com/smbk/ One: Java代码 : 1 public class Singleton { 2 private static Singleton instance; 3 private Singleton (){} 4 5 public static Singleton getInstance() { 6 if (instance == null) { 7 instance = new Singleton(); 8 } 9 retu

行为类模式(七):观察者(Observer)

定义 定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新. UML 优点 观察者和被观察者之间是松耦合的,分别可以各自独立改变. Subject在发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知. 遵守大部分GRASP原则和常用设计原则,高内聚.低耦合. 缺点 松耦合导致代码关系不明显,有时可能难以理解. 如果一个对象被大量观察者订阅的话,在广播通知的时候可能会有效率问题.(毕竟只是简

makefile编写规则

cc = g++ -std=c++11 prom = calc deps = FtTest.h obj = FtTest.o newft.o LIBS = -lgtest_c11 $(prom): $(obj) $(cc) -o $(prom) $(obj) $(LIBS) %.o: %.c $(deps) $(cc) -c $< -o [email protected] 原文地址:https://www.cnblogs.com/ims-/p/9862557.html