如何强制在库中包含“未使用的”对象定义

时间:2010-12-08 02:13:34

标签: c++ linker

我的问题与这些相似,但似乎并不完全相关:

How to force inclusion of an object file in a static library when linking into executable?

Forcing symbol export with MSVC

我得到的是这样的:

struct thingy;
struct container
{
  static container& instance(); // singleton

  int register_thingy(thingy*);
};

struct thingy
{
  virtual ~thingy() {}
  virtual int id() const = 0;
};

//template trick to force registration.
template < typename Derived >
struct registered_thingy : thingy
{
  registered_thingy() : my_id(my_static_id) {} 

  int id() const { return my_id; }
private:
  int my_id;
  static int my_static_id;
}
template < typename Derived >
int registered_thingy<Derived>::my_static_id = 
  container::instance().register_thingy(new Derived);

现在,在concrete_thingy.cpp文件中我有:

struct my_concrete_thingy : registered_thingy<my_concrete_thingy>
{
  my_concrete_thingy() {} // registered_thingy's constructor not called otherwise
};

当然,上面的内容完全没用,但这里有抽象的真实行为。

当在作为整体编译的应用程序中使用时,这非常有效。现在的问题是,到目前为止,我还无法在库中填充collection背后的行为时使用这种技术。换句话说,我有一个包含thingys.lib的{​​{1}}文件,但是当链接到可执行文件时,注册不会发生。 <{1}}最终存在且工作正常,但它是空的。

现在,这是一个STATIC库,而不是DLL。这可能会稍微改变这个问题,而上述链接中所说的技术似乎并不适用。当然是关于函数的,我不知道如何将它应用于这些C ++结构。

我尝试在concrete_thingy.cpp中使用collection方法和以下三行(当然是单独的),但没有一种方法有效:

#pragma comment

如果concrete_thingy.cpp在可执行文件而不是库中,则一切正常。

那么,这是我的问题:

1)我可以做我想做的事情吗?我猜是的,但我只是不知道如何。

2)如果有可能,我将如何获得MSVC ++ 2010?

3)如果可能,我怎么能以便携的方式做到这一点?

简而言之,我要做的就是创建一个创建抽象实现的抽象工厂。它对这些实现一无所知,这些实现是使用全局初始化技巧注册的。这应该都在一个可以由应用程序链接的静态库中,这些实现应该可以通过该工厂获得。除了他们自己以外,没有人知道这些实现,因此正常的链接导致它们和它们的注册全局消失。

这不完全是我要做的,但它足够接近。

编辑:============================================= =======

看起来这种行为是“按设计”。 MS认识到造成副作用的物体的构造无论是否使用都会发生,他们使用标准中的漏洞,允许它们不包括不使用任何物品的翻译单位:\

https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=244410&wa=wsignin1.0&siteid=210

/ OPT:NOREF选项在这种情况下显然不会做任何事情。

4 个答案:

答案 0 :(得分:5)

嗯,另一个回答好的尝试,但最终没有结果。我将使用改装技巧,但其余的似乎是一个红色的鲱鱼;它是有道理的,因为有问题的模板实际上并没有在其他任何地方使用,所以它没有明确实例化的事实不应该有所作为...全局的声明仍然发生在A翻译单元中,它有副作用......我不认为标准允许它被优化掉。

关于标准的不幸一点,不说是否需要包括翻译单元是最终的问题。我认为C ++ 0x正在对此做些什么,但也许不是......无论如何,MS根本不会包含单元,因为它不会将全局最终包含在可执行文件中,因此没有其他废话发生。

我决定做什么,当然还有许多其他方法,就是创建一个文件'tag'变量。然后将该标签分配给可全局访问的功能(它可以分配或分配,或者参考被优化掉)。然后必须从可执行文件中调用该函数。

我决定这样做,因为其余的仍然和以往一样。如果我只是编写一个手动注册类型的注册函数,我最终不会最终改变行为。另外,我可以通过这种方式做其他事情......我只需要确保任何可能属于这个fucktardery分类的东西都有一个标签,并且可以访问该标签。

我会写一堆辅助宏来使这种情况变得无痛。

答案 1 :(得分:1)

有链接器选项/ OPT:REF和/ OPT:NOREF,通过链接器 - &gt; optimization-&gt;引用访问。

答案 2 :(得分:0)

经过大量的尝试和丑陋的破解之后,我最终使我的库变得动态(共享)。解决了问题

答案 3 :(得分:0)

快速浏览LINK.exe的文档指向/WHOLEARCHIVE选项:

/ WHOLEARCHIVE选项强制链接器包括来自指定静态库的每个目标文件。[...]默认情况下,只有在链接器导出由其他对象文件引用的符号时,链接器才将对象文件包括在链接输出中。可执行文件。