连接一个自我注册的抽象工厂

Eth*_*oon 7 c++ g++ cmake unix-ar

我一直在研究和测试一个基于这里描述的自我注册的抽象工厂:

/sf/answers/40771951/

在我的所有测试用例中,它都像魅力一样工作,并提供我想要的功能和重用.

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

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

该行创建的可执行文件:

g++ -o testFactory main.cpp derivedb.o deriveda.o
Run Code Online (Sandbox Code Playgroud)

按预期工作.将我的派生类移动到一个库中(使用cmake,但我也单独用ar测试过它),然后链接失败:

ar cr libbase.a deriveda.o derivedb.o
g++ -o testFactory libbase.a main.cpp
Run Code Online (Sandbox Code Playgroud)

只调用第一个静态实例化(来自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");
Run Code Online (Sandbox Code Playgroud)

请注意,在ar行中交换两个调用仅调用derivedb.cpp静态实例化,而不调用deriveda.cpp实例化.

我是否遗漏了一些使用ar或静态库的东西,这些库在某种程度上与C++中的静态变量不相称?

Geo*_*edy 10

与直觉相反,包括链接命令中的存档与包含存档中的所有对象文件不同.仅包括解析未定义符号所需的归档中的那些目标文件.如果你考虑到一旦没有动态链接,那么这是一件好事,否则任何库(想想C库)都会被复制到每个可执行文件中.这是ld(1)联机帮助页(Linux上的GNU ld)必须说的:

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

遗憾的是,没有标准方法可以在链接的可执行文件中包含存档的每个成员.在Linux上你可以使用g++ -Wl,-whole-archive和在Mac OS X上使用g++ -all_load.

所以使用GNU binutils ld,link命令应该是

g++ -o testFactory -Wl,-whole-archive libbase.a -Wl,-no-whole-archive main.cpp
Run Code Online (Sandbox Code Playgroud)

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