aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMaxim Zaitsev <maxim.m.zaitsev@gmail.com>2014-03-04 02:46:31 +0400
committerJoerg Bornemann <joerg.bornemann@digia.com>2014-03-12 15:27:44 +0100
commit9c8997413fb7d744e1d1b62b5c926cb089eb0d52 (patch)
tree566370cd102144ed4cb3c0000cf2998cf3dd974c /src
parent91d4e47fc8eb506b3a906d75a838a28b2c3a38e4 (diff)
Add new qml item Scanner
This item allows to write custom dependency scanners in modules. Change-Id: I6cb49969973ee29896d1909e7a16bf5da50f8aef Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/lib/corelib/api/project.cpp4
-rw-r--r--src/lib/corelib/buildgraph/buildgraph.cpp4
-rw-r--r--src/lib/corelib/buildgraph/buildgraph.h2
-rw-r--r--src/lib/corelib/buildgraph/buildgraph.pri2
-rw-r--r--src/lib/corelib/buildgraph/depscanner.cpp217
-rw-r--r--src/lib/corelib/buildgraph/depscanner.h99
-rw-r--r--src/lib/corelib/buildgraph/inputartifactscanner.cpp256
-rw-r--r--src/lib/corelib/buildgraph/inputartifactscanner.h37
-rw-r--r--src/lib/corelib/buildgraph/jscommandexecutor.cpp2
-rw-r--r--src/lib/corelib/buildgraph/projectbuilddata.cpp2
-rw-r--r--src/lib/corelib/buildgraph/qtmocscanner.cpp15
-rw-r--r--src/lib/corelib/buildgraph/rulesapplicator.cpp2
-rw-r--r--src/lib/corelib/buildgraph/scanresultcache.cpp19
-rw-r--r--src/lib/corelib/buildgraph/scanresultcache.h15
-rw-r--r--src/lib/corelib/corelib.qbs2
-rw-r--r--src/lib/corelib/language/builtindeclarations.cpp21
-rw-r--r--src/lib/corelib/language/builtindeclarations.h1
-rw-r--r--src/lib/corelib/language/forward_decls.h4
-rw-r--r--src/lib/corelib/language/language.cpp18
-rw-r--r--src/lib/corelib/language/language.h21
-rw-r--r--src/lib/corelib/language/projectresolver.cpp18
-rw-r--r--src/lib/corelib/language/projectresolver.h1
-rw-r--r--src/lib/corelib/tools/persistence.cpp2
23 files changed, 598 insertions, 166 deletions
diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp
index dd4d57a97..22f4f7b51 100644
--- a/src/lib/corelib/api/project.cpp
+++ b/src/lib/corelib/api/project.cpp
@@ -549,6 +549,10 @@ void ProjectPrivate::updateInternalCodeLocations(const ResolvedProjectPtr &proje
}
foreach (const ResolvedTransformerConstPtr &transformer, product->transformers)
updateLocationIfNecessary(transformer->transform->location, changeLocation, lineOffset);
+ foreach (const ResolvedScannerConstPtr &scanner, product->scanners) {
+ updateLocationIfNecessary(scanner->searchPathsScript->location, changeLocation, lineOffset);
+ updateLocationIfNecessary(scanner->scanScript->location, changeLocation, lineOffset);
+ }
foreach (const ResolvedModuleConstPtr &module, product->modules) {
updateLocationIfNecessary(module->setupBuildEnvironmentScript->location,
changeLocation, lineOffset);
diff --git a/src/lib/corelib/buildgraph/buildgraph.cpp b/src/lib/corelib/buildgraph/buildgraph.cpp
index c2be83f45..f7ccf3e7e 100644
--- a/src/lib/corelib/buildgraph/buildgraph.cpp
+++ b/src/lib/corelib/buildgraph/buildgraph.cpp
@@ -170,7 +170,7 @@ void setupScriptEngineForFile(ScriptEngine *engine, const ResolvedFileContextCon
}
void setupScriptEngineForProduct(ScriptEngine *engine, const ResolvedProductConstPtr &product,
- const RuleConstPtr &rule, QScriptValue targetObject,
+ const ResolvedModuleConstPtr &module, QScriptValue targetObject,
PrepareScriptObserver *observer)
{
ScriptEngine::ScriptValueCache * const cache = engine->scriptValueCache();
@@ -211,7 +211,7 @@ void setupScriptEngineForProduct(ScriptEngine *engine, const ResolvedProductCons
// If the Rule is in a Module, set up the 'moduleName' property
cache->productScriptValue.setProperty(QLatin1String("moduleName"),
- rule->module->name.isEmpty() ? QScriptValue() : rule->module->name);
+ module->name.isEmpty() ? QScriptValue() : module->name);
}
bool findPath(BuildGraphNode *u, BuildGraphNode *v, QList<BuildGraphNode *> &path)
diff --git a/src/lib/corelib/buildgraph/buildgraph.h b/src/lib/corelib/buildgraph/buildgraph.h
index d0da37fa7..7180913d4 100644
--- a/src/lib/corelib/buildgraph/buildgraph.h
+++ b/src/lib/corelib/buildgraph/buildgraph.h
@@ -72,7 +72,7 @@ void disconnect(BuildGraphNode *u, BuildGraphNode *v, const Logger &logger);
void setupScriptEngineForFile(ScriptEngine *engine, const ResolvedFileContextConstPtr &fileContext,
QScriptValue targetObject);
void setupScriptEngineForProduct(ScriptEngine *engine, const ResolvedProductConstPtr &product,
- const RuleConstPtr &rule, QScriptValue targetObject,
+ const ResolvedModuleConstPtr &module, QScriptValue targetObject,
PrepareScriptObserver *observer = 0);
QString relativeArtifactFileName(const Artifact *artifact); // Debugging helpers
diff --git a/src/lib/corelib/buildgraph/buildgraph.pri b/src/lib/corelib/buildgraph/buildgraph.pri
index 0674f2ca7..2192df23a 100644
--- a/src/lib/corelib/buildgraph/buildgraph.pri
+++ b/src/lib/corelib/buildgraph/buildgraph.pri
@@ -9,6 +9,7 @@ SOURCES += \
$$PWD/buildgraphnode.cpp \
$$PWD/command.cpp \
$$PWD/cycledetector.cpp \
+ $$PWD/depscanner.cpp \
$$PWD/executor.cpp \
$$PWD/executorjob.cpp \
$$PWD/filedependency.cpp \
@@ -41,6 +42,7 @@ HEADERS += \
$$PWD/buildgraphvisitor.h \
$$PWD/command.h \
$$PWD/cycledetector.h \
+ $$PWD/depscanner.h \
$$PWD/executor.h \
$$PWD/executorjob.h \
$$PWD/filedependency.h \
diff --git a/src/lib/corelib/buildgraph/depscanner.cpp b/src/lib/corelib/buildgraph/depscanner.cpp
new file mode 100644
index 000000000..e273e19d2
--- /dev/null
+++ b/src/lib/corelib/buildgraph/depscanner.cpp
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 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 "depscanner.h"
+#include "artifact.h"
+#include "projectbuilddata.h"
+#include "buildgraph.h"
+
+#include <tools/error.h>
+#include <logging/translator.h>
+#include <language/language.h>
+#include <language/scriptengine.h>
+#include <jsextensions/moduleproperties.h>
+#include <plugins/scanner/scanner.h>
+
+#include <QVariantMap>
+#include <QSet>
+#include <QScriptContext>
+
+namespace qbs {
+namespace Internal {
+
+static void collectCppIncludePaths(const QVariantMap &modules, QSet<QString> *collectedPaths)
+{
+ QMapIterator<QString, QVariant> iterator(modules);
+ while (iterator.hasNext()) {
+ iterator.next();
+ if (iterator.key() == QLatin1String("cpp")) {
+ QVariant includePathsVariant =
+ iterator.value().toMap().value(QLatin1String("includePaths"));
+ if (includePathsVariant.isValid())
+ collectedPaths->unite(QSet<QString>::fromList(includePathsVariant.toStringList()));
+ } else {
+ collectCppIncludePaths(iterator.value().toMap().value(QLatin1String("modules")).toMap(),
+ collectedPaths);
+ }
+ }
+}
+
+PluginDependencyScanner::PluginDependencyScanner(ScannerPlugin *plugin)
+ : m_plugin(plugin)
+{
+ m_fileTag += FileTag(plugin->fileTag);
+}
+
+QStringList PluginDependencyScanner::collectSearchPaths(Artifact *artifact)
+{
+ if (m_plugin->flags & ScannerUsesCppIncludePaths) {
+ QVariantMap modules = artifact->properties->value().value(QLatin1String("modules")).toMap();
+ QSet<QString> collectedPaths;
+ collectCppIncludePaths(modules, &collectedPaths);
+ return QStringList(collectedPaths.toList());
+ } else {
+ return QStringList();
+ }
+}
+
+QStringList PluginDependencyScanner::collectDependencies(Artifact *artifact)
+{
+ QSet<QString> result;
+ QString baseDirOfInFilePath = artifact->dirPath();
+ const QString &filepath = artifact->filePath();
+ void *scannerHandle = m_plugin->open(filepath.utf16(), ScanForDependenciesFlag);
+ if (!scannerHandle)
+ return QStringList();
+ forever {
+ int flags = 0;
+ int length = 0;
+ const char *szOutFilePath = m_plugin->next(scannerHandle, &length, &flags);
+ if (szOutFilePath == 0)
+ break;
+ QString outFilePath = QString::fromLocal8Bit(szOutFilePath, length);
+ if (outFilePath.isEmpty())
+ continue;
+ if (flags & SC_LOCAL_INCLUDE_FLAG) {
+ QString localFilePath = FileInfo::resolvePath(baseDirOfInFilePath, outFilePath);
+ if (FileInfo::exists(localFilePath))
+ outFilePath = localFilePath;
+ }
+ result += outFilePath;
+ }
+ m_plugin->close(scannerHandle);
+ return QStringList(result.toList());
+}
+
+const FileTags &PluginDependencyScanner::fileTags()
+{
+ return m_fileTag;
+}
+
+bool PluginDependencyScanner::recursive()
+{
+ return m_plugin->flags & ScannerRecursiveDependencies;
+}
+
+void *PluginDependencyScanner::key()
+{
+ return m_plugin;
+}
+
+UserDependencyScanner::UserDependencyScanner(const ResolvedScannerConstPtr &scanner,
+ const Logger &logger, ScriptEngine *engine)
+ : m_scanner(scanner),
+ m_logger(logger),
+ m_engine(engine),
+ m_observer(engine),
+ m_project(0),
+ m_product(0)
+{
+ m_global = engine->newObject();
+ setupScriptEngineForFile(m_engine, m_scanner->scanScript->fileContext, m_global);
+}
+
+QStringList UserDependencyScanner::collectSearchPaths(Artifact *artifact)
+{
+ return evaluate(artifact, m_scanner->searchPathsScript);
+}
+
+QStringList UserDependencyScanner::collectDependencies(Artifact *artifact)
+{
+ return evaluate(artifact, m_scanner->scanScript);
+}
+
+const FileTags &UserDependencyScanner::fileTags()
+{
+ return m_scanner->inputs;
+}
+
+bool UserDependencyScanner::recursive()
+{
+ return m_scanner->recursive;
+}
+
+void *UserDependencyScanner::key()
+{
+ return const_cast<ResolvedScanner*>(m_scanner.data());
+}
+
+QStringList UserDependencyScanner::evaluate(Artifact *artifact, const ScriptFunctionPtr &script)
+{
+ if ((artifact->product.data() != m_product) || (artifact->product->project.data() != m_project)) {
+ m_product = artifact->product.data();
+ m_project = artifact->product->project.data();
+ setupScriptEngineForProduct(m_engine, artifact->product,
+ m_scanner->module, m_global, &m_observer);
+ }
+
+ QScriptValue artifactConfig = m_engine->newObject();
+ ModuleProperties::init(artifactConfig, artifact);
+ artifactConfig.setProperty(QLatin1String("fileName"), artifact->filePath(), 0);
+ const QStringList fileTags = artifact->fileTags.toStringList();
+ artifactConfig.setProperty(QLatin1String("fileTags"), m_engine->toScriptValue(fileTags));
+ if (!m_scanner->module->name.isEmpty())
+ artifactConfig.setProperty(QLatin1String("moduleName"), m_scanner->module->name);
+ QScriptValueList args;
+ args.reserve(3);
+ args.append(m_global.property(QString::fromLatin1("project")));
+ args.append(m_global.property(QString::fromLatin1("product")));
+ args.append(artifactConfig);
+
+ QScriptContext *ctx = m_engine->currentContext();
+ ctx->pushScope(m_global);
+ QScriptValue &function = script->scriptFunction;
+ if (!function.isValid() || function.engine() != m_engine) {
+ function = m_engine->evaluate(script->sourceCode);
+ if (Q_UNLIKELY(!function.isFunction()))
+ throw ErrorInfo(Tr::tr("Invalid scan script."), script->location);
+ }
+ QScriptValue result = function.call(QScriptValue(), args);
+ ctx->popScope();
+ m_engine->clearRequestedProperties();
+ if (Q_UNLIKELY(m_engine->hasErrorOrException(result))) {
+ QString msg = Tr::tr("evaluating scan script: ") + m_engine->uncaughtException().toString();
+ m_engine->clearExceptions();
+ throw ErrorInfo(msg, script->location);
+ }
+ QStringList list;
+ if (result.isArray()) {
+ const int count = result.property(QLatin1String("length")).toInt32();
+ list.reserve(count);
+ for (qint32 i = 0; i < count; ++i) {
+ QScriptValue item = result.property(i);
+ if (item.isValid() && !item.isUndefined())
+ list.append(item.toString());
+ }
+ }
+ return list;
+}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/lib/corelib/buildgraph/depscanner.h b/src/lib/corelib/buildgraph/depscanner.h
new file mode 100644
index 000000000..9e05d96c0
--- /dev/null
+++ b/src/lib/corelib/buildgraph/depscanner.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 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_DEPENDENCY_SCANNER_H
+#define QBS_DEPENDENCY_SCANNER_H
+
+#include <language/forward_decls.h>
+#include <language/filetags.h>
+#include <language/preparescriptobserver.h>
+
+#include <QStringList>
+#include <QScriptValue>
+
+class ScannerPlugin;
+
+namespace qbs {
+namespace Internal {
+
+class Artifact;
+class Logger;
+class ScriptEngine;
+
+class DependencyScanner
+{
+public:
+ virtual ~DependencyScanner() {}
+ virtual QStringList collectSearchPaths(Artifact *artifact) = 0;
+ virtual QStringList collectDependencies(Artifact *artifact) = 0;
+ virtual const FileTags &fileTags() = 0;
+ virtual bool recursive() = 0;
+ virtual void *key() = 0;
+};
+
+class PluginDependencyScanner : public DependencyScanner
+{
+public:
+ PluginDependencyScanner(ScannerPlugin *plugin);
+ virtual QStringList collectSearchPaths(Artifact *artifact);
+ virtual QStringList collectDependencies(Artifact *artifact);
+ virtual const FileTags &fileTags();
+ virtual bool recursive();
+ virtual void *key();
+private:
+ ScannerPlugin* m_plugin;
+ FileTags m_fileTag;
+};
+
+class UserDependencyScanner : public DependencyScanner
+{
+public:
+ UserDependencyScanner(const ResolvedScannerConstPtr &scanner, const Logger &logger,
+ ScriptEngine *engine);
+ virtual QStringList collectSearchPaths(Artifact *artifact);
+ virtual QStringList collectDependencies(Artifact *artifact);
+ virtual const FileTags &fileTags();
+ virtual bool recursive();
+ virtual void *key();
+private:
+ QStringList evaluate(Artifact *artifact, const ScriptFunctionPtr &script);
+private:
+ ResolvedScannerConstPtr m_scanner;
+ Logger m_logger;
+ ScriptEngine *m_engine;
+ PrepareScriptObserver m_observer;
+ QScriptValue m_global;
+ void *m_project;
+ void *m_product;
+};
+
+} // namespace Internal
+} // namespace qbs
+
+#endif // QBS_DEPENDENCY_SCANNER_H
diff --git a/src/lib/corelib/buildgraph/inputartifactscanner.cpp b/src/lib/corelib/buildgraph/inputartifactscanner.cpp
index 36defdcb0..de2e518f6 100644
--- a/src/lib/corelib/buildgraph/inputartifactscanner.cpp
+++ b/src/lib/corelib/buildgraph/inputartifactscanner.cpp
@@ -34,11 +34,14 @@
#include "productbuilddata.h"
#include "projectbuilddata.h"
#include "transformer.h"
+#include "depscanner.h"
+#include "rulesevaluationcontext.h"
#include <language/language.h>
#include <tools/fileinfo.h>
#include <tools/scannerpluginmanager.h>
#include <tools/qbsassert.h>
+#include <tools/error.h>
#include <QDir>
#include <QSet>
@@ -57,31 +60,6 @@ InputArtifactScannerContext::~InputArtifactScannerContext()
{
}
-static void collectIncludePaths(const QVariantMap &modules, QSet<QString> *collectedPaths)
-{
- QMapIterator<QString, QVariant> iterator(modules);
- while (iterator.hasNext()) {
- iterator.next();
- if (iterator.key() == QLatin1String("cpp")) {
- QVariant includePathsVariant =
- iterator.value().toMap().value(QLatin1String("includePaths"));
- if (includePathsVariant.isValid())
- collectedPaths->unite(QSet<QString>::fromList(includePathsVariant.toStringList()));
- } else {
- collectIncludePaths(iterator.value().toMap().value(QLatin1String("modules")).toMap(),
- collectedPaths);
- }
- }
-}
-
-static QStringList collectIncludePaths(const QVariantMap &modules)
-{
- QSet<QString> collectedPaths;
-
- collectIncludePaths(modules, &collectedPaths);
- return QStringList(collectedPaths.toList());
-}
-
static void resolveWithIncludePath(const QString &includePath,
const ScanResultCache::Dependency &dependency, const ResolvedProduct *product,
ResolvedDependency *result)
@@ -119,30 +97,49 @@ static void resolveWithIncludePath(const QString &includePath,
result->filePath = absFilePath;
}
-static bool scanWithScannerPlugin(ScannerPlugin *scannerPlugin,
- const QString &filePathToBeScanned,
- ScanResultCache::Result *scanResult)
+static void resolveAbsolutePath(const ScanResultCache::Dependency &dependency,
+ const ResolvedProduct *product, ResolvedDependency *result)
{
- void *scannerHandle = scannerPlugin->open(filePathToBeScanned.utf16(), ScanForDependenciesFlag);
- if (!scannerHandle)
- return false;
- while (true) {
- int flags = 0;
- int length = 0;
- const char *szOutFilePath = scannerPlugin->next(scannerHandle, &length, &flags);
- if (szOutFilePath == 0)
- break;
- QString outFilePath = QString::fromLocal8Bit(szOutFilePath, length);
- if (outFilePath.isEmpty())
+ QString absDirPath = dependency.dirPath();
+ if (!dependency.isClean())
+ absDirPath = QDir::cleanPath(absDirPath);
+
+ ResolvedProject *project = product->project.data();
+ FileDependency *fileDependencyArtifact = 0;
+ Artifact *dependencyInProduct = 0;
+ Artifact *dependencyInOtherProduct = 0;
+ foreach (FileResourceBase *lookupResult, project->topLevelProject()
+ ->buildData->lookupFiles(absDirPath, dependency.fileName())) {
+ if ((fileDependencyArtifact = dynamic_cast<FileDependency *>(lookupResult)))
continue;
- bool isLocalInclude = (flags & SC_LOCAL_INCLUDE_FLAG);
- scanResult->deps += ScanResultCache::Dependency(outFilePath, isLocalInclude);
+ Artifact * const foundArtifact = dynamic_cast<Artifact *>(lookupResult);
+ if (foundArtifact->product == product)
+ dependencyInProduct = foundArtifact;
+ else
+ dependencyInOtherProduct = foundArtifact;
}
- scannerPlugin->close(scannerHandle);
- scanResult->valid = true;
- return true;
+
+ // prioritize found artifacts
+ if ((result->file = dependencyInProduct)
+ || (result->file = dependencyInOtherProduct)
+ || (result->file = fileDependencyArtifact)) {
+ result->filePath = result->file->filePath();
+ return;
+ }
+
+ if (FileInfo::exists(dependency.filePath()))
+ result->filePath = dependency.filePath();
}
+static void scanWithScannerPlugin(DependencyScanner *scanner,
+ Artifact *artifactToBeScanned,
+ ScanResultCache::Result *scanResult)
+{
+ QStringList dependencies = scanner->collectDependencies(artifactToBeScanned);
+ foreach (const QString &s, dependencies)
+ scanResult->deps += ScanResultCache::Dependency(s);
+ scanResult->valid = true;
+}
InputArtifactScanner::InputArtifactScanner(Artifact *artifact, InputArtifactScannerContext *ctx,
const Logger &logger)
@@ -168,121 +165,120 @@ void InputArtifactScanner::scan()
ArtifactSet::const_iterator it = m_artifact->transformer->inputs.begin();
for (; it != m_artifact->transformer->inputs.end(); ++it) {
Artifact *inputArtifact = *it;
- QStringList includePaths;
- bool mustCollectIncludePaths = false;
-
- QSet<ScannerPlugin *> scanners;
- foreach (const FileTag &fileTag, inputArtifact->fileTags) {
- foreach (ScannerPlugin *scanner, ScannerPluginManager::scannersForFileTag(fileTag)) {
- scanners += scanner;
- if (scanner->flags & ScannerUsesCppIncludePaths)
- mustCollectIncludePaths = true;
- }
- }
+ scanForFileDependencies(inputArtifact);
+ }
+}
+
+void InputArtifactScanner::scanForFileDependencies(Artifact *inputArtifact)
+{
+ InputArtifactScannerContext::CacheItem &cacheItem = m_context->cache[inputArtifact->properties];
+ QSet<QString> visitedFilePaths;
+ QList<Artifact*> artifactsToScan;
+ artifactsToScan.append(inputArtifact);
+ QSet<DependencyScanner*> scanners;
+ TopLevelProject *project = inputArtifact->product->topLevelProject();
+ ScriptEngine* engine = project->buildData->evaluationContext->engine();
+ while (!artifactsToScan.isEmpty()) {
+ Artifact* artifactToBeScanned = artifactsToScan.takeFirst();
+ const QString &filePathToBeScanned = artifactToBeScanned->filePath();
+ if (visitedFilePaths.contains(filePathToBeScanned))
+ continue;
+ visitedFilePaths.insert(filePathToBeScanned);
- InputArtifactScannerContext::CacheItem &cacheItem = m_context->cache[inputArtifact->properties];
- if (mustCollectIncludePaths) {
- const bool cacheHit = cacheItem.valid;
- if (cacheHit) {
- includePaths = cacheItem.includePaths;
- } else {
- includePaths = collectIncludePaths(inputArtifact->properties->value()
- .value(QLatin1String("modules")).toMap());
- cacheItem.includePaths = includePaths;
- cacheItem.valid = true;
+ scanners.clear();
+ ResolvedProduct* product = artifactToBeScanned->product.data();
+ QHash<FileTag, InputArtifactScannerContext::DependencyScannerCacheItem> &scannerCache = m_context->scannersCache[product];
+ foreach (const FileTag &fileTag, artifactToBeScanned->fileTags) {
+ InputArtifactScannerContext::DependencyScannerCacheItem &cache = scannerCache[fileTag];
+ if (!cache.valid) {
+ cache.valid = true;
+ foreach (ScannerPlugin *scanner, ScannerPluginManager::scannersForFileTag(fileTag)) {
+ PluginDependencyScanner *pluginScanner = new PluginDependencyScanner(scanner);
+ cache.scanners += DependencyScannerPtr(pluginScanner);
+ }
+ foreach (const ResolvedScannerConstPtr &scanner, product->scanners) {
+ if (scanner->inputs.contains(fileTag)) {
+ UserDependencyScanner *userScanner = new UserDependencyScanner(scanner, m_logger, engine);
+ cache.scanners += DependencyScannerPtr(userScanner);
+ break;
+ }
+ }
}
- if (m_logger.traceEnabled()) {
- m_logger.qbsTrace()
- << "[DEPSCAN] include paths (cache " << (cacheHit ? "hit)" : "miss)");
- foreach (const QString &s, includePaths)
- m_logger.qbsTrace() << " " << s;
+ foreach (const DependencyScannerPtr &scanner, cache.scanners) {
+ scanners += scanner.data();
}
}
-
- const QStringList emptyIncludePaths;
- foreach (ScannerPlugin *scanner, scanners) {
- scanForFileDependencies(scanner,
- (scanner->flags & ScannerUsesCppIncludePaths)
- ? includePaths : emptyIncludePaths,
- inputArtifact,
- cacheItem.resolvedDependenciesCache[scanner]);
+ foreach (DependencyScanner *scanner, scanners) {
+ scanForScannerFileDependencies(scanner, inputArtifact, artifactToBeScanned,
+ scanner->recursive() ? &artifactsToScan : 0, cacheItem[scanner->key()]);
}
}
}
-void InputArtifactScanner::scanForFileDependencies(ScannerPlugin *scannerPlugin,
- const QStringList &includePaths, Artifact *inputArtifact, InputArtifactScannerContext::ResolvedDependenciesCache &resolvedDependenciesCache)
+void InputArtifactScanner::scanForScannerFileDependencies(DependencyScanner *scanner,
+ Artifact *inputArtifact, Artifact* artifactToBeScanned, QList<Artifact *> *artifactsToScan,
+ InputArtifactScannerContext::ScannerResolvedDependenciesCache &cache)
{
+ const bool cacheHit = cache.valid;
+ if (!cacheHit) {
+ cache.valid = true;
+ cache.searchPaths = scanner->collectSearchPaths(inputArtifact);
+ }
+ if (m_logger.traceEnabled()) {
+ m_logger.qbsTrace()
+ << "[DEPSCAN] include paths (cache " << (cacheHit ? "hit)" : "miss)");
+ foreach (const QString &s, cache.searchPaths)
+ m_logger.qbsTrace() << " " << s;
+ }
+
if (m_logger.debugEnabled()) {
+ QString tags = scanner->fileTags().toStringList().join(QString::fromLocal8Bit(","));
m_logger.qbsDebug() << QString::fromLocal8Bit("scanning %1 [%2]\n from %3")
- .arg(inputArtifact->filePath()).arg(QLatin1String(scannerPlugin->fileTag))
+ .arg(inputArtifact->filePath()).arg(tags)
.arg(m_artifact->filePath());
}
-
- QSet<QString> visitedFilePaths;
- QStringList filePathsToScan;
- filePathsToScan.append(inputArtifact->filePath());
- QStringList * const filePathsToScanPtr =
- (scannerPlugin->flags & ScannerRecursiveDependencies) ? &filePathsToScan : 0;
-
- while (!filePathsToScan.isEmpty()) {
- const QString filePathToBeScanned = filePathsToScan.takeFirst();
- if (visitedFilePaths.contains(filePathToBeScanned))
- continue;
- visitedFilePaths.insert(filePathToBeScanned);
-
- ScanResultCache::Result scanResult = m_context->scanResultCache->value(filePathToBeScanned);
- if (!scanResult.valid) {
- bool successfulScan = scanWithScannerPlugin(scannerPlugin, filePathToBeScanned, &scanResult);
- if (!successfulScan)
- continue;
- m_context->scanResultCache->insert(filePathToBeScanned, scanResult);
+ const QString &filePathToBeScanned = artifactToBeScanned->filePath();
+ ScanResultCache::Result scanResult = m_context->scanResultCache->value(scanner->key(), filePathToBeScanned);
+ if (!scanResult.valid) {
+ try {
+ scanWithScannerPlugin(scanner, artifactToBeScanned, &scanResult);
+ } catch (const ErrorInfo &error) {
+ m_logger.printWarning(error);
+ return;
}
-
- resolveScanResultDependencies(includePaths, inputArtifact, scanResult, filePathToBeScanned,
- filePathsToScanPtr, resolvedDependenciesCache);
+ m_context->scanResultCache->insert(scanner->key(), filePathToBeScanned, scanResult);
}
+
+ resolveScanResultDependencies(inputArtifact, scanResult, artifactsToScan, cache);
}
-void InputArtifactScanner::resolveScanResultDependencies(const QStringList &includePaths,
- const Artifact *inputArtifact, const ScanResultCache::Result &scanResult,
- const QString &filePathToBeScanned, QStringList *filePathsToScan, InputArtifactScannerContext::ResolvedDependenciesCache &resolvedDependenciesCache)
+void InputArtifactScanner::resolveScanResultDependencies(const Artifact *inputArtifact,
+ const ScanResultCache::Result &scanResult, QList<Artifact*> *artifactsToScan,
+ InputArtifactScannerContext::ScannerResolvedDependenciesCache &cache)
{
- QString baseDirOfInFilePath;
foreach (const ScanResultCache::Dependency &dependency, scanResult.deps) {
const QString &dependencyFilePath = dependency.filePath();
ResolvedDependency pristineResolvedDependency;
ResolvedDependency *resolvedDependency = &pristineResolvedDependency;
InputArtifactScannerContext::ResolvedDependencyCacheItem *cachedResolvedDependencyItem = 0;
- if (FileInfo::isAbsolute(dependencyFilePath)) {
- resolvedDependency->filePath = dependencyFilePath;
- goto resolved;
- }
-
- if (dependency.isLocal()) {
- // try base directory of source file
- if (baseDirOfInFilePath.isNull())
- baseDirOfInFilePath = FileInfo::path(filePathToBeScanned);
- resolveWithIncludePath(baseDirOfInFilePath, dependency, inputArtifact->product.data(),
- resolvedDependency);
- if (resolvedDependency->isValid())
- goto resolved;
- }
-
- cachedResolvedDependencyItem = &resolvedDependenciesCache[dependency.fileName()][dependency.dirPath()];
+ cachedResolvedDependencyItem = &cache.resolvedDependenciesCache[dependency.dirPath()][dependency.fileName()];
resolvedDependency = &cachedResolvedDependencyItem->resolvedDependency;
if (cachedResolvedDependencyItem->valid) {
-// qDebug() << "RESCACHE HIT" << dependency.filePath();
if (resolvedDependency->filePath.isEmpty())
goto unresolved;
goto resolved;
}
-// qDebug() << "RESCACHE MISS";
cachedResolvedDependencyItem->valid = true;
+ if (FileInfo::isAbsolute(dependencyFilePath)) {
+ resolveAbsolutePath(dependency, inputArtifact->product.data(),
+ resolvedDependency);
+ goto resolved;
+ }
+
// try include paths
- foreach (const QString &includePath, includePaths) {
+ foreach (const QString &includePath, cache.searchPaths) {
resolveWithIncludePath(includePath, dependency, inputArtifact->product.data(),
resolvedDependency);
if (resolvedDependency->isValid())
@@ -291,7 +287,7 @@ void InputArtifactScanner::resolveScanResultDependencies(const QStringList &incl
unresolved:
if (m_logger.traceEnabled()) {
- m_logger.qbsTrace() << QString::fromLocal8Bit("[DEPSCAN] unresolved '%1'")
+ m_logger.qbsWarning() << QString::fromLocal8Bit("[DEPSCAN] unresolved '%1'")
.arg(dependencyFilePath);
}
continue;
@@ -299,10 +295,10 @@ unresolved:
resolved:
// Do not scan artifacts that are being built. Otherwise we might read an incomplete
// file or conflict with the writing process.
- if (filePathsToScan) {
+ if (artifactsToScan) {
Artifact *artifactDependency = dynamic_cast<Artifact *>(resolvedDependency->file);
- if (!artifactDependency || artifactDependency->buildState != BuildGraphNode::Building)
- filePathsToScan->append(resolvedDependency->filePath);
+ if (artifactDependency && artifactDependency->buildState != BuildGraphNode::Building)
+ artifactsToScan->append(artifactDependency);
}
handleDependency(*resolvedDependency);
}
diff --git a/src/lib/corelib/buildgraph/inputartifactscanner.h b/src/lib/corelib/buildgraph/inputartifactscanner.h
index 57a1be2b2..572b8b27b 100644
--- a/src/lib/corelib/buildgraph/inputartifactscanner.h
+++ b/src/lib/corelib/buildgraph/inputartifactscanner.h
@@ -46,6 +46,9 @@ class Artifact;
class FileResourceBase;
class PropertyMapInternal;
+class DependencyScanner;
+typedef QSharedPointer<DependencyScanner> DependencyScannerPtr;
+
class ResolvedDependency
{
public:
@@ -80,18 +83,31 @@ private:
typedef QHash<QString, QHash<QString, ResolvedDependencyCacheItem> > ResolvedDependenciesCache;
- struct CacheItem
+ struct ScannerResolvedDependenciesCache
+ {
+ ScannerResolvedDependenciesCache() :
+ valid(false)
+ {}
+
+ bool valid;
+ QStringList searchPaths;
+ ResolvedDependenciesCache resolvedDependenciesCache;
+ };
+
+ struct DependencyScannerCacheItem
{
- CacheItem()
+ DependencyScannerCacheItem()
: valid(false)
{}
bool valid;
- QStringList includePaths;
- QHash<ScannerPlugin *, ResolvedDependenciesCache> resolvedDependenciesCache;
+ QList<DependencyScannerPtr> scanners;
};
+ typedef QHash<void *, ScannerResolvedDependenciesCache> CacheItem;
+
QHash<PropertyMapConstPtr, CacheItem> cache;
+ QHash<ResolvedProduct*, QHash<FileTag, DependencyScannerCacheItem> > scannersCache;
friend class InputArtifactScanner;
};
@@ -105,11 +121,14 @@ public:
bool newDependencyAdded() const { return m_newDependencyAdded; }
private:
- void scanForFileDependencies(ScannerPlugin *scannerPlugin, const QStringList &includePaths,
- Artifact *inputArtifact, InputArtifactScannerContext::ResolvedDependenciesCache &cacheItem);
- void resolveScanResultDependencies(const QStringList &includePaths,
- const Artifact *inputArtifact, const ScanResultCache::Result &scanResult,
- const QString &filePathToBeScanned, QStringList *filePathsToScan, InputArtifactScannerContext::ResolvedDependenciesCache &cacheItem);
+ void scanForFileDependencies(Artifact *inputArtifact);
+ void scanForScannerFileDependencies(DependencyScanner *scanner,
+ Artifact *inputArtifact, Artifact* artifactToBeScanned,
+ QList<Artifact*> *artifactsToScan,
+ InputArtifactScannerContext::ScannerResolvedDependenciesCache &cache);
+ void resolveScanResultDependencies(const Artifact *inputArtifact,
+ const ScanResultCache::Result &scanResult, QList<Artifact*> *artifactsToScan,
+ InputArtifactScannerContext::ScannerResolvedDependenciesCache &cache);
void handleDependency(ResolvedDependency &dependency);
Artifact * const m_artifact;
diff --git a/src/lib/corelib/buildgraph/jscommandexecutor.cpp b/src/lib/corelib/buildgraph/jscommandexecutor.cpp
index d8d86ecbe..0b09a69ac 100644
--- a/src/lib/corelib/buildgraph/jscommandexecutor.cpp
+++ b/src/lib/corelib/buildgraph/jscommandexecutor.cpp
@@ -82,7 +82,7 @@ public slots:
QScriptValue scope = scriptEngine->newObject();
PrepareScriptObserver observer(scriptEngine);
setupScriptEngineForFile(scriptEngine, transformer->rule->prepareScript->fileContext, scope);
- setupScriptEngineForProduct(scriptEngine, transformer->product(), transformer->rule, scope,
+ setupScriptEngineForProduct(scriptEngine, transformer->product(), transformer->rule->module, scope,
&observer);
transformer->setupInputs(scope);
transformer->setupOutputs(scriptEngine, scope);
diff --git a/src/lib/corelib/buildgraph/projectbuilddata.cpp b/src/lib/corelib/buildgraph/projectbuilddata.cpp
index 0111100d1..b244e571e 100644
--- a/src/lib/corelib/buildgraph/projectbuilddata.cpp
+++ b/src/lib/corelib/buildgraph/projectbuilddata.cpp
@@ -503,7 +503,7 @@ void BuildDataResolver::resolveProductBuildData(const ResolvedProductPtr &produc
setupScriptEngineForFile(engine(), transformer->rule->prepareScript->fileContext, scope());
QScriptValue prepareScriptContext = engine()->newObject();
PrepareScriptObserver observer(engine());
- setupScriptEngineForProduct(engine(), product, transformer->rule, prepareScriptContext,
+ setupScriptEngineForProduct(engine(), product, transformer->rule->module, prepareScriptContext,
&observer);
transformer->setupInputs(prepareScriptContext);
transformer->setupOutputs(engine(), prepareScriptContext);
diff --git a/src/lib/corelib/buildgraph/qtmocscanner.cpp b/src/lib/corelib/buildgraph/qtmocscanner.cpp
index 995250441..bf8558c3b 100644
--- a/src/lib/corelib/buildgraph/qtmocscanner.cpp
+++ b/src/lib/corelib/buildgraph/qtmocscanner.cpp
@@ -68,10 +68,11 @@ QtMocScanner::~QtMocScanner()
static ScanResultCache::Result runScanner(ScannerPlugin *scanner, const Artifact *artifact,
ScanResultCache *scanResultCache)
{
- ScanResultCache::Result scanResult = scanResultCache->value(artifact->filePath());
+ const QString &filepath = artifact->filePath();
+ ScanResultCache::Result scanResult = scanResultCache->value(scanner, filepath);
if (!scanResult.valid) {
scanResult.valid = true;
- void *opaq = scanner->open(artifact->filePath().utf16(),
+ void *opaq = scanner->open(filepath.utf16(),
ScanForDependenciesFlag | ScanForFileTagsFlag);
if (!opaq || !scanner->additionalFileTags)
return scanResult;
@@ -83,6 +84,7 @@ static ScanResultCache::Result runScanner(ScannerPlugin *scanner, const Artifact
scanResult.additionalFileTags += szFileTagsFromScanner[i];
}
+ QString baseDirOfInFilePath = artifact->dirPath();
forever {
int flags = 0;
const char *szOutFilePath = scanner->next(opaq, &length, &flags);
@@ -92,11 +94,16 @@ static ScanResultCache::Result runScanner(ScannerPlugin *scanner, const Artifact
if (includedFilePath.isEmpty())
continue;
bool isLocalInclude = (flags & SC_LOCAL_INCLUDE_FLAG);
- scanResult.deps += ScanResultCache::Dependency(includedFilePath, isLocalInclude);
+ if (isLocalInclude) {
+ QString localFilePath = FileInfo::resolvePath(baseDirOfInFilePath, includedFilePath);
+ if (FileInfo::exists(localFilePath))
+ includedFilePath = localFilePath;
+ }
+ scanResult.deps += ScanResultCache::Dependency(includedFilePath);
}
scanner->close(opaq);
- scanResultCache->insert(artifact->filePath(), scanResult);
+ scanResultCache->insert(scanner, filepath, scanResult);
}
return scanResult;
}
diff --git a/src/lib/corelib/buildgraph/rulesapplicator.cpp b/src/lib/corelib/buildgraph/rulesapplicator.cpp
index 7e7ca1876..6c117a361 100644
--- a/src/lib/corelib/buildgraph/rulesapplicator.cpp
+++ b/src/lib/corelib/buildgraph/rulesapplicator.cpp
@@ -82,7 +82,7 @@ void RulesApplicator::applyRule(const RuleConstPtr &rule)
QScriptValue prepareScriptContext = engine()->newObject();
PrepareScriptObserver observer(engine());
setupScriptEngineForFile(engine(), m_rule->prepareScript->fileContext, scope());
- setupScriptEngineForProduct(engine(), m_product, m_rule, prepareScriptContext, &observer);
+ setupScriptEngineForProduct(engine(), m_product, m_rule->module, prepareScriptContext, &observer);
ArtifactSet inputArtifacts;
foreach (const FileTag &fileTag, m_rule->inputs)
diff --git a/src/lib/corelib/buildgraph/scanresultcache.cpp b/src/lib/corelib/buildgraph/scanresultcache.cpp
index 98cfb7fba..1d5b1d578 100644
--- a/src/lib/corelib/buildgraph/scanresultcache.cpp
+++ b/src/lib/corelib/buildgraph/scanresultcache.cpp
@@ -33,8 +33,7 @@
namespace qbs {
namespace Internal {
-ScanResultCache::Dependency::Dependency(const QString &filePath, bool isLocal)
- : m_isLocal(isLocal)
+ScanResultCache::Dependency::Dependency(const QString &filePath)
{
FileInfo::splitIntoDirectoryAndFileName(filePath, &m_dirPath, &m_fileName);
@@ -42,19 +41,23 @@ ScanResultCache::Dependency::Dependency(const QString &filePath, bool isLocal)
&& !m_dirPath.contains(QLatin1String("//"));
}
-ScanResultCache::Result ScanResultCache::value(const QString &fileName) const
+ScanResultCache::Result ScanResultCache::value(void *scanner, const QString &fileName) const
{
- return m_data.value(fileName);
+ return m_data[scanner][fileName];
}
-void ScanResultCache::insert(const QString &fileName, const ScanResultCache::Result &value)
+void ScanResultCache::insert(void *scanner, const QString &fileName, const ScanResultCache::Result &value)
{
- m_data.insert(fileName, value);
+ m_data[scanner].insert(fileName, value);
}
-void ScanResultCache::remove(const QString &filePath)
+void ScanResultCache::remove(const QString &fileName)
{
- m_data.remove(filePath);
+ ScanResultCacheData::iterator i = m_data.begin();
+ while (i != m_data.end()) {
+ i.value().remove(fileName);
+ ++i;
+ }
}
} // namespace Internal
diff --git a/src/lib/corelib/buildgraph/scanresultcache.h b/src/lib/corelib/buildgraph/scanresultcache.h
index 289aa31e6..81be35477 100644
--- a/src/lib/corelib/buildgraph/scanresultcache.h
+++ b/src/lib/corelib/buildgraph/scanresultcache.h
@@ -45,19 +45,17 @@ public:
class Dependency
{
public:
- Dependency() : m_isLocal(false), m_isClean(true) {}
- Dependency(const QString &filePath, bool m_isLocal);
+ Dependency() : m_isClean(true) {}
+ Dependency(const QString &filePath);
QString filePath() const { return m_dirPath.isEmpty() ? m_fileName : m_dirPath + QLatin1Char('/') + m_fileName; }
const QString &dirPath() const { return m_dirPath; }
const QString &fileName() const { return m_fileName; }
- bool isLocal() const { return m_isLocal; }
bool isClean() const { return m_isClean; }
private:
QString m_dirPath;
QString m_fileName;
- bool m_isLocal;
bool m_isClean;
};
@@ -73,12 +71,13 @@ public:
bool valid;
};
- Result value(const QString &fileName) const;
- void insert(const QString &fileName, const Result &value);
- void remove(const QString &filePath);
+ Result value(void* scanner, const QString &fileName) const;
+ void insert(void* scanner, const QString &fileName, const Result &value);
+ void remove(const QString &fileName);
private:
- QHash<QString, Result> m_data;
+ typedef QHash<void*, QHash<QString, Result> > ScanResultCacheData;
+ ScanResultCacheData m_data;
};
} // namespace qbs
diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs
index 74db39d5d..a7214f306 100644
--- a/src/lib/corelib/corelib.qbs
+++ b/src/lib/corelib/corelib.qbs
@@ -86,6 +86,8 @@ QbsLibrary {
"command.h",
"cycledetector.cpp",
"cycledetector.h",
+ "depscanner.cpp",
+ "depscanner.h",
"executor.cpp",
"executor.h",
"executorjob.cpp",
diff --git a/src/lib/corelib/language/builtindeclarations.cpp b/src/lib/corelib/language/builtindeclarations.cpp
index 85210a68c..187408add 100644
--- a/src/lib/corelib/language/builtindeclarations.cpp
+++ b/src/lib/corelib/language/builtindeclarations.cpp
@@ -52,6 +52,7 @@ BuiltinDeclarations::BuiltinDeclarations()
addRuleItem();
addSubprojectItem();
addTransformerItem();
+ addScannerItem();
}
QString BuiltinDeclarations::languageVersion() const
@@ -196,6 +197,7 @@ void BuiltinDeclarations::addModuleItem()
<< QLatin1String("Rule")
<< QLatin1String("PropertyOptions")
<< QLatin1String("Transformer")
+ << QLatin1String("Scanner")
<< QLatin1String("Module") // needed, because we're adding module instances internally
);
item << nameProperty();
@@ -350,5 +352,24 @@ void BuiltinDeclarations::addTransformerItem()
insert(item);
}
+void BuiltinDeclarations::addScannerItem()
+{
+ ItemDeclaration item(QLatin1String("Scanner"));
+ item << conditionProperty();
+ item << PropertyDeclaration(QLatin1String("inputs"), PropertyDeclaration::StringList);
+ PropertyDeclaration recursive(QLatin1String("recursive"), PropertyDeclaration::Boolean);
+ recursive.initialValueSource = QLatin1String("false");
+ item << recursive;
+ PropertyDeclaration searchPaths(QLatin1String("searchPaths"), PropertyDeclaration::Verbatim);
+ searchPaths.functionArgumentNames << QLatin1String("project")
+ << QLatin1String("product") << QLatin1String("input");
+ item << searchPaths;
+ PropertyDeclaration scan(QLatin1String("scan"), PropertyDeclaration::Verbatim);
+ scan.functionArgumentNames << QLatin1String("project")
+ << QLatin1String("product") << QLatin1String("input");
+ item << scan;
+ insert(item);
+}
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/builtindeclarations.h b/src/lib/corelib/language/builtindeclarations.h
index b41e4cf61..39de427fa 100644
--- a/src/lib/corelib/language/builtindeclarations.h
+++ b/src/lib/corelib/language/builtindeclarations.h
@@ -67,6 +67,7 @@ private:
void addRuleItem();
void addSubprojectItem();
void addTransformerItem();
+ void addScannerItem();
QString m_languageVersion;
QMap<QString, ItemDeclaration> m_builtins;
diff --git a/src/lib/corelib/language/forward_decls.h b/src/lib/corelib/language/forward_decls.h
index 0bbd33326..96012b883 100644
--- a/src/lib/corelib/language/forward_decls.h
+++ b/src/lib/corelib/language/forward_decls.h
@@ -90,6 +90,10 @@ class Rule;
typedef QSharedPointer<Rule> RulePtr;
typedef QSharedPointer<const Rule> RuleConstPtr;
+class ResolvedScanner;
+typedef QSharedPointer<ResolvedScanner> ResolvedScannerPtr;
+typedef QSharedPointer<const ResolvedScanner> ResolvedScannerConstPtr;
+
class SourceArtifact;
typedef QSharedPointer<SourceArtifact> SourceArtifactPtr;
typedef QSharedPointer<const SourceArtifact> SourceArtifactConstPtr;
diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp
index 148b17962..f501f7a59 100644
--- a/src/lib/corelib/language/language.cpp
+++ b/src/lib/corelib/language/language.cpp
@@ -461,6 +461,7 @@ void ResolvedProduct::load(PersistentPool &pool)
pool.loadContainerS(fileTaggers);
pool.loadContainerS(modules);
pool.loadContainerS(transformers);
+ pool.loadContainerS(scanners);
pool.loadContainerS(groups);
pool.loadContainerS(artifactProperties);
buildData.reset(pool.idLoad<ProductBuildData>());
@@ -484,6 +485,7 @@ void ResolvedProduct::store(PersistentPool &pool) const
pool.storeContainer(fileTaggers);
pool.storeContainer(modules);
pool.storeContainer(transformers);
+ pool.storeContainer(scanners);
pool.storeContainer(groups);
pool.storeContainer(artifactProperties);
pool.store(buildData.data());
@@ -1247,5 +1249,21 @@ bool artifactPropertyListsAreEqual(const QList<ArtifactPropertiesPtr> &l1,
return listsAreEqual(l1, l2);
}
+void ResolvedScanner::load(PersistentPool &pool)
+{
+ module = pool.idLoadS<ResolvedModule>();
+ pool.stream() >> inputs >> recursive;
+ searchPathsScript = pool.idLoadS<ScriptFunction>();
+ scanScript = pool.idLoadS<ScriptFunction>();
+}
+
+void ResolvedScanner::store(PersistentPool &pool) const
+{
+ pool.store(module);
+ pool.stream() << inputs << recursive;
+ pool.store(searchPathsScript);
+ pool.store(scanScript);
+}
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h
index 72e41548f..fd0ab1ff7 100644
--- a/src/lib/corelib/language/language.h
+++ b/src/lib/corelib/language/language.h
@@ -318,6 +318,26 @@ inline bool operator!=(const ResolvedTransformer &t1, const ResolvedTransformer
bool transformerListsAreEqual(const QList<ResolvedTransformerConstPtr> &l1,
const QList<ResolvedTransformerConstPtr> &l2);
+class ResolvedScanner : public PersistentObject
+{
+public:
+ static ResolvedScannerPtr create() { return ResolvedScannerPtr(new ResolvedScanner); }
+
+ ResolvedModuleConstPtr module;
+ FileTags inputs;
+ bool recursive;
+ ScriptFunctionPtr searchPathsScript;
+ ScriptFunctionPtr scanScript;
+
+private:
+ ResolvedScanner() :
+ recursive(false)
+ {}
+
+ void load(PersistentPool &pool);
+ void store(PersistentPool &pool) const;
+};
+
class TopLevelProject;
class ScriptEngine;
@@ -343,6 +363,7 @@ public:
QList<FileTaggerConstPtr> fileTaggers;
QList<ResolvedModuleConstPtr> modules;
QList<ResolvedTransformerConstPtr> transformers;
+ QList<ResolvedScannerConstPtr> scanners;
QList<GroupPtr> groups;
QList<ArtifactPropertiesPtr> artifactProperties;
QScopedPointer<ProductBuildData> buildData;
diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp
index 869b8c63e..081ccd55d 100644
--- a/src/lib/corelib/language/projectresolver.cpp
+++ b/src/lib/corelib/language/projectresolver.cpp
@@ -403,6 +403,7 @@ void ProjectResolver::resolveModule(const QStringList &moduleName, Item *item,
mapping["Rule"] = &ProjectResolver::resolveRule;
mapping["FileTagger"] = &ProjectResolver::resolveFileTagger;
mapping["Transformer"] = &ProjectResolver::resolveTransformer;
+ mapping["Scanner"] = &ProjectResolver::resolveScanner;
mapping["PropertyOptions"] = &ProjectResolver::ignoreItem;
mapping["Depends"] = &ProjectResolver::ignoreItem;
mapping["Probe"] = &ProjectResolver::ignoreItem;
@@ -768,6 +769,23 @@ void ProjectResolver::resolveTransformer(Item *item, ProjectContext *projectCont
m_productContext->product->transformers += rtrafo;
}
+void ProjectResolver::resolveScanner(Item *item, ProjectResolver::ProjectContext *projectContext)
+{
+ checkCancelation();
+ if (!m_evaluator->boolValue(item, QLatin1String("condition"))) {
+ m_logger.qbsTrace() << "[PR] scanner condition is false";
+ return;
+ }
+
+ ResolvedScannerPtr scanner = ResolvedScanner::create();
+ scanner->module = m_moduleContext ? m_moduleContext->module : projectContext->dummyModule;
+ scanner->inputs = m_evaluator->fileTagsValue(item, QLatin1String("inputs"));
+ scanner->recursive = m_evaluator->boolValue(item, QLatin1String("recursive"));
+ scanner->searchPathsScript = scriptFunctionValue(item, QLatin1String("searchPaths"));
+ scanner->scanScript = scriptFunctionValue(item, QLatin1String("scan"));
+ m_productContext->product->scanners += scanner;
+}
+
void ProjectResolver::resolveExport(Item *item, ProjectContext *projectContext)
{
Q_UNUSED(projectContext);
diff --git a/src/lib/corelib/language/projectresolver.h b/src/lib/corelib/language/projectresolver.h
index 3c6621d18..636fd7299 100644
--- a/src/lib/corelib/language/projectresolver.h
+++ b/src/lib/corelib/language/projectresolver.h
@@ -105,6 +105,7 @@ private:
StringListSet *seenBindings);
void resolveFileTagger(Item *item, ProjectContext *projectContext);
void resolveTransformer(Item *item, ProjectContext *projectContext);
+ void resolveScanner(Item *item, ProjectContext *projectContext);
void resolveExport(Item *item, ProjectContext *projectContext);
void resolveProductDependencies(ProjectContext *projectContext);
void postProcess(const ResolvedProductPtr &product, ProjectContext *projectContext) const;
diff --git a/src/lib/corelib/tools/persistence.cpp b/src/lib/corelib/tools/persistence.cpp
index bea21b4e9..489ba5008 100644
--- a/src/lib/corelib/tools/persistence.cpp
+++ b/src/lib/corelib/tools/persistence.cpp
@@ -40,7 +40,7 @@
namespace qbs {
namespace Internal {
-static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-66";
+static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-67";
PersistentPool::PersistentPool(const Logger &logger) : m_logger(logger)
{