如何将标准库静态链接到我的 c++ 程序?
我正在使用带有 GNU GCC 编译器的 Code::Blocks IDE(v13.12).
I'm using Code::Blocks IDE(v13.12) with GNU GCC Compiler.
- 我希望链接器为我的程序链接所需运行时库的静态版本,我该怎么做?
- 我已经知道我的可执行文件大小会增加,您能告诉我其他的缺点吗?
- 在 Visual C++ Express 中执行此操作怎么样?
推荐答案
由于还没有人给出答案,我会尝试一下.不幸的是,我不知道 Code::Blocks IDE,所以我的回答只是部分的.
Since nobody else has come up with an answer yet, I will give it a try. Unfortunately, I don't know that Code::Blocks IDE so my answer will only be partial.
这不是 IDE 特定的,但通常适用于 GCC(和许多其他编译器).假设您在 main.cpp
中有一个简单的hello, world"程序(除了标准库和运行时库之外没有外部依赖项).您可以通过以下方式编译并静态链接它:
This is not IDE specific but holds for GCC (and many other compilers) in general. Assume you have a simplistic "hello, world" program in main.cpp
(no external dependencies except for the standard library and runtime library). You'd compile and statically link it via:
将
main.cpp
编译成main.o
(输出文件名是隐含的):
Compile
main.cpp
tomain.o
(the output file name is implicit):
$ g++ -c -Wall main.cpp
-c
告诉 GCC 在编译步骤之后停止(不运行链接器).-Wall
打开大多数诊断消息.如果新手程序员会更频繁地使用它并更多地关注它,那么这个网站上的许多问题都不会被问到.;-)
The -c
tells GCC to stop after the compilation step (not run the linker). The -Wall
turns on most diagnostic messages. If novice programmers would use it more often and pay more attention to it, many questions on this site would not have been asked. ;-)
链接 main.o
(可以列出多个目标文件)静态拉入标准和运行时库并将可执行文件放入文件 main
中:
Link main.o
(could list more than one object file) statically pulling in the standard and runtime library and put the executable in the file main
:
$ g++ -o main main.o -static
如果不使用 -o main
开关,GCC 会将最终的可执行文件放在名称不太好的文件 a.out
中(它曾经最终代表汇编输出").
Without using the -o main
switch, GCC would have put the final executable in the not so well-named file a.out
(which once eventually stood for "assembly output").
特别是在开始时,我强烈建议手动"做这些事情,因为这将有助于更好地理解构建工具链.
Especially at the beginning, I strongly recommend doing such things "by hand" as it will help get a better understanding of the build tool-chain.
事实上,以上两个命令可以合并为一个:
As a matter of fact, the above two commands could have been combined into just one:
$ g++ -Wall -o main main.cpp -static
任何合理的 IDE 都应该具有指定此类编译器/链接器标志的选项.
Any reasonable IDE should have options for specifying such compiler / linker flags.
静态链接的原因:
你有一个文件,可以复制到任何具有兼容架构和操作系统的机器上,无论安装什么版本的库,它都能正常工作.
You have a single file that can be copied to any machine with a compatible architecture and operating system and it will just work, no matter what version of what library is installed.
您可以在共享库不可用的环境中执行程序.例如,将静态链接的 CGI 可执行文件放入 chroot()
监狱可能有助于减少 Web 服务器上的攻击面.
You can execute the program in an environment where the shared libraries are not available. For example, putting a statically linked CGI executable into a chroot()
jail might help reduce the attack surface on a web server.
由于不需要动态链接,程序启动可能会更快.(我确信在某些情况下情况正好相反,特别是如果共享库已经为另一个进程加载了.)
Since no dynamic linking is needed, program startup might be faster. (I'm sure there are situations where the opposite is true, especially if the shared library was already loaded for another process.)
由于链接器可以对函数地址进行硬编码,因此函数调用可能会更快.
Since the linker can hard-code function addresses, function calls might be faster.
在安装了多个版本的公共库(例如 LAPACK)的系统上,静态链接可以帮助确保始终使用特定版本,而无需担心设置 LD_LIBRARY_PATH代码>正确.显然,这也是一个缺点,因为现在您无法在不重新编译的情况下再选择库.如果您总是想要相同的版本,为什么要安装多个版本?
On systems that have more than one version of a common library (LAPACK, for example) installed, static linking can help make sure that a specific version is always used without worrying about setting the LD_LIBRARY_PATH
correctly. Obviously, this is also a disadvantage since now you cannot select the library any more without recompiling. If you always wanted the same version, why would you have installed more than one in the first place?
反对静态链接的原因:
正如您已经提到的,可执行文件的大小可能会急剧增长.这当然很大程度上取决于您链接的库.
As you have already mentioned, the size of the executable might grow dramatically. This depends of course heavily on what libraries you link in.
如果多个进程同时需要该库,操作系统可能足够聪明,只需将共享库的文本部分加载到 RAM 中一次.通过静态链接,您将失去这一优势,并且系统可能会更快地耗尽内存.
The operating system might be smart enough to load the text section of a shared library into the RAM only once if several processes need the library at the same time. By linking statically, you void this advantage and the system might run short of memory more quickly.
您的程序不再从库升级中获利.系统管理员将不得不重新编译和重新安装使用它的每个程序,而不是简单地用(希望与 ABI 兼容的)新版本替换一个共享库.这是我认为最严重的缺点.
Your program no longer profits from library upgrades. Instead of simply replacing one shared library with a (hopefully ABI compatible) newer release, a system administrator will have to recompile and reinstall every program that uses it. This is the most severe drawback in my opinion.
以 OpenSSL 库为例.当今年早些时候发现并修复了 Heartbleed 漏洞时,系统管理员可以安装补丁版本的 OpenSSL,并在补丁发布后的一天内重新启动所有服务以修复漏洞.也就是说,如果他们的服务是针对 OpenSSL 动态链接的.对于那些静态链接的,可能需要数周时间才能修复最后一个,而且我很确定仍有一些专有的一体化"软件在野外,但到目前为止还没有看到修复天.
Consider for example the OpenSSL library. When the Heartbleed bug was discovered and fixed earlier this year, system administrators could install a patched version of OpenSSL and restart all services to fix the vulnerability within a day as soon as the patch was out. That is, if their services were linking dynamically against OpenSSL. For those that have been linked statically, it would have taken weeks until the last one was fixed and I'm pretty sure that there is still proprietary "all in one" software out in the wild that did not see a fix up to the present day.
您的用户无法即时替换共享库.例如,torsocks
脚本(和相关库)允许用户(通过适当地设置 LD_PRELOAD
)将网络系统库替换为通过 Tor 网络路由其流量的库.这甚至适用于开发人员从未想过这种可能性的程序.(这是否安全和一个好主意是一个不相关的争论的主题.)另一个常见的用例是通过用专用版本替换 malloc
等来调试或强化"应用程序.
Your users cannot replace a shared library on the fly. For example, the torsocks
script (and associated library) allows users to replace (via setting LD_PRELOAD
appropriately) the networking system library by one that routes their traffic through the Tor network. And this even works for programs whose developers never even thought of that possibility. (Whether this is secure and a good idea is subject of an unrelated debate.) An other common use-case is debugging or "hardening" applications by replacing malloc
and the like with specialized versions.
在我看来,除了非常特殊的情况外,静态链接的缺点都超过了优点.作为经验法则:如果可以动态链接,如果必须静态链接.
In my opinion, the disadvantages of static linking outweigh the advantages in all but very special cases. As a rule of thumb: link dynamically if you can and statically if you have to.
正如 Alf 所指出的(见评论),有一个特殊的 GCC 选项可以选择性地静态链接 C++ 标准库,但不静态链接整个程序.来自 GCC 手册:
As Alf has pointed out (see comments), there is a special GCC option to selectively link in the C++ standard library statically but not link the whole program statically. From the GCC manual:
-static-libstdc++
当 g++ 程序用于链接 C++ 程序时,它通常会自动链接到 libstdc++.如果 libstdc++ 可用作共享库,并且未使用 -static
选项,则此链接针对 libstdc++ 的共享版本.这通常没问题.但是,有时冻结程序使用的 libstdc++ 版本而不是一直到完全静态的链接很有用.-static-libstdc++
选项指示 g++ 驱动程序静态链接 libstdc++,而不必静态链接其他库.
When the g++ program is used to link a C++ program, it normally automatically links against libstdc++. If libstdc++ is available as a shared library, and the -static
option is not used, then this links against the shared version of libstdc++. That is normally fine. However, it is sometimes useful to freeze the version of libstdc++ used by the program without going all the way to a fully static link. The -static-libstdc++
option directs the g++ driver to link libstdc++ statically, without necessarily linking other libraries statically.
相关文章