如何将标准库静态链接到我的 C++ 程序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26103966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:31:29  来源:igfitidea点击:

How can i statically link standard library to my c++ program?

c++linkerstatic-librariesstatic-linking

提问by AmRCPP

I'm using Code::Blocks IDE(v13.12) with GNU GCC Compiler.

我正在使用带有 GNU GCC 编译器的 Code::Blocks IDE(v13.12)。

  1. I want to the linker to link static versions of required runtime libraries for my programs,how may i do this?
  2. I already know that my executable size will increase,Would you please tell me other downsides?
  3. What about doing this in Visual C++ Express?
  1. 我想让链接器为我的程序链接所需运行时库的静态版本,我该怎么做?
  2. 我已经知道我的可执行文件大小会增加,你能告诉我其他的缺点吗?
  3. 在 Visual C++ Express 中这样做怎么样?

回答by 5gon12eder

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.

由于还没有其他人提出答案,我会尝试一下。不幸的是,我不知道 Code::Blocks IDE,所以我的回答只是部分的。

1 How to Create a Statically Linked Executable with GCC

1 如何使用 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:

这不是特定于 IDE 的,但通常适用于 GCC(和许多其他编译器)。假设您有一个简单的“hello, world”程序main.cpp(除了标准库和运行时库之外没有外部依赖项)。您可以通过以下方式编译并静态链接它:

  1. Compile main.cppto main.o(the output file name is implicit):

    $ g++ -c -Wall main.cpp
    

    The -ctells GCC to stop after the compilation step (not run the linker). The -Wallturns 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. ;-)

  2. 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
    

    Without using the -o mainswitch, GCC would have put the final executable in the not so well-named file a.out(which once eventually stood for “assembly output”).

  1. 编译main.cppmain.o(输出文件名是隐式的):

    $ g++ -c -Wall main.cpp
    

    -c编译步骤(不运行链接器)后告诉GCC停下来。在-Wall大多数诊断消息转弯。如果新手程序员多用多一些,多关注一下,本站的很多问题就不会被问到了。;-)

  2. 链接main.o(可以列出多个目标文件)静态地拉入标准库和运行时库并将可执行文件放入文件中main

    $ g++ -o main main.o -static
    

    如果不使用-o main开关,GCC 会将最终的可执行文件放在名称不太好的文件中a.out(它曾经最终代表“程序集输出”)。

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

Any reasonable IDE should have options for specifying such compiler / linker flags.

任何合理的 IDE 都应该有用于指定此类编译器/链接器标志的选项。

2 Pros and Cons of Static Linking

2 静态链接的优缺点

Reasons forstatic 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 mightbe 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 mightbe 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_PATHcorrectly. Obviously, this is also a disadvantage since now you cannotselect 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?

  • 您有一个文件,可以将其复制到任何具有兼容架构和操作系统的机器上,并且无论安装什么版本的库,它都可以正常工作。

  • 您可以在共享库不可用的环境中执行程序。例如,将静态链接的 CGI 可执行文件放入chroot()监狱可能有助于减少 Web 服务器上的攻击面。

  • 由于不需要动态链接,程序启动可能会更快。(我确信在某些情况下,情况正好相反,尤其是在共享库已经为另一个进程加载的情况下。)

  • 由于链接器可以对函数地址进行硬编码,因此函数调用可能会更快。

  • 在安装了多个版本的公共库(例如 LAPACK)的系统上,静态链接可以帮助确保始终使用特定版本,而无需担心LD_LIBRARY_PATH正确设置。显然,这也是一个缺点,因为现在您不能在不重新编译的情况下选择库。如果您总是想要相同的版本,为什么一开始要安装多个?

Reasons againststatic 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 everyprogram 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 torsocksscript (and associated library) allows users to replace (via setting LD_PRELOADappropriately) 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 mallocand the like with specialized versions.

  • 正如您已经提到的,可执行文件的大小可能会急剧增加。这当然在很大程度上取决于您链接的库。

  • 如果多个进程同时需要共享库,操作系统可能足够聪明,只将共享库的文本部分加载到 RAM 中一次。通过静态链接,您会失去这种优势,并且系统可能会更快地耗尽内存。

  • 您的程序不再从库升级中获利。系统管理员不是简单地用(希望 ABI 兼容的)更新版本替换一个共享库,而是必须重新编译并重新安装使用它的每个程序。这是我认为最严重的缺点。

    例如考虑 OpenSSL 库。当 Heartbleed 漏洞在今年早些时候被发现并修复时,系统管理员可以安装 OpenSSL 的补丁版本并在补丁发布后的一天内重新启动所有服务以修复漏洞。也就是说,如果他们的服务针对 OpenSSL 动态链接。对于那些静态链接的软件,最后一个修复需要数周时间,而且我很确定仍然有专有的“一体机”软件在使用中,直到现在还没有修复日。

  • 您的用户无法即时替换共享库。例如,torsocks脚本(和相关的库)允许用户LD_PRELOAD用一个通过 Tor 网络路由他们的流量的库来替换(通过适当的设置)网络系统库。这甚至适用于开发人员从未想过这种可能性的程序。(这是否安全以及一个好主意是否是一个不相关的争论的主题。)另一个常见的用例是通过用malloc专门的版本替换等来调试或“强化”应用程序。

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 Alfhas 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:

正如Alf指出的(见评论),有一个特殊的 GCC 选项可以有选择地静态链接 C++ 标准库,但不静态链接整个程序。从海湾合作委员会手册

-static-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 -staticoption 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.

-static-libstdc++

当 g++ 程序用于链接 C++ 程序时,它通常会自动链接 libstdc++。如果 libstdc++ 可用作共享库,并且-static未使用该选项,则这将链接到 libstdc++ 的共享版本。这通常很好。但是,有时冻结程序使用的 libstdc++ 版本而不完全进入完全静态链接是有用的。该-static-libstdc++选项指示 g++ 驱动程序静态链接 libstdc++,而不必静态链接其他库。

回答by Juan

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)

在 Visual C++ 中,/MT 选项执行静态链接,/MD 选项执行动态链接。(见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?

我建议使用 /MD 并重新分发 C++ 运行时,它可以从 Microsoft 免费获得。一旦安装了 C++ 运行时,任何需要运行时的程序都将继续工作。您需要传递正确的选项来告诉编译器使用哪个运行时。这里有一个很好的解释,我应该用 /MD 还是 /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.

在 Linux 上,我建议重新分发 libstdc++ 而不是静态链接。如果他们的系统 libstdc++ 有效,我会让用户使用它。系统库,例如 libpthread 和 libgcc 应该只使用系统默认值。这需要在具有与您分发的所有 linux 版本兼容的符号的系统上编译程序。

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.

在 Mac OS X 上,只需通过动态链接到 libstdc++ 重新分发应用程序。使用相同操作系统版本的任何人都应该能够使用您的程序。