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 <eike.ziller@theqtcompany.com>
Reviewed-by: Daniel Teske <daniel.teske@theqtcompany.com>
This commit is contained in:
Daniel Teske
2015-03-04 17:14:28 +01:00
parent cb42ff0deb
commit 51e6fc9416
13 changed files with 854 additions and 455 deletions

View File

@@ -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 <qtsupport/qtversionmanager.h>
#include <qtsupport/baseqtversion.h>
#include <utils/qtcprocess.h>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QTextStream>
#include <QLoggingCategory>
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<QMakeAssignment> *assignments, QList<QMakeAssignment> *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<QMakeAssignment> &list)
{
foreach (const QMakeAssignment &qa, list) {
qCDebug(MakeFileParse::logging()) << " " << qa.variable << qa.op << qa.value;
}
}
void MakeFileParse::parseAssignments(QList<QMakeAssignment> *assignments)
{
bool foundSeparateDebugInfo = false;
bool foundForceDebugInfo = false;
QList<QMakeAssignment> 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:"<<r1.cap(1).trimmed();
QFileInfo qmake(r1.cap(1).trimmed());
QString qmakePath = qmake.filePath();
if (!QString::fromLatin1(QTC_HOST_EXE_SUFFIX).isEmpty()
&& !qmakePath.endsWith(QLatin1String(QTC_HOST_EXE_SUFFIX))) {
qmakePath.append(QLatin1String(QTC_HOST_EXE_SUFFIX));
}
// Is qmake still installed?
QFileInfo fi(qmakePath);
if (fi.exists())
return FileName(fi);
}
}
}
return FileName();
}
MakeFileParse::MakeFileParse(const QString &makefile)
{
qCDebug(logging()) << "Parsing makefile" << makefile;
if (!QFileInfo::exists(makefile)) {
qCDebug(logging()) << "**doesn't exist";
m_state = MakefileMissing;
return;
}
// Qt Version!
m_qmakePath = findQMakeBinaryFromMakefile(makefile);
qCDebug(logging()) << " qmake:" << m_qmakePath;
QString line = findQMakeLine(makefile, QLatin1String("# Project:")).trimmed();
if (line.isEmpty()) {
m_state = CouldNotParse;
qCDebug(logging()) << "**No Project line";
return;
}
line.remove(0, line.indexOf(QLatin1Char(':')) + 1);
line = line.trimmed();
// Src Pro file
m_srcProFile = QDir::cleanPath(QFileInfo(makefile).absoluteDir().filePath(line));
qCDebug(logging()) << " source .pro file:" << m_srcProFile;
line = findQMakeLine(makefile, QLatin1String("# Command:"));
if (line.trimmed().isEmpty()) {
m_state = CouldNotParse;
qCDebug(logging()) << "**No Command line found";
return;
}
line = trimLine(line);
QList<QMakeAssignment> assignments;
QList<QMakeAssignment> 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;
}

View File

@@ -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 <utils/fileutils.h>
#include <qtsupport/baseqtversion.h>
#include <qmakeprojectmanager/qmakestep.h>
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<QMakeAssignment> *assignments, QList<QMakeAssignment> *afterAssignments);
void parseAssignments(QList<QMakeAssignment> *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

View File

@@ -38,6 +38,7 @@
#include "qmakenodes.h"
#include "qmakestep.h"
#include "makestep.h"
#include "makefileparse.h"
#include <coreplugin/documentmanager.h>
#include <coreplugin/icore.h>
@@ -59,6 +60,7 @@
#include <QDebug>
#include <QInputDialog>
#include <QLoggingCategory>
#include <limits>
@@ -329,25 +331,52 @@ 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();
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;
}
if (version->qmakeCommand() == qmakePath) {
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
QPair<BaseQtVersion::QmakeBuildConfigs, QString> result =
QtVersionManager::scanMakeFile(makefile, version->defaultBuildConfig());
if (qmakeBuildConfiguration() == result.first) {
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
@@ -358,19 +387,18 @@ QmakeBuildConfiguration::MakefileState QmakeBuildConfiguration::compareToImportF
// 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;
QString qmakeArgs = parse.unparsedArguments();
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();
}
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
@@ -388,46 +416,31 @@ QmakeBuildConfiguration::MakefileState QmakeBuildConfiguration::compareToImportF
// -norecursive vs. recursive
actualArgs.sort();
parsedArgs.sort();
if (actualArgs == parsedArgs) {
if (actualArgs != parsedArgs) {
qCDebug(logs) << "**Mismateched args";
return MakefileIncompatible;
}
if (parse.config() != qs->deducedArguments()) {
qCDebug(logs) << "**Mismatched config";
return MakefileIncompatible;
}
// Specs match exactly
if (actualSpec == parsedSpec)
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()))
&& (parsedSpec == version->mkspec() || parsedSpec == FileName::fromLatin1("default") || parsedSpec.isEmpty())) {
qCDebug(logs) << "**Matched specs (2)";
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;
}
}
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;
}
}
return removedArgument;
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);

View File

@@ -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;

View File

