diff options
| author | Joerg Bornemann <joerg.bornemann@digia.com> | 2013-08-02 13:57:26 +0200 |
|---|---|---|
| committer | Joerg Bornemann <joerg.bornemann@digia.com> | 2013-11-27 11:49:01 +0100 |
| commit | 006824f89c4f298f19c45f4f4585b4452cd2d2b9 (patch) | |
| tree | 0007c73137e7d167cefa4e5611a01803e69fa5fd /src/lib/buildgraph/executor.cpp | |
| parent | dbb39fc1fce3686a5161d68e89e96086fc664556 (diff) | |
| download | qbs-006824f89c4f298f19c45f4f4585b4452cd2d2b9.tar.gz | |
introduce class BuildGraphNodedynablaster
To support different types of nodes in the build graph, we introduce
the base class BuildGraphNode. Artifact now derives from BuildGraphNode.
A - yet unused - RuleNode class is introduced that represents a rule in
the build graph.
Change-Id: Ie1ad5e7a9e65bfd5f99d3e824737516053de0f94
***new artifacts hash in ProductBuildData
Change-Id: I50521ec64f734bfb3662759076fa5e7912ac084e
***automoc fixup
Change-Id: Ie2bb228ae38d63deccc600d67d283bc3beda9fec
slightly nicer rule debug output
Change-Id: I60ddef73cd7f0a67055f2d56e6dbe7fa45ddd450
create RuleNode objects and add them to roots
Change-Id: I51a0f89b98cda524d34888ab758d7bd397d82f00
***execute rule nodes on build
Change-Id: I291c32868cd982e37393d6bc8d696f2b63fbff50
***ArtifactSet::fromNodeSet
Change-Id: I7586bcfbe43406c22b1ee1a1fd826beaa247164f
***update after rebase
Change-Id: I5f73afc80b746b11eeb83aeadf29c2358accbab8
***phonytarget
Change-Id: I587b7e072e54b866e8d5ea37c874e6a8baa550e0
update after rebase
Change-Id: I6017c0cbe9244fea04d513f53e3a2a85092bf962
skip nodes early
We must skip Building and Built nodes.
m_leaves can contain duplicates now.
Change-Id: If275106a47c403a455103f4deeb20049548007f5
debug message
Change-Id: I90e238eef72a8a02fb0a9f2c77715f5f15c1442d
disable phony thingy
Change-Id: I7bb60b850b96b65ab738c11e96c3a84cbe58d2f7
connect each output of a rule to the rule itself
Change-Id: I159d76c4b63094058cc9a07ccc2d0b67c7ce06e6
TagScanner
Change-Id: I4741e48cd674c0ca830ee1b4d05b59a8c542694f
TagScanner deps
Change-Id: If3e43a7ac25616cd151229684a085ac8ee787645
update after rebase
Change-Id: I58d49a5ed1049a17733fc2154588f12c1cda53e6
only root tag scanners in product
Change-Id: Ia94732a5632156a5ec3c5518c9596cd4cefac105
run TagScanners
Change-Id: I869a183f2da23a43957a6df45dc5a1b30b10af92
TagScannerRunner
Change-Id: Id3c5fac73e6fb84e56d6ab1d48a959f3677f7a67
crash fix
Change-Id: Ie3c26dbed41ab4615915a08913c495868c3a8910
more TagScanRunner
Change-Id: I80b79f101c0f4d802fb4f6515c0848e369fed066
handle removal of filetags
Change-Id: Icdd8d05c2e26953f7b12d968aa5dfcc23928b9ba
Qt4 build fix
Change-Id: Ie5fcb64e36ddc5004003183bea7243536bc8ab15
do not waste space with type information
Change-Id: I7b9354e6fceead228ba335723b9addeb701bef56
update nodes that must get new transformers
Change-Id: I06cd7ffe606ae643393350c5959ef6475343929f
update after rebase
Change-Id: If080e664972f2950c12fd800a3e4b521e65dca3a
only run tag scanners on changed sources
And do not call RulesApplicator in bgloader.
Change-Id: I5140c91c79a842dab933ad7b328100bdec13cb10
Conflicts:
src/lib/buildgraph/buildgraphloader.cpp
sketch of moc tagscanners impl
Change-Id: I7736c2da1b1742bc3556ef660c163e6c32cbd4c9
Conflicts:
share/qbs/modules/Qt/core/core.qbs
MocTagScanner
Change-Id: I87199e8f355b8b20cf2387f4d4190a20bddae0db
fix lib.qbs
Change-Id: Ibcb5bc290d3839b04828f8c9b155577634bcc9e4
moctagscanner split
Change-Id: Iace5d48483c02b5d33d9ccd54ac07162bfc09d27
Diffstat (limited to 'src/lib/buildgraph/executor.cpp')
| -rw-r--r-- | src/lib/buildgraph/executor.cpp | 351 |
1 files changed, 223 insertions, 128 deletions
diff --git a/src/lib/buildgraph/executor.cpp b/src/lib/buildgraph/executor.cpp index 5d8ea52cf..fc80eff87 100644 --- a/src/lib/buildgraph/executor.cpp +++ b/src/lib/buildgraph/executor.cpp @@ -29,14 +29,16 @@ #include "executor.h" #include "artifactvisitor.h" -#include "automoc.h" #include "buildgraph.h" #include "productbuilddata.h" #include "projectbuilddata.h" #include "cycledetector.h" #include "executorjob.h" #include "inputartifactscanner.h" +#include "phonytarget.h" +#include "rulenode.h" #include "rulesevaluationcontext.h" +#include "tagscannerrunner.h" #include <buildgraph/transformer.h> #include <language/language.h> @@ -91,7 +93,7 @@ private: }; -bool Executor::ComparePriority::operator() (const Artifact *x, const Artifact *y) const +bool Executor::ComparePriority::operator() (const BuildGraphNode *x, const BuildGraphNode *y) const { return x->product->buildData->buildPriority < y->product->buildData->buildPriority; } @@ -106,10 +108,6 @@ Executor::Executor(const Logger &logger, QObject *parent) , m_doDebug(logger.debugEnabled()) { m_inputArtifactScanContext = new InputArtifactScannerContext(&m_scanResultCache); - m_autoMoc = new AutoMoc(logger); - connect(m_autoMoc, SIGNAL(reportCommandDescription(QString,QString)), - this, SIGNAL(reportCommandDescription(QString,QString))); - m_autoMoc->setScanResultCache(&m_scanResultCache); } Executor::~Executor() @@ -119,7 +117,6 @@ Executor::~Executor() delete job; foreach (ExecutorJob *job, m_processingJobs.keys()) delete job; - delete m_autoMoc; // delete before shared scan result cache delete m_inputArtifactScanContext; } @@ -225,6 +222,7 @@ void Executor::doBuild() } QBS_CHECK(m_state == ExecutorIdle); m_leaves = Leaves(); + m_changedSourceArtifacts.clear(); m_error.clear(); m_explicitlyCanceled = false; m_activeFileTags = FileTags::fromStringList(m_buildOptions.activeFileTags()); @@ -250,8 +248,7 @@ void Executor::doBuild() foreach (ExecutorJob * const job, m_availableJobs) job->setDryRun(m_buildOptions.dryRun()); - bool sourceFilesChanged = false; - prepareAllArtifacts(&sourceFilesChanged); + prepareAllNodes(); Artifact::BuildState initialBuildState = m_buildOptions.changedFiles().isEmpty() ? Artifact::Buildable : Artifact::Built; @@ -281,19 +278,22 @@ void Executor::doBuild() // find the root nodes m_roots.clear(); foreach (const ResolvedProductPtr &product, m_productsToBuild) { - foreach (Artifact *targetArtifact, product->buildData->targetArtifacts) { - m_roots += targetArtifact; - - // The user expects that he can delete target artifacts and they get rebuilt. - // To achieve this we must retrieve their timestamps. - targetArtifact->setTimestamp(FileInfo(targetArtifact->filePath()).lastModified()); + foreach (BuildGraphNode *rootNode, product->buildData->roots) { + m_roots += rootNode; + Artifact *targetArtifact = dynamic_cast<Artifact *>(rootNode); + if (targetArtifact && product->buildData->targetArtifacts.contains(targetArtifact)) { + // The user expects that he can delete target artifacts and they get rebuilt. + // To achieve this we must retrieve their timestamps. + targetArtifact->setTimestamp(FileInfo(targetArtifact->filePath()).lastModified()); + } } } prepareReachableArtifacts(initialBuildState); - setupProgressObserver(sourceFilesChanged); - if (sourceFilesChanged) - runAutoMoc(); + setupProgressObserver(!m_changedSourceArtifacts.isEmpty()); + if (!m_changedSourceArtifacts.isEmpty()) { + runTagScanners(); + } initLeaves(changedArtifacts); if (!scheduleJobs()) { m_logger.qbsTrace() << "Nothing to do at all, finishing."; @@ -306,48 +306,49 @@ void Executor::setBuildOptions(const BuildOptions &buildOptions) m_buildOptions = buildOptions; } -static void initArtifactsBottomUp(Artifact *artifact) +static void initArtifactsBottomUp(BuildGraphNode *node) { - if (artifact->buildState == Artifact::Untouched) + if (node->buildState == Artifact::Untouched) return; - artifact->buildState = Artifact::Buildable; - foreach (Artifact *parent, artifact->parents) + node->buildState = Artifact::Buildable; + foreach (BuildGraphNode *parent, node->parents) initArtifactsBottomUp(parent); } void Executor::initLeaves(const QList<Artifact *> &changedArtifacts) { if (changedArtifacts.isEmpty()) { - QSet<Artifact *> seenArtifacts; - foreach (Artifact *root, m_roots) - initLeavesTopDown(root, seenArtifacts); + QSet<BuildGraphNode *> seenNodes; + foreach (BuildGraphNode *root, m_roots) + initLeavesTopDown(root, seenNodes); } else { - foreach (Artifact *artifact, changedArtifacts) { + foreach (BuildGraphNode *artifact, changedArtifacts) { m_leaves.push(artifact); initArtifactsBottomUp(artifact); } } } -void Executor::initLeavesTopDown(Artifact *artifact, QSet<Artifact *> &seenArtifacts) +void Executor::initLeavesTopDown(BuildGraphNode *node, QSet<BuildGraphNode *> &seenNodes) { - if (seenArtifacts.contains(artifact)) + if (seenNodes.contains(node)) return; - seenArtifacts += artifact; + seenNodes += node; // Artifacts that appear in the build graph after // prepareBuildGraph() has been called, must be initialized. - if (artifact->buildState == Artifact::Untouched) { - artifact->buildState = Artifact::Buildable; - if (artifact->artifactType == Artifact::SourceFile) + if (node->buildState == Artifact::Untouched) { + node->buildState = Artifact::Buildable; + Artifact *artifact = dynamic_cast<Artifact *>(node); + if (artifact && artifact->artifactType == Artifact::SourceFile) retrieveSourceFileTimestamp(artifact); } - if (artifact->children.isEmpty()) { - m_leaves.push(artifact); + if (node->children.isEmpty()) { + m_leaves.push(node); } else { - foreach (Artifact *child, artifact->children) - initLeavesTopDown(child, seenArtifacts); + foreach (BuildGraphNode *child, node->children) + initLeavesTopDown(child, seenNodes); } } @@ -356,11 +357,34 @@ bool Executor::scheduleJobs() { QBS_CHECK(m_state == ExecutorRunning); while (!m_leaves.empty() && !m_availableJobs.isEmpty()) { - Artifact * const artifact = m_leaves.top(); + BuildGraphNode * const nodeToBuild = m_leaves.top(); m_leaves.pop(); - buildArtifact(artifact); + + switch (nodeToBuild->buildState) { + case BuildGraphNode::Untouched: + QBS_ASSERT(!"untouched node in leaves list", /* ignore */); + continue; + case BuildGraphNode::Buildable: + // This is the only state in which we want to build a node. + break; + case BuildGraphNode::Building: + if (m_doDebug) { + m_logger.qbsDebug() << "[EXEC] " << nodeToBuild->toString(); + m_logger.qbsDebug() << "[EXEC] node is currently being built. Skipping."; + } + continue; + case BuildGraphNode::Built: + if (m_doDebug) { + m_logger.qbsDebug() << "[EXEC] " << nodeToBuild->toString(); + m_logger.qbsDebug() << "[EXEC] node already built. Skipping."; + } + continue; + } + + nodeToBuild->accept(this); } return !m_leaves.empty() || !m_processingJobs.isEmpty(); + } bool Executor::isUpToDate(Artifact *artifact) const @@ -387,11 +411,15 @@ bool Executor::isUpToDate(Artifact *artifact) const return false; } - foreach (Artifact *child, artifact->children) { - QBS_CHECK(child->timestamp().isValid()); + foreach (BuildGraphNode *child, artifact->children) { + Artifact *childArtifact = dynamic_cast<Artifact *>(child); + if (!childArtifact) + continue; + QBS_CHECK(childArtifact->timestamp().isValid()); if (debug) - m_logger.qbsDebug() << "[UTD] child timestamp " << child->timestamp().toString(); - if (artifact->timestamp() < child->timestamp()) + m_logger.qbsDebug() << "[UTD] child timestamp " + << childArtifact->timestamp().toString(); + if (artifact->timestamp() < childArtifact->timestamp()) return false; } @@ -429,13 +457,6 @@ void Executor::buildArtifact(Artifact *artifact) if (m_doDebug) m_logger.qbsDebug() << "[EXEC] " << relativeArtifactFileName(artifact); - // Skip artifacts that are already built. - if (artifact->buildState == Artifact::Built) { - if (m_doDebug) - m_logger.qbsDebug() << "[EXEC] artifact already built. Skipping."; - return; - } - // skip artifacts without transformer if (artifact->artifactType != Artifact::Generated) { // For source artifacts, that were not reachable when initializing the build, we must @@ -495,7 +516,7 @@ void Executor::buildArtifact(Artifact *artifact) // create the output directories if (!m_buildOptions.dryRun()) { - ArtifactList::const_iterator it = artifact->transformer->outputs.begin(); + ArtifactSet::const_iterator it = artifact->transformer->outputs.begin(); for (; it != artifact->transformer->outputs.end(); ++it) { Artifact *output = *it; QDir outDir = QFileInfo(output->filePath()).absoluteDir(); @@ -511,8 +532,8 @@ void Executor::buildArtifact(Artifact *artifact) // postpone the build of this artifact, if new dependencies found if (scanner.newDependencyAdded()) { bool buildingDependenciesFound = false; - QVector<Artifact *> unbuiltDependencies; - foreach (Artifact *dependency, artifact->children) { + QVector<BuildGraphNode *> unbuiltDependencies; + foreach (BuildGraphNode *dependency, artifact->children) { switch (dependency->buildState) { case Artifact::Untouched: case Artifact::Buildable: @@ -548,6 +569,59 @@ void Executor::buildArtifact(Artifact *artifact) job->run(artifact->transformer.data(), artifact->product); } +void Executor::buildPhonyTarget(PhonyTarget *target) +{ + if (target->transformer()) { + if (m_doDebug) + m_logger.qbsDebug() << "[EXEC] " << target->toString(); + + // Skip targets that are already built. + if (target->buildState == Artifact::Built) { + if (m_doDebug) + m_logger.qbsDebug() << "[EXEC] phony target already built. Skipping."; + return; + } + + } else { + if (m_doDebug) + m_logger.qbsDebug() << "[EXEC] " << target->toString() + << " No transformer. Skipping."; + } + finishNode(target); +} + +void Executor::executeRuleNode(RuleNode *ruleNode) +{ + RuleNode::ApplicationResult result; + ruleNode->apply(m_logger, &result); + + if (result.upToDate) { + if (m_doDebug) + m_logger.qbsDebug() << "[EXEC] " << ruleNode->toString() + << " is up to date. Skipping."; + } else { + qDebug() << "EXEC RULE" << ruleNode->toString(); + if (m_doDebug) + m_logger.qbsDebug() << "[EXEC] " << ruleNode->toString(); + const QVector<BuildGraphNode *> &createdNodes = result.createdNodes; + const WeakPointer<ResolvedProduct> &product = ruleNode->product; + foreach (BuildGraphNode *node, createdNodes) { + if (m_doDebug) + m_logger.qbsDebug() << "[EXEC] rule created " << node->toString(); + loggedConnect(node, ruleNode, m_logger); + Artifact *artifact = dynamic_cast<Artifact *>(node); + if (!artifact) + continue; + if (artifact->fileTags.matches(product->fileTags)) { + product->buildData->roots += artifact; + product->buildData->targetArtifacts += artifact; + } + } + insertLeavesAfterAddingDependencies(createdNodes); + } + finishNode(ruleNode); +} + void Executor::finishJob(ExecutorJob *job, bool success) { QBS_CHECK(job); @@ -583,27 +657,21 @@ void Executor::finishJob(ExecutorJob *job, bool success) } } -static bool allChildrenBuilt(Artifact *artifact) +static bool allChildrenBuilt(BuildGraphNode *node) { - foreach (Artifact *child, artifact->children) + foreach (BuildGraphNode *child, node->children) if (child->buildState != Artifact::Built) return false; return true; } -void Executor::finishArtifact(Artifact *leaf) +void Executor::finishNode(BuildGraphNode *leaf) { - QBS_CHECK(leaf); - - if (m_doTrace) - m_logger.qbsTrace() << "[EXEC] finishArtifact " << relativeArtifactFileName(leaf); - leaf->buildState = Artifact::Built; - m_scanResultCache.remove(leaf->filePath()); - foreach (Artifact *parent, leaf->parents) { + foreach (BuildGraphNode *parent, leaf->parents) { if (parent->buildState != Artifact::Buildable) { if (m_doTrace) { - m_logger.qbsTrace() << "[EXEC] parent " << relativeArtifactFileName(parent) + m_logger.qbsTrace() << "[EXEC] parent " << parent->toString() << " build state: " << toString(parent->buildState); } continue; @@ -612,16 +680,26 @@ void Executor::finishArtifact(Artifact *leaf) if (allChildrenBuilt(parent)) { m_leaves.push(parent); if (m_doTrace) { - m_logger.qbsTrace() << "[EXEC] finishArtifact adds leaf " - << relativeArtifactFileName(parent) << " " << toString(parent->buildState); + m_logger.qbsTrace() << "[EXEC] finishNode adds leaf " + << parent->toString() << " " << toString(parent->buildState); } } else { if (m_doTrace) { - m_logger.qbsTrace() << "[EXEC] parent " << relativeArtifactFileName(parent) + m_logger.qbsTrace() << "[EXEC] parent " << parent->toString() << " build state: " << toString(parent->buildState); } } } +} + +void Executor::finishArtifact(Artifact *leaf) +{ + QBS_CHECK(leaf); + if (m_doTrace) + m_logger.qbsTrace() << "[EXEC] finishArtifact " << relativeArtifactFileName(leaf); + + finishNode(leaf); + m_scanResultCache.remove(leaf->filePath()); if (leaf->transformer) foreach (Artifact *sideBySideArtifact, leaf->transformer->outputs) @@ -632,28 +710,28 @@ void Executor::finishArtifact(Artifact *leaf) m_progressObserver->incrementProgressValue(BuildEffortCalculator::multiplier(leaf)); } -void Executor::insertLeavesAfterAddingDependencies_recurse(Artifact *const artifact, - QSet<Artifact *> *seenArtifacts, Leaves *leaves) const +void Executor::insertLeavesAfterAddingDependencies_recurse(BuildGraphNode *const node, + QSet<BuildGraphNode *> *seenNodes, Leaves *leaves) const { - if (seenArtifacts->contains(artifact)) + if (seenNodes->contains(node)) return; - seenArtifacts->insert(artifact); + seenNodes->insert(node); - if (artifact->buildState == Artifact::Untouched) - artifact->buildState = Artifact::Buildable; + if (node->buildState == Artifact::Untouched) + node->buildState = Artifact::Buildable; bool isLeaf = true; - foreach (Artifact *child, artifact->children) { + foreach (BuildGraphNode *child, node->children) { if (child->buildState != Artifact::Built) { isLeaf = false; - insertLeavesAfterAddingDependencies_recurse(child, seenArtifacts, leaves); + insertLeavesAfterAddingDependencies_recurse(child, seenNodes, leaves); } } if (isLeaf) { if (m_doDebug) - m_logger.qbsDebug() << "[EXEC] adding leaf " << relativeArtifactFileName(artifact); - leaves->push(artifact); + m_logger.qbsDebug() << "[EXEC] adding leaf " << node->toString(); + leaves->push(node); } } @@ -662,11 +740,11 @@ QString Executor::configString() const return tr(" for configuration %1").arg(m_project->id()); } -void Executor::insertLeavesAfterAddingDependencies(QVector<Artifact *> dependencies) +void Executor::insertLeavesAfterAddingDependencies(QVector<BuildGraphNode *> dependencies) { - QSet<Artifact *> seenArtifacts; - foreach (Artifact *dependency, dependencies) - insertLeavesAfterAddingDependencies_recurse(dependency, &seenArtifacts, &m_leaves); + QSet<BuildGraphNode *> seenNodes; + foreach (BuildGraphNode *dependency, dependencies) + insertLeavesAfterAddingDependencies_recurse(dependency, &seenNodes, &m_leaves); } void Executor::cancelJobs() @@ -731,27 +809,19 @@ void Executor::addExecutorJobs(int jobNumber) } } -void Executor::runAutoMoc() +void Executor::runTagScanners() { - bool autoMocApplied = false; foreach (const ResolvedProductPtr &product, m_productsToBuild) { if (m_progressObserver && m_progressObserver->canceled()) throw ErrorInfo(Tr::tr("Build canceled%1.").arg(configString())); - // HACK call the automoc thingy here only if we have use Qt/core module - foreach (const ResolvedModuleConstPtr &m, product->modules) { - if (m->name == "Qt/core") { - autoMocApplied = true; - m_autoMoc->apply(product); - break; - } - } + QHash<FileTag, QList<Artifact *> > sourceArtifacts; + foreach (Artifact *artifact, m_changedSourceArtifacts) + foreach (const FileTag &tag, artifact->fileTags) + sourceArtifacts[tag] += artifact; + foreach (const TagScannerConstPtr &rootTagScanner, product->tagScanners) + runTagScannersTopOrdered(&m_scanResultCache, product, rootTagScanner, sourceArtifacts, + m_logger); } - if (autoMocApplied) { - foreach (const ResolvedProductConstPtr &product, m_productsToBuild) - CycleDetector(m_logger).visitProduct(product); - } - if (m_progressObserver) - m_progressObserver->incrementProgressValue(m_mocEffort); } void Executor::onProcessError(const qbs::ErrorInfo &err) @@ -800,8 +870,8 @@ void Executor::finish() QStringList unbuiltProductNames; foreach (const ResolvedProductPtr &product, m_productsToBuild) { - foreach (Artifact *artifact, product->buildData->targetArtifacts) { - if (artifact->buildState != Artifact::Built) { + foreach (BuildGraphNode *rootNode, product->buildData->roots) { + if (rootNode->buildState != Artifact::Built) { unbuiltProductNames += product->name; break; } @@ -823,35 +893,59 @@ void Executor::finish() emit finished(); } +bool Executor::visit(Artifact *artifact) +{ + buildArtifact(artifact); + return false; +} + +bool Executor::visit(PhonyTarget *target) +{ + buildPhonyTarget(target); + return false; +} + +bool Executor::visit(RuleNode *ruleNode) +{ + executeRuleNode(ruleNode); + return false; +} + /** * Sets the state of all artifacts in the graph to "untouched". * This must be done before doing a build. * * Retrieves the timestamps of source artifacts. * - * This function sets *sourceFilesChanged to true, if the timestamp of a reachable source artifact - * changed. + * This function also fills the list of changed source files. */ -void Executor::prepareAllArtifacts(bool *sourceFilesChanged) +void Executor::prepareAllNodes() { foreach (const ResolvedProductPtr &product, m_productsToBuild) { - foreach (Artifact *artifact, product->buildData->artifacts) { - artifact->buildState = Artifact::Untouched; - artifact->inputsScanned = false; - artifact->timestampRetrieved = false; + foreach (BuildGraphNode *node, product->buildData->nodes) { + node->buildState = Artifact::Untouched; + Artifact *artifact = dynamic_cast<Artifact *>(node); + if (artifact) + prepareArtifact(artifact); + } + } +} - if (artifact->artifactType == Artifact::SourceFile) { - const FileTime oldTimestamp = artifact->timestamp(); - retrieveSourceFileTimestamp(artifact); - if (oldTimestamp != artifact->timestamp()) - *sourceFilesChanged = true; - } +void Executor::prepareArtifact(Artifact *artifact) +{ + artifact->inputsScanned = false; + artifact->timestampRetrieved = false; - // Timestamps of file dependencies must be invalid for every build. - foreach (FileDependency *fileDependency, artifact->fileDependencies) - fileDependency->clearTimestamp(); - } + if (artifact->artifactType == Artifact::SourceFile) { + const FileTime oldTimestamp = artifact->timestamp(); + retrieveSourceFileTimestamp(artifact); + if (oldTimestamp != artifact->timestamp()) + m_changedSourceArtifacts.append(artifact); } + + // Timestamps of file dependencies must be invalid for every build. + foreach (FileDependency *fileDependency, artifact->fileDependencies) + fileDependency->clearTimestamp(); } /** @@ -860,38 +954,39 @@ void Executor::prepareAllArtifacts(bool *sourceFilesChanged) */ void Executor::prepareReachableArtifacts(const Artifact::BuildState buildState) { - foreach (Artifact *root, m_roots) + foreach (BuildGraphNode *root, m_roots) prepareReachableArtifacts_impl(root, buildState); } -void Executor::prepareReachableArtifacts_impl(Artifact *artifact, +void Executor::prepareReachableArtifacts_impl(BuildGraphNode *node, const Artifact::BuildState buildState) { - if (artifact->buildState != Artifact::Untouched) + if (node->buildState != Artifact::Untouched) return; - artifact->buildState = buildState; - foreach (Artifact *child, artifact->children) + node->buildState = buildState; + foreach (BuildGraphNode *child, node->children) prepareReachableArtifacts_impl(child, buildState); } void Executor::updateBuildGraph(Artifact::BuildState buildState) { - QSet<Artifact *> seenArtifacts; - foreach (Artifact *root, m_roots) + QSet<BuildGraphNode *> seenArtifacts; + foreach (BuildGraphNode *root, m_roots) updateBuildGraph_impl(root, buildState, seenArtifacts); } -void Executor::updateBuildGraph_impl(Artifact *artifact, Artifact::BuildState buildState, QSet<Artifact *> &seenArtifacts) +void Executor::updateBuildGraph_impl(BuildGraphNode *node, Artifact::BuildState buildState, + QSet<BuildGraphNode *> &seenNodes) { - if (seenArtifacts.contains(artifact)) + if (seenNodes.contains(node)) return; - seenArtifacts += artifact; - artifact->buildState = buildState; + seenNodes += node; + node->buildState = buildState; - foreach (Artifact *child, artifact->children) - updateBuildGraph_impl(child, buildState, seenArtifacts); + foreach (BuildGraphNode *child, node->children) + updateBuildGraph_impl(child, buildState, seenNodes); } void Executor::setState(ExecutorState s) |
