From a8c019454d89468771253722224dd00802705289 Mon Sep 17 00:00:00 2001
From: Martchus <martchus@gmx.net>
Date: Sun, 18 Sep 2016 18:45:08 +0200
Subject: [PATCH 18/33] Merge shared and static library trees

Allow installation of shared and static build in the same prefix

Change-Id: I1de08df42d83d411aae519691cd3cde1fd6f3d1d
---
 configure.pri                      | 16 +++++++++++++++-
 mkspecs/features/default_post.prf  | 11 +++++++++++
 mkspecs/features/device_config.prf |  9 ++++++++-
 mkspecs/features/qt.prf            | 17 +++++++++++++++++
 mkspecs/features/spec_pre.prf      | 11 ++++++++---
 qmake/generators/makefile.cpp      | 11 +++++++----
 qtbase.pro                         | 10 ++++++++--
 7 files changed, 74 insertions(+), 11 deletions(-)

diff --git a/configure.pri b/configure.pri
index 49755f7abf..53c67f885b 100644
--- a/configure.pri
+++ b/configure.pri
@@ -659,7 +659,12 @@ defineTest(qtConfOutput_machineTuple) {
 
 defineTest(qtConfOutput_commitOptions) {
     # qdevice.pri needs to be written early, because the compile tests require it.
-    write_file($$QT_BUILD_TREE/mkspecs/qdevice.pri, $${currentConfig}.output.devicePro)|error()
+    shared|actually_a_shared_build {
+        DEVICE_PRI_SUFFIX = .pri
+    } else {
+        DEVICE_PRI_SUFFIX = .static.pri
+    }
+    write_file($$QT_BUILD_TREE/mkspecs/qdevice$$DEVICE_PRI_SUFFIX, $${currentConfig}.output.devicePro)|error()
 }
 
 # type (empty or 'host'), option name, default value
@@ -1398,3 +1403,12 @@ defineTest(createConfigStatus) {
 
 QMAKE_POST_CONFIGURE += \
     "createConfigStatus()"
+
+# merge shared and static library trees
+contains(CONFIG, static) {
+    CONFIG -= shared
+    QT_CONFIG += static jpeg gif
+    QT_CONFIG -= shared
+    # prevent smart library merge from messing cyclic dependency between freetype2 and harfbuzz
+    CONFIG += no_smart_library_merge
+}
diff --git a/mkspecs/features/default_post.prf b/mkspecs/features/default_post.prf
index 1d79f5c958..48f6e710b6 100644
--- a/mkspecs/features/default_post.prf
+++ b/mkspecs/features/default_post.prf
@@ -1,5 +1,16 @@
 # This file is loaded by qmake right after loading the actual project file.
 
+win32:contains(CONFIG, static) {
+    # Ensure defines are set correctly for static build
+    DEFINES -= QT_SHARED
+    DEFINES *= QT_STATIC QT_DESIGNER_STATIC
+    contains(QT_CONFIG, angle): DEFINES *= QT_OPENGL_ES_2_ANGLE_STATIC
+    # Ensure we link against all dependencies statically
+    QMAKE_LFLAGS += -static -static-libstdc++ -static-libgcc
+    # Prevent qmake from finding the prl file for shared libs
+    QMAKE_EXT_PRL = .static.prl
+}
+
 contains(TEMPLATE, ".*(lib|app)"):CONFIG += have_target
 
 !have_target:!force_qt: CONFIG -= qt
diff --git a/mkspecs/features/device_config.prf b/mkspecs/features/device_config.prf
index c15559e174..dd09ac749d 100644
--- a/mkspecs/features/device_config.prf
+++ b/mkspecs/features/device_config.prf
@@ -4,7 +4,14 @@
 # supposed to be influenced by -device-option then.
 host_build: return()
 
-DEVICE_PRI = $$[QT_HOST_DATA/get]/mkspecs/qdevice.pri
+shared|actually_a_shared_build {
+    DEVICE_PRI = $$[QT_HOST_DATA/get]/mkspecs/qdevice.pri
+} else {
+    DEVICE_PRI = $$[QT_HOST_DATA/get]/mkspecs/qdevice.static.pri
+    !exists($$DEVICE_PRI) {
+        DEVICE_PRI = $$[QT_HOST_DATA/get]/mkspecs/qdevice.pri
+    }
+}
 exists($$DEVICE_PRI):include($$DEVICE_PRI)
 unset(DEVICE_PRI)
 
diff --git a/mkspecs/features/qt.prf b/mkspecs/features/qt.prf
index 69d1954306..2bc7b1dedd 100644
--- a/mkspecs/features/qt.prf
+++ b/mkspecs/features/qt.prf
@@ -235,6 +235,23 @@ for(ever) {
             !isEmpty(MODULE_WINRT_CAPABILITIES_DEVICE): \
                 WINRT_MANIFEST.capabilities_device_default += $$MODULE_WINRT_CAPABILITIES_DEVICE
         }
+
+        # Ensure linking against all required static libraries as defined in mingw-w64-g++ mkspec
+        win32:contains(CONFIG, static) {
+            isEqual(MODULE_NAME, QtCore) {
+                LIBS$$var_sfx += $$QMAKE_LIBS_CORE
+            } else:isEqual(MODULE_NAME, QtGui) {
+                LIBS$$var_sfx += $$QMAKE_LIBS_GUI_STATIC
+            } else:isEqual(MODULE_NAME, QtNetwork) {
+                LIBS$$var_sfx += $$QMAKE_LIBS_NETWORK_STATIC
+            } else:isEqual(MODULE_NAME, QtDBus) {
+                LIBS$$var_sfx += $$QMAKE_LIBS_DBUS_STATIC
+            } else:isEqual(MODULE_NAME, QtWidgets) {
+                LIBS$$var_sfx += $$QMAKE_LIBS_WIDGETS_STATIC
+            } else:isEqual(MODULE_NAME, QtOpenGL) {
+                LIBS$$var_sfx += $$QMAKE_LIBS_OPENGL
+            }
+        }
     }
     !isEmpty(BAD_QT):error("Unknown module(s) in QT$$var_sfx: $$replace(BAD_QT, _private$, -private)")
 
diff --git a/mkspecs/features/spec_pre.prf b/mkspecs/features/spec_pre.prf
index 51ea3a8321..275e080ae4 100644
--- a/mkspecs/features/spec_pre.prf
+++ b/mkspecs/features/spec_pre.prf
@@ -14,9 +14,14 @@ QMAKE_EXT_H             = .h .hpp .hh .hxx
 QMAKE_EXT_H_MOC         = .cpp
 QMAKE_EXT_JS            = .js
 QMAKE_EXT_LEX           = .l
-QMAKE_EXT_LIBTOOL       = .la
-QMAKE_EXT_PKGCONFIG     = .pc
-QMAKE_EXT_PRL           = .prl
+QMAKE_EXT_PKGCONFIG = .pc
+contains(CONFIG, static) {
+    QMAKE_EXT_LIBTOOL   = .static.la
+    QMAKE_EXT_PRL       = .static.prl
+} else {
+    QMAKE_EXT_LIBTOOL   = .la
+    QMAKE_EXT_PRL       = .prl
+}
 QMAKE_EXT_UI            = .ui
 QMAKE_EXT_YACC          = .y
 
diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp
index 62a06d3560..bd8bd91438 100644
--- a/qmake/generators/makefile.cpp
+++ b/qmake/generators/makefile.cpp
@@ -3244,6 +3244,9 @@ MakefileGenerator::pkgConfigFileName(bool fixify, bool onlyPrependDestdir)
     if (project->isActiveConfig("debug")) {
         ret += "d";
     }
+    if (project->isActiveConfig("staticlib")) {
+        ret.insert(0, QStringLiteral("Static"));
+    }
     ret += Option::pkgcfg_ext;
     QString subdir = project->first("QMAKE_PKGCONFIG_DESTDIR").toQString();
     if(!subdir.isEmpty()) {
@@ -3420,11 +3423,11 @@ MakefileGenerator::writePkgConfigFile()
     t << Qt::endl;
 
     // requires
-    const QString requiresString = project->values("QMAKE_PKGCONFIG_REQUIRES").join(' ');
-    if (!requiresString.isEmpty()) {
-        t << "Requires: " << requiresString << Qt::endl;
+    t << "Requires:";
+    const auto pkgconfigRequires = project->values("QMAKE_PKGCONFIG_REQUIRES");
+    for (const auto &required : pkgconfigRequires) {
+        t << (project->isActiveConfig("staticlib") ? QStringLiteral(" Static") : QStringLiteral(" ")) << required.toQString();
     }
-
     t << Qt::endl;
 }
 
diff --git a/qtbase.pro b/qtbase.pro
index c0ce0972ef..5a2deaf31d 100644
--- a/qtbase.pro
+++ b/qtbase.pro
@@ -20,6 +20,12 @@ CLEAN_DEPS += qmake-clean
 # recursive distclean proceeds, including beyond qtbase.
 DISTCLEAN_DEPS += qmake-clean
 
+shared|actually_a_shared_build {
+    DEVICE_PRI_SUFFIX = .pri
+} else {
+    DEVICE_PRI_SUFFIX = .static.pri
+}
+
 # Files created by configure.
 # config.status (and configure.cache, which is the same for Windows)
 # are omitted for convenience of rebuilds.
@@ -27,7 +33,7 @@ QMAKE_DISTCLEAN += \
     config.summary \
     config.tests/.qmake.cache \
     mkspecs/qconfig.pri \
-    mkspecs/qdevice.pri \
+    mkspecs/qdevice$$DEVICE_PRI_SUFFIX \
     mkspecs/qmodule.pri \
     src/corelib/global/qconfig.h \
     src/corelib/global/qconfig_p.h \
@@ -78,7 +84,7 @@ prefix_build|!equals(PWD, $$OUT_PWD) {
 mkspecs.path = $$[QT_HOST_DATA]/mkspecs
 mkspecs.files = \
     $$OUT_PWD/mkspecs/qconfig.pri $$OUT_PWD/mkspecs/qmodule.pri \
-    $$OUT_PWD/mkspecs/qdevice.pri \
+    $$OUT_PWD/mkspecs/qdevice$$DEVICE_PRI_SUFFIX \
     $$files($$PWD/mkspecs/*)
 mkspecs.files -= $$PWD/mkspecs/modules $$PWD/mkspecs/modules-inst
 INSTALLS += mkspecs
-- 
2.36.1

