diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2016-04-13 17:25:37 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2016-07-20 02:54:09 +0000 |
commit | da04322b4c429de9a6f5aa06545c10284ec2e56d (patch) | |
tree | 772dd5a5fa5d93df2dfceec0c767c8b2d0f7eb6b | |
parent | 36d524e6a3b64a8c35805c1b868d6d67ccae765c (diff) |
Make moc obey the preprocessor environment variable for include paths
C preprocessors augment their standard list of include paths from the
environment: Unix preprocessors use $C_INCLUDE_PATH (for C) and
$CPLUS_INCLUDE_PATH (for C++), plus CPATH for both, whereas MSVC uses
the an environment variable simply called "INCLUDE". Handling this for
MSVC is particularly important because the VCVARSALL.BAT script sets the
necessary #include paths in the environment for important things.
Without that being parsed, moc won't find some #defines, like
WINAPI_DESKTOP_FAMILY.
[ChangeLog][moc] qmake and moc now cooperate to use the Visual Studio
environment variables (set by the VCVARSALL.BAT script) to find system
include files. A possible consequence is that moc parses application
headers slightly differently, depending on #if conditions that depended
on macros that previous versions had not seen #define'd. Implementers of
other buildsystems are advised to pass the --compiler-flavor=msvc option
to moc.
Change-Id: I7e06274214d1939b0124e5b4bf169cceaef9ca46
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
-rw-r--r-- | mkspecs/features/moc.prf | 1 | ||||
-rw-r--r-- | src/corelib/Qt5CoreMacros.cmake | 3 | ||||
-rw-r--r-- | src/network/socket/socket.pri | 4 | ||||
-rw-r--r-- | src/tools/moc/main.cpp | 29 | ||||
-rw-r--r-- | tests/auto/tools/moc/tst_moc.cpp | 48 |
5 files changed, 85 insertions, 0 deletions
diff --git a/mkspecs/features/moc.prf b/mkspecs/features/moc.prf index 693be4a22d..6368c8e394 100644 --- a/mkspecs/features/moc.prf +++ b/mkspecs/features/moc.prf @@ -51,6 +51,7 @@ defineReplace(mocCmdBase) { } RET = $$QMAKE_MOC $(DEFINES) + msvc: RET += --compiler-flavor=msvc isEmpty(MOC_PREDEF_FILE): RET += $$join(QMAKE_COMPILER_DEFINES, " -D", -D) else: RET += --include $$moc_predefs.output diff --git a/src/corelib/Qt5CoreMacros.cmake b/src/corelib/Qt5CoreMacros.cmake index 9235641544..23909c9f3f 100644 --- a/src/corelib/Qt5CoreMacros.cmake +++ b/src/corelib/Qt5CoreMacros.cmake @@ -90,6 +90,9 @@ macro(QT5_GET_MOC_FLAGS _moc_flags) if(WIN32) set(${_moc_flags} ${${_moc_flags}} -DWIN32) endif() + if (MSVC) + set(${_moc_flags} --compiler-flavor=msvc) + endif() endmacro() diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri index 2d80f38bec..2e3e26d37d 100644 --- a/src/network/socket/socket.pri +++ b/src/network/socket/socket.pri @@ -39,6 +39,10 @@ unix: { unix:HEADERS += \ socket/qnet_unix_p.h +# Suppress deprecation warnings with moc because MS headers have +# invalid C/C++ code otherwise. +msvc: QMAKE_MOC_OPTIONS += -D_WINSOCK_DEPRECATED_NO_WARNINGS + win32:!winrt:SOURCES += socket/qnativesocketengine_win.cpp \ socket/qlocalsocket_win.cpp \ socket/qlocalserver_win.cpp diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp index c111fa4e6b..0a10aef989 100644 --- a/src/tools/moc/main.cpp +++ b/src/tools/moc/main.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -242,6 +243,11 @@ int runMoc(int argc, char **argv) metadataOption.setFlags(QCommandLineOption::ShortOptionStyle); parser.addOption(metadataOption); + QCommandLineOption compilerFlavorOption(QStringLiteral("compiler-flavor")); + compilerFlavorOption.setDescription(QStringLiteral("Set the compiler flavor: either \"msvc\" or \"unix\".")); + compilerFlavorOption.setValueName(QStringLiteral("flavor")); + parser.addOption(compilerFlavorOption); + QCommandLineOption noIncludeOption(QStringLiteral("i")); noIncludeOption.setDescription(QStringLiteral("Do not generate an #include statement.")); parser.addOption(noIncludeOption); @@ -328,9 +334,32 @@ int runMoc(int argc, char **argv) if (parser.isSet(pathPrefixOption)) moc.includePath = QFile::encodeName(parser.value(pathPrefixOption)); } + const auto includePaths = parser.values(includePathOption); for (const QString &path : includePaths) pp.includes += Preprocessor::IncludePath(QFile::encodeName(path)); + QString compilerFlavor = parser.value(compilerFlavorOption); + if (compilerFlavor.isEmpty() || compilerFlavor == QLatin1String("unix")) { + // traditional Unix compilers use both CPATH and CPLUS_INCLUDE_PATH + // $CPATH feeds to #include <...> and #include "...", whereas + // CPLUS_INCLUDE_PATH is equivalent to GCC's -isystem, so we parse later + const auto cpath = qgetenv("CPATH").split(QDir::listSeparator().toLatin1()); + for (const QByteArray &p : cpath) + pp.includes += Preprocessor::IncludePath(p); + const auto cplus_include_path = qgetenv("CPLUS_INCLUDE_PATH").split(QDir::listSeparator().toLatin1()); + for (const QByteArray &p : cplus_include_path) + pp.includes += Preprocessor::IncludePath(p); + } else if (compilerFlavor == QLatin1String("msvc")) { + // MSVC uses one environment variable: INCLUDE + const auto include = qgetenv("INCLUDE").split(QDir::listSeparator().toLatin1()); + for (const QByteArray &p : include) + pp.includes += Preprocessor::IncludePath(p); + } else { + error(qPrintable(QLatin1String("Unknown compiler flavor '") + compilerFlavor + + QLatin1String("'; valid values are: msvc, unix."))); + parser.showHelp(1); + } + const auto macFrameworks = parser.values(macFrameworkOption); for (const QString &path : macFrameworks) { // minimalistic framework support for the mac diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 1cf6f94720..ab15f81939 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -577,6 +577,8 @@ private slots: void defineMacroViaCmdline(); void defineMacroViaForcedInclude(); void defineMacroViaForcedIncludeRelative(); + void environmentIncludePaths_data(); + void environmentIncludePaths(); void specifyMetaTagsFromCmdline(); void invokable(); void singleFunctionKeywordSignalAndSlot(); @@ -1295,6 +1297,52 @@ void tst_Moc::defineMacroViaForcedIncludeRelative() #endif } + +void tst_Moc::environmentIncludePaths_data() +{ +#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(QT_NO_PROCESS) + QTest::addColumn<QString>("cmdline"); + QTest::addColumn<QString>("varname"); + + QTest::newRow("INCLUDE") << "--compiler-flavor=msvc" << "INCLUDE"; + QTest::newRow("CPATH1") << QString() << "CPATH"; + QTest::newRow("CPATH2") << "--compiler-flavor=unix" << "CPATH"; + QTest::newRow("CPLUS_INCLUDE_PATH1") << QString() << "CPLUS_INCLUDE_PATH"; + QTest::newRow("CPLUS_INCLUDE_PATH2") << "--compiler-flavor=unix" << "CPLUS_INCLUDE_PATH"; +#endif +} + +void tst_Moc::environmentIncludePaths() +{ +#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(QT_NO_PROCESS) + QFETCH(QString, cmdline); + QFETCH(QString, varname); + + QStringList args; + if (!cmdline.isEmpty()) + args << cmdline; + args << "--include" << QStringLiteral("extradefines.h") + << m_sourceDirectory + QStringLiteral("/macro-on-cmdline.h"); + + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.remove("INCLUDE"); + env.remove("CPATH"); + env.remove("CPLUS_INCLUDE_PATH"); + env.insert(varname, m_sourceDirectory + "/subdir"); + + QProcess proc; + proc.setProcessEnvironment(env); + 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: |