Download the script – https://github.com/mpreisler/mingw-bundledlls
I recently had to build an application with mingw32 on Fedora 21 and then prepare the binaries for usage on Windows without any external dependencies.
In the past I used to look at the list of dependencies using depends32.exe or similar tools on Windows and then copy all the DLLs manually. Needless to say that is very repetitive work and gets annoying quickly. Googling for existing solutions did not yield any useful results so I decided to solve this myself.
The solution I came up with is a small Python 3 script that uses objdump to recursively gather all dependencies of an executable file (WinPE EXE) or a dynamic loaded library (DLL). I published the script on GitHub – https://github.com/mpreisler/mingw-bundledlls.
The script can be run from Linux and only depends on python3 and objdump from binutils. It is very convenient to just run:
mingw32-configure && make && mingw-bundledlls --copy $EXE
After this invocation all the necessary DLLs will be right next to the EXE so you can just pack it all up and upload the release.
Practical example
I will show how I build SCAP Workbench for Windows from scratch on Fedora 21.
git clone https://github.com/OpenSCAP/scap-workbench.git cd scap-workbench mkdir build cd build mingw32-cmake ../ make -j 4
After the previous command finishes build/scap-workbench contains all the necessary resources including scap-workbench.exe. You however cannot run it on Windows without getting an error message about missing DLLs. Let us now run the script to solve that 🙂
$ mingw-bundledlls ./scap-workbench/scap-workbench.exe Found the following dependencies: /usr/i686-w64-mingw32/sys-root/mingw/bin/libstdc++-6.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libpng16-16.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/zlib1.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libcurl-4.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libxslt-1.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/QtGui4.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/iconv.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libxml2-2.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libidn-11.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libintl-8.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libopenscap-8.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libcrypto-10.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/QtNetwork4.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libexslt-0.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libssh2-1.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/QtXmlPatterns4.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libgcc_s_sjlj-1.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libpcre-1.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/QtCore4.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libssl-10.dll
After confirming that the script did not find anything crazy we can proceed to copy the dependencies next to the exe. Use –copy as an option to accomplish that.
$ mingw-bundledlls --copy ./scap-workbench/scap-workbench.exe Copying enabled, will now copy all dependencies next to the exe_file. Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libidn-11.dll' to './scap-workbench/libidn-11.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libssh2-1.dll' to './scap-workbench/libssh2-1.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll' to './scap-workbench/libwinpthread-1.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libxml2-2.dll' to './scap-workbench/libxml2-2.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/QtNetwork4.dll' to './scap-workbench/QtNetwork4.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libstdc++-6.dll' to './scap-workbench/libstdc++-6.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/zlib1.dll' to './scap-workbench/zlib1.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libopenscap-8.dll' to './scap-workbench/libopenscap-8.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libpcre-1.dll' to './scap-workbench/libpcre-1.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libgcc_s_sjlj-1.dll' to './scap-workbench/libgcc_s_sjlj-1.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/QtXmlPatterns4.dll' to './scap-workbench/QtXmlPatterns4.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libexslt-0.dll' to './scap-workbench/libexslt-0.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libcurl-4.dll' to './scap-workbench/libcurl-4.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libpng16-16.dll' to './scap-workbench/libpng16-16.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/QtCore4.dll' to './scap-workbench/QtCore4.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libssl-10.dll' to './scap-workbench/libssl-10.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libxslt-1.dll' to './scap-workbench/libxslt-1.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libcrypto-10.dll' to './scap-workbench/libcrypto-10.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/QtGui4.dll' to './scap-workbench/QtGui4.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/iconv.dll' to './scap-workbench/iconv.dll' Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libintl-8.dll' to './scap-workbench/libintl-8.dll'
The script also runs upx on all the binaries if –upx is supplied. That is useful for minimizing installed size of your application.
At this point I just zip build/scap-workbench and test it on Windows.
Runtime loaded DLLs
The script will not find any runtime loaded dependencies. Doing that would be possible by looking for LoadLibrary, LoadLibraryEx, … calls but probably not worth it. Bundling runtime loaded DLLs is a potential nightmare depending on whether relative or absolute paths are used when calling LoadLibrary. Inevitably the script would have to alter the EXE itself or any of the DLLs that is calling LoadLibrary.
Since I did not need this I decided to ignore this issue 🙂