summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@digia.com>2013-07-18 13:45:57 +0200
committerChristian Kandeler <christian.kandeler@digia.com>2013-07-19 10:40:14 +0200
commit8a059586cc109f97b2cfc456cb4262009191ce2b (patch)
tree8773303ec78580e1225e991374f2cf80b2e7cd8b
parente17ce94d5191411f939f9c9599f15db089a20fa1 (diff)
downloadqbs-8a059586cc109f97b2cfc456cb4262009191ce2b.tar.gz
split overridden values off the build configuration
Property values in profiles now serve as default values for module values. Property values given on the command line override properties that are specified in files. This way it is possible to specify a property value in a profile but override it in a file or on the command line. The hierarchy is profile < file < command line. Change-Id: I786ef5a215312779ed1b79ed64f856b82c612403 Reviewed-by: Christian Kandeler <christian.kandeler@digia.com>
-rw-r--r--src/app/qbs/commandlinefrontend.cpp1
-rw-r--r--src/lib/language/loader.cpp4
-rw-r--r--src/lib/language/moduleloader.cpp34
-rw-r--r--src/lib/language/moduleloader.h10
-rw-r--r--src/lib/language/projectresolver.cpp9
-rw-r--r--src/lib/language/projectresolver.h3
-rw-r--r--src/lib/language/testdata/modules/dummy/dummy.qbs1
-rw-r--r--src/lib/language/testdata/profilevaluesandoverriddenvalues.qbs11
-rw-r--r--src/lib/language/tst_language.cpp40
-rw-r--r--src/lib/language/tst_language.h1
-rw-r--r--src/lib/tools/setupprojectparameters.cpp67
-rw-r--r--src/lib/tools/setupprojectparameters.h4
12 files changed, 149 insertions, 36 deletions
diff --git a/src/app/qbs/commandlinefrontend.cpp b/src/app/qbs/commandlinefrontend.cpp
index 95a3b56f2..02768aa21 100644
--- a/src/app/qbs/commandlinefrontend.cpp
+++ b/src/app/qbs/commandlinefrontend.cpp
@@ -109,6 +109,7 @@ void CommandLineFrontend::start()
if (!m_parser.buildBeforeInstalling())
params.setRestoreBehavior(SetupProjectParameters::RestoreOnly);
foreach (const QVariantMap &buildConfig, m_parser.buildConfigurations()) {
+ params.setOverriddenValues(buildConfig);
params.setBuildConfiguration(buildConfig);
const ErrorInfo err = params.expandBuildConfiguration(m_settings);
if (err.hasError())
diff --git a/src/lib/language/loader.cpp b/src/lib/language/loader.cpp
index 520db3584..2e3fd90a9 100644
--- a/src/lib/language/loader.cpp
+++ b/src/lib/language/loader.cpp
@@ -101,10 +101,12 @@ TopLevelProjectPtr Loader::loadProject(const SetupProjectParameters &parameters)
ModuleLoaderResult loadResult
= m_moduleLoader->load(parameters.projectFilePath(),
+ parameters.overriddenValuesTree(),
parameters.buildConfigurationTree(),
true);
const TopLevelProjectPtr project = m_projectResolver->resolve(loadResult,
- parameters.buildRoot(), parameters.buildConfigurationTree());
+ parameters.buildRoot(), parameters.overriddenValuesTree(),
+ parameters.buildConfigurationTree());
// E.g. if the top-level project is disabled.
if (m_progressObserver)
diff --git a/src/lib/language/moduleloader.cpp b/src/lib/language/moduleloader.cpp
index fda92d2e8..a2541717c 100644
--- a/src/lib/language/moduleloader.cpp
+++ b/src/lib/language/moduleloader.cpp
@@ -91,12 +91,14 @@ void ModuleLoader::setSearchPaths(const QStringList &searchPaths)
m_moduleSearchPaths += FileInfo::resolvePath(path, moduleSearchSubDir);
}
-ModuleLoaderResult ModuleLoader::load(const QString &filePath, const QVariantMap &userProperties,
- bool wrapWithProjectItem)
+ModuleLoaderResult ModuleLoader::load(const QString &filePath,
+ const QVariantMap &overriddenProperties, const QVariantMap &buildConfigProperties,
+ bool wrapWithProjectItem)
{
if (m_logger.traceEnabled())
m_logger.qbsTrace() << "[MODLDR] load" << filePath;
- m_userProperties = userProperties;
+ m_overriddenProperties = overriddenProperties;
+ m_buildConfigProperties = buildConfigProperties;
ModuleLoaderResult result;
m_pool = result.itemPool.data();
@@ -132,7 +134,7 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult, Item *item)
ProductContext dummyProductContext;
dummyProductContext.project = &projectContext;
loadBaseModule(&dummyProductContext, item);
- overrideItemProperties(item, QLatin1String("project"), m_userProperties);
+ overrideItemProperties(item, QLatin1String("project"), m_overriddenProperties);
foreach (Item *child, item->children()) {
child->setScope(projectContext.scope);
@@ -547,6 +549,7 @@ Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext,
searchPaths.append(m_moduleSearchPaths);
bool triedToLoadModule = moduleName.count() > 1;
+ const QString fullName = fullModuleName(moduleName);
foreach (const QString &path, searchPaths) {
const QString dirPath = findExistingModulePath(path, moduleName);
if (dirPath.isEmpty())
@@ -561,7 +564,7 @@ Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext,
}
foreach (const QString &filePath, moduleFileNames) {
triedToLoadModule = true;
- Item *module = loadModuleFile(productContext,
+ Item *module = loadModuleFile(productContext, fullName,
moduleName.count() == 1
&& moduleName.first() == QLatin1String("qbs"),
filePath);
@@ -571,14 +574,14 @@ Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext,
}
if (Q_UNLIKELY(triedToLoadModule))
- throw ErrorInfo(Tr::tr("Module %1 could not be loaded.").arg(fullModuleName(moduleName)),
+ throw ErrorInfo(Tr::tr("Module %1 could not be loaded.").arg(fullName),
dependsItemLocation);
return 0;
}
-Item *ModuleLoader::loadModuleFile(ProductContext *productContext, bool isBaseModule,
- const QString &filePath)
+Item *ModuleLoader::loadModuleFile(ProductContext *productContext, const QString &fullModuleName,
+ bool isBaseModule, const QString &filePath)
{
checkCancelation();
Item *module = productContext->moduleItemCache.value(filePath);
@@ -606,6 +609,17 @@ Item *ModuleLoader::loadModuleFile(ProductContext *productContext, bool isBaseMo
return 0;
}
+ // Module properties that are defined in the profile are used as default values.
+ const QVariantMap profileModuleProperties
+ = m_buildConfigProperties.value(fullModuleName).toMap();
+ for (QVariantMap::const_iterator vmit = profileModuleProperties.begin();
+ vmit != profileModuleProperties.end(); ++vmit)
+ {
+ if (Q_UNLIKELY(!module->hasProperty(vmit.key())))
+ throw ErrorInfo(Tr::tr("Unknown property: %1.%2").arg(fullModuleName, vmit.key()));
+ module->setProperty(vmit.key(), VariantValue::create(vmit.value()));
+ }
+
productContext->moduleItemCache.insert(filePath, module);
productContext->project->moduleItemCache.insert(filePath, module);
return module;
@@ -760,7 +774,7 @@ void ModuleLoader::instantiateModule(ProductContext *productContext, Item *insta
}
// override module properties given on the command line
- const QVariantMap userModuleProperties = m_userProperties.value(fullName).toMap();
+ const QVariantMap userModuleProperties = m_overriddenProperties.value(fullName).toMap();
for (QVariantMap::const_iterator vmit = userModuleProperties.begin();
vmit != userModuleProperties.end(); ++vmit) {
if (Q_UNLIKELY(!moduleInstance->hasProperty(vmit.key()))) {
@@ -840,7 +854,7 @@ void ModuleLoader::checkCancelation() const
{
if (m_progressObserver && m_progressObserver->canceled()) {
throw ErrorInfo(Tr::tr("Project resolving canceled for configuration %1.")
- .arg(TopLevelProject::deriveId(m_userProperties)));
+ .arg(TopLevelProject::deriveId(m_buildConfigProperties)));
}
}
diff --git a/src/lib/language/moduleloader.h b/src/lib/language/moduleloader.h
index 2d936a643..6c196c414 100644
--- a/src/lib/language/moduleloader.h
+++ b/src/lib/language/moduleloader.h
@@ -98,8 +98,9 @@ public:
void setSearchPaths(const QStringList &searchPaths);
Evaluator *evaluator() const { return m_evaluator; }
- ModuleLoaderResult load(const QString &filePath, const QVariantMap &userProperties,
- bool wrapWithProjectItem = false);
+ ModuleLoaderResult load(const QString &filePath,
+ const QVariantMap &overriddenProperties, const QVariantMap &buildConfigProperties,
+ bool wrapWithProjectItem = false);
static QString fullModuleName(const QStringList &moduleName);
static void overrideItemProperties(Item *item, const QString &buildConfigKey,
@@ -163,7 +164,7 @@ private:
Item *searchAndLoadModuleFile(ProductContext *productContext,
const CodeLocation &dependsItemLocation, const QStringList &moduleName,
const QStringList &extraSearchPaths);
- Item *loadModuleFile(ProductContext *productContext, bool isBaseModule, const QString &filePath);
+ Item *loadModuleFile(ProductContext *productContext, const QString &fullModuleName, bool isBaseModule, const QString &filePath);
void loadBaseModule(ProductContext *productContext, Item *item);
void instantiateModule(ProductContext *productContext, Item *instanceScope, Item *moduleInstance, Item *modulePrototype, const QStringList &moduleName);
void createChildInstances(ProductContext *productContext, Item *instance,
@@ -188,7 +189,8 @@ private:
Evaluator *m_evaluator;
QStringList m_moduleSearchPaths;
QMap<QString, QStringList> m_moduleDirListCache;
- QVariantMap m_userProperties;
+ QVariantMap m_overriddenProperties;
+ QVariantMap m_buildConfigProperties;
};
} // namespace Internal
diff --git a/src/lib/language/projectresolver.cpp b/src/lib/language/projectresolver.cpp
index 231dab1c2..321877142 100644
--- a/src/lib/language/projectresolver.cpp
+++ b/src/lib/language/projectresolver.cpp
@@ -79,8 +79,8 @@ void ProjectResolver::setProgressObserver(ProgressObserver *observer)
}
TopLevelProjectPtr ProjectResolver::resolve(ModuleLoaderResult &loadResult,
- const QString &buildRoot,
- const QVariantMap &buildConfiguration)
+ const QString &buildRoot, const QVariantMap &overriddenProperties,
+ const QVariantMap &buildConfiguration)
{
QBS_ASSERT(FileInfo::isAbsolute(buildRoot), return TopLevelProjectPtr());
if (m_logger.traceEnabled())
@@ -89,6 +89,7 @@ TopLevelProjectPtr ProjectResolver::resolve(ModuleLoaderResult &loadResult,
ProjectContext projectContext;
projectContext.loadResult = &loadResult;
m_buildRoot = buildRoot;
+ m_overriddenProperties = overriddenProperties;
m_buildConfiguration = buildConfiguration;
m_productContext = 0;
m_moduleContext = 0;
@@ -256,7 +257,7 @@ void ProjectResolver::resolveProduct(Item *item, ProjectContext *projectContext)
item->setProperty("name", VariantValue::create(product->name));
}
m_logger.qbsTrace() << "[PR] resolveProduct " << product->name;
- ModuleLoader::overrideItemProperties(item, product->name, m_buildConfiguration);
+ ModuleLoader::overrideItemProperties(item, product->name, m_overriddenProperties);
m_productsByName.insert(product->name, product);
product->enabled = m_evaluator->boolValue(item, QLatin1String("condition"), true);
product->additionalFileTags
@@ -845,6 +846,8 @@ QVariantMap ProjectResolver::evaluateProperties(Item *item,
}
case Value::VariantValueType:
{
+ if (result.contains(it.key()))
+ break;
VariantValuePtr vvp = it.value().staticCast<VariantValue>();
result[it.key()] = vvp->value();
break;
diff --git a/src/lib/language/projectresolver.h b/src/lib/language/projectresolver.h
index b97633e50..d7d3fc4ab 100644
--- a/src/lib/language/projectresolver.h
+++ b/src/lib/language/projectresolver.h
@@ -57,7 +57,7 @@ public:
void setProgressObserver(ProgressObserver *observer);
TopLevelProjectPtr resolve(ModuleLoaderResult &loadResult, const QString &buildRoot,
- const QVariantMap &buildConfiguration);
+ const QVariantMap &overriddenProperties, const QVariantMap &buildConfiguration);
private:
struct ProjectContext
@@ -118,6 +118,7 @@ private:
ScriptEngine *m_engine;
ProgressObserver *m_progressObserver;
QString m_buildRoot;
+ QVariantMap m_overriddenProperties;
QVariantMap m_buildConfiguration;
ProductContext *m_productContext;
ModuleContext *m_moduleContext;
diff --git a/src/lib/language/testdata/modules/dummy/dummy.qbs b/src/lib/language/testdata/modules/dummy/dummy.qbs
index 55a410ade..031d6425f 100644
--- a/src/lib/language/testdata/modules/dummy/dummy.qbs
+++ b/src/lib/language/testdata/modules/dummy/dummy.qbs
@@ -3,5 +3,6 @@ import "dummy_base.qbs" as DummyBase
DummyBase {
property stringList defines
property pathList includePaths
+ property stringList cFlags
property stringList cxxFlags
}
diff --git a/src/lib/language/testdata/profilevaluesandoverriddenvalues.qbs b/src/lib/language/testdata/profilevaluesandoverriddenvalues.qbs
new file mode 100644
index 000000000..d3a18bcb5
--- /dev/null
+++ b/src/lib/language/testdata/profilevaluesandoverriddenvalues.qbs
@@ -0,0 +1,11 @@
+import qbs 1.0
+
+Project {
+ Application {
+ name: "product1"
+ Depends { name: "dummy" }
+ // dummy.cxxFlags is set via profile and is not overridden
+ dummy.defines: ["IN_FILE"] // set in profile, overridden in file
+ dummy.cFlags: ["IN_FILE"] // set in profile, overridden on command line
+ }
+}
diff --git a/src/lib/language/tst_language.cpp b/src/lib/language/tst_language.cpp
index 225892070..15d426eec 100644
--- a/src/lib/language/tst_language.cpp
+++ b/src/lib/language/tst_language.cpp
@@ -895,6 +895,46 @@ void TestLanguage::pathProperties()
QCOMPARE(exceptionCaught, false);
}
+void TestLanguage::profileValuesAndOverriddenValues()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters parameters = defaultParameters;
+ QVariantMap buildConfig = parameters.buildConfiguration();
+ buildConfig.insert("dummy.defines", "IN_PROFILE");
+ buildConfig.insert("dummy.cFlags", "IN_PROFILE");
+ buildConfig.insert("dummy.cxxFlags", "IN_PROFILE");
+ parameters.setBuildConfiguration(buildConfig);
+ QVariantMap overriddenValues;
+ overriddenValues.insert("dummy.cFlags", "OVERRIDDEN");
+ parameters.setOverriddenValues(overriddenValues);
+ parameters.setProjectFilePath(testProject("profilevaluesandoverriddenvalues.qbs"));
+ project = loader->loadProject(parameters);
+ QVERIFY(project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value("product1");
+ QVERIFY(product);
+ PropertyFinder pf;
+ QVariantList values;
+ values = pf.propertyValues(product->properties->value(),
+ "dummy", "cxxFlags", PropertyFinder::DoMergeLists);
+ QCOMPARE(values.length(), 1);
+ QCOMPARE(values.first().toString(), QString("IN_PROFILE"));
+ values = pf.propertyValues(product->properties->value(),
+ "dummy", "defines", PropertyFinder::DoMergeLists);
+ QCOMPARE(values.length(), 1);
+ QCOMPARE(values.first().toString(), QString("IN_FILE"));
+ values = pf.propertyValues(product->properties->value(),
+ "dummy", "cFlags", PropertyFinder::DoMergeLists);
+ QCOMPARE(values.length(), 1);
+ QCOMPARE(values.first().toString(), QString("OVERRIDDEN"));
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
void TestLanguage::productConditions()
{
bool exceptionCaught = false;
diff --git a/src/lib/language/tst_language.h b/src/lib/language/tst_language.h
index e820c3224..67193308b 100644
--- a/src/lib/language/tst_language.h
+++ b/src/lib/language/tst_language.h
@@ -92,6 +92,7 @@ private slots:
void modules();
void outerInGroup();
void pathProperties();
+ void profileValuesAndOverriddenValues();
void productConditions();
void productDirectories();
void propertiesBlocks_data();
diff --git a/src/lib/tools/setupprojectparameters.cpp b/src/lib/tools/setupprojectparameters.cpp
index a0d8df6c8..34e8a2268 100644
--- a/src/lib/tools/setupprojectparameters.cpp
+++ b/src/lib/tools/setupprojectparameters.cpp
@@ -58,7 +58,9 @@ public:
QString buildRoot;
QStringList searchPaths;
QStringList pluginPaths;
+ QVariantMap overriddenValues;
QVariantMap buildConfiguration;
+ mutable QVariantMap overriddenValuesTree;
mutable QVariantMap buildConfigurationTree;
bool ignoreDifferentProjectFilePath;
bool dryRun;
@@ -162,6 +164,52 @@ void SetupProjectParameters::setPluginPaths(const QStringList &pluginPaths)
}
/*!
+ * Returns the overridden values of the build configuration.
+ */
+QVariantMap SetupProjectParameters::overriddenValues() const
+{
+ return d->overriddenValues;
+}
+
+/*!
+ * Set the overridden values of the build configuration.
+ */
+void SetupProjectParameters::setOverriddenValues(const QVariantMap &values)
+{
+ // warn if somebody tries to set a build configuration tree:
+ for (QVariantMap::const_iterator i = values.constBegin();
+ i != values.constEnd(); ++i) {
+ QBS_ASSERT(i.value().type() != QVariant::Map, return);
+ }
+ d->overriddenValues = values;
+ d->overriddenValuesTree.clear();
+}
+
+static void provideValuesTree(const QVariantMap &values, QVariantMap *valueTree)
+{
+ if (!valueTree->isEmpty() || values.isEmpty())
+ return;
+
+ valueTree->clear();
+ for (QVariantMap::const_iterator it = values.constBegin(); it != values.constEnd(); ++it) {
+ QStringList nameElements = it.key().split(QLatin1Char('.'));
+ if (nameElements.count() > 2) { // ### workaround for submodules being represented internally as a single module of name "module/submodule" rather than two nested modules "module" and "submodule"
+ const QStringList allButLast = nameElements.mid(0, nameElements.length() - 1);
+ QStringList newElements(allButLast.join(QLatin1String("/")));
+ newElements.append(nameElements.last());
+ nameElements = newElements;
+ }
+ Internal::setConfigProperty(*valueTree, nameElements, it.value());
+ }
+}
+
+QVariantMap SetupProjectParameters::overriddenValuesTree() const
+{
+ provideValuesTree(d->overriddenValues, &d->overriddenValuesTree);
+ return d->overriddenValuesTree;
+}
+
+/*!
* \brief The collection of properties to use for resolving the project.
*/
QVariantMap SetupProjectParameters::buildConfiguration() const
@@ -192,23 +240,8 @@ void SetupProjectParameters::setBuildConfiguration(const QVariantMap &buildConfi
*/
QVariantMap SetupProjectParameters::buildConfigurationTree() const
{
- if (!d->buildConfigurationTree.isEmpty() && !d->buildConfiguration.isEmpty())
- return d->buildConfigurationTree;
-
- QVariantMap result;
- foreach (const QString &property, d->buildConfiguration.keys()) {
- QStringList nameElements = property.split('.');
- if (nameElements.count() > 2) { // ### workaround for submodules being represented internally as a single module of name "module/submodule" rather than two nested modules "module" and "submodule"
- QStringList allButLast = nameElements;
- allButLast.removeLast();
- QStringList newElements(allButLast.join("/"));
- newElements.append(nameElements.last());
- nameElements = newElements;
- }
- Internal::setConfigProperty(result, nameElements, d->buildConfiguration.value(property));
- }
- d->buildConfigurationTree = result;
- return result;
+ provideValuesTree(d->buildConfiguration, &d->buildConfigurationTree);
+ return d->buildConfigurationTree;
}
/*!
diff --git a/src/lib/tools/setupprojectparameters.h b/src/lib/tools/setupprojectparameters.h
index c262930f6..77e09ef9a 100644
--- a/src/lib/tools/setupprojectparameters.h
+++ b/src/lib/tools/setupprojectparameters.h
@@ -65,6 +65,10 @@ public:
QStringList pluginPaths() const;
void setPluginPaths(const QStringList &pluginPaths);
+ QVariantMap overriddenValues() const;
+ void setOverriddenValues(const QVariantMap &values);
+ QVariantMap overriddenValuesTree() const;
+
QVariantMap buildConfiguration() const;
void setBuildConfiguration(const QVariantMap &buildConfiguration);
QVariantMap buildConfigurationTree() const;