diff options
author | Maxim Zaitsev <maxim.m.zaitsev@gmail.com> | 2014-03-04 02:46:31 +0400 |
---|---|---|
committer | Joerg Bornemann <joerg.bornemann@digia.com> | 2014-03-12 15:27:44 +0100 |
commit | 9c8997413fb7d744e1d1b62b5c926cb089eb0d52 (patch) | |
tree | 566370cd102144ed4cb3c0000cf2998cf3dd974c /src | |
parent | 91d4e47fc8eb506b3a906d75a838a28b2c3a38e4 (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')
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) { |