diff options
author | Christian Kandeler <christian.kandeler@digia.com> | 2014-03-25 10:54:45 +0100 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@digia.com> | 2014-03-26 16:21:53 +0100 |
commit | 8042731153f49484dc831b7e51675652cef317cb (patch) | |
tree | 2fd43db5cc656f2e103f884644f8fd746ee6b7f0 /src/lib/corelib/buildgraph/executor.cpp | |
parent | c0e86b13594631188d457e0a360799e7de73777d (diff) |
Fix "build single file" and "changed files" functionalities.
These had several problems.
Firstly, the "changed files" case was implemented by setting all
artifacts to "Built" and then setting the ones to "Buildable" that were
reachable bottom-up from artifacts corresponding to the respective files.
This approach broke with the introduction of rule nodes, because
parent nodes do not necessarily exist yet at initialization time. This
was not caught due to the lack of an autotest.
Secondly, the logic behind the "build single file" functionality was
faulty. The assumption was that this could be implemented on top of the
"changed file" functionality, which is wrong: Consider the case where
you have several cpp files that have not yet been built. Now
marking one of them as changed and filtering by the "obj" tag will still
cause all of them to be compiled, as we cannot simply exclude all other
source files from being built, which would break the build for the
normal "changed files" case without tag filtering. Therefore we need a
dedicated list of input files by which we can filter transformers.
Task-number: QBS-537
Change-Id: I47e2ba6d0cbd073561064640eaf8f63c4e0b39fa
Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
Diffstat (limited to 'src/lib/corelib/buildgraph/executor.cpp')
-rw-r--r-- | src/lib/corelib/buildgraph/executor.cpp | 100 |
1 files changed, 49 insertions, 51 deletions
diff --git a/src/lib/corelib/buildgraph/executor.cpp b/src/lib/corelib/buildgraph/executor.cpp index 583fd2396..f54034173 100644 --- a/src/lib/corelib/buildgraph/executor.cpp +++ b/src/lib/corelib/buildgraph/executor.cpp @@ -111,7 +111,12 @@ void Executor::retrieveSourceFileTimestamp(Artifact *artifact) const { QBS_CHECK(artifact->artifactType == Artifact::SourceFile); - artifact->setTimestamp(recursiveFileTime(artifact->filePath())); + if (m_buildOptions.changedFiles().contains(artifact->filePath())) + artifact->setTimestamp(FileTime::currentTime()); + else if (m_buildOptions.changedFiles().isEmpty()) + artifact->setTimestamp(recursiveFileTime(artifact->filePath())); + else + artifact->setTimestamp(FileTime::oldestTime()); artifact->timestampRetrieved = true; } @@ -220,21 +225,10 @@ void Executor::setBuildOptions(const BuildOptions &buildOptions) m_buildOptions = buildOptions; } -static void initNodesBottomUp(BuildGraphNode *node) -{ - if (node->buildState == BuildGraphNode::Untouched) - return; - node->buildState = BuildGraphNode::Buildable; - foreach (BuildGraphNode *parent, node->parents) - initNodesBottomUp(parent); -} void Executor::initLeaves() { - if (m_buildOptions.changedFiles().isEmpty()) - updateLeaves(m_roots); - else - initLeavesForSelectedFiles(); + updateLeaves(m_roots); } void Executor::updateLeaves(const NodeSet &nodes) @@ -244,28 +238,6 @@ void Executor::updateLeaves(const NodeSet &nodes) updateLeaves(node, seenNodes); } -void Executor::initLeavesForSelectedFiles() -{ - ArtifactSet changedArtifacts; - foreach (const QString &filePath, m_buildOptions.changedFiles()) { - QList<FileResourceBase *> lookupResults; - lookupResults.append(m_project->buildData->lookupFiles(filePath)); - if (lookupResults.isEmpty()) { - m_logger.qbsWarning() << QString::fromLocal8Bit("Out of date file '%1' provided " - "but not found.").arg(QDir::toNativeSeparators(filePath)); - continue; - } - foreach (FileResourceBase *lookupResult, lookupResults) - if (Artifact *artifact = dynamic_cast<Artifact *>(lookupResult)) - changedArtifacts += artifact; - } - - foreach (Artifact *artifact, changedArtifacts) { - m_leaves.push(artifact); - initNodesBottomUp(artifact); - } -} - void Executor::updateLeaves(BuildGraphNode *node, NodeSet &seenNodes) { if (seenNodes.contains(node)) @@ -306,7 +278,8 @@ bool Executor::scheduleJobs() switch (nodeToBuild->buildState) { case BuildGraphNode::Untouched: - QBS_ASSERT(!"untouched node in leaves list", /* ignore */); + QBS_ASSERT(!"untouched node in leaves list", + qDebug("%s", qPrintable(nodeToBuild->toString()))); break; case BuildGraphNode::Buildable: // This is the only state in which we want to build a node. @@ -582,6 +555,34 @@ QString Executor::configString() const return tr(" for configuration %1").arg(m_project->id()); } +bool Executor::transformerHasMatchingOutputTags(const TransformerConstPtr &transformer) const +{ + if (m_activeFileTags.isEmpty()) + return true; // No filtering requested. + + foreach (Artifact * const output, transformer->outputs) { + if (m_activeFileTags.matches(output->fileTags)) + return true; + } + + return false; +} + +bool Executor::transformerHasMatchingInputFiles(const TransformerConstPtr &transformer) const +{ + if (m_buildOptions.filesToConsider().isEmpty()) + return true; // No filtering requested. + + foreach (const Artifact * const input, transformer->inputs) { + foreach (const QString &filePath, m_buildOptions.filesToConsider()) { + if (input->filePath() == filePath) + return true; + } + } + + return false; +} + void Executor::cancelJobs() { m_logger.qbsTrace() << "Canceling all jobs."; @@ -733,8 +734,6 @@ bool Executor::checkForUnbuiltDependencies(Artifact *artifact) void Executor::potentiallyRunTransformer(const TransformerPtr &transformer) { - bool matchingFileTagsExist = m_activeFileTags.isEmpty(); - foreach (Artifact * const output, transformer->outputs) { // Rescuing build data can introduce new dependencies, potentially delaying execution of // this transformer. @@ -742,20 +741,22 @@ void Executor::potentiallyRunTransformer(const TransformerPtr &transformer) rescueOldBuildData(output, &childrenAddedDueToRescue); if (childrenAddedDueToRescue && checkForUnbuiltDependencies(output)) return; - - if (!matchingFileTagsExist && m_activeFileTags.matches(output->fileTags)) - matchingFileTagsExist = true; } - // Skip if we're building just one file and the file tags do not match. - if (!matchingFileTagsExist) { + if (!transformerHasMatchingOutputTags(transformer)) { if (m_doDebug) m_logger.qbsDebug() << "[EXEC] file tags do not match. Skipping."; finishTransformer(transformer); return; } - // Skip transformers that do not need to be built. + if (!transformerHasMatchingInputFiles(transformer)) { + if (m_doDebug) + m_logger.qbsDebug() << "[EXEC] input files do not match. Skipping."; + finishTransformer(transformer); + return; + } + if (!mustExecuteTransformer(transformer)) { if (m_doDebug) m_logger.qbsDebug() << "[EXEC] Up to date. Skipping."; @@ -927,21 +928,18 @@ void Executor::prepareArtifact(Artifact *artifact) */ void Executor::prepareReachableNodes() { - const BuildGraphNode::BuildState initialBuildState = m_buildOptions.changedFiles().isEmpty() - ? BuildGraphNode::Buildable : BuildGraphNode::Built; foreach (BuildGraphNode *root, m_roots) - prepareReachableNodes_impl(root, initialBuildState); + prepareReachableNodes_impl(root); } -void Executor::prepareReachableNodes_impl(BuildGraphNode *node, - const BuildGraphNode::BuildState buildState) +void Executor::prepareReachableNodes_impl(BuildGraphNode *node) { if (node->buildState != BuildGraphNode::Untouched) return; - node->buildState = buildState; + node->buildState = BuildGraphNode::Buildable; foreach (BuildGraphNode *child, node->children) - prepareReachableNodes_impl(child, buildState); + prepareReachableNodes_impl(child); } void Executor::prepareProducts() |