diff options
| author | Joerg Bornemann <joerg.bornemann@digia.com> | 2013-11-14 14:31:13 +0100 |
|---|---|---|
| committer | Joerg Bornemann <joerg.bornemann@digia.com> | 2013-11-14 14:40:22 +0100 |
| commit | e91f6b50957c504bd05bba20734c56eb8d6f2f23 (patch) | |
| tree | 9bd7e563e8530b8db4fb7fdc90b83edfb4f252b3 | |
| parent | 154b78e01ad4fdec9c68ca84b9ac0afd8d5a22e8 (diff) | |
| parent | 4d97182f31e19881d8246324bc1a119b7d77e28a (diff) | |
| download | qbs-e91f6b50957c504bd05bba20734c56eb8d6f2f23.tar.gz | |
Merge remote-tracking branch 'origin/1.1'
Change-Id: I7475c4a71c15c83c59400c44ef96d73d15caea58
26 files changed, 281 insertions, 38 deletions
diff --git a/doc/reference/modules/cpp-module.qdoc b/doc/reference/modules/cpp-module.qdoc index f5a05425f..564ca7e24 100644 --- a/doc/reference/modules/cpp-module.qdoc +++ b/doc/reference/modules/cpp-module.qdoc @@ -322,7 +322,7 @@ \row \li \b{Default:} \li determined by qbs-detect-toolchains \endtable - Directory where the compiler binary is located. This is set in the build profile. + Full path of the compiler binary. This is set in the build profile. \section2 compilerWrapper @@ -334,6 +334,24 @@ Wrapper binary and its arguments for wrapping compiler calls. This is useful for compiler wrappers like ccache and alike. + \section2 linkerName + + \table + \row \li \b{Type:} \li \c{string} + \row \li \b{Default:} \li determined by qbs-detect-toolchains + \endtable + + Name of the linker binary. This is set in the build profile. + + \section2 linkerPath + + \table + \row \li \b{Type:} \li \c{string} + \row \li \b{Default:} \li determined by qbs-detect-toolchains + \endtable + + Full path of the linker binary. This is set in the build profile. + \section2 supportedStaticLibrarySuffixes \table diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs index f6c339d14..ce98fa154 100644 --- a/share/qbs/modules/cpp/CppModule.qbs +++ b/share/qbs/modules/cpp/CppModule.qbs @@ -85,6 +85,8 @@ Module { property string compilerName property string compilerPath: compilerName property stringList compilerWrapper + property string linkerName + property string linkerPath: linkerName property string staticLibraryPrefix property string dynamicLibraryPrefix property string executablePrefix diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs index 023708e3a..9bbb152c5 100644 --- a/share/qbs/modules/cpp/GenericGCC.qbs +++ b/share/qbs/modules/cpp/GenericGCC.qbs @@ -13,6 +13,7 @@ CppModule { property string toolchainPrefix property path toolchainInstallPath compilerName: 'g++' + linkerName: "g++" property string archiverName: 'ar' property path sysroot: qbs.sysroot property path platformPath @@ -30,6 +31,7 @@ CppModule { } compilerPath: toolchainPathPrefix + compilerName + linkerPath: toolchainPathPrefix + linkerName property path archiverPath: { return toolchainPathPrefix + archiverName } readonly property bool shouldCreateSymlinks: { @@ -135,7 +137,7 @@ CppModule { args.push(libFilePath); args = args.concat(Gcc.libraryLinkerFlags(product, inputs)); args = args.concat(Gcc.additionalCompilerAndLinkerFlags(product)); - var cmd = new Command(ModUtils.moduleProperty(product, "compilerPath"), args); + var cmd = new Command(ModUtils.moduleProperty(product, "linkerPath"), args); cmd.description = 'linking ' + FileInfo.fileName(libFilePath); cmd.highlight = 'linker'; cmd.responseFileUsagePrefix = '@'; @@ -262,7 +264,7 @@ CppModule { args = args.concat(Gcc.libraryLinkerFlags(product, inputs)); args = args.concat(Gcc.additionalCompilerAndLinkerFlags(product)); - var cmd = new Command(ModUtils.moduleProperty(product, "compilerPath"), args); + var cmd = new Command(ModUtils.moduleProperty(product, "linkerPath"), args); cmd.description = 'linking ' + FileInfo.fileName(output.fileName); cmd.highlight = 'linker' cmd.responseFileUsagePrefix = '@'; diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js index f71b3db99..01986c16e 100644 --- a/share/qbs/modules/cpp/msvc.js +++ b/share/qbs/modules/cpp/msvc.js @@ -196,7 +196,7 @@ function prepareLinker(product, inputs, outputs, libraryPaths, dynamicLibraries, args = args.concat(linkerFlags); var commands = []; - var cmd = new Command("link.exe", args) + var cmd = new Command(product.moduleProperty("cpp", "linkerPath"), args) cmd.description = 'linking ' + FileInfo.fileName(primaryOutput.fileName) cmd.highlight = 'linker'; cmd.workingDirectory = FileInfo.path(primaryOutput.fileName) diff --git a/share/qbs/modules/cpp/windows-msvc.qbs b/share/qbs/modules/cpp/windows-msvc.qbs index 944a9e1fc..0c121c820 100644 --- a/share/qbs/modules/cpp/windows-msvc.qbs +++ b/share/qbs/modules/cpp/windows-msvc.qbs @@ -17,6 +17,7 @@ CppModule { compilerDefines: ['_WIN32'] warningLevel: "default" compilerName: "cl.exe" + linkerName: "link.exe" property bool generateManifestFiles: true property path toolchainInstallPath diff --git a/src/app/detect-toolchains/probe.cpp b/src/app/detect-toolchains/probe.cpp index d7c1530bd..e6b7bb239 100644 --- a/src/app/detect-toolchains/probe.cpp +++ b/src/app/detect-toolchains/probe.cpp @@ -203,6 +203,11 @@ static void mingwProbe(Settings *settings, QList<Profile> &profiles) return; } + QByteArray architecture = gccMachineName.split('-').first(); + if (architecture == "mingw32") + architecture = "x86"; + else if (architecture == "mingw64") + architecture = "x86_64"; Profile profile(QString::fromLocal8Bit(gccMachineName), settings); qbsInfo() << Tr::tr("Platform '%1' detected in '%2'.").arg(profile.name(), mingwPath); @@ -210,6 +215,10 @@ static void mingwProbe(Settings *settings, QList<Profile> &profiles) profile.setValue("cpp.toolchainInstallPath", mingwBinPath); profile.setValue("cpp.compilerName", QLatin1String("g++.exe")); profile.setValue("qbs.toolchain", QStringList() << "mingw" << "gcc"); + profile.setValue(QLatin1String("qbs.architecture"), + HostOsInfo::canonicalArchitecture(QString::fromLatin1(architecture))); + profile.setValue(QLatin1String("qbs.endianness"), + QLatin1String("little")); profiles << profile; } diff --git a/src/lib/buildgraph/buildgraphloader.cpp b/src/lib/buildgraph/buildgraphloader.cpp index 1ef1f8dcc..7ebca9703 100644 --- a/src/lib/buildgraph/buildgraphloader.cpp +++ b/src/lib/buildgraph/buildgraphloader.cpp @@ -205,9 +205,19 @@ void BuildGraphLoader::trackProjectChanges(const SetupProjectParameters ¶met productsWithChangedFiles); QSharedPointer<ProjectBuildData> oldBuildData; + ChildListHash childLists; if (!changedProducts.isEmpty() || !productsWithChangedFiles.isEmpty()) { oldBuildData = QSharedPointer<ProjectBuildData>( new ProjectBuildData(restoredProject->buildData.data())); + foreach (const ResolvedProductConstPtr &product, allRestoredProducts) { + if (!product->buildData) + continue; + + // If the product gets temporarily removed, its artifacts will get disconnected + // and this structural information will no longer be directly available from them. + foreach (const Artifact * const a, product->buildData->artifacts) + childLists.insert(a, a->children); + } } // For products with "serious" changes such as different prepare scripts, we set up the @@ -285,7 +295,7 @@ void BuildGraphLoader::trackProjectChanges(const SetupProjectParameters ¶met foreach (const ResolvedProductConstPtr &changedProduct, changedProducts) { rescueOldBuildData(changedProduct, freshProductsByName.value(changedProduct->name), - oldBuildData.data()); + oldBuildData.data(), childLists); } doSanityChecks(m_result.newlyResolvedProject, m_logger); @@ -413,6 +423,8 @@ bool BuildGraphLoader::checkProductForChanges(const ResolvedProductPtr &restored { return !transformerListsAreEqual(restoredProduct->transformers, newlyResolvedProduct->transformers) + || !ruleListsAreEqual(restoredProduct->rules.toList(), + newlyResolvedProduct->rules.toList()) || !dependenciesAreEqual(restoredProduct, newlyResolvedProduct) || checkForPropertyChanges(restoredProduct, newlyResolvedProduct); // TODO: Check for more stuff. @@ -698,7 +710,7 @@ static bool commandsEqual(const TransformerConstPtr &t1, const TransformerConstP */ void BuildGraphLoader::rescueOldBuildData(const ResolvedProductConstPtr &restoredProduct, const ResolvedProductPtr &newlyResolvedProduct, - const ProjectBuildData *oldBuildData) + const ProjectBuildData *oldBuildData, const ChildListHash &childLists) { if (!restoredProduct->enabled || !newlyResolvedProduct->enabled) return; @@ -731,11 +743,7 @@ void BuildGraphLoader::rescueOldBuildData(const ResolvedProductConstPtr &restore } artifact->setTimestamp(oldArtifact->timestamp()); - foreach (Artifact * const oldChild, oldArtifact->children) { - // skip transform edges - if (oldArtifact->transformer->inputs.contains(oldChild)) - continue; - + foreach (Artifact * const oldChild, childLists.value(oldArtifact)) { foreach (FileResourceBase *childFileRes, newlyResolvedProduct->topLevelProject()->buildData->lookupFiles(oldChild)) { Artifact * const child = dynamic_cast<Artifact *>(childFileRes); diff --git a/src/lib/buildgraph/buildgraphloader.h b/src/lib/buildgraph/buildgraphloader.h index f13749f26..4806daad3 100644 --- a/src/lib/buildgraph/buildgraphloader.h +++ b/src/lib/buildgraph/buildgraphloader.h @@ -31,6 +31,7 @@ #include "forward_decls.h" +#include <buildgraph/artifactlist.h> #include <language/forward_decls.h> #include <logging/logger.h> @@ -41,7 +42,6 @@ namespace qbs { class SetupProjectParameters; namespace Internal { -class ArtifactList; class FileDependency; class FileResourceBase; class FileTime; @@ -97,9 +97,12 @@ private: const PropertyMapConstPtr &newProperties); void replaceFileDependencyWithArtifact(const ResolvedProductPtr &fileDepProduct, FileDependency *filedep, Artifact *artifact); + + typedef QHash<const Artifact *, ArtifactList> ChildListHash; void rescueOldBuildData(const ResolvedProductConstPtr &restoredProduct, const ResolvedProductPtr &newlyResolvedProduct, - const ProjectBuildData *oldBuildData); + const ProjectBuildData *oldBuildData, + const ChildListHash &childLists); RulesEvaluationContextPtr m_evalContext; BuildGraphLoadResult m_result; diff --git a/src/lib/jsextensions/moduleproperties.cpp b/src/lib/jsextensions/moduleproperties.cpp index 0f2833754..cc9102b73 100644 --- a/src/lib/jsextensions/moduleproperties.cpp +++ b/src/lib/jsextensions/moduleproperties.cpp @@ -33,6 +33,7 @@ #include <language/language.h> #include <language/scriptengine.h> #include <logging/translator.h> +#include <tools/error.h> #include <tools/propertyfinder.h> #include <QScriptEngine> @@ -70,12 +71,20 @@ void ModuleProperties::init(QScriptValue objectWithProperties, const void *ptr, QScriptValue ModuleProperties::js_moduleProperties(QScriptContext *context, QScriptEngine *engine) { - return moduleProperties(context, engine, false); + try { + return moduleProperties(context, engine, false); + } catch (const ErrorInfo &e) { + return context->throwError(e.toString()); + } } QScriptValue ModuleProperties::js_moduleProperty(QScriptContext *context, QScriptEngine *engine) { - return moduleProperties(context, engine, true); + try { + return moduleProperties(context, engine, true); + } catch (const ErrorInfo &e) { + return context->throwError(e.toString()); + } } QScriptValue ModuleProperties::moduleProperties(QScriptContext *context, QScriptEngine *engine, @@ -112,7 +121,7 @@ QScriptValue ModuleProperties::moduleProperties(QScriptContext *context, QScript } ScriptEngine * const qbsEngine = static_cast<ScriptEngine *>(engine); - const QString moduleName = context->argument(0).toString(); + const QString moduleName = internalModuleName(context->argument(0).toString()); const QString propertyName = context->argument(1).toString(); QVariant value = qbsEngine->retrieveFromPropertyCache(moduleName, propertyName, properties); @@ -134,5 +143,12 @@ QScriptValue ModuleProperties::moduleProperties(QScriptContext *context, QScript return engine->toScriptValue(value); } +QString ModuleProperties::internalModuleName(const QString &name) +{ + QString result = name; + result.replace(QLatin1Char('.'), QLatin1Char('/')); + return result; +} + } // namespace Internal } // namespace qbs diff --git a/src/lib/jsextensions/moduleproperties.h b/src/lib/jsextensions/moduleproperties.h index 644f5f25c..9032d83ee 100644 --- a/src/lib/jsextensions/moduleproperties.h +++ b/src/lib/jsextensions/moduleproperties.h @@ -53,6 +53,7 @@ private: static QScriptValue moduleProperties(QScriptContext *context, QScriptEngine *engine, bool oneValue); + static QString internalModuleName(const QString &name); }; } // namespace Internal diff --git a/src/lib/language/builtindeclarations.cpp b/src/lib/language/builtindeclarations.cpp index 87beda2fd..ebc876b60 100644 --- a/src/lib/language/builtindeclarations.cpp +++ b/src/lib/language/builtindeclarations.cpp @@ -124,6 +124,11 @@ QByteArray BuiltinDeclarations::qmlTypeInfo() const return result; } +bool BuiltinDeclarations::containsType(const QString &typeName) const +{ + return m_builtins.contains(typeName); +} + QList<PropertyDeclaration> BuiltinDeclarations::declarationsForType(const QString &typeName) const { return m_builtins.value(typeName); diff --git a/src/lib/language/builtindeclarations.h b/src/lib/language/builtindeclarations.h index 1f0c26e69..4cbd352a7 100644 --- a/src/lib/language/builtindeclarations.h +++ b/src/lib/language/builtindeclarations.h @@ -47,6 +47,7 @@ public: QString languageVersion() const; QByteArray qmlTypeInfo() const; + bool containsType(const QString &typeName) const; QList<PropertyDeclaration> declarationsForType(const QString &typeName) const; void setupItemForBuiltinType(qbs::Internal::Item *item) const; diff --git a/src/lib/language/language.cpp b/src/lib/language/language.cpp index 131b5e4b4..9241af3da 100644 --- a/src/lib/language/language.cpp +++ b/src/lib/language/language.cpp @@ -1015,6 +1015,7 @@ template<typename T> bool listsAreEqual(const QList<T> &l1, const QList<T> &l2) QString keyFromElem(const SourceArtifactPtr &sa) { return sa->absoluteFilePath; } QString keyFromElem(const ResolvedTransformerConstPtr &t) { return t->transform->sourceCode; } +QString keyFromElem(const RulePtr &r) { return r->toString(); } bool operator==(const SourceArtifact &sa1, const SourceArtifact &sa2) { @@ -1048,5 +1049,54 @@ bool transformerListsAreEqual(const QList<ResolvedTransformerConstPtr> &l1, return listsAreEqual(l1, l2); } +bool operator==(const Rule &r1, const Rule &r2) +{ + if (&r1 == &r2) + return true; + if (!&r1 != !&r2) + return false; + if (r1.artifacts.count() != r2.artifacts.count()) + return false; + for (int i = 0; i < r1.artifacts.count(); ++i) { + if (*r1.artifacts.at(i) != *r2.artifacts.at(i)) + return false; + } + + return r1.module->name == r2.module->name + && r1.script->sourceCode == r2.script->sourceCode + && r1.inputs == r2.inputs + && r1.auxiliaryInputs == r2.auxiliaryInputs + && r1.usings == r2.usings + && r1.explicitlyDependsOn == r2.explicitlyDependsOn + && r1.multiplex == r2.multiplex; +} + +bool ruleListsAreEqual(const QList<RulePtr> &l1, const QList<RulePtr> &l2) +{ + return listsAreEqual(l1, l2); +} + +bool operator==(const RuleArtifact &a1, const RuleArtifact &a2) +{ + if (&a1 == &a2) + return true; + if (!&a1 != !&a2) + return false; + return a1.fileName == a2.fileName + && a1.fileTags == a2.fileTags + && a1.alwaysUpdated == a2.alwaysUpdated + && a1.bindings.toList().toSet() == a2.bindings.toList().toSet(); +} + +bool operator==(const RuleArtifact::Binding &b1, const RuleArtifact::Binding &b2) +{ + return b1.code == b2.code && b1.name == b2.name; +} + +uint qHash(const RuleArtifact::Binding &b) +{ + return qHash(qMakePair(b.code, b.name.join(QLatin1String(",")))); +} + } // namespace Internal } // namespace qbs diff --git a/src/lib/language/language.h b/src/lib/language/language.h index 98bf2f7f1..a41f1f948 100644 --- a/src/lib/language/language.h +++ b/src/lib/language/language.h @@ -113,6 +113,13 @@ private: void load(PersistentPool &pool); void store(PersistentPool &pool) const; }; +uint qHash(const RuleArtifact::Binding &b); +bool operator==(const RuleArtifact::Binding &b1, const RuleArtifact::Binding &b2); +inline bool operator!=(const RuleArtifact::Binding &b1, const RuleArtifact::Binding &b2) { + return !(b1 == b2); +} +bool operator==(const RuleArtifact &a1, const RuleArtifact &a2); +inline bool operator!=(const RuleArtifact &a1, const RuleArtifact &a2) { return !(a1 == a2); } class SourceArtifact : public PersistentObject { @@ -289,6 +296,9 @@ private: void load(PersistentPool &pool); void store(PersistentPool &pool) const; }; +bool operator==(const Rule &r1, const Rule &r2); +inline bool operator!=(const Rule &r1, const Rule &r2) { return !(r1 == r2); } +bool ruleListsAreEqual(const QList<RulePtr> &l1, const QList<RulePtr> &l2); class ResolvedTransformer : public PersistentObject { diff --git a/src/lib/language/moduleloader.cpp b/src/lib/language/moduleloader.cpp index c5d722710..c26e55d76 100644 --- a/src/lib/language/moduleloader.cpp +++ b/src/lib/language/moduleloader.cpp @@ -125,14 +125,17 @@ ModuleLoaderResult ModuleLoader::load(const QString &filePath, class PropertyDeclarationCheck : public ValueHandler { + const BuiltinDeclarations *m_builtins; const QHash<Item *, QSet<QString> > &m_validItemPropertyNamesPerItem; const QSet<Item *> &m_disabledItems; Item *m_parentItem; QString m_currentName; public: - PropertyDeclarationCheck(const QHash<Item *, QSet<QString> > &validItemPropertyNamesPerItem, + PropertyDeclarationCheck(const BuiltinDeclarations *builtins, + const QHash<Item *, QSet<QString> > &validItemPropertyNamesPerItem, const QSet<Item *> &disabledItems) - : m_validItemPropertyNamesPerItem(validItemPropertyNamesPerItem) + : m_builtins(builtins) + , m_validItemPropertyNamesPerItem(validItemPropertyNamesPerItem) , m_disabledItems(disabledItems) , m_parentItem(0) { @@ -169,6 +172,12 @@ private: void handleItem(Item *item) { + if (Q_UNLIKELY(!item->typeName().isEmpty() + && !m_builtins->containsType(item->typeName()))) { + const QString msg = Tr::tr("Unexpected item type '%1'."); + throw ErrorInfo(msg.arg(item->typeName()), item->location()); + } + if (m_disabledItems.contains(item) || item->typeName() == QLatin1String("SubProject")) return; @@ -249,7 +258,8 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult, Item *item, } } - PropertyDeclarationCheck check(m_validItemPropertyNamesPerItem, m_disabledItems); + PropertyDeclarationCheck check(m_reader->builtins(), m_validItemPropertyNamesPerItem, + m_disabledItems); check(item); m_reader->popExtraSearchPaths(); diff --git a/src/lib/language/projectresolver.cpp b/src/lib/language/projectresolver.cpp index af6f0a164..b71f16f2f 100644 --- a/src/lib/language/projectresolver.cpp +++ b/src/lib/language/projectresolver.cpp @@ -840,13 +840,14 @@ void ProjectResolver::applyFileTaggers(const SourceArtifactPtr &artifact, const ResolvedProductConstPtr &product) const { if (!artifact->overrideFileTags || artifact->fileTags.isEmpty()) { - const FileTags fileTags = product->fileTagsForFileName(artifact->absoluteFilePath); + const QString fileName = FileInfo::fileName(artifact->absoluteFilePath); + const FileTags fileTags = product->fileTagsForFileName(fileName); artifact->fileTags.unite(fileTags); if (artifact->fileTags.isEmpty()) artifact->fileTags.insert(unknownFileTag()); if (m_logger.traceEnabled()) m_logger.qbsTrace() << "[PR] adding file tags " << artifact->fileTags - << " to " << FileInfo::fileName(artifact->absoluteFilePath); + << " to " << fileName; } } @@ -974,10 +975,7 @@ void ProjectResolver::callItemFunction(const ItemFuncMap &mappings, Item *item, { const QByteArray typeName = item->typeName().toLocal8Bit(); ItemFuncPtr f = mappings.value(typeName); - if (Q_UNLIKELY(!f)) { - const QString msg = Tr::tr("Unexpected item type '%1'."); - throw ErrorInfo(msg.arg(item->typeName()), item->location()); - } + QBS_CHECK(f); if (typeName == "Project") { ProjectContext subProjectContext = createProjectContext(projectContext); (this->*f)(item, &subProjectContext); diff --git a/src/lib/language/testdata/Banana b/src/lib/language/testdata/Banana new file mode 100644 index 000000000..53164be8a --- /dev/null +++ b/src/lib/language/testdata/Banana @@ -0,0 +1 @@ +Peanut butter jelly time! diff --git a/src/lib/language/testdata/erroneous/unknown_item_type.qbs b/src/lib/language/testdata/erroneous/unknown_item_type.qbs new file mode 100644 index 000000000..9e34e9243 --- /dev/null +++ b/src/lib/language/testdata/erroneous/unknown_item_type.qbs @@ -0,0 +1,3 @@ +Narf { + zort: 1 // This invalid binding should not hide the "Unexpected item type" error. +} diff --git a/src/lib/language/testdata/filetags.qbs b/src/lib/language/testdata/filetags.qbs index 97cccd510..38182e5f1 100644 --- a/src/lib/language/testdata/filetags.qbs +++ b/src/lib/language/testdata/filetags.qbs @@ -21,6 +21,15 @@ Project { } Product { + name: "filetagger_static_pattern" + files: "Banana" + FileTagger { + patterns: "Banana" + fileTags: ["yellow"] + } + } + + Product { name: "unknown_file_tag" files: "narf.zort" } diff --git a/src/lib/language/tst_language.cpp b/src/lib/language/tst_language.cpp index 268711ab0..bb984c3fc 100644 --- a/src/lib/language/tst_language.cpp +++ b/src/lib/language/tst_language.cpp @@ -347,6 +347,8 @@ void TestLanguage::erroneousFiles_data() << "Item 'cpp' is not declared."; QTest::newRow("undeclared_property") << "Property 'doesntexist' is not declared."; + QTest::newRow("unknown_item_type") + << "Unexpected item type 'Narf'"; } void TestLanguage::erroneousFiles() @@ -1154,6 +1156,7 @@ void TestLanguage::fileTags_data() QTest::newRow("init") << 0 << QStringList(); QTest::newRow("filetagger_project_scope") << 1 << (QStringList() << "cpp"); QTest::newRow("filetagger_product_scope") << 1 << (QStringList() << "asm"); + QTest::newRow("filetagger_static_pattern") << 1 << (QStringList() << "yellow"); QTest::newRow("unknown_file_tag") << 1 << (QStringList() << "unknown-file-tag"); QTest::newRow("set_file_tag_via_group") << 2 << (QStringList() << "c++"); QTest::newRow("override_file_tag_via_group") << 2 << (QStringList() << "c++"); diff --git a/tests/auto/blackbox/testdata/codegen/codegen.qbs b/tests/auto/blackbox/testdata/codegen/codegen.qbs index d7210e21c..bb71a5540 100644 --- a/tests/auto/blackbox/testdata/codegen/codegen.qbs +++ b/tests/auto/blackbox/testdata/codegen/codegen.qbs @@ -18,6 +18,7 @@ Project { fileTags: ['text'] } Depends { name: 'cpp' } + Depends { name: 'Qt.core' } } Rule { @@ -40,6 +41,11 @@ Project { return str; } + // check whether multipart module name translation is working + var actual = product.moduleProperty("Qt.core", "mocName"); + if (!actual || !actual.contains("moc")) + throw "multipart module name translation is broken"; + // check whether we can access project properties here var expected = "CODEGEN_" + product.moduleProperty("qbs", "targetOS")[0].toUpperCase(); if (project.osSpecificName !== expected) diff --git a/tests/auto/blackbox/testdata/propertyChanges/modules/TestModule/module.qbs b/tests/auto/blackbox/testdata/propertyChanges/modules/TestModule/module.qbs new file mode 100644 index 000000000..ef14d3f47 --- /dev/null +++ b/tests/auto/blackbox/testdata/propertyChanges/modules/TestModule/module.qbs @@ -0,0 +1,28 @@ +import qbs +import qbs.File + +Module { + FileTagger { + pattern: "*.in" + fileTags: "test-input" + } + + Rule { + inputs: ['test-input'] + Artifact { + fileTags: "test-output" + fileName: input.fileName + ".out" + } + + prepare: { + var cmd = new JavaScriptCommand(); + cmd.highlight = "codegen"; + cmd.description = "Making output from input"; + cmd.sourceCode = function() { + // print('Change in source code'); + File.copy(input.fileName, output.fileName); + } + return cmd; + } + } +} diff --git a/tests/auto/blackbox/testdata/propertyChanges/project.qbs b/tests/auto/blackbox/testdata/propertyChanges/project.qbs index d1f0ab5ee..b2de04e84 100644 --- a/tests/auto/blackbox/testdata/propertyChanges/project.qbs +++ b/tests/auto/blackbox/testdata/propertyChanges/project.qbs @@ -44,4 +44,8 @@ Project { } } } + + references: "ruletest.qbs" + + qbsSearchPaths: "." } diff --git a/tests/auto/blackbox/testdata/propertyChanges/ruletest.qbs b/tests/auto/blackbox/testdata/propertyChanges/ruletest.qbs new file mode 100644 index 000000000..02088da7b --- /dev/null +++ b/tests/auto/blackbox/testdata/propertyChanges/ruletest.qbs @@ -0,0 +1,7 @@ +import qbs + +Product { + type: "test-output" + Depends { name: "TestModule" } + files: "test.in" +} diff --git a/tests/auto/blackbox/testdata/propertyChanges/test.in b/tests/auto/blackbox/testdata/propertyChanges/test.in new file mode 100644 index 000000000..8633abf18 --- /dev/null +++ b/tests/auto/blackbox/testdata/propertyChanges/test.in @@ -0,0 +1 @@ +blubb diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index 30b62dc41..0700df165 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -1055,41 +1055,45 @@ void TestBlackbox::propertyChanges() { QDir::setCurrent(testDataDir + "/propertyChanges"); QFile projectFile("project.qbs"); + QbsRunParameters params(QStringList() << "-f" << "project.qbs"); // Initial build. - QCOMPARE(runQbs(), 0); + QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(m_qbsStdout.contains("linking product 1.debug")); QVERIFY(m_qbsStdout.contains("generated.txt")); + QVERIFY(m_qbsStdout.contains("Making output from input")); QFile generatedFile(buildDir + QLatin1String("/generated.txt")); QVERIFY(generatedFile.open(QIODevice::ReadOnly)); QCOMPARE(generatedFile.readAll(), QByteArray("contents 1")); generatedFile.close(); // Incremental build with no changes. - QCOMPARE(runQbs(), 0); + QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp.cpp")); QVERIFY(!m_qbsStdout.contains("linking")); QVERIFY(!m_qbsStdout.contains("generated.txt")); + QVERIFY(!m_qbsStdout.contains("Making output from input")); // Incremental build with no changes, but updated project file timestamp. waitForNewTimestamp(); QVERIFY(projectFile.open(QIODevice::ReadWrite | QIODevice::Append)); projectFile.write("\n"); projectFile.close(); - QCOMPARE(runQbs(), 0); + QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(!m_qbsStdout.contains("linking")); QVERIFY(!m_qbsStdout.contains("generated.txt")); + QVERIFY(!m_qbsStdout.contains("Making output from input")); // Incremental build, input property changed for first product waitForNewTimestamp(); @@ -1099,13 +1103,14 @@ void TestBlackbox::propertyChanges() projectFile.resize(0); projectFile.write(contents); projectFile.close(); - QCOMPARE(runQbs(), 0); + QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(m_qbsStdout.contains("linking product 1.debug")); QVERIFY(!m_qbsStdout.contains("linking product 2")); QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("linking library")); QVERIFY(!m_qbsStdout.contains("generated.txt")); + QVERIFY(!m_qbsStdout.contains("Making output from input")); // Incremental build, input property changed via project for second product. waitForNewTimestamp(); @@ -1115,26 +1120,29 @@ void TestBlackbox::propertyChanges() projectFile.resize(0); projectFile.write(contents); projectFile.close(); - QCOMPARE(runQbs(), 0); + QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("linking product 1")); QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("generated.txt")); + QVERIFY(!m_qbsStdout.contains("Making output from input")); // Incremental build, input property changed via command line for second product. - QCOMPARE(runQbs(QbsRunParameters(QLatin1String("project.projectDefines:blubb002"))), 0); + params.arguments << "project.projectDefines:blubb002"; + QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("linking product 1")); QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("generated.txt")); - QCOMPARE(runQbs(), 0); + params.arguments.removeLast(); + QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("linking product 1")); QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("generated.txt")); + QVERIFY(!m_qbsStdout.contains("Making output from input")); // Incremental build, input property changed via environment for third product. - QbsRunParameters params; params.environment.insert("QBS_BLACKBOX_DEFINE", "newvalue"); QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("linking product 1")); @@ -1147,21 +1155,25 @@ void TestBlackbox::propertyChanges() QVERIFY(!m_qbsStdout.contains("linking product 2")); QVERIFY(m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); + QVERIFY(!m_qbsStdout.contains("Making output from input")); // Incremental build, module property changed via command line. - QCOMPARE(runQbs(QbsRunParameters(QLatin1String("qbs.enableDebugCode:false"))), 0); + params.arguments << "qbs.enableDebugCode:false"; + QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(m_qbsStdout.contains("linking product 1.release")); QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); - QCOMPARE(runQbs(), 0); + params.arguments.removeLast(); + QCOMPARE(runQbs(params), 0); QVERIFY(m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(m_qbsStdout.contains("linking product 1.debug")); QVERIFY(m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("generated.txt")); + QVERIFY(!m_qbsStdout.contains("Making output from input")); // Incremental build, non-essential dependency removed. waitForNewTimestamp(); @@ -1171,12 +1183,13 @@ void TestBlackbox::propertyChanges() projectFile.resize(0); projectFile.write(contents); projectFile.close(); - QCOMPARE(runQbs(), 0); + QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("linking product 1")); QVERIFY(m_qbsStdout.contains("linking product 2")); QVERIFY(!m_qbsStdout.contains("linking product 3")); QVERIFY(!m_qbsStdout.contains("linking library")); QVERIFY(!m_qbsStdout.contains("generated.txt")); + QVERIFY(!m_qbsStdout.contains("Making output from input")); // Incremental build, prepare script of a transformer changed. waitForNewTimestamp(); @@ -1186,15 +1199,49 @@ void TestBlackbox::propertyChanges() projectFile.resize(0); projectFile.write(contents); projectFile.close(); - QCOMPARE(runQbs(), 0); + QCOMPARE(runQbs(params), 0); QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); QVERIFY(m_qbsStdout.contains("generated.txt")); + QVERIFY(!m_qbsStdout.contains("Making output from input")); QVERIFY(generatedFile.open(QIODevice::ReadOnly)); QCOMPARE(generatedFile.readAll(), QByteArray("contents 2")); generatedFile.close(); + + // Incremental build, prepare script of a rule in a module changed. + waitForNewTimestamp(); + QFile moduleFile("modules/TestModule/module.qbs"); + QVERIFY(moduleFile.open(QIODevice::ReadWrite)); + contents = moduleFile.readAll(); + contents.replace("// print('Change in source code')", "print('Change in source code')"); + moduleFile.resize(0); + moduleFile.write(contents); + moduleFile.close(); + QCOMPARE(runQbs(params), 0); + QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); + QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); + QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); + QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); + QVERIFY(!m_qbsStdout.contains("generated.txt")); + QVERIFY(m_qbsStdout.contains("Making output from input")); + + // Incremental build, irrelevant file tag of a rule in a module changed. + waitForNewTimestamp(); + QVERIFY(moduleFile.open(QIODevice::ReadWrite)); + contents = moduleFile.readAll(); + contents.replace("inputs: ['test-input']", "inputs: ['test-input', 'hupe']"); + moduleFile.resize(0); + moduleFile.write(contents); + moduleFile.close(); + QCOMPARE(runQbs(params), 0); + QVERIFY(!m_qbsStdout.contains("compiling source1.cpp")); + QVERIFY(!m_qbsStdout.contains("compiling source2.cpp")); + QVERIFY(!m_qbsStdout.contains("compiling source3.cpp")); + QVERIFY(!m_qbsStdout.contains("compiling lib.cpp")); + QVERIFY(!m_qbsStdout.contains("generated.txt")); + QVERIFY(!m_qbsStdout.contains("Making output from input")); } void TestBlackbox::disabledProduct() @@ -1480,7 +1527,7 @@ void TestBlackbox::testAssembly() { SettingsPtr settings = qbsSettings(); Profile profile(buildProfileName, settings.data()); - bool haveGcc = profile.value("qbs.toolchain").toString().contains("gcc"); + bool haveGcc = profile.value("qbs.toolchain").toStringList().contains("gcc"); QDir::setCurrent(testDataDir + "/assembly"); QVERIFY(runQbs() == 0); QCOMPARE((bool)m_qbsStdout.contains("compiling testa.s"), haveGcc); |
