I'm just starting to look into the mingw packages and building mingw executables with them - and in particular static building. I'm hoping someone can clarify some things for me.
For "regular" libs we seem to have:
%{mingw32_bindir}/libexample-0.dll %{mingw32_libdir}/libexample.dll.a
and for static libs:
%{mingw32_libdir}/libexample.a
so for example:
-rw-r--r--. 1 root root 7539008 Apr 11 18:00 /usr/i686-w64-mingw32/sys-root/mingw/bin/Qt5Gui.dll -rw-r--r--. 1 root root 13373318 Apr 11 18:00 /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.a -rw-r--r--. 1 root root 6699310 Apr 11 18:00 /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.dll.a
/usr/i686-w64-mingw32/sys-root/mingw/bin/Qt5Gui.dll: PE32 executable (DLL) (GUI) Intel 80386, for MS Windows, 12 sections /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.dll.a: current ar archive /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.a: current ar archive
From what I've gleaned from some web searches is that the .dll.a file is an "import" library which seems to encode a dependency on the .dll library at runtime, while the plain .a file is a more "normal" static library.
So to link a static executable it looks like I want to be using libQt5Gui.a. However, when attempting to build the x2goclient executable I'm ending up with the following link line:
i686-w64-mingw32-g++ -g -fstack-protector -static -static-libstdc++ -static-libgcc -Wl,-subsystem,windows -mthreads -o release/x2goclient.exe @object_script.x2goclient.Release -lssh.dll -lwinspool /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Svg.dll.a /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Widgets.dll.a /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.dll.a -lgdi32 -lcomdlg32 -loleaut32 -limm32 -luxtheme -ljpeg -lpng -lharfbuzz /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Network.dll.a -lcrypt32 -ldnsapi -liphlpapi /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Core.dll.a -lz -lpcre2-16 -lversion -lole32 -luuid -lwinmm -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32 -lnetapi32 -luserenv -liconv release/x2goclient_res.o -lmingw32 /usr/i686-w64-mingw32/sys-root/mingw/lib/libqt5main.a -lshell32
with lots of references to the .dll.a files. And from what I can tell, the x2goclient.exe executable does appear to have runtime dependencies on the various Qt dlls (e.g. Qt5Gui.dll, etc.).
I’m specifying a static config to qmake and QT is specified in the x2goclient.pro simply with:
QT += svg network
So I really have no idea where the .dll.a references are coming from. Some possibilities:
/usr/i686-w64-mingw32/sys-root/mingw/lib/Qt5Widgets.prl: QMAKE_PRL_TARGET = libQt5Widgets.dll.a
$ rpm -qf /usr/i686-w64-mingw32/sys-root/mingw/lib/Qt5Widgets.prl mingw32-qt5-qtbase-static-5.15.9-1.fc39.noarch
so that file is coming in as part of the -static package, but referring to the dll import file not the static file. But I'm not finding similar files for the other libraries.
I'm starting to think that the issue is that both the static and shared builds of the libraries produce .prl files - but generally the static build is installed first and then the shared build, so the .prl files that are in the Fedora packages are for the shared libraries since they have the same path.
So - is there a way for the static .prl files to be installed in a different location for for qmake find them there?
On 5/5/23 21:31, Orion Poplawski wrote:
I'm just starting to look into the mingw packages and building mingw executables with them - and in particular static building. I'm hoping someone can clarify some things for me.
For "regular" libs we seem to have:
%{mingw32_bindir}/libexample-0.dll %{mingw32_libdir}/libexample.dll.a
and for static libs:
%{mingw32_libdir}/libexample.a
so for example:
-rw-r--r--. 1 root root 7539008 Apr 11 18:00 /usr/i686-w64-mingw32/sys-root/mingw/bin/Qt5Gui.dll -rw-r--r--. 1 root root 13373318 Apr 11 18:00 /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.a -rw-r--r--. 1 root root 6699310 Apr 11 18:00 /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.dll.a
/usr/i686-w64-mingw32/sys-root/mingw/bin/Qt5Gui.dll: PE32 executable (DLL) (GUI) Intel 80386, for MS Windows, 12 sections /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.dll.a: current ar archive /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.a: current ar archive
From what I've gleaned from some web searches is that the .dll.a file is an "import" library which seems to encode a dependency on the .dll library at runtime, while the plain .a file is a more "normal" static library.
So to link a static executable it looks like I want to be using libQt5Gui.a. However, when attempting to build the x2goclient executable I'm ending up with the following link line:
i686-w64-mingw32-g++ -g -fstack-protector -static -static-libstdc++ -static-libgcc -Wl,-subsystem,windows -mthreads -o release/x2goclient.exe @object_script.x2goclient.Release -lssh.dll -lwinspool /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Svg.dll.a /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Widgets.dll.a /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.dll.a -lgdi32 -lcomdlg32 -loleaut32 -limm32 -luxtheme -ljpeg -lpng -lharfbuzz /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Network.dll.a -lcrypt32 -ldnsapi -liphlpapi /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Core.dll.a -lz -lpcre2-16 -lversion -lole32 -luuid -lwinmm -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32 -lnetapi32 -luserenv -liconv release/x2goclient_res.o -lmingw32 /usr/i686-w64-mingw32/sys-root/mingw/lib/libqt5main.a -lshell32
with lots of references to the .dll.a files. And from what I can tell, the x2goclient.exe executable does appear to have runtime dependencies on the various Qt dlls (e.g. Qt5Gui.dll, etc.).
I’m specifying a static config to qmake and QT is specified in the x2goclient.pro simply with:
QT += svg network
So I really have no idea where the .dll.a references are coming from. Some possibilities:
/usr/i686-w64-mingw32/sys-root/mingw/lib/Qt5Widgets.prl: QMAKE_PRL_TARGET = libQt5Widgets.dll.a
$ rpm -qf /usr/i686-w64-mingw32/sys-root/mingw/lib/Qt5Widgets.prl mingw32-qt5-qtbase-static-5.15.9-1.fc39.noarch
so that file is coming in as part of the -static package, but referring to the dll import file not the static file. But I'm not finding similar files for the other libraries.
I'm starting to think that the issue is that both the static and shared builds of the libraries produce .prl files - but generally the static build is installed first and then the shared build, so the .prl files that are in the Fedora packages are for the shared libraries since they have the same path.
So - is there a way for the static .prl files to be installed in a different location for for qmake find them there?
Discovered a bit more information, and it's a bit more of a mess than initially thought:
qmake appears to look for the presence of "staticlib" in the module_config line of the .pri file to see if a static library is present. e.g.:
/usr/i686-w64-mingw32/sys-root/mingw/share/qt5/mkspecs/modules/qt_lib_svg.pri:
QT.svg.module_config = v2 staticlib
Now at least for QtSvg, the only difference between the static and shared version of the pri file is the presence of "staticlib". So we might be able to get away with simply installing the static build after the shared build.
Also, it appears that the .prl files are really only necessary for static libraries, so we could just not build them for shared libraries with the "no_install_prl" CONFIG option:
MINGW_BUILDDIR_SUFFIX=_static %mingw_qmake_qt5 ../%{qt_module}.pro CONFIG+="static create_prl" MINGW_BUILDDIR_SUFFIX=_static %mingw_make_build MINGW_BUILDDIR_SUFFIX=_shared %mingw_qmake_qt5 ../%{qt_module}.pro CONFIG+="no_install_prl" MINGW_BUILDDIR_SUFFIX=_shared %mingw_make_build
Next comes the pkgconfig files. Again the only difference seems to be the addition of Libs.private:
diff -ru ./qtsvg-everywhere-src-5.15.9/build_win32_shared/lib/pkgconfig/Qt5Svgd.pc ./qtsvg-everywhere-src-5.15.9/build_win32_static/lib/pkgconfig/Qt5Svgd.pc --- ./qtsvg-everywhere-src-5.15.9/build_win32_shared/lib/pkgconfig/Qt5Svgd.pc 2023-05-05 21:51:48.559526488 -0600 +++ ./qtsvg-everywhere-src-5.15.9/build_win32_static/lib/pkgconfig/Qt5Svgd.pc 2023-05-05 21:50:58.634080123 -0600 @@ -8,6 +8,7 @@ Description: Qt Svg module Version: 5.15.9 Libs: -lQt5Svg +Libs.private: /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Widgets.dll.a /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.dll.a -lgdi32 -lcomdlg32 -loleaut32 -limm32 -luxtheme -ljpeg -lpng -lharfbuzz /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Core.dll.a -lz -lpcre2-16 -lversion -lole32 -luuid -lwinmm -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32 -lnetapi32 -luserenv -liconv -lz Cflags: -DQT_SVG_LIB -I${includedir}/QtSvg -I${includedir} Requires: Qt5Core Qt5Gui Qt5Widgets
which should be okay. Although again we are presented with the pkgconfig files using .dll.a when they should be the .a file.
More complicated are the cmake files - they appear to be very different for the shared and static versions and so I think will need to live in different locations. Although I don't think cmake files like to be moved from their install location so this will have to be handled differently.
Finally though the show stopper from my testing is that with staticlib present in the .pri module_config line, it seems that qmake will insist on using the static library. So we seem to be back to needing a separate location for the static .pri and perhaps other files.
Has anyone else struggled with this and come up with better solutions?
It looks like perhaps the mingw-qt5-qtbase package contains some patches for dealing with static libraries. Is something similar needed for qtsvg?
The mingw packaging guidelines don't seem to mention any of this issues - but I support most of them are qmake specific.
On 5/5/23 22:30, Orion Poplawski wrote:
On 5/5/23 21:31, Orion Poplawski wrote:
I'm just starting to look into the mingw packages and building mingw executables with them - and in particular static building. I'm hoping someone can clarify some things for me.
For "regular" libs we seem to have:
%{mingw32_bindir}/libexample-0.dll %{mingw32_libdir}/libexample.dll.a
and for static libs:
%{mingw32_libdir}/libexample.a
so for example:
-rw-r--r--. 1 root root 7539008 Apr 11 18:00 /usr/i686-w64-mingw32/sys-root/mingw/bin/Qt5Gui.dll -rw-r--r--. 1 root root 13373318 Apr 11 18:00 /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.a -rw-r--r--. 1 root root 6699310 Apr 11 18:00 /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.dll.a
/usr/i686-w64-mingw32/sys-root/mingw/bin/Qt5Gui.dll: PE32 executable (DLL) (GUI) Intel 80386, for MS Windows, 12 sections /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.dll.a: current ar archive /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.a: current ar archive
From what I've gleaned from some web searches is that the .dll.a file is an "import" library which seems to encode a dependency on the .dll library at runtime, while the plain .a file is a more "normal" static library.
So to link a static executable it looks like I want to be using libQt5Gui.a. However, when attempting to build the x2goclient executable I'm ending up with the following link line:
i686-w64-mingw32-g++ -g -fstack-protector -static -static-libstdc++ -static-libgcc -Wl,-subsystem,windows -mthreads -o release/x2goclient.exe @object_script.x2goclient.Release -lssh.dll -lwinspool /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Svg.dll.a /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Widgets.dll.a /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.dll.a -lgdi32 -lcomdlg32 -loleaut32 -limm32 -luxtheme -ljpeg -lpng -lharfbuzz /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Network.dll.a -lcrypt32 -ldnsapi -liphlpapi /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Core.dll.a -lz -lpcre2-16 -lversion -lole32 -luuid -lwinmm -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32 -lnetapi32 -luserenv -liconv release/x2goclient_res.o -lmingw32 /usr/i686-w64-mingw32/sys-root/mingw/lib/libqt5main.a -lshell32
with lots of references to the .dll.a files. And from what I can tell, the x2goclient.exe executable does appear to have runtime dependencies on the various Qt dlls (e.g. Qt5Gui.dll, etc.).
I’m specifying a static config to qmake and QT is specified in the x2goclient.pro simply with:
QT += svg network
So I really have no idea where the .dll.a references are coming from. Some possibilities:
/usr/i686-w64-mingw32/sys-root/mingw/lib/Qt5Widgets.prl: QMAKE_PRL_TARGET = libQt5Widgets.dll.a
$ rpm -qf /usr/i686-w64-mingw32/sys-root/mingw/lib/Qt5Widgets.prl mingw32-qt5-qtbase-static-5.15.9-1.fc39.noarch
so that file is coming in as part of the -static package, but referring to the dll import file not the static file. But I'm not finding similar files for the other libraries.
I'm starting to think that the issue is that both the static and shared builds of the libraries produce .prl files - but generally the static build is installed first and then the shared build, so the .prl files that are in the Fedora packages are for the shared libraries since they have the same path.
So - is there a way for the static .prl files to be installed in a different location for for qmake find them there?
Discovered a bit more information, and it's a bit more of a mess than initially thought:
qmake appears to look for the presence of "staticlib" in the module_config line of the .pri file to see if a static library is present. e.g.:
/usr/i686-w64-mingw32/sys-root/mingw/share/qt5/mkspecs/modules/qt_lib_svg.pri:
QT.svg.module_config = v2 staticlib
Now at least for QtSvg, the only difference between the static and shared version of the pri file is the presence of "staticlib". So we might be able to get away with simply installing the static build after the shared build.
Also, it appears that the .prl files are really only necessary for static libraries, so we could just not build them for shared libraries with the "no_install_prl" CONFIG option:
MINGW_BUILDDIR_SUFFIX=_static %mingw_qmake_qt5 ../%{qt_module}.pro CONFIG+="static create_prl" MINGW_BUILDDIR_SUFFIX=_static %mingw_make_build MINGW_BUILDDIR_SUFFIX=_shared %mingw_qmake_qt5 ../%{qt_module}.pro CONFIG+="no_install_prl" MINGW_BUILDDIR_SUFFIX=_shared %mingw_make_build
Next comes the pkgconfig files. Again the only difference seems to be the addition of Libs.private:
diff -ru ./qtsvg-everywhere-src-5.15.9/build_win32_shared/lib/pkgconfig/Qt5Svgd.pc ./qtsvg-everywhere-src-5.15.9/build_win32_static/lib/pkgconfig/Qt5Svgd.pc
./qtsvg-everywhere-src-5.15.9/build_win32_shared/lib/pkgconfig/Qt5Svgd.pc 2023-05-05 21:51:48.559526488 -0600 +++ ./qtsvg-everywhere-src-5.15.9/build_win32_static/lib/pkgconfig/Qt5Svgd.pc 2023-05-05 21:50:58.634080123 -0600 @@ -8,6 +8,7 @@ Description: Qt Svg module Version: 5.15.9 Libs: -lQt5Svg +Libs.private: /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Widgets.dll.a /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.dll.a -lgdi32 -lcomdlg32 -loleaut32 -limm32 -luxtheme -ljpeg -lpng -lharfbuzz /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Core.dll.a -lz -lpcre2-16 -lversion -lole32 -luuid -lwinmm -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32 -lnetapi32 -luserenv -liconv -lz Cflags: -DQT_SVG_LIB -I${includedir}/QtSvg -I${includedir} Requires: Qt5Core Qt5Gui Qt5Widgets
which should be okay. Although again we are presented with the pkgconfig files using .dll.a when they should be the .a file.
More complicated are the cmake files - they appear to be very different for the shared and static versions and so I think will need to live in different locations. Although I don't think cmake files like to be moved from their install location so this will have to be handled differently.
Finally though the show stopper from my testing is that with staticlib present in the .pri module_config line, it seems that qmake will insist on using the static library. So we seem to be back to needing a separate location for the static .pri and perhaps other files.
Has anyone else struggled with this and come up with better solutions?
It looks like perhaps the mingw-qt5-qtbase package contains some patches for dealing with static libraries. Is something similar needed for qtsvg?
The mingw packaging guidelines don't seem to mention any of this issues
- but I support most of them are qmake specific.
So it seems that this really isn't a mingw specific issue, but a qmake specific issue and that the only way to really support this would be to have a totally separate install root for the static libraries.
Is there any interest in supporting this or is this a bridge too far?
On Fri, May 05, 2023 at 09:31:02PM -0600, Orion Poplawski wrote:
I'm just starting to look into the mingw packages and building mingw executables with them - and in particular static building. I'm hoping someone can clarify some things for me.
For "regular" libs we seem to have:
%{mingw32_bindir}/libexample-0.dll %{mingw32_libdir}/libexample.dll.a
and for static libs:
%{mingw32_libdir}/libexample.a
I see you've already concluded this is a problem in the build system, but just to clarify a few things ...
[...]
From what I've gleaned from some web searches is that the .dll.a file is an "import" library which seems to encode a dependency on the .dll library at runtime, while the plain .a file is a more "normal" static library.
Correct -- *.dll.a is part of how Windows binaries use dynamic libraries.
Apparently their link loader isn't able to just consume a *.dll directly, in the way that ELF can just use a *.so. Instead all binaries needs a stub of code to be linked into them (the *.dll.a thing) which contains calls to Win32 functions like LoadLibrary that locates and loads the dll at runtime. On Windows this stub is called an import library (or sometimes "implib") and has the extension *.lib.
https://en.wikipedia.org/wiki/Dynamic-link_library#Import_libraries
So to link a static executable it looks like I want to be using libQt5Gui.a. However, when attempting to build the x2goclient executable I'm ending up with the following link line:
i686-w64-mingw32-g++ -g -fstack-protector -static -static-libstdc++ -static-libgcc -Wl,-subsystem,windows -mthreads -o release/x2goclient.exe @object_script.x2goclient.Release -lssh.dll -lwinspool /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Svg.dll.a /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Widgets.dll.a /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Gui.dll.a -lgdi32 -lcomdlg32 -loleaut32 -limm32 -luxtheme -ljpeg -lpng -lharfbuzz /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Network.dll.a -lcrypt32 -ldnsapi -liphlpapi /usr/i686-w64-mingw32/sys-root/mingw/lib/libQt5Core.dll.a -lz -lpcre2-16 -lversion -lole32 -luuid -lwinmm -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32 -lnetapi32 -luserenv -liconv release/x2goclient_res.o -lmingw32 /usr/i686-w64-mingw32/sys-root/mingw/lib/libqt5main.a -lshell32
with lots of references to the .dll.a files. And from what I can tell, the x2goclient.exe executable does appear to have runtime dependencies on the various Qt dlls (e.g. Qt5Gui.dll, etc.).
As you concluded already, this link command looks very wrong. The use of -static with implibs shows some confusion in the build system.
FWIW zlib is a simpler package that we know works:
$ rpm -ql mingw64-zlib /usr/x86_64-w64-mingw32/sys-root/mingw/bin/zlib1.dll <- DLL /usr/x86_64-w64-mingw32/sys-root/mingw/include/zconf.h /usr/x86_64-w64-mingw32/sys-root/mingw/include/zlib.h /usr/x86_64-w64-mingw32/sys-root/mingw/lib/libz.dll.a <- implib /usr/x86_64-w64-mingw32/sys-root/mingw/lib/pkgconfig/zlib.pc
$ rpm -ql mingw64-zlib-static /usr/x86_64-w64-mingw32/sys-root/mingw/lib/libz.a <- static lib
$ cat test-inflate.c #include <zlib.h> z_stream z; int main () { inflateInit (&z); return 0; }
$ x86_64-w64-mingw32-gcc test-inflate.c -lz $ strings a.exe | fgrep '.dll' KERNEL32.dll msvcrt.dll zlib1.dll
$ x86_64-w64-mingw32-gcc test-inflate.c -lz -static $ strings a.exe | fgrep '.dll' KERNEL32.dll msvcrt.dll
(I wish we had better analysis tools for PE files!)
Rich.