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

2022-01-11 00:00:00 linker c++

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

My question is similar to these but doesn't seem to correlate exactly:

如何在链接到可执行文件时强制将目标文件包含在静态库中?

强制使用 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 文件中,我有:

Now, in a concrete_thingy.cpp file I have:

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

当然,上面说的完全没用,但是这里抽象了真实的行为.

Of course, the above is totally useless, but there's real behavior being abstracted here.

当在作为一个整体编译的应用程序中使用时,这非常有效.现在的问题是,到目前为止,我无法在将 collection 背后的行为装瓶到库中时使用这种技术.换句话说,我有一个包含 concrete_thingy.cppthingys.lib 文件,但是当它链接到可执行文件时没有发生注册.collection 最终存在并且工作正常,但它是空的.

This works wonderfully when used in an application that is compiled as a whole. The issue now is that I'm not able, so far, to use this technique while bottling up the behavior behind collection in a library. In other words, I've got a thingys.lib file that contains concrete_thingy.cpp but the registration is not occurring when that is linked to an executable. The collection ends up existing and working fine, but it's empty.

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

Now, this is a STATIC library, not a DLL. That may change the issue a little and the techniques spoken about in the links above don't seem to apply. The one of course is about functions and I don't see how I could apply it to these C++ structures.

我尝试在 concrete_thingy.cpp 中使用 #pragma comment 方法和以下三行(当然是单独的),但均无效:p>

I've tried to use the #pragma comment method with the following three lines (individually of course) in concrete_thingy.cpp, none of which worked:

#pragma comment (linker, "/export:concrete_thingy")
#pragma comment (linker, "/export:concrete_thingy::my_static_id")
#pragma comment (linker, "/export:registered_thingy<concrete_thingy>::my_static_id")

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

If concrete_thingy.cpp is in the executable rather than the library everything works fine.

那么,这是我的问题:

1) 有可能做我想做的事吗?我猜是的,但我就是不知道怎么做.

1) Is it possible to do what I'm trying to do? I'm guessing yes, but I just don't know how.

2) 如果可能,我将如何让 MSVC++ 2010 做到这一点?

2) If it is possible, how would I get MSVC++ 2010 to do it?

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

3) If it is possible, how could I do it in a portable way?

简而言之,我想做的类似于创建一个抽象工厂来创建抽象的实现.它对这些使用全局初始化技巧注册的实现一无所知.这应该都在一个可以被应用程序链接到的静态库中,并且这些实现应该可以通过该工厂获得.除了他们自己之外,没有人对这些实现一无所知,因此正常的链接会导致它们以及它们的注册全局变量消失.

In short, what I'm trying to do would be similar to creating an abstract factory that creates implementations of an abstraction. It knows nothing about these implementations, which are registered using global initialization trickery. This should all be in a static library that can be linked to by an application and these implementations should be available through that factory. Nobody knows anything about these implementations except themselves and thus normal linking is causing them, and their registration globals, to disappear.

这不是我想要的,但已经足够接近了.

It's not exactly what I'm up to, but it's close enough.

=====================================================

====================================================

看起来这种行为是设计使然".MS 认识到,无论是否使用它们都应该构造引起副作用的对象,它们使用了标准中的一个漏洞,允许它们不包括没有使用任何内容的翻译单元:

Looks like this behavior is "by design". MS recognizes that construction of object that cause side effects should occur whether or not their used, they use a loophole in the standard that allows them to not include translation units in which nothing is used :

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

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

The /OPT:NOREF option is designed to not do anything in this case apparently.

推荐答案

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

Well, the other answers where good attempts but ultimately fruitless. I am going to use the refit trick but the rest appears to have been a red herring; it kind of makes sense since the template in question isn't actually used anywhere else so the fact that it's not explicitly instantiated shouldn't make a difference...the declaration of the global still happens in A translation unit, it has side effects...I don't think the standard allows it to be optimized away.

不幸的是,标准没有说明是否需要包含翻译单元,这是最终的问题.我认为 C++0x 正在对此做一些事情,但可能没有……无论如何,MS 可以随意不包含该单元,并且由于它不包含全局,因此最终不会包含在可执行文件中,因此没有其他废话发生.

The unfortunate bit about the standard not saying whether or not it is required to include a translation unit at all is the ultimate issue. I think C++0x is doing something about this but maybe not... At any rate, MS feels free to not include the unit at all, and since it doesn't the global isn't ultimately included in the executable and thus none of the other crap happens.

我决定做的,当然还有很多其他方法,就是创建一个文件标签"变量.然后将该标签分配给一个可全局访问的函数(它必须分配或分配,或者引用被优化掉).然后必须从可执行文件中调用该函数.

What I've decided to do, and there are of course many other ways, is to create a file 'tag' variable. That tag is then assigned to in a function that is globally accessible (it HAS to assign or assign from or the reference is optimized away). Then that function has to be called from the executable.

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

I decided to do it this way because then the rest still works the same as it always has. I don't end up ultimately changing behavior like I could if I simply wrote a registration function that hand-registered the types. Plus I can do other things this way...I just have to make sure that anything that might fall into this classification of fucktardery has a tag and that tag is accessed.

我将编写一堆辅助宏来让这一切变得轻松.

I'll be writing a bunch of helper macros to make this mostly painless.

相关文章