// Returns true if both are equal. QmakeBuildConfiguration::MakefileState QmakeBuildConfiguration::compareToImportFrom(const QString &makefile, QString *errorString) { const QLoggingCategory &logs = MakeFileParse::logging(); qCDebug(logs) << "QMakeBuildConfiguration::compareToImport"; QMakeStep *qs = qmakeStep(); MakeFileParse parse(makefile); if (parse.makeFileState() == MakeFileParse::MakefileMissing) { qCDebug(logs) << "**Makefile missing"; return MakefileMissing; } if (parse.makeFileState() == MakeFileParse::CouldNotParse) { qCDebug(logs) << "**Makefile incompatible"; if (errorString) *errorString = tr("Could not parse Makefile."); return MakefileIncompatible; } 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(); if (errorString) *errorString = tr("The Makefile is for a different project."); 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; if (errorString) *errorString = tr("The build type has changed."); 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) << "**Mismatched args"; if (errorString) *errorString = tr("The qmake arguments have changed."); return MakefileIncompatible; } if (parse.config() != qs->deducedArguments()) { qCDebug(logs) << "**Mismatched config"; if (errorString) *errorString = tr("The qmake arguments have changed."); 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"; if (errorString) *errorString = tr("The mkspec has changed."); return MakefileIncompatible; }
// Returns true if both are equal. QmakeBuildConfiguration::MakefileState QmakeBuildConfiguration::compareToImportFrom(const QString &makefile) { QMakeStep *qs = qmakeStep(); if (QFileInfo(makefile).exists() && 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<BaseQtVersion::QmakeBuildConfigs, QString> 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 + qs->deducedArgumentsAfter(); 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; } } return MakefileMissing; }