Linux CRunTime库与Microsoft相比是如何处理的?

3
我一直在与Microsoft的CRT(C运行时库)概念问题纠缠不清。对于任何项目,您必须编译所有所需的库以链接到相同版本的CRT。
第一个问题是当您的项目静态链接到CRT(/MT)时。那么所有依赖的库也必须静态地链接它们自己的CRT。因此,每个库都有自己的版本,例如malloc()。如果您去年在A系统上编译了其中一个库,则该CRT版本可能与您当前在另一个带服务包3+的B系统上使用的版本不同。如果您释放由库分配的对象,则可能会遇到问题。
因此,动态链接的CRT似乎是正确的选择(/MD)。使用dll,所有库都会获取系统上当前的CRT实现。除了Microsoft的Side by Side机制并非如此。相反,您会获得在您编译的库上标记的CRT版本,并且该版本的DLL提供给该库。因此,之前描述的完全相同的问题可能会发生。您在一年前在A系统上编译了一个库并使用了一个CRT。一年后有新的升级版本。您的主程序获取带有一个CRT版本的DLL,库获取带有另一个CRT版本的DLL,同样可能会出现问题。
那你怎么办?我意识到跨库内存分配是不被看好的。但可以忽略malloc示例并想出另一个示例。您是否要求每个开发人员在其计算机上重新编译每个依赖库,以确保所有内容都使用相同的CRT?然后再次为发布重新编译每个库?
在Linux上,这是如何工作的?那是我的主要兴趣。GCC提供CRT还是Linux系统本身带有CRT库?我从未在Makefile中显式链接CRT。
在Linux上,动态库链接的是什么CRT?在机器上最新的一个,还是更像“side by side”的机制。

据我所知,在Linux中重新构建整个项目和依赖通常不是问题,因为代码经常是可用的。 - Lol4t0
glibc(C库的GNU实现,涵盖ISO C + POSIX +一些扩展)使用版本化符号来处理不同版本之间的兼容性。几乎所有其他库的作者都不太关心版本之间的这种兼容性,因为大多数Linux软件都是以源代码形式分发的,并且可以随意重新编译(无论是由发行版还是最终用户)。 - ninjalj
从技术上讲,由于符号版本的原因,在Linux上不同代码部分调用相同的samefunc@@version也可能会出现问题。然而,与msvcrt不同,截至目前为止,glibc仍只有一个malloc符号(malloc@@GLIBC_2.2.5)。我也不明白为什么它需要更多,毕竟,malloc的ABI自ANSI C以来就没有改变过,并且在不久的将来也不太可能改变。 - jørgensen
1个回答

2
在Linux方面,我认为标准库有两个基本部分存在问题:我们有C运行时部分,这部分应该永远是ABI兼容的。实际上,无论哪个版本在最终链接时链接都应该没问题,如果需要向后兼容,您可以重新分发任何所需的共享库与您的二进制文件。通常库只是在*NIX系统上并排放置。
其次,您有C++库。这些库基本上保证不会以任何方式与ABI兼容,因此您必须针对同一版本的C++库重新构建最终二进制文件的每个组件。不幸的是,没有其他办法,否则您可能会遇到各种不匹配。这就是为什么许多开源库甚至不费心预先制作库二进制文件的原因:每个人都需要构建自己的副本,以确保它能正确链接到他们的最终应用程序代码。

我认为过于简化了Linux的情况。在那里,程序难道不也链接到特定的主次版本libc吗(补丁版本被省略以支持非ABI更改更新)?问题是,在Linux平台上有更多的软件是从源代码构建的。此外,适当的库下载由软件包管理器处理。 - André Caron
CRT和C++ STD库是否总是动态链接的?如果链接了"crt.so",那么路径中的那一个会被使用,还是有类似于Windows的机制,Windows DLL Loader会查看CRT版本的清单,并从Windows\WinSxS获取DLL? - Budric
尽管在*NIX中动态链接库非常流行,但并不总是动态链接。它会链接类似于libc.so.1的东西,其中附加了一个版本号,以便在运行时知道要加载哪个.so(虽然兼容补丁是允许的)。 - Mark B
@AndréCaron:实际上,程序甚至可以链接到特定的符号版本,一个很好的例子是链接到glibc时,它有很多版本化的符号。 - ninjalj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接