From cd64dbe445558a71327adbbff60bb779e51811b7 Mon Sep 17 00:00:00 2001 From: Rex Dieter Date: Wed, 16 Dec 2015 16:11:53 -0600 Subject: [PATCH] 5.6.0-0.15 - pull in another upstream moc fix/improvement (#1290020,QTBUG-49972) - fix bootstrap/docs --- ...tem-defines-from-the-compiler-itself.patch | 368 ++++++++++++++++++ qt5-qtbase.spec | 12 +- 2 files changed, 377 insertions(+), 3 deletions(-) create mode 100644 moc-get-the-system-defines-from-the-compiler-itself.patch diff --git a/moc-get-the-system-defines-from-the-compiler-itself.patch b/moc-get-the-system-defines-from-the-compiler-itself.patch new file mode 100644 index 0000000..cd8de49 --- /dev/null +++ b/moc-get-the-system-defines-from-the-compiler-itself.patch @@ -0,0 +1,368 @@ +From 7b2877325d398b28a3a99d29b7651a34c60237b1 Mon Sep 17 00:00:00 2001 +From: Thiago Macieira +Date: Fri, 21 Aug 2015 17:08:19 -0700 +Subject: [PATCH] moc: get the system #defines from the compiler itself + +In order for moc to properly parse #ifdefs and family, we've had +QMAKE_COMPILER_DEFINES as a list of pre-defined macros from the +compiler. That list is woefully incomplete. + +Instead, let's simply ask the compiler for the list. With GCC and +family, we use the -dM flag while preprocessing. With ICC on Windows, +the flag gains an extra "Q" but is otherwise the same. For MSVC, it +requires using some undocumented switches and parsing environment +variables (I've tested MSVC 2012, 2013 and 2015). + +The new moc option is called --include to be similar to GCC's -include +option. It does more than just parse a list of pre-defined macros and +can be used to insert any sort of code that moc needs to parse prior to +the main file. + +Change-Id: I7de033f80b0e4431b7f1ffff13fca02dbb60a0a6 +--- + mkspecs/features/moc.prf | 31 +++++++++++++-- + qmake/main.cpp | 38 +++++++++++++++++++ + src/tools/moc/main.cpp | 16 +++++++- + src/tools/moc/preprocessor.cpp | 60 +++++++++++++++++------------- + src/tools/moc/preprocessor.h | 1 + + tests/auto/tools/moc/subdir/extradefines.h | 1 + + tests/auto/tools/moc/tst_moc.cpp | 42 +++++++++++++++++++++ + 7 files changed, 158 insertions(+), 31 deletions(-) + create mode 100644 tests/auto/tools/moc/subdir/extradefines.h + +diff --git a/mkspecs/features/moc.prf b/mkspecs/features/moc.prf +index c0b5682..159c659 100644 +--- a/mkspecs/features/moc.prf ++++ b/mkspecs/features/moc.prf +@@ -24,8 +24,25 @@ win32:count(MOC_INCLUDEPATH, 40, >) { + write_file($$absolute_path($$WIN_INCLUDETEMP, $$OUT_PWD), WIN_INCLUDETEMP_CONT)|error("Aborting.") + } + ++# QNX's compiler sets "gcc" config, but does not support the -dM option; ++# iOS builds are multi-arch, so this feature cannot possibly work. ++if(gcc|intel_icl|msvc):!rim_qcc:!ios { ++ moc_predefs.CONFIG = no_link ++ gcc: moc_predefs.commands = $$QMAKE_CXX $$QMAKE_CXXFLAGS -dM -E -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN} ++ else:intel_icl: moc_predefs.commands = $$QMAKE_CXX $$QMAKE_CXXFLAGS -QdM -P -Fi${QMAKE_FILE_OUT} ${QMAKE_FILE_IN} ++ else:msvc { ++ # make sure that our bin dir is first in path, so qmake is found ++ moc_predefs.commands = PATH $$shell_path($$[QT_INSTALL_BINS/src]);%PATH%& ++ moc_predefs.commands += $$QMAKE_CXX -Bxqmake $$QMAKE_CXXFLAGS -E ${QMAKE_FILE_IN} 2>NUL >${QMAKE_FILE_OUT} ++ } else: error("Oops, I messed up") ++ moc_predefs.output = $$MOC_DIR/moc_predefs.h ++ moc_predefs.input = MOC_PREDEF_FILE ++ silent: moc_predefs.commands = @echo generating $$moc_predefs.output$$escape_expand(\n\t)@$$moc_predefs.commands ++ QMAKE_EXTRA_COMPILERS += moc_predefs ++ MOC_PREDEF_FILE = $$[QT_INSTALL_ARCHDATA/src]/mkspecs/features/data/dummy.cpp ++} ++ + defineReplace(mocCmdBase) { +- RET = + !isEmpty(WIN_INCLUDETEMP) { + incvar = @$$WIN_INCLUDETEMP + } else { +@@ -34,7 +51,13 @@ defineReplace(mocCmdBase) { + incvar += -I$$shell_quote($$inc) + incvar += $$QMAKE_FRAMEWORKPATH_FLAGS + } +- RET += $$QMAKE_MOC $(DEFINES) $$join(QMAKE_COMPILER_DEFINES, " -D", -D) $$incvar $$QMAKE_MOC_OPTIONS ++ ++ RET = $$QMAKE_MOC $(DEFINES) ++ ++ isEmpty(MOC_PREDEF_FILE): RET += $$join(QMAKE_COMPILER_DEFINES, " -D", -D) ++ else: RET += --include $$moc_predefs.output ++ ++ RET += $$incvar $$QMAKE_MOC_OPTIONS + return($$RET) + } + +@@ -46,7 +69,7 @@ moc_header.output = $$MOC_DIR/$${QMAKE_H_MOD_MOC}${QMAKE_FILE_BASE}$${first(QMAK + moc_header.input = HEADERS + moc_header.variable_out = SOURCES + moc_header.name = MOC ${QMAKE_FILE_IN} +-moc_header.depends += $$WIN_INCLUDETEMP ++moc_header.depends += $$WIN_INCLUDETEMP $$moc_predefs.output + silent:moc_header.commands = @echo moc ${QMAKE_FILE_IN} && $$moc_header.commands + QMAKE_EXTRA_COMPILERS += moc_header + INCREDIBUILD_XGE += moc_header +@@ -58,7 +81,7 @@ moc_source.commands = ${QMAKE_FUNC_mocCmdBase} ${QMAKE_FILE_IN} -o ${QMAKE_FILE_ + moc_source.output = $$MOC_DIR/$${QMAKE_CPP_MOD_MOC}${QMAKE_FILE_BASE}$${QMAKE_EXT_CPP_MOC} + moc_source.input = SOURCES OBJECTIVE_SOURCES + moc_source.name = MOC ${QMAKE_FILE_IN} +-moc_source.depends += $$WIN_INCLUDETEMP ++moc_source.depends += $$WIN_INCLUDETEMP $$moc_predefs.output + silent:moc_source.commands = @echo moc ${QMAKE_FILE_IN} && $$moc_source.commands + QMAKE_EXTRA_COMPILERS += moc_source + INCREDIBUILD_XGE += moc_source +diff --git a/qmake/main.cpp b/qmake/main.cpp +index bde537d..e9b8bde 100644 +--- a/qmake/main.cpp ++++ b/qmake/main.cpp +@@ -1,6 +1,7 @@ + /**************************************************************************** + ** + ** Copyright (C) 2015 The Qt Company Ltd. ++** Copyright (C) 2015 Intel Corporation. + ** Contact: http://www.qt.io/licensing/ + ** + ** This file is part of the qmake application of the Qt Toolkit. +@@ -47,6 +48,10 @@ + #include + #include + ++#ifdef Q_OS_WIN ++# include ++#endif ++ + QT_BEGIN_NAMESPACE + + #ifdef Q_OS_WIN +@@ -246,6 +251,30 @@ static int doInstall(int argc, char **argv) + return 3; + } + ++static int dumpMacros(const wchar_t *cmdline) ++{ ++ // from http://stackoverflow.com/questions/3665537/how-to-find-out-cl-exes-built-in-macros ++ int argc; ++ wchar_t **argv = CommandLineToArgvW(cmdline, &argc); ++ if (!argv) ++ return 2; ++ for (int i = 0; i < argc; ++i) { ++ if (argv[i][0] != L'-' || argv[i][1] != 'D') ++ continue; ++ ++ wchar_t *value = wcschr(argv[i], L'='); ++ if (value) { ++ *value = 0; ++ ++value; ++ } else { ++ // point to the NUL at the end, so we don't print anything ++ value = argv[i] + wcslen(argv[i]); ++ } ++ wprintf(L"#define %Ls %Ls\n", argv[i] + 2, value); ++ } ++ return 0; ++} ++ + #endif // Q_OS_WIN + + /* This is to work around lame implementation on Darwin. It has been noted that the getpwd(3) function +@@ -280,6 +309,15 @@ int runQMake(int argc, char **argv) + // Workaround for inferior/missing command line tools on Windows: make our own! + if (argc >= 2 && !strcmp(argv[1], "-install")) + return doInstall(argc - 2, argv + 2); ++ ++ { ++ // Support running as Visual C++'s compiler ++ const wchar_t *cmdline = _wgetenv(L"MSC_CMD_FLAGS"); ++ if (!cmdline || !*cmdline) ++ cmdline = _wgetenv(L"MSC_IDE_FLAGS"); ++ if (cmdline && *cmdline) ++ return dumpMacros(cmdline); ++ } + #endif + + QMakeVfs vfs; +diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp +index a5cbad7..d06335d 100644 +--- a/src/tools/moc/main.cpp ++++ b/src/tools/moc/main.cpp +@@ -259,6 +259,11 @@ int runMoc(int argc, char **argv) + prependIncludeOption.setValueName(QStringLiteral("file")); + parser.addOption(prependIncludeOption); + ++ QCommandLineOption includeOption(QStringLiteral("include")); ++ includeOption.setDescription(QStringLiteral("Parse as an #include before the main source(s).")); ++ includeOption.setValueName(QStringLiteral("file")); ++ parser.addOption(includeOption); ++ + QCommandLineOption noNotesWarningsCompatOption(QStringLiteral("n")); + noNotesWarningsCompatOption.setDescription(QStringLiteral("Do not display notes (-nn) or warnings (-nw). Compatibility option.")); + noNotesWarningsCompatOption.setValueName(QStringLiteral("which")); +@@ -406,7 +411,16 @@ int runMoc(int argc, char **argv) + moc.includes = pp.includes; + + // 1. preprocess +- moc.symbols = pp.preprocessed(moc.filename, &in); ++ foreach (const QString &includeName, parser.values(includeOption)) { ++ QByteArray rawName = pp.resolveInclude(QFile::encodeName(includeName), moc.filename); ++ QFile f(QFile::decodeName(rawName)); ++ if (f.open(QIODevice::ReadOnly)) { ++ moc.symbols += Symbol(0, MOC_INCLUDE_BEGIN, rawName); ++ moc.symbols += pp.preprocessed(rawName, &f); ++ moc.symbols += Symbol(0, MOC_INCLUDE_END, rawName); ++ } ++ } ++ moc.symbols += pp.preprocessed(moc.filename, &in); + + if (!pp.preprocessOnly) { + // 2. parse +diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp +index d036c40..70cf14a 100644 +--- a/src/tools/moc/preprocessor.cpp ++++ b/src/tools/moc/preprocessor.cpp +@@ -1001,6 +1001,37 @@ static void mergeStringLiterals(Symbols *_symbols) + } + } + ++QByteArray Preprocessor::resolveInclude(const QByteArray &include, const QByteArray &relativeTo) ++{ ++ // #### stringery ++ QFileInfo fi; ++ if (!relativeTo.isEmpty()) ++ fi.setFile(QFileInfo(QString::fromLocal8Bit(relativeTo.constData())).dir(), QString::fromLocal8Bit(include.constData())); ++ for (int j = 0; j < Preprocessor::includes.size() && !fi.exists(); ++j) { ++ const IncludePath &p = Preprocessor::includes.at(j); ++ if (p.isFrameworkPath) { ++ const int slashPos = include.indexOf('/'); ++ if (slashPos == -1) ++ continue; ++ QByteArray frameworkCandidate = include.left(slashPos); ++ frameworkCandidate.append(".framework/Headers/"); ++ fi.setFile(QString::fromLocal8Bit(QByteArray(p.path + '/' + frameworkCandidate).constData()), QString::fromLocal8Bit(include.mid(slashPos + 1).constData())); ++ } else { ++ fi.setFile(QString::fromLocal8Bit(p.path.constData()), QString::fromLocal8Bit(include.constData())); ++ } ++ // try again, maybe there's a file later in the include paths with the same name ++ // (186067) ++ if (fi.isDir()) { ++ fi = QFileInfo(); ++ continue; ++ } ++ } ++ ++ if (!fi.exists() || fi.isDir()) ++ return QByteArray(); ++ return fi.canonicalFilePath().toLocal8Bit(); ++} ++ + void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed) + { + currentFilenames.push(filename); +@@ -1021,33 +1052,9 @@ void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed) + continue; + until(PP_NEWLINE); + +- // #### stringery +- QFileInfo fi; +- if (local) +- fi.setFile(QFileInfo(QString::fromLocal8Bit(filename.constData())).dir(), QString::fromLocal8Bit(include.constData())); +- for (int j = 0; j < Preprocessor::includes.size() && !fi.exists(); ++j) { +- const IncludePath &p = Preprocessor::includes.at(j); +- if (p.isFrameworkPath) { +- const int slashPos = include.indexOf('/'); +- if (slashPos == -1) +- continue; +- QByteArray frameworkCandidate = include.left(slashPos); +- frameworkCandidate.append(".framework/Headers/"); +- fi.setFile(QString::fromLocal8Bit(QByteArray(p.path + '/' + frameworkCandidate).constData()), QString::fromLocal8Bit(include.mid(slashPos + 1).constData())); +- } else { +- fi.setFile(QString::fromLocal8Bit(p.path.constData()), QString::fromLocal8Bit(include.constData())); +- } +- // try again, maybe there's a file later in the include paths with the same name +- // (186067) +- if (fi.isDir()) { +- fi = QFileInfo(); +- continue; +- } +- } +- +- if (!fi.exists() || fi.isDir()) ++ include = resolveInclude(include, local ? filename : QByteArray()); ++ if (include.isNull()) + continue; +- include = fi.canonicalFilePath().toLocal8Bit(); + + if (Preprocessor::preprocessedIncludes.contains(include)) + continue; +@@ -1202,6 +1209,7 @@ Symbols Preprocessor::preprocessed(const QByteArray &filename, QFile *file) + input = cleaned(input); + + // phase 2: tokenize for the preprocessor ++ index = 0; + symbols = tokenize(input); + + #if 0 +diff --git a/src/tools/moc/preprocessor.h b/src/tools/moc/preprocessor.h +index 9c81f86..d876caf 100644 +--- a/src/tools/moc/preprocessor.h ++++ b/src/tools/moc/preprocessor.h +@@ -67,6 +67,7 @@ public: + QList frameworks; + QSet preprocessedIncludes; + Macros macros; ++ QByteArray resolveInclude(const QByteArray &filename, const QByteArray &relativeTo); + Symbols preprocessed(const QByteArray &filename, QFile *device); + + void parseDefineArguments(Macro *m); +diff --git a/tests/auto/tools/moc/subdir/extradefines.h b/tests/auto/tools/moc/subdir/extradefines.h +new file mode 100644 +index 0000000..e7888ce +--- /dev/null ++++ b/tests/auto/tools/moc/subdir/extradefines.h +@@ -0,0 +1 @@ ++#define FOO 1 +diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp +index fa1b68b..1d6a911 100644 +--- a/tests/auto/tools/moc/tst_moc.cpp ++++ b/tests/auto/tools/moc/tst_moc.cpp +@@ -552,6 +552,8 @@ private slots: + void frameworkSearchPath(); + void cstyleEnums(); + void defineMacroViaCmdline(); ++ void defineMacroViaForcedInclude(); ++ void defineMacroViaForcedIncludeRelative(); + void specifyMetaTagsFromCmdline(); + void invokable(); + void singleFunctionKeywordSignalAndSlot(); +@@ -1219,6 +1221,46 @@ void tst_Moc::defineMacroViaCmdline() + #endif + } + ++void tst_Moc::defineMacroViaForcedInclude() ++{ ++#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(QT_NO_PROCESS) ++ QProcess proc; ++ ++ QStringList args; ++ args << "--include" << m_sourceDirectory + QLatin1String("/subdir/extradefines.h"); ++ args << m_sourceDirectory + QStringLiteral("/macro-on-cmdline.h"); ++ ++ proc.start(m_moc, args); ++ QVERIFY(proc.waitForFinished()); ++ QCOMPARE(proc.exitCode(), 0); ++ QCOMPARE(proc.readAllStandardError(), QByteArray()); ++ QByteArray mocOut = proc.readAllStandardOutput(); ++ QVERIFY(!mocOut.isEmpty()); ++#else ++ QSKIP("Only tested on linux/gcc"); ++#endif ++} ++ ++void tst_Moc::defineMacroViaForcedIncludeRelative() ++{ ++#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(QT_NO_PROCESS) ++ QProcess proc; ++ ++ QStringList args; ++ args << "--include" << QStringLiteral("extradefines.h") << "-I" + m_sourceDirectory + "/subdir"; ++ args << m_sourceDirectory + QStringLiteral("/macro-on-cmdline.h"); ++ ++ proc.start(m_moc, args); ++ QVERIFY(proc.waitForFinished()); ++ QCOMPARE(proc.exitCode(), 0); ++ QCOMPARE(proc.readAllStandardError(), QByteArray()); ++ QByteArray mocOut = proc.readAllStandardOutput(); ++ QVERIFY(!mocOut.isEmpty()); ++#else ++ QSKIP("Only tested on linux/gcc"); ++#endif ++} ++ + // tst_Moc::specifyMetaTagsFromCmdline() + // plugin_metadata.h contains a plugin which we register here. Since we're not building this + // application as a plugin, we need top copy some of the initializer code found in qplugin.h: +-- +1.9.3 + diff --git a/qt5-qtbase.spec b/qt5-qtbase.spec index d43e7ff..27ca285 100644 --- a/qt5-qtbase.spec +++ b/qt5-qtbase.spec @@ -39,7 +39,7 @@ Summary: Qt5 - QtBase components Name: qt5-qtbase Version: 5.6.0 -Release: 0.13%{?dist} +Release: 0.15%{?dist} # See LGPL_EXCEPTIONS.txt, for exception details License: LGPLv2 with exceptions or GPLv3 with exceptions @@ -88,6 +88,9 @@ Patch102: 0002-xcb-compare-to-previous-state-when-sending-geometry-.patch Patch111: 0011-xcb-Don-t-cache-the-screen-for-a-window.patch Patch112: 0012-xcb-Use-a-placeholder-QScreen-when-there-are-no-outp.patch +# recently passed code review, not integrated yet +Patch150: moc-get-the-system-defines-from-the-compiler-itself.patch + # macros, be mindful to keep sync'd with macros.qt5 Source10: macros.qt5 %define _qt5 %{name} @@ -331,6 +334,7 @@ rm -fv mkspecs/linux-g++*/qmake.conf.multilib-optflags %patch102 -p1 -b .0002 %patch111 -p1 -b .0011 %patch112 -p1 -b .0012 +%patch150 -p1 -b .moc_system_defines # drop -fexceptions from $RPM_OPT_FLAGS RPM_OPT_FLAGS=`echo $RPM_OPT_FLAGS | sed 's|-fexceptions||g'` @@ -602,10 +606,8 @@ fi %dir %{_qt5_libdir}/cmake/Qt5Test/ %dir %{_qt5_libdir}/cmake/Qt5Widgets/ %dir %{_qt5_libdir}/cmake/Qt5Xml/ -%if 0%{?docs} %dir %{_qt5_docdir}/ %{_qt5_docdir}/global/ -%endif %{_qt5_importdir}/ %{_qt5_translationdir}/ %dir %{_qt5_prefix}/ @@ -865,6 +867,10 @@ fi %changelog +* Wed Dec 16 2015 Rex Dieter - 5.6.0-0.15 +- pull in another upstream moc fix/improvement (#1290020,QTBUG-49972) +- fix bootstrap/docs + * Wed Dec 16 2015 Rex Dieter 5.6.0-0.13 - workaround moc/qconfig-multilib issues (#1290020,QTBUG-49972)