From b2fd16b4782f61a9b3fd6fc2d75985250b5cf7fd Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Mon, 8 Oct 2018 14:41:57 +1000 Subject: [PATCH 01/20] wasm: fix parse error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-70952 Change-Id: I8a39de1d16b5301d221be4e9e47cabd4827b71aa Reviewed-by: Morten Johan Sørvig --- src/3rdparty/wasm/qt_attribution.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/3rdparty/wasm/qt_attribution.json b/src/3rdparty/wasm/qt_attribution.json index 184e2968cd..2724008157 100644 --- a/src/3rdparty/wasm/qt_attribution.json +++ b/src/3rdparty/wasm/qt_attribution.json @@ -18,4 +18,3 @@ "LicenseFile": "LICENSE", "Copyright": "Copyright (C) 2003 Bitstream,Inc" } - From 5c94130a6708a7f7b4631645e52abd8768a48b7b Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 3 Oct 2018 12:44:50 +0200 Subject: [PATCH 02/20] doc: Document version of bundled Freetype in qt_attribution Task-number: QTBUG-70901 Change-Id: Ibc330320cf3851e9aed13a66a3552bd8b2ad34da Reviewed-by: Simon Hausmann --- src/3rdparty/freetype/qt_attribution.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/3rdparty/freetype/qt_attribution.json b/src/3rdparty/freetype/qt_attribution.json index 4be86e92b6..f46541cf2e 100644 --- a/src/3rdparty/freetype/qt_attribution.json +++ b/src/3rdparty/freetype/qt_attribution.json @@ -7,6 +7,8 @@ "Description": "FreeType is a freely available software library to render fonts.", "Homepage": "http://www.freetype.org", + "Version": "2.6.1", + "License": "Freetype Project License or GNU General Public License v2.0 only", "LicenseId": "FTL OR GPL-2.0", "LicenseFile": "LICENSE.txt", From 25830cf91298d2440e649b1f9e200a3433b8c679 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 2 Oct 2018 13:46:17 +0200 Subject: [PATCH 03/20] Fix builds without DTLS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ic7215c7aa0bf6f7b37ae34649d809f2e1e1ee95b Reviewed-by: Jesus Fernandez Reviewed-by: Mårten Nordheim Reviewed-by: Timur Pocheptsov --- examples/network/network.pro | 8 ++------ tests/auto/network/ssl/ssl.pro | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/examples/network/network.pro b/examples/network/network.pro index 93049014eb..1556e26ab1 100644 --- a/examples/network/network.pro +++ b/examples/network/network.pro @@ -29,12 +29,8 @@ qtHaveModule(widgets) { } - qtConfig(openssl) { - SUBDIRS += \ - securesocketclient \ - secureudpserver \ - secureudpclient - } + qtConfig(openssl): SUBDIRS += securesocketclient + qtConfig(dtls): SUBDIRS += secureudpserver secureudpclient qtConfig(sctp): SUBDIRS += multistreamserver multistreamclient } diff --git a/tests/auto/network/ssl/ssl.pro b/tests/auto/network/ssl/ssl.pro index a2d9159579..e89443ef4e 100644 --- a/tests/auto/network/ssl/ssl.pro +++ b/tests/auto/network/ssl/ssl.pro @@ -16,7 +16,7 @@ qtConfig(ssl) { qsslsocket_onDemandCertificates_member \ qsslsocket_onDemandCertificates_static - qtConfig(openssl) { + qtConfig(dtls) { SUBDIRS += \ qdtlscookie \ qdtls From b7c5c2e65bd00d2b6729a54ae7ba5ddd4e891a03 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 6 Sep 2018 11:20:36 +0200 Subject: [PATCH 04/20] Add NEON optimized ARGB32 unpremultiply routines Mirroring similar routines recently added for SSE4.1 Change-Id: Ibb9d10cc34655ce1dc0e97fdff4e4f6a81d47d05 Reviewed-by: Erik Verbruggen Reviewed-by: Eirik Aavitsland --- src/gui/image/qimage_conversions.cpp | 17 ++- src/gui/painting/qdrawhelper.cpp | 9 ++ src/gui/painting/qdrawhelper_neon.cpp | 159 ++++++++++++++++++++++---- 3 files changed, 158 insertions(+), 27 deletions(-) diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index e1f66dceee..964dc0d5c6 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -119,6 +119,7 @@ void qGamma_correct_back_to_linear_cs(QImage *image) *****************************************************************************/ // The drawhelper conversions from/to RGB32 are passthroughs which is not always correct for general image conversion +#if !defined(__ARM_NEON__) static void QT_FASTCALL storeRGB32FromARGB32PM(uchar *dest, const uint *src, int index, int count, const QVector *, QDitherInfo *) { @@ -126,6 +127,7 @@ static void QT_FASTCALL storeRGB32FromARGB32PM(uchar *dest, const uint *src, int for (int i = 0; i < count; ++i) d[i] = 0xff000000 | qUnpremultiply(src[i]); } +#endif static void QT_FASTCALL storeRGB32FromARGB32(uchar *dest, const uint *src, int index, int count, const QVector *, QDitherInfo *) @@ -147,6 +149,9 @@ static const uint *QT_FASTCALL fetchRGB32ToARGB32PM(uint *buffer, const uchar *s #ifdef QT_COMPILER_SUPPORTS_SSE4_1 extern void QT_FASTCALL storeRGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, const QVector *, QDitherInfo *); +#elif defined(__ARM_NEON__) +extern void QT_FASTCALL storeRGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector *, QDitherInfo *); #endif void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags) @@ -175,8 +180,12 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio if (qCpuHasFeature(SSE4_1)) store = storeRGB32FromARGB32PM_sse4; else -#endif store = storeRGB32FromARGB32PM; +#elif defined(__ARM_NEON__) + store = storeRGB32FromARGB32PM_neon; +#else + store = storeRGB32FromARGB32PM; +#endif } } if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied && @@ -261,8 +270,12 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im if (qCpuHasFeature(SSE4_1)) store = storeRGB32FromARGB32PM_sse4; else -#endif store = storeRGB32FromARGB32PM; +#elif defined(__ARM_NEON__) + store = storeRGB32FromARGB32PM_neon; +#else + store = storeRGB32FromARGB32PM; +#endif } } if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied && diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 0264059a5c..bbeb9fd9ea 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -6505,10 +6505,19 @@ static void qInitDrawhelperFunctions() const QVector *, QDitherInfo *); extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_neon(uint *buffer, const uchar *src, int index, int count, const QVector *, QDitherInfo *); + extern void QT_FASTCALL storeARGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector *, QDitherInfo *); + extern void QT_FASTCALL storeRGBA8888FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector *, QDitherInfo *); + extern void QT_FASTCALL storeRGBXFromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector *, QDitherInfo *); qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_neon; qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_neon; + qPixelLayouts[QImage::Format_ARGB32].storeFromARGB32PM = storeARGB32FromARGB32PM_neon; qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_neon; qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_neon; + qPixelLayouts[QImage::Format_RGBA8888].storeFromARGB32PM = storeRGBA8888FromARGB32PM_neon; + qPixelLayouts[QImage::Format_RGBX8888].storeFromARGB32PM = storeRGBXFromARGB32PM_neon; #endif #if defined(ENABLE_PIXMAN_DRAWHELPERS) diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index 98995f485a..629dfe2358 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -1081,15 +1081,28 @@ const uint * QT_FASTCALL qt_fetchUntransformed_888_neon(uint *buffer, const Oper } #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -template -static inline void convertARGBToARGB32PM_neon(uint *buffer, const uint *src, int count) +static inline uint32x4_t vrgba2argb(uint32x4_t srcVector) { - int i = 0; #if defined(Q_PROCESSOR_ARM_64) const uint8x16_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15}; #else const uint8x8_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7 }; #endif +#if defined(Q_PROCESSOR_ARM_64) + srcVector = vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(srcVector), rgbaMask)); +#else + // no vqtbl1q_u8, so use two vtbl1_u8 + const uint8x8_t low = vtbl1_u8(vreinterpret_u8_u32(vget_low_u32(srcVector)), rgbaMask); + const uint8x8_t high = vtbl1_u8(vreinterpret_u8_u32(vget_high_u32(srcVector)), rgbaMask); + srcVector = vcombine_u32(vreinterpret_u32_u8(low), vreinterpret_u32_u8(high)); +#endif + return srcVector; +} + +template +static inline void convertARGBToARGB32PM_neon(uint *buffer, const uint *src, int count) +{ + int i = 0; const uint8x8_t shuffleMask = { 3, 3, 3, 3, 7, 7, 7, 7}; const uint32x4_t blendMask = vdupq_n_u32(0xff000000); @@ -1105,16 +1118,8 @@ static inline void convertARGBToARGB32PM_neon(uint *buffer, const uint *src, int #endif if (alphaSum) { if (alphaSum != 255 * 4) { - if (RGBA) { -#if defined(Q_PROCESSOR_ARM_64) - srcVector = vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(srcVector), rgbaMask)); -#else - // no vqtbl1q_u8 - const uint8x8_t low = vtbl1_u8(vreinterpret_u8_u32(vget_low_u32(srcVector)), rgbaMask); - const uint8x8_t high = vtbl1_u8(vreinterpret_u8_u32(vget_high_u32(srcVector)), rgbaMask); - srcVector = vcombine_u32(vreinterpret_u32_u8(low), vreinterpret_u32_u8(high)); -#endif - } + if (RGBA) + srcVector = vrgba2argb(srcVector); const uint8x8_t s1 = vreinterpret_u8_u32(vget_low_u32(srcVector)); const uint8x8_t s2 = vreinterpret_u8_u32(vget_high_u32(srcVector)); const uint8x8_t alpha1 = vtbl1_u8(s1, shuffleMask); @@ -1128,19 +1133,10 @@ static inline void convertARGBToARGB32PM_neon(uint *buffer, const uint *src, int const uint32x4_t d = vbslq_u32(blendMask, srcVector, vreinterpretq_u32_u8(vcombine_u8(d1, d2))); vst1q_u32(buffer + i, d); } else { - if (RGBA) { -#if defined(Q_PROCESSOR_ARM_64) - srcVector = vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(srcVector), rgbaMask)); -#else - // no vqtbl1q_u8 - const uint8x8_t low = vtbl1_u8(vreinterpret_u8_u32(vget_low_u32(srcVector)), rgbaMask); - const uint8x8_t high = vtbl1_u8(vreinterpret_u8_u32(vget_high_u32(srcVector)), rgbaMask); - srcVector = vcombine_u32(vreinterpret_u32_u8(low), vreinterpret_u32_u8(high)); -#endif + if (RGBA) + vst1q_u32(buffer + i, vrgba2argb(srcVector)); + else if (buffer != src) vst1q_u32(buffer + i, srcVector); - } else if (buffer != src) { - vst1q_u32(buffer + i, srcVector); - } } } else { vst1q_u32(buffer + i, vdupq_n_u32(0)); @@ -1153,6 +1149,91 @@ static inline void convertARGBToARGB32PM_neon(uint *buffer, const uint *src, int } } +static inline float32x4_t reciprocal_mul_ps(float32x4_t a, float mul) +{ + float32x4_t ia = vrecpeq_f32(a); // estimate 1/a + ia = vmulq_f32(vrecpsq_f32(a, ia), vmulq_n_f32(ia, mul)); // estimate improvement step * mul + return ia; +} + +template +static inline void convertARGBFromARGB32PM_neon(uint *buffer, const uint *src, int count) +{ + int i = 0; + const uint32x4_t alphaMask = vdupq_n_u32(0xff000000); + + for (; i < count - 3; i += 4) { + uint32x4_t srcVector = vld1q_u32(src + i); + uint32x4_t alphaVector = vshrq_n_u32(srcVector, 24); +#if defined(Q_PROCESSOR_ARM_64) + uint32_t alphaSum = vaddvq_u32(alphaVector); +#else + // no vaddvq_u32 + uint32x2_t tmp = vpadd_u32(vget_low_u32(alphaVector), vget_high_u32(alphaVector)); + uint32_t alphaSum = vget_lane_u32(vpadd_u32(tmp, tmp), 0); +#endif + if (alphaSum) { + if (alphaSum != 255 * 4) { + if (RGBA) + srcVector = vrgba2argb(srcVector); + const float32x4_t a = vcvtq_f32_u32(alphaVector); + const float32x4_t ia = reciprocal_mul_ps(a, 255.0f); + // Convert 4x(4xU8) to 4x(4xF32) + uint16x8_t tmp1 = vmovl_u8(vget_low_u8(vreinterpretq_u8_u32(srcVector))); + uint16x8_t tmp3 = vmovl_u8(vget_high_u8(vreinterpretq_u8_u32(srcVector))); + float32x4_t src1 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(tmp1))); + float32x4_t src2 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(tmp1))); + float32x4_t src3 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(tmp3))); + float32x4_t src4 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(tmp3))); + src1 = vmulq_lane_f32(src1, vget_low_f32(ia), 0); + src2 = vmulq_lane_f32(src2, vget_low_f32(ia), 1); + src3 = vmulq_lane_f32(src3, vget_high_f32(ia), 0); + src4 = vmulq_lane_f32(src4, vget_high_f32(ia), 1); + // Convert 4x(4xF32) back to 4x(4xU8) (over a 8.1 fixed point format to get rounding) + tmp1 = vcombine_u16(vrshrn_n_u32(vcvtq_n_u32_f32(src1, 1), 1), + vrshrn_n_u32(vcvtq_n_u32_f32(src2, 1), 1)); + tmp3 = vcombine_u16(vrshrn_n_u32(vcvtq_n_u32_f32(src3, 1), 1), + vrshrn_n_u32(vcvtq_n_u32_f32(src4, 1), 1)); + uint32x4_t dstVector = vreinterpretq_u32_u8(vcombine_u8(vmovn_u16(tmp1), vmovn_u16(tmp3))); + // Overwrite any undefined results from alpha==0 with zeros: +#if defined(Q_PROCESSOR_ARM_64) + uint32x4_t srcVectorAlphaMask = vceqzq_u32(alphaVector); +#else + uint32x4_t srcVectorAlphaMask = vceqq_u32(alphaVector, vdupq_n_u32(0)); +#endif + dstVector = vbicq_u32(dstVector, srcVectorAlphaMask); + // Restore or mask alpha values: + if (RGBx) + dstVector = vorrq_u32(alphaMask, dstVector); + else + dstVector = vbslq_u32(alphaMask, srcVector, dstVector); + vst1q_u32(&buffer[i], dstVector); + } else { + // 4xAlpha==255, no change except if we are doing RGBA->ARGB: + if (RGBA) + vst1q_u32(&buffer[i], vrgba2argb(srcVector)); + else if (buffer != src) + vst1q_u32(&buffer[i], srcVector); + } + } else { + // 4xAlpha==0, always zero, except if output is RGBx: + if (RGBx) + vst1q_u32(&buffer[i], alphaMask); + else + vst1q_u32(&buffer[i], vdupq_n_u32(0)); + } + } + + SIMD_EPILOGUE(i, count, 3) { + uint v = qUnpremultiply(src[i]); + if (RGBx) + v = 0xff000000 | v; + if (RGBA) + v = ARGB2RGBA(v); + buffer[i] = v; + } +} + void QT_FASTCALL convertARGB32ToARGB32PM_neon(uint *buffer, int count, const QVector *) { convertARGBToARGB32PM_neon(buffer, buffer, count); @@ -1177,6 +1258,34 @@ const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_neon(uint *buffer, const uchar * return buffer; } +void QT_FASTCALL storeRGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector *, QDitherInfo *) +{ + uint *d = reinterpret_cast(dest) + index; + convertARGBFromARGB32PM_neon(d, src, count); +} + +void QT_FASTCALL storeARGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector *, QDitherInfo *) +{ + uint *d = reinterpret_cast(dest) + index; + convertARGBFromARGB32PM_neon(d, src, count); +} + +void QT_FASTCALL storeRGBA8888FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector *, QDitherInfo *) +{ + uint *d = reinterpret_cast(dest) + index; + convertARGBFromARGB32PM_neon(d, src, count); +} + +void QT_FASTCALL storeRGBXFromARGB32PM_neon(uchar *dest, const uint *src, int index, int count, + const QVector *, QDitherInfo *) +{ + uint *d = reinterpret_cast(dest) + index; + convertARGBFromARGB32PM_neon(d, src, count); +} + #endif // Q_BYTE_ORDER == Q_LITTLE_ENDIAN QT_END_NAMESPACE From 49f1f944bcd72586cc76622fd42c904974506f91 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Fri, 28 Sep 2018 10:51:54 +1000 Subject: [PATCH 05/20] wasm: rewrite QNetworkReplyWasmImpl to remove EM_ASM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and fix handling of incoming binary data Change-Id: I31e97505ad4ff64cf8e380df5d0d6b70c3cd60b0 Reviewed-by: Ryan Chu Reviewed-by: Edward Welbourne Reviewed-by: Morten Johan Sørvig --- configure.json | 1 + src/network/access/qnetworkreplywasmimpl.cpp | 388 +++++++++---------- src/network/access/qnetworkreplywasmimpl_p.h | 16 +- 3 files changed, 187 insertions(+), 218 deletions(-) diff --git a/configure.json b/configure.json index 85d6a8c31a..3702c24f63 100644 --- a/configure.json +++ b/configure.json @@ -730,6 +730,7 @@ "headersclean": { "label": "Check for clean headers", "autoDetect": "features.developer-build", + "condition": "!config.wasm", "output": [ "privateConfig" ] }, "framework": { diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp index 9c2ff8fb89..23ca62acd4 100644 --- a/src/network/access/qnetworkreplywasmimpl.cpp +++ b/src/network/access/qnetworkreplywasmimpl.cpp @@ -49,10 +49,135 @@ #include #include -#include +#include +#include +#include QT_BEGIN_NAMESPACE +using namespace emscripten; + +static void q_requestErrorCallback(val event) +{ + val xhr = event["target"]; + + quintptr func = xhr["data-handler"].as(); + QNetworkReplyWasmImplPrivate *reply = reinterpret_cast(func); + Q_ASSERT(reply); + + int statusCode = xhr["status"].as(); + + QString reasonStr = QString::fromStdString(xhr["statusText"].as()); + + reply->setReplyAttributes(func, statusCode, reasonStr); + + if (statusCode >= 400 && !reasonStr.isEmpty()) + reply->emitReplyError(reply->statusCodeFromHttp(statusCode, reply->request.url()), reasonStr); +} + +static void q_progressCallback(val event) +{ + val xhr = event["target"]; + + QNetworkReplyWasmImplPrivate *reply = + reinterpret_cast(xhr["data-handler"].as()); + Q_ASSERT(reply); + + if (xhr["lengthComputable"].as() && xhr["status"].as() < 400) + reply->emitDataReadProgress(xhr["loaded"].as(), xhr["total"].as()); + +} + +static void q_loadCallback(val event) +{ + val xhr = event["target"]; + + QNetworkReplyWasmImplPrivate *reply = + reinterpret_cast(xhr["data-handler"].as()); + Q_ASSERT(reply); + + int status = xhr["status"].as(); + if (status >= 300) { + q_requestErrorCallback(event); + return; + } + QString statusText = QString::fromStdString(xhr["statusText"].as()); + if (status == 200 || status == 203) { + QString responseString; + const std::string responseType = xhr["responseType"].as(); + if (responseType.length() == 0 || responseType == "document" || responseType == "text") { + responseString = QString::fromStdWString(xhr["responseText"].as()); + } else if (responseType == "json") { + responseString = + QString::fromStdWString(val::global("JSON").call("stringify", xhr["response"])); + } else if (responseType == "arraybuffer" || responseType == "blob") { + // handle this data in the FileReader, triggered by the call to readAsArrayBuffer + val reader = val::global("FileReader").new_(); + reader.set("onload", val::module_property("QNetworkReplyWasmImplPrivate_readBinary")); + reader.set("data-handler", xhr["data-handler"]); + reader.call("readAsArrayBuffer", xhr["response"]); + } + + int readyState = xhr["readyState"].as(); + + if (readyState == 4) { // done + reply->setReplyAttributes(xhr["data-handler"].as(), status, statusText); + if (!responseString.isEmpty()) + reply->dataReceived(responseString.toUtf8(), responseString.size()); + } + } + if (status >= 400 && !statusText.isEmpty()) + reply->emitReplyError(reply->statusCodeFromHttp(status, reply->request.url()), statusText); +} + +static void q_responseHeadersCallback(val event) +{ + val xhr = event["target"]; + + if (xhr["readyState"].as() == 2) { // HEADERS_RECEIVED + std::string responseHeaders = xhr.call("getAllResponseHeaders"); + if (!responseHeaders.empty()) { + QNetworkReplyWasmImplPrivate *reply = + reinterpret_cast(xhr["data-handler"].as()); + Q_ASSERT(reply); + + reply->headersReceived(QString::fromStdString(responseHeaders)); + } + } +} + +static void q_readBinary(val event) +{ + val fileReader = event["target"]; + + QNetworkReplyWasmImplPrivate *reply = + reinterpret_cast(fileReader["data-handler"].as()); + Q_ASSERT(reply); + + // Set up source typed array + val result = fileReader["result"]; // ArrayBuffer + val Uint8Array = val::global("Uint8Array"); + val sourceTypedArray = Uint8Array.new_(result); + + // Allocate and set up destination typed array + const quintptr size = result["byteLength"].as(); + QByteArray buffer(size, Qt::Uninitialized); + + val destinationTypedArray = Uint8Array.new_(val::module_property("HEAPU8")["buffer"], + reinterpret_cast(buffer.data()), size); + destinationTypedArray.call("set", sourceTypedArray); + reply->dataReceived(buffer, buffer.size()); +} + + +EMSCRIPTEN_BINDINGS(network_module) { + function("QNetworkReplyWasmImplPrivate_requestErrorCallback", q_requestErrorCallback); + function("QNetworkReplyWasmImplPrivate_progressCallback", q_progressCallback); + function("QNetworkReplyWasmImplPrivate_loadCallback", q_loadCallback); + function("QNetworkReplyWasmImplPrivate_responseHeadersCallback", q_responseHeadersCallback); + function("QNetworkReplyWasmImplPrivate_readBinary", q_readBinary); +} + QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate() : QNetworkReplyPrivate() , managerPrivate(0) @@ -172,226 +297,80 @@ void QNetworkReplyWasmImplPrivate::setup(QNetworkAccessManager::Operation op, co doSendRequest(); } -void QNetworkReplyWasmImplPrivate::onLoadCallback(void *data, int statusCode, int statusReason, int readyState, int buffer, int bufferSize) +void QNetworkReplyWasmImplPrivate::setReplyAttributes(quintptr data, int statusCode, const QString &statusReason) { QNetworkReplyWasmImplPrivate *handler = reinterpret_cast(data); - - const QString reasonStr = QString::fromUtf8(reinterpret_cast(statusReason)); - - switch (readyState) { - case 0://unsent - break; - case 1://opened - break; - case 2://headers received - break; - case 3://loading - break; - case 4: {//done - handler->q_func()->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode); - if (!reasonStr.isEmpty()) - handler->q_func()->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonStr); - - if (statusCode >= 400) { - if (!reasonStr.isEmpty()) - handler->emitReplyError(handler->statusCodeFromHttp(statusCode, handler->request.url()), reasonStr); - } else { - handler->dataReceived(reinterpret_cast(buffer), bufferSize); - } - } - break; - }; - } - -void QNetworkReplyWasmImplPrivate::onProgressCallback(void* data, int bytesWritten, int total, uint timestamp) -{ - Q_UNUSED(timestamp); - - QNetworkReplyWasmImplPrivate *handler = reinterpret_cast(data); - handler->emitDataReadProgress(bytesWritten, total); -} - -void QNetworkReplyWasmImplPrivate::onRequestErrorCallback(void* data, int statusCode, int statusReason) -{ - QString reasonStr = QString::fromUtf8(reinterpret_cast(statusReason)); - - QNetworkReplyWasmImplPrivate *handler = reinterpret_cast(data); + Q_ASSERT(handler); handler->q_func()->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode); - if (!reasonStr.isEmpty()) - handler->q_func()->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonStr); - - if (statusCode >= 400) { - if (!reasonStr.isEmpty()) - handler->emitReplyError(handler->statusCodeFromHttp(statusCode, handler->request.url()), reasonStr); - } -} - -void QNetworkReplyWasmImplPrivate::onResponseHeadersCallback(void* data, int headers) -{ - QNetworkReplyWasmImplPrivate *handler = reinterpret_cast(data); - handler->headersReceived(reinterpret_cast(headers)); + if (!statusReason.isEmpty()) + handler->q_func()->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, statusReason); } void QNetworkReplyWasmImplPrivate::doSendRequest() { Q_Q(QNetworkReplyWasmImpl); totalDownloadSize = 0; - jsRequest(QString::fromUtf8(q->methodName()), // GET POST - request.url().toString(), - (void *)&onLoadCallback, - (void *)&onProgressCallback, - (void *)&onRequestErrorCallback, - (void *)&onResponseHeadersCallback); -} -/* const QString &body, const QList > &headers ,*/ -void QNetworkReplyWasmImplPrivate::jsRequest(const QString &verb, const QString &url, - void *loadCallback, void *progressCallback, - void *errorCallback, void *onResponseHeadersCallback) -{ + val xhr = val::global("XMLHttpRequest").new_(); + std::string verb = q->methodName().toStdString(); + + QUrl url; QString extraDataString; + if (request.url().hasQuery()) { //strip query from url + extraDataString = request.url().query(QUrl::FullyEncoded); + QString urlStr = request.url().toString(); + url.setUrl(urlStr.left(urlStr.indexOf("?"))); + } else { + url = request.url(); + } + xhr.call("open", verb, url.toString().toStdString()); + + xhr.set("onerror", val::module_property("QNetworkReplyWasmImplPrivate_requestErrorCallback")); + xhr.set("onload", val::module_property("QNetworkReplyWasmImplPrivate_loadCallback")); + xhr.set("onprogress", val::module_property("QNetworkReplyWasmImplPrivate_progressCallback")); + xhr.set("onreadystatechange", val::module_property("QNetworkReplyWasmImplPrivate_responseHeadersCallback")); + + xhr.set("data-handler", val(quintptr(reinterpret_cast(this)))); + + QByteArray contentType = request.rawHeader("Content-Type"); + + // handle extra data + val dataToSend = val::null(); QByteArray extraData; - if (outgoingData) + + if (outgoingData) // data from post request extraData = outgoingData->readAll(); - if (extraData.size() > 0) - extraDataString.fromUtf8(extraData); - - if (extraDataString.size() >= 0 && verb == QStringLiteral("POST") && extraDataString.startsWith(QStringLiteral("?"))) - extraDataString.remove(QStringLiteral("?")); - - // Probably a good idea to save any shared pointers as members in C++ - // so the objects they point to survive as long as you need them - - QStringList headersList; - for (auto header : request.rawHeaderList()) - headersList << QString::fromUtf8(header + ":" + request.rawHeader(header)); - - EM_ASM_ARGS({ - var verb = Pointer_stringify($0); - var url = Pointer_stringify($1); - var onLoadCallbackPointer = $2; - var onProgressCallbackPointer = $3; - var onErrorCallbackPointer = $4; - var onHeadersCallback = $5; - var handler = $8; - - var dataToSend; - var extraRequestData = Pointer_stringify($6); // request parameters - var headersData = Pointer_stringify($7); - - var xhr; - xhr = new XMLHttpRequest(); - xhr.responseType = 'arraybuffer'; - - xhr.open(verb, url, true); //async - - function handleError(xhrStatusCode, xhrStatusText) { - var errorPtr = allocate(intArrayFromString(xhrStatusText), 'i8', ALLOC_NORMAL); - Runtime.dynCall('viii', onErrorCallbackPointer, [handler, xhrStatusCode, errorPtr]); - _free(errorPtr); + if (contentType.contains("text") || + contentType.contains("json") || + contentType.contains("form")) { + if (extraData.size() > 0) + extraDataString.fromUtf8(extraData); + } + if (contentType.contains("json")) { + if (!extraDataString.isEmpty()) { + xhr.set("responseType", val("json")); + dataToSend = val(extraDataString.toStdString()); } + } + if (contentType.contains("form")) { //construct form data + if (!extraDataString.isEmpty()) { + val formData = val::global("FormData").new_(); + QStringList formList = extraDataString.split('&'); - if (headersData) { - var headers = headersData.split("&"); - for (var i = 0; i < headers.length; i++) { - var header = headers[i].split(":")[0]; - var value = headers[i].split(":")[1]; - - if (verb === 'POST' && value.toLowerCase().includes('json')) { - if (extraRequestData) { - xhr.responseType = 'json'; - dataToSend = extraRequestData; - } - } - if (verb === 'POST' && value.toLowerCase().includes('form')) { - if (extraRequestData) { - var formData = new FormData(); - var extra = extraRequestData.split("&"); - for (var i = 0; i < extra.length; i++) { - formData.append(extra[i].split("=")[0],extra[i].split("=")[1]); - } - dataToSend = formData; - } - } - xhr.setRequestHeader(header, value); + for (auto formEntry : formList) { + formData.call("append", formEntry.split('=')[0].toStdString(), formEntry.split('=')[1].toStdString()); } + dataToSend = formData; } - - xhr.onprogress = function(e) { - switch (xhr.status) { - case 200: - case 206: - case 300: - case 301: - case 302: { - var date = xhr.getResponseHeader('Last-Modified'); - date = ((date != null) ? new Date(date).getTime() / 1000 : 0); - Runtime.dynCall('viiii', onProgressCallbackPointer, [handler, e.loaded, e.total, date]); - } - break; - } - }; - - xhr.onreadystatechange = function() { - if (this.readyState == this.HEADERS_RECEIVED) { - var responseStr = this.getAllResponseHeaders(); - if (responseStr.length > 0) { - var ptr = allocate(intArrayFromString(responseStr), 'i8', ALLOC_NORMAL); - Runtime.dynCall('vii', onHeadersCallback, [handler, ptr]); - _free(ptr); - } - } - }; - - xhr.onload = function(e) { - if (xhr.status >= 300) { //error - handleError(xhr.status, xhr.statusText); - } else { - if (this.status == 200 || this.status == 203) { - var datalength; - var byteArray = 0; - var buffer; - if (this.responseType.length === 0 || this.responseType === 'document') { - byteArray = new Uint8Array(this.responseText); - } else if (this.responseType === 'json') { - var jsonResponse = JSON.stringify(this.response); - buffer = allocate(intArrayFromString(jsonResponse), 'i8', ALLOC_NORMAL); - datalength = jsonResponse.length; - } else if (this.responseType === 'arraybuffer') { - byteArray = new Uint8Array(xhr.response); - } - if (byteArray != 0 ) { - datalength = byteArray.length; - buffer = _malloc(datalength); - HEAPU8.set(byteArray, buffer); - } - var reasonPtr = allocate(intArrayFromString(this.statusText), 'i8', ALLOC_NORMAL); - Runtime.dynCall('viiiiii', onLoadCallbackPointer, [handler, this.status, reasonPtr, this.readyState, buffer, datalength]); - _free(buffer); - _free(reasonPtr); - } - } - }; - - xhr.onerror = function(e) { - handleError(xhr.status, xhr.statusText); - }; - //TODO other operations, handle user/pass, handle binary data, data streaming - xhr.send(dataToSend); - - }, verb.toLatin1().data(), - url.toLatin1().data(), - loadCallback, - progressCallback, - errorCallback, - onResponseHeadersCallback, - extraDataString.size() > 0 ? extraDataString.toLatin1().data() : extraData.data(), - headersList.join(QStringLiteral("&")).toLatin1().data(), - this - ); + } + // set request headers + for (auto header : request.rawHeaderList()) { + xhr.call("setRequestHeader", header.toStdString(), request.rawHeader(header).toStdString()); + } + xhr.call("send", dataToSend); } void QNetworkReplyWasmImplPrivate::emitReplyError(QNetworkReply::NetworkError errorCode, const QString &errorString) @@ -414,10 +393,10 @@ void QNetworkReplyWasmImplPrivate::emitDataReadProgress(qint64 bytesReceived, qi percentFinished = (bytesReceived / bytesTotal) * 100; - emit q->downloadProgress(bytesReceived, totalDownloadSize); + emit q->downloadProgress(bytesReceived, bytesTotal); } -void QNetworkReplyWasmImplPrivate::dataReceived(char *buffer, int bufferSize) +void QNetworkReplyWasmImplPrivate::dataReceived(const QByteArray &buffer, int bufferSize) { Q_Q(QNetworkReplyWasmImpl); @@ -481,11 +460,10 @@ static int parseHeaderName(const QByteArray &headerName) } -void QNetworkReplyWasmImplPrivate::headersReceived(char *buffer) +void QNetworkReplyWasmImplPrivate::headersReceived(const QString &bufferString) { Q_Q(QNetworkReplyWasmImpl); - QString bufferString = QString::fromUtf8(buffer); if (!bufferString.isEmpty()) { QStringList headers = bufferString.split(QString::fromUtf8("\r\n"), QString::SkipEmptyParts); diff --git a/src/network/access/qnetworkreplywasmimpl_p.h b/src/network/access/qnetworkreplywasmimpl_p.h index a707390503..69c90de41a 100644 --- a/src/network/access/qnetworkreplywasmimpl_p.h +++ b/src/network/access/qnetworkreplywasmimpl_p.h @@ -95,7 +95,6 @@ public: private: QByteArray methodName() const; - }; class QNetworkReplyWasmImplPrivate: public QNetworkReplyPrivate @@ -106,19 +105,12 @@ public: QNetworkAccessManagerPrivate *managerPrivate; void doSendRequest(); - - void jsRequest(const QString &verb, const QString &url, void *, void *, void *, void *); - - static void onLoadCallback(void *data, int statusCode, int statusReason, int readyState, int textBuffer, int size); - static void onProgressCallback(void *data, int done, int bytesTotal, uint timestamp); - static void onRequestErrorCallback(void *data, int statusCode, int statusReason); - static void onStateChangedCallback(int status); - static void onResponseHeadersCallback(void *data, int headers); + static void setReplyAttributes(quintptr data, int statusCode, const QString &statusReason); void emitReplyError(QNetworkReply::NetworkError errorCode, const QString &); void emitDataReadProgress(qint64 done, qint64 total); - void dataReceived(char *buffer, int bufferSize); - void headersReceived(char *buffer); + void dataReceived(const QByteArray &buffer, int bufferSize); + void headersReceived(const QString &bufferString); void setup(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData); @@ -148,6 +140,4 @@ public: QT_END_NAMESPACE -//Q_DECLARE_METATYPE(QNetworkRequest::KnownHeaders) - #endif // QNETWORKREPLYWASMIMPL_H From 9436e3c315420c7ebfb36628e6bf388c780bf0ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Tue, 9 Oct 2018 13:38:53 +0300 Subject: [PATCH 06/20] configure: Treat win32-clang-g++ the same as win32-g++ This fixes configure with win32-clang-g++ as the native compiler. Change-Id: Iced43d70b9a0aa413d1f5f6034b42b976cb7c39e Reviewed-by: Oswald Buddenhagen --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 2830a1b189..ef7bad1bfc 100755 --- a/configure +++ b/configure @@ -771,7 +771,7 @@ setBootstrapVariable() echo "RM_RF = rm -rf" >> "$mkfile" case `basename "$PLATFORM"` in - win32-g++*) + win32-*g++*) cat "$in_mkfile.win32" >> "$mkfile" ;; *) From f864a62ccd639c2f9b255fdf9927973b4a678e7f Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 2 Oct 2018 13:06:04 +0200 Subject: [PATCH 07/20] Add missing null checks after detach A few places we didn't check if detach() succeeded including in reinterpretAsFormat(), where it can be undone. Task-number: QTBUG-70785 Change-Id: Ibcc8e26e2961f6288eb7a045ae1cb28e59213a49 Reviewed-by: Eirik Aavitsland --- src/gui/image/qimage.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 8a4c6b7fda..636cacfb9c 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -1454,7 +1454,8 @@ void QImage::setDevicePixelRatio(qreal scaleFactor) return; detach(); - d->devicePixelRatio = scaleFactor; + if (d) + d->devicePixelRatio = scaleFactor; } /*! @@ -2240,8 +2241,15 @@ bool QImage::reinterpretAsFormat(Format format) return true; if (qt_depthForFormat(format) != qt_depthForFormat(d->format)) return false; - if (!isDetached()) // Detach only if shared, not for read-only data. + if (!isDetached()) { // Detach only if shared, not for read-only data. + QImageData *oldD = d; detach(); + // In case detach() ran out of memory + if (!d) { + d = oldD; + return false; + } + } d->format = format; return true; @@ -3288,6 +3296,8 @@ void QImage::mirrored_inplace(bool horizontal, bool vertical) return; detach(); + if (!d) + return; if (!d->own_data) *this = copy(); @@ -3440,6 +3450,8 @@ void QImage::rgbSwapped_inplace() return; detach(); + if (!d) + return; if (!d->own_data) *this = copy(); From 02f7caaa7deb7637923870dd7ba31eac2f230a5d Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Wed, 10 Oct 2018 14:29:38 +0300 Subject: [PATCH 08/20] QPixmap: use rvalue more Change-Id: Ifb8c014abf6e02dc782fab2d653e4edfc4972125 Reviewed-by: Allan Sandfeld Jensen --- src/gui/image/qpixmap_win.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gui/image/qpixmap_win.cpp b/src/gui/image/qpixmap_win.cpp index a9e472f8c4..b8d13ac092 100644 --- a/src/gui/image/qpixmap_win.cpp +++ b/src/gui/image/qpixmap_win.cpp @@ -449,8 +449,7 @@ Q_GUI_EXPORT QImage qt_imageFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0 Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0) { - const QImage image = imageFromWinHBITMAP_GetDiBits(bitmap, /* forceQuads */ true, hbitmapFormat); - return QPixmap::fromImage(image); + return QPixmap::fromImage(imageFromWinHBITMAP_GetDiBits(bitmap, /* forceQuads */ true, hbitmapFormat)); } Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &p) @@ -567,7 +566,7 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon) SelectObject(hdc, oldhdc); //restore state DeleteObject(winBitmap); DeleteDC(hdc); - return QPixmap::fromImage(image); + return QPixmap::fromImage(std::move(image)); } QT_END_NAMESPACE From 466d65cd5b62caa1359b8e64e7e369a35390ac2d Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Sun, 19 Aug 2018 17:13:28 +0200 Subject: [PATCH 09/20] xcb: remove runtime check for xcb_poll_for_queued_event xcb_poll_for_queued_event() was introduced in libxcb 1.8. The minimal required libxcb version was bumped up to 1.9 in 1f5d791708d5d256a76872f254251dac66e82cdb. Before this version bump we needed the runtime check to support older versions of libxcb. Updated connections in the event reader to use the new signal and slot syntax. Removed threadedEventHandling() method because now it is always 'true'. Change-Id: I0bce61fd478a871d35e676239ee5280c4f40be8a Reviewed-by: Thiago Macieira --- src/plugins/platforms/xcb/qxcbconnection.cpp | 55 ++----------------- src/plugins/platforms/xcb/qxcbconnection.h | 5 -- src/plugins/platforms/xcb/qxcbintegration.cpp | 3 +- 3 files changed, 7 insertions(+), 56 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 6dda6487c8..4e24c970b4 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -90,25 +90,6 @@ #include #endif -#if defined(Q_CC_GNU) && defined(Q_OF_ELF) -static xcb_generic_event_t *local_xcb_poll_for_queued_event(xcb_connection_t *c) - __attribute__((weakref("xcb_poll_for_queued_event"))); - -static inline void checkXcbPollForQueuedEvent() -{ } -#else -#include -typedef xcb_generic_event_t * (*XcbPollForQueuedEventFunctionPointer)(xcb_connection_t *c); -static XcbPollForQueuedEventFunctionPointer local_xcb_poll_for_queued_event; - -static inline void checkXcbPollForQueuedEvent() -{ -#ifdef RTLD_DEFAULT - local_xcb_poll_for_queued_event = (XcbPollForQueuedEventFunctionPointer)dlsym(RTLD_DEFAULT, "xcb_poll_for_queued_event"); -#endif -} -#endif - QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaXInput, "qt.qpa.input") @@ -1365,39 +1346,19 @@ bool QXcbConnection::peekEventQueue(PeekerCallback peeker, void *peekerData, QXcbEventReader::QXcbEventReader(QXcbConnection *connection) : m_connection(connection) { - checkXcbPollForQueuedEvent(); } void QXcbEventReader::start() { - if (local_xcb_poll_for_queued_event) { - connect(this, SIGNAL(eventPending()), m_connection, SLOT(processXcbEvents()), Qt::QueuedConnection); - connect(this, SIGNAL(finished()), m_connection, SLOT(processXcbEvents())); - QThread::start(); - } else { - // Must be done after we have an event-dispatcher. By posting a method invocation - // we are sure that by the time the method is called we have an event-dispatcher. - QMetaObject::invokeMethod(this, "registerForEvents", Qt::QueuedConnection); - } -} - -void QXcbEventReader::registerForEvents() -{ - QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(m_connection->xcb_connection()), QSocketNotifier::Read, this); - connect(notifier, SIGNAL(activated(int)), m_connection, SLOT(processXcbEvents())); - - QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher; - connect(dispatcher, SIGNAL(aboutToBlock()), m_connection, SLOT(processXcbEvents())); - connect(dispatcher, SIGNAL(awake()), m_connection, SLOT(processXcbEvents())); + connect(this, &QXcbEventReader::eventPending, m_connection, &QXcbConnection::processXcbEvents, Qt::QueuedConnection); + connect(this, &QXcbEventReader::finished, m_connection, &QXcbConnection::processXcbEvents); + QThread::start(); } void QXcbEventReader::registerEventDispatcher(QAbstractEventDispatcher *dispatcher) { - // flush the xcb connection before the EventDispatcher is going to block - // In the non-threaded case processXcbEvents is called before going to block, - // which flushes the connection. - if (local_xcb_poll_for_queued_event) - connect(dispatcher, SIGNAL(aboutToBlock()), m_connection, SLOT(flush())); + // Flush the xcb connection before the event dispatcher is going to block. + connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, m_connection, &QXcbConnection::flush); } void QXcbEventReader::run() @@ -1406,7 +1367,7 @@ void QXcbEventReader::run() while (m_connection && (event = xcb_wait_for_event(m_connection->xcb_connection()))) { m_mutex.lock(); addEvent(event); - while (m_connection && (event = local_xcb_poll_for_queued_event(m_connection->xcb_connection()))) + while (m_connection && (event = xcb_poll_for_queued_event(m_connection->xcb_connection()))) addEvent(event); m_mutex.unlock(); emit eventPending(); @@ -1430,10 +1391,6 @@ void QXcbEventReader::addEvent(xcb_generic_event_t *event) QXcbEventArray *QXcbEventReader::lock() { m_mutex.lock(); - if (!local_xcb_poll_for_queued_event) { - while (xcb_generic_event_t *event = xcb_poll_for_event(m_connection->xcb_connection())) - m_events << event; - } return &m_events; } diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 1e28ef8fac..db45031cf4 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -326,9 +326,6 @@ public: signals: void eventPending(); -private slots: - void registerForEvents(); - private: void addEvent(xcb_generic_event_t *event); @@ -493,8 +490,6 @@ public: bool hasShmFd() const { return has_shm_fd; } bool hasXSync() const { return has_sync_extension; } - bool threadedEventHandling() const { return m_reader->isRunning(); } - xcb_timestamp_t getTimestamp(); xcb_window_t getSelectionOwner(xcb_atom_t atom) const; xcb_window_t getQtSelectionOwner(); diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 9fc1189181..db8dc09025 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -308,8 +308,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const { const auto *connection = qAsConst(m_connections).first(); if (const auto *integration = connection->glIntegration()) - return cap != ThreadedOpenGL - || (connection->threadedEventHandling() && integration->supportsThreadedOpenGL()); + return cap != ThreadedOpenGL || integration->supportsThreadedOpenGL(); return false; } From 8315acfb16ebc0c8788255965f73eb9d3557f027 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Tue, 4 Sep 2018 10:30:53 +0200 Subject: [PATCH 10/20] Revert "glib dispatcher: ensure all window system events are flushed" This reverts commit 341bfcd1eaa9116c143e3b7d3219ef04c7b8a0cb. As it turns out there might be use cases where we want to have proper windowing system event integration with glib dispatcher via g_source_attach(). For example with gtk_dialog_run, where GTK blocks in a recursive main loop. We want to continue dispatcing our windowing system events during this nested event loop. Not having a proper glib integration can result in rendering issues, e.g. when resizing parent window via mouse while GTK-based dialog is shown. Can be seen on examples/widgets/richtext/textedit/ -> Format (from menu) -> "Color..." The issue from 341bfcd1eaa actually should be fixed inside XCB platform plugin, by improving integration with event dispatcher. That is handled in follow-up patches. Change-Id: Icabc6d841a554aefbdd460765a3165d22e65f651 Reviewed-by: Thiago Macieira Reviewed-by: Allan Sandfeld Jensen --- .../qeventdispatcher_glib.cpp | 56 ++++++++++++++++++- .../qeventdispatcher_glib_p.h | 3 + 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp b/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp index 06f0aa6747..dc4785071f 100644 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp +++ b/src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp @@ -48,26 +48,78 @@ QT_BEGIN_NAMESPACE +struct GUserEventSource +{ + GSource source; + QPAEventDispatcherGlib *q; +}; + +static gboolean userEventSourcePrepare(GSource *source, gint *timeout) +{ + Q_UNUSED(timeout) + GUserEventSource *userEventSource = reinterpret_cast(source); + QPAEventDispatcherGlib *dispatcher = userEventSource->q; + if (dispatcher->m_flags & QEventLoop::ExcludeUserInputEvents) + return QWindowSystemInterface::nonUserInputEventsQueued(); + else + return QWindowSystemInterface::windowSystemEventsQueued() > 0; +} + +static gboolean userEventSourceCheck(GSource *source) +{ + return userEventSourcePrepare(source, 0); +} + +static gboolean userEventSourceDispatch(GSource *source, GSourceFunc, gpointer) +{ + GUserEventSource *userEventSource = reinterpret_cast(source); + QPAEventDispatcherGlib *dispatcher = userEventSource->q; + QWindowSystemInterface::sendWindowSystemEvents(dispatcher->m_flags); + return true; +} + +static GSourceFuncs userEventSourceFuncs = { + userEventSourcePrepare, + userEventSourceCheck, + userEventSourceDispatch, + NULL, + NULL, + NULL +}; + QPAEventDispatcherGlibPrivate::QPAEventDispatcherGlibPrivate(GMainContext *context) : QEventDispatcherGlibPrivate(context) { + Q_Q(QPAEventDispatcherGlib); + userEventSource = reinterpret_cast(g_source_new(&userEventSourceFuncs, + sizeof(GUserEventSource))); + userEventSource->q = q; + g_source_set_can_recurse(&userEventSource->source, true); + g_source_attach(&userEventSource->source, mainContext); } + QPAEventDispatcherGlib::QPAEventDispatcherGlib(QObject *parent) : QEventDispatcherGlib(*new QPAEventDispatcherGlibPrivate, parent) , m_flags(QEventLoop::AllEvents) { + Q_D(QPAEventDispatcherGlib); + d->userEventSource->q = this; } QPAEventDispatcherGlib::~QPAEventDispatcherGlib() { + Q_D(QPAEventDispatcherGlib); + + g_source_destroy(&d->userEventSource->source); + g_source_unref(&d->userEventSource->source); + d->userEventSource = 0; } bool QPAEventDispatcherGlib::processEvents(QEventLoop::ProcessEventsFlags flags) { m_flags = flags; - const bool didSendEvents = QEventDispatcherGlib::processEvents(m_flags); - return QWindowSystemInterface::sendWindowSystemEvents(m_flags) || didSendEvents; + return QEventDispatcherGlib::processEvents(m_flags); } QT_END_NAMESPACE diff --git a/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h b/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h index 5930dc68e7..085a1c52f3 100644 --- a/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h +++ b/src/platformsupport/eventdispatchers/qeventdispatcher_glib_p.h @@ -71,11 +71,14 @@ public: QEventLoop::ProcessEventsFlags m_flags; }; +struct GUserEventSource; + class QPAEventDispatcherGlibPrivate : public QEventDispatcherGlibPrivate { Q_DECLARE_PUBLIC(QPAEventDispatcherGlib) public: QPAEventDispatcherGlibPrivate(GMainContext *context = 0); + GUserEventSource *userEventSource; }; From 8d2deea49c506330a1077eedd1ec104beced65e7 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 18 Sep 2018 10:42:12 +0200 Subject: [PATCH 11/20] Report compiler and version in configure overview It is not always easy to spot the compiler version in the build or configure log, so report it explicitly to make our lives easier when trying to figure out why a specific build might have failed. Change-Id: I1c84199aad4a98a30b0b4c4fbf2554008dc3ba2d Reviewed-by: Oswald Buddenhagen --- configure.pri | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/configure.pri b/configure.pri index 3747f96f3d..64ed6b9ed8 100644 --- a/configure.pri +++ b/configure.pri @@ -1221,13 +1221,43 @@ defineReplace(qtConfReportArch) { return("$$arch, CPU features: $$subarch") } +defineReplace(qtConfReportCompiler) { + clang_cl: { + return("clang-cl $${QMAKE_CLANG_MAJOR_VERSION}.$${QMAKE_CLANG_MINOR_VERSION}.$${QMAKE_CLANG_PATCH_VERSION}") + } else: clang { + !isEmpty(QMAKE_APPLE_CLANG_MAJOR_VERSION) { + return("clang (Apple) $${QMAKE_APPLE_CLANG_MAJOR_VERSION}.$${QMAKE_APPLE_CLANG_MINOR_VERSION}.$${QMAKE_APPLE_CLANG_PATCH_VERSION}") + } else { + return("clang $${QMAKE_CLANG_MAJOR_VERSION}.$${QMAKE_CLANG_MINOR_VERSION}.$${QMAKE_CLANG_PATCH_VERSION}") + } + } else: intel_icc { + return("intel_icc $$QMAKE_ICC_VER") + } else: intel_icl { + return("intel_icl $$QMAKE_ICC_VER") + } else: rim_qcc { + return("rim_qcc $${QMAKE_GCC_MAJOR_VERSION}.$${QMAKE_GCC_MINOR_VERSION}.$${QMAKE_GCC_PATCH_VERSION}") + } else: gcc { + return("gcc $${QMAKE_GCC_MAJOR_VERSION}.$${QMAKE_GCC_MINOR_VERSION}.$${QMAKE_GCC_PATCH_VERSION}") + } else: msvc { + return("msvc $$QMAKE_MSC_FULL_VER") + } else: ghs { + return("ghs $$QMAKE_GHS_VERSION") + } else { + return("unknown ($$QMAKE_COMPILER)") + } +} + + defineTest(qtConfReport_buildTypeAndConfig) { !$$qtConfEvaluate("features.cross_compile") { qtConfAddReport("Build type: $$[QMAKE_SPEC] ($$qtConfReportArch(architecture))") + qtConfAddReport("Compiler: $$qtConfReportCompiler()") } else { qtConfAddReport("Building on: $$[QMAKE_SPEC] ($$qtConfReportArch(host_architecture))") qtConfAddReport("Building for: $$[QMAKE_XSPEC] ($$qtConfReportArch(architecture))") + qtConfAddReport("Target compiler: $$qtConfReportCompiler()") } + qtConfAddReport() qtConfAddReport("Configuration: $$eval($${currentConfig}.output.privatePro.append.CONFIG) $$eval($${currentConfig}.output.publicPro.append.QT_CONFIG)") qtConfAddReport() From d92c25b1b4ac0423a824715a08b2db2def4b6e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Tue, 9 Oct 2018 13:51:46 +0300 Subject: [PATCH 12/20] qmake: Fix building with lld with mingw makefiles lld for coff/mingw doesn't support linker scripts, which qmake used for passing larger numbers of input file names to the linker. Instead of using a fullblown linker script for this, just use a plain response file, which both lld and binutils ld support. Change-Id: I3aace7902fa6ca861a0a9fe67feaa236e7ea417b Reviewed-by: Oswald Buddenhagen --- qmake/generators/win32/mingw_make.cpp | 32 ++++++++++++++------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp index 13412e971a..99788394ea 100644 --- a/qmake/generators/win32/mingw_make.cpp +++ b/qmake/generators/win32/mingw_make.cpp @@ -131,22 +131,25 @@ QString MingwMakefileGenerator::installRoot() const return QStringLiteral("$(INSTALL_ROOT:@msyshack@%=%)"); } -void createLdObjectScriptFile(const QString &fileName, const ProStringList &objList) +void createLdResponseFile(const QString &fileName, const ProStringList &objList) { QString filePath = Option::output_dir + QDir::separator() + fileName; QFile file(filePath); if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { QTextStream t(&file); - t << "INPUT(\n"; for (ProStringList::ConstIterator it = objList.constBegin(); it != objList.constEnd(); ++it) { QString path = (*it).toQString(); - // ### quoting? - if (QDir::isRelativePath(path)) - t << "./" << path << endl; - else - t << path << endl; + // In response files, whitespace and special characters are + // escaped with a backslash; backslashes themselves can either + // be escaped into double backslashes, or, as this is a list of + // path names, converted to forward slashes. + path.replace(QLatin1Char('\\'), QLatin1String("/")) + .replace(QLatin1Char(' '), QLatin1String("\\ ")) + .replace(QLatin1Char('\t'), QLatin1String("\\\t")) + .replace(QLatin1Char('"'), QLatin1String("\\\"")) + .replace(QLatin1Char('\''), QLatin1String("\\'")); + t << path << endl; } - t << ");\n"; t.flush(); file.close(); } @@ -307,14 +310,13 @@ void MingwMakefileGenerator::writeObjectsPart(QTextStream &t) createArObjectScriptFile(ar_script_file, var("DEST_TARGET"), project->values("OBJECTS")); objectsLinkLine = ar_cmd + " -M < " + escapeFilePath(ar_script_file); } else { - QString ld_script_file = var("QMAKE_LINK_OBJECT_SCRIPT") + "." + var("TARGET"); - if (!var("BUILD_NAME").isEmpty()) { - ld_script_file += "." + var("BUILD_NAME"); - } + QString ld_response_file = var("QMAKE_LINK_OBJECT_SCRIPT") + "." + var("TARGET"); + if (!var("BUILD_NAME").isEmpty()) + ld_response_file += "." + var("BUILD_NAME"); if (!var("MAKEFILE").isEmpty()) - ld_script_file += "." + var("MAKEFILE"); - createLdObjectScriptFile(ld_script_file, project->values("OBJECTS")); - objectsLinkLine = escapeFilePath(ld_script_file); + ld_response_file += "." + var("MAKEFILE"); + createLdResponseFile(ld_response_file, project->values("OBJECTS")); + objectsLinkLine = "@" + escapeFilePath(ld_response_file); } Win32MakefileGenerator::writeObjectsPart(t); } From 9098ef697ad85cb0c7c589d6794b57bd0775dc64 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 9 Oct 2018 10:12:46 +0200 Subject: [PATCH 13/20] windows: Disable shader disk cache for all Intel GPUs Follow up to dff9bb2f9b981e263d8d3d5b1ef67054297e731c Task-number: QTBUG-64697 Change-Id: I73a114dd3c75f3ed1272fa73dad378ecfdc0db09 Reviewed-by: Andy Shaw --- src/plugins/platforms/windows/openglblacklists/default.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/platforms/windows/openglblacklists/default.json b/src/plugins/platforms/windows/openglblacklists/default.json index b618d8567a..3cfa7e3856 100644 --- a/src/plugins/platforms/windows/openglblacklists/default.json +++ b/src/plugins/platforms/windows/openglblacklists/default.json @@ -144,9 +144,8 @@ }, { "id": 12, - "description": "Intel HD Graphics 620 crash in conjunction with shader caches (QTBUG-64697)", + "description": "Intel HD Graphics crash in conjunction with shader caches (QTBUG-64697) - disable for all Intel GPUs", "vendor_id": "0x8086", - "device_id": [ "0x5916" ], "os": { "type": "win" }, From 4d51e099b369a29f844a905193b8b6cb69b3404c Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Wed, 10 Oct 2018 18:42:16 +0200 Subject: [PATCH 14/20] WinRT QPA: Fix crash in QWinRTBackingStore::flush() QWinRTBackingStore::flush() was not considering the possibility that the supplied region may fall partially outside the bounds of the paint device. This resulted in possible accesses to invalid memory addresses, causing a crash. This bug was exposed by an update in ANGLE that was causing a crash when running tst_QTableView::bigMode with a small screen size. With this fix the function will use the intersection of the supplied region with the paint device bounds. Change-Id: I2f0f0f7f5510688bfa1459320a0c146df6be65d1 Reviewed-by: Miguel Costa --- src/plugins/platforms/winrt/qwinrtbackingstore.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp index b3bf52f09b..c23d48b2dd 100644 --- a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp +++ b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp @@ -118,11 +118,14 @@ void QWinRTBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo if (d->size.isEmpty()) return; + const QRect bounds = region.boundingRect() & d->paintDevice.rect(); + if (bounds.isEmpty()) + return; + const bool ok = d->context->makeCurrent(window); if (!ok) qWarning("unable to flush"); - const QRect bounds = region.boundingRect(); glBindTexture(GL_TEXTURE_2D, d->fbo->texture()); // TODO: when ANGLE GLES3 support is finished, use the glPixelStorei functions to minimize upload glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.y(), d->size.width(), bounds.height(), From d30de0900080b278df87945e7b231421d5b467af Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 8 Oct 2018 17:07:59 +0200 Subject: [PATCH 15/20] qmake: remove support for static archive splitting this was introduced in 2002 supposedly for qnx4, but doesn't appear to have actually been used ever. remove it, as it's in the way now. Change-Id: I54dcabb61e1d3609a1e7a9fa4ff4b25509cfdb7a Reviewed-by: Liang Qi Reviewed-by: BogDan Vatra Reviewed-by: Simon Hausmann --- qmake/generators/unix/unixmake.cpp | 24 ----------- qmake/generators/unix/unixmake2.cpp | 64 +++++++---------------------- 2 files changed, 14 insertions(+), 74 deletions(-) diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index 4fe1a54501..fdc911211a 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -300,35 +300,11 @@ UnixMakefileGenerator::init() } init2(); - project->values("QMAKE_INTERNAL_PRL_LIBS") << "QMAKE_LIBS"; ProString target = project->first("TARGET"); int slsh = target.lastIndexOf(Option::dir_sep); if (slsh != -1) target.chopFront(slsh + 1); project->values("LIB_TARGET").prepend(target); - if(!project->isEmpty("QMAKE_MAX_FILES_PER_AR")) { - bool ok; - int max_files = project->first("QMAKE_MAX_FILES_PER_AR").toInt(&ok); - ProStringList ar_sublibs, objs = project->values("OBJECTS"); - if(ok && max_files > 5 && max_files < (int)objs.count()) { - QString lib; - for(int i = 0, obj_cnt = 0, lib_cnt = 0; i != objs.size(); ++i) { - if((++obj_cnt) >= max_files) { - if(lib_cnt) { - lib.sprintf("lib%s-tmp%d.a", - project->first("QMAKE_ORIG_TARGET").toLatin1().constData(), lib_cnt); - ar_sublibs << lib; - obj_cnt = 0; - } - lib_cnt++; - } - } - } - if(!ar_sublibs.isEmpty()) { - project->values("QMAKE_AR_SUBLIBS") = ar_sublibs; - project->values("QMAKE_INTERNAL_PRL_LIBS") << "QMAKE_AR_SUBLIBS"; - } - } } QStringList diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index ab946fa439..88bbb49516 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -690,56 +690,20 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) QString destdir_r = project->first("DESTDIR").toQString(); QString destdir_d = escapeDependencyPath(destdir_r); QString destdir = escapeFilePath(destdir_r); - allDeps = ' ' + destdir_d + depVar("TARGET") - + varGlue("QMAKE_AR_SUBLIBS", ' ' + destdir_d, ' ' + destdir_d, ""); - t << "staticlib: " << destdir_d << "$(TARGET)\n\n"; - if(project->isEmpty("QMAKE_AR_SUBLIBS")) { - t << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS") - << " $(OBJECTS) $(OBJCOMP) " << depVar("POST_TARGETDEPS") << "\n\t"; - if(!destdir.isEmpty()) - t << mkdir_p_asstring(destdir, false) << "\n\t"; - if (!project->isEmpty("QMAKE_PRE_LINK")) - t << var("QMAKE_PRE_LINK") << "\n\t"; - t << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t" - << var("QMAKE_AR_CMD") << "\n"; - if(!project->isEmpty("QMAKE_POST_LINK")) - t << "\t" << var("QMAKE_POST_LINK") << "\n"; - if(!project->isEmpty("QMAKE_RANLIB")) - t << "\t$(RANLIB) " << destdir << "$(TARGET)\n"; - } else { - int max_files = project->first("QMAKE_MAX_FILES_PER_AR").toInt(); - ProStringList objs = project->values("OBJECTS") + project->values("OBJCOMP"), - libs = project->values("QMAKE_AR_SUBLIBS"); - libs.prepend("$(TARGET)"); - for (ProStringList::Iterator libit = libs.begin(), objit = objs.begin(); - libit != libs.end(); ++libit) { - ProStringList build; - for(int cnt = 0; cnt < max_files && objit != objs.end(); ++objit, cnt++) - build << (*objit); - QString ar; - ProString lib = destdir + escapeFilePath(*libit); - if((*libit) == "$(TARGET)") { - t << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS") - << ' ' << depVar("POST_TARGETDEPS") << valList(escapeDependencyPaths(build)) << "\n\t"; - ar = project->first("QMAKE_AR_CMD").toQString(); - ar.replace(QLatin1String("$(OBJECTS)"), escapeFilePaths(build).join(' ')); - } else { - t << destdir_d << escapeDependencyPath(*libit) << ": " - << valList(escapeDependencyPaths(build)) << "\n\t"; - ar = "$(AR) " + lib + ' ' + escapeFilePaths(build).join(' '); - } - if(!destdir.isEmpty()) - t << mkdir_p_asstring(destdir, false) << "\n\t"; - if (!project->isEmpty("QMAKE_PRE_LINK")) - t << var("QMAKE_PRE_LINK") << "\n\t"; - t << "-$(DEL_FILE) " << lib << "\n\t" - << ar << "\n"; - if(!project->isEmpty("QMAKE_POST_LINK")) - t << "\t" << var("QMAKE_POST_LINK") << "\n"; - if(!project->isEmpty("QMAKE_RANLIB")) - t << "\t$(RANLIB) " << lib << "\n"; - } - } + allDeps = ' ' + destdir_d + depVar("TARGET"); + t << "staticlib: " << destdir_d << "$(TARGET)\n\n" + << destdir_d << depVar("TARGET") << ": " << depVar("PRE_TARGETDEPS") + << " $(OBJECTS) $(OBJCOMP) " << depVar("POST_TARGETDEPS") << "\n\t"; + if (!destdir.isEmpty()) + t << mkdir_p_asstring(destdir, false) << "\n\t"; + if (!project->isEmpty("QMAKE_PRE_LINK")) + t << var("QMAKE_PRE_LINK") << "\n\t"; + t << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t" + << var("QMAKE_AR_CMD") << "\n"; + if (!project->isEmpty("QMAKE_POST_LINK")) + t << "\t" << var("QMAKE_POST_LINK") << "\n"; + if (!project->isEmpty("QMAKE_RANLIB")) + t << "\t$(RANLIB) " << destdir << "$(TARGET)\n"; t << endl << endl; } From 2a3695b7e07a40e413f045e2dcc4f3c36ca15287 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 8 Oct 2018 17:11:25 +0200 Subject: [PATCH 16/20] qmake: nuke QMAKE_INTERNAL_PRL_LIBS it's unused now, and just complicates matters. its interaction with LIBS_PRIVATE & co. has always been a bit shaky. google produces no public hits outside qt itself, so let's assume it really remained internal. Change-Id: I6606bbabd44f1b76d84e97219e155e38d6f1b3a6 Reviewed-by: Liang Qi Reviewed-by: BogDan Vatra Reviewed-by: Simon Hausmann --- qmake/generators/makefile.cpp | 10 ++-------- qmake/generators/unix/unixmake2.cpp | 5 +---- qmake/generators/win32/msvc_vcproj.cpp | 2 -- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 7c359071bf..f2a1f79d3d 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -1012,10 +1012,7 @@ MakefileGenerator::writePrlFile(QTextStream &t) t << "QMAKE_PRL_VERSION = " << project->first("VERSION") << endl; if(project->isActiveConfig("staticlib") || project->isActiveConfig("explicitlib")) { ProStringList libs; - if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) - libs = project->values("QMAKE_INTERNAL_PRL_LIBS"); - else - libs << "QMAKE_LIBS"; //obvious one + libs << "QMAKE_LIBS"; if(project->isActiveConfig("staticlib")) libs << "QMAKE_LIBS_PRIVATE"; t << "QMAKE_PRL_LIBS ="; @@ -3348,10 +3345,7 @@ MakefileGenerator::writePkgConfigFile() if (project->isActiveConfig("staticlib")) { ProStringList libs; - if (!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) - libs = project->values("QMAKE_INTERNAL_PRL_LIBS"); - else - libs << "QMAKE_LIBS"; //obvious one + libs << "QMAKE_LIBS"; // FIXME: this should not be conditional on staticlib libs << "QMAKE_LIBS_PRIVATE"; libs << "QMAKE_LFLAGS_THREAD"; //not sure about this one, but what about things like -pthread? t << "Libs.private:"; diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index 88bbb49516..78e9173f11 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -1479,10 +1479,7 @@ UnixMakefileGenerator::writeLibtoolFile() t << "# Libraries that this one depends upon.\n"; ProStringList libs; - if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) - libs = project->values("QMAKE_INTERNAL_PRL_LIBS"); - else - libs << "QMAKE_LIBS"; //obvious one + libs << "QMAKE_LIBS"; t << "dependency_libs='"; for (ProStringList::ConstIterator it = libs.begin(); it != libs.end(); ++it) t << fixLibFlags((*it).toKey()).join(' ') << ' '; diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 73f0f35d1b..c984736c78 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -458,8 +458,6 @@ ProStringList VcprojGenerator::collectDependencies(QMakeProject *proj, QHash Date: Mon, 8 Oct 2018 18:24:14 +0200 Subject: [PATCH 17/20] qmake: make sure QMAKE_LIBS{,_PRIVATE} comes after LIBS{,_PRIVATE} the early merging of LIBS* into QMAKE_LIBS* meant that we could not interleave them properly. defer the merging until the points of use. Task-number: QTBUG-70779 Started-by: BogDan Vatra Change-Id: I890f98016c3721396a1f0f6f149a9e2b37d56d8e Reviewed-by: Liang Qi --- qmake/doc/src/qmake-manual.qdoc | 12 +++++++----- qmake/generators/mac/pbuilder_pbx.cpp | 5 ++++- qmake/generators/makefile.cpp | 9 ++++++--- qmake/generators/unix/unixmake.cpp | 7 +++---- qmake/generators/unix/unixmake2.cpp | 6 ++++-- qmake/generators/win32/mingw_make.cpp | 4 +++- qmake/generators/win32/msvc_nmake.cpp | 2 +- qmake/generators/win32/msvc_vcproj.cpp | 11 +++++++---- qmake/generators/win32/winmakefile.cpp | 11 +++++++---- 9 files changed, 42 insertions(+), 25 deletions(-) diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 409062cf49..3595bb0b4e 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -907,9 +907,9 @@ Platform-specific variables follow the naming pattern of the variables which they extend or modify, but include the name of the relevant - platform in their name. For example, \c QMAKE_LIBS can be used to specify a list - of libraries that a project needs to link against, and \c QMAKE_LIBS_X11 can be - used to extend or override this list. + platform in their name. For example, a makespec may use \c QMAKE_LIBS + to specify a list of libraries that each project needs to link against, + and \c QMAKE_LIBS_X11 would be used to extend this list. \target CONFIG \section1 CONFIG @@ -2098,10 +2098,12 @@ \section1 QMAKE_LIBS - Specifies all project libraries. The value of this variable - is typically handled by qmake or + Specifies additional libraries each project needs to link against. + The value of this variable is typically handled by qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + To specify libraries in a project file, use \l LIBS instead. + \section1 QMAKE_LIBS_EGL Specifies all EGL libraries when building Qt with OpenGL/ES diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp index 72daa97fe4..5407ed6c69 100644 --- a/qmake/generators/mac/pbuilder_pbx.cpp +++ b/qmake/generators/mac/pbuilder_pbx.cpp @@ -829,7 +829,8 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) if(!project->isActiveConfig("staticlib")) { //DUMP LIBRARIES ProStringList &libdirs = project->values("QMAKE_PBX_LIBPATHS"), &frameworkdirs = project->values("QMAKE_FRAMEWORKPATH"); - static const char * const libs[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; + static const char * const libs[] = { "LIBS", "LIBS_PRIVATE", + "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; for (int i = 0; libs[i]; i++) { tmp = project->values(libs[i]); for(int x = 0; x < tmp.count();) { @@ -1695,6 +1696,8 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) t << "\t\t\t\t" << writeSettings("OTHER_LDFLAGS", fixListForOutput("SUBLIBS") + fixListForOutput("QMAKE_LFLAGS") + + fixListForOutput(fixLibFlags("LIBS")) + + fixListForOutput(fixLibFlags("LIBS_PRIVATE")) + fixListForOutput(fixLibFlags("QMAKE_LIBS")) + fixListForOutput(fixLibFlags("QMAKE_LIBS_PRIVATE")), SettingsAsList, 6) << ";\n"; diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index f2a1f79d3d..e41e391cad 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -1012,9 +1012,10 @@ MakefileGenerator::writePrlFile(QTextStream &t) t << "QMAKE_PRL_VERSION = " << project->first("VERSION") << endl; if(project->isActiveConfig("staticlib") || project->isActiveConfig("explicitlib")) { ProStringList libs; - libs << "QMAKE_LIBS"; - if(project->isActiveConfig("staticlib")) - libs << "QMAKE_LIBS_PRIVATE"; + if (!project->isActiveConfig("staticlib")) + libs << "LIBS" << "QMAKE_LIBS"; + else + libs << "LIBS" << "LIBS_PRIVATE" << "QMAKE_LIBS" << "QMAKE_LIBS_PRIVATE"; t << "QMAKE_PRL_LIBS ="; for (ProStringList::Iterator it = libs.begin(); it != libs.end(); ++it) t << qv(project->values((*it).toKey())); @@ -3345,6 +3346,8 @@ MakefileGenerator::writePkgConfigFile() if (project->isActiveConfig("staticlib")) { ProStringList libs; + libs << "LIBS"; // FIXME: this should not be conditional on staticlib + libs << "LIBS_PRIVATE"; libs << "QMAKE_LIBS"; // FIXME: this should not be conditional on staticlib libs << "QMAKE_LIBS_PRIVATE"; libs << "QMAKE_LFLAGS_THREAD"; //not sure about this one, but what about things like -pthread? diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index fdc911211a..3e96b2cf61 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -80,8 +80,6 @@ UnixMakefileGenerator::init() } project->values("QMAKE_ORIG_DESTDIR") = project->values("DESTDIR"); - project->values("QMAKE_LIBS") += project->values("LIBS"); - project->values("QMAKE_LIBS_PRIVATE") += project->values("LIBS_PRIVATE"); if((!project->isEmpty("QMAKE_LIB_FLAG") && !project->isActiveConfig("staticlib")) || (project->isActiveConfig("qt") && project->isActiveConfig("plugin"))) { if(configs.indexOf("dll") == -1) configs.append("dll"); @@ -118,7 +116,7 @@ UnixMakefileGenerator::init() } ldadd += project->values("QMAKE_FRAMEWORKPATH_FLAGS"); } - ProStringList &qmklibs = project->values("QMAKE_LIBS"); + ProStringList &qmklibs = project->values("LIBS"); qmklibs = ldadd + qmklibs; if (!project->isEmpty("QMAKE_RPATHDIR") && !project->isEmpty("QMAKE_LFLAGS_RPATH")) { const ProStringList &rpathdirs = project->values("QMAKE_RPATHDIR"); @@ -396,7 +394,8 @@ UnixMakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags) libdirs.append(QMakeLocalFileName(dlib.toQString())); frameworkdirs.append(QMakeLocalFileName("/System/Library/Frameworks")); frameworkdirs.append(QMakeLocalFileName("/Library/Frameworks")); - static const char * const lflags[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; + static const char * const lflags[] = { "LIBS", "LIBS_PRIVATE", + "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; for (int i = 0; lflags[i]; i++) { ProStringList &l = project->values(lflags[i]); for (ProStringList::Iterator it = l.begin(); it != l.end(); ) { diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index 78e9173f11..976751b02c 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -213,7 +213,9 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) if(!project->isActiveConfig("staticlib")) { t << "LINK = " << var("QMAKE_LINK") << endl; t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl; - t << "LIBS = $(SUBLIBS) " << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' + t << "LIBS = $(SUBLIBS) " << fixLibFlags("LIBS").join(' ') << ' ' + << fixLibFlags("LIBS_PRIVATE").join(' ') << ' ' + << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' << fixLibFlags("QMAKE_LIBS_PRIVATE").join(' ') << endl; } @@ -1479,7 +1481,7 @@ UnixMakefileGenerator::writeLibtoolFile() t << "# Libraries that this one depends upon.\n"; ProStringList libs; - libs << "QMAKE_LIBS"; + libs << "LIBS" << "QMAKE_LIBS"; t << "dependency_libs='"; for (ProStringList::ConstIterator it = libs.begin(); it != libs.end(); ++it) t << fixLibFlags((*it).toKey()).join(' ') << ' '; diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp index 99788394ea..de7363e51b 100644 --- a/qmake/generators/win32/mingw_make.cpp +++ b/qmake/generators/win32/mingw_make.cpp @@ -209,7 +209,7 @@ void MingwMakefileGenerator::init() processVars(); - project->values("QMAKE_LIBS") += project->values("RES_FILE"); + project->values("LIBS") += project->values("RES_FILE"); if (project->isActiveConfig("dll")) { QString destDir = ""; @@ -285,6 +285,8 @@ void MingwMakefileGenerator::writeLibsPart(QTextStream &t) t << "LINKER = " << var("QMAKE_LINK") << endl; t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl; t << "LIBS = " + << fixLibFlags("LIBS").join(' ') << ' ' + << fixLibFlags("LIBS_PRIVATE").join(' ') << ' ' << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' << fixLibFlags("QMAKE_LIBS_PRIVATE").join(' ') << endl; } diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index fa7ee1b98a..f2cd7c633b 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -383,7 +383,7 @@ void NmakeMakefileGenerator::init() processVars(); - project->values("QMAKE_LIBS") += project->values("RES_FILE"); + project->values("LIBS") += project->values("RES_FILE"); if (!project->values("DEF_FILE").isEmpty()) { QString defFileName = fileFixify(project->first("DEF_FILE").toQString()); diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index c984736c78..f7837fc1b4 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -457,7 +457,8 @@ ProStringList VcprojGenerator::collectDependencies(QMakeProject *proj, QHashdependencies << "idc.exe"; // Add all unknown libs to the deps - QStringList where = QStringList() << "QMAKE_LIBS" << "QMAKE_LIBS_PRIVATE"; + QStringList where = QStringList() << "LIBS" << "LIBS_PRIVATE" + << "QMAKE_LIBS" << "QMAKE_LIBS_PRIVATE"; for (QStringList::ConstIterator wit = where.begin(); wit != where.end(); ++wit) { const ProStringList &l = tmp_proj.values(ProKey(*wit)); @@ -748,7 +749,7 @@ void VcprojGenerator::init() projectTarget = Application; } else if(project->first("TEMPLATE") == "vclib") { if(project->isActiveConfig("staticlib")) { - project->values("QMAKE_LIBS") += project->values("RES_FILE"); + project->values("LIBS") += project->values("RES_FILE"); projectTarget = StaticLib; } else projectTarget = SharedLib; @@ -1084,7 +1085,8 @@ void VcprojGenerator::initLinkerTool() if (!project->values("DEF_FILE").isEmpty()) conf.linker.ModuleDefinitionFile = project->first("DEF_FILE").toQString(); - static const char * const lflags[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; + static const char * const lflags[] = { "LIBS", "LIBS_PRIVATE", + "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; for (int i = 0; lflags[i]; i++) { const auto libs = fixLibFlags(lflags[i]); for (const ProString &lib : libs) { @@ -1179,7 +1181,8 @@ void VcprojGenerator::initDeploymentTool() if (!dllPaths.isEmpty() && !(conf.WinRT && project->first("MSVC_VER").toQString() == "14.0")) { // FIXME: This code should actually resolve the libraries from all Qt modules. - ProStringList arg = project->values("QMAKE_LIBS") + project->values("QMAKE_LIBS_PRIVATE"); + ProStringList arg = project->values("LIBS") + project->values("LIBS_PRIVATE") + + project->values("QMAKE_LIBS") + project->values("QMAKE_LIBS_PRIVATE"); bool qpaPluginDeployed = false; for (ProStringList::ConstIterator it = arg.constBegin(); it != arg.constEnd(); ++it) { QString dllName = (*it).toQString(); diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index 1388e120e7..e0d03ccc1c 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -84,7 +84,8 @@ Win32MakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags) if (impexts.isEmpty()) impexts = project->values("QMAKE_EXTENSION_STATICLIB"); QList dirs; - static const char * const lflags[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; + static const char * const lflags[] = { "LIBS", "LIBS_PRIVATE", + "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr }; for (int i = 0; lflags[i]; i++) { ProStringList &l = project->values(lflags[i]); for (ProStringList::Iterator it = l.begin(); it != l.end();) { @@ -225,8 +226,8 @@ void Win32MakefileGenerator::processVars() libs << QLatin1String("-L") + lib; } } - project->values("QMAKE_LIBS") += libs + project->values("LIBS"); - project->values("QMAKE_LIBS_PRIVATE") += project->values("LIBS_PRIVATE"); + ProStringList &qmklibs = project->values("LIBS"); + qmklibs = libs + qmklibs; if (project->values("TEMPLATE").contains("app")) { project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_APP"); @@ -651,7 +652,9 @@ void Win32MakefileGenerator::writeLibsPart(QTextStream &t) } else { t << "LINKER = " << var("QMAKE_LINK") << endl; t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl; - t << "LIBS = " << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' + t << "LIBS = " << fixLibFlags("LIBS").join(' ') << ' ' + << fixLibFlags("LIBS_PRIVATE").join(' ') << ' ' + << fixLibFlags("QMAKE_LIBS").join(' ') << ' ' << fixLibFlags("QMAKE_LIBS_PRIVATE").join(' ') << endl; } } From 56f949ad3ca8a13d9c49913bae1c9396946672e2 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Mon, 1 Oct 2018 15:46:46 +0300 Subject: [PATCH 18/20] Android: fix compile with NDK r18+ In NDK r18, libc++.so was renamed to libc++.so.XX where XX is the Android API level. [ChangeLog][Android] Fixed build issue with NDK r18+. Task-number: QTBUG-70631 Change-Id: Id0d2955648197e3054e3c69263b5a90d57964f6c Reviewed-by: Oswald Buddenhagen Reviewed-by: Liang Qi --- mkspecs/android-clang/qmake.conf | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mkspecs/android-clang/qmake.conf b/mkspecs/android-clang/qmake.conf index b665000d00..1f5e690329 100644 --- a/mkspecs/android-clang/qmake.conf +++ b/mkspecs/android-clang/qmake.conf @@ -40,7 +40,11 @@ QMAKE_CFLAGS += -DANDROID_HAS_WSTRING --sysroot=$$NDK_ROOT/sysroot \ ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/llvm-libc++/libs/$$ANDROID_TARGET_ARCH ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++_shared.so -ANDROID_CXX_STL_LIBS = -lc++ + +exists($$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++.so): \ + ANDROID_CXX_STL_LIBS = -lc++ +else: \ + ANDROID_CXX_STL_LIBS = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++.so.$$replace(ANDROID_PLATFORM, "android-", "") QMAKE_CFLAGS_OPTIMIZE_SIZE = -Oz From 342b13944c8b4210ab44760dad9ab289e2a89499 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 8 Oct 2018 18:00:33 +0200 Subject: [PATCH 19/20] qmake: document {,QMAKE_}LIBS_PRIVATE Change-Id: I6637d5f57d372f63b3cfaeb28c7e48c940887db6 Reviewed-by: Liang Qi Reviewed-by: Simon Hausmann --- qmake/doc/src/qmake-manual.qdoc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 3595bb0b4e..d4b2f2a07b 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -1320,6 +1320,19 @@ \snippet code/doc_src_qmake-manual.pro 39 + \target LIBS_PRIVATE + \section1 LIBS_PRIVATE + + Specifies a list of libraries to be linked privately into the project. + The behavior of this variable is identical to \l LIBS, except that + shared library projects built for Unix do not expose these dependencies + in their link interface. + + The effect of this is that if project C depends on library B which + depends on library A privately, but C also wants to use symbols from A + directly, it needs to link to A explicitly. Put differently, libraries + linked privately are not exposed transitively at build time. + \target LITERAL_HASH \section1 LITERAL_HASH @@ -2104,6 +2117,16 @@ To specify libraries in a project file, use \l LIBS instead. + \section1 QMAKE_LIBS_PRIVATE + + Specifies additional private libraries each project needs to + link against. + The value of this variable is typically handled by qmake or + \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + + To specify private libraries in a library project file, + use \l LIBS_PRIVATE instead. + \section1 QMAKE_LIBS_EGL Specifies all EGL libraries when building Qt with OpenGL/ES From 473d9a5fc763d114fbfa1c0d2b5f8d03cab6e972 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 8 Oct 2018 18:17:26 +0200 Subject: [PATCH 20/20] qmake: fix the precedence of QMAKE_LIBDIR_POST it must end up in front of QMAKE_LIBS{,_PRIVATE}, but not of LIBS{,_PRIVATE} (which are preceded by QMAKE_LIBDIR). Task-number: QTBUG-61982 Started-by: Liang Qi Change-Id: Id3de01ee0e9b66af02f79949aeb5a0eabd55363f Reviewed-by: Liang Qi Reviewed-by: Simon Hausmann --- qmake/doc/src/qmake-manual.qdoc | 14 +++++++++++++- qmake/generators/unix/unixmake.cpp | 27 ++++++++++++++++----------- qmake/generators/unix/unixmake.h | 1 + 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index d4b2f2a07b..7fd9dd9623 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -2061,7 +2061,19 @@ \section1 QMAKE_LIBDIR - Specifies a list of system library paths. + Specifies a list of library search paths for all projects. + The value of this variable is typically handled by qmake + or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + + To specify additional search paths in project files, + use \l LIBS like that, instead: + \badcode + LIBS += -L/path/to/libraries + \endcode + + \section1 QMAKE_LIBDIR_POST + + Specifies a list of system library search paths for all projects. The value of this variable is typically handled by qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index 3e96b2cf61..50ec8db79e 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -37,6 +37,17 @@ QT_BEGIN_NAMESPACE +ProStringList UnixMakefileGenerator::libdirToFlags(const ProKey &key) +{ + ProStringList results; + for (const auto &libdir : qAsConst(project->values(key))) { + if (!project->isEmpty("QMAKE_LFLAGS_RPATH") && project->isActiveConfig("rpath_libdirs")) + project->values("QMAKE_LFLAGS") += var("QMAKE_LFLAGS_RPATH") + libdir; + results.append("-L" + escapeFilePath(libdir)); + } + return results; +} + void UnixMakefileGenerator::init() { @@ -93,21 +104,13 @@ UnixMakefileGenerator::init() project->isActiveConfig("dll")) project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_PREBIND"); project->values("QMAKE_INCDIR") += project->values("QMAKE_INCDIR_POST"); - project->values("QMAKE_LIBDIR") += project->values("QMAKE_LIBDIR_POST"); project->values("QMAKE_RPATHDIR") += project->values("QMAKE_RPATHDIR_POST"); project->values("QMAKE_RPATHLINKDIR") += project->values("QMAKE_RPATHLINKDIR_POST"); if(!project->isEmpty("QMAKE_INCDIR")) project->values("INCLUDEPATH") += project->values("QMAKE_INCDIR"); - ProStringList ldadd; - if(!project->isEmpty("QMAKE_LIBDIR")) { - const ProStringList &libdirs = project->values("QMAKE_LIBDIR"); - for(int i = 0; i < libdirs.size(); ++i) { - if(!project->isEmpty("QMAKE_LFLAGS_RPATH") && project->isActiveConfig("rpath_libdirs")) - project->values("QMAKE_LFLAGS") += var("QMAKE_LFLAGS_RPATH") + libdirs[i]; - project->values("QMAKE_LIBDIR_FLAGS") += "-L" + escapeFilePath(libdirs[i]); - } - } - ldadd += project->values("QMAKE_LIBDIR_FLAGS"); + // The order of the next two lines is relevant due to side effect on QMAKE_LFLAGS. + ProStringList ldadd = project->values("QMAKE_LIBDIR_FLAGS") + libdirToFlags("QMAKE_LIBDIR"); + ProStringList ldaddpost = libdirToFlags("QMAKE_LIBDIR_POST"); if (project->isActiveConfig("mac")) { if (!project->isEmpty("QMAKE_FRAMEWORKPATH")) { const ProStringList &fwdirs = project->values("QMAKE_FRAMEWORKPATH"); @@ -118,6 +121,8 @@ UnixMakefileGenerator::init() } ProStringList &qmklibs = project->values("LIBS"); qmklibs = ldadd + qmklibs; + ProStringList &qmklibspost = project->values("QMAKE_LIBS"); + qmklibspost = ldaddpost + qmklibspost; if (!project->isEmpty("QMAKE_RPATHDIR") && !project->isEmpty("QMAKE_LFLAGS_RPATH")) { const ProStringList &rpathdirs = project->values("QMAKE_RPATHDIR"); for (int i = 0; i < rpathdirs.size(); ++i) { diff --git a/qmake/generators/unix/unixmake.h b/qmake/generators/unix/unixmake.h index c5e42aa1ae..5b0766855b 100644 --- a/qmake/generators/unix/unixmake.h +++ b/qmake/generators/unix/unixmake.h @@ -66,6 +66,7 @@ protected: private: void init2(); + ProStringList libdirToFlags(const ProKey &key); }; inline UnixMakefileGenerator::~UnixMakefileGenerator()