aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@digia.com>2012-11-13 11:55:02 +0100
committerJoerg Bornemann <joerg.bornemann@digia.com>2012-11-13 15:21:29 +0100
commit96db5a6b8d957e30379a8bba2ee47dae5387c4d3 (patch)
treee39beb62ed41c41f41392d4f0996024f0362ce0d
parentfdca8c555fdbb224bbffbf16ea1d42a155579b5e (diff)
introduce property RuleArtifact.alwaysUpdated
RuleArtifact.alwaysUpdated is a bool property that specifies, if an output artifact will always be updated by its transformer. The default value is true. When finishing the build of artifact A, qbs will retrieve the timestamp of A, if and only if A.alwaysUpdated is false. Otherwise the actual timestamp of A is ignored and the current time is used. When determining whether to run a transformer, only the timestamps of artifacts that have alwaysUpdated set to true are taken into account. Transformers whose outputs have all alwaysUpdated == false are always executed. Change-Id: I19d2626f17640a813f862980fafd507a13fcca95 Reviewed-by: Christian Kandeler <christian.kandeler@digia.com>
-rw-r--r--src/lib/buildgraph/artifact.cpp9
-rw-r--r--src/lib/buildgraph/artifact.h9
-rw-r--r--src/lib/buildgraph/buildgraph.cpp1
-rw-r--r--src/lib/buildgraph/executor.cpp37
-rw-r--r--src/lib/language/language.h5
-rw-r--r--src/lib/language/loader.cpp10
-rw-r--r--src/lib/tools/persistence.cpp2
7 files changed, 53 insertions, 20 deletions
diff --git a/src/lib/buildgraph/artifact.cpp b/src/lib/buildgraph/artifact.cpp
index 367f30234..b48cb0b73 100644
--- a/src/lib/buildgraph/artifact.cpp
+++ b/src/lib/buildgraph/artifact.cpp
@@ -61,6 +61,7 @@ Artifact::Artifact(BuildProject *p)
, buildState(Untouched)
, inputsScanned(false)
, timestampRetrieved(false)
+ , alwaysUpdated(true)
{
}
@@ -80,10 +81,13 @@ void Artifact::load(PersistentPool &pool)
fileTags = pool.idLoadStringSet();
properties = pool.idLoadS<PropertyMap>();
transformer = pool.idLoadS<Transformer>();
+ unsigned char c;
pool.stream()
>> artifactType
>> timestamp
- >> autoMocTimestamp;
+ >> autoMocTimestamp
+ >> c;
+ alwaysUpdated = c;
}
void Artifact::store(PersistentPool &pool) const
@@ -95,7 +99,8 @@ void Artifact::store(PersistentPool &pool) const
pool.stream()
<< artifactType
<< timestamp
- << autoMocTimestamp;
+ << autoMocTimestamp
+ << static_cast<unsigned char>(alwaysUpdated);
}
} // namespace Internal
diff --git a/src/lib/buildgraph/artifact.h b/src/lib/buildgraph/artifact.h
index e0c902e1b..cc55f3778 100644
--- a/src/lib/buildgraph/artifact.h
+++ b/src/lib/buildgraph/artifact.h
@@ -85,11 +85,10 @@ public:
ArtifactType artifactType;
FileTime timestamp;
FileTime autoMocTimestamp;
-
- // Do not serialize the following members. They'll be refreshed for every build.
- BuildState buildState;
- bool inputsScanned : 1;
- bool timestampRetrieved : 1;
+ BuildState buildState; // Do not serialize. Will be refreshed for every build.
+ bool inputsScanned : 1; // Do not serialize. Will be refreshed for every build.
+ bool timestampRetrieved : 1; // Do not serialize. Will be refreshed for every build.
+ bool alwaysUpdated : 1;
void setFilePath(const QString &filePath);
const QString &filePath() const { return m_filePath; }
diff --git a/src/lib/buildgraph/buildgraph.cpp b/src/lib/buildgraph/buildgraph.cpp
index a4862133e..65d710a95 100644
--- a/src/lib/buildgraph/buildgraph.cpp
+++ b/src/lib/buildgraph/buildgraph.cpp
@@ -1421,6 +1421,7 @@ Artifact *RulesApplicator::createOutputArtifact(const RuleArtifact::ConstPtr &ru
outputArtifact->artifactType = Artifact::Generated;
outputArtifact->setFilePath(outputPath);
outputArtifact->fileTags = ruleArtifact->fileTags.toSet();
+ outputArtifact->alwaysUpdated = ruleArtifact->alwaysUpdated;
m_buildGraph->insert(m_buildProduct, outputArtifact);
}
diff --git a/src/lib/buildgraph/executor.cpp b/src/lib/buildgraph/executor.cpp
index b54f60f02..216154c9f 100644
--- a/src/lib/buildgraph/executor.cpp
+++ b/src/lib/buildgraph/executor.cpp
@@ -328,6 +328,18 @@ static bool isUpToDate(Artifact *artifact)
return true;
}
+static bool mustExecuteTransformer(const QSharedPointer<Transformer> &transformer)
+{
+ foreach (Artifact *artifact, transformer->outputs)
+ if (artifact->alwaysUpdated)
+ return !isUpToDate(artifact);
+
+ // All outputs of the transformer have alwaysUpdated == false.
+ // We need at least on output that is always updated.
+ Q_ASSERT(false);
+ return true;
+}
+
void Executor::buildArtifact(Artifact *artifact)
{
if (qbsLogLevel(LoggerDebug))
@@ -358,14 +370,6 @@ void Executor::buildArtifact(Artifact *artifact)
// Every generated artifact must have a transformer.
Q_ASSERT(artifact->transformer);
- // skip artifacts that are up-to-date
- if (isUpToDate(artifact)) {
- if (qbsLogLevel(LoggerDebug))
- qbsDebug("[EXEC] Up to date. Skipping.");
- finishArtifact(artifact);
- return;
- }
-
// Skip if outputs of this transformer are already built.
// That means we already ran the transformation.
foreach (Artifact *sideBySideArtifact, artifact->transformer->outputs) {
@@ -389,6 +393,14 @@ void Executor::buildArtifact(Artifact *artifact)
}
}
+ // Skip transformers that do not need to be built.
+ if (!mustExecuteTransformer(artifact->transformer)) {
+ if (qbsLogLevel(LoggerDebug))
+ qbsDebug("[EXEC] Up to date. Skipping.");
+ finishArtifact(artifact);
+ return;
+ }
+
// create the output directories
QSet<Artifact*>::const_iterator it = artifact->transformer->outputs.begin();
for (; it != artifact->transformer->outputs.end(); ++it) {
@@ -609,9 +621,12 @@ void Executor::onProcessSuccess()
// Update the timestamps of the outputs of the transformer we just executed.
processedArtifact->project->markDirty();
- const FileTime currentTime = FileTime::currentTime();
- foreach (Artifact *sideBySideArtifact, processedArtifact->transformer->outputs)
- sideBySideArtifact->timestamp = currentTime;
+ foreach (Artifact *artifact, processedArtifact->transformer->outputs) {
+ if (artifact->alwaysUpdated)
+ artifact->timestamp = FileTime::currentTime();
+ else
+ artifact->timestamp = FileInfo(artifact->filePath()).lastModified();
+ }
finishArtifact(processedArtifact);
diff --git a/src/lib/language/language.h b/src/lib/language/language.h
index 8fa3efad8..89463133b 100644
--- a/src/lib/language/language.h
+++ b/src/lib/language/language.h
@@ -120,6 +120,7 @@ public:
QString fileName;
QStringList fileTags;
+ bool alwaysUpdated;
struct Binding
{
@@ -131,7 +132,9 @@ public:
QVector<Binding> bindings;
private:
- RuleArtifact() {}
+ RuleArtifact()
+ : alwaysUpdated(true)
+ {}
void load(PersistentPool &pool);
void store(PersistentPool &pool) const;
diff --git a/src/lib/language/loader.cpp b/src/lib/language/loader.cpp
index d457719c2..01f0c95a5 100644
--- a/src/lib/language/loader.cpp
+++ b/src/lib/language/loader.cpp
@@ -1198,6 +1198,7 @@ void Loader::setupBuiltinDeclarations()
artifact += conditionProperty;
artifact += PropertyDeclaration("fileName", PropertyDeclaration::Verbatim);
artifact += PropertyDeclaration("fileTags", PropertyDeclaration::Variant);
+ artifact += PropertyDeclaration("alwaysUpdated", PropertyDeclaration::Boolean);
m_builtinDeclarations.insert(name_Artifact, artifact);
QList<PropertyDeclaration> rule;
@@ -2334,6 +2335,7 @@ Rule::Ptr Loader::resolveRule(EvaluationObject *object, ResolvedModule::ConstPtr
// read artifacts
QList<RuleArtifact::ConstPtr> artifacts;
+ bool hasAlwaysUpdatedArtifact = false;
foreach (EvaluationObject *child, object->children) {
const uint hashChildPrototypeName = qHash(child->prototype);
if (hashChildPrototypeName == hashName_Artifact) {
@@ -2341,6 +2343,9 @@ Rule::Ptr Loader::resolveRule(EvaluationObject *object, ResolvedModule::ConstPtr
artifacts.append(artifact);
artifact->fileName = child->scope->verbatimValue("fileName");
artifact->fileTags = child->scope->stringListValue("fileTags");
+ artifact->alwaysUpdated = child->scope->boolValue("alwaysUpdated", true);
+ if (artifact->alwaysUpdated)
+ hasAlwaysUpdatedArtifact = true;
LanguageObject *origArtifactObj = child->instantiatingObject();
foreach (const Binding &binding, origArtifactObj->bindings) {
if (binding.name.length() <= 1)
@@ -2358,6 +2363,11 @@ Rule::Ptr Loader::resolveRule(EvaluationObject *object, ResolvedModule::ConstPtr
}
}
+ if (!hasAlwaysUpdatedArtifact)
+ throw Error(Tr::tr("At least one output artifact of a rule "
+ "must have alwaysUpdated set to true."),
+ object->instantiatingObject()->prototypeLocation);
+
const PrepareScript::Ptr prepareScript = PrepareScript::create();
prepareScript->script = object->scope->verbatimValue("prepare");
prepareScript->location.fileName = object->instantiatingObject()->file->fileName;
diff --git a/src/lib/tools/persistence.cpp b/src/lib/tools/persistence.cpp
index 06c915f74..bc9bea07d 100644
--- a/src/lib/tools/persistence.cpp
+++ b/src/lib/tools/persistence.cpp
@@ -39,7 +39,7 @@
namespace qbs {
namespace Internal {
-static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE0_0_1__22";
+static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE0_0_1__23";
PersistentPool::PersistentPool()
{