aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/corelib/buildgraph/buildgraph.cpp
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@digia.com>2014-02-10 18:08:01 +0100
committerJoerg Bornemann <joerg.bornemann@digia.com>2014-02-13 15:33:27 +0100
commite73f60919079fc7cb0f0ad6d50b1a364c7b0d2a6 (patch)
tree3ce15f1f9b336063d591999ce325ce28a6e21320 /src/lib/corelib/buildgraph/buildgraph.cpp
parenta3634a6bbb193c47cdec887a6b29356c979961aa (diff)
support transformers with an unknown number of outputs
To support different types of nodes in the build graph, we introduce the base class BuildGraphNode. Artifact now derives from BuildGraphNode. A RuleNode class is introduced that represents a rule in the build graph. Rules are applied in the build phase and not in a pre-build phase anymore. The handling of moc has been revisited. The fixed automoc pre-build phase is no more. This is the squashed merge of a feature branch. Task-number: QBS-370 Change-Id: If27cdc51cba8c9542e4282c2caa456faa723aeff Reviewed-by: Christian Kandeler <christian.kandeler@digia.com>
Diffstat (limited to 'src/lib/corelib/buildgraph/buildgraph.cpp')
-rw-r--r--src/lib/corelib/buildgraph/buildgraph.cpp103
1 files changed, 62 insertions, 41 deletions
diff --git a/src/lib/corelib/buildgraph/buildgraph.cpp b/src/lib/corelib/buildgraph/buildgraph.cpp
index 252f636cf..dd36ee15c 100644
--- a/src/lib/corelib/buildgraph/buildgraph.cpp
+++ b/src/lib/corelib/buildgraph/buildgraph.cpp
@@ -216,14 +216,14 @@ void setupScriptEngineForProduct(ScriptEngine *engine, const ResolvedProductCons
rule->module->name.isEmpty() ? QScriptValue() : rule->module->name);
}
-bool findPath(Artifact *u, Artifact *v, QList<Artifact*> &path)
+bool findPath(BuildGraphNode *u, BuildGraphNode *v, QList<BuildGraphNode *> &path)
{
if (u == v) {
path.append(v);
return true;
}
- for (ArtifactSet::const_iterator it = u->children.begin(); it != u->children.end(); ++it) {
+ for (NodeSet::const_iterator it = u->children.begin(); it != u->children.end(); ++it) {
if (findPath(*it, v, path)) {
path.prepend(u);
return true;
@@ -242,28 +242,34 @@ bool findPath(Artifact *u, Artifact *v, QList<Artifact*> &path)
* also: children means i depend on or i am produced by
* parent means "produced by me" or "depends on me"
*/
-void connect(Artifact *p, Artifact *c)
+void connect(BuildGraphNode *p, BuildGraphNode *c)
{
QBS_CHECK(p != c);
- foreach (const Artifact * const child, p->children)
- if (child != c && child->filePath() == c->filePath())
- throw ErrorInfo(QString::fromLocal8Bit("Artifact %1 already has a child artifact %2 as different object.").arg(p->filePath(), c->filePath()), CodeLocation(), true);
+ if (Artifact *ac = dynamic_cast<Artifact *>(c)) {
+ foreach (const Artifact * const child, ArtifactSet::fromNodeSet(p->children))
+ if (child != ac && child->filePath() == ac->filePath()) {
+ throw ErrorInfo(QString::fromLocal8Bit("%1 already has a child artifact %2 as "
+ "different object.").arg(p->toString(),
+ ac->filePath()),
+ CodeLocation(), true);
+ }
+ }
p->children.insert(c);
c->parents.insert(p);
p->product->topLevelProject()->buildData->isDirty = true;
}
-void loggedConnect(Artifact *u, Artifact *v, const Logger &logger)
+void loggedConnect(BuildGraphNode *u, BuildGraphNode *v, const Logger &logger)
{
QBS_CHECK(u != v);
if (logger.traceEnabled()) {
logger.qbsTrace() << QString::fromLocal8Bit("[BG] connect '%1' -> '%2'")
- .arg(relativeArtifactFileName(u), relativeArtifactFileName(v));
+ .arg(u->toString(), v->toString());
}
connect(u, v);
}
-static bool existsPath_impl(Artifact *u, Artifact *v, QSet<Artifact *> *seen)
+static bool existsPath_impl(BuildGraphNode *u, BuildGraphNode *v, QSet<BuildGraphNode *> *seen)
{
if (u == v)
return true;
@@ -272,19 +278,27 @@ static bool existsPath_impl(Artifact *u, Artifact *v, QSet<Artifact *> *seen)
return false;
seen->insert(u);
- for (ArtifactSet::const_iterator it = u->children.begin(); it != u->children.end(); ++it)
+ for (NodeSet::const_iterator it = u->children.begin(); it != u->children.end(); ++it)
if (existsPath_impl(*it, v, seen))
return true;
return false;
}
-static bool existsPath(Artifact *u, Artifact *v)
+static bool existsPath(BuildGraphNode *u, BuildGraphNode *v)
{
- QSet<Artifact *> seen;
+ QSet<BuildGraphNode *> seen;
return existsPath_impl(u, v, &seen);
}
+static QStringList toStringList(const QList<BuildGraphNode *> &path)
+{
+ QStringList lst;
+ foreach (BuildGraphNode *node, path)
+ lst << node->toString();
+ return lst;
+}
+
bool safeConnect(Artifact *u, Artifact *v, const Logger &logger)
{
QBS_CHECK(u != v);
@@ -294,7 +308,7 @@ bool safeConnect(Artifact *u, Artifact *v, const Logger &logger)
}
if (existsPath(v, u)) {
- QList<Artifact *> circle;
+ QList<BuildGraphNode *> circle;
findPath(v, u, circle);
logger.qbsTrace() << "[BG] safeConnect: circle detected " << toStringList(circle);
return false;
@@ -304,31 +318,32 @@ bool safeConnect(Artifact *u, Artifact *v, const Logger &logger)
return true;
}
-void disconnect(Artifact *u, Artifact *v, const Logger &logger)
+void disconnect(BuildGraphNode *u, BuildGraphNode *v, const Logger &logger)
{
if (logger.traceEnabled()) {
logger.qbsTrace() << QString::fromLocal8Bit("[BG] disconnect: '%1' '%2'")
- .arg(relativeArtifactFileName(u), relativeArtifactFileName(v));
+ .arg(u->toString(), v->toString());
}
u->children.remove(v);
- u->childrenAddedByScanner.remove(v);
v->parents.remove(u);
+ u->onChildDisconnected(v);
}
void removeGeneratedArtifactFromDisk(Artifact *artifact, const Logger &logger)
{
if (artifact->artifactType != Artifact::Generated)
return;
+ removeGeneratedArtifactFromDisk(artifact->filePath(), logger);
+}
- QFile file(artifact->filePath());
+void removeGeneratedArtifactFromDisk(const QString &filePath, const Logger &logger)
+{
+ QFile file(filePath);
if (!file.exists())
return;
-
- logger.qbsDebug() << "removing " << artifact->fileName();
- if (!file.remove()) {
- logger.qbsWarning() << QString::fromLocal8Bit("Cannot remove '%1'.")
- .arg(artifact->filePath());
- }
+ logger.qbsDebug() << "removing " << filePath;
+ if (!file.remove())
+ logger.qbsWarning() << QString::fromLocal8Bit("Cannot remove '%1'.").arg(filePath);
}
QString relativeArtifactFileName(const Artifact *artifact)
@@ -404,7 +419,7 @@ void insertArtifact(const ResolvedProductPtr &product, Artifact *artifact, const
{
QBS_CHECK(!artifact->product);
QBS_CHECK(!artifact->filePath().isEmpty());
- QBS_CHECK(!product->buildData->artifacts.contains(artifact));
+ QBS_CHECK(!product->buildData->nodes.contains(artifact));
#ifdef QT_DEBUG
foreach (const ResolvedProductConstPtr &otherProduct, product->project->products) {
if (lookupArtifact(otherProduct, artifact->filePath())) {
@@ -421,7 +436,7 @@ void insertArtifact(const ResolvedProductPtr &product, Artifact *artifact, const
}
}
#endif
- product->buildData->artifacts.insert(artifact);
+ product->buildData->nodes.insert(artifact);
artifact->product = product;
product->topLevelProject()->buildData->insertIntoLookupTable(artifact);
product->topLevelProject()->buildData->isDirty = true;
@@ -443,25 +458,31 @@ static void doSanityChecksForProduct(const ResolvedProductConstPtr &product, con
QBS_CHECK(!!product->enabled == !!buildData);
if (!product->enabled)
return;
- foreach (Artifact * const ta, buildData->targetArtifacts) {
+ foreach (BuildGraphNode * const node, buildData->roots) {
if (logger.traceEnabled())
- logger.qbsTrace() << "Checking target artifact '" << ta->fileName() << "'.";
- QBS_CHECK(buildData->artifacts.contains(ta));
+ logger.qbsTrace() << "Checking root node '" << node->toString() << "'.";
+ QBS_CHECK(buildData->nodes.contains(node));
}
QSet<QString> filePaths;
- foreach (Artifact * const artifact, buildData->artifacts) {
- logger.qbsDebug() << "Sanity checking artifact '" << artifact->fileName() << "'";
+ foreach (BuildGraphNode * const node, buildData->nodes) {
+ logger.qbsDebug() << "Sanity checking node '" << node->toString() << "'";
+ QBS_CHECK(node->product == product);
+ foreach (const BuildGraphNode * const parent, node->parents)
+ QBS_CHECK(parent->children.contains(node));
+ foreach (BuildGraphNode * const child, node->children) {
+ QBS_CHECK(child->parents.contains(node));
+ QBS_CHECK(child->product);
+ QBS_CHECK(!child->product->buildData.isNull());
+ QBS_CHECK(child->product->buildData->nodes.contains(child));
+ }
+
+ Artifact * const artifact = dynamic_cast<Artifact *>(node);
+ if (!artifact)
+ continue;
+
QBS_CHECK(!filePaths.contains(artifact->filePath()));
filePaths << artifact->filePath();
- QBS_CHECK(artifact->product == product);
- foreach (const Artifact * const parent, artifact->parents)
- QBS_CHECK(parent->children.contains(artifact));
- foreach (Artifact * const child, artifact->children) {
- QBS_CHECK(child->parents.contains(artifact));
- QBS_CHECK(!child->product.isNull());
- QBS_CHECK(child->product->buildData);
- QBS_CHECK(child->product->buildData->artifacts.contains(child));
- }
+
foreach (Artifact * const child, artifact->childrenAddedByScanner)
QBS_CHECK(artifact->children.contains(child));
const TransformerConstPtr transformer = artifact->transformer;
@@ -475,9 +496,9 @@ static void doSanityChecksForProduct(const ResolvedProductConstPtr &product, con
ArtifactSet transformerOutputChildren;
foreach (const Artifact * const output, transformer->outputs) {
QBS_CHECK(output->transformer == transformer);
- transformerOutputChildren.unite(output->children);
+ transformerOutputChildren.unite(ArtifactSet::fromNodeSet(output->children));
QSet<QString> childFilePaths;
- foreach (const Artifact * const a, output->children) {
+ foreach (const Artifact * const a, ArtifactSet::fromNodeSet(output->children)) {
if (childFilePaths.contains(a->filePath())) {
throw ErrorInfo(QString::fromLocal8Bit("There is more than one artifact for "
"file '%1' in the child list for output '%2'.")