如何创建与 pthreads 和 libstdc 静态链接的共享对象++ 在 Linux/gcc 上?
如何在 Linux/gcc 上创建与 pthreads 和 libstdc++ 静态链接的共享对象?
How to create a shared object that is statically linked with pthreads and libstdc++ on Linux/gcc?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在我按照描述回答您的问题之前,我会注意到,您最终想要实现的目标并不完全清楚,并且可能有更好的解决方案来解决您的问题。
也就是说 - 尝试执行您所描述的操作有两个主要问题:
一个是,您需要将
libpthread
和libstdc++
分解为它们的对象文件是用. 这是因为ELF二进制文件(在Linux上使用)有两个级别的“运行时”库加载 - 即使可执行文件是静态链接的,加载器也必须在执行时加载二进制文件中的静态链接库,并映射正确的内存地址。 这是在动态加载的库(共享对象)并映射到共享内存的共享链接之前完成的。 因此,共享对象不能与此类库静态链接,因为在加载对象时,所有静态链接库都已加载。 这是静态库和普通目标文件链接之间的一个区别 - 静态库不仅像任何目标文件一样粘合到可执行文件中,而且仍然包含加载时引用的单独表。 (我相信这与 MS-DOS 和经典 Windows 中简单得多的静态库.LIB
文件形成鲜明对比,但可能比我记得的要多) >.当然,您实际上不必分解
libpthread
和libstdc++
,您可以只使用构建它们时生成的目标文件。 不过,收集它们可能有点困难(查找这些库的最终 Makefile 规则引用的对象)。 并且您必须直接使用ld
而不是gcc
/g++
进行链接,以避免与动态版本链接。第二个问题是必然的。 如果您执行上述操作,您肯定会拥有您要求构建的共享对象/动态库。 但是,它不会很有用,因为一旦您尝试将使用这些
libpthread
/libstdc++
(后者是任何 C++ 程序)的常规可执行文件与此共享对象链接起来,它将因符号冲突而失败 - 您链接共享对象的静态libpthread
/libstdc++
对象的符号将与标准libpthread< 中的符号发生冲突/code>/
libstdc++
由该可执行文件使用,无论它是与标准库动态还是静态链接。您当然可以尝试隐藏共享库使用的
libstdc++
/libpthread
的静态对象中的所有符号,以某种方式将它们设为私有,或者链接时自动重命名它们,这样就不会发生冲突。 然而,即使你让它工作,你也会在运行时发现一些不想要的结果,因为libstdc++
/libpthread
在全局变量和结构中保留了相当多的状态,现在你们将拥有重复的文件,并且彼此不知道对方。 这将导致这些全局数据与底层操作系统状态(例如文件描述符和内存边界)之间不一致(可能还有标准 C 库中的一些值,例如libstdc++
的errno
>,以及libpthread
的信号处理程序和计时器。为了避免过于宽泛的解释,我将添加一条评论:有时想要静态链接可能有合理的理由。甚至像
libstdc++
甚至libc
这样的基本库,即使对于最近的系统和这些库的版本来说它变得有点困难(由于与加载器和使用的特殊链接器技巧),这是绝对可能的 - 我做了几次,并且知道在其他情况下它仍然完成。在这种情况下,您需要静态链接整个可执行文件,与标准库的静态链接与其他对象的动态链接通常是不可行的。编辑:我忘记提及但必须考虑的一个问题是 C++ 特定的。 不幸的是,C++ 的设计不能很好地与对象链接和加载的经典模型(在 Unix 和其他系统上使用)配合使用。 这使得 C++ 中的共享库不能真正实现应有的可移植性,因为许多内容(例如类型信息和模板)在对象之间没有清晰地分离(通常在编译时从标头中与许多实际的库代码一起获取) )。 由于这个原因,
libstdc++
与 GCC 紧密耦合,并且使用一个版本的g++
编译的代码通常只能与此中的libstdc++
一起使用(或非常相似的)g++
版本。 如果您尝试在使用 GCC 3 构建的系统上使用任何重要的库来使用 GCC 4 构建程序,您肯定会注意到,这不仅仅是libstdc++
。 如果您想要这样做的原因是试图确保您的共享对象始终与它所构建的特定版本的libstdc++
和libpthread
链接,则这不会因为使用不同/不兼容的libstdc++
的程序也会使用不兼容的 C++ 编译器或g++
版本构建,因此无论如何都无法与您的共享对象链接,除了实际的libstdc++
冲突。如果您想知道“为什么不把这做得更简单一些?”,那么一个值得深思的普遍思考:C++ 可以很好地与动态/共享库配合使用(意味着跨编译器的兼容性,以及替换动态库的能力)具有兼容接口的另一个版本的库,而无需重建使用它的所有内容),不仅需要编译器标准化,而且在操作系统加载器级别,对象和库文件的结构和接口以及链接器的工作都需要显着扩展,超出了常见操作系统(Microsoft Windows、基于 Mach 的系统和 NeXTStep 相关系统,例如 Mac OS、VMS 相关系统和一些大型机系统)上使用的相对简单的 Unix 经典)今天本地构建的代码。 链接器和动态加载器需要了解诸如模板和类型之类的事情,在某种程度上具有小型编译器的功能,以实际使库的代码适应给定的类型 - 并且(< em>此处的个人主观观察)似乎高级中间代码(连同高级语言和即时编译)正在更快地流行起来,并且可能比此类扩展更快地标准化。本机对象格式和链接器。
Before I go to answering your question as it was described, I will note that it is not exactly clear what you are trying to achieve in the end, and there is probably a better solution to your problem.
That said - there are two main problems with trying to do what you described:
One is, that you will need to decompose
libpthread
andlibstdc++
to the object files they are made with. This is because ELF binaries (used on Linux) have two levels of "run time" library loading - even when an executable is statically linked, the loader has to load the statically linked libraries within the binary on execution, and map the right memory addresses. This is done before the shared linkage of libraries that are dynamically loaded (shared objects) and mapped to shared memory. Thus, a shared object cannot be statically linked with such libraries, as at the time the object is loaded, all static linked libraries were loaded already. This is one difference between linking with a static library and a plain object file - a static library is not merely glued like any object file into the executable, but still contains separate tables which are referred to on loading. (I believe that this is in contrast to the much simpler static libraries in MS-DOS and classic Windows,.LIB
files, but there may be more to those than I remember).Of course you do not actually have to decompose
libpthread
andlibstdc++
, you can just use the object files generated when building them. Collecting them may be a bit difficult though (look for the objects referred to by the final Makefile rule of those libraries). And you would have to useld
directly and notgcc
/g++
to link, to avoid linking with the dynamic versions as well.The second problem is consequential. If you do the above, you will sure have such a shared object / dynamic library as you asked to build. However, it will not be very useful, as once you try to link a regular executable that uses those
libpthread
/libstdc++
(the latter being any C++ program) with this shared object, it will fail with symbol conflicts - the symbols of the staticlibpthread
/libstdc++
objects you linked your shared object against will clash with the symbols from the standardlibpthread
/libstdc++
used by that executable, no matter if it is dynamically or statically linked with the standard libraries.You could of course then try to either hide all symbols in the static objects from
libstdc++
/libpthread
used by your shared library, make them private in some way, or rename them automatically on linkage so that there will be no conflict. However, even if you get that to work, you will find some undesireable results in runtime, since bothlibstdc++
/libpthread
keep quite a bit of state in global variables and structures, which you would now have duplicate and each unaware of the other. This will lead to inconsistencies between these global data and the underlying operating system state such as file descriptors and memory bounds (and perhaps some values from the standard C library such aserrno
forlibstdc++
, and signal handlers and timers forlibpthread
.To avoid over-broad interpretation, I will add a remark: at times there can be sensible grounds for wanting to statically link against even such basic libraries as
libstdc++
and evenlibc
, and even though it is becoming a bit more difficult with recent systems and versions of those libraries (due to a bit of coupling with the loader and special linker tricks used), it is definitely possible - I did it a few times, and know of other cases in which it is still done. However, in that case you need to link a whole executable statically. Static linkage with standard libraries combined with dynamic linkage with other objects is not normally feasible.Edit: One issue which I forgot to mention but is important to take into account is C++ specific. C++ was unfortunately not designed to work well with the classic model of object linkage and loading (used on Unix and other systems). This makes shared libraries in C++ not really portable as they should be, because a lot of things such as type information and templates are not cleanly separated between objects (often being taken, together with a lot of actual library code at compile time from the headers).
libstdc++
for that reason is tightly coupled with GCC, and code compiled with one version ofg++
will in general only work with thelibstdc++
from with this (or a very similar) version ofg++
. As you will surely notice if you ever try to build a program with GCC 4 with any non-trivial library on your system that was built with GCC 3, this is not justlibstdc++
. If your reason for wanting to do that is trying to ensure that your shared object is always linked with the specific versions oflibstdc++
andlibpthread
that it was built against, this would not help because a program that uses a different/incompatiblelibstdc++
would also be built with an incompatible C++ compiler or version ofg++
, and would thus fail to link with your shared object anyway, aside from the actuallibstdc++
conflicts.If you wonder "why wasn't this done simpler?", a general rumination worth pondering: For C++ to work nicely with dynamic/shared libraries (meaning compatibility across compilers, and the ability to replace a dynamic library with another version with a compatible interface without rebuilding everything that uses it), not just compiler standartization is needed, but at the level of the operating system's loader, the structure and interface of object and library files and the work of the linker would need to be significantly extended beyond the relatively simple Unix classics used on common operating systems (Microsoft Windows, Mach based systems and NeXTStep relatives such as Mac OS, VMS relatives and some mainframe systems also included) for natively built code today. The linker and dynamic loader would need to be aware of such things as templates and typing, having to some extent functionality of a small compiler to actually adapt the library's code to the type given to it - and (personal subjective observation here) it seems that higher-level intermediate intermediate code (together with higher-level languages and just-in-time compilation) is catching ground faster and likely to be standardized sooner than such extensions to the native object formats and linkers.
您在单独的评论中提到您正在尝试将 C++ 库移植到嵌入式设备。 (我在这里添加一个新答案,而不是在这里编辑我的原始答案,因为我认为对这个原始问题感兴趣的其他 StackOverflow 用户可能仍然对其上下文中的答案感兴趣)
显然,取决于关于你的嵌入式系统的精简程度(我没有太多嵌入式Linux经验,所以我不确定最有可能的是什么),你当然可以在上面安装共享的
libstdc++
并且动态链接所有内容,就像您在其他情况下所做的那样。如果动态链接
libstdc++
对您不利或无法在您的系统上工作(嵌入式系统有许多不同级别,人们无法知道),并且您需要链接到staticlibstdc++
,那么正如我所说,您唯一真正的选择是使用该库与它和libstdc++
静态链接可执行文件。 您提到将库移植到嵌入式设备,但如果这是为了在您在设备上编写或构建的某些代码中使用它,并且您不介意静态libstdc++
,那么静态链接所有内容(除了libc
)可能没问题。如果
libstdc++
的大小是一个问题,并且您发现您的库实际上只使用了其接口的一小部分,那么我仍然建议首先尝试确定您需要的实际空间通过仅链接您需要的部分来保存。 它可能重要也可能不重要,我从来没有深入研究过 libstdc++ 并且我怀疑它有很多内部依赖项,所以虽然您肯定不需要某些接口,但您可能会也可能不会仍然取决于其内部的很大一部分 - 我不知道也没有尝试,但它可能会让你感到惊讶。 您可以通过将使用该库的二进制文件与它和 libstdc++ 的静态构建链接起来(当然,不要忘记剥离二进制文件),并将生成的可执行文件的大小与与库和 libstdc++ 的完整 (strip
ped) 共享对象动态链接在一起的 (strip
ped) 可执行文件的总大小。< /p>如果您发现大小差异很大,但又不想静态链接所有内容,则可以尝试通过重建 libstdc++ 来减小它的大小,而无需某些您知道不需要的部分(其中的某些部分有配置时选项,您也可以尝试在最终创建
libstdc++.so
时删除一些独立对象。有一些工具可以优化库的大小 -搜索网络(我记得来自一家名为 MontaVista 的公司,但现在在他们的网站上看不到它,还有其他一些)。需要考虑一些想法和建议:
您提到您使用 uClibc,我自己从未摆弄过它(我对嵌入式编程的经验要原始得多,主要涉及嵌入式处理器的汇编编程和使用最小嵌入式库的交叉编译),我假设您检查了这一点,并且我知道 uClibc 旨在成为一个轻量级但相当完整的标准 C 库,但是不要忘记,C++ 代码很难独立于 C 库,而
g++
和libstdc++
依赖于一些微妙的东西(我记得libc
的问题> 在某些专有的 Unix 版本上),所以我不会只是假设g++
或 GNUlibstdc++
实际上可以在没有尝试的情况下与uClibc
一起工作 - 我不这样做我不记得在uClibc
页面中看到过它。此外,如果这是一个嵌入式系统,请考虑其性能、计算能力、整体复杂性以及时序/简单性/可靠性要求。 考虑到所涉及的复杂性,并考虑在您的嵌入式系统中使用 C++ 和线程是否合适,如果系统中没有其他东西使用它们,是否值得为该库引入它们。 可能是,我不知道我无法告诉的库或系统(同样,嵌入式系统现在范围如此广泛)。
在这种情况下,我偶然发现了一个快速链接来寻找
uClibc
- 如果您正在使用uClibc
开发嵌入式系统,并且想要使用 C++ 代码关于它——看看uClibc++
。 我不知道你需要多少标准的 C++ 东西并且它已经支持,而且它似乎是一个正在进行的项目,所以不清楚它是否已经处于对你来说足够好的状态,但假设你的工作也在对于您的嵌入式工作来说,它仍然是 GCC 的libstdc++
的一个很好的替代品。You mentioned in a separate comment that you are trying to port a C++ library to an embedded device. (I am adding a new answer here instead of editing my original answer here because I think other StackOverflow users interested in this original question may still be interested in that answer in its context)
Obviously, depending on how stripped down your embedded system is (I have not much embedded Linux experience, so I am not sure what is most likely), you may of course be able to just install the shared
libstdc++
on it and dynamically link everything as you would do otherwise.If dynamically linking with
libstdc++
would not be good for you or not work on your system (there are so many different levels of embedded systems that one cannot know), and you need to link against a staticlibstdc++
, then as I said, your only real option is static linking the executable using the library with it andlibstdc++
. You mentioned porting a library to the embedded device, but if this is for the purpose of using it in some code you write or build on the device and you do not mind a staticlibstdc++
, then linking everything statically (aside from perhapslibc
) is probably OK.If the size of
libstdc++
is a problem, and you find that your library is actually only using a small part of its interfaces, then I would nonetheless suggest first trying to determine the actual space you would save by linking against only the parts you need. It may be significant or not, I never looked that deep intolibstdc++
and I suspect that it has a lot of internal dependencies, so while you surely do not need some of the interfaces, you may or may not still depend on a big part of its internals - I do not know and did not try, but it may surprise you. You can get an idea by just linking a binary using the library against a static build of it andlibstdc++
(not forgetting to strip the binary, of course), and comparing the size of the resulting executable that with the total size of a (strip
ped) executable dynamically linked together with the full (strip
ped) shared objects of the library andlibstdc++
.If you find that the size difference is significant, but do not want to statically link everything, you try to reduce the size of
libstdc++
by rebuilding it without some parts you know that you do not need (there are configure-time options for some parts of it, and you can also try to remove some independent objects at the final creation oflibstdc++.so
. There are some tools to optimize the size of libraries - search the web (I recall one from a company named MontaVista but do not see it on their web site now, there are some others too).Other than the straightforward above, some ideas and suggestions to think of:
You mentioned that you use
uClibc
, which I never fiddled with myself (my experience with embedded programming is a lot more primitive, mostly involving assembly programming for the embedded processor and cross-compiling with minimal embedded libraries). I assume you checked this, and I know thatuClibc
is intended to be a lightweight but rather full standard C library, but do not forget that C++ code is hardly independent on the C library, andg++
andlibstdc++
depend on quite some delicate things (I remember problems withlibc
on some proprietary Unix versions), so I would not just assume thatg++
or the GNUlibstdc++
actually works withuClibc
without trying - I don't recall seeing it mentioned in theuClibc
pages.Also, if this is an embedded system, think of its performance, compute power, overall complexity, and timing/simplicity/solidity requirements. Take into consideration the complexity involved, and think whether using C++ and threads is appropriate in your embedded system, and if nothing else in the system uses those, whether it is worth introducing for that library. It may be, not knowing the library or system I cannot tell (again, embedded systems being such a wide range nowadays).
And in this case also, just a quick link I stumbled upon looking for
uClibc
-- if you are working on an embedded system, usinguClibc
, and want to use C++ code on it -- take a look atuClibc++
. I do not know how much of the standard C++ stuff you need and it already supports, and it seems to be an ongoing project, so not clear if it is in a state good enough for you already, but assuming that your work is also under development still, it might be a good alternative to GCC'slibstdc++
for your embedded work.我认为这个人很好地解释了为什么这不会使感觉。 使用共享对象但使用不同 libstdc++ 的 C++ 代码可以正常链接,但无法工作。
I think this guy explains quite well why that wouldn't make sense. C++ code that uses your shared object but a different libstdc++ would link alright, but wouldn't work.