From 51e6fc9416aa540e61498dbfe2a5ee5e74533712 Mon Sep 17 00:00:00 2001 From: Daniel Teske Date: Wed, 4 Mar 2015 17:14:28 +0100 Subject: [PATCH] Fix importing creating additional kits on OS X Extract the whole makefile parsing code into a separate class, to make the code more manageable. Also fix some bugs on importing additional flags like qt quick compiler or separate debug info. Task-number: QTCREATORBUG-13947 Change-Id: Id04bff191c188f95230274d990b1676e9b2f419d Reviewed-by: Eike Ziller Reviewed-by: Daniel Teske --- .../qmakeprojectmanager/makefileparse.cpp | 394 ++++++++++++++++++ .../qmakeprojectmanager/makefileparse.h | 103 +++++ .../qmakebuildconfiguration.cpp | 257 +++++------- .../qmakebuildconfiguration.h | 3 - .../qmakeprojectmanager/qmakebuildinfo.h | 5 +- .../qmakeprojectimporter.cpp | 131 ++++-- .../qmakeprojectimporter.h | 4 +- .../qmakeprojectmanager.pro | 4 +- .../qmakeprojectmanagerconstants.h | 5 - src/plugins/qmakeprojectmanager/qmakestep.cpp | 109 ++++- src/plugins/qmakeprojectmanager/qmakestep.h | 57 ++- src/plugins/qtsupport/qtversionmanager.cpp | 238 ----------- src/plugins/qtsupport/qtversionmanager.h | 5 - 13 files changed, 857 insertions(+), 458 deletions(-) create mode 100644 src/plugins/qmakeprojectmanager/makefileparse.cpp create mode 100644 src/plugins/qmakeprojectmanager/makefileparse.h diff --git a/src/plugins/qmakeprojectmanager/makefileparse.cpp b/src/plugins/qmakeprojectmanager/makefileparse.cpp new file mode 100644 index 0000000000..6749fa4a22 --- /dev/null +++ b/src/plugins/qmakeprojectmanager/makefileparse.cpp @@ -0,0 +1,394 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "makefileparse.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace QmakeProjectManager; +using namespace Internal; + +using Utils::FileName; +using Utils::QtcProcess; +using QtSupport::QtVersionManager; +using QtSupport::BaseQtVersion; + +static QString findQMakeLine(const QString &makefile, const QString &key) +{ + QFile fi(makefile); + if (fi.exists() && fi.open(QFile::ReadOnly)) { + QTextStream ts(&fi); + while (!ts.atEnd()) { + const QString line = ts.readLine(); + if (line.startsWith(key)) + return line; + } + } + return QString(); +} + +/// This function trims the "#Command /path/to/qmake" from the line +static QString trimLine(const QString &line) +{ + + // Actually the first space after #Command: /path/to/qmake + const int firstSpace = line.indexOf(QLatin1Char(' '), 11); + return line.mid(firstSpace).trimmed(); +} + +void MakeFileParse::parseArgs(const QString &args, QList *assignments, QList *afterAssignments) +{ + QRegExp regExp(QLatin1String("([^\\s\\+-]*)\\s*(\\+=|=|-=|~=)(.*)")); + bool after = false; + bool ignoreNext = false; + m_unparsedArguments = args; + QtcProcess::ArgIterator ait(&m_unparsedArguments); + while (ait.next()) { + if (ignoreNext) { + // Ignoring + ignoreNext = false; + ait.deleteArg(); + } else if (ait.value() == QLatin1String("-after")) { + after = true; + ait.deleteArg(); + } else if (ait.value().contains(QLatin1Char('='))) { + if (regExp.exactMatch(ait.value())) { + QMakeAssignment qa; + qa.variable = regExp.cap(1); + qa.op = regExp.cap(2); + qa.value = regExp.cap(3).trimmed(); + if (after) + afterAssignments->append(qa); + else + assignments->append(qa); + } else { + qDebug()<<"regexp did not match"; + } + ait.deleteArg(); + } else if (ait.value() == QLatin1String("-o")) { + ignoreNext = true; + ait.deleteArg(); +#if defined(Q_OS_WIN32) + } else if (ait.value() == QLatin1String("-win32")) { +#elif defined(Q_OS_MAC) + } else if (ait.value() == QLatin1String("-macx")) { +#elif defined(Q_OS_QNX6) + } else if (ait.value() == QLatin1String("-qnx6")) { +#else + } else if (ait.value() == QLatin1String("-unix")) { +#endif + ait.deleteArg(); + } + } + ait.deleteArg(); // The .pro file is always the last arg +} + +void dumpQMakeAssignments(const QList &list) +{ + foreach (const QMakeAssignment &qa, list) { + qCDebug(MakeFileParse::logging()) << " " << qa.variable << qa.op << qa.value; + } +} + +void MakeFileParse::parseAssignments(QList *assignments) +{ + bool foundSeparateDebugInfo = false; + bool foundForceDebugInfo = false; + QList oldAssignments = *assignments; + assignments->clear(); + foreach (const QMakeAssignment &qa, oldAssignments) { + if (qa.variable == QLatin1String("CONFIG")) { + QStringList values = qa.value.split(QLatin1Char(' ')); + QStringList newValues; + foreach (const QString &value, values) { + if (value == QLatin1String("debug")) { + if (qa.op == QLatin1String("+=")) { + m_qmakeBuildConfig.explicitDebug = true; + m_qmakeBuildConfig.explicitRelease = false; + } else { + m_qmakeBuildConfig.explicitDebug = false; + m_qmakeBuildConfig.explicitRelease = true; + } + } else if (value == QLatin1String("release")) { + if (qa.op == QLatin1String("+=")) { + m_qmakeBuildConfig.explicitDebug = false; + m_qmakeBuildConfig.explicitRelease = true; + } else { + m_qmakeBuildConfig.explicitDebug = true; + m_qmakeBuildConfig.explicitRelease = false; + } + } else if (value == QLatin1String("debug_and_release")) { + if (qa.op == QLatin1String("+=")) { + m_qmakeBuildConfig.explicitBuildAll = true; + m_qmakeBuildConfig.explicitNoBuildAll = false; + } else { + m_qmakeBuildConfig.explicitBuildAll = false; + m_qmakeBuildConfig.explicitNoBuildAll = true; + } + } else if (value == QLatin1String("x86")) { + if (qa.op == QLatin1String("+=")) + m_config.archConfig = QMakeStepConfig::X86; + else + m_config.archConfig = QMakeStepConfig::NoArch; + } else if (value == QLatin1String("x86_64")) { + if (qa.op == QLatin1String("+=")) + m_config.archConfig = QMakeStepConfig::X86_64; + else + m_config.archConfig = QMakeStepConfig::NoArch; + } else if (value == QLatin1String("ppc")) { + if (qa.op == QLatin1String("+=")) + m_config.archConfig = QMakeStepConfig::PPC; + else + m_config.archConfig = QMakeStepConfig::NoArch; + } else if (value == QLatin1String("ppc64")) { + if (qa.op == QLatin1String("+=")) + m_config.archConfig = QMakeStepConfig::PPC64; + else + m_config.archConfig = QMakeStepConfig::NoArch; + } else if (value == QLatin1String("iphonesimulator")) { + if (qa.op == QLatin1String("+=")) + m_config.osType = QMakeStepConfig::IphoneSimulator; + else + m_config.osType = QMakeStepConfig::NoOsType; + } else if (value == QLatin1String("iphoneos")) { + if (qa.op == QLatin1String("+=")) + m_config.osType = QMakeStepConfig::IphoneOS; + else + m_config.osType = QMakeStepConfig::NoOsType; + } else if (value == QLatin1String("declarative_debug")) { + if (qa.op == QLatin1String("+=")) + m_config.linkQmlDebuggingQQ1 = true; + else + m_config.linkQmlDebuggingQQ1 = false; + } else if (value == QLatin1String("qml_debug")) { + if (qa.op == QLatin1String("+=")) + m_config.linkQmlDebuggingQQ2 = true; + else + m_config.linkQmlDebuggingQQ2 = false; + } else if (value == QLatin1String("qtquickcompiler")) { + if (qa.op == QLatin1String("+=")) + m_config.useQtQuickCompiler = true; + else + m_config.useQtQuickCompiler = false; + } else if (value == QLatin1String("force_debug_info")) { + if (qa.op == QLatin1String("+=")) + foundForceDebugInfo = true; + else + foundForceDebugInfo = false; + } else if (value == QLatin1String("separate_debug_info")) { + if (qa.op == QLatin1String("+=")) + foundSeparateDebugInfo = true; + else + foundSeparateDebugInfo = false; + } else { + newValues.append(value); + } + QMakeAssignment newQA = qa; + newQA.value = newValues.join(QLatin1Char(' ')); + if (!newValues.isEmpty()) + assignments->append(newQA); + } + } else { + assignments->append(qa); + } + } + + if (foundForceDebugInfo && foundSeparateDebugInfo) { + m_config.separateDebugInfo = true; + } else if (foundForceDebugInfo) { + // Found only force_debug_info, so readd it + QMakeAssignment newQA; + newQA.variable = QLatin1String("CONFIG"); + newQA.op = QLatin1String("+="); + newQA.value = QLatin1String("force_debug_info"); + assignments->append(newQA); + } else if (foundSeparateDebugInfo) { + // Found only separate_debug_info, so readd it + QMakeAssignment newQA; + newQA.variable = QLatin1String("CONFIG"); + newQA.op = QLatin1String("+="); + newQA.value = QLatin1String("separate_debug_info"); + assignments->append(newQA); + } +} + +static FileName findQMakeBinaryFromMakefile(const QString &makefile) +{ + bool debugAdding = false; + QFile fi(makefile); + if (fi.exists() && fi.open(QFile::ReadOnly)) { + QTextStream ts(&fi); + QRegExp r1(QLatin1String("QMAKE\\s*=(.*)")); + while (!ts.atEnd()) { + QString line = ts.readLine(); + if (r1.exactMatch(line)) { + if (debugAdding) + qDebug()<<"#~~ QMAKE is:"< assignments; + QList afterAssignments; + // Split up args into assignments and other arguments, writes m_unparsedArguments + parseArgs(line, &assignments, &afterAssignments); + qCDebug(logging()) << " Initial assignments:"; + dumpQMakeAssignments(assignments); + + // Filter out CONFIG arguments we know into m_qmakeBuildConfig and m_config + parseAssignments(&assignments); + qCDebug(logging()) << " After parsing"; + dumpQMakeAssignments(assignments); + + qCDebug(logging()) << " Explicit Debug" << m_qmakeBuildConfig.explicitDebug; + qCDebug(logging()) << " Explicit Release" << m_qmakeBuildConfig.explicitRelease; + qCDebug(logging()) << " Explicit BuildAll" << m_qmakeBuildConfig.explicitBuildAll; + qCDebug(logging()) << " Explicit NoBuildAll" << m_qmakeBuildConfig.explicitNoBuildAll; + qCDebug(logging()) << " TargetArch" << m_config.archConfig; + qCDebug(logging()) << " OsType" << m_config.osType; + qCDebug(logging()) << " LinkQmlDebuggingQQ1" << m_config.linkQmlDebuggingQQ1; + qCDebug(logging()) << " LinkQmlDebuggingQQ2" << m_config.linkQmlDebuggingQQ2; + qCDebug(logging()) << " Qt Quick Compiler" << m_config.useQtQuickCompiler; + qCDebug(logging()) << " Separate Debug Info" << m_config.separateDebugInfo; + + + // Create command line of all unfiltered arguments + foreach (const QMakeAssignment &qa, assignments) + QtcProcess::addArg(&m_unparsedArguments, qa.variable + qa.op + qa.value); + if (!afterAssignments.isEmpty()) { + QtcProcess::addArg(&m_unparsedArguments, QLatin1String("-after")); + foreach (const QMakeAssignment &qa, afterAssignments) + QtcProcess::addArg(&m_unparsedArguments, qa.variable + qa.op + qa.value); + } + m_state = Okay; +} + +MakeFileParse::MakefileState MakeFileParse::makeFileState() const +{ + return m_state; +} + +Utils::FileName MakeFileParse::qmakePath() const +{ + return m_qmakePath; +} + +QString MakeFileParse::srcProFile() const +{ + return m_srcProFile; +} + +QMakeStepConfig MakeFileParse::config() const +{ + return m_config; +} + + +QString MakeFileParse::unparsedArguments() const +{ + return m_unparsedArguments; +} + +BaseQtVersion::QmakeBuildConfigs MakeFileParse::effectiveBuildConfig(BaseQtVersion::QmakeBuildConfigs defaultBuildConfig) const +{ + BaseQtVersion::QmakeBuildConfigs buildConfig = defaultBuildConfig; + if (m_qmakeBuildConfig.explicitDebug) + buildConfig = buildConfig & BaseQtVersion::DebugBuild; + else if (m_qmakeBuildConfig.explicitRelease) + buildConfig = buildConfig & ~BaseQtVersion::DebugBuild; + if (m_qmakeBuildConfig.explicitBuildAll) + buildConfig = buildConfig & BaseQtVersion::BuildAll; + else if (m_qmakeBuildConfig.explicitNoBuildAll) + buildConfig = buildConfig &~ BaseQtVersion::BuildAll; + return buildConfig; +} + +const QLoggingCategory &MakeFileParse::logging() +{ + static const QLoggingCategory category("qtc.qmakeprojectmanager.import"); + return category; +} + diff --git a/src/plugins/qmakeprojectmanager/makefileparse.h b/src/plugins/qmakeprojectmanager/makefileparse.h new file mode 100644 index 0000000000..a5690929aa --- /dev/null +++ b/src/plugins/qmakeprojectmanager/makefileparse.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** 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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef MAKEFILEPARSE_H +#define MAKEFILEPARSE_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QLogggingCategory; +QT_END_NAMESPACE + +namespace QmakeProjectManager { +namespace Internal { + +struct QMakeAssignment +{ + QString variable; + QString op; + QString value; +}; + +class MakeFileParse +{ +public: + MakeFileParse(const QString &makefile); + + enum MakefileState { MakefileMissing, CouldNotParse, Okay }; + + MakefileState makeFileState() const; + Utils::FileName qmakePath() const; + QString srcProFile() const; + QMakeStepConfig config() const; + + QString unparsedArguments() const; + + QtSupport::BaseQtVersion::QmakeBuildConfigs + effectiveBuildConfig(QtSupport::BaseQtVersion::QmakeBuildConfigs defaultBuildConfig) const; + + static const QLoggingCategory &logging(); + +private: + void parseArgs(const QString &args, QList *assignments, QList *afterAssignments); + void parseAssignments(QList *assignments); + + class QmakeBuildConfig + { + public: + QmakeBuildConfig() + : explicitDebug(false), + explicitRelease(false), + explicitBuildAll(false), + explicitNoBuildAll(false) + {} + bool explicitDebug; + bool explicitRelease; + bool explicitBuildAll; + bool explicitNoBuildAll; + }; + + MakefileState m_state; + Utils::FileName m_qmakePath; + QString m_srcProFile; + + QmakeBuildConfig m_qmakeBuildConfig; + QMakeStepConfig m_config; + QString m_unparsedArguments; +}; + +} // namespace Internal +} // namespace QmakeProjectManager + + +#endif // MAKEFILEPARSE_H diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp index fe638e69ae..1dd793b1b5 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp @@ -38,6 +38,7 @@ #include "qmakenodes.h" #include "qmakestep.h" #include "makestep.h" +#include "makefileparse.h" #include #include @@ -59,6 +60,7 @@ #include #include +#include #include @@ -329,105 +331,116 @@ MakeStep *QmakeBuildConfiguration::makeStep() const // Returns true if both are equal. QmakeBuildConfiguration::MakefileState QmakeBuildConfiguration::compareToImportFrom(const QString &makefile) { + const QLoggingCategory &logs = MakeFileParse::logging(); + qCDebug(logs) << "QMakeBuildConfiguration::compareToImport"; + QMakeStep *qs = qmakeStep(); - if (QFileInfo::exists(makefile) && qs) { - FileName qmakePath = QtVersionManager::findQMakeBinaryFromMakefile(makefile); - BaseQtVersion *version = QtKitInformation::qtVersion(target()->kit()); - if (!version) - return MakefileForWrongProject; - if (QtSupport::QtVersionManager::makefileIsFor(makefile, qs->project()->projectFilePath().toString()) - != QtSupport::QtVersionManager::SameProject) { - if (debug) { - qDebug() << "different profile used to generate the Makefile:" - << makefile << " expected profile:" << qs->project()->projectFilePath(); - } - return MakefileIncompatible; - } - if (version->qmakeCommand() == qmakePath) { - // same qtversion - QPair result = - QtVersionManager::scanMakeFile(makefile, version->defaultBuildConfig()); - if (qmakeBuildConfiguration() == result.first) { - // The qmake Build Configuration are the same, - // now compare arguments lists - // we have to compare without the spec/platform cmd argument - // and compare that on its own - QString workingDirectory = QFileInfo(makefile).absolutePath(); - QStringList actualArgs; - QString userArgs = qs->userArguments(); - // This copies the settings from userArgs to actualArgs (minus some we - // are not interested in), splitting them up into individual strings: - extractSpecFromArguments(&userArgs, workingDirectory, version, &actualArgs); - actualArgs = qs->deducedArguments() + actualArgs; - FileName actualSpec = qs->mkspec(); - - QString qmakeArgs = result.second; - QStringList parsedArgs; - FileName parsedSpec = extractSpecFromArguments(&qmakeArgs, workingDirectory, version, &parsedArgs); - - if (debug) { - qDebug() << "Actual args:" << actualArgs; - qDebug() << "Parsed args:" << parsedArgs; - qDebug() << "Actual spec:" << actualSpec.toString(); - qDebug() << "Parsed spec:" << parsedSpec.toString(); - } - - // Comparing the sorted list is obviously wrong - // Though haven written a more complete version - // that managed had around 200 lines and yet faild - // to be actually foolproof at all, I think it's - // not feasible without actually taking the qmake - // command line parsing code - - // Things, sorting gets wrong: - // parameters to positional parameters matter - // e.g. -o -spec is different from -spec -o - // -o 1 -spec 2 is diffrent from -spec 1 -o 2 - // variable assignment order matters - // variable assignment vs -after - // -norecursive vs. recursive - actualArgs.sort(); - parsedArgs.sort(); - if (actualArgs == parsedArgs) { - // Specs match exactly - if (actualSpec == parsedSpec) - return MakefileMatches; - // Actual spec is the default one -// qDebug() << "AS vs VS" << actualSpec << version->mkspec(); - if ((actualSpec == version->mkspec() || actualSpec == FileName::fromLatin1("default")) - && (parsedSpec == version->mkspec() || parsedSpec == FileName::fromLatin1("default") || parsedSpec.isEmpty())) - return MakefileMatches; - } - return MakefileIncompatible; - } else { - if (debug) - qDebug() << "different qmake buildconfigurations buildconfiguration:" - << qmakeBuildConfiguration() << " Makefile:" << result.first; - return MakefileIncompatible; - } - } else { - if (debug) - qDebug() << "different Qt versions, buildconfiguration:" << version->qmakeCommand().toString() - << " Makefile:"<< qmakePath.toString(); - return MakefileForWrongProject; - } + MakeFileParse parse(makefile); + + if (parse.makeFileState() == MakeFileParse::MakefileMissing) { + qCDebug(logs) << "**Makefile missing"; + return MakefileMissing; + } + if (parse.makeFileState() == MakeFileParse::CouldNotParse) { + qCDebug(logs) << "**Makefile incompatible"; + return MakefileIncompatible; } - return MakefileMissing; -} -bool QmakeBuildConfiguration::removeQMLInspectorFromArguments(QString *args) -{ - bool removedArgument = false; - for (QtcProcess::ArgIterator ait(args); ait.next(); ) { - const QString arg = ait.value(); - if (arg.contains(QLatin1String(Constants::QMAKEVAR_QMLJSDEBUGGER_PATH)) - || arg.contains(QLatin1String(Constants::QMAKEVAR_QUICK1_DEBUG)) - || arg.contains(QLatin1String(Constants::QMAKEVAR_QUICK2_DEBUG))) { - ait.deleteArg(); - removedArgument = true; - } + if (!qs) { + qCDebug(logs) << "**No qmake step"; + return MakefileMissing; + } + + BaseQtVersion *version = QtKitInformation::qtVersion(target()->kit()); + if (!version) { + qCDebug(logs) << "**No qt version in kit"; + return MakefileForWrongProject; + } + + if (parse.srcProFile() != qs->project()->projectFilePath().toString()) { + qCDebug(logs) << "**Different profile used to generate the Makefile:" + << parse.srcProFile() << " expected profile:" << qs->project()->projectFilePath(); + return MakefileIncompatible; + } + + if (version->qmakeCommand() != parse.qmakePath()) { + qCDebug(logs) << "**Different Qt versions, buildconfiguration:" << version->qmakeCommand().toString() + << " Makefile:"<< parse.qmakePath().toString(); + return MakefileForWrongProject; + } + + // same qtversion + BaseQtVersion::QmakeBuildConfigs buildConfig = parse.effectiveBuildConfig(version->defaultBuildConfig()); + if (qmakeBuildConfiguration() != buildConfig) { + qCDebug(logs) << "**Different qmake buildconfigurations buildconfiguration:" + << qmakeBuildConfiguration() << " Makefile:" << buildConfig; + return MakefileIncompatible; + } + + // The qmake Build Configuration are the same, + // now compare arguments lists + // we have to compare without the spec/platform cmd argument + // and compare that on its own + QString workingDirectory = QFileInfo(makefile).absolutePath(); + QStringList actualArgs; + QString userArgs = qs->userArguments(); + // This copies the settings from userArgs to actualArgs (minus some we + // are not interested in), splitting them up into individual strings: + extractSpecFromArguments(&userArgs, workingDirectory, version, &actualArgs); + FileName actualSpec = qs->mkspec(); + + QString qmakeArgs = parse.unparsedArguments(); + QStringList parsedArgs; + FileName parsedSpec = extractSpecFromArguments(&qmakeArgs, workingDirectory, version, &parsedArgs); + + qCDebug(logs) << " Actual args:" << actualArgs; + qCDebug(logs) << " Parsed args:" << parsedArgs; + qCDebug(logs) << " Actual spec:" << actualSpec.toString(); + qCDebug(logs) << " Parsed spec:" << parsedSpec.toString(); + qCDebug(logs) << " Actual config:" << qs->deducedArguments(); + qCDebug(logs) << " Parsed config:" << parse.config(); + + // Comparing the sorted list is obviously wrong + // Though haven written a more complete version + // that managed had around 200 lines and yet faild + // to be actually foolproof at all, I think it's + // not feasible without actually taking the qmake + // command line parsing code + + // Things, sorting gets wrong: + // parameters to positional parameters matter + // e.g. -o -spec is different from -spec -o + // -o 1 -spec 2 is diffrent from -spec 1 -o 2 + // variable assignment order matters + // variable assignment vs -after + // -norecursive vs. recursive + actualArgs.sort(); + parsedArgs.sort(); + if (actualArgs != parsedArgs) { + qCDebug(logs) << "**Mismateched args"; + return MakefileIncompatible; } - return removedArgument; + + if (parse.config() != qs->deducedArguments()) { + qCDebug(logs) << "**Mismatched config"; + return MakefileIncompatible; + } + + // Specs match exactly + if (actualSpec == parsedSpec) { + qCDebug(logs) << "**Matched specs (1)"; + return MakefileMatches; + } + // Actual spec is the default one +// qDebug() << "AS vs VS" << actualSpec << version->mkspec(); + if ((actualSpec == version->mkspec() || actualSpec == FileName::fromLatin1("default")) + && (parsedSpec == version->mkspec() || parsedSpec == FileName::fromLatin1("default") || parsedSpec.isEmpty())) { + qCDebug(logs) << "**Matched specs (2)"; + return MakefileMatches; + } + + qCDebug(logs) << "**Incompatible specs"; + return MakefileIncompatible; } FileName QmakeBuildConfiguration::extractSpecFromArguments(QString *args, @@ -499,52 +512,6 @@ FileName QmakeBuildConfiguration::extractSpecFromArguments(QString *args, return parsedSpec; } -QStringList QmakeBuildConfiguration::extractDeducedArguments(QString *args) -{ - QStringList allPossibleDeducedArguments; - allPossibleDeducedArguments << QLatin1String("CONFIG+=x86") - << QLatin1String("CONFIG+=x86_64") - << QLatin1String("CONFIG+=iphonesimulator") - << QLatin1String("CONFIG+=ppc") - << QLatin1String("CONFIG+=ppc64") - << QLatin1String("CONFIG+=iphoneos"); - QStringList result; - for (QtcProcess::ArgIterator ait(args); ait.next(); ) { - QString arg = ait.value(); - if (allPossibleDeducedArguments.contains(arg)) { - result << arg; - ait.deleteArg(); - } - } - return result; -} - -QStringList QmakeBuildConfiguration::deduceArgumentsForTargetAbi(const ProjectExplorer::Abi &targetAbi, const BaseQtVersion *version) -{ - QStringList arguments; - if ((targetAbi.os() == ProjectExplorer::Abi::MacOS) - && (targetAbi.binaryFormat() == ProjectExplorer::Abi::MachOFormat)) { - if (targetAbi.architecture() == ProjectExplorer::Abi::X86Architecture) { - if (targetAbi.wordWidth() == 32) - arguments << QLatin1String("CONFIG+=x86"); - else if (targetAbi.wordWidth() == 64) - arguments << QLatin1String("CONFIG+=x86_64"); - - const char IOSQT[] = "Qt4ProjectManager.QtVersion.Ios"; - if (version && version->type() == QLatin1String(IOSQT)) // ugly, we can't distinguish between ios and mac toolchains - arguments << QLatin1String("CONFIG+=iphonesimulator"); - } else if (targetAbi.architecture() == ProjectExplorer::Abi::PowerPCArchitecture) { - if (targetAbi.wordWidth() == 32) - arguments << QLatin1String("CONFIG+=ppc"); - else if (targetAbi.wordWidth() == 64) - arguments << QLatin1String("CONFIG+=ppc64"); - } else if (targetAbi.architecture() == ProjectExplorer::Abi::ArmArchitecture) { - arguments << QLatin1String("CONFIG+=iphoneos"); - } - } - return arguments; -} - bool QmakeBuildConfiguration::isEnabled() const { return m_isEnabled; @@ -702,13 +669,13 @@ void QmakeBuildConfigurationFactory::configureBuildConfiguration(Target *parent, cleanSteps->insertStep(0, cleanStep); QString additionalArguments = qmakeInfo->additionalArguments; - - bool enableQmlDebugger - = QmakeBuildConfiguration::removeQMLInspectorFromArguments(&additionalArguments); if (!additionalArguments.isEmpty()) qmakeStep->setUserArguments(additionalArguments); if (!qmakeInfo->makefile.isEmpty()) - qmakeStep->setLinkQmlDebuggingLibrary(enableQmlDebugger); + qmakeStep->setLinkQmlDebuggingLibrary(qmakeInfo->config.linkQmlDebuggingQQ1 + || qmakeInfo->config.linkQmlDebuggingQQ2); + qmakeStep->setSeparateDebugInfo(qmakeInfo->config.separateDebugInfo); + qmakeStep->setUseQtQuickCompiler(qmakeInfo->config.useQtQuickCompiler); bc->setQMakeBuildConfiguration(config); diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h index 112e8f10db..f47c551451 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h @@ -92,12 +92,9 @@ public: enum MakefileState { MakefileMatches, MakefileForWrongProject, MakefileIncompatible, MakefileMissing }; MakefileState compareToImportFrom(const QString &makefile); - static bool removeQMLInspectorFromArguments(QString *args); static Utils::FileName extractSpecFromArguments(QString *arguments, const QString &directory, const QtSupport::BaseQtVersion *version, QStringList *outArgs = 0); - static QStringList extractDeducedArguments(QString *args); - static QStringList deduceArgumentsForTargetAbi(const ProjectExplorer::Abi &targetAbi, const QtSupport::BaseQtVersion *version); QVariantMap toMap() const; diff --git a/src/plugins/qmakeprojectmanager/qmakebuildinfo.h b/src/plugins/qmakeprojectmanager/qmakebuildinfo.h index 5aa77d1ee7..87f8fe17ce 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildinfo.h +++ b/src/plugins/qmakeprojectmanager/qmakebuildinfo.h @@ -32,6 +32,7 @@ #define QMAKEBUILDINFO_H #include "qmakebuildconfiguration.h" +#include "qmakestep.h" #include #include @@ -48,6 +49,7 @@ public: ProjectExplorer::BuildConfiguration::BuildType type; QString additionalArguments; QString makefile; + QMakeStepConfig config; bool operator==(const QmakeBuildInfo &o) { return displayName == o.displayName @@ -55,7 +57,8 @@ public: && buildDirectory == o.buildDirectory && kitId == o.kitId && type == o.type - && additionalArguments == o.additionalArguments; + && additionalArguments == o.additionalArguments + && config == o.config; } QList reportIssues(const QString &projectPath, diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp index 9f41387929..79d225bb00 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.cpp @@ -34,6 +34,8 @@ #include "qmakekitinformation.h" #include "qmakebuildconfiguration.h" #include "qmakeproject.h" +#include "makefileparse.h" +#include "qmakestep.h" #include #include @@ -52,6 +54,7 @@ #include #include #include +#include using namespace ProjectExplorer; using namespace QtSupport; @@ -61,6 +64,7 @@ namespace QmakeProjectManager { namespace Internal { const Core::Id QT_IS_TEMPORARY("Qmake.TempQt"); +const char IOSQT[] = "Qt4ProjectManager.QtVersion.Ios"; // ugly QmakeProjectImporter::QmakeProjectImporter(const QString &path) : ProjectImporter(path) @@ -68,47 +72,58 @@ QmakeProjectImporter::QmakeProjectImporter(const QString &path) : QList QmakeProjectImporter::import(const FileName &importPath, bool silent) { + const auto &logs = MakeFileParse::logging(); + qCDebug(logs) << "QmakeProjectImporter::import" << importPath << silent; + QList result; QFileInfo fi = importPath.toFileInfo(); - if (!fi.exists() && !fi.isDir()) + if (!fi.exists() && !fi.isDir()) { + qCDebug(logs) << "**doesn't exist"; return result; + } QStringList makefiles = QDir(importPath.toString()).entryList(QStringList(QLatin1String("Makefile*"))); + qCDebug(logs) << " Makefiles:" << makefiles; - BaseQtVersion *version = 0; bool temporaryVersion = false; foreach (const QString &file, makefiles) { + qCDebug(logs) << " Parsing makefile" << file; // find interesting makefiles QString makefile = importPath.toString() + QLatin1Char('/') + file; - FileName qmakeBinary = QtVersionManager::findQMakeBinaryFromMakefile(makefile); - QFileInfo qmakeFi = qmakeBinary.toFileInfo(); + MakeFileParse parse(makefile); + QFileInfo qmakeFi = parse.qmakePath().toFileInfo(); FileName canonicalQmakeBinary = FileName::fromString(qmakeFi.canonicalFilePath()); - if (canonicalQmakeBinary.isEmpty()) + if (canonicalQmakeBinary.isEmpty()) { + qCDebug(logs) << " " << parse.qmakePath() << "doesn't exist anymore"; continue; - if (QtVersionManager::makefileIsFor(makefile, projectFilePath()) != QtVersionManager::SameProject) + } + if (parse.srcProFile() != projectFilePath()) { + qCDebug(logs) << " pro files doesn't match" << parse.srcProFile() << projectFilePath(); continue; - - // Find version: - foreach (BaseQtVersion *v, QtVersionManager::versions()) { - QFileInfo vfi = v->qmakeCommand().toFileInfo(); - FileName current = FileName::fromString(vfi.canonicalFilePath()); - if (current == canonicalQmakeBinary) { - version = v; - break; - } } + qCDebug(logs) << " QMake:" << canonicalQmakeBinary; + + BaseQtVersion *version + = Utils::findOrDefault(QtVersionManager::versions(), + [&canonicalQmakeBinary](BaseQtVersion *v) { + QFileInfo vfi = v->qmakeCommand().toFileInfo(); + FileName current = FileName::fromString(vfi.canonicalFilePath()); + return current == canonicalQmakeBinary; + }); + if (version) { // Check if version is a temporary qt int qtId = version->uniqueId(); temporaryVersion = Utils::anyOf(KitManager::kits(), [&qtId](Kit *k){ return k->value(QT_IS_TEMPORARY, -1).toInt() == qtId; }); + qCDebug(logs) << " qt version already exist. Temporary:" << temporaryVersion; } else { // Create a new version if not found: // Do not use the canonical path here... - version = QtVersionFactory::createQtVersionFromQMakePath(qmakeBinary); + version = QtVersionFactory::createQtVersionFromQMakePath(parse.qmakePath()); if (!version) continue; @@ -116,28 +131,58 @@ QList QmakeProjectImporter::import(const FileName &importPath, bool QtVersionManager::addVersion(version); setIsUpdating(oldIsUpdating); temporaryVersion = true; + qCDebug(logs) << " created new qt version"; } - // find qmake arguments and mkspec - QPair makefileBuildConfig = - QtVersionManager::scanMakeFile(makefile, version->defaultBuildConfig()); + QMakeStepConfig::TargetArchConfig archConfig = parse.config().archConfig; + QMakeStepConfig::OsType osType = parse.config().osType; + qCDebug(logs) << " archConfig:" << archConfig; + qCDebug(logs) << " osType: " << osType; + if (version->type() == QLatin1String(IOSQT) + && osType == QMakeStepConfig::NoOsType) { + osType = QMakeStepConfig::IphoneOS; + qCDebug(logs) << " IOS found without osType, adjusting osType" << osType; + } - QString additionalArguments = makefileBuildConfig.second; + if (version->type() == QLatin1String(Constants::DESKTOPQT)) { + QList abis = version->qtAbis(); + if (!abis.isEmpty()) { + ProjectExplorer::Abi abi = abis.first(); + if (abi.os() == ProjectExplorer::Abi::MacOS) { + if (abi.wordWidth() == 64) + archConfig = QMakeStepConfig::X86_64; + else + archConfig = QMakeStepConfig::X86; + qCDebug(logs) << " OS X found without targetarch, adjusting archType" << archConfig; + } + } + } + + + // find qmake arguments and mkspec + QString additionalArguments = parse.unparsedArguments(); + qCDebug(logs) << " Unparsed arguments:" << additionalArguments; FileName parsedSpec = QmakeBuildConfiguration::extractSpecFromArguments(&additionalArguments, importPath.toString(), version); - QStringList deducedArguments = - QmakeBuildConfiguration::extractDeducedArguments(&additionalArguments); + qCDebug(logs) << " Extracted spec:" << parsedSpec; + qCDebug(logs) << " Arguments now:" << additionalArguments; FileName versionSpec = version->mkspec(); - if (parsedSpec.isEmpty() || parsedSpec == FileName::fromLatin1("default")) + if (parsedSpec.isEmpty() || parsedSpec == FileName::fromLatin1("default")) { parsedSpec = versionSpec; + qCDebug(logs) << " No parsed spec or default spec => parsed spec now:" << parsedSpec; + } QString specArgument; // Compare mkspecs and add to additional arguments - if (parsedSpec != versionSpec) + if (parsedSpec != versionSpec) { specArgument = QLatin1String("-spec ") + QtcProcess::quoteArg(parsedSpec.toUserOutput()); - QtcProcess::addArgs(&specArgument, additionalArguments); + QtcProcess::addArgs(&specArgument, additionalArguments); + qCDebug(logs) << " custom spec added to additionalArguments:" << additionalArguments; + } + qCDebug(logs) << "*******************"; + qCDebug(logs) << "* Looking for kits"; // Find kits (can be more than one, e.g. (Linux-)Desktop and embedded linux): QList kitList; foreach (Kit *k, KitManager::kits()) { @@ -146,17 +191,23 @@ QList QmakeProjectImporter::import(const FileName &importPath, bool ToolChain *tc = ToolChainKitInformation::toolChain(k); if (kitSpec.isEmpty() && kitVersion) kitSpec = kitVersion->mkspecFor(tc); - QStringList kitDeducedArguments; - if (tc) - kitDeducedArguments = QmakeBuildConfiguration::deduceArgumentsForTargetAbi(tc->targetAbi(), kitVersion); - + QMakeStepConfig::TargetArchConfig kitTargetArch = QMakeStepConfig::targetArchFor(tc->targetAbi(), kitVersion); + QMakeStepConfig::OsType kitOsType = QMakeStepConfig::osTypeFor(tc->targetAbi(), kitVersion); + qCDebug(logs) << k->displayName() + << "version:" << (kitVersion == version) + << "spec:" << (kitSpec == parsedSpec) + << "targetarch:" << (kitTargetArch == archConfig) + << "ostype:" << (kitOsType == osType); if (kitVersion == version && kitSpec == parsedSpec - && kitDeducedArguments == deducedArguments) + && kitTargetArch == archConfig + && kitOsType == osType) kitList.append(k); } - if (kitList.isEmpty()) - kitList.append(createTemporaryKit(version, temporaryVersion, parsedSpec, deducedArguments)); + if (kitList.isEmpty()) { + kitList.append(createTemporaryKit(version, temporaryVersion, parsedSpec, archConfig, osType)); + qCDebug(logs) << " No matching kits found, created new kit"; + } foreach (Kit *k, kitList) { addProject(k); @@ -169,7 +220,8 @@ QList QmakeProjectImporter::import(const FileName &importPath, bool // create info: QmakeBuildInfo *info = new QmakeBuildInfo(factory); - if (makefileBuildConfig.first & BaseQtVersion::DebugBuild) { + BaseQtVersion::QmakeBuildConfigs buildConfig = parse.effectiveBuildConfig(version->defaultBuildConfig()); + if (buildConfig & BaseQtVersion::DebugBuild) { info->type = BuildConfiguration::Debug; info->displayName = QCoreApplication::translate("QmakeProjectManager::Internal::QmakeProjectImporter", "Debug"); } else { @@ -179,6 +231,7 @@ QList QmakeProjectImporter::import(const FileName &importPath, bool info->kitId = k->id(); info->buildDirectory = FileName::fromString(fi.absoluteFilePath()); info->additionalArguments = additionalArguments; + info->config = parse.config(); info->makefile = makefile; bool found = false; @@ -289,7 +342,7 @@ void QmakeProjectImporter::makePermanent(Kit *k) ProjectImporter::makePermanent(k); } -static ToolChain *preferredToolChain(BaseQtVersion *qtVersion, const FileName &ms, const QStringList &deducedArguments) +static ToolChain *preferredToolChain(BaseQtVersion *qtVersion, const FileName &ms, const QMakeStepConfig::TargetArchConfig &archConfig) { const FileName spec = ms.isEmpty() ? qtVersion->mkspec() : ms; @@ -297,25 +350,27 @@ static ToolChain *preferredToolChain(BaseQtVersion *qtVersion, const FileName &m QList qtAbis = qtVersion->qtAbis(); return findOr(toolchains, toolchains.isEmpty() ? 0 : toolchains.first(), - [&spec, &deducedArguments, &qtAbis](ToolChain *tc) -> bool{ + [&spec, &archConfig, &qtAbis, &qtVersion](ToolChain *tc) -> bool{ return qtAbis.contains(tc->targetAbi()) && tc->suggestedMkspecList().contains(spec) - && QmakeBuildConfiguration::deduceArgumentsForTargetAbi(tc->targetAbi(), 0) == deducedArguments; + && QMakeStepConfig::targetArchFor(tc->targetAbi(), qtVersion) == archConfig; }); } Kit *QmakeProjectImporter::createTemporaryKit(BaseQtVersion *version, bool temporaryVersion, const FileName &parsedSpec, - const QStringList &deducedQmakeArguments) + const QMakeStepConfig::TargetArchConfig &archConfig, + const QMakeStepConfig::OsType &osType) { + Q_UNUSED(osType); // TODO use this to select the right toolchain? Kit *k = new Kit; bool oldIsUpdating = setIsUpdating(true); { KitGuard guard(k); QtKitInformation::setQtVersion(k, version); - ToolChainKitInformation::setToolChain(k, preferredToolChain(version, parsedSpec, deducedQmakeArguments)); + ToolChainKitInformation::setToolChain(k, preferredToolChain(version, parsedSpec, archConfig)); QmakeKitInformation::setMkspec(k, parsedSpec); markTemporary(k); diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.h b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.h index 2e5336ed18..79c12ffde0 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectimporter.h +++ b/src/plugins/qmakeprojectmanager/qmakeprojectimporter.h @@ -32,6 +32,7 @@ #define QMAKEPROJECTIMPORTER_H #include +#include namespace QtSupport { class BaseQtVersion; } @@ -58,7 +59,8 @@ public: private: ProjectExplorer::Kit *createTemporaryKit(QtSupport::BaseQtVersion *version, bool temporaryVersion, - const Utils::FileName &parsedSpec, const QStringList &deducedQmakeArguments); + const Utils::FileName &parsedSpec, + const QmakeProjectManager::QMakeStepConfig::TargetArchConfig &archConfig, const QMakeStepConfig::OsType &osType); }; } // namespace Internal diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro index af4371dd0a..204ea2adf4 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro @@ -51,7 +51,8 @@ HEADERS += \ findqmakeprofiles.h \ qmakeprojectmanager_global.h \ desktopqmakerunconfiguration.h \ - profilecompletionassist.h + profilecompletionassist.h \ + makefileparse.h SOURCES += \ qmakekitconfigwidget.cpp \ @@ -98,6 +99,7 @@ SOURCES += \ findqmakeprofiles.cpp \ desktopqmakerunconfiguration.cpp \ profilecompletionassist.cpp \ + makefileparse.cpp FORMS += makestep.ui \ qmakestep.ui \ diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerconstants.h b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerconstants.h index 077c55dbf9..15ba074051 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerconstants.h +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerconstants.h @@ -72,11 +72,6 @@ const char QMAKEPROJECT_ID[] = "Qt4ProjectManager.Qt4Project"; // ICONS const char ICON_QTQUICK_APP[] = ":/wizards/images/qtquickapp.png"; -// Env variables -const char QMAKEVAR_QMLJSDEBUGGER_PATH[] = "QMLJSDEBUGGER_PATH"; -const char QMAKEVAR_QUICK1_DEBUG[] = "CONFIG+=declarative_debug"; -const char QMAKEVAR_QUICK2_DEBUG[] = "CONFIG+=qml_debug"; - } // namespace Constants } // namespace QmakeProjectManager diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 76ae18bca0..0f69f809c9 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,7 @@ using namespace QmakeProjectManager; using namespace QmakeProjectManager::Internal; +using namespace QtSupport; using namespace ProjectExplorer; using namespace Utils; @@ -154,7 +156,7 @@ QString QMakeStep::allArguments(bool shorted) // Find out what flags we pass on to qmake arguments << bc->configCommandLineArguments(); - arguments << deducedArguments(); + arguments << deducedArguments().toArguments(); QString args = QtcProcess::joinArgs(arguments); // User arguments @@ -162,40 +164,36 @@ QString QMakeStep::allArguments(bool shorted) return args; } -/// -/// moreArguments, -/// iphoneos/iphonesimulator for ios -/// QMAKE_VAR_QMLJSDEBUGGER_PATH -QStringList QMakeStep::deducedArguments() +QMakeStepConfig QMakeStep::deducedArguments() { - QStringList arguments; + ProjectExplorer::Kit *kit = target()->kit(); + QMakeStepConfig config; ProjectExplorer::ToolChain *tc - = ProjectExplorer::ToolChainKitInformation::toolChain(target()->kit()); + = ProjectExplorer::ToolChainKitInformation::toolChain(kit); ProjectExplorer::Abi targetAbi; if (tc) targetAbi = tc->targetAbi(); - // explicitly add architecture to CONFIG - QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit()); - arguments << QmakeBuildConfiguration::deduceArgumentsForTargetAbi(targetAbi, version); + + config.archConfig = QMakeStepConfig::targetArchFor(targetAbi, version); + config.osType = QMakeStepConfig::osTypeFor(targetAbi, version); if (linkQmlDebuggingLibrary() && version) { - arguments << QLatin1String(Constants::QMAKEVAR_QUICK1_DEBUG); + config.linkQmlDebuggingQQ1 = true; if (version->qtVersion().majorVersion >= 5) - arguments << QLatin1String(Constants::QMAKEVAR_QUICK2_DEBUG); + config.linkQmlDebuggingQQ2 = true; } if (useQtQuickCompiler() && version) - arguments << QLatin1String("CONFIG+=qtquickcompiler"); + config.useQtQuickCompiler = true; - if (separateDebugInfo()) { - arguments << QLatin1String("CONFIG+=force_debug_info") - << QLatin1String("CONFIG+=separate_debug_info"); - } + if (separateDebugInfo()) + config.separateDebugInfo = true; - return arguments; + return config; } + bool QMakeStep::init() { QmakeBuildConfiguration *qt4bc = qmakeBuildConfiguration(); @@ -822,3 +820,76 @@ QString QMakeStepFactory::displayNameForId(Core::Id id) const return tr("qmake"); return QString(); } + + +QMakeStepConfig::TargetArchConfig QMakeStepConfig::targetArchFor(const Abi &targetAbi, const BaseQtVersion *version) +{ + QMakeStepConfig::TargetArchConfig arch = QMakeStepConfig::NoArch; + if (!version || version->type() != QLatin1String(QtSupport::Constants::DESKTOPQT)) + return arch; + if ((targetAbi.os() == ProjectExplorer::Abi::MacOS) + && (targetAbi.binaryFormat() == ProjectExplorer::Abi::MachOFormat)) { + if (targetAbi.architecture() == ProjectExplorer::Abi::X86Architecture) { + if (targetAbi.wordWidth() == 32) + arch = QMakeStepConfig::X86; + else if (targetAbi.wordWidth() == 64) + arch = QMakeStepConfig::X86_64; + } else if (targetAbi.architecture() == ProjectExplorer::Abi::PowerPCArchitecture) { + if (targetAbi.wordWidth() == 32) + arch = QMakeStepConfig::PPC; + else if (targetAbi.wordWidth() == 64) + arch = QMakeStepConfig::PPC64; + } + } + return arch; +} + +QMakeStepConfig::OsType QMakeStepConfig::osTypeFor(const ProjectExplorer::Abi &targetAbi, const BaseQtVersion *version) +{ + QMakeStepConfig::OsType os = QMakeStepConfig::NoOsType; + const char IOSQT[] = "Qt4ProjectManager.QtVersion.Ios"; + if (!version || version->type() != QLatin1String(IOSQT)) + return os; + if ((targetAbi.os() == ProjectExplorer::Abi::MacOS) + && (targetAbi.binaryFormat() == ProjectExplorer::Abi::MachOFormat)) { + if (targetAbi.architecture() == ProjectExplorer::Abi::X86Architecture) { + os = QMakeStepConfig::IphoneSimulator; + } else if (targetAbi.architecture() == ProjectExplorer::Abi::ArmArchitecture) { + os = QMakeStepConfig::IphoneOS; + } + } + return os; +} + +QStringList QMakeStepConfig::toArguments() const +{ + QStringList arguments; + if (archConfig == X86) + arguments << QLatin1String("CONFIG+=x86"); + else if (archConfig == X86_64) + arguments << QLatin1String("CONFIG+=x86_64"); + else if (archConfig == PPC) + arguments << QLatin1String("CONFIG+=ppc"); + else if (archConfig == PPC64) + arguments << QLatin1String("CONFIG+=ppc64"); + + if (osType == IphoneSimulator) + arguments << QLatin1String("CONFIG+=iphonesimulator"); + else if (osType == IphoneOS) + arguments << QLatin1String("CONFIG+=iphoneos"); + + if (linkQmlDebuggingQQ1) + arguments << QLatin1String("CONFIG+=declarative_debug"); + if (linkQmlDebuggingQQ2) + arguments << QLatin1String("CONFIG+=qml_debug"); + + if (useQtQuickCompiler) + arguments << QLatin1String("CONFIG+=qtquickcompiler"); + + if (separateDebugInfo) + arguments << QLatin1String("CONFIG+=force_debug_info") + << QLatin1String("CONFIG+=separate_debug_info"); + + return arguments; +} + diff --git a/src/plugins/qmakeprojectmanager/qmakestep.h b/src/plugins/qmakeprojectmanager/qmakestep.h index 6314533dbf..ea1a9f9f47 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.h +++ b/src/plugins/qmakeprojectmanager/qmakestep.h @@ -39,11 +39,15 @@ namespace Utils { class FileName; } namespace ProjectExplorer { +class Abi; class BuildStep; class IBuildStepFactory; class Project; +class Kit; } +namespace QtSupport { class BaseQtVersion; } + namespace QmakeProjectManager { class QmakeBuildConfiguration; class QmakeProject; @@ -71,6 +75,56 @@ public: } // namespace Internal +class QMAKEPROJECTMANAGER_EXPORT QMakeStepConfig +{ +public: + enum TargetArchConfig { + NoArch, X86, X86_64, PPC, PPC64 + }; + + enum OsType { + NoOsType, IphoneSimulator, IphoneOS + }; + + static TargetArchConfig targetArchFor(const ProjectExplorer::Abi &targetAbi, const QtSupport::BaseQtVersion *version); + static OsType osTypeFor(const ProjectExplorer::Abi &targetAbi, const QtSupport::BaseQtVersion *version); + + + QMakeStepConfig() + : archConfig(NoArch), + osType(NoOsType), + linkQmlDebuggingQQ1(false), + linkQmlDebuggingQQ2(false), + useQtQuickCompiler(false), + separateDebugInfo(false) + {} + + QStringList toArguments() const; + + // Actual data + TargetArchConfig archConfig; + OsType osType; + bool linkQmlDebuggingQQ1; + bool linkQmlDebuggingQQ2; + bool useQtQuickCompiler; + bool separateDebugInfo; +}; + + +inline bool operator ==(const QMakeStepConfig &a, const QMakeStepConfig &b) { + return std::tie(a.archConfig, a.osType, a.linkQmlDebuggingQQ1, a.linkQmlDebuggingQQ2, a.useQtQuickCompiler, a.separateDebugInfo) + == std::tie(b.archConfig, b.osType, b.linkQmlDebuggingQQ1, b.linkQmlDebuggingQQ2, b.useQtQuickCompiler, b.separateDebugInfo); +} + +inline bool operator !=(const QMakeStepConfig &a, const QMakeStepConfig &b) { + return !(a == b); +} + +inline QDebug operator<<(QDebug dbg, const QMakeStepConfig &c) +{ + dbg << c.archConfig << c.osType << c.linkQmlDebuggingQQ1 << c.linkQmlDebuggingQQ2 << c.useQtQuickCompiler << c.separateDebugInfo; + return dbg; +} class QMAKEPROJECTMANAGER_EXPORT QMakeStep : public ProjectExplorer::AbstractProcessStep { @@ -100,8 +154,7 @@ public: // the complete argument line QString allArguments(bool shorted = false); - // deduced arguments e.g. qmljs debugging - QStringList deducedArguments(); + QMakeStepConfig deducedArguments(); // arguments passed to the pro file parser QStringList parserArguments(); // arguments set by the user diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp index ea1e99851b..7513ad40e3 100644 --- a/src/plugins/qtsupport/qtversionmanager.cpp +++ b/src/plugins/qtsupport/qtversionmanager.cpp @@ -64,13 +64,6 @@ namespace QtSupport { using namespace Internal; -struct QMakeAssignment -{ - QString variable; - QString op; - QString value; -}; - const char QTVERSION_DATA_KEY[] = "QtVersion."; const char QTVERSION_TYPE_KEY[] = "QtVersion.Type"; const char QTVERSION_FILE_VERSION_KEY[] = "Version"; @@ -107,36 +100,6 @@ bool qtVersionNumberCompare(BaseQtVersion *a, BaseQtVersion *b) { return a->qtVersion() > b->qtVersion() || (a->qtVersion() == b->qtVersion() && a->uniqueId() < b->uniqueId()); } - -static QString findQMakeLine(const QString &makefile, const QString &key) -{ - QFile fi(makefile); - if (fi.exists() && fi.open(QFile::ReadOnly)) { - QTextStream ts(&fi); - while (!ts.atEnd()) { - const QString line = ts.readLine(); - if (line.startsWith(key)) - return line; - } - } - return QString(); -} - -/// This function trims the "#Command /path/to/qmake" from the line -static QString trimLine(const QString &line) -{ - - // Actually the first space after #Command: /path/to/qmake - const int firstSpace = line.indexOf(QLatin1Char(' '), 11); - return line.mid(firstSpace).trimmed(); -} - -static void parseArgs(const QString &args, - QList *assignments, - QList *afterAssignments, - QString *additionalArguments); -static BaseQtVersion::QmakeBuildConfigs qmakeBuildConfigFromCmdArgs(QList *assignments, - BaseQtVersion::QmakeBuildConfigs defaultBuildConfig); static bool restoreQtVersions(); static void findSystemQt(); static void saveQtVersions(); @@ -608,210 +571,9 @@ void QtVersionManager::setNewQtVersions(QList newVersions) emit m_instance->qtVersionsChanged(addedVersions, removedVersions, changedVersions); } -// Returns the version that was used to build the project in that directory -// That is returns the directory -// To find out whether we already have a qtversion for that directory call -// QtVersion *QtVersionManager::qtVersionForDirectory(const QString directory); -FileName QtVersionManager::findQMakeBinaryFromMakefile(const QString &makefile) -{ - bool debugAdding = false; - QFile fi(makefile); - if (fi.exists() && fi.open(QFile::ReadOnly)) { - QTextStream ts(&fi); - QRegExp r1(QLatin1String("QMAKE\\s*=(.*)")); - while (!ts.atEnd()) { - QString line = ts.readLine(); - if (r1.exactMatch(line)) { - if (debugAdding) - qDebug()<<"#~~ QMAKE is:"< &list) -{ - foreach (const QMakeAssignment &qa, list) { - qDebug()< QtVersionManager::scanMakeFile(const QString &makefile, BaseQtVersion::QmakeBuildConfigs defaultBuildConfig) -{ - if (debug) - qDebug()<<"ScanMakeFile, the gory details:"; - BaseQtVersion::QmakeBuildConfigs result = defaultBuildConfig; - QString result2; - - QString line = findQMakeLine(makefile, QLatin1String("# Command:")); - if (!line.isEmpty()) { - if (debug) - qDebug()<<"Found line"< assignments; - QList afterAssignments; - parseArgs(line, &assignments, &afterAssignments, &result2); - - if (debug) { - dumpQMakeAssignments(assignments); - if (!afterAssignments.isEmpty()) - qDebug()<<"-after"; - dumpQMakeAssignments(afterAssignments); - } - - // Search in assignments for CONFIG(+=,-=,=)(debug,release,debug_and_release) - // Also remove them from the list - result = qmakeBuildConfigFromCmdArgs(&assignments, defaultBuildConfig); - - if (debug) - dumpQMakeAssignments(assignments); - - foreach (const QMakeAssignment &qa, assignments) - QtcProcess::addArg(&result2, qa.variable + qa.op + qa.value); - if (!afterAssignments.isEmpty()) { - QtcProcess::addArg(&result2, QLatin1String("-after")); - foreach (const QMakeAssignment &qa, afterAssignments) - QtcProcess::addArg(&result2, qa.variable + qa.op + qa.value); - } - } - - // Dump the gathered information: - if (debug) { - qDebug()<<"\n\nDumping information from scanMakeFile"; - qDebug()<<"QMake CONFIG variable parsing"; - qDebug()<<" "<< (result & BaseQtVersion::NoBuild ? QByteArray("No Build") : QByteArray::number(int(result))); - qDebug()<<" "<< (result & BaseQtVersion::DebugBuild ? "debug" : "release"); - qDebug()<<" "<< (result & BaseQtVersion::BuildAll ? "debug_and_release" : "no debug_and_release"); - qDebug()<<"\nAddtional Arguments"; - qDebug()< *assignments, QList *afterAssignments, QString *additionalArguments) -{ - QRegExp regExp(QLatin1String("([^\\s\\+-]*)\\s*(\\+=|=|-=|~=)(.*)")); - bool after = false; - bool ignoreNext = false; - *additionalArguments = args; - QtcProcess::ArgIterator ait(additionalArguments); - while (ait.next()) { - if (ignoreNext) { - // Ignoring - ignoreNext = false; - ait.deleteArg(); - } else if (ait.value() == QLatin1String("-after")) { - after = true; - ait.deleteArg(); - } else if (ait.value().contains(QLatin1Char('='))) { - if (regExp.exactMatch(ait.value())) { - QMakeAssignment qa; - qa.variable = regExp.cap(1); - qa.op = regExp.cap(2); - qa.value = regExp.cap(3).trimmed(); - if (after) - afterAssignments->append(qa); - else - assignments->append(qa); - } else { - qDebug()<<"regexp did not match"; - } - ait.deleteArg(); - } else if (ait.value() == QLatin1String("-o")) { - ignoreNext = true; - ait.deleteArg(); -#if defined(Q_OS_WIN32) - } else if (ait.value() == QLatin1String("-win32")) { -#elif defined(Q_OS_MAC) - } else if (ait.value() == QLatin1String("-macx")) { -#elif defined(Q_OS_QNX6) - } else if (ait.value() == QLatin1String("-qnx6")) { -#else - } else if (ait.value() == QLatin1String("-unix")) { -#endif - ait.deleteArg(); - } - } - ait.deleteArg(); // The .pro file is always the last arg -} - -/// This function extracts all the CONFIG+=debug, CONFIG+=release -static BaseQtVersion::QmakeBuildConfigs qmakeBuildConfigFromCmdArgs(QList *assignments, BaseQtVersion::QmakeBuildConfigs defaultBuildConfig) -{ - BaseQtVersion::QmakeBuildConfigs result = defaultBuildConfig; - QList oldAssignments = *assignments; - assignments->clear(); - foreach (const QMakeAssignment &qa, oldAssignments) { - if (qa.variable == QLatin1String("CONFIG")) { - QStringList values = qa.value.split(QLatin1Char(' ')); - QStringList newValues; - foreach (const QString &value, values) { - if (value == QLatin1String("debug")) { - if (qa.op == QLatin1String("+=")) - result = result | BaseQtVersion::DebugBuild; - else - result = result & ~BaseQtVersion::DebugBuild; - } else if (value == QLatin1String("release")) { - if (qa.op == QLatin1String("+=")) - result = result & ~BaseQtVersion::DebugBuild; - else - result = result | BaseQtVersion::DebugBuild; - } else if (value == QLatin1String("debug_and_release")) { - if (qa.op == QLatin1String("+=")) - result = result | BaseQtVersion::BuildAll; - else - result = result & ~BaseQtVersion::BuildAll; - } else { - newValues.append(value); - } - QMakeAssignment newQA = qa; - newQA.value = newValues.join(QLatin1Char(' ')); - if (!newValues.isEmpty()) - assignments->append(newQA); - } - } else { - assignments->append(qa); - } - } - return result; -} - } // namespace QtVersion diff --git a/src/plugins/qtsupport/qtversionmanager.h b/src/plugins/qtsupport/qtversionmanager.h index d70b67d20c..0754a56675 100644 --- a/src/plugins/qtsupport/qtversionmanager.h +++ b/src/plugins/qtsupport/qtversionmanager.h @@ -66,11 +66,6 @@ public: static void addVersion(BaseQtVersion *version); static void removeVersion(BaseQtVersion *version); - enum MakefileCompatible { CouldNotParse, DifferentProject, SameProject }; - static MakefileCompatible makefileIsFor(const QString &makefile, const QString &proFile); - static QPair scanMakeFile(const QString &makefile, - BaseQtVersion::QmakeBuildConfigs defaultBuildConfig); - static Utils::FileName findQMakeBinaryFromMakefile(const QString &directory); static bool isValidId(int id); signals: -- GitLab