2012-04-09 55 views
7

我一直使用和测试自行注册,抽象工厂根据这里所描述的:链接自行注册,抽象工厂

https://stackoverflow.com/a/582456

在我所有的测试案例,它的工作原理像一个魅力,并提供了我想要的功能和重用。

在我的项目中使用cmake链接这个工厂一直非常棘手(尽管它似乎更像是一个问题)。

我有相同的base.hpp,derivedb.hpp/cpp和等效的deriveda.hpp/cpp链接的例子。在main中,我只是实例化工厂并调用createInstance()两次,每次都使用“DerivedA”和“DerivedB”。

由线创建可执行文件:

g++ -o testFactory main.cpp derivedb.o deriveda.o 

按预期工作。移动我的派生类到库(使用cmake,但我已经与AR单独以及测试这一点),然后链接失败:

ar cr libbase.a deriveda.o derivedb.o 
g++ -o testFactory libbase.a main.cpp 

只要求第一个静态实例(从derivedA.cpp),从不第二静态实例,即

// deriveda.cpp (if listed first in the "ar" line, this gets called) 
DerivedRegister<DerivedA> DerivedA::reg("DerivedA"); 

// derivedb.cpp (if listed second in the "ar" line, this does not get called) 
DerivedRegister<DerivedB> DerivedB::reg("DerivedB"); 

注意,在AR线交换两个只调用derivedb.cpp静态实例,而不是deriveda.cpp实例。

我是否错过了某些与ar或静态库,某种方式不能很好地用C++中的静态变量播放?

回答

10

与直觉相反,包括链接命令中的存档与包含存档中的所有对象文件不同。只包含归档中解析未定义符号所需的那些对象文件。如果您认为一旦没有动态链接,并且其他任何库(认为C库)都将被复制到每个可执行文件中,这是件好事。以下是ld(1)手册页(linux上的GNU ld)必须说的:

链接器将只在命令行中指定的位置搜索存档。如果归档文件定义了一个符号,该符号在命令行上归档之前出现的某个对象中未定义,则链接器将从归档文件中包含相应的文件。但是,稍后在命令行中出现的对象中的未定义符号将不会导致链接器再次搜索存档。

不幸的是,没有一种标准的方法可以将链接的可执行文件中的每个档案成员包含进来。在Linux上,您可以使用g++ -Wl,-whole-archive,在Mac OS X上,您可以使用g++ -all_load

因此,与GNU binutils的LD,该链接命令应该是

g++ -o testFactory -Wl,-whole-archive libbase.a -Wl,-no-whole-archive main.cpp 

-Wl,-no-whole-archive确保任何档案由++将以正常方式被链接克生成的最终链接命令后面出现。

+0

非常感谢,这让我走上了正确的道路。为了将来的参考,这也有所帮助(感谢在整个档案库中改进了search-foo!) http://stackoverflow.com/a/842770/1322752 – 2012-04-09 22:25:14