我如何静态地将标准库链接到我的C++程序?
我正在使用GNU GCC编译器使用Code :: Blocks IDE(V13.12)。
- 我想让链接器链接我程序所需的运行时库的静态版本,我该怎么做?
- 我已经知道我的可执行文件大小会增加。你能告诉我其他缺点吗?
- 在Visual C ++ Express中这样做呢?
I'm using Code::Blocks IDE(v13.12) with GNU GCC Compiler.
- I want to the linker to link static versions of required runtime libraries for my programs, how may I do this?
- I already know that my executable size will increase. Would you please tell me other the downsides?
- What about doing this in Visual C++ Express?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
由于没有其他人提出答案,所以我会尝试一下。不幸的是,我不知道Code :: blocks IDE,所以我的答案只会部分。
1如何与GCC创建静态链接的可执行文件,
这不是特定于IDE,而是GCC(以及许多其他编译器)。假设您在
main.cpp
中具有简单的“ Hello,world”程序(除了标准库和运行时库外,没有外部依赖关系)。您将通过:编译
main.cpp
main.o
(输出文件名称隐含):-c
告诉GCC在编译步骤后停止(不运行链接器)。-wall
打开大多数诊断消息。如果新手程序员会更频繁地使用它并更加注意它,那么本网站上的许多问题就不会被问到。 ; - )链接
main.o
(可以列出多个对象文件)静态拉动标准和运行时库,并将可执行文件放入文件main
:不使用
-O main
交换机,GCC会将最终可执行文件放在不太命名的文件a.out
中(曾经最终代表“汇编输出”)。尤其是在一开始,我强烈建议您“手工”做这样的事情,因为它将有助于更好地了解构建工具链。
实际上,以上两个命令可以仅合并为一个:
任何合理的IDE都应具有指定此类编译器 /链接器标志的选项。
2静态链接原因的优缺点
静态链接:
您有一个可以复制到具有兼容体系结构和操作系统的机器的单个文件,无论如何都可以正常工作安装了哪个库的版本。
您可以在没有共享库的环境中执行程序。例如,将静态链接的CGI可执行器放入
chroot()
监狱可能有助于减少Web服务器上的攻击表面。由于不需要动态链接,因此程序启动可能会更快。 (我敢肯定在某些情况下,相反的情况是正确的,尤其是如果共享库已经为另一个过程加载。)
,由于链接器可以硬代码函数地址,函数呼叫 要快。
在安装了多个公共库(例如Lapack)的系统上,静态链接可以帮助确保始终使用特定版本,而不必担心设置
ld_library_path
正确地使用了特定版本。显然,这也是一个缺点,因为现在您 在不进行重新编译的情况下选择了库。如果您一直想要相同的版本,为什么首先要安装多个以上的版本原因反对静态链接:
您已经提到,可执行文件的大小可能会急剧增长。当然,这在很大程度上取决于您链接的库。
操作系统可能足够聪明,可以将共享库的文本部分加载到RAM中,仅当几个进程同时需要库时一次。通过静态链接,您可以使这个优势无效,并且系统可能更快地运行内存。
您的程序不再从图书馆升级中获利。系统管理员将不得不重新编译并重新安装每个使用它的程序。我认为这是最严重的缺点。
考虑例如OpenSSL库。当今年早些时候发现并修复了Heartbleed错误时,系统管理员可以安装修补版的OpenSSL版本,并重新启动所有服务,以在补丁后立即在一天内修复漏洞。也就是说,如果他们的服务动态地与OpenSSL联系。对于那些在静态上链接的人,直到最后一个链接才需要数周才能修复,我很确定仍然有专有的“全部”软件,而在野外则没有看到现在的修复程序
您的用户无法即时替换共享库。例如,
torsocks
脚本(和关联的库)允许用户替换(通过设置ld_preload
适当地)通过一个通过TOR网络路由其流量的网络系统库。而且,这甚至适用于开发人员甚至从未想过这种可能性的程序。 (无论这是安全的还是一个好主意,都是无关辩论的主题。)另一个常见的用例是通过更换malloc
等来调试或“硬化”应用程序。我认为,除了非常特殊的情况外,静态连接的缺点超过了优势。 您的经验法则:如果可以的话,请动态链接
。
根据 -alf“> alf 已经指出(请参阅注释),有一个特殊的GCC选项可以在C ++标准库中有选择地链接,但不会静态地链接整个程序。来自
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.
1 How to Create a Statically Linked Executable with GCC
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:Compile
main.cpp
tomain.o
(the output file name is implicit):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. ;-)Link
main.o
(could list more than one object file) statically pulling in the standard and runtime library and put the executable in the filemain
:Without using the
-o main
switch, GCC would have put the final executable in the not so well-named filea.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:
Any reasonable IDE should have options for specifying such compiler / linker flags.
2 Pros and Cons of Static Linking
Reasons for static linking:
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.
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.
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?Reasons against static linking:
As you have already mentioned, the size of the executable might grow dramatically. This depends of course heavily on what libraries you link in.
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.
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.
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.
Your users cannot replace a shared library on the fly. For example, the
torsocks
script (and associated library) allows users to replace (via settingLD_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 replacingmalloc
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.
A Addendum
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:
在Visual C ++中, /MT选项执行静态链接,并且 /MD选项执行动态链接。 (请参阅 http://msdn.microsoft.com/en-us/library/ 2kzt1wy3.aspx )
我建议使用 /MD并重新分布C ++运行时,这是从Microsoft免费获得的。一旦安装了C ++运行时,就会比任何需要运行时间的程序继续工作。您需要通过适当的选项来告诉编译器使用哪个运行时。这里有一个很好的解释,我应该用/md或/md吗? /a>
在Linux上,我建议重新分配LibstDC ++而不是静态链接。如果他们的系统libstdc ++有效,我会让用户使用它。系统库,例如libpthread和libgcc,应仅使用系统默认值。这就需要在系统上使用与您要分发的所有Linux版本兼容的符号。
在Mac OS X上,只需使用动态链接到libstdc ++重新分发应用。使用相同OS版本的任何人都应该能够使用您的程序。
In Visual C++, the /MT option does a static link and the /MD option does a dynamic link. (see http://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx)
I'd recommend using /MD and redistributing the C++ runtime, which is freely available from Microsoft. Once the C++ runtime is installed, than any program requiring the run time will continue to work. You would need to pass the proper option to tell the compiler which runtime to use. There is a good explanation here, Should I compile with /MD or /MT?
On Linux, I'd recommend redistributing libstdc++ instead of a static link. If their system libstdc++ works, I'd let the user just use that. System libraries, such as libpthread and libgcc should just use the system default. This requires compiling the program on a system with symbols compatible with all linux versions you are distributing for.
On Mac OS X, just redistribute the app with dynamic linking to libstdc++. Anyone using the same OS version should be able to use your program.
很容易,如果您正在手动调用编译器(像疯子一样),并且正在使用mingw使用flags
-static-libgcc
和-static-libstdc ++
,如果您正在使用cmake(像任何普通人一样)使用set(cmake_exe_linker_flags“ $ {cmake_exe_linker_flags} -static -libgcc -static -libstdc ++”)
。由于您要求弊端,因此(我还将包括专业人士):
优点:具有性能好处,因为库将仅加载该应用程序,并且使用DLL,库将在运行时加载。而且它显然也可以防止缺少DLL问题。
缺点:更大的可执行文件大小(显然),并且由于链接时间的增加,编译时间将会更高。另外,由于您不能仅交换DLL并将其称为一天(仅在更新单个函数而不是重命名函数或添加新功能时,更换DLL会起作用),因此更新会更困难,您将不得不重新编译此功能。
It is easy, if you are manually invoking the compiler (like a mad man) and you are using MinGW use the flags
-static-libgcc
and-static-libstdc++
, if you are using CMake (like any normal person) useset(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
.Since you asked for the cons, here (I will also include the pros):
Pros: There is a performance benefit, because the library will just be loaded with the app, and with DLLs the library will be loaded at runtime. And it also prevents missing DLL issues obviously.
Cons: Bigger executable size (obviously), and there will be higher compile times due to link times increasing. Also, updating would be harder since you can't just swap a DLL and call it a day (swapping DLLs only works when you update individual functions and not rename functions or add new functions), you will have to re-compile the thing.