diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2017-02-23 16:42:37 +0100 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2019-01-23 14:35:02 +0000 |
commit | c2833b1a009bc7c382b30d94109b9b7a25a404a6 (patch) | |
tree | 5b960940919310f8867e503234ca6d4f4295bfbe /tests/auto/blackbox | |
parent | 1bfc30065371a3d28421e2e7af5653e1e78259f3 (diff) |
Introduce module providers
If a dependency is not found, we now search for a matching module
provider that can generate one for us.
We also provide a generic fall-back provider which uses pkg-config to
locate the dependency (but could be extended to incorporate other
methods in the future). This is the most important part of this change
for practical purposes, as it makes hundreds of popular libraries
available for use in qbs projects without users having to write any
boilerplate code.
In a future patch, a module provider could also be used to implement the
functionality of the qtprofilesetup library, relieving users of the need
to create a profile for building Qt applications.
[ChangeLog] The Depends item now falls back to pkg-config to locate
dependencies whose names do not correspond to a qbs module.
Fixes: QBS-1107
Change-Id: Ifd4f05c237cf58cd9fe707c3da648d3dbb33e82b
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
Diffstat (limited to 'tests/auto/blackbox')
8 files changed, 178 insertions, 0 deletions
diff --git a/tests/auto/blackbox/testdata/fallback-module-provider/fallback-module-provider.qbs b/tests/auto/blackbox/testdata/fallback-module-provider/fallback-module-provider.qbs new file mode 100644 index 000000000..a798e15b3 --- /dev/null +++ b/tests/auto/blackbox/testdata/fallback-module-provider/fallback-module-provider.qbs @@ -0,0 +1,8 @@ +CppApplication { + name: "p" + property bool fallbacksEnabled + Depends { name: "pkgconfig"; required: false } + Depends { name: "qbsmetatestmodule"; required: false; enableFallback: fallbacksEnabled } + property bool dummy: { console.info("pkg-config present: " + pkgconfig.present); } + files: "main.cpp" +} diff --git a/tests/auto/blackbox/testdata/fallback-module-provider/libdir/qbsmetatestmodule.pc b/tests/auto/blackbox/testdata/fallback-module-provider/libdir/qbsmetatestmodule.pc new file mode 100644 index 000000000..ae4daba89 --- /dev/null +++ b/tests/auto/blackbox/testdata/fallback-module-provider/libdir/qbsmetatestmodule.pc @@ -0,0 +1,5 @@ +Name: qbsmetatestmodule +Description: just a test +Version: 0.0.1 + +Cflags: -DTHE_MAGIC_DEFINE diff --git a/tests/auto/blackbox/testdata/fallback-module-provider/main.cpp b/tests/auto/blackbox/testdata/fallback-module-provider/main.cpp new file mode 100644 index 000000000..442b755bf --- /dev/null +++ b/tests/auto/blackbox/testdata/fallback-module-provider/main.cpp @@ -0,0 +1,5 @@ +#ifndef THE_MAGIC_DEFINE +#error "missing the magic define" +#endif + +int main() {} diff --git a/tests/auto/blackbox/testdata/module-providers/main.cpp b/tests/auto/blackbox/testdata/module-providers/main.cpp new file mode 100644 index 000000000..9cd29b1fe --- /dev/null +++ b/tests/auto/blackbox/testdata/module-providers/main.cpp @@ -0,0 +1,6 @@ +#include <iostream> + +int main() +{ + std::cout << "The letters are " << LETTER1 << " and " << LETTER2 << std::endl; +} diff --git a/tests/auto/blackbox/testdata/module-providers/module-providers.qbs b/tests/auto/blackbox/testdata/module-providers/module-providers.qbs new file mode 100644 index 000000000..d1ff79269 --- /dev/null +++ b/tests/auto/blackbox/testdata/module-providers/module-providers.qbs @@ -0,0 +1,20 @@ +Project { + CppApplication { + name: "app1" + Depends { name: "mygenerator.module1" } + Depends { name: "mygenerator.module2" } + moduleProviders.mygenerator.chooseLettersFrom: "beginning" + files: "main.cpp" + } + CppApplication { + name: "app2" + Depends { name: "mygenerator.module1" } + Depends { name: "mygenerator.module2" } + Profile { + name: "myProfile" + moduleProviders.mygenerator.chooseLettersFrom: "end" + } + qbs.profile: "myProfile" + files: "main.cpp" + } +} diff --git a/tests/auto/blackbox/testdata/module-providers/module-providers/mygenerator/provider.qbs b/tests/auto/blackbox/testdata/module-providers/module-providers/mygenerator/provider.qbs new file mode 100644 index 000000000..dae02c03a --- /dev/null +++ b/tests/auto/blackbox/testdata/module-providers/module-providers/mygenerator/provider.qbs @@ -0,0 +1,31 @@ +import qbs.File; +import qbs.FileInfo; +import qbs.TextFile; + +ModuleProvider { + property string chooseLettersFrom + relativeSearchPaths: { + console.info("Running setup script for " + name); + var startAtBeginning = chooseLettersFrom === "beginning"; + var moduleBaseDir = FileInfo.joinPaths(outputBaseDir, "modules", "mygenerator"); + var module1Dir = FileInfo.joinPaths(moduleBaseDir, "module1"); + File.makePath(module1Dir); + var module1 = new TextFile(FileInfo.joinPaths(module1Dir, "module1.qbs"), TextFile.WriteOnly); + module1.writeLine("Module {"); + module1.writeLine(" Depends { name: 'cpp' }"); + module1.writeLine(" cpp.defines: 'LETTER1=" + (startAtBeginning ? "\\\'A\\\'" : "\\\'Z\\\'") + + "'"); + module1.writeLine("}"); + module1.close(); + var module2Dir = FileInfo.joinPaths(moduleBaseDir, "module2"); + File.makePath(module2Dir); + var module2 = new TextFile(FileInfo.joinPaths(module2Dir, "module2.qbs"), TextFile.WriteOnly); + module2.writeLine("Module {"); + module2.writeLine(" Depends { name: 'cpp' }"); + module2.writeLine(" cpp.defines: 'LETTER2=" + (startAtBeginning ? "\\\'B\\\'" : "\\\'Y\\\'") + + "'"); + module2.writeLine("}"); + module2.close(); + return ""; + } +} diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index fbcd16eb8..82f29f320 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -6310,6 +6310,106 @@ void TestBlackbox::maximumCxxLanguageVersion() m_qbsStdout.constData()); } +void TestBlackbox::moduleProviders() +{ + QDir::setCurrent(testDataDir + "/module-providers"); + + // Resolving in dry-run mode must not leave any data behind. + QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("-n"))), 0); + QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 2); + QVERIFY(!QFile::exists(relativeBuildDir())); + + // Initial build. + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); + QVERIFY(QFile::exists(relativeBuildDir())); + QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 2); + QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are Z and Y"), m_qbsStdout.constData()); + + // Rebuild with overridden module provider config. The output for product 2 must change, + // but no setup script must be re-run, because both config values have already been + // handled in the first run. + const QStringList resolveArgs("moduleProviders.mygenerator.chooseLettersFrom:beginning"); + QCOMPARE(runQbs(QbsRunParameters("resolve", resolveArgs)), 0); + QVERIFY2(!m_qbsStdout.contains("Running setup script"), m_qbsStdout.constData()); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); + + // Forcing Probe execution triggers a re-run of the setup script. But only once, + // because the module provider config is the same now. + QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList(resolveArgs) + << "--force-probe-execution")), 0); + QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 1); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); + + // Now re-run without the module provider config override. Again, the setup script must + // run once, for the config value that was not present in the last run. + QCOMPARE(runQbs(QbsRunParameters("resolve")), 0); + QCOMPARE(m_qbsStdout.count("Running setup script for mygenerator"), 1); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app1"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are A and B"), m_qbsStdout.constData()); + QCOMPARE(runQbs(QbsRunParameters("run", QStringList{"-p", "app2"})), 0); + QVERIFY2(m_qbsStdout.contains("The letters are Z and Y"), m_qbsStdout.constData()); +} + +void TestBlackbox::fallbackModuleProvider_data() +{ + QTest::addColumn<bool>("fallbacksEnabledGlobally"); + QTest::addColumn<bool>("fallbacksEnabledInProduct"); + QTest::addColumn<QStringList>("pkgConfigLibDirs"); + QTest::addColumn<bool>("successExpected"); + QTest::newRow("without custom lib dir, fallbacks disabled globally and in product") + << false << false << QStringList() << false; + QTest::newRow("without custom lib dir, fallbacks disabled globally, enabled in product") + << false << true << QStringList() << false; + QTest::newRow("without custom lib dir, fallbacks enabled globally, disabled in product") + << true << false << QStringList() << false; + QTest::newRow("without custom lib dir, fallbacks enabled globally and in product") + << true << true << QStringList() << false; + QTest::newRow("with custom lib dir, fallbacks disabled globally and in product") + << false << false << QStringList(testDataDir + "/fallback-module-provider/libdir") + << false; + QTest::newRow("with custom lib dir, fallbacks disabled globally, enabled in product") + << false << true << QStringList(testDataDir + "/fallback-module-provider/libdir") + << false; + QTest::newRow("with custom lib dir, fallbacks enabled globally, disabled in product") + << true << false << QStringList(testDataDir + "/fallback-module-provider/libdir") + << false; + QTest::newRow("with custom lib dir, fallbacks enabled globally and in product") + << true << true << QStringList(testDataDir + "/fallback-module-provider/libdir") + << true; +} + +void TestBlackbox::fallbackModuleProvider() +{ + QFETCH(bool, fallbacksEnabledInProduct); + QFETCH(bool, fallbacksEnabledGlobally); + QFETCH(QStringList, pkgConfigLibDirs); + QFETCH(bool, successExpected); + QDir::setCurrent(testDataDir + "/fallback-module-provider"); + static const auto b2s = [](bool b) { return QString(b ? "true" : "false"); }; + QbsRunParameters resolveParams("resolve", + QStringList{"modules.pkgconfig.libDirs:" + pkgConfigLibDirs.join(','), + "products.p.fallbacksEnabled:" + b2s(fallbacksEnabledInProduct)}); + if (!fallbacksEnabledGlobally) + resolveParams.arguments << "--no-fallback-module-provider"; + QCOMPARE(runQbs(resolveParams), 0); + const bool pkgConfigPresent = m_qbsStdout.contains("pkg-config present: true"); + const bool pkgConfigNotPresent = m_qbsStdout.contains("pkg-config present: false"); + QVERIFY(pkgConfigPresent != pkgConfigNotPresent); + if (pkgConfigNotPresent) + successExpected = false; + QbsRunParameters buildParams; + buildParams.expectFailure = !successExpected; + QCOMPARE(runQbs(buildParams) == 0, successExpected); +} + void TestBlackbox::minimumSystemVersion() { rmDirR(relativeBuildDir()); diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h index 313ad5d40..624cd5fbb 100644 --- a/tests/auto/blackbox/tst_blackbox.h +++ b/tests/auto/blackbox/tst_blackbox.h @@ -174,6 +174,9 @@ private slots: void makefileGenerator(); void maximumCLanguageVersion(); void maximumCxxLanguageVersion(); + void moduleProviders(); + void fallbackModuleProvider_data(); + void fallbackModuleProvider(); void minimumSystemVersion(); void minimumSystemVersion_data(); void missingBuildGraph(); |