简体   繁体   English

g ++会将我的程序与库中没有使用的类链接起来吗?

[英]Will g++ link my programs with classes it doesn't use from a library?

I've created a simple static library, contained in a .a file. 我创建了一个简单的静态库,包含在.a文件中。 I might use it in a variety of projects, some of which simply will not need 90% of it. 我可能会在各种项目中使用它,其中一些项目根本不需要90%的项目。 For example, if I want to use neural networks, which are a part of my library, on an AVR microcomputer, I probably wont need a tonne of other stuff, but will that be linked in my code potentially generating a rather large file? 例如,如果我想在AVR微型计算机上使用神经网络(我的库的一部分),我可能不需要其他一些东西,但是在我的代码中是否会链接可能产生一个相当大的文件?

I intend to compile programs like this: 我打算编译这样的程序:

g++ myProg.cpp myLib.a -o prog

G++ will pull in only the object files it needs from your library, but this means that if one symbol from a single object file is used, everything in that object file gets added to your executable. G ++只会从库中提取所需的目标文件,但这意味着如果使用单个目标文件中的一个符号,该目标文件中的所有内容都会添加到您的可执行文件中。

One source file becomes one object file, so it makes sense to logically group things together only when they are sure to be needed together. 一个源文件成为一个目标文件,因此只有在确定需要它们时才将逻辑分组在一起才有意义。

This practice varies by compiler (actually by linker). 这种做法因编译器(实际上是链接器)而异。 For example, the Microsoft linker will pick object files apart and only include those parts that actually are needed. 例如,Microsoft链接器将选择对象文件,仅包含实际需要的那些部分。

您还可以尝试将库拆分为独立的较小部分,并仅链接您真正需要的部分。

When you link to a static library the linker pulls in things that resolve names used in other parts of the code. 链接到静态库时,链接器会引入解析代码其他部分中使用的名称的内容。 In general, if the name isn't used it doesn't get linked in. 通常,如果未使用该名称,则不会链接到该名称。

The GNU linker will pull in the stuff it needs from the libraries you have specified on an object file by object file basis. GNU链接器将根据目标文件从您在目标文件上指定的库中提取所需的内容。 Object files are atomic units as far as the GNU linker is concerned. 就GNU链接器而言,目标文件是原子单元。 It doesn't split them apart. 它不会将它们分开。 The linker will bring in an object file if that object file defines one or more unresolved external references. 如果该对象文件定义了一个或多个未解析的外部引用,则链接器将引入目标文件。 That object file may have external references. 该目标文件可能具有外部引用。 The linker will try to resolve these, but if it can't, the linker adds those to the set of references that need to be resolved. 链接器将尝试解析这些问题,但如果不能,则链接器会将这些内容添加到需要解析的引用集中。

There are a couple of gotchas that can make for a much larger than needed executable. 有几个问题可以使得比需要的可执行文件大得多。 By larger than needed, I mean an executable that contains functions that will never be called, global objects that will never be examined or modified, during the execution of the program. 大于需要,我指的是一个可执行文件,它包含永远不会被调用的函数,在程序执行期间永远不会被检查或修改的全局对象。 You will have binary code that is unreachable. 您将拥有无法访问的二进制代码。

One of these gotchas results when an object file contains a large number of functions or global objects. 当目标文件包含大量函数或全局对象时,会产生其中一个问题。 Your program might only need one of these, but your executable gets all of them because object files are atomic units to the linker. 您的程序可能只需要其中一个,但您的可执行文件会获取所有这些,因为目标文件是链接器的原子单元。 Those extra functions will be unreachable because there's no call path from your main to these functions, but they're still in your executable. 这些额外的功能将无法访问,因为从main功能到这些功能没有呼叫路径,但它们仍然在您的可执行文件中。 The only way to ensure that this doesn't happen is to use the "one function per source file" rule. 确保不会发生这种情况的唯一方法是使用“每个源文件一个函数”规则。 I don't follow that rule myself, but I do understand the logic of it. 我自己并不遵循这条规则,但我确实理解它的逻辑。

Another set of gotchas occur when you use polymorphic classes. 当您使用多态类时会发生另一组陷阱。 A constructor contains auto-generated code as well as the body of the constructor itself. 构造函数包含自动生成的代码以及构造函数本身。 That auto-generated code calls the constructors for parent classes, inserts a pointer to the vtable for the class in the object, and initializes data members per the initializer list. 该自动生成的代码调用父类的构造函数,在对象中插入指向类的vtable的指针,并根据初始化列表初始化数据成员。 These parent class constructors, the vtable, and the mechanisms to process the initializer list might be external references that the linker needs to resolve. 这些父类构造函数,vtable和处理初始化列表的机制可能是链接器需要解析的外部引用。 If the parent class constructor is in a larger header file, you've just dragged all that stuff into your executable. 如果父类构造函数位于较大的头文件中,那么您只需将所有内容拖到可执行文件中即可。

What about the vtable? 那个vtable怎么样? The GNU compiler picks a key member function as the place to store the vtable. GNU编译器选择一个关键成员函数作为存储vtable的地方。 That key function is the first member function in the class that does not have a an inline definition. 该关键函数是类中第一个没有内联定义的成员函数。 Even if you don't call that member function, you get the object file that contains it in your executable -- and you get everything that that object file drags in. 即使您不调用该成员函数,您也会在可执行文件中获得包含它的目标文件 - 并且您将获得该对象文件拖入的所有内容。

Keeping your source files down to a small size once again helps with this "look what the cat dragged in!" 将源文件保持在较小的尺寸再一次有助于“看看猫拖入的内容!” problem. 问题。 It's a good idea to pay special attention to the file that contains that key member function. 特别注意包含该关键成员函数的文件是个好主意。 Keep that source file small, at least in terms of stuff the cat will drag in. I tend to put small, self-contained member functions in that source file. 保持该源文件较小,至少在cat将拖入的内容方面。我倾向于在该源文件中放置小的,自包含的成员函数。 Functions that will inevitably drag in a bunch of other stuff shouldn't go there. 不可避免地拖入其他东西的功能不应该去那里。

Another issue with the vtable is that it contains pointers to all of the virtual functions for a class. vtable的另一个问题是它包含指向类的所有虚函数的指针。 Those pointers need to point to something real. 那些指针需要指向真实的东西。 Your executable will contain the object files that define each and every virtual function defined for a class, including the ones you never call. 您的可执行文件将包含定义为类定义的每个虚拟函数的目标文件,包括您从未调用的函数。 And you're going to get everything that those virtual functions drag in as well. 而且你将获得那些虚拟函数所拖入的所有东西。

One solution to this problem is to avoid making big huge classes. 这个问题的一个解决方案是避免制作大型课程。 They tend to drag in everything . 他们倾向于拖入一切 God classes in particular are problematic in this regard. 在这方面,上帝课程尤其成问题。 Another solution is to think hard about whether a function really does need to be virtual. 另一个解决方案是努力思考一个函数是否真的需要是虚拟的。 Don't just make a function virtual because you think someday someone will need to overload it. 不要只是将函数设置为虚拟,因为你认为有一天会有人需要重载它。 That's speculative generality, and with virtual functions, speculative generality comes with a high cost. 这是推测性的普遍性,并且对于虚拟功能,投机性的普遍性带来了高成本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM