From 73f8478c9844aaf1282cc7461075f9c73230af2f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 24 May 2018 14:45:14 +0200 Subject: Allow rules without output artifacts It is occasionally useful to have a rule whose purpose lies solely in its "side effects", that is, it does not produce any actual files. This patch removes the necessity to declare a dummy artifact in that case. [ChangeLog] Added support for rules without output artifacts Change-Id: I38e76a5ddc78ffa768e8ae1f270ae2f7461c5ee7 Reviewed-by: Joerg Bornemann --- src/lib/corelib/buildgraph/rulesapplicator.cpp | 37 ++++++++++++++++++++------ src/lib/corelib/language/projectresolver.cpp | 13 +++++---- 2 files changed, 35 insertions(+), 15 deletions(-) (limited to 'src/lib') diff --git a/src/lib/corelib/buildgraph/rulesapplicator.cpp b/src/lib/corelib/buildgraph/rulesapplicator.cpp index 22c89ea54..d04475abb 100644 --- a/src/lib/corelib/buildgraph/rulesapplicator.cpp +++ b/src/lib/corelib/buildgraph/rulesapplicator.cpp @@ -65,6 +65,7 @@ #include #include +#include #include #include @@ -218,6 +219,10 @@ void RulesApplicator::doApply(const ArtifactSet &inputArtifacts, QScriptValue &p outputArtifacts.push_back(outputArtifact); ruleArtifactArtifactMap.push_back({ ruleArtifact.get(), outputArtifact }); } + if (m_rule->artifacts.empty()) { + outputArtifacts.push_back(createOutputArtifactFromRuleArtifact(nullptr, inputArtifacts, + &outputFilePaths)); + } } if (outputArtifacts.empty()) @@ -352,18 +357,34 @@ Artifact *RulesApplicator::createOutputArtifactFromRuleArtifact( const RuleArtifactConstPtr &ruleArtifact, const ArtifactSet &inputArtifacts, Set *outputFilePaths) { - QScriptValue scriptValue = engine()->evaluate(ruleArtifact->filePath, - ruleArtifact->filePathLocation.filePath(), - ruleArtifact->filePathLocation.line()); - if (Q_UNLIKELY(engine()->hasErrorOrException(scriptValue))) - throw engine()->lastError(scriptValue, ruleArtifact->filePathLocation); - QString outputPath = FileInfo::resolvePath(m_product->buildDirectory(), scriptValue.toString()); + QString outputPath; + FileTags fileTags; + bool alwaysUpdated; + if (ruleArtifact) { + QScriptValue scriptValue = engine()->evaluate(ruleArtifact->filePath, + ruleArtifact->filePathLocation.filePath(), + ruleArtifact->filePathLocation.line()); + if (Q_UNLIKELY(engine()->hasErrorOrException(scriptValue))) + throw engine()->lastError(scriptValue, ruleArtifact->filePathLocation); + outputPath = scriptValue.toString(); + fileTags = ruleArtifact->fileTags; + alwaysUpdated = ruleArtifact->alwaysUpdated; + } else { + outputPath = QStringLiteral("__dummyoutput__"); + QByteArray hashInput = m_rule->toString().toLatin1(); + for (const Artifact * const input : inputArtifacts) + hashInput += input->filePath().toLatin1(); + outputPath += QLatin1String(QCryptographicHash::hash(hashInput, QCryptographicHash::Sha1) + .toHex().left(16)); + fileTags = m_rule->outputFileTags; + alwaysUpdated = false; + } + outputPath = FileInfo::resolvePath(m_product->buildDirectory(), outputPath); if (Q_UNLIKELY(!outputFilePaths->insert(outputPath).second)) { throw ErrorInfo(Tr::tr("Rule %1 already created '%2'.") .arg(m_rule->toString(), outputPath)); } - return createOutputArtifact(outputPath, ruleArtifact->fileTags, ruleArtifact->alwaysUpdated, - inputArtifacts); + return createOutputArtifact(outputPath, fileTags, alwaysUpdated, inputArtifacts); } Artifact *RulesApplicator::createOutputArtifact(const QString &filePath, const FileTags &fileTags, diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp index 5364184fc..b7535c2eb 100644 --- a/src/lib/corelib/language/projectresolver.cpp +++ b/src/lib/corelib/language/projectresolver.cpp @@ -1174,19 +1174,18 @@ void ProjectResolver::resolveRule(Item *item, ProjectContext *projectContext) rule->prepareScript.initialize(scriptFunctionValue(item, StringConstants::prepareProperty())); rule->outputArtifactsScript.initialize(scriptFunctionValue( item, StringConstants::outputArtifactsProperty())); + rule->outputFileTags = m_evaluator->fileTagsValue( + item, StringConstants::outputFileTagsProperty()); if (rule->outputArtifactsScript.isValid()) { if (hasArtifactChildren) throw ErrorInfo(Tr::tr("The Rule.outputArtifacts script is not allowed in rules " "that contain Artifact items."), item->location()); - rule->outputFileTags = m_evaluator->fileTagsValue( - item, StringConstants::outputFileTagsProperty()); - if (rule->outputFileTags.empty()) - throw ErrorInfo(Tr::tr("Rule.outputFileTags must be specified if " - "Rule.outputArtifacts is specified."), - item->location()); } - + if (!hasArtifactChildren && rule->outputFileTags.empty()) { + throw ErrorInfo(Tr::tr("A rule needs to have Artifact items or a non-empty " + "outputFileTags property."), item->location()); + } rule->multiplex = m_evaluator->boolValue(item, StringConstants::multiplexProperty()); rule->alwaysRun = m_evaluator->boolValue(item, StringConstants::alwaysRunProperty()); rule->inputs = m_evaluator->fileTagsValue(item, StringConstants::inputsProperty()); -- cgit v1.2.3