diff -up qtbase-opensource-src-5.7.1/mkspecs/features/moc.prf.moc_system_defines qtbase-opensource-src-5.7.1/mkspecs/features/moc.prf --- qtbase-opensource-src-5.7.1/mkspecs/features/moc.prf.moc_system_defines 2016-12-01 02:17:04.000000000 -0600 +++ qtbase-opensource-src-5.7.1/mkspecs/features/moc.prf 2016-12-09 10:24:12.463205987 -0600 @@ -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_HOST_DATA/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 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_mocCm 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 -up qtbase-opensource-src-5.7.1/qmake/main.cpp.moc_system_defines qtbase-opensource-src-5.7.1/qmake/main.cpp --- qtbase-opensource-src-5.7.1/qmake/main.cpp.moc_system_defines 2016-12-01 02:17:04.000000000 -0600 +++ qtbase-opensource-src-5.7.1/qmake/main.cpp 2016-12-09 10:24:12.463205987 -0600 @@ -42,6 +42,10 @@ #include #include +#ifdef Q_OS_WIN +# include +#endif + QT_BEGIN_NAMESPACE #ifdef Q_OS_WIN @@ -241,6 +245,30 @@ static int doInstall(int argc, char **ar 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 @@ -275,6 +303,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 -up qtbase-opensource-src-5.7.1/src/tools/moc/main.cpp.moc_system_defines qtbase-opensource-src-5.7.1/src/tools/moc/main.cpp --- qtbase-opensource-src-5.7.1/src/tools/moc/main.cpp.moc_system_defines 2016-12-09 10:24:12.458205887 -0600 +++ qtbase-opensource-src-5.7.1/src/tools/moc/main.cpp 2016-12-09 10:53:10.285347282 -0600 @@ -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")); @@ -415,7 +420,31 @@ int runMoc(int argc, char **argv) moc.includes = pp.includes; // 1. preprocess - moc.symbols = pp.preprocessed(moc.filename, &in); + const auto includeFiles = parser.values(includeOption); + for (const QString &includeName : includeFiles) { + QByteArray rawName = pp.resolveInclude(QFile::encodeName(includeName), moc.filename); + if (rawName.isEmpty()) { + fprintf(stderr, "Warning: Failed to resolve include \"%s\" for moc file %s\n", + includeName.toLocal8Bit().constData(), + moc.filename.isEmpty() ? "" : moc.filename.constData()); + } else { + 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); + } else { + fprintf(stderr, "Warning: Cannot open %s included by moc file %s: %s\n", + rawName.constData(), + moc.filename.isEmpty() ? "" : moc.filename.constData(), + f.errorString().toLocal8Bit().constData()); + } + } + } + moc.symbols += pp.preprocessed(moc.filename, &in); + + // We obviously do not support MS extensions + pp.macros.remove("_MSC_EXTENSIONS"); if (!pp.preprocessOnly) { // 2. parse diff -up qtbase-opensource-src-5.7.1/src/tools/moc/preprocessor.cpp.moc_system_defines qtbase-opensource-src-5.7.1/src/tools/moc/preprocessor.cpp --- qtbase-opensource-src-5.7.1/src/tools/moc/preprocessor.cpp.moc_system_defines 2016-12-01 02:17:04.000000000 -0600 +++ qtbase-opensource-src-5.7.1/src/tools/moc/preprocessor.cpp 2016-12-09 10:24:12.464206007 -0600 @@ -1008,6 +1008,37 @@ static void mergeStringLiterals(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); @@ -1028,32 +1059,9 @@ void Preprocessor::preprocess(const QByt 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; - fi.setFile(QString::fromLocal8Bit(p.path + '/' + include.left(slashPos) + ".framework/Headers/"), - 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; @@ -1208,6 +1216,7 @@ Symbols Preprocessor::preprocessed(const input = cleaned(input); // phase 2: tokenize for the preprocessor + index = 0; symbols = tokenize(input); #if 0 diff -up qtbase-opensource-src-5.7.1/src/tools/moc/preprocessor.h.moc_system_defines qtbase-opensource-src-5.7.1/src/tools/moc/preprocessor.h --- qtbase-opensource-src-5.7.1/src/tools/moc/preprocessor.h.moc_system_defines 2016-12-01 02:17:04.000000000 -0600 +++ qtbase-opensource-src-5.7.1/src/tools/moc/preprocessor.h 2016-12-09 10:24:12.464206007 -0600 @@ -62,6 +62,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 -up qtbase-opensource-src-5.7.1/tests/auto/tools/moc/subdir/extradefines.h.moc_system_defines qtbase-opensource-src-5.7.1/tests/auto/tools/moc/subdir/extradefines.h --- qtbase-opensource-src-5.7.1/tests/auto/tools/moc/subdir/extradefines.h.moc_system_defines 2016-12-09 10:24:12.464206007 -0600 +++ qtbase-opensource-src-5.7.1/tests/auto/tools/moc/subdir/extradefines.h 2016-12-09 10:24:12.464206007 -0600 @@ -0,0 +1 @@ +#define FOO 1 diff -up qtbase-opensource-src-5.7.1/tests/auto/tools/moc/tst_moc.cpp.moc_system_defines qtbase-opensource-src-5.7.1/tests/auto/tools/moc/tst_moc.cpp --- qtbase-opensource-src-5.7.1/tests/auto/tools/moc/tst_moc.cpp.moc_system_defines 2016-12-01 02:17:04.000000000 -0600 +++ qtbase-opensource-src-5.7.1/tests/auto/tools/moc/tst_moc.cpp 2016-12-09 10:24:12.465206027 -0600 @@ -576,6 +576,8 @@ private slots: void frameworkSearchPath(); void cstyleEnums(); void defineMacroViaCmdline(); + void defineMacroViaForcedInclude(); + void defineMacroViaForcedIncludeRelative(); void specifyMetaTagsFromCmdline(); void invokable(); void singleFunctionKeywordSignalAndSlot(); @@ -1244,6 +1246,46 @@ void tst_Moc::defineMacroViaCmdline() 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::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());