我将用一个小例子以供参考。 考虑一个项目有:
inner_definitions.o : inner_definitions.cpp inner_definitions.h
gcc $^ -o $@
inner_class_1.o : inner_class_1.cpp inner_class_1.h inner_definitions.h
gcc $^ -o $@
inner_class_2.o : inner_class_2.cpp inner_class_2.h inner_definitions.h
gcc $^ -o $@
outer_class.o : outer_class.cpp outer_class.h inner_class_1.h inner_class_2.h
gcc $^ -o $@
executable.o : executable.cpp executable.h outer_class.h
gcc $^ -o $@
executable : __?1__
__?2__
但填空题__?1__
链接器的依赖和__?2__
链接器命令是不容易的。
在这个小例子,人们可以说,它很容易地看到, __?1__ = inner_definitions.o inner_class_1.o inner_class_2.o outer_class.o executable.o
。 但是,这显然不是一个灵活的解决方案,因为它迫使每个开发者,了解他们与这样他们就可以通过手 ,而不是通过计算出相关性问题的代码的所有依赖性make
工具。
另一解决方案是具有用于所列出的所有下游依赖每个目标文件不同的变量:即__?1__ = executable.o $(executable_dependencies)
这是不是期望的解决方案,因为它迫使在特定的方式进行编译,所以当它们完全定义的变量只是用来生成文件。 另外,对于真正的大应用这些变量可能超过最大可变长度。
另一种解决方案是使用归档.a文件联系起来。 在这种情况下,我们可以构建一个inner_class_1.a
,其中包括两个inner_defintions.o
和inner_class_1.o
,因此它可以与任何需要的目标文件链接inner_class_1.o
而不强制开发商重建的依赖关系。 这种做法似乎有前途的,但涉及有许多重复的文件。 此外,它不会出现在gcc
连接器可以处理嵌套的存档文件。
是否有另一种方法? 什么是最好的方法呢? 在可gcc
连接处理嵌套的存档文件?
你想自动化(选择正确的目标文件,以满足所有的引用)的工作通常是留给连接器,使用静态库(名为“.a”文件),以组候选对象文件,就像你的建议。
你可能会丢失一个重要的细节:如果您通过链接的存档,只会在那些文件链接,从实际需要的档案。 所以,你可以在粒度的相当粗糙级别创建档案,而不必腹胀所有可执行文件 - 连接器将只选择它所需要的 - 虽然可以很容易地结束了,如果你采取这种方法太远不必要慢的基础之上。
GNU链接拉不出来的对象嵌套库。 如果你想通过合并许多小的,使一个很大的图书馆,你可以做到这一点与在该“addlib”命令AR脚本 。 这会给你一个包含所有目标文件没有任何嵌套库结构单一存档。
如果具有的.o包含相同的目标代码躺在身边文件和.a文件的复制困扰你, 精细手册介绍的方式来让我所有的更新档案“直接” 。
你的Makefile必须有对象的列表链接在一起,就像这样:
OBJ_FILES = inner_definitions.o inner_class_1.o inner_class_2.o \
outer_class.o executable.o
executable : $(OBJ_FILES)
gcc $^ -o $@
必须有人写这一点; GCC不能为你做,让你不能做到这一点。 不在项目每个开发人员需要知道如何构建一个列表,只有谁写Makefile中部分之一。 所有的人都会使用的makefile,谁增加了一个新的依赖开发者(如inner_class_3
)可以将其添加到列表中。
如果你的makefile是在火,谁知道所有的依赖是被车撞的唯一开发商失去了,这真的是不难重建列表:当您尝试使executable
,链接器抱怨说, foo::bar()
是不确定的,你用grep四周,发现foo::bar()
中定义inner_class_2.cpp
,添加inner_class_2.o
到列表中。 重复,直到连接停止抱怨。
PS一旦这是为了,可以简化makefile文件相当多的休息:
%.o: %.cpp %.h
gcc -c $< -o $@
inner_class_1.o inner_class_2.o : inner_definitions.h
outer_class.o : inner_class_1.h inner_class_2.h
executable.o : outer_class.h
编辑:
- 我建议的方法不需要列出可以做,只是在打造'executable`实际需要的那些中的每个对象文件; 我从你的问题推断列表。
- 传递额外的目标文件的链接使最终可执行文件没有什么区别,但它确实导致不必要的重建。 例如,假设您添加`alien.o`到`OBJ_FILES`。 然后,如果你修改`alien.cpp`运行`使executable`,它会重建`alien.o`和`executable`即使没有真正这样做的必要。 更正(感谢slowdog):不必要的目标文件进入最终的可执行死代码-但我还是说得对,没有必要重建。
- 目标文件组织成档案和共享库通常是方便,但并没有真正改变任何东西。
- 我知道没有可靠的方法自动构造对象列表 - 也就是说,可以处理的问题情况下,当同样的功能在两个不同的源文件中被定义,例如一种方式。 如果单元测试涉及这可能成为一个真正的问题。 但是你可以,如果你遵循一个简单的命名约定生成文件内做到这一点。
- 为你的Makefile中这样做的伎俩是一个非常先进的一个。 老实说,我认为你会好起来的,直到你更舒适的工具,这样做的简单方法。
编辑:
好吧,这里是先进技术的概要。
首先,考虑所有的包含(#include)头文件。 这将是不错的制作处理的依赖关系,而不是把他们的手,如上面的Makefile中。 这是一个简单的任务:如果X.cpp来#include Yh的(直接或通过包含(#include)头文件的一些连锁),然后XO将取决于Yh的这一点已经制定出“高级自动依存产生” 。 但是,如果你遵循严格的命名约定,你可以把它更进了一步:如果一切已宣告但尚未在的Xh定义X.cpp定义,然后通过下面的#include语句的同一棵树上,我们应该能够建立一个列表的所需目标文件,那么这将是依赖executable
。
这确实是大量吸纳一次,所以我不会试图通过一个例子来工作。 我建议你查看文档,看看它是如何产生的Yh的依赖关系,然后尝试将其应用到例如makefile文件,再想想“一步”应该做的事。
稍后,您可以将其应用到测试工具,其中对象文件,例如, outer_class.o
, stub_inner_class_1.o
, stub_inner_class_2.o
和test_outer_class.o
。
文章来源: How do I get make to figure out the correct dependencies to link in the correct downstream object files?