diff options
35 files changed, 292 insertions, 33 deletions
diff --git a/doc/man/man.qbs b/doc/man/man.qbs index 44e2f0e12..32f8e624e 100644 --- a/doc/man/man.qbs +++ b/doc/man/man.qbs @@ -31,7 +31,9 @@ Product { Rule { condition: updateManPage multiplex: true + // TODO: Remove in 1.14. explicitlyDependsOn: ["application"] + property stringList explicitlyDependsOnFromDependencies: ["application"] inputs: ["man.section"] Artifact { filePath: "qbs.1" diff --git a/doc/reference/items/language/rule.qdoc b/doc/reference/items/language/rule.qdoc index 200bd94c0..3a14c2fa6 100644 --- a/doc/reference/items/language/rule.qdoc +++ b/doc/reference/items/language/rule.qdoc @@ -303,13 +303,23 @@ A list of file tags. Each artifact that matches the file tags is added to the dependencies of each output node. All artifacts in the current product - and target artifacts of products that this product depends on are - considered. + are considered. \nodefaultvalue */ /*! + \qmlproperty stringList Rule::explicitlyDependsOnFromDependencies + + A list of file tags. Each artifact that matches the file tags is added to + the dependencies of each output node. Only target artifacts of products that this product + depends on are considered. + + \nodefaultvalue + \since Qbs 1.12 +*/ + +/*! \qmlproperty script Rule::prepare A script that prepares the commands to transform the inputs to outputs. diff --git a/qbs-resources/imports/QbsLibrary.qbs b/qbs-resources/imports/QbsLibrary.qbs index 736025cbb..f8bc70580 100644 --- a/qbs-resources/imports/QbsLibrary.qbs +++ b/qbs-resources/imports/QbsLibrary.qbs @@ -16,11 +16,12 @@ QbsProduct { cpp.soVersion: version.replace(/\.\d+$/, '') } cpp.visibility: "minimal" - property string visibilityType: Qt.core.staticBuild ? "static" : "dynamic" + property string visibilityType: staticBuild ? "static" : "dynamic" property string headerInstallPrefix: "/include/qbs" property bool hasExporter: Utilities.versionCompare(qbs.version, "1.12") >= 0 property bool generateQbsModule: install && qbsbuildconfig.generateQbsModules && hasExporter - property stringList libType: [Qt.core.staticBuild ? "staticlibrary" : "dynamiclibrary"] + property bool staticBuild: Qt.core.staticBuild || qbsbuildconfig.staticBuild + property stringList libType: [staticBuild ? "staticlibrary" : "dynamiclibrary"] Depends { name: "Exporter.qbs"; condition: generateQbsModule } Group { fileTagsFilter: libType.concat("dynamiclibrary_symlink") diff --git a/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs b/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs index 8bd3c617a..7f978d47b 100644 --- a/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs +++ b/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs @@ -8,6 +8,7 @@ Module { property bool installApiHeaders: true property bool enableBundledQt: true property bool useBundledQtScript: false + property bool staticBuild: false property string libDirName: "lib" property string appInstallDir: "bin" property string libInstallDir: qbs.targetOS.contains("windows") ? "bin" : libDirName diff --git a/src/lib/corelib/buildgraph/projectbuilddata.cpp b/src/lib/corelib/buildgraph/projectbuilddata.cpp index 2874fe23c..67228d35d 100644 --- a/src/lib/corelib/buildgraph/projectbuilddata.cpp +++ b/src/lib/corelib/buildgraph/projectbuilddata.cpp @@ -390,7 +390,7 @@ static bool areRulesCompatible(const RuleNode *ruleNode, const RuleNode *depende return true; if (!dependencyRule->product->fileTags.intersects(outTags)) return false; - if (ruleNode->rule()->explicitlyDependsOn.intersects(outTags)) + if (ruleNode->rule()->explicitlyDependsOnFromDependencies.intersects(outTags)) return true; return ruleNode->rule()->auxiliaryInputs.intersects(outTags); } @@ -464,7 +464,8 @@ void BuildDataResolver::connectRulesToDependencies(const ResolvedProductPtr &pro if (areRulesCompatible(ruleNode, depRuleNode) || ((ruleNode->rule()->inputsFromDependencies.contains(installableTag) || ruleNode->rule()->auxiliaryInputs.contains(installableTag) - || ruleNode->rule()->explicitlyDependsOn.contains(installableTag)) + || ruleNode->rule()->explicitlyDependsOnFromDependencies.contains( + installableTag)) && isRootRuleNode(depRuleNode))) { connect(ruleNode, depRuleNode); } diff --git a/src/lib/corelib/buildgraph/rulesapplicator.cpp b/src/lib/corelib/buildgraph/rulesapplicator.cpp index 8a908b27c..22c89ea54 100644 --- a/src/lib/corelib/buildgraph/rulesapplicator.cpp +++ b/src/lib/corelib/buildgraph/rulesapplicator.cpp @@ -154,7 +154,8 @@ void RulesApplicator::handleRemovedRuleOutputs(const ArtifactSet &inputArtifacts ArtifactSet RulesApplicator::collectAuxiliaryInputs(const Rule *rule, const ResolvedProduct *product) { - return collectAdditionalInputs(rule->auxiliaryInputs, rule, product); + return collectAdditionalInputs(rule->auxiliaryInputs, rule, product, + RulesApplicator::CurrentProduct | RulesApplicator::Dependencies); } static void copyProperty(const QString &name, const QScriptValue &src, QScriptValue dst) @@ -298,19 +299,37 @@ ArtifactSet RulesApplicator::collectOldOutputArtifacts(const ArtifactSet &inputA } ArtifactSet RulesApplicator::collectAdditionalInputs(const FileTags &tags, const Rule *rule, - const ResolvedProduct *product) + const ResolvedProduct *product, + InputsSources inputsSources) { ArtifactSet artifacts; for (const FileTag &fileTag : tags) { for (Artifact *dependency : product->lookupArtifactsByFileTag(fileTag)) { - if (!dependency->fileTags().intersects(rule->excludedInputs)) + // Skip excluded inputs. + if (dependency->fileTags().intersects(rule->excludedInputs)) + continue; + + // Two cases are considered: + // 1) An artifact is considered a dependency when it's part of the current product. + // 2) An artifact marked with filesAreTargets: true inside a Group inside of a + // Module also ends up in the results returned by product->lookupArtifactsByFileTag, + // so it should be considered conceptually as a "dependent product artifact". + if ((inputsSources.testFlag(RulesApplicator::CurrentProduct) + && !dependency->isTargetOfModule()) + || (inputsSources.testFlag(RulesApplicator::Dependencies) + && dependency->isTargetOfModule()) + ) { artifacts << dependency; + } } - for (const ResolvedProductConstPtr &depProduct : product->dependencies) { - for (Artifact * const ta : depProduct->targetArtifacts()) { - if (ta->fileTags().contains(fileTag) - && !ta->fileTags().intersects(rule->excludedInputs)) { - artifacts << ta; + + if (inputsSources.testFlag(RulesApplicator::Dependencies)) { + for (const ResolvedProductConstPtr &depProduct : product->dependencies) { + for (Artifact * const ta : depProduct->targetArtifacts()) { + if (ta->fileTags().contains(fileTag) + && !ta->fileTags().intersects(rule->excludedInputs)) { + artifacts << ta; + } } } } @@ -320,7 +339,13 @@ ArtifactSet RulesApplicator::collectAdditionalInputs(const FileTags &tags, const ArtifactSet RulesApplicator::collectExplicitlyDependsOn() { - return collectAdditionalInputs(m_rule->explicitlyDependsOn, m_rule.get(), m_product.get()); + ArtifactSet first = collectAdditionalInputs( + m_rule->explicitlyDependsOn, m_rule.get(), m_product.get(), + RulesApplicator::CurrentProduct); + ArtifactSet second = collectAdditionalInputs( + m_rule->explicitlyDependsOnFromDependencies, m_rule.get(), m_product.get(), + RulesApplicator::Dependencies); + return first.unite(second); } Artifact *RulesApplicator::createOutputArtifactFromRuleArtifact( diff --git a/src/lib/corelib/buildgraph/rulesapplicator.h b/src/lib/corelib/buildgraph/rulesapplicator.h index ac4501491..76220f52d 100644 --- a/src/lib/corelib/buildgraph/rulesapplicator.h +++ b/src/lib/corelib/buildgraph/rulesapplicator.h @@ -46,6 +46,7 @@ #include <language/forward_decls.h> #include <logging/logger.h> +#include <QtCore/qflags.h> #include <QtCore/qhash.h> #include <QtCore/qstring.h> #include <QtScript/qscriptvalue.h> @@ -75,10 +76,14 @@ public: const ArtifactSet &artifactsToRemove, const Logger &logger); static ArtifactSet collectAuxiliaryInputs(const Rule *rule, const ResolvedProduct *product); + enum InputsSourceFlag { CurrentProduct, Dependencies }; + Q_DECLARE_FLAGS(InputsSources, InputsSourceFlag) + private: void doApply(const ArtifactSet &inputArtifacts, QScriptValue &prepareScriptContext); ArtifactSet collectOldOutputArtifacts(const ArtifactSet &inputArtifacts) const; ArtifactSet collectExplicitlyDependsOn(); + ArtifactSet collectExplicitlyDependsOnFromDependencies(); Artifact *createOutputArtifactFromRuleArtifact(const RuleArtifactConstPtr &ruleArtifact, const ArtifactSet &inputArtifacts, Set<QString> *outputFilePaths); Artifact *createOutputArtifact(const QString &filePath, const FileTags &fileTags, @@ -93,7 +98,8 @@ private: QScriptValue scope() const; static ArtifactSet collectAdditionalInputs(const FileTags &tags, - const Rule *rule, const ResolvedProduct *product); + const Rule *rule, const ResolvedProduct *product, + InputsSources inputsSources); const ResolvedProductPtr m_product; const std::unordered_map<QString, const ResolvedProduct *> &m_productsByName; @@ -108,6 +114,8 @@ private: Logger m_logger; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(RulesApplicator::InputsSources) + } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs index e1fe4cf9b..900fde759 100644 --- a/src/lib/corelib/corelib.qbs +++ b/src/lib/corelib/corelib.qbs @@ -15,7 +15,7 @@ QbsLibrary { condition: qbsbuildconfig.useBundledQtScript || !Qt.script.present } Depends { condition: qbsbuildconfig.enableProjectFileUpdates; name: "Qt.gui" } - Depends { condition: Qt.core.staticBuild; productTypes: ["qbsplugin"] } + Depends { condition: staticBuild; productTypes: ["qbsplugin"] } name: "qbscore" cpp.includePaths: base.concat([ ".", diff --git a/src/lib/corelib/language/builtindeclarations.cpp b/src/lib/corelib/language/builtindeclarations.cpp index 8aac3c24a..4be405112 100644 --- a/src/lib/corelib/language/builtindeclarations.cpp +++ b/src/lib/corelib/language/builtindeclarations.cpp @@ -507,6 +507,8 @@ void BuiltinDeclarations::addRuleItem() PropertyDeclaration::StringList); item << PropertyDeclaration(StringConstants::explicitlyDependsOnProperty(), PropertyDeclaration::StringList); + item << PropertyDeclaration(StringConstants::explicitlyDependsOnFromDependenciesProperty(), + PropertyDeclaration::StringList); item << prepareScriptProperty(); insert(item); } diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp index 2acd867a8..ac78b06c5 100644 --- a/src/lib/corelib/language/language.cpp +++ b/src/lib/corelib/language/language.cpp @@ -902,6 +902,7 @@ bool operator==(const Rule &r1, const Rule &r2) && r1.excludedInputs == r2.excludedInputs && r1.inputsFromDependencies == r2.inputsFromDependencies && r1.explicitlyDependsOn == r2.explicitlyDependsOn + && r1.explicitlyDependsOnFromDependencies == r2.explicitlyDependsOnFromDependencies && r1.multiplex == r2.multiplex && r1.requiresInputs == r2.requiresInputs && r1.alwaysRun == r2.alwaysRun; diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h index 96fb83640..05fcfcf46 100644 --- a/src/lib/corelib/language/language.h +++ b/src/lib/corelib/language/language.h @@ -414,6 +414,7 @@ public: FileTags excludedInputs; FileTags inputsFromDependencies; FileTags explicitlyDependsOn; + FileTags explicitlyDependsOnFromDependencies; bool multiplex; bool requiresInputs; std::vector<RuleArtifactPtr> artifacts; // unused, if outputFileTags/outputArtifactsScript is non-empty @@ -436,7 +437,8 @@ public: { pool.serializationOp<opType>(name, prepareScript, outputArtifactsScript, module, inputs, outputFileTags, auxiliaryInputs, excludedInputs, - inputsFromDependencies, explicitlyDependsOn, multiplex, + inputsFromDependencies, explicitlyDependsOn, + explicitlyDependsOnFromDependencies, multiplex, requiresInputs, alwaysRun, artifacts); } private: diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp index 3ebfb38d3..a90f51536 100644 --- a/src/lib/corelib/language/moduleloader.cpp +++ b/src/lib/corelib/language/moduleloader.cpp @@ -3025,7 +3025,6 @@ Item *ModuleLoader::loadModuleFile(ProductContext *productContext, const QString // Module properties that are defined in the profile are used as default values. const QVariantMap profileModuleProperties = productContext->moduleProperties.value(fullModuleName).toMap(); - QList<ErrorInfo> unknownProfilePropertyErrors; for (QVariantMap::const_iterator vmit = profileModuleProperties.begin(); vmit != profileModuleProperties.end(); ++vmit) { diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp index 33fee79b7..8b129c98b 100644 --- a/src/lib/corelib/language/projectresolver.cpp +++ b/src/lib/corelib/language/projectresolver.cpp @@ -1194,6 +1194,8 @@ void ProjectResolver::resolveRule(Item *item, ProjectContext *projectContext) } rule->explicitlyDependsOn = m_evaluator->fileTagsValue(item, StringConstants::explicitlyDependsOnProperty()); + rule->explicitlyDependsOnFromDependencies = m_evaluator->fileTagsValue( + item, StringConstants::explicitlyDependsOnFromDependenciesProperty()); rule->module = m_moduleContext ? m_moduleContext->module : projectContext->dummyModule; if (!rule->multiplex && !rule->declaresInputs()) { throw ErrorInfo(Tr::tr("Rule has no inputs, but is not a multiplex rule."), diff --git a/src/lib/corelib/tools/persistence.cpp b/src/lib/corelib/tools/persistence.cpp index 6d8aadf7e..0dab81440 100644 --- a/src/lib/corelib/tools/persistence.cpp +++ b/src/lib/corelib/tools/persistence.cpp @@ -49,7 +49,7 @@ namespace qbs { namespace Internal { -static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-116"; +static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-117"; NoBuildGraphError::NoBuildGraphError(const QString &filePath) : ErrorInfo(Tr::tr("Build graph not found for configuration '%1'. Expected location was '%2'.") diff --git a/src/lib/corelib/tools/stringconstants.h b/src/lib/corelib/tools/stringconstants.h index fa0836d2e..f2666e070 100644 --- a/src/lib/corelib/tools/stringconstants.h +++ b/src/lib/corelib/tools/stringconstants.h @@ -83,6 +83,9 @@ public: QBS_STRING_CONSTANT(excludedAuxiliaryInputsProperty, "excludedAuxiliaryInputs") QBS_STRING_CONSTANT(excludedInputsProperty, "excludedInputs") static const QString &explicitlyDependsOnProperty() { return explicitlyDependsOn(); } + static const QString &explicitlyDependsOnFromDependenciesProperty() { + return explicitlyDependsOnFromDependencies(); + } static const QString &fileNameProperty() { return fileName(); } static const QString &filePathProperty() { return filePath(); } QBS_STRING_CONSTANT(fileTagsFilterProperty, "fileTagsFilter") @@ -225,6 +228,7 @@ public: private: QBS_STRING_CONSTANT(cpp, "cpp") QBS_STRING_CONSTANT(explicitlyDependsOn, "explicitlyDependsOn") + QBS_STRING_CONSTANT(explicitlyDependsOnFromDependencies, "explicitlyDependsOnFromDependencies") QBS_STRING_CONSTANT(fileName, "fileName") QBS_STRING_CONSTANT(filePath, "filePath") QBS_STRING_CONSTANT(inputs, "inputs") diff --git a/src/plugins/generator/generator.pro b/src/plugins/generator/generator.pro index f51646541..1607aa14d 100644 --- a/src/plugins/generator/generator.pro +++ b/src/plugins/generator/generator.pro @@ -1,2 +1,2 @@ TEMPLATE = subdirs -SUBDIRS = clangcompilationdb makefile visualstudio +SUBDIRS = clangcompilationdb makefilegenerator visualstudio diff --git a/src/plugins/generator/makefile/makefilegenerator.cpp b/src/plugins/generator/makefilegenerator/makefilegenerator.cpp index 267bd90dc..267bd90dc 100644 --- a/src/plugins/generator/makefile/makefilegenerator.cpp +++ b/src/plugins/generator/makefilegenerator/makefilegenerator.cpp diff --git a/src/plugins/generator/makefile/makefilegenerator.h b/src/plugins/generator/makefilegenerator/makefilegenerator.h index b2b23f081..b2b23f081 100644 --- a/src/plugins/generator/makefile/makefilegenerator.h +++ b/src/plugins/generator/makefilegenerator/makefilegenerator.h diff --git a/src/plugins/generator/makefile/makefile.pro b/src/plugins/generator/makefilegenerator/makefilegenerator.pro index fae962fbb..fae962fbb 100644 --- a/src/plugins/generator/makefile/makefile.pro +++ b/src/plugins/generator/makefilegenerator/makefilegenerator.pro diff --git a/src/plugins/generator/makefile/makefilegenerator.qbs b/src/plugins/generator/makefilegenerator/makefilegenerator.qbs index baabc43e3..baabc43e3 100644 --- a/src/plugins/generator/makefile/makefilegenerator.qbs +++ b/src/plugins/generator/makefilegenerator/makefilegenerator.qbs diff --git a/src/plugins/generator/makefile/makefilegeneratorplugin.cpp b/src/plugins/generator/makefilegenerator/makefilegeneratorplugin.cpp index 01b843a06..01b843a06 100644 --- a/src/plugins/generator/makefile/makefilegeneratorplugin.cpp +++ b/src/plugins/generator/makefilegenerator/makefilegeneratorplugin.cpp diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index 392145b7f..dcc1ded87 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -4,7 +4,7 @@ Project { name: "qbs plugins" references: [ "generator/clangcompilationdb/clangcompilationdb.qbs", - "generator/makefile/makefilegenerator.qbs", + "generator/makefilegenerator/makefilegenerator.qbs", "generator/visualstudio/visualstudio.qbs", "scanner/cpp/cpp.qbs", "scanner/qt/qt.qbs" diff --git a/src/plugins/qbsplugin.qbs b/src/plugins/qbsplugin.qbs index f6a752dc1..269614e11 100644 --- a/src/plugins/qbsplugin.qbs +++ b/src/plugins/qbsplugin.qbs @@ -3,16 +3,16 @@ import qbs.FileInfo QbsProduct { property bool isForDarwin: qbs.targetOS.contains("darwin") + property bool staticBuild: Qt.core.staticBuild || qbsbuildconfig.staticBuild Depends { name: "cpp" } Depends { name: "bundle"; condition: isForDarwin } Depends { name: "Qt.core" } Depends { name: "qbsbuildconfig" } - Depends { name: "qbscore"; condition: !Qt.core.staticBuild } - type: (Qt.core.staticBuild ? ["staticlibrary"] - : [isForDarwin ? "loadablemodule" : "dynamiclibrary"]) + Depends { name: "qbscore"; condition: !staticBuild } + type: (staticBuild ? ["staticlibrary"] : [isForDarwin ? "loadablemodule" : "dynamiclibrary"]) .concat(["qbsplugin"]) Properties { - condition: Qt.core.staticBuild + condition: staticBuild cpp.defines: ["QBS_STATIC_LIB"] } cpp.includePaths: base.concat(["../../../lib/corelib"]) diff --git a/tests/auto/api/testdata/excluded-inputs/excluded-inputs.qbs b/tests/auto/api/testdata/excluded-inputs/excluded-inputs.qbs index 37c4261f4..faa51d3b9 100644 --- a/tests/auto/api/testdata/excluded-inputs/excluded-inputs.qbs +++ b/tests/auto/api/testdata/excluded-inputs/excluded-inputs.qbs @@ -92,7 +92,7 @@ Project { } Rule { multiplex: true - explicitlyDependsOn: "the_tag" + explicitlyDependsOnFromDependencies: "the_tag" excludedAuxiliaryInputs: "the_other_tag" Artifact { filePath: "dummy3.txt" diff --git a/tests/auto/api/testdata/explicitly-depends-on/explicitly-depends-on.qbs b/tests/auto/api/testdata/explicitly-depends-on/explicitly-depends-on.qbs index 0ac4a7463..17aa74697 100644 --- a/tests/auto/api/testdata/explicitly-depends-on/explicitly-depends-on.qbs +++ b/tests/auto/api/testdata/explicitly-depends-on/explicitly-depends-on.qbs @@ -20,7 +20,7 @@ Project { Rule { inputs: ["mytype.in"] - explicitlyDependsOn: ["compiler"] + explicitlyDependsOnFromDependencies: ["compiler"] Artifact { filePath: input.fileName + ".out" fileTags: product.type @@ -36,7 +36,7 @@ Project { Rule { multiplex: true - explicitlyDependsOn: ["compiler"] + explicitlyDependsOnFromDependencies: ["compiler"] Artifact { filePath: "compiler-name.txt" fileTags: product.type diff --git a/tests/auto/api/testdata/tool-in-module/use-outside-project/modules/thetool/thetool.qbs b/tests/auto/api/testdata/tool-in-module/use-outside-project/modules/thetool/thetool.qbs index d9bd47003..9521f3ae4 100644 --- a/tests/auto/api/testdata/tool-in-module/use-outside-project/modules/thetool/thetool.qbs +++ b/tests/auto/api/testdata/tool-in-module/use-outside-project/modules/thetool/thetool.qbs @@ -13,7 +13,7 @@ Module { Rule { multiplex: true - explicitlyDependsOn: ["thetool.thetool"] + explicitlyDependsOnFromDependencies: ["thetool.thetool"] Artifact { filePath: "tool-output.txt" fileTags: ["thetool.output"] diff --git a/tests/auto/api/testdata/tool-in-module/use-within-project/use-within-project.qbs b/tests/auto/api/testdata/tool-in-module/use-within-project/use-within-project.qbs index 13b2bb819..bd480fb08 100644 --- a/tests/auto/api/testdata/tool-in-module/use-within-project/use-within-project.qbs +++ b/tests/auto/api/testdata/tool-in-module/use-within-project/use-within-project.qbs @@ -15,7 +15,7 @@ Project { Depends { name: "cpp" } Rule { multiplex: true - explicitlyDependsOn: ["thetool.thetool"] + explicitlyDependsOnFromDependencies: ["thetool.thetool"] Artifact { filePath: "tool-output.txt" fileTags: ["thetool.output"] diff --git a/tests/auto/blackbox/testdata/aux-inputs-from-deps/aux-inputs-from-deps.qbs b/tests/auto/blackbox/testdata/aux-inputs-from-deps/aux-inputs-from-deps.qbs index e5be44b76..620ae2ea0 100644 --- a/tests/auto/blackbox/testdata/aux-inputs-from-deps/aux-inputs-from-deps.qbs +++ b/tests/auto/blackbox/testdata/aux-inputs-from-deps/aux-inputs-from-deps.qbs @@ -16,7 +16,7 @@ Project { Depends { name: "dep" } Rule { multiplex: true - explicitlyDependsOn: ["hpp"] + explicitlyDependsOnFromDependencies: ["hpp"] Artifact { filePath: "dummy.out" fileTags: ["p.out"] diff --git a/tests/auto/blackbox/testdata/explicitly-depends-on/explicitly-depends-on.qbs b/tests/auto/blackbox/testdata/explicitly-depends-on/explicitly-depends-on.qbs new file mode 100644 index 000000000..10cfa089b --- /dev/null +++ b/tests/auto/blackbox/testdata/explicitly-depends-on/explicitly-depends-on.qbs @@ -0,0 +1,124 @@ +import qbs +import qbs.File +import qbs.TextFile + +Project { + // Cases: + // step1 + in-product final -> step2 -> step3 -> final => rule cycle + // step1 + dependency final -> step2 -> step3 -> final => ok + // step1 + module filesAreTargets final -> step2 -> step3 -> final => ok + + name: "proj1" + property bool useModule: false + + Product { + name: "prod1" + type: "final" + property bool useExplicitlyDependsOn: false + property bool useExplicitlyDependsOnFromDependencies: false + + Depends { + condition: !project.useModule + name: "prod2" + } + Depends { + condition: project.useModule + name: "module1" + } + + Group { + files: ["step1.txt"] + fileTags: ["step1"] + } + + Rule { + inputs: ["step3"] + outputFileTags: ["final"] + Artifact { + filePath: "final.txt" + fileTags: ["final"] + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "step3 -> final"; + cmd.sourceCode = function() { + File.copy(input.filePath, output.filePath); + }; + return cmd; + } + } + + Rule { + inputs: ["step2"] + outputFileTags: ["step3"] + Artifact { + filePath: "step3.txt" + fileTags: ["step3"] + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "step2 -> step3"; + cmd.sourceCode = function() { + File.copy(input.filePath, output.filePath); + }; + return cmd; + } + } + + Rule { + inputs: ["step1"] + outputFileTags: ["step2"] + Artifact { + filePath: "step2.txt" + fileTags: ["step2"] + } + + Properties { + condition: useExplicitlyDependsOn + explicitlyDependsOn: ["final"] + } + + Properties { + condition: useExplicitlyDependsOnFromDependencies + explicitlyDependsOnFromDependencies: ["final"] + } + + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "step1 -> step2"; + cmd.sourceCode = function() { + console.info("Using explicitlyDependsOnArtifact: " + + explicitlyDependsOn["final"][0].fileName) + File.copy(input.filePath, output.filePath); + }; + return cmd; + } + } + } + + Product { + name: "prod2" + type: "final" + condition: !project.useModule + + Rule { + multiplex: true + requiresInputs: false + outputFileTags: ["final"] + Artifact { + filePath: "product-fish.txt" + fileTags: ["final"] + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "creating 'product-fish.txt' tagged with 'final'"; + cmd.sourceCode = function() { + var file = new TextFile(output.filePath, TextFile.ReadWrite); + file.write("Lots of fish."); + file.close() + }; + return cmd; + } + } + } +} diff --git a/tests/auto/blackbox/testdata/explicitly-depends-on/modules/module1/module-fish.txt b/tests/auto/blackbox/testdata/explicitly-depends-on/modules/module1/module-fish.txt new file mode 100644 index 000000000..10b4b7cbe --- /dev/null +++ b/tests/auto/blackbox/testdata/explicitly-depends-on/modules/module1/module-fish.txt @@ -0,0 +1 @@ +Module fish diff --git a/tests/auto/blackbox/testdata/explicitly-depends-on/modules/module1/module1.qbs b/tests/auto/blackbox/testdata/explicitly-depends-on/modules/module1/module1.qbs new file mode 100644 index 000000000..f1752b4ed --- /dev/null +++ b/tests/auto/blackbox/testdata/explicitly-depends-on/modules/module1/module1.qbs @@ -0,0 +1,9 @@ +import qbs + +Module { + Group { + filesAreTargets: true + fileTags: ["final"] + files: ["module-fish.txt"] + } +} diff --git a/tests/auto/blackbox/testdata/explicitly-depends-on/step1.txt b/tests/auto/blackbox/testdata/explicitly-depends-on/step1.txt new file mode 100644 index 000000000..45b983be3 --- /dev/null +++ b/tests/auto/blackbox/testdata/explicitly-depends-on/step1.txt @@ -0,0 +1 @@ +hi diff --git a/tests/auto/blackbox/testdata/exports-qbs/tool.qbs b/tests/auto/blackbox/testdata/exports-qbs/tool.qbs index 0139b7e14..b0078a75c 100644 --- a/tests/auto/blackbox/testdata/exports-qbs/tool.qbs +++ b/tests/auto/blackbox/testdata/exports-qbs/tool.qbs @@ -40,7 +40,7 @@ CppApplication { property var helper2Obj: Helper2 Rule { inputs: Helper.toolInputs() - explicitlyDependsOn: toolTags + explicitlyDependsOnFromDependencies: toolTags outputFileTags: parent.outTags outputArtifacts: [{ diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index 62930f54f..a18a735ab 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -4936,6 +4936,70 @@ void TestBlackbox::auxiliaryInputsFromDependencies() QVERIFY2(m_qbsStdout.contains("generating dummy.out"), m_qbsStdout.constData()); } +void TestBlackbox::explicitlyDependsOn() +{ + QFETCH(QString, useExplicitlyDependsOn); + QFETCH(QString, useExplicitlyDependsOnFromDependencies); + QFETCH(QString, useModule); + QFETCH(bool, expectFailure); + + QDir::setCurrent(testDataDir + "/explicitly-depends-on"); + QbsRunParameters params("", + QStringList("products.prod1.useExplicitlyDependsOn:" + useExplicitlyDependsOn) + << "products.prod1.useExplicitlyDependsOnFromDependencies:" + + useExplicitlyDependsOnFromDependencies + << "projects.proj1.useModule:" + + useModule); + params.expectFailure = expectFailure; + + rmDirR(relativeBuildDir()); + + if (params.expectFailure) { + // Build should fail because a rule cycle is created within the product when + // explicitlyDependsOn is used. + QVERIFY(runQbs(params) != 0); + QVERIFY2(m_qbsStderr.contains("Cycle detected in rule dependencies"), + m_qbsStderr.constData()); + } else { + // When explicitlyDependsOnFromDependencies is used, build should succeed due to the + // "final" tag being pulled in from dependencies. + QCOMPARE(runQbs(params), 0); + + if (useModule == QLatin1String("false")) { + QVERIFY2(m_qbsStdout.contains("creating 'product-fish.txt' tagged with 'final'"), + m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("Using explicitlyDependsOnArtifact: product-fish.txt"), + m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("step1 -> step2"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("step2 -> step3"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("step3 -> final"), m_qbsStdout.constData()); + } else { + QVERIFY2(!m_qbsStdout.contains("creating 'product-fish.txt' tagged with 'final'"), + m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("Using explicitlyDependsOnArtifact: module-fish.txt"), + m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("step1 -> step2"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("step2 -> step3"), m_qbsStdout.constData()); + QVERIFY2(m_qbsStdout.contains("step3 -> final"), m_qbsStdout.constData()); + } + } +} + +void TestBlackbox::explicitlyDependsOn_data() +{ + QTest::addColumn<QString>("useExplicitlyDependsOn"); + QTest::addColumn<QString>("useExplicitlyDependsOnFromDependencies"); + QTest::addColumn<QString>("useModule"); + QTest::addColumn<bool>("expectFailure"); + + QTest::newRow("useExplicitlyDependsOn -> causes cycle") + << "true" << "false" << "false" << true; + QTest::newRow("explicitlyDependsOnFromDependencies + product") + << "false" << "true" << "false" << false; + QTest::newRow("explicitlyDependsOnFromDependencies + module + filesAreTargets") + << "false" << "true" << "true" << false; +} + static bool haveMakeNsis() { QStringList regKeys; diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h index f3fb1f90d..5a4544bbe 100644 --- a/tests/auto/blackbox/tst_blackbox.h +++ b/tests/auto/blackbox/tst_blackbox.h @@ -97,6 +97,8 @@ private slots: void erroneousFiles(); void errorInfo(); void escapedLinkerFlags(); + void explicitlyDependsOn(); + void explicitlyDependsOn_data(); void exportedDependencyInDisabledProduct(); void exportedDependencyInDisabledProduct_data(); void exportedPropertyInDisabledProduct(); |