@@ -32,6 +32,7 @@
#define QMAKEBUILDINFO_H
#include "qmakebuildconfiguration.h"
#include "qmakestep.h"
#include <projectexplorer/buildinfo.h>
#include <projectexplorer/kitmanager.h>
@@ -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<ProjectExplorer::Task> reportIssues(const QString &projectPath,

View File

@@ -34,6 +34,8 @@
#include "qmakekitinformation.h"
#include "qmakebuildconfiguration.h"
#include "qmakeproject.h"
#include "makefileparse.h"
#include "qmakestep.h"
#include <coreplugin/icore.h>
#include <coreplugin/idocument.h>
@@ -52,6 +54,7 @@
#include <QFileInfo>
#include <QMessageBox>
#include <QStringList>
#include <QLoggingCategory>
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,36 +72,46 @@ QmakeProjectImporter::QmakeProjectImporter(const QString &path) :
QList<BuildInfo *> QmakeProjectImporter::import(const FileName &importPath, bool silent)
{
const auto &logs = MakeFileParse::logging();
qCDebug(logs) << "QmakeProjectImporter::import" << importPath << silent;
QList<BuildInfo *> 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()) {
qCDebug(logs) << " QMake:" << canonicalQmakeBinary;
BaseQtVersion *version
= Utils::findOrDefault(QtVersionManager::versions(),
[&canonicalQmakeBinary](BaseQtVersion *v) {
QFileInfo vfi = v->qmakeCommand().toFileInfo();
FileName current = FileName::fromString(vfi.canonicalFilePath());
if (current == canonicalQmakeBinary) {
version = v;
break;
}
}
return current == canonicalQmakeBinary;
});
if (version) {
// Check if version is a temporary qt
@@ -105,10 +119,11 @@ QList<BuildInfo *> QmakeProjectImporter::import(const FileName &importPath, bool
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<BuildInfo *> 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<BaseQtVersion::QmakeBuildConfigs, QString> 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<ProjectExplorer::Abi> 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);
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<Kit *> kitList;
foreach (Kit *k, KitManager::kits()) {
@@ -146,17 +191,23 @@ QList<BuildInfo *> 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<BuildInfo *> 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<BuildInfo *> 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<Abi> 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);

View File

@@ -32,6 +32,7 @@
#define QMAKEPROJECTIMPORTER_H
#include <projectexplorer/projectimporter.h>
#include <qmakestep.h>
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

View File

@@ -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 \

View File

@@ -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

View File

@@ -49,6 +49,7 @@
#include <qtsupport/debugginghelperbuildtask.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtversionmanager.h>
#include <qtsupport/qtsupportconstants.h>
#include <utils/algorithm.h>
#include <utils/hostosinfo.h>
#include <utils/qtcprocess.h>
@@ -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;
}

View File

@@ -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

View File

@@ -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<QMakeAssignment> *assignments,
QList<QMakeAssignment> *afterAssignments,
QString *additionalArguments);
static BaseQtVersion::QmakeBuildConfigs qmakeBuildConfigFromCmdArgs(QList<QMakeAssignment> *assignments,
BaseQtVersion::QmakeBuildConfigs defaultBuildConfig);
static bool restoreQtVersions();
static void findSystemQt();
static void saveQtVersions();
@@ -608,210 +571,9 @@ void QtVersionManager::setNewQtVersions(QList<BaseQtVersion *> 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:"<<r1.cap(1).trimmed();
QFileInfo qmake(r1.cap(1).trimmed());
QString qmakePath = qmake.filePath();
if (!QString::fromLatin1(QTC_HOST_EXE_SUFFIX).isEmpty()
&& !qmakePath.endsWith(QLatin1String(QTC_HOST_EXE_SUFFIX))) {
qmakePath.append(QLatin1String(QTC_HOST_EXE_SUFFIX));
}
// Is qmake still installed?
QFileInfo fi(qmakePath);
if (fi.exists())
return FileName(fi);
}
}
}
return FileName();
}
BaseQtVersion *QtVersionManager::qtVersionForQMakeBinary(const FileName &qmakePath)
{
return Utils::findOrDefault(versions(), Utils::equal(&BaseQtVersion::qmakeCommand, qmakePath));
}
void dumpQMakeAssignments(const QList<QMakeAssignment> &list)
{
foreach (const QMakeAssignment &qa, list) {
qDebug()<<qa.variable<<qa.op<<qa.value;
}
}
QtVersionManager::MakefileCompatible QtVersionManager::makefileIsFor(const QString &makefile, const QString &proFile)
{
if (proFile.isEmpty())
return CouldNotParse;
// The Makefile.Debug / Makefile.Release lack a # Command: line
if (findQMakeLine(makefile, QLatin1String("# Command:")).trimmed().isEmpty())
return CouldNotParse;
QString line = findQMakeLine(makefile, QLatin1String("# Project:")).trimmed();
if (line.isEmpty())
return CouldNotParse;
line.remove(0, line.indexOf(QLatin1Char(':')) + 1);
line = line.trimmed();
QFileInfo srcFileInfo(QFileInfo(makefile).absoluteDir(), line);
QFileInfo proFileInfo(proFile);
return (srcFileInfo == proFileInfo) ? SameProject : DifferentProject;
}
QPair<BaseQtVersion::QmakeBuildConfigs, QString> 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"<<line;
line = trimLine(line);
QList<QMakeAssignment> assignments;
QList<QMakeAssignment> 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()<<result2;
qDebug()<<"\n\n";
}
return qMakePair(result, result2);
}
static void parseArgs(const QString &args, QList<QMakeAssignment> *assignments, QList<QMakeAssignment> *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<QMakeAssignment> *assignments, BaseQtVersion::QmakeBuildConfigs defaultBuildConfig)
{
BaseQtVersion::QmakeBuildConfigs result = defaultBuildConfig;
QList<QMakeAssignment> 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

View File

@@ -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<BaseQtVersion::QmakeBuildConfigs, QString> scanMakeFile(const QString &makefile,
BaseQtVersion::QmakeBuildConfigs defaultBuildConfig);
static Utils::FileName findQMakeBinaryFromMakefile(const QString &directory);
static bool isValidId(int id);
signals: