aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app/qbs/commandlinefrontend.cpp1
-rw-r--r--src/app/qbs/parser/commandlineoption.cpp11
-rw-r--r--src/app/qbs/parser/commandlineoption.h9
-rw-r--r--src/app/qbs/parser/commandlineoptionpool.cpp9
-rw-r--r--src/app/qbs/parser/commandlineoptionpool.h1
-rw-r--r--src/app/qbs/parser/commandlineparser.cpp5
-rw-r--r--src/app/qbs/parser/commandlineparser.h1
-rw-r--r--src/app/qbs/parser/parsercommand.cpp3
-rw-r--r--src/lib/corelib/buildgraph/buildgraphloader.cpp2
-rw-r--r--src/lib/corelib/corelib.qbs1
-rw-r--r--src/lib/corelib/language/builtindeclarations.cpp14
-rw-r--r--src/lib/corelib/language/builtindeclarations.h1
-rw-r--r--src/lib/corelib/language/evaluatorscriptclass.cpp3
-rw-r--r--src/lib/corelib/language/itemtype.h1
-rw-r--r--src/lib/corelib/language/language.cpp20
-rw-r--r--src/lib/corelib/language/language.h7
-rw-r--r--src/lib/corelib/language/language.pri1
-rw-r--r--src/lib/corelib/language/loader.cpp6
-rw-r--r--src/lib/corelib/language/loader.h3
-rw-r--r--src/lib/corelib/language/moduleloader.cpp236
-rw-r--r--src/lib/corelib/language/moduleloader.h34
-rw-r--r--src/lib/corelib/language/moduleproviderinfo.h90
-rw-r--r--src/lib/corelib/language/projectresolver.cpp1
-rw-r--r--src/lib/corelib/tools/persistence.cpp2
-rw-r--r--src/lib/corelib/tools/setupprojectparameters.cpp17
-rw-r--r--src/lib/corelib/tools/setupprojectparameters.h3
-rw-r--r--src/lib/corelib/tools/stringconstants.h2
27 files changed, 460 insertions, 24 deletions
diff --git a/src/app/qbs/commandlinefrontend.cpp b/src/app/qbs/commandlinefrontend.cpp
index 978fdbb7a..c848b24d0 100644
--- a/src/app/qbs/commandlinefrontend.cpp
+++ b/src/app/qbs/commandlinefrontend.cpp
@@ -146,6 +146,7 @@ void CommandLineFrontend::start()
params.setDryRun(m_parser.dryRun());
params.setForceProbeExecution(m_parser.forceProbesExecution());
params.setWaitLockBuildGraph(m_parser.waitLockBuildGraph());
+ params.setFallbackProviderEnabled(!m_parser.disableFallbackProvider());
params.setLogElapsedTime(m_parser.logTime());
params.setSettingsDirectory(m_settings->baseDirectory());
params.setOverrideBuildGraphData(m_parser.command() == ResolveCommandType);
diff --git a/src/app/qbs/parser/commandlineoption.cpp b/src/app/qbs/parser/commandlineoption.cpp
index e18658751..dc5b4e440 100644
--- a/src/app/qbs/parser/commandlineoption.cpp
+++ b/src/app/qbs/parser/commandlineoption.cpp
@@ -681,6 +681,17 @@ QString WaitLockOption::longRepresentation() const
return QLatin1String("--wait-lock");
}
+QString DisableFallbackProviderOption::description(CommandType) const
+{
+ return Tr::tr("%1\n\tDo not fall back to pkg-config if a dependency is not found.\n")
+ .arg(longRepresentation());
+}
+
+QString DisableFallbackProviderOption::longRepresentation() const
+{
+ return QLatin1String("--no-fallback-module-provider");
+}
+
QString RunEnvConfigOption::description(CommandType command) const
{
Q_UNUSED(command);
diff --git a/src/app/qbs/parser/commandlineoption.h b/src/app/qbs/parser/commandlineoption.h
index d57ec76b7..414f90489 100644
--- a/src/app/qbs/parser/commandlineoption.h
+++ b/src/app/qbs/parser/commandlineoption.h
@@ -75,6 +75,7 @@ public:
GeneratorOptionType,
WaitLockOptionType,
RunEnvConfigOptionType,
+ DisableFallbackProviderType,
};
virtual ~CommandLineOption();
@@ -414,6 +415,14 @@ public:
QString longRepresentation() const override;
};
+class DisableFallbackProviderOption : public OnOffOption
+{
+public:
+ QString description(CommandType command) const override;
+ QString shortRepresentation() const override { return QString(); }
+ QString longRepresentation() const override;
+};
+
} // namespace qbs
#endif // QBS_COMMANDLINEOPTION_H
diff --git a/src/app/qbs/parser/commandlineoptionpool.cpp b/src/app/qbs/parser/commandlineoptionpool.cpp
index 9964f051a..63711f623 100644
--- a/src/app/qbs/parser/commandlineoptionpool.cpp
+++ b/src/app/qbs/parser/commandlineoptionpool.cpp
@@ -128,6 +128,9 @@ CommandLineOption *CommandLineOptionPool::getOption(CommandLineOption::Type type
case CommandLineOption::WaitLockOptionType:
option = new WaitLockOption;
break;
+ case CommandLineOption::DisableFallbackProviderType:
+ option = new DisableFallbackProviderOption;
+ break;
case CommandLineOption::RunEnvConfigOptionType:
option = new RunEnvConfigOption;
break;
@@ -273,6 +276,12 @@ WaitLockOption *CommandLineOptionPool::waitLockOption() const
return static_cast<WaitLockOption *>(getOption(CommandLineOption::WaitLockOptionType));
}
+DisableFallbackProviderOption *CommandLineOptionPool::disableFallbackProviderOption() const
+{
+ return static_cast<DisableFallbackProviderOption *>(
+ getOption(CommandLineOption::DisableFallbackProviderType));
+}
+
RunEnvConfigOption *CommandLineOptionPool::runEnvConfigOption() const
{
return static_cast<RunEnvConfigOption *>(getOption(CommandLineOption::RunEnvConfigOptionType));
diff --git a/src/app/qbs/parser/commandlineoptionpool.h b/src/app/qbs/parser/commandlineoptionpool.h
index 6a4669165..c7ac263e1 100644
--- a/src/app/qbs/parser/commandlineoptionpool.h
+++ b/src/app/qbs/parser/commandlineoptionpool.h
@@ -77,6 +77,7 @@ public:
RespectProjectJobLimitsOption *respectProjectJobLimitsOption() const;
GeneratorOption *generatorOption() const;
WaitLockOption *waitLockOption() const;
+ DisableFallbackProviderOption *disableFallbackProviderOption() const;
RunEnvConfigOption *runEnvConfigOption() const;
private:
diff --git a/src/app/qbs/parser/commandlineparser.cpp b/src/app/qbs/parser/commandlineparser.cpp
index c2e265336..2ec0df1df 100644
--- a/src/app/qbs/parser/commandlineparser.cpp
+++ b/src/app/qbs/parser/commandlineparser.cpp
@@ -231,6 +231,11 @@ bool CommandLineParser::waitLockBuildGraph() const
return d->optionPool.waitLockOption()->enabled();
}
+bool CommandLineParser::disableFallbackProvider() const
+{
+ return d->optionPool.disableFallbackProviderOption()->enabled();
+}
+
bool CommandLineParser::logTime() const
{
return d->logTime;
diff --git a/src/app/qbs/parser/commandlineparser.h b/src/app/qbs/parser/commandlineparser.h
index e2ef8ad77..d47657b16 100644
--- a/src/app/qbs/parser/commandlineparser.h
+++ b/src/app/qbs/parser/commandlineparser.h
@@ -76,6 +76,7 @@ public:
bool dryRun() const;
bool forceProbesExecution() const;
bool waitLockBuildGraph() const;
+ bool disableFallbackProvider() const;
bool logTime() const;
bool withNonDefaultProducts() const;
bool buildBeforeInstalling() const;
diff --git a/src/app/qbs/parser/parsercommand.cpp b/src/app/qbs/parser/parsercommand.cpp
index 33f93ce53..79636ff0a 100644
--- a/src/app/qbs/parser/parsercommand.cpp
+++ b/src/app/qbs/parser/parsercommand.cpp
@@ -210,7 +210,8 @@ static QList<CommandLineOption::Type> resolveOptions()
<< CommandLineOption::ShowProgressOptionType
<< CommandLineOption::DryRunOptionType
<< CommandLineOption::ForceProbesOptionType
- << CommandLineOption::LogTimeOptionType;
+ << CommandLineOption::LogTimeOptionType
+ << CommandLineOption::DisableFallbackProviderType;
}
QList<CommandLineOption::Type> ResolveCommand::supportedOptions() const
diff --git a/src/lib/corelib/buildgraph/buildgraphloader.cpp b/src/lib/corelib/buildgraph/buildgraphloader.cpp
index a1ca7afdb..e6d1cb75a 100644
--- a/src/lib/corelib/buildgraph/buildgraphloader.cpp
+++ b/src/lib/corelib/buildgraph/buildgraphloader.cpp
@@ -340,6 +340,8 @@ void BuildGraphLoader::trackProjectChanges()
ldr.setSearchPaths(m_parameters.searchPaths());
ldr.setProgressObserver(m_evalContext->observer());
ldr.setOldProjectProbes(restoredProject->probes);
+ if (!m_parameters.forceProbeExecution())
+ ldr.setStoredModuleProviderInfo(restoredProject->moduleProviderInfo);
ldr.setLastResolveTime(restoredProject->lastResolveTime);
QHash<QString, std::vector<ProbeConstPtr>> restoredProbes;
for (const auto &restoredProduct : qAsConst(allRestoredProducts))
diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs
index c947cb484..db00a7005 100644
--- a/src/lib/corelib/corelib.qbs
+++ b/src/lib/corelib/corelib.qbs
@@ -299,6 +299,7 @@ QbsLibrary {
"moduleloader.h",
"modulemerger.cpp",
"modulemerger.h",
+ "moduleproviderinfo.h",
"preparescriptobserver.cpp",
"preparescriptobserver.h",
"projectresolver.cpp",
diff --git a/src/lib/corelib/language/builtindeclarations.cpp b/src/lib/corelib/language/builtindeclarations.cpp
index bfdfab51e..3ca0608d4 100644
--- a/src/lib/corelib/language/builtindeclarations.cpp
+++ b/src/lib/corelib/language/builtindeclarations.cpp
@@ -69,6 +69,7 @@ BuiltinDeclarations::BuiltinDeclarations()
{ QLatin1String("Group"), ItemType::Group },
{ QLatin1String("JobLimit"), ItemType::JobLimit },
{ QLatin1String("Module"), ItemType::Module },
+ { QLatin1String("ModuleProvider"), ItemType::ModuleProvider },
{ QLatin1String("Parameter"), ItemType::Parameter },
{ QLatin1String("Parameters"), ItemType::Parameters },
{ QLatin1String("Probe"), ItemType::Probe },
@@ -90,6 +91,7 @@ BuiltinDeclarations::BuiltinDeclarations()
addGroupItem();
addJobLimitItem();
addModuleItem();
+ addModuleProviderItem();
addProbeItem();
addProductItem();
addProfileItem();
@@ -244,6 +246,8 @@ void BuiltinDeclarations::addDependsItem()
item << PropertyDeclaration(StringConstants::multiplexConfigurationIdsProperty(),
PropertyDeclaration::StringList, QString(),
PropertyDeclaration::ReadOnlyFlag);
+ item << PropertyDeclaration(StringConstants::enableFallbackProperty(),
+ PropertyDeclaration::Boolean, StringConstants::trueValue());
insert(item);
}
@@ -316,6 +320,16 @@ void BuiltinDeclarations::addModuleItem()
insert(item);
}
+void BuiltinDeclarations::addModuleProviderItem()
+{
+ ItemDeclaration item(ItemType::ModuleProvider);
+ item << nameProperty()
+ << PropertyDeclaration(QStringLiteral("outputBaseDir"), PropertyDeclaration::String)
+ << PropertyDeclaration(QStringLiteral("relativeSearchPaths"),
+ PropertyDeclaration::StringList);
+ insert(item);
+}
+
ItemDeclaration BuiltinDeclarations::moduleLikeItem(ItemType type)
{
ItemDeclaration item(type);
diff --git a/src/lib/corelib/language/builtindeclarations.h b/src/lib/corelib/language/builtindeclarations.h
index ff16b395a..988f9ab81 100644
--- a/src/lib/corelib/language/builtindeclarations.h
+++ b/src/lib/corelib/language/builtindeclarations.h
@@ -78,6 +78,7 @@ private:
void addGroupItem();
void addJobLimitItem();
void addModuleItem();
+ void addModuleProviderItem();
static ItemDeclaration moduleLikeItem(ItemType type);
void addProbeItem();
void addProductItem();
diff --git a/src/lib/corelib/language/evaluatorscriptclass.cpp b/src/lib/corelib/language/evaluatorscriptclass.cpp
index a5e23a131..829cb7494 100644
--- a/src/lib/corelib/language/evaluatorscriptclass.cpp
+++ b/src/lib/corelib/language/evaluatorscriptclass.cpp
@@ -621,7 +621,8 @@ public:
|| itemOfProperty->type() == ItemType::Export)) {
const VariantValueConstPtr varValue
= itemOfProperty->variantProperty(StringConstants::nameProperty());
- QBS_ASSERT(varValue, return);
+ if (!varValue)
+ return;
m_stackUpdate = true;
const QualifiedId fullPropName
= QualifiedId::fromString(varValue->value().toString()) << name.toString();
diff --git a/src/lib/corelib/language/itemtype.h b/src/lib/corelib/language/itemtype.h
index 324a1fb87..724666cb4 100644
--- a/src/lib/corelib/language/itemtype.h
+++ b/src/lib/corelib/language/itemtype.h
@@ -55,6 +55,7 @@ enum class ItemType {
Group,
JobLimit,
Module,
+ ModuleProvider,
Parameter,
Parameters,
Probe,
diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp
index d8a5d9162..2a9eb5b0e 100644
--- a/src/lib/corelib/language/language.cpp
+++ b/src/lib/corelib/language/language.cpp
@@ -594,6 +594,7 @@ TopLevelProject::TopLevelProject()
TopLevelProject::~TopLevelProject()
{
+ cleanupModuleProviderOutput();
delete bgLocker;
}
@@ -636,6 +637,8 @@ void TopLevelProject::store(Logger logger)
qCDebug(lcBuildGraph) << "build graph is unchanged in project" << id();
return;
}
+ for (ModuleProviderInfo &m : moduleProviderInfo)
+ m.transientOutput = false;
const QString fileName = buildGraphFilePath();
qCDebug(lcBuildGraph) << "storing:" << fileName;
PersistentPool pool(logger);
@@ -661,6 +664,23 @@ void TopLevelProject::store(PersistentPool &pool)
serializationOp<PersistentPool::Store>(pool);
}
+void TopLevelProject::cleanupModuleProviderOutput()
+{
+ QString error;
+ for (const ModuleProviderInfo &m : moduleProviderInfo) {
+ if (m.transientOutput) {
+ if (!removeDirectoryWithContents(m.outputDirPath(buildDirectory), &error))
+ qCWarning(lcBuildGraph) << "Error removing module provider output:" << error;
+ }
+ }
+ QDir moduleProviderBaseDir(buildDirectory + QLatin1Char('/')
+ + ModuleProviderInfo::outputBaseDirName());
+ if (moduleProviderBaseDir.exists() && moduleProviderBaseDir.isEmpty()
+ && !removeDirectoryWithContents(moduleProviderBaseDir.path(), &error)) {
+ qCWarning(lcBuildGraph) << "Error removing module provider output:" << error;
+ }
+}
+
/*!
* \class SourceWildCards
* \brief Objects of the \c SourceWildCards class result from giving wildcards in a
diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h
index f9d69efff..994ad6c55 100644
--- a/src/lib/corelib/language/language.h
+++ b/src/lib/corelib/language/language.h
@@ -43,6 +43,7 @@
#include "filetags.h"
#include "forward_decls.h"
#include "jsimports.h"
+#include "moduleproviderinfo.h"
#include "propertydeclaration.h"
#include "resolvedfilecontext.h"
@@ -691,6 +692,7 @@ public:
QString buildDirectory; // Not saved
QProcessEnvironment environment;
std::vector<ProbeConstPtr> probes;
+ ModuleProviderInfoList moduleProviderInfo;
QHash<QString, QString> canonicalFilePathResults; // Results of calls to "File.canonicalFilePath()."
QHash<QString, bool> fileExistsResults; // Results of calls to "File.exists()".
@@ -722,11 +724,14 @@ private:
pool.serializationOp<opType>(m_id, canonicalFilePathResults, fileExistsResults,
directoryEntriesResults, fileLastModifiedResults, environment,
probes, profileConfigs, overriddenValues, buildSystemFiles,
- lastResolveTime, warningsEncountered, buildData);
+ lastResolveTime, warningsEncountered, buildData,
+ moduleProviderInfo);
}
void load(PersistentPool &pool) override;
void store(PersistentPool &pool) override;
+ void cleanupModuleProviderOutput();
+
QString m_id;
QVariantMap m_buildConfiguration;
};
diff --git a/src/lib/corelib/language/language.pri b/src/lib/corelib/language/language.pri
index 6d68f9643..e07a671b9 100644
--- a/src/lib/corelib/language/language.pri
+++ b/src/lib/corelib/language/language.pri
@@ -28,6 +28,7 @@ HEADERS += \
$$PWD/loader.h \
$$PWD/moduleloader.h \
$$PWD/modulemerger.h \
+ $$PWD/moduleproviderinfo.h \
$$PWD/preparescriptobserver.h \
$$PWD/projectresolver.h \
$$PWD/property.h \
diff --git a/src/lib/corelib/language/loader.cpp b/src/lib/corelib/language/loader.cpp
index 98a90e221..4d2eef983 100644
--- a/src/lib/corelib/language/loader.cpp
+++ b/src/lib/corelib/language/loader.cpp
@@ -104,6 +104,11 @@ void Loader::setStoredProfiles(const QVariantMap &profiles)
m_storedProfiles = profiles;
}
+void Loader::setStoredModuleProviderInfo(const ModuleProviderInfoList &providerInfo)
+{
+ m_storedModuleProviderInfo = providerInfo;
+}
+
TopLevelProjectPtr Loader::loadProject(const SetupProjectParameters &_parameters)
{
SetupProjectParameters parameters = _parameters;
@@ -160,6 +165,7 @@ TopLevelProjectPtr Loader::loadProject(const SetupProjectParameters &_parameters
moduleLoader.setOldProductProbes(m_oldProductProbes);
moduleLoader.setLastResolveTime(m_lastResolveTime);
moduleLoader.setStoredProfiles(m_storedProfiles);
+ moduleLoader.setStoredModuleProviderInfo(m_storedModuleProviderInfo);
const ModuleLoaderResult loadResult = moduleLoader.load(parameters);
ProjectResolver resolver(&evaluator, loadResult, parameters, m_logger);
resolver.setProgressObserver(m_progressObserver);
diff --git a/src/lib/corelib/language/loader.h b/src/lib/corelib/language/loader.h
index 9883d5b66..48a0b6065 100644
--- a/src/lib/corelib/language/loader.h
+++ b/src/lib/corelib/language/loader.h
@@ -40,6 +40,7 @@
#define QBS_LOADER_H
#include "forward_decls.h"
+#include "moduleproviderinfo.h"
#include <logging/logger.h>
#include <tools/filetime.h>
@@ -64,6 +65,7 @@ public:
void setOldProductProbes(const QHash<QString, std::vector<ProbeConstPtr>> &oldProbes);
void setLastResolveTime(const FileTime &time) { m_lastResolveTime = time; }
void setStoredProfiles(const QVariantMap &profiles);
+ void setStoredModuleProviderInfo(const ModuleProviderInfoList &providerInfo);
TopLevelProjectPtr loadProject(const SetupProjectParameters &parameters);
static void setupProjectFilePath(SetupProjectParameters &parameters);
@@ -75,6 +77,7 @@ private:
QStringList m_searchPaths;
std::vector<ProbeConstPtr> m_oldProjectProbes;
QHash<QString, std::vector<ProbeConstPtr>> m_oldProductProbes;
+ ModuleProviderInfoList m_storedModuleProviderInfo;
QVariantMap m_storedProfiles;
FileTime m_lastResolveTime;
};
diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp
index b34cfd6a9..c4d77ba40 100644
--- a/src/lib/corelib/language/moduleloader.cpp
+++ b/src/lib/corelib/language/moduleloader.cpp
@@ -57,6 +57,7 @@
#include <logging/translator.h>
#include <tools/error.h>
#include <tools/fileinfo.h>
+#include <tools/jsliterals.h>
#include <tools/preferences.h>
#include <tools/profile.h>
#include <tools/profiling.h>
@@ -73,6 +74,8 @@
#include <QtCore/qdiriterator.h>
#include <QtCore/qjsondocument.h>
#include <QtCore/qjsonobject.h>
+#include <QtCore/qtemporaryfile.h>
+#include <QtCore/qtextstream.h>
#include <QtScript/qscriptvalueiterator.h>
#include <algorithm>
@@ -267,6 +270,11 @@ void ModuleLoader::setStoredProfiles(const QVariantMap &profiles)
m_storedProfiles = profiles;
}
+void ModuleLoader::setStoredModuleProviderInfo(const ModuleProviderInfoList &moduleProviderInfo)
+{
+ m_moduleProviderInfo = moduleProviderInfo;
+}
+
ModuleLoaderResult ModuleLoader::load(const SetupProjectParameters &parameters)
{
TimedActivityLogger moduleLoaderTimer(m_logger, Tr::tr("ModuleLoader"),
@@ -290,6 +298,7 @@ ModuleLoaderResult ModuleLoader::load(const SetupProjectParameters &parameters)
static const QStringList prefixes({ StringConstants::projectPrefix(),
QLatin1String("projects"),
QLatin1String("products"), QLatin1String("modules"),
+ StringConstants::moduleProviders(),
StringConstants::qbsModule()});
bool ok = false;
for (const auto &prefix : prefixes) {
@@ -309,6 +318,8 @@ ModuleLoaderResult ModuleLoader::load(const SetupProjectParameters &parameters)
e.append(QLatin1Char('\t') + Tr::tr("modules.<module-name>.<property-name>:value"));
e.append(QLatin1Char('\t') + Tr::tr("products.<product-name>.<module-name>."
"<property-name>:value"));
+ e.append(QLatin1Char('\t') + Tr::tr("moduleProviders.<provider-name>."
+ "<property-name>:value"));
handlePropertyError(e, m_parameters, m_logger);
}
@@ -456,6 +467,9 @@ private:
m_parentItems.push_back(item);
for (Item::PropertyMap::const_iterator it = item->properties().constBegin();
it != item->properties().constEnd(); ++it) {
+ if (item->type() == ItemType::Product && it.key() == StringConstants::moduleProviders()
+ && it.value()->type() == Value::ItemValueType)
+ continue;
const PropertyDeclaration decl = item->propertyDeclaration(it.key());
if (decl.isValid()) {
if (!decl.isDeprecated())
@@ -547,6 +561,9 @@ void ModuleLoader::handleTopLevelProject(ModuleLoaderResult *loadResult, Item *p
throw err;
handleProductError(err, &productContext);
}
+ for (std::size_t i = 0; i < productContext.newlyAddedModuleProviderSearchPaths.size(); ++i)
+ m_reader->popExtraSearchPaths();
+ productContext.newlyAddedModuleProviderSearchPaths.clear();
}
}
if (!m_productsWithDeferredDependsItems.empty() || !m_exportsWithDeferredDependsItems.empty()) {
@@ -585,6 +602,7 @@ void ModuleLoader::handleTopLevelProject(ModuleLoaderResult *loadResult, Item *p
}
loadResult->projectProbes = tlp.probes;
+ loadResult->moduleProviderInfo = m_moduleProviderInfo;
m_reader->clearExtraSearchPathsStack();
AccumulatingTimer timer(m_parameters.logElapsedTime()
@@ -2111,6 +2129,18 @@ void ModuleLoader::setSearchPathsForProduct(ModuleLoader::ProductContext *produc
if (!currentSearchPaths.contains(p) && FileInfo(p).exists())
product->searchPaths << p;
}
+
+ // Existing module provider search paths are re-used if and only if the provider configuration
+ // at setup time was the same as the current one for the respective module provider.
+ if (!m_moduleProviderInfo.empty()) {
+ const QVariantMap configForProduct = moduleProviderConfig(*product);
+ for (const ModuleProviderInfo &c : m_moduleProviderInfo) {
+ if (configForProduct.value(c.name.toString()) == c.config) {
+ product->knownModuleProviders.insert(c.name);
+ product->searchPaths << c.searchPaths;
+ }
+ }
+ }
}
ModuleLoader::ShadowProductInfo ModuleLoader::getShadowProductInfo(
@@ -2498,6 +2528,9 @@ void ModuleLoader::resolveDependsItem(DependsContext *dependsContext, Item *pare
QString msg = Tr::tr("A Depends item with more than one module cannot have an id.");
throw ErrorInfo(msg, dependsItem->location());
}
+ const FallbackMode fallbackMode = m_parameters.fallbackProviderEnabled()
+ && m_evaluator->boolValue(dependsItem, StringConstants::enableFallbackProperty())
+ ? FallbackMode::Enabled : FallbackMode::Disabled;
QList<QualifiedId> moduleNames;
const QualifiedId nameParts = QualifiedId::fromString(name);
@@ -2554,8 +2587,8 @@ void ModuleLoader::resolveDependsItem(DependsContext *dependsContext, Item *pare
QVariantMap defaultParameters;
Item *moduleItem = loadModule(dependsContext->product, dependsContext->exportingProductItem,
parentItem, dependsItem->location(), dependsItem->id(),
- moduleName, multiplexConfigurationIds.first(), isRequired,
- &result.isProduct, &defaultParameters);
+ moduleName, multiplexConfigurationIds.first(), fallbackMode,
+ isRequired, &result.isProduct, &defaultParameters);
if (!moduleItem) {
const QString productName = ResolvedProduct::fullDisplayName(
dependsContext->product->name,
@@ -2746,11 +2779,12 @@ Item *ModuleLoader::moduleInstanceItem(Item *containerItem, const QualifiedId &m
return instance;
}
-ModuleLoader::ProductModuleInfo *ModuleLoader::productModule(
- ProductContext *productContext, const QString &name, const QString &multiplexId)
+ModuleLoader::ProductModuleInfo *ModuleLoader::productModule(ProductContext *productContext,
+ const QString &name, const QString &multiplexId, bool &productNameMatch)
{
auto &exportsData = productContext->project->topLevelProject->productModules;
const auto firstIt = exportsData.find(name);
+ productNameMatch = firstIt != exportsData.end();
for (auto it = firstIt; it != exportsData.end() && it.key() == name; ++it) {
if (it.value().multiplexId == multiplexId)
return &it.value();
@@ -2861,8 +2895,9 @@ private:
Item *ModuleLoader::loadModule(ProductContext *productContext, Item *exportingProductItem,
Item *item, const CodeLocation &dependsItemLocation,
const QString &moduleId, const QualifiedId &moduleName,
- const QString &multiplexId, bool isRequired,
- bool *isProductDependency, QVariantMap *defaultParameters)
+ const QString &multiplexId, FallbackMode fallbackMode,
+ bool isRequired, bool *isProductDependency,
+ QVariantMap *defaultParameters)
{
qCDebug(lcModuleLoader) << "loadModule name:" << moduleName.toString() << "id:" << moduleId;
@@ -2900,17 +2935,15 @@ Item *ModuleLoader::loadModule(ProductContext *productContext, Item *exportingPr
Item *modulePrototype = nullptr;
ProductModuleInfo * const pmi = productModule(productContext, moduleName.toString(),
- multiplexId);
+ multiplexId, *isProductDependency);
if (pmi) {
- *isProductDependency = true;
m_dependsChain.back().isProduct = true;
modulePrototype = pmi->exportItem;
if (defaultParameters)
*defaultParameters = pmi->defaultParameters;
- } else {
- *isProductDependency = false;
+ } else if (!*isProductDependency) {
modulePrototype = searchAndLoadModuleFile(productContext, dependsItemLocation,
- moduleName, isRequired, moduleInstance);
+ moduleName, fallbackMode, isRequired, moduleInstance);
}
delayedPropertyChanger.applyNow();
if (!modulePrototype)
@@ -2968,17 +3001,19 @@ static Item *chooseModuleCandidate(const std::vector<PrioritizedItem> &candidate
Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext,
const CodeLocation &dependsItemLocation, const QualifiedId &moduleName,
- bool isRequired, Item *moduleInstance)
+ FallbackMode fallbackMode, bool isRequired, Item *moduleInstance)
{
bool triedToLoadModule = false;
const QString fullName = moduleName.toString();
std::vector<PrioritizedItem> candidates;
const QStringList &searchPaths = m_reader->allSearchPaths();
+ bool matchingDirectoryFound = false;
for (int i = 0; i < searchPaths.size(); ++i) {
const QString &path = searchPaths.at(i);
const QString dirPath = findExistingModulePath(path, moduleName);
if (dirPath.isEmpty())
continue;
+ matchingDirectoryFound = true;
QStringList moduleFileNames = m_moduleDirListCache.value(dirPath);
if (moduleFileNames.empty()) {
QDirIterator dirIter(dirPath, StringConstants::qbsFileWildcards());
@@ -2999,6 +3034,36 @@ Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext,
}
if (candidates.empty()) {
+ if (!matchingDirectoryFound) {
+ bool moduleAlreadyKnown = false;
+ ModuleProviderResult result;
+ for (QualifiedId providerName = moduleName; !providerName.empty();
+ providerName.pop_back()) {
+ if (!productContext->knownModuleProviders.insert(providerName).second) {
+ moduleAlreadyKnown = true;
+ break;
+ }
+ qCDebug(lcModuleLoader) << "Module" << moduleName.toString()
+ << "not found, checking for module providers";
+ result = findModuleProvider(providerName, *productContext,
+ ModuleProviderLookup::Regular, dependsItemLocation);
+ if (result.providerFound)
+ break;
+ }
+ if (fallbackMode == FallbackMode::Enabled && !result.providerFound
+ && !moduleAlreadyKnown) {
+ qCDebug(lcModuleLoader) << "Specific module provider not found for"
+ << moduleName.toString() << ", setting up fallback.";
+ result = findModuleProvider(moduleName, *productContext,
+ ModuleProviderLookup::Fallback, dependsItemLocation);
+ }
+ if (result.providerAddedSearchPaths) {
+ qCDebug(lcModuleLoader) << "Re-checking for module" << moduleName.toString()
+ << "with newly added search paths from module provider";
+ return searchAndLoadModuleFile(productContext, dependsItemLocation, moduleName,
+ fallbackMode, isRequired, moduleInstance);
+ }
+ }
if (!isRequired)
return createNonPresentModule(fullName, QLatin1String("not found"), nullptr);
if (Q_UNLIKELY(triedToLoadModule))
@@ -3177,8 +3242,8 @@ Item::Module ModuleLoader::loadBaseModule(ProductContext *productContext, Item *
Item::Module baseModuleDesc;
baseModuleDesc.name = baseModuleName;
baseModuleDesc.item = loadModule(productContext, nullptr, item, CodeLocation(), QString(),
- baseModuleName, QString(), true, &baseModuleDesc.isProduct,
- nullptr);
+ baseModuleName, QString(), FallbackMode::Disabled, true,
+ &baseModuleDesc.isProduct, nullptr);
if (productContext->item) {
const Item * const qbsInstanceItem
= moduleInstanceItem(productContext->item, baseModuleName);
@@ -3599,6 +3664,145 @@ QString ModuleLoader::findExistingModulePath(const QString &searchPath,
return dirPath;
}
+QVariantMap ModuleLoader::moduleProviderConfig(ModuleLoader::ProductContext &product)
+{
+ if (product.moduleProviderConfigRetrieved)
+ return product.theModuleProviderConfig;
+ const ItemValueConstPtr configItemValue
+ = product.item->itemProperty(StringConstants::moduleProviders());
+ if (configItemValue) {
+ const std::function<void(const Item *, QualifiedId)> collectMap
+ = [this, &product, &collectMap](const Item *item, QualifiedId name) {
+ const Item::PropertyMap &props = item->properties();
+ for (auto it = props.begin(); it != props.end(); ++it) {
+ QVariant value;
+ switch (it.value()->type()) {
+ case Value::ItemValueType:
+ collectMap(static_cast<ItemValue *>(it.value().get())->item(),
+ QualifiedId(name += it.key()));
+ return;
+ case Value::JSSourceValueType:
+ value = m_evaluator->value(item, it.key()).toVariant();
+ break;
+ case Value::VariantValueType:
+ value = static_cast<VariantValue *>(it.value().get())->value();
+ break;
+ }
+ QVariantMap m = product.theModuleProviderConfig.value(name.toString()).toMap();
+ m.insert(it.key(), value);
+ product.theModuleProviderConfig.insert(name.toString(), m);
+ }
+ };
+ collectMap(configItemValue->item(), QualifiedId());
+ }
+ for (auto it = product.moduleProperties.begin(); it != product.moduleProperties.end(); ++it) {
+ if (!it.key().startsWith(QStringLiteral("moduleProviders.")))
+ continue;
+ const QString provider = it.key().mid(QStringLiteral("moduleProviders.").size());
+ const QVariantMap providerConfigFromBuildConfig = it.value().toMap();
+ if (providerConfigFromBuildConfig.empty())
+ continue;
+ QVariantMap currentMapForProvider = product.theModuleProviderConfig.value(provider).toMap();
+ for (auto propIt = providerConfigFromBuildConfig.begin();
+ propIt != providerConfigFromBuildConfig.end(); ++propIt) {
+ currentMapForProvider.insert(propIt.key(), propIt.value());
+ }
+ product.theModuleProviderConfig.insert(provider, currentMapForProvider);
+ }
+ product.moduleProviderConfigRetrieved = true;
+ return product.theModuleProviderConfig;
+}
+
+ModuleLoader::ModuleProviderResult ModuleLoader::findModuleProvider(const QualifiedId &name,
+ ModuleLoader::ProductContext &product, ModuleProviderLookup lookupType,
+ const CodeLocation &dependsItemLocation)
+{
+ for (const QString &path : m_reader->allSearchPaths()) {
+ QString fullPath = FileInfo::resolvePath(path, QStringLiteral("module-providers"));
+ switch (lookupType) {
+ case ModuleProviderLookup::Regular:
+ for (const QString &component : name)
+ fullPath = FileInfo::resolvePath(fullPath, component);
+ break;
+ case ModuleProviderLookup::Fallback:
+ fullPath = FileInfo::resolvePath(fullPath, QStringLiteral("__fallback"));
+ break;
+ }
+ const QString providerFile = FileInfo::resolvePath(fullPath,
+ QStringLiteral("provider.qbs"));
+ if (!FileInfo::exists(providerFile)) {
+ qCDebug(lcModuleLoader) << "No module provider found at" << providerFile;
+ continue;
+ }
+ QTemporaryFile dummyItemFile;
+ if (!dummyItemFile.open()) {
+ throw ErrorInfo(Tr::tr("Failed to create temporary file for running module provider "
+ "for dependency '%1': %2").arg(name.toString(),
+ dummyItemFile.errorString()));
+ }
+ qCDebug(lcModuleLoader) << "Instantiating module provider at" << providerFile;
+ const QString projectBuildDir = product.project->item->variantProperty(
+ StringConstants::buildDirectoryProperty())->value().toString();
+ const QString searchPathBaseDir = ModuleProviderInfo::outputDirPath(projectBuildDir, name);
+ const QVariant moduleConfig = moduleProviderConfig(product).value(name.toString());
+ QTextStream stream(&dummyItemFile);
+ stream.setCodec("UTF-8");
+ stream << "import qbs.FileInfo" << endl;
+ stream << "import qbs.Utilities" << endl;
+ stream << "import '" << providerFile << "' as Provider" << endl;
+ stream << "Provider {" << endl;
+ stream << " name: " << toJSLiteral(name.toString()) << endl;
+ stream << " property var config: (" << toJSLiteral(moduleConfig) << ')' << endl;
+ stream << " outputBaseDir: FileInfo.joinPaths(baseDirPrefix, "
+ " Utilities.getHash(JSON.stringify(config)))" << endl;
+ stream << " property string baseDirPrefix: " << toJSLiteral(searchPathBaseDir) << endl;
+ stream << " property stringList searchPaths: (relativeSearchPaths || [])"
+ " .map(function(p) { return FileInfo.joinPaths(outputBaseDir, p); })"
+ << endl;
+ stream << "}" << endl;
+ stream.flush();
+ Item * const providerItem = loadItemFromFile(dummyItemFile.fileName(), dependsItemLocation);
+ if (providerItem->type() != ItemType::ModuleProvider) {
+ throw ErrorInfo(Tr::tr("File '%1' declares an item of type '%2', "
+ "but '%3' was expected.")
+ .arg(providerFile, providerItem->typeName(),
+ BuiltinDeclarations::instance().nameForType(ItemType::ModuleProvider)));
+ }
+ const QVariantMap configMap = moduleConfig.toMap();
+ for (auto it = configMap.begin(); it != configMap.end(); ++it) {
+ const PropertyDeclaration decl = providerItem->propertyDeclaration(it.key());
+ if (!decl.isValid()) {
+ throw ErrorInfo(Tr::tr("No such property '%1' in module provider '%2'.")
+ .arg(it.key(), name.toString()));
+ }
+ providerItem->setProperty(it.key(), VariantValue::create(it.value()));
+ }
+ EvalContextSwitcher contextSwitcher(m_evaluator->engine(), EvalContext::ProbeExecution);
+ const QStringList searchPaths
+ = m_evaluator->stringListValue(providerItem, QStringLiteral("searchPaths"));
+ if (searchPaths.empty()) {
+ qCDebug(lcModuleLoader) << "Module provider did run, but did not set up "
+ "any modules.";
+ return ModuleProviderResult(true, false);
+ }
+ qCDebug(lcModuleLoader) << "Module provider added" << searchPaths.size()
+ << "new search path(s)";
+
+ // (1) is needed so the immediate new look-up works.
+ // (2) is needed so the next use of SearchPathManager considers the new paths.
+ // (3) is needed for the code that removes the product-specific search paths when
+ // product handling is done.
+ // (4) is needed for possible re-use in subsequent products and builds.
+ m_reader->pushExtraSearchPaths(searchPaths); // (1)
+ product.searchPaths << searchPaths; // (2)
+ product.newlyAddedModuleProviderSearchPaths.push_back(searchPaths); // (3)
+ m_moduleProviderInfo.emplace_back(ModuleProviderInfo(name, moduleConfig.toMap(), // (4)
+ searchPaths, m_parameters.dryRun()));
+ return ModuleProviderResult(true, true);
+ }
+ return ModuleProviderResult();
+}
+
void ModuleLoader::setScopeForDescendants(Item *item, Item *scope)
{
for (Item * const child : item->children()) {
@@ -3755,8 +3959,8 @@ void ModuleLoader::addTransitiveDependencies(ProductContext *ctx)
} else {
Item::Module dep;
dep.item = loadModule(ctx, nullptr, ctx->item, ctx->item->location(), QString(),
- module.name, QString(), module.required, &dep.isProduct,
- &dep.parameters);
+ module.name, QString(), FallbackMode::Disabled,
+ module.required, &dep.isProduct, &dep.parameters);
if (!dep.item) {
throw ErrorInfo(Tr::tr("Module '%1' not found when setting up transitive "
"dependencies for product '%2'.").arg(module.name.toString(),
diff --git a/src/lib/corelib/language/moduleloader.h b/src/lib/corelib/language/moduleloader.h
index 7b9e0bede..9e45908c3 100644
--- a/src/lib/corelib/language/moduleloader.h
+++ b/src/lib/corelib/language/moduleloader.h
@@ -44,6 +44,7 @@
#include "forward_decls.h"
#include "item.h"
#include "itempool.h"
+#include "moduleproviderinfo.h"
#include <logging/logger.h>
#include <tools/filetime.h>
#include <tools/qttools.h>
@@ -106,6 +107,7 @@ struct ModuleLoaderResult
Item *root;
QHash<Item *, ProductInfo> productInfos;
std::vector<ProbeConstPtr> projectProbes;
+ ModuleProviderInfoList moduleProviderInfo;
Set<QString> qbsFiles;
QVariantMap profileConfigs;
};
@@ -128,6 +130,7 @@ public:
void setOldProductProbes(const QHash<QString, std::vector<ProbeConstPtr>> &oldProbes);
void setLastResolveTime(const FileTime &time) { m_lastResolveTime = time; }
void setStoredProfiles(const QVariantMap &profiles);
+ void setStoredModuleProviderInfo(const ModuleProviderInfoList &moduleProviderInfo);
Evaluator *evaluator() const { return m_evaluator; }
ModuleLoaderResult load(const SetupProjectParameters &parameters);
@@ -181,6 +184,11 @@ private:
std::unordered_map<const Item *, std::vector<ErrorInfo>> unknownProfilePropertyErrors;
QStringList searchPaths;
+ std::vector<QStringList> newlyAddedModuleProviderSearchPaths;
+ Set<QualifiedId> knownModuleProviders;
+ QVariantMap theModuleProviderConfig;
+ bool moduleProviderConfigRetrieved = false;
+
// The key corresponds to DeferredDependsContext.exportingProductItem, which is the
// only value from that data structure that we still need here.
std::unordered_map<Item *, std::vector<Item *>> deferredDependsItems;
@@ -297,16 +305,18 @@ private:
QVariantMap extractParameters(Item *dependsItem) const;
Item *moduleInstanceItem(Item *containerItem, const QualifiedId &moduleName);
static ProductModuleInfo *productModule(ProductContext *productContext, const QString &name,
- const QString &multiplexId);
+ const QString &multiplexId, bool &productNameMatch);
static ProductContext *product(ProjectContext *projectContext, const QString &name);
static ProductContext *product(TopLevelProjectContext *tlpContext, const QString &name);
+
+ enum class FallbackMode { Enabled, Disabled };
Item *loadModule(ProductContext *productContext, Item *exportingProductItem, Item *item,
const CodeLocation &dependsItemLocation, const QString &moduleId,
- const QualifiedId &moduleName, const QString &multiplexId, bool isRequired,
- bool *isProductDependency, QVariantMap *defaultParameters);
+ const QualifiedId &moduleName, const QString &multiplexId, FallbackMode fallbackMode,
+ bool isRequired, bool *isProductDependency, QVariantMap *defaultParameters);
Item *searchAndLoadModuleFile(ProductContext *productContext,
const CodeLocation &dependsItemLocation, const QualifiedId &moduleName,
- bool isRequired, Item *moduleInstance);
+ FallbackMode fallbackMode, bool isRequired, Item *moduleInstance);
Item *loadModuleFile(ProductContext *productContext, const QString &fullModuleName,
bool isBaseModule, const QString &filePath, bool *triedToLoad, Item *moduleInstance);
Item *getModulePrototype(ProductContext *productContext, const QString &fullModuleName,
@@ -329,6 +339,20 @@ private:
Item *wrapInProjectIfNecessary(Item *item);
static QString findExistingModulePath(const QString &searchPath,
const QualifiedId &moduleName);
+
+ enum class ModuleProviderLookup { Regular, Fallback };
+ struct ModuleProviderResult
+ {
+ ModuleProviderResult() = default;
+ ModuleProviderResult(bool ran, bool added)
+ : providerFound(ran), providerAddedSearchPaths(added) {}
+ bool providerFound = false;
+ bool providerAddedSearchPaths = false;
+ };
+ ModuleProviderResult findModuleProvider(const QualifiedId &name, ProductContext &product,
+ ModuleProviderLookup lookupType, const CodeLocation &dependsItemLocation);
+ QVariantMap moduleProviderConfig(ProductContext &product);
+
static void setScopeForDescendants(Item *item, Item *scope);
void overrideItemProperties(Item *item, const QString &buildConfigKey,
const QVariantMap &buildConfig);
@@ -425,6 +449,8 @@ private:
std::unordered_map<ProductContext *, Set<DeferredDependsContext>> m_productsWithDeferredDependsItems;
Set<Item *> m_exportsWithDeferredDependsItems;
+ ModuleProviderInfoList m_moduleProviderInfo;
+
SetupProjectParameters m_parameters;
std::unique_ptr<Settings> m_settings;
Version m_qbsVersion;
diff --git a/src/lib/corelib/language/moduleproviderinfo.h b/src/lib/corelib/language/moduleproviderinfo.h
new file mode 100644
index 000000000..fef9d9765
--- /dev/null
+++ b/src/lib/corelib/language/moduleproviderinfo.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBS_MODULEPROVIDERINFO_H
+#define QBS_MODULEPROVIDERINFO_H
+
+#include "qualifiedid.h"
+#include <tools/persistence.h>
+
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvariant.h>
+
+#include <vector>
+
+namespace qbs {
+namespace Internal {
+
+class ModuleProviderInfo
+{
+public:
+ ModuleProviderInfo() = default;
+ ModuleProviderInfo(const QualifiedId &name, const QVariantMap &config,
+ const QStringList &searchPaths, bool transientOutput)
+ : name(name), config(config), searchPaths(searchPaths), transientOutput(transientOutput)
+ {}
+
+ static QString outputBaseDirName() { return QStringLiteral("genmodules"); }
+ static QString outputDirPath(const QString &baseDir, const QualifiedId &name)
+ {
+ return baseDir + QLatin1Char('/') + outputBaseDirName() + QLatin1Char('/')
+ + name.toString();
+ }
+ QString outputDirPath(const QString &baseDir) const
+ {
+ return outputDirPath(baseDir, name);
+ }
+
+ template<PersistentPool::OpType opType> void completeSerializationOp(PersistentPool &pool)
+ {
+ pool.serializationOp<opType>(reinterpret_cast<QStringList &>(name), config, searchPaths);
+ }
+
+ QualifiedId name;
+ QVariantMap config;
+ QStringList searchPaths;
+ bool transientOutput = false; // Not to be serialized.
+};
+
+using ModuleProviderInfoList = std::vector<ModuleProviderInfo>;
+
+} // namespace Internal
+} // namespace qbs
+
+#endif // Include guard
diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp
index 7deb964b3..d0af0b7ed 100644
--- a/src/lib/corelib/language/projectresolver.cpp
+++ b/src/lib/corelib/language/projectresolver.cpp
@@ -240,6 +240,7 @@ TopLevelProjectPtr ProjectResolver::resolveTopLevelProject()
project->buildSystemFiles = m_loadResult.qbsFiles;
project->profileConfigs = m_loadResult.profileConfigs;
project->probes = m_loadResult.projectProbes;
+ project->moduleProviderInfo = m_loadResult.moduleProviderInfo;
ProjectContext projectContext;
projectContext.project = project;
diff --git a/src/lib/corelib/tools/persistence.cpp b/src/lib/corelib/tools/persistence.cpp
index ec412cf3b..b50084702 100644
--- a/src/lib/corelib/tools/persistence.cpp
+++ b/src/lib/corelib/tools/persistence.cpp
@@ -48,7 +48,7 @@
namespace qbs {
namespace Internal {
-static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-124";
+static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-125";
NoBuildGraphError::NoBuildGraphError(const QString &filePath)
: ErrorInfo(Tr::tr("Build graph not found for configuration '%1'. Expected location was '%2'.")
diff --git a/src/lib/corelib/tools/setupprojectparameters.cpp b/src/lib/corelib/tools/setupprojectparameters.cpp
index 39304d4c9..5600d9b0b 100644
--- a/src/lib/corelib/tools/setupprojectparameters.cpp
+++ b/src/lib/corelib/tools/setupprojectparameters.cpp
@@ -92,6 +92,7 @@ public:
bool logElapsedTime;
bool forceProbeExecution;
bool waitLockBuildGraph;
+ bool fallbackProviderEnabled = true;
SetupProjectParameters::RestoreBehavior restoreBehavior;
ErrorHandlingMode propertyCheckingMode;
ErrorHandlingMode productErrorMode;
@@ -505,6 +506,22 @@ void SetupProjectParameters::setWaitLockBuildGraph(bool wait)
}
/*!
+ * \brief Returns true if qbs should fall back to pkg-config if a dependency is not found.
+ */
+bool SetupProjectParameters::fallbackProviderEnabled() const
+{
+ return d->fallbackProviderEnabled;
+}
+
+/*!
+ * Controls whether to fall back to pkg-config if a dependency is not found.
+ */
+void SetupProjectParameters::setFallbackProviderEnabled(bool enable)
+{
+ d->fallbackProviderEnabled = enable;
+}
+
+/*!
* \brief Gets the environment used while resolving the project.
*/
QProcessEnvironment SetupProjectParameters::environment() const
diff --git a/src/lib/corelib/tools/setupprojectparameters.h b/src/lib/corelib/tools/setupprojectparameters.h
index fe7e3d487..10e4310cd 100644
--- a/src/lib/corelib/tools/setupprojectparameters.h
+++ b/src/lib/corelib/tools/setupprojectparameters.h
@@ -123,6 +123,9 @@ public:
bool waitLockBuildGraph() const;
void setWaitLockBuildGraph(bool wait);
+ bool fallbackProviderEnabled() const;
+ void setFallbackProviderEnabled(bool enable);
+
QProcessEnvironment environment() const;
void setEnvironment(const QProcessEnvironment &env);
QProcessEnvironment adjustedEnvironment() const;
diff --git a/src/lib/corelib/tools/stringconstants.h b/src/lib/corelib/tools/stringconstants.h
index 1a9356e49..cd41f3768 100644
--- a/src/lib/corelib/tools/stringconstants.h
+++ b/src/lib/corelib/tools/stringconstants.h
@@ -86,6 +86,7 @@ public:
static const QString &explicitlyDependsOnFromDependenciesProperty() {
return explicitlyDependsOnFromDependencies();
}
+ QBS_STRING_CONSTANT(enableFallbackProperty, "enableFallback")
static const QString &fileNameProperty() { return fileName(); }
static const QString &filePathProperty() { return filePath(); }
static const QString &filePathVar() { return filePath(); }
@@ -111,6 +112,7 @@ public:
QBS_STRING_CONSTANT(limitToSubProjectProperty, "limitToSubProject")
QBS_STRING_CONSTANT(minimumQbsVersionProperty, "minimumQbsVersion")
QBS_STRING_CONSTANT(moduleNameProperty, "moduleName")
+ QBS_STRING_CONSTANT(moduleProviders, "moduleProviders")
QBS_STRING_CONSTANT(multiplexByQbsPropertiesProperty, "multiplexByQbsProperties")
QBS_STRING_CONSTANT(multiplexConfigurationIdProperty, "multiplexConfigurationId")
QBS_STRING_CONSTANT(multiplexConfigurationIdsProperty, "multiplexConfigurationIds")