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