diff options
author | Christian Kandeler <christian.kandeler@digia.com> | 2012-11-29 16:25:17 +0100 |
---|---|---|
committer | Joerg Bornemann <joerg.bornemann@digia.com> | 2012-12-03 11:07:09 +0100 |
commit | 29150c3efdf0afee63317486760bc7b7a30cac3d (patch) | |
tree | ff41c26d328ac625ed0b56edb09c69af52fb2fdf | |
parent | bb75c2724f4e09327b342f5372719d286526f271 (diff) |
Move engine-related functionality out of BuildGraph.
Change-Id: I5da16ea99bce3e6f737f37770fb0fe3e2e5c0214
Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
-rw-r--r-- | src/lib/api/internaljobs.cpp | 19 | ||||
-rw-r--r-- | src/lib/buildgraph/automoc.cpp | 7 | ||||
-rw-r--r-- | src/lib/buildgraph/automoc.h | 4 | ||||
-rw-r--r-- | src/lib/buildgraph/buildgraph.cpp | 197 | ||||
-rw-r--r-- | src/lib/buildgraph/buildgraph.h | 78 | ||||
-rw-r--r-- | src/lib/buildgraph/buildgraph.pri | 6 | ||||
-rw-r--r-- | src/lib/buildgraph/executor.cpp | 29 | ||||
-rw-r--r-- | src/lib/buildgraph/executor.h | 5 | ||||
-rw-r--r-- | src/lib/buildgraph/rulesevaluationcontext.cpp | 116 | ||||
-rw-r--r-- | src/lib/buildgraph/rulesevaluationcontext.h | 81 |
10 files changed, 320 insertions, 222 deletions
diff --git a/src/lib/api/internaljobs.cpp b/src/lib/api/internaljobs.cpp index 67ff0deee..19543cc8f 100644 --- a/src/lib/api/internaljobs.cpp +++ b/src/lib/api/internaljobs.cpp @@ -31,9 +31,9 @@ #include <buildgraph/artifactcleaner.h> #include <buildgraph/buildgraph.h> #include <buildgraph/executor.h> +#include <buildgraph/rulesevaluationcontext.h> #include <language/language.h> #include <language/loader.h> -#include <language/scriptengine.h> #include <logging/logger.h> #include <logging/translator.h> #include <tools/error.h> @@ -143,25 +143,23 @@ void InternalSetupProjectJob::doResolve() void InternalSetupProjectJob::execute() { - ScriptEngine scriptEngine; - QScopedPointer<BuildGraph> buildGraph(new BuildGraph); - buildGraph->setEngine(&scriptEngine); - buildGraph->setProgressObserver(observer()); + QScopedPointer<RulesEvaluationContext> evalContext(new RulesEvaluationContext); + evalContext->setObserver(observer()); const QStringList searchPaths = Settings().searchPaths(); const BuildProjectLoader::LoadResult loadResult = BuildProjectLoader().load(m_projectFilePath, - buildGraph.data(), m_buildRoot, m_buildConfig, searchPaths); + evalContext.data(), m_buildRoot, m_buildConfig, searchPaths); ResolvedProjectPtr rProject; if (!loadResult.discardLoadedProject) m_buildProject = loadResult.loadedProject; if (m_buildProject) { - buildGraph.take(); + evalContext.take(); rProject = m_buildProject->resolvedProject(); } else { if (loadResult.changedResolvedProject) { rProject = loadResult.changedResolvedProject; } else { - Loader loader(&scriptEngine); + Loader loader(evalContext->engine()); loader.setSearchPaths(searchPaths); loader.setProgressObserver(observer()); rProject = loader.loadProject(m_projectFilePath, m_buildRoot, m_buildConfig); @@ -188,10 +186,10 @@ void InternalSetupProjectJob::execute() return; TimedActivityLogger resolveLogger(QLatin1String("Resolving build project")); - m_buildProject = BuildProjectResolver().resolveProject(rProject, buildGraph.data(), observer()); + m_buildProject = BuildProjectResolver().resolveProject(rProject, evalContext.data()); if (loadResult.loadedProject) m_buildProject->rescueDependencies(loadResult.loadedProject); - buildGraph.take(); + evalContext.take(); } @@ -237,7 +235,6 @@ void InternalBuildJob::start() { m_executor = new Executor(this); connect(m_executor, SIGNAL(finished()), SLOT(handleFinished())); - m_executor->setEngine(new ScriptEngine(this)); m_executor->setBuildOptions(buildOptions()); m_executor->setProgressObserver(observer()); m_executor->build(products()); diff --git a/src/lib/buildgraph/automoc.cpp b/src/lib/buildgraph/automoc.cpp index f6a9fffc8..070b75e17 100644 --- a/src/lib/buildgraph/automoc.cpp +++ b/src/lib/buildgraph/automoc.cpp @@ -51,8 +51,7 @@ void AutoMoc::setScanResultCache(ScanResultCache *scanResultCache) m_scanResultCache = scanResultCache; } -void AutoMoc::apply(const BuildProductPtr &product, ScriptEngine *engine, - ProgressObserver *observer) +void AutoMoc::apply(const BuildProductPtr &product) { if (scanners().isEmpty()) throw Error("C++ scanner cannot be loaded."); @@ -131,7 +130,7 @@ void AutoMoc::apply(const BuildProductPtr &product, ScriptEngine *engine, artifactsPerFileTag[QLatin1String("c++_pch")] += pchFile; if (!artifactsPerFileTag.isEmpty()) { qbsInfo() << DontPrintLogLevel << "Applying moc rules for '" << product->rProduct->name << "'."; - product->applyRules(artifactsPerFileTag, engine, observer); + product->applyRules(artifactsPerFileTag); } if (pluginHeaderFile && pluginMetaDataFile) { // Make every artifact that is dependent of the header file also @@ -140,7 +139,7 @@ void AutoMoc::apply(const BuildProductPtr &product, ScriptEngine *engine, BuildGraph::loggedConnect(outputOfHeader, pluginMetaDataFile); } - product->project->updateNodesThatMustGetNewTransformer(engine, observer); + product->project->updateNodesThatMustGetNewTransformer(); } QString AutoMoc::generateMocFileName(Artifact *artifact, FileType fileType) diff --git a/src/lib/buildgraph/automoc.h b/src/lib/buildgraph/automoc.h index 18c0089bc..89bcd7537 100644 --- a/src/lib/buildgraph/automoc.h +++ b/src/lib/buildgraph/automoc.h @@ -36,9 +36,7 @@ struct ScannerPlugin; namespace qbs { namespace Internal { -class ProgressObserver; class ScanResultCache; -class ScriptEngine; /** * Scans cpp and hpp files for the Q_OBJECT / Q_GADGET macro and @@ -54,7 +52,7 @@ public: AutoMoc(); void setScanResultCache(ScanResultCache *scanResultCache); - void apply(const BuildProductPtr &product, ScriptEngine *engine, ProgressObserver *observer); + void apply(const BuildProductPtr &product); private: enum FileType diff --git a/src/lib/buildgraph/buildgraph.cpp b/src/lib/buildgraph/buildgraph.cpp index 4f4db8498..4e79acd0f 100644 --- a/src/lib/buildgraph/buildgraph.cpp +++ b/src/lib/buildgraph/buildgraph.cpp @@ -33,6 +33,7 @@ #include "cycledetector.h" #include "command.h" #include "rulegraph.h" +#include "rulesevaluationcontext.h" #include "transformer.h" #include <language/language.h> @@ -173,37 +174,17 @@ void BuildProduct::insertArtifact(Artifact *artifact) qbsTrace("[BG] insert artifact '%s'", qPrintable(artifact->filePath())); } -void BuildProduct::applyRules(ArtifactsPerFileTagMap &artifactsPerFileTag, ScriptEngine *engine, - ProgressObserver *observer) +void BuildProduct::applyRules(ArtifactsPerFileTagMap &artifactsPerFileTag) { - BuildGraph::EngineInitializer engineInitializer(project->buildGraph()); - RulesApplicator rulesApplier(this, artifactsPerFileTag, engine, observer); + RulesEvaluationContext::Scope s(project->evaluationContext()); + RulesApplicator rulesApplier(this, artifactsPerFileTag); rulesApplier.applyAllRules(); } -BuildGraph::BuildGraph() - : m_progressObserver(0) - , m_engine(0) - , m_initEngineCalls(0) -{ -} - -BuildGraph::~BuildGraph() -{ -} - -void BuildGraph::setEngine(ScriptEngine *engine) -{ - m_engine = engine; - m_prepareScriptScope = m_engine->newObject(); - ProcessCommand::setupForJavaScript(m_prepareScriptScope); - JavaScriptCommand::setupForJavaScript(m_prepareScriptScope); -} - void BuildGraph::setupScriptEngineForProduct(ScriptEngine *engine, const ResolvedProductConstPtr &product, - RuleConstPtr rule, + const RuleConstPtr &rule, QScriptValue targetObject) { const ResolvedProject *lastSetupProject = reinterpret_cast<ResolvedProject *>(engine->property("lastSetupProject").toULongLong()); @@ -241,11 +222,6 @@ void BuildGraph::setupScriptEngineForProduct(ScriptEngine *engine, engine->import(rule->jsImports, targetObject, targetObject); } -void BuildGraph::setProgressObserver(ProgressObserver *observer) -{ - m_progressObserver = observer; -} - bool BuildGraph::findPath(Artifact *u, Artifact *v, QList<Artifact*> &path) { if (u == v) { @@ -329,32 +305,6 @@ void BuildGraph::disconnect(Artifact *u, Artifact *v) v->parents.remove(u); } -void BuildGraph::initEngine() -{ - if (m_initEngineCalls++ > 0) - return; - - m_engine->setProperty("lastSetupProject", QVariant()); - m_engine->setProperty("lastSetupProduct", QVariant()); - - m_engine->clearImportsCache(); - m_engine->pushContext(); - m_scope = m_engine->newObject(); - m_scope.setPrototype(m_prepareScriptScope); - m_engine->currentContext()->pushScope(m_scope); -} - -void BuildGraph::cleanupEngine() -{ - Q_ASSERT(m_initEngineCalls > 0); - if (--m_initEngineCalls > 0) - return; - - m_scope = QScriptValue(); - m_engine->currentContext()->popScope(); - m_engine->popContext(); -} - void BuildGraph::removeGeneratedArtifactFromDisk(Artifact *artifact) { if (artifact->artifactType != Artifact::Generated) @@ -473,15 +423,13 @@ void BuildProduct::store(PersistentPool &pool) const pool.storeContainer(dependencies); } -BuildProject::BuildProject(BuildGraph *bg) - : m_buildGraph(bg) - , m_dirty(false) +BuildProject::BuildProject() : m_evalContext(0), m_dirty(false) { } BuildProject::~BuildProject() { - delete m_buildGraph; + delete m_evalContext; qDeleteAll(m_dependencyArtifacts); } @@ -529,6 +477,12 @@ QString BuildProject::buildGraphFilePath() const return deriveBuildGraphFilePath(resolvedProject()->buildDirectory, resolvedProject()->id()); } +void BuildProject::setEvaluationContext(RulesEvaluationContext *evalContext) +{ + delete m_evalContext; + m_evalContext = evalContext; +} + void BuildProject::load(PersistentPool &pool) { TimedActivityLogger logger(QLatin1String("Loading project from disk.")); @@ -587,11 +541,6 @@ void freeCFileTags(char **cFileTags, int numFileTags) delete[] cFileTags; } -BuildGraph * BuildProject::buildGraph() const -{ - return m_buildGraph; -} - ResolvedProjectPtr BuildProject::resolvedProject() const { return m_resolvedProject; @@ -717,17 +666,15 @@ void BuildProject::removeArtifact(Artifact *artifact) markDirty(); } -void BuildProject::updateNodesThatMustGetNewTransformer(ScriptEngine *engine, - ProgressObserver *observer) +void BuildProject::updateNodesThatMustGetNewTransformer() { - BuildGraph::EngineInitializer engineInitializer(buildGraph()); + RulesEvaluationContext::Scope s(evaluationContext()); foreach (Artifact *artifact, m_artifactsThatMustGetNewTransformers) - updateNodeThatMustGetNewTransformer(artifact, engine, observer); + updateNodeThatMustGetNewTransformer(artifact); m_artifactsThatMustGetNewTransformers.clear(); } -void BuildProject::updateNodeThatMustGetNewTransformer(Artifact *artifact, ScriptEngine *engine, - ProgressObserver *observer) +void BuildProject::updateNodeThatMustGetNewTransformer(Artifact *artifact) { Q_ASSERT(artifact->transformer); @@ -745,7 +692,7 @@ void BuildProject::updateNodeThatMustGetNewTransformer(Artifact *artifact, Scrip foreach (const QString &fileTag, input->fileTags) artifactsPerFileTag[fileTag] += input; } - RulesApplicator rulesApplier(artifact->product, artifactsPerFileTag, engine, observer); + RulesApplicator rulesApplier(artifact->product, artifactsPerFileTag); rulesApplier.applyRule(rule); } @@ -761,23 +708,9 @@ QString fileName(Artifact *n) return str; } -BuildGraph::EngineInitializer::EngineInitializer(BuildGraph *bg) - : buildGraph(bg) -{ - buildGraph->initEngine(); -} - -BuildGraph::EngineInitializer::~EngineInitializer() -{ - buildGraph->cleanupEngine(); -} - -RulesApplicator::RulesApplicator(BuildProduct *product, ArtifactsPerFileTagMap &artifactsPerFileTag, - ScriptEngine *engine, ProgressObserver *observer) +RulesApplicator::RulesApplicator(BuildProduct *product, ArtifactsPerFileTagMap &artifactsPerFileTag) : m_buildProduct(product) , m_artifactsPerFileTag(artifactsPerFileTag) - , m_engine(engine) - , m_observer(observer) { } @@ -790,8 +723,8 @@ void RulesApplicator::applyAllRules() void RulesApplicator::applyRule(const RuleConstPtr &rule) { m_rule = rule; - BuildGraph::setupScriptEngineForProduct(m_engine, m_buildProduct->rProduct, m_rule, scope()); - Q_ASSERT_X(scope().property("product").strictlyEquals(m_engine->evaluate("product")), + BuildGraph::setupScriptEngineForProduct(engine(), m_buildProduct->rProduct, m_rule, scope()); + Q_ASSERT_X(scope().property("product").strictlyEquals(engine()->evaluate("product")), "BG", "Product object is not in current scope."); ArtifactList inputArtifacts; @@ -813,8 +746,7 @@ void RulesApplicator::applyRule(const RuleConstPtr &rule) void RulesApplicator::doApply(const ArtifactList &inputArtifacts) { - if (m_observer && m_observer->canceled()) - throw Error(Tr::tr("Build canceled.")); + evalContext()->checkForCancelation(); if (qbsLogLevel(LoggerDebug)) qbsDebug() << "[BG] apply rule " << m_rule->toString() << " " @@ -870,7 +802,7 @@ void RulesApplicator::doApply(const ArtifactList &inputArtifacts) m_buildProduct->project->removeFromArtifactsThatMustGetNewTransformers(outputArtifact); } - m_transformer->setupInputs(m_engine, scope()); + m_transformer->setupInputs(engine(), scope()); // change the transformer outputs according to the bindings in Artifact QScriptValue scriptValue; @@ -883,13 +815,13 @@ void RulesApplicator::doApply(const ArtifactList &inputArtifacts) Artifact *outputArtifact = ruleArtifactArtifactMap.at(i).second; outputArtifact->properties = outputArtifact->properties->clone(); - scope().setProperty("fileName", m_engine->toScriptValue(outputArtifact->filePath())); - scope().setProperty("fileTags", toScriptValue(m_engine, outputArtifact->fileTags)); + scope().setProperty("fileName", engine()->toScriptValue(outputArtifact->filePath())); + scope().setProperty("fileTags", toScriptValue(engine(), outputArtifact->fileTags)); QVariantMap artifactModulesCfg = outputArtifact->properties->value().value("modules").toMap(); for (int i=0; i < ra->bindings.count(); ++i) { const RuleArtifact::Binding &binding = ra->bindings.at(i); - scriptValue = m_engine->evaluate(binding.code); + scriptValue = engine()->evaluate(binding.code); if (scriptValue.isError()) { QString msg = QLatin1String("evaluating rule binding '%1': %2"); throw Error(msg.arg(binding.name.join(QLatin1String(".")), scriptValue.toString()), binding.location); @@ -901,8 +833,8 @@ void RulesApplicator::doApply(const ArtifactList &inputArtifacts) outputArtifact->properties->setValue(outputArtifactConfig); } - m_transformer->setupOutputs(m_engine, scope()); - m_transformer->createCommands(m_rule->script, m_engine); + m_transformer->setupOutputs(engine(), scope()); + m_transformer->createCommands(m_rule->script, engine()); if (m_transformer->commands.isEmpty()) throw Error(QString("There's a rule without commands: %1.").arg(m_rule->toString()), m_rule->script->location); } @@ -922,11 +854,11 @@ void RulesApplicator::setupScriptEngineForArtifact(Artifact *artifact) basedir = FileInfo::path(buildDir.relativeFilePath(artifact->filePath())); } - QScriptValue modulesScriptValue = artifact->properties->toScriptValue(m_engine); + QScriptValue modulesScriptValue = artifact->properties->toScriptValue(engine()); modulesScriptValue = modulesScriptValue.property("modules"); // expose per file properties we want to use in an Artifact within a Rule - QScriptValue scriptValue = m_engine->newObject(); + QScriptValue scriptValue = engine()->newObject(); scriptValue.setProperty("fileName", inFileName); scriptValue.setProperty("baseName", inBaseName); scriptValue.setProperty("completeBaseName", inCompleteBaseName); @@ -934,15 +866,15 @@ void RulesApplicator::setupScriptEngineForArtifact(Artifact *artifact) scriptValue.setProperty("modules", modulesScriptValue); scope().setProperty("input", scriptValue); - Q_ASSERT_X(scriptValue.strictlyEquals(m_engine->evaluate("input")), + Q_ASSERT_X(scriptValue.strictlyEquals(engine()->evaluate("input")), "BG", "The input object is not in current scope."); } Artifact *RulesApplicator::createOutputArtifact(const RuleArtifactConstPtr &ruleArtifact, const ArtifactList &inputArtifacts) { - QScriptValue scriptValue = m_engine->evaluate(ruleArtifact->fileName); - if (scriptValue.isError() || m_engine->hasUncaughtException()) + QScriptValue scriptValue = engine()->evaluate(ruleArtifact->fileName); + if (scriptValue.isError() || engine()->hasUncaughtException()) throw Error("Error in Rule.Artifact fileName: " + scriptValue.toString()); QString outputPath = scriptValue.toString(); outputPath.replace("..", "dotdot"); // don't let the output artifact "escape" its build dir @@ -1020,25 +952,33 @@ QString RulesApplicator::resolveOutPath(const QString &path) const return result; } +RulesEvaluationContext *RulesApplicator::evalContext() const +{ + return m_buildProduct->project->evaluationContext(); +} + +ScriptEngine *RulesApplicator::engine() const +{ + return evalContext()->engine(); +} + QScriptValue RulesApplicator::scope() const { - return m_engine->currentContext()->scopeChain().first(); + return evalContext()->scope(); } BuildProjectPtr BuildProjectResolver::resolveProject(const ResolvedProjectPtr &resolvedProject, - BuildGraph *buildgraph, ProgressObserver *observer) + RulesEvaluationContext *evalContext) { m_productCache.clear(); - m_observer = observer; - m_project = BuildProjectPtr(new BuildProject(buildgraph)); + m_project = BuildProjectPtr(new BuildProject); + m_project->setEvaluationContext(evalContext); m_project->setResolvedProject(resolvedProject); - if (m_observer) - m_observer->initialize(Tr::tr("Resolving project"), resolvedProject->products.count()); + evalContext->initializeObserver(Tr::tr("Resolving project"), resolvedProject->products.count()); foreach (ResolvedProductPtr rProduct, resolvedProject->products) { resolveProduct(rProduct); - if (m_observer) - m_observer->incrementProgressValue(); + evalContext->incrementProgressValue(); } CycleDetector().visitProject(m_project); return m_project; @@ -1050,8 +990,7 @@ BuildProductPtr BuildProjectResolver::resolveProduct(const ResolvedProductPtr &r if (product) return product; - if (m_observer && m_observer->canceled()) - throw Error(Tr::tr("Build canceled.")); + evalContext()->checkForCancelation(); product = BuildProduct::create(); m_productCache.insert(rProduct, product); @@ -1114,7 +1053,7 @@ BuildProductPtr BuildProjectResolver::resolveProduct(const ResolvedProductPtr &r transformer->outputs += outputArtifact; product->targetArtifacts += outputArtifact; foreach (Artifact *inputArtifact, inputArtifacts) - buildGraph()->safeConnect(outputArtifact, inputArtifact); + BuildGraph::safeConnect(outputArtifact, inputArtifact); foreach (const QString &fileTag, outputArtifact->fileTags) artifactsPerFileTag[fileTag].insert(outputArtifact); @@ -1125,16 +1064,16 @@ BuildProductPtr BuildProjectResolver::resolveProduct(const ResolvedProductPtr &r } transformer->rule = rule; - BuildGraph::EngineInitializer initializer(buildGraph()); - buildGraph()->setupScriptEngineForProduct(engine(), rProduct, transformer->rule, scope()); + RulesEvaluationContext::Scope s(evalContext()); + BuildGraph::setupScriptEngineForProduct(engine(), rProduct, transformer->rule, scope()); transformer->setupInputs(engine(), scope()); transformer->setupOutputs(engine(), scope()); - transformer->createCommands(rtrafo->transform, buildGraph()->engine()); + transformer->createCommands(rtrafo->transform, engine()); if (transformer->commands.isEmpty()) throw Error(QString("There's a transformer without commands."), rtrafo->transform->location); } - product->applyRules(artifactsPerFileTag, buildGraph()->engine(), m_observer); + product->applyRules(artifactsPerFileTag); QSet<Artifact *> productArtifactCandidates; for (int i = 0; i < product->rProduct->fileTags.count(); ++i) @@ -1152,18 +1091,27 @@ BuildProductPtr BuildProjectResolver::resolveProduct(const ResolvedProductPtr &r return product; } +RulesEvaluationContext *BuildProjectResolver::evalContext() const +{ + return m_project->evaluationContext(); +} + +ScriptEngine *BuildProjectResolver::engine() const +{ + return evalContext()->engine(); +} + QScriptValue BuildProjectResolver::scope() const { - return engine()->currentContext()->scopeChain().first(); + return evalContext()->scope(); } BuildProjectLoader::LoadResult BuildProjectLoader::load(const QString &projectFilePath, - BuildGraph *bg, const QString &buildRoot, const QVariantMap &cfg, + RulesEvaluationContext *evalContext, const QString &buildRoot, const QVariantMap &cfg, const QStringList &loaderSearchPaths) { m_result = LoadResult(); - m_engine = bg->engine(); - m_observer = bg->observer(); + m_evalContext = evalContext; const QString projectId = ResolvedProject::deriveId(cfg); const QString buildDir = ResolvedProject::deriveBuildDirectory(buildRoot, projectId); @@ -1178,7 +1126,8 @@ BuildProjectLoader::LoadResult BuildProjectLoader::load(const QString &projectFi return m_result; } - const BuildProjectPtr project = BuildProjectPtr(new BuildProject(bg)); + const BuildProjectPtr project = BuildProjectPtr(new BuildProject); + project->setEvaluationContext(evalContext); TimedActivityLogger loadLogger(QLatin1String("Loading build graph"), QLatin1String("[BG] ")); project->load(pool); foreach (const BuildProductPtr &bp, project->buildProducts()) @@ -1219,7 +1168,7 @@ BuildProjectLoader::LoadResult BuildProjectLoader::load(const QString &projectFi } if (projectFileChanged || referencedProductRemoved || !changedProducts.isEmpty()) { - Loader ldr(bg->engine()); + Loader ldr(evalContext->engine()); ldr.setSearchPaths(loaderSearchPaths); const ResolvedProjectPtr changedProject = ldr.loadProject(project->resolvedProject()->location.fileName, buildRoot, cfg); @@ -1349,13 +1298,13 @@ void BuildProjectLoader::onProductChanged(const BuildProductPtr &product, foreach (Artifact *artifact, addedArtifacts) foreach (const QString &ft, artifact->fileTags) artifactsPerFileTag[ft] += artifact; - product->applyRules(artifactsPerFileTag, m_engine, m_observer); + product->applyRules(artifactsPerFileTag); // parents of removed artifacts must update their transformers foreach (Artifact *removedArtifact, artifactsToRemove) foreach (Artifact *parent, removedArtifact->parents) product->project->addToArtifactsThatMustGetNewTransformers(parent); - product->project->updateNodesThatMustGetNewTransformer(m_engine, m_observer); + product->project->updateNodesThatMustGetNewTransformer(); // delete all removed artifacts physically from the disk foreach (Artifact *artifact, artifactsToRemove) { diff --git a/src/lib/buildgraph/buildgraph.h b/src/lib/buildgraph/buildgraph.h index 7547a095a..25dd664d5 100644 --- a/src/lib/buildgraph/buildgraph.h +++ b/src/lib/buildgraph/buildgraph.h @@ -47,9 +47,9 @@ #include <QVector> namespace qbs { - namespace Internal { class ProgressObserver; +class RulesEvaluationContext; class ScriptEngine; class Transformer; @@ -68,8 +68,7 @@ public: Artifact *lookupArtifact(const QString &filePath) const; Artifact *createArtifact(const SourceArtifactConstPtr &sourceArtifact); void insertArtifact(Artifact *n); - void applyRules(ArtifactsPerFileTagMap &artifactsPerFileTag, ScriptEngine *engine, - ProgressObserver *observer); + void applyRules(ArtifactsPerFileTagMap &artifactsPerFileTag); WeakPointer<BuildProject> project; ResolvedProductPtr rProduct; @@ -96,14 +95,16 @@ class BuildProject : public PersistentObject friend class BuildProjectLoader; friend class BuildProjectResolver; public: - BuildProject(BuildGraph *bg); + BuildProject(); ~BuildProject(); void store() const; static QString deriveBuildGraphFilePath(const QString &buildDir, const QString projectId); QString buildGraphFilePath() const; - BuildGraph *buildGraph() const; + void setEvaluationContext(RulesEvaluationContext *evalContext); + RulesEvaluationContext *evaluationContext() const { return m_evalContext; } + ResolvedProjectPtr resolvedProject() const; QSet<BuildProductPtr> buildProducts() const; bool dirty() const; @@ -115,7 +116,7 @@ public: void insertFileDependency(Artifact *artifact); void rescueDependencies(const BuildProjectPtr &other); void removeArtifact(Artifact *artifact); - void updateNodesThatMustGetNewTransformer(ScriptEngine *engine, ProgressObserver *observer); + void updateNodesThatMustGetNewTransformer(); void removeFromArtifactsThatMustGetNewTransformers(Artifact *a) { m_artifactsThatMustGetNewTransformers -= a; } @@ -128,11 +129,10 @@ private: void store(PersistentPool &pool) const; void addBuildProduct(const BuildProductPtr &product); void setResolvedProject(const ResolvedProjectPtr &resolvedProject); - void updateNodeThatMustGetNewTransformer(Artifact *artifact, ScriptEngine *engine, - ProgressObserver *observer); + void updateNodeThatMustGetNewTransformer(Artifact *artifact); private: - BuildGraph *m_buildGraph; + RulesEvaluationContext *m_evalContext; ResolvedProjectPtr m_resolvedProject; QSet<BuildProductPtr> m_buildProducts; ArtifactList m_dependencyArtifacts; @@ -154,54 +154,24 @@ private: class BuildGraph { public: - class EngineInitializer - { - public: - EngineInitializer(BuildGraph *bg); - ~EngineInitializer(); - - private: - BuildGraph *buildGraph; - }; - - BuildGraph(); - ~BuildGraph(); - - void setEngine(ScriptEngine *engine); - ScriptEngine *engine() { return m_engine; } - - void setProgressObserver(ProgressObserver *observer); - ProgressObserver *observer() const { return m_progressObserver; } - static bool findPath(Artifact *u, Artifact *v, QList<Artifact*> &path); static void connect(Artifact *p, Artifact *c); static void loggedConnect(Artifact *u, Artifact *v); static bool safeConnect(Artifact *u, Artifact *v); static void removeGeneratedArtifactFromDisk(Artifact *artifact); - - static void setupScriptEngineForProduct(ScriptEngine *scriptEngine, - const ResolvedProductConstPtr &product, - RuleConstPtr rule, QScriptValue targetObject); static void disconnect(Artifact *u, Artifact *v); + static void setupScriptEngineForProduct(ScriptEngine *engine, + const ResolvedProductConstPtr &product, const RuleConstPtr &rule, + QScriptValue targetObject); private: - void initEngine(); - void cleanupEngine(); - - ProgressObserver *m_progressObserver; - ScriptEngine *m_engine; - unsigned int m_initEngineCalls; - QScriptValue m_scope; - QScriptValue m_prepareScriptScope; - - friend class EngineInitializer; + BuildGraph(); }; class RulesApplicator { public: - RulesApplicator(BuildProduct *product, ArtifactsPerFileTagMap &artifactsPerFileTag, - ScriptEngine *engine, ProgressObserver *observer); + RulesApplicator(BuildProduct *product, ArtifactsPerFileTagMap &artifactsPerFileTag); void applyAllRules(); void applyRule(const RuleConstPtr &rule); @@ -211,13 +181,12 @@ private: Artifact *createOutputArtifact(const RuleArtifactConstPtr &ruleArtifact, const ArtifactList &inputArtifacts); QString resolveOutPath(const QString &path) const; - + RulesEvaluationContext *evalContext() const; + ScriptEngine *engine() const; QScriptValue scope() const; BuildProduct * const m_buildProduct; ArtifactsPerFileTagMap &m_artifactsPerFileTag; - ScriptEngine * const m_engine; - ProgressObserver * const m_observer; RuleConstPtr m_rule; TransformerPtr m_transformer; @@ -227,17 +196,16 @@ class BuildProjectResolver { public: BuildProjectPtr resolveProject(const ResolvedProjectPtr &resolvedProject, - BuildGraph *buildgraph, ProgressObserver *observer = 0); + RulesEvaluationContext *evalContext); private: BuildProductPtr resolveProduct(const ResolvedProductPtr &rProduct); - BuildGraph *buildGraph() const { return m_project->buildGraph(); } - ScriptEngine *engine() const { return buildGraph()->engine(); } + RulesEvaluationContext *evalContext() const; + ScriptEngine *engine() const; QScriptValue scope() const; BuildProjectPtr m_project; - ProgressObserver *m_observer; QHash<ResolvedProductPtr, BuildProductPtr> m_productCache; }; @@ -253,8 +221,9 @@ public: bool discardLoadedProject; }; - LoadResult load(const QString &projectFilePath, BuildGraph *bg, const QString &buildRoot, - const QVariantMap &cfg, const QStringList &loaderSearchPaths); + LoadResult load(const QString &projectFilePath, RulesEvaluationContext *evalContext, + const QString &buildRoot, const QVariantMap &cfg, + const QStringList &loaderSearchPaths); private: void onProductRemoved(const BuildProductPtr &product); @@ -263,8 +232,7 @@ private: void removeArtifactAndExclusiveDependents(Artifact *artifact, QList<Artifact*> *removedArtifacts = 0); - ScriptEngine *m_engine; - ProgressObserver *m_observer; + RulesEvaluationContext *m_evalContext; LoadResult m_result; }; diff --git a/src/lib/buildgraph/buildgraph.pri b/src/lib/buildgraph/buildgraph.pri index 2290df847..45d34ffec 100644 --- a/src/lib/buildgraph/buildgraph.pri +++ b/src/lib/buildgraph/buildgraph.pri @@ -15,7 +15,8 @@ SOURCES += \ $$PWD/inputartifactscanner.cpp \ $$PWD/artifactvisitor.cpp \ $$PWD/artifactcleaner.cpp \ - $$PWD/cycledetector.cpp + $$PWD/cycledetector.cpp \ + $$PWD/rulesevaluationcontext.cpp HEADERS += \ $$PWD/automoc.h\ @@ -35,4 +36,5 @@ HEADERS += \ $$PWD/artifactvisitor.h \ $$PWD/artifactcleaner.h \ $$PWD/cycledetector.h \ - $$PWD/forward_decls.h + $$PWD/forward_decls.h \ + $$PWD/rulesevaluationcontext.h diff --git a/src/lib/buildgraph/executor.cpp b/src/lib/buildgraph/executor.cpp index 9d055c85f..df63aa111 100644 --- a/src/lib/buildgraph/executor.cpp +++ b/src/lib/buildgraph/executor.cpp @@ -34,6 +34,7 @@ #include "cycledetector.h" #include "executorjob.h" #include "inputartifactscanner.h" +#include "rulesevaluationcontext.h" #include <buildgraph/transformer.h> #include <language/language.h> @@ -87,13 +88,15 @@ private: Executor::Executor(QObject *parent) : QObject(parent) - , m_engine(0) + , m_evalContext(new RulesEvaluationContext) , m_progressObserver(0) , m_state(ExecutorIdle) { m_inputArtifactScanContext = new InputArtifactScannerContext(&m_scanResultCache); m_autoMoc = new AutoMoc; m_autoMoc->setScanResultCache(&m_scanResultCache); + foreach (ExecutorJob *job, findChildren<ExecutorJob *>()) + job->setMainThreadScriptEngine(m_evalContext->engine()); } Executor::~Executor() @@ -133,7 +136,6 @@ void Executor::build(const QList<BuildProductPtr> &productsToBuild) void Executor::doBuild(const QList<BuildProductPtr> &productsToBuild) { Q_ASSERT(m_buildOptions.maxJobCount > 0); - Q_ASSERT(m_engine); Q_ASSERT(m_state == ExecutorIdle); m_leaves.clear(); m_productsToBuild = productsToBuild; @@ -143,10 +145,8 @@ void Executor::doBuild(const QList<BuildProductPtr> &productsToBuild) QSet<BuildProject *> projects; foreach (const BuildProductConstPtr &buildProduct, productsToBuild) projects << buildProduct->project; - foreach (BuildProject * const project, projects) { - project->buildGraph()->setEngine(m_engine); - project->buildGraph()->setProgressObserver(m_progressObserver); - } + foreach (BuildProject * const project, projects) + project->setEvaluationContext(m_evalContext); initializeArtifactsState(); setState(ExecutorRunning); @@ -170,7 +170,7 @@ void Executor::doBuild(const QList<BuildProductPtr> &productsToBuild) // prepare products const QProcessEnvironment systemEnvironment = QProcessEnvironment::systemEnvironment(); foreach (BuildProductPtr product, m_productsToBuild) - product->rProduct->setupBuildEnvironment(m_engine, systemEnvironment); + product->rProduct->setupBuildEnvironment(m_evalContext->engine(), systemEnvironment); // find the root nodes m_roots.clear(); @@ -196,16 +196,6 @@ void Executor::doBuild(const QList<BuildProductPtr> &productsToBuild) } } -void Executor::setEngine(ScriptEngine *engine) -{ - if (m_engine == engine) - return; - - m_engine = engine; - foreach (ExecutorJob *job, findChildren<ExecutorJob *>()) - job->setMainThreadScriptEngine(engine); -} - void Executor::setBuildOptions(const BuildOptions &buildOptions) { m_buildOptions = buildOptions; @@ -577,8 +567,7 @@ void Executor::addExecutorJobs(int jobNumber) { for (int i = 1; i <= jobNumber; i++) { ExecutorJob *job = new ExecutorJob(this); - if (m_engine) - job->setMainThreadScriptEngine(m_engine); + job->setMainThreadScriptEngine(m_evalContext->engine()); job->setObjectName(QString(QLatin1String("J%1")).arg(i)); m_availableJobs.append(job); connect(job, SIGNAL(error(QString)), this, SLOT(onProcessError(QString))); @@ -606,7 +595,7 @@ void Executor::runAutoMoc() foreach (const ResolvedModuleConstPtr &m, product->rProduct->modules) { if (m->name == "qt/core") { autoMocApplied = true; - m_autoMoc->apply(product, m_engine, m_progressObserver); + m_autoMoc->apply(product); break; } } diff --git a/src/lib/buildgraph/executor.h b/src/lib/buildgraph/executor.h index 918045308..7ddb66b9e 100644 --- a/src/lib/buildgraph/executor.h +++ b/src/lib/buildgraph/executor.h @@ -46,8 +46,8 @@ class AutoMoc; class ExecutorJob; class InputArtifactScannerContext; class ProgressObserver; +class RulesEvaluationContext; class ScanResultCache; -class ScriptEngine; class Executor : public QObject { @@ -58,7 +58,6 @@ public: void build(const QList<BuildProductPtr> &productsToBuild); - void setEngine(ScriptEngine *engine); void setBuildOptions(const BuildOptions &buildOptions); void setProgressObserver(ProgressObserver *observer) { m_progressObserver = observer; } @@ -96,7 +95,7 @@ private: void cancelJobs(); void setupProgressObserver(bool mocWillRun); - ScriptEngine *m_engine; + RulesEvaluationContext *m_evalContext; BuildOptions m_buildOptions; ProgressObserver *m_progressObserver; QList<ExecutorJob*> m_availableJobs; diff --git a/src/lib/buildgraph/rulesevaluationcontext.cpp b/src/lib/buildgraph/rulesevaluationcontext.cpp new file mode 100644 index 000000000..9c5db3643 --- /dev/null +++ b/src/lib/buildgraph/rulesevaluationcontext.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ +#include "rulesevaluationcontext.h" + +#include "artifact.h" +#include "buildgraph.h" +#include "command.h" +#include "transformer.h" +#include <language/language.h> +#include <language/scriptengine.h> +#include <logging/translator.h> +#include <tools/error.h> +#include <tools/fileinfo.h> +#include <tools/progressobserver.h> + +#include <QVariant> + +namespace qbs { +namespace Internal { + +RulesEvaluationContext::RulesEvaluationContext() + : m_engine(new ScriptEngine), m_observer(0), m_initScopeCalls(0) +{ + m_prepareScriptScope = m_engine->newObject(); + ProcessCommand::setupForJavaScript(m_prepareScriptScope); + JavaScriptCommand::setupForJavaScript(m_prepareScriptScope); +} + +RulesEvaluationContext::~RulesEvaluationContext() +{ + delete m_engine; +} + +void RulesEvaluationContext::initializeObserver(const QString &description, int maximumProgress) +{ + if (m_observer) + m_observer->initialize(description, maximumProgress); +} + +void RulesEvaluationContext::incrementProgressValue() +{ + if (m_observer) + m_observer->incrementProgressValue(); +} + +void RulesEvaluationContext::checkForCancelation() +{ + if (m_observer && m_observer->canceled()) + throw Error(Tr::tr("Build canceled.")); +} + +void RulesEvaluationContext::initScope() +{ + if (m_initScopeCalls++ > 0) + return; + + m_engine->setProperty("lastSetupProject", QVariant()); + m_engine->setProperty("lastSetupProduct", QVariant()); + + m_engine->clearImportsCache(); + m_engine->pushContext(); + m_scope = m_engine->newObject(); + m_scope.setPrototype(m_prepareScriptScope); + m_engine->currentContext()->pushScope(m_scope); +} + +void RulesEvaluationContext::cleanupScope() +{ + Q_ASSERT(m_initScopeCalls > 0); + if (--m_initScopeCalls > 0) + return; + + m_scope = QScriptValue(); + m_engine->currentContext()->popScope(); + m_engine->popContext(); +} + +RulesEvaluationContext::Scope::Scope(RulesEvaluationContext *evalContext) + : m_evalContext(evalContext) +{ + evalContext->initScope(); +} + +RulesEvaluationContext::Scope::~Scope() +{ + m_evalContext->cleanupScope(); +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/buildgraph/rulesevaluationcontext.h b/src/lib/buildgraph/rulesevaluationcontext.h new file mode 100644 index 000000000..2395cc34f --- /dev/null +++ b/src/lib/buildgraph/rulesevaluationcontext.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ +#ifndef QBS_RULESEVALUATIONCONTEXT_H +#define QBS_RULESEVALUATIONCONTEXT_H + +#include <language/forward_decls.h> + +#include <QScriptValue> + +namespace qbs { +namespace Internal { +class ProgressObserver; +class ScriptEngine; + +class RulesEvaluationContext +{ +public: + RulesEvaluationContext(); + ~RulesEvaluationContext(); + + class Scope + { + public: + Scope(RulesEvaluationContext *evalContext); + ~Scope(); + + private: + RulesEvaluationContext * const m_evalContext; + }; + + ScriptEngine *engine() const { return m_engine; } + QScriptValue scope() const { return m_scope; } + + void setObserver(ProgressObserver *observer) { m_observer = observer; } + void initializeObserver(const QString &description, int maximumProgress); + void incrementProgressValue(); + void checkForCancelation(); + +private: + friend class Scope; + + void initScope(); + void cleanupScope(); + + ScriptEngine * const m_engine; + ProgressObserver *m_observer; + unsigned int m_initScopeCalls; + QScriptValue m_scope; + QScriptValue m_prepareScriptScope; +}; + +} // namespace Internal +} // namespace qbs + +#endif // QBS_RULESEVALUATIONCONTEXT_H |