使用MinGW g++编译的程序进行分发。

14

假设我使用MinGW 64(g++编译器)创建和编译了一个简单的程序。在我的电脑上运行此程序并查看进程资源管理器以查找该程序正在使用哪些DLL文件,我发现(除其他许多文件外):

libgcc_s_seh-1.dll
libstdc++6.dll
libwinpthread-1.dll

这些是我MinGW安装文件夹下唯一的文件。其他使用的DLL文件位于 C:\Windows

问题1:

MinGW DLL文件是MinGW C++运行时库吗?它们与例如msvcrXXX.dll(XXX = Microsoft运行时库版本)具有相同的作用吗?

问题2:

如果我想在另一台没有安装MinGW的计算机上运行该应用程序,只需包含上述列出的DLL文件(即将它们放置在可执行文件所在的同一文件夹中)就足以在另一台计算机上运行吗(假设另一台计算机也是64位Windows计算机)?如果是,这是否意味着我们实际上是将MinGW C++运行时与我们的可执行文件一起发布的?如果不是,为什么?


2
@BasileStarynkevitch,不,目前我只是想给朋友一个应用程序来运行。比如一个简单的井字棋游戏或类似的游戏。如果我要在github或类似的平台上发布它,那么我会按照您建议的方式发布源代码和可能的makefile。 - jensa
那么你可能需要向你的朋友解释如何安装MinGW运行时。请务必尊重MinGW的许可证。 - Basile Starynkevitch
3
您可以使用"-static-libgcc"和"-static-libstdc++"选项将语言运行时库静态链接。 - Kerrek SB
虽然我不是律师,但原帖的提问者应该咨询他的律师。 - Basile Starynkevitch
2
@BasileStarynkevitch:好吧,想知道。你不应该相信OP的律师,而OP也不应该相信你的律师。:( 回到C++... - Kerrek SB
显示剩余6条评论
5个回答

9

libstdc++6.dll是C++标准库,就像您所说的那样。

libwinpthread-1.dll用于支持C++11线程。MinGW-W64有两种可能的线程变体:一种是使用本地Windows函数(如CreateThread),但C++11类似std::thread将不可用;或者包括这个库并使用C++11类(也可以)。请注意,要切换线程模型,您需要重新安装MinGW。仅删除DLL并不使用C++11内容将无效,当前安装仍需要该DLL。

libgcc_s_seh-1.dll涉及C++异常处理。

是的,只需提供DLL文件就足以满足需求(或使用静态链接并仅提供程序文件)。


1
@deviantfan和jensa,你们能告诉我这些文件使用的是哪些许可证吗?(这与jensa的问题2有关) - Nikhil Gupta

5

如果您在进行复杂项目时不确定需要包含哪些DLL文件来分发应用程序,那么我制作了一个方便的bash脚本(适用于MSYS2 shell),可告诉您需要包含哪些DLL文件。它依赖于Dependency Walker二进制文件。

#!/usr/bin/sh

depends_bin="depends.exe"
target="./build/main.exe" # Or wherever your binary is
temp_file=$(mktemp)
output="dll_list.txt"

MSYS2_ARG_CONV_EXCL="*" `cygpath -w $depends_bin` /c /oc:`cygpath -w $temp_file` `cygpath -w $target`
cat $temp_file | cut -d , -f 2 | grep mingw32 > $output

rm $temp_file

请注意,此脚本需要稍作修改才能在常规的MSYS中使用(特别是MSYS2_ARG_CONV_EXCL和cygpath指令)。此脚本还假定您的MinGW DLL文件位于包含MinGW的路径中。
您甚至可以将此脚本用于自动部署系统的一部分,以便将涉及的DLL文件自动复制到您的构建目录中。

4
您可以添加选项-static-libgcc-static-libstdc++,以静态链接C和C++标准库,从而无需携带任何单独的副本。

你确定它在Windows上有任何意义吗?我认为在Windows上,MinGW链接到系统DLL。据我所知,它不能被配置为链接到静态的(例如MSVC中的/MT)。 - Royi
我非常确定,当传递我提到的那些命令时,您将不需要分发DLL文件。 - Dhia Hassen

2
我使用ntldd获取依赖项列表。 https://github.com/LRN/ntldd 我正在使用msys2,所以我只需使用pacman安装它。使用它然后复制所有需要的依赖项。原始答案: "最初的回答"

1
分发已编译软件面临以下几个主要挑战:
  1. 为所有目标处理器编译代码(请记住,对于编译代码,您需要为每种指令集架构单独生成下载/分发)。

  2. 确保构建是可重现的、一致的,并且可以轻松地与特定版本的代码(以及依赖关系的版本)相关联。

  3. 确保构建输出是自包含的,并包括其中的所有依赖项(以便它不依赖于仅存在于您系统上的任何其他安装)。

  4. 确保您的代码经常构建和分发,并自动分发更新,以便在出现安全问题时,您可以推出新的修补程序版本。

为了方便和扩大范围,为非专业用户提供预编译版本以供安装是很好的选择。然而,我建议首先共享源代码。

大多数这些要求都相当不容易达成,通常需要自动化构建流程,还需要自动化实例化 / 配置 VM 的过程,才能进行构建。但是,有一些开源项目可以帮助您...例如,请查看Gitian

在第3个要点方面,关键在于使用静态链接...虽然这会使您分发的二进制文件变得更大(因为其依赖项现在已经嵌入到输出中),但它也使您的二进制文件与系统上的库的版本隔离开来(避免“依赖地狱”)。

第4个要点非常棘手,但幸运的是也有一些开源工具可以帮助您,例如cloudup,它提供了一种向应用程序分发添加自动更新功能的方式。


谢谢,很好的建议。从我得到的答案中,我得出结论可能更好的方法是在他们的系统上构建/编译代码。但对于非技术用户来说,这可能不可行。关于第三点,我不会静态链接原帖中提到的DLL(由于法律原因等),也不会以任何方式分发这些DLL。我想我们只需要跟踪依赖项。如果程序仅使用标准DLL(如Win环境中的kernel32.dll、user32.dll等),那么可以认为这些DLL已经存在于目标Win计算机上。 - jensa
1
通常情况下,你会静态链接一些库(通常是任何第三方库,你不能保证它们在系统上存在或者可能存在于系统上但版本不兼容),但动态链接任何由系统提供并可以保证存在于你要分发的系统上的库。 - Michael Aaron Safyan
谢谢,这正是我所想的。听起来非常合理。 - jensa

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