Hi, a consequence of the merging of the refactor branch is that all Q_WS_XX defines other than Q_WS_QPA are no longer defined on any platform. Any code #ifdefed Q_WS_XX (or Q_OS_SYMBIAN) is now basically dead and should be carefully removed; only the code #ifdefed Q_WS_QPA should be left intact and no longer be enclosed in #if (see for example qtbase: I2ac33765: Remove Q_WS_ and Q_OS_SYMBIAN which should appear soon after testing/integrating).
I will try to follow that through in qtbase/src and hopefully finally get rid of the need build with -qpa. As for the other modules and the qtbase tests, I would like to ask the respective maintainers to step up (priority is entirely up to you, but I think any gain in code clarity and speed-up of the compiling/testing cycle due to reduced code size is worth the effort). I am not touching the tests since there a few places where it is not entirely trivial; there is code like #ifdef Q_WS_X11 sleep(10) // wait for X11 WM #endif. This needs to be done on a case by case base. There is currently no way to query the platform name/type from Qt. Should such a need arise, please talk to the Lighthouse experts on how best do this. The process can be semi-automated by running the attached program (a bastardized version of a preprocesssor from Qt Creator), which takes file names on the command line. It handles some #ifdefs it knows and prompts you for the complicated cases like #if defined(Q_WS_WIN) && !defined(QT_NO_FREETYPE) || defined(Q_NO_PRINTER) whether they evaluate to true/false or should be left intact. Regards, Friedemann -- Friedemann Kleint Nokia, Qt Development Frameworks
/************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (qt-i...@nokia.com) ** ** Commercial Usage ** ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at http://qt.nokia.com/contact. ** **************************************************************************/ #include <QtCore/QCoreApplication> #include <QtCore/QString> #include <QtCore/QStringList> #include <QtCore/QScopedPointer> #include <QtCore/QFile> #include <QtCore/QStack> #include <QtCore/QPair> #include <QtCore/QRegExp> #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QTemporaryFile> #include <stdio.h> #include <stdlib.h> enum { debug = 0 }; // Preprocessor: Conditional section enum PreprocessorSection { IfSection, IfdefSection, IfndefSection, ElsifSection, ElseSection, EndifSection, OtherSection }; // Preprocessor: Section stack containing nested '@if' sections struct PreprocessStackEntry { PreprocessStackEntry(PreprocessorSection section = OtherSection, bool parentEnabled = true, bool condition = false, bool anyIfClauseMatched = false, bool wsExpression = false); PreprocessorSection section; bool parentEnabled; bool condition; bool anyIfClauseMatched; bool wsExpression; }; PreprocessStackEntry::PreprocessStackEntry(PreprocessorSection s, bool p, bool c, bool a, bool w) : section(s), parentEnabled(p), condition(c), anyIfClauseMatched(a),wsExpression(w) { } class PreprocessContext { public: PreprocessContext(); unsigned process(QIODevice &in, QIODevice &out, QIODevice *inputLog, QString *errorMessage); private: void reset(); PreprocessorSection preprocessorLine(const QString & in, QString *ifExpression) const; mutable QRegExp m_ifPattern; mutable QRegExp m_ifdefPattern; mutable QRegExp m_ifndefPattern; mutable QRegExp m_elsifPattern; const QRegExp m_elsePattern; const QRegExp m_endifPattern; QStack<PreprocessStackEntry> m_sectionStack; }; PreprocessContext::PreprocessContext() : // Cut out expression for 'if/elsif ' m_ifPattern(QLatin1String("^\\s*#\\s*if\\s+(.*)$")), m_ifdefPattern(QLatin1String("^\\s*#\\s*ifdef\\s+(.*)$")), m_ifndefPattern(QLatin1String("^\\s*#\\s*ifndef\\s+(.*)$")), m_elsifPattern(QLatin1String("^\\s*#\\s*elif\\s+(.*)$")), m_elsePattern(QLatin1String("^\\s*#\\s*else.*$")), m_endifPattern(QLatin1String("^\\s*#\\s*endif.*$")) { Q_ASSERT(m_ifPattern.isValid() && m_ifdefPattern.isValid() && m_ifndefPattern.isValid() && m_elsifPattern.isValid() && m_elsePattern.isValid() && m_endifPattern.isValid()); } void PreprocessContext::reset() { m_sectionStack.clear(); m_sectionStack.push(PreprocessStackEntry(OtherSection, true, true)); } PreprocessorSection PreprocessContext::preprocessorLine(const QString &in, QString *ifExpression) const { if (m_ifPattern.exactMatch(in)) { *ifExpression = m_ifPattern.cap(1).trimmed(); return IfSection; } if (m_ifdefPattern.exactMatch(in)) { *ifExpression = m_ifdefPattern.cap(1).trimmed(); return IfdefSection; } if (m_ifndefPattern.exactMatch(in)) { *ifExpression = m_ifndefPattern.cap(1).trimmed(); return IfndefSection; } if (m_elsifPattern.exactMatch(in)) { *ifExpression = m_elsifPattern.cap(1).trimmed(); return ElsifSection; } ifExpression->clear(); if (m_elsePattern.exactMatch(in)) return ElseSection; if (m_endifPattern.exactMatch(in)) return EndifSection; return OtherSection; } enum EvalResult { EvalFalse, EvalTrue, EvalIrrelevant }; static EvalResult evaluateExpressionI(PreprocessorSection ps, QIODevice *inputLog, const QString &expression) { static QSet<QString> otherWS; if (otherWS.isEmpty()) { otherWS.insert("Q_WS_X11"); otherWS.insert("Q_WS_WIN"); otherWS.insert("Q_WS_S60"); otherWS.insert("Q_WS_QWS"); otherWS.insert("Q_WS_MAC"); otherWS.insert("Q_OS_SYMBIAN"); otherWS.insert("Q_WS_WINCE"); otherWS.insert("Q_WS_MAC64"); otherWS.insert("Q_WS_MAC32"); } if (!(expression.contains("Q_WS_") || expression.contains("Q_OS_SYMBIAN"))) return EvalIrrelevant; switch (ps) { case IfdefSection: case IfndefSection: if (expression == "Q_WS_QPA") return ps == IfdefSection ? EvalTrue : EvalFalse; if (otherWS.contains(expression)) return ps == IfdefSection ? EvalFalse : EvalTrue; break; case IfSection: case ElsifSection: { if (expression == "defined(Q_WS_QPA)" || expression == "defined(Q_WS_QWS) || defined(Q_WS_QPA)") return EvalTrue; if (expression == "!defined(Q_WS_QPA)") return EvalFalse; static QRegExp definedRE("defined *\\(*([^\\s())]+)\\)*"); static QRegExp notDefinedRE("!defined *\\(*([^\\s())]+)\\)*"); Q_ASSERT(definedRE.isValid() && notDefinedRE.isValid()); if (definedRE.exactMatch(expression)) { if (definedRE.cap(1) == "Q_WS_QPA") return EvalTrue; if (otherWS.contains(definedRE.cap(1))) return EvalFalse; } else if (notDefinedRE.exactMatch(expression)) { if (definedRE.cap(1) == "Q_WS_QPA") return EvalFalse; if (otherWS.contains(notDefinedRE.cap(1))) return EvalTrue; } } break; default: break; } // Ask user to enter int er = -1; static QMap<QString, EvalResult > cache; if (cache.contains(expression)) return cache.value(expression); while (true) { printf("\nPlease enter for expression '%s'\n" "0 : Evaluates to false\n" "1 : Evaluates to true\n" "2 : Irrelevant to the WS change, leave code as is\n", qPrintable(expression)); int input = 0; do { input = getc(stdin); } while (input == '\n' || input == '\r'); er = input - '0'; if (er >= 0 && er <= EvalIrrelevant) { cache.insert(expression, (EvalResult)er); if (inputLog) { inputLog->putChar(char(er) + '0'); inputLog->putChar('\n'); } break; } } return (EvalResult)er; } static EvalResult evaluateExpression(PreprocessorSection ps, QIODevice *inputLog, const QString &expression) { const EvalResult er = evaluateExpressionI(ps,inputLog, expression); printf("Using: %d for '%s' of type %d\n", er, qPrintable(expression), ps); return er; } unsigned PreprocessContext::process(QIODevice &in, QIODevice &out, QIODevice *inputLog, QString *errorMessage) { unsigned removedLines = 0; reset(); const QChar newLine = QLatin1Char('\n'); while (true) { const QByteArray lineBA = in.readLine(); if (lineBA.isEmpty()) break; // Needs an element of the stack (be it dummy, else something is wrong). if (m_sectionStack.isEmpty()) { *errorMessage = "Empty stack"; return false; } QString expression; bool expressionValue = false; bool printLine = true; QString line = QLatin1String(lineBA); const int nlPos = line.lastIndexOf(newLine); if (nlPos != -1) line.truncate(nlPos); const PreprocessorSection section = preprocessorLine(line, &expression); PreprocessStackEntry &top = m_sectionStack.back(); switch (section) { case IfSection: case IfdefSection: case IfndefSection: { EvalResult er = EvalIrrelevant; // evaluateExpression(section ,expression); bool parentEnabled = top.parentEnabled && top.condition; if (parentEnabled) { er = evaluateExpression(section, inputLog, expression); expressionValue = er == EvalIrrelevant || er == EvalTrue; } if (debug) qDebug() << "IF t=" << section << "ex=" << expression << "er=" << er << "v=" << expressionValue; printLine = parentEnabled && er == EvalIrrelevant; PreprocessStackEntry pe(section, parentEnabled, expressionValue, expressionValue, er != EvalIrrelevant); m_sectionStack.push(pe); } break; case ElsifSection: top.section = ElsifSection; // ignore consecutive '@elsifs' once something matched if (top.parentEnabled) { if (top.wsExpression) { printLine = false; if (top.anyIfClauseMatched) { top.condition = false; } else { EvalResult er = evaluateExpression(section, inputLog, expression); top.condition = er == EvalIrrelevant || er == EvalTrue; if (top.condition) top.anyIfClauseMatched = true; } } } else { printLine = false; } break; case ElseSection: if (top.parentEnabled) { if (top.wsExpression) { top.condition = !top.anyIfClauseMatched; printLine = false; } } else { printLine = false; } top.section = ElseSection; if (debug) qDebug() << "ELSE tope=" << top.parentEnabled << "v=" << expressionValue << "ws=" << top.wsExpression << "any if=" << top.anyIfClauseMatched; break; case EndifSection: if (top.wsExpression || !top.parentEnabled) printLine = false; m_sectionStack.pop(); break; case OtherSection: // Rest: Append according to current condition. printLine = top.condition; break; } // switch section if (printLine) { out.write(lineBA); } else { removedLines++; } } // for lines return removedLines; } int processFiles(const QStringList &files, QFile *inputLog = 0) { PreprocessContext ctx; QString errorMessage; foreach (const QString &file, files) { if (file.isEmpty()) { qWarning("Empty file specified"); continue; } printf("#### Processing: '%s'\n", qPrintable(file)); QFile inFile(file); if (!inFile.open(QIODevice::ReadOnly|QIODevice::Text)) { qWarning("Cannot open %s: %s", qPrintable(file), qPrintable(inFile.errorString())); continue; } QTemporaryFile outFile; if (!outFile.open()) { qWarning("Cannot open %s: %s", qPrintable(outFile.fileName()), qPrintable(outFile.errorString())); return -2; } if (const unsigned removedLines = ctx.process(inFile, outFile, inputLog, &errorMessage)) { printf("#### %u modifications in '%s'\n", removedLines, qPrintable(file)); } else { printf("#### '%s' not modified\n", qPrintable(file)); continue; } inFile.close(); outFile.close(); if (!inFile.remove()) { qWarning("Cannot remove %s: %s", qPrintable(file), qPrintable(inFile.errorString())); continue; } if (!QFile::copy(outFile.fileName(), file)) { qWarning("Cannot copy %s to %s", qPrintable(outFile.fileName()), qPrintable(file)); continue; } if (!outFile.remove()) { qWarning("Cannot remove %s %s", qPrintable(outFile.fileName()), qPrintable(outFile.errorString())); } } return 0; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); if (argc < 2) return -1; QStringList arguments = a.arguments(); arguments.pop_front(); QScopedPointer<QFile> inputLog; if (arguments.size() >= 2 && arguments.at(0) == "-l") { inputLog.reset(new QFile(arguments.at(1))); if (!inputLog->open(QIODevice::WriteOnly|QIODevice::Text)) { qWarning("Cannot open %s: %s", qPrintable(inputLog->fileName()), qPrintable(inputLog->errorString())); return -1; } printf("Logging to %s\n", qPrintable(inputLog->fileName())); arguments.pop_front(); arguments.pop_front(); } // List of files with -f QStringList files; if (arguments.size() == 2 && arguments.at(0) == "-f") { QFile filesListFile(arguments.at(1)); if (!filesListFile.open(QIODevice::ReadOnly|QIODevice::Text)) { qWarning("Cannot open %s: %s", qPrintable(filesListFile.fileName()), qPrintable(filesListFile.errorString())); return -1; } while (true) { const QByteArray fNameBA = filesListFile.readLine(); const QString fName = QString::fromLocal8Bit(fNameBA).trimmed(); if (fName.isEmpty()) break; files.push_back(fName); } printf("%d files from %s\n", files.size(), qPrintable(filesListFile.fileName())); } else { files = arguments; } return processFiles(files, inputLog.data()); }
_______________________________________________ Qt5-feedback mailing list Qt5-feedback@qt.nokia.com http://lists.qt.nokia.com/mailman/listinfo/qt5-feedback