aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Komissarov <abbapoh@gmail.com>2020-04-16 13:07:28 +0200
committerIvan Komissarov <abbapoh@gmail.com>2020-04-16 13:07:28 +0200
commit04240d47225f06eb36df4eec2270813a78a44344 (patch)
tree06dc4ad265583413912a23ccfaaf1fdee04ed2ac
parentebda20ac2677085d79f5a6fab31a282cbcd958d5 (diff)
parent99d009c0ae5558d86159206e7a27d4ed7e8ade28 (diff)
Merge branch 'master' into wip/ci-ios
-rw-r--r--.clang-tidy66
-rw-r--r--.travis.yml140
-rw-r--r--CONTRIBUTING.md102
-rw-r--r--README8
-rw-r--r--README.md36
-rw-r--r--VERSION2
-rw-r--r--changelogs/changes-1.15.0.md44
-rw-r--r--changelogs/changes-1.16.0.md126
-rw-r--r--doc/appendix/json-api.qdoc5
-rw-r--r--doc/doc.qbs14
-rwxr-xr-xdoc/fix-qmlimports.py6
-rw-r--r--doc/howtos.qdoc179
-rw-r--r--doc/qbs.qdoc53
-rw-r--r--doc/reference/commands.qdoc4
-rw-r--r--doc/reference/items/convenience/application.qdoc33
-rw-r--r--doc/reference/items/convenience/autotestrunner.qdoc34
-rw-r--r--doc/reference/items/convenience/cppapplication.qdoc4
-rw-r--r--doc/reference/items/convenience/dynamiclibrary.qdoc52
-rw-r--r--doc/reference/items/convenience/javajarfile.qdoc2
-rw-r--r--doc/reference/items/convenience/library.qdoc130
-rw-r--r--doc/reference/items/convenience/loadablemodule.qdoc4
-rw-r--r--doc/reference/items/convenience/qtapplication.qdoc2
-rw-r--r--doc/reference/items/convenience/staticlibrary.qdoc26
-rw-r--r--doc/reference/items/language/export.qdoc37
-rw-r--r--doc/reference/items/probe/conanfile-probe.qdoc250
-rw-r--r--doc/reference/items/probe/library-probe.qdoc62
-rw-r--r--doc/reference/items/probe/path-probe.qdoc20
-rw-r--r--doc/reference/modules/android-sdk-module.qdoc4
-rw-r--r--doc/reference/modules/autotest-module.qdoc11
-rw-r--r--doc/reference/modules/cpp-module.qdoc43
-rw-r--r--doc/reference/modules/freedesktop-module.qdoc141
-rw-r--r--doc/reference/modules/qbs-module.qdoc271
-rw-r--r--doc/reference/modules/qt-core-module.qdoc28
-rw-r--r--doc/reference/modules/qt-qml-module.qdoc71
-rw-r--r--docker-compose.yml47
-rw-r--r--docker/bionic/Dockerfile40
-rw-r--r--docker/bionic/test-android.Dockerfile107
-rw-r--r--docker/docker.qbs39
-rw-r--r--docker/stretch/Dockerfile73
-rw-r--r--docker/windowsservercore/Dockerfile78
-rw-r--r--docker/windowsservercore/build-qt.bat23
-rw-r--r--examples/app-and-lib/app/main.cpp2
-rw-r--r--examples/app-and-lib/lib/lib.cpp2
-rw-r--r--examples/baremetal/at90can128olimex/redblink/README.md2
-rw-r--r--examples/baremetal/cc2540usbdongle/greenblink/system.h3
-rw-r--r--examples/baremetal/msp430f5529/redblink/README.md2
-rw-r--r--examples/baremetal/stm32f4discovery/blueblink/blueblink.qbs2
-rw-r--r--examples/cocoa-touch-application/CocoaTouchApplication.qbs5
-rw-r--r--examples/cocoa-touch-application/CocoaTouchApplication/MasterViewController.m2
-rw-r--r--examples/code-generator/code-generator.qbs4
-rw-r--r--examples/collidingmice/main.cpp2
-rw-r--r--examples/collidingmice/mouse.cpp5
-rw-r--r--examples/collidingmice/mouse.h8
-rw-r--r--examples/grpc/client.cpp2
-rw-r--r--examples/grpc/ping-pong-grpc.qbs12
-rw-r--r--examples/helloworld-complex/hello.qbs2
-rw-r--r--examples/helloworld-complex/src/main.cpp6
-rw-r--r--examples/helloworld-qt/main.cpp4
-rw-r--r--examples/protobuf/cpp/addressbook.qbs2
-rw-r--r--examples/protobuf/cpp/main.cpp2
-rw-r--r--qbs-resources/modules/docker/docker.qbs50
-rw-r--r--qbs.pro5
-rw-r--r--qbs.qbs9
-rwxr-xr-xscripts/build-qbs-with-qbs.sh23
-rwxr-xr-xscripts/build-qbs-with-qmake.sh3
-rw-r--r--scripts/make-release-archives.bat1
-rwxr-xr-xscripts/run-analyzer.sh45
-rwxr-xr-xscripts/test-qt-for-android.sh (renamed from docker/stretch/entrypoint.sh)59
-rw-r--r--share/qbs/imports/qbs/ModUtils/utils.js2
-rw-r--r--share/qbs/imports/qbs/Probes/ClBinaryProbe.qbs71
-rw-r--r--share/qbs/imports/qbs/Probes/ClangClBinaryProbe.qbs73
-rw-r--r--share/qbs/imports/qbs/Probes/ClangClProbe.qbs8
-rw-r--r--share/qbs/imports/qbs/Probes/ConanfileProbe.qbs130
-rw-r--r--share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs35
-rw-r--r--share/qbs/imports/qbs/Probes/LibraryProbe.qbs33
-rw-r--r--share/qbs/imports/qbs/Probes/NpmProbe.qbs26
-rw-r--r--share/qbs/imports/qbs/Probes/PathProbe.qbs12
-rw-r--r--share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs23
-rw-r--r--share/qbs/imports/qbs/base/Application.qbs8
-rw-r--r--share/qbs/imports/qbs/base/DynamicLibrary.qbs20
-rw-r--r--share/qbs/imports/qbs/base/Library.qbs53
-rw-r--r--share/qbs/imports/qbs/base/NativeBinary.qbs3
-rw-r--r--share/qbs/imports/qbs/base/QtApplication.qbs4
-rw-r--r--share/qbs/imports/qbs/base/QtGuiApplication.qbs2
-rw-r--r--share/qbs/imports/qbs/base/StaticLibrary.qbs9
-rw-r--r--share/qbs/module-providers/Qt/setup-qt.js254
-rw-r--r--share/qbs/module-providers/Qt/templates/android_support.qbs150
-rw-r--r--share/qbs/module-providers/Qt/templates/core.qbs31
-rw-r--r--share/qbs/module-providers/Qt/templates/moc.js18
-rw-r--r--share/qbs/module-providers/Qt/templates/qml.qbs70
-rw-r--r--share/qbs/module-providers/Qt/templates/quick.qbs2
-rw-r--r--share/qbs/modules/Android/sdk/sdk.qbs43
-rw-r--r--share/qbs/modules/Android/sdk/utils.js9
-rw-r--r--share/qbs/modules/bundle/BundleModule.qbs91
-rw-r--r--share/qbs/modules/cpp/CppModule.qbs15
-rw-r--r--share/qbs/modules/cpp/DarwinGCC.qbs2
-rw-r--r--share/qbs/modules/cpp/GenericGCC.qbs15
-rw-r--r--share/qbs/modules/cpp/UnixGCC.qbs2
-rw-r--r--share/qbs/modules/cpp/android-gcc.qbs2
-rw-r--r--share/qbs/modules/cpp/freebsd-gcc.qbs2
-rw-r--r--share/qbs/modules/cpp/iar.js301
-rw-r--r--share/qbs/modules/cpp/keil.js400
-rw-r--r--share/qbs/modules/cpp/keil.qbs1
-rw-r--r--share/qbs/modules/cpp/msvc.js158
-rw-r--r--share/qbs/modules/cpp/sdcc.js22
-rw-r--r--share/qbs/modules/cpp/sdcc.qbs2
-rw-r--r--share/qbs/modules/cpp/windows-clang-cl.qbs19
-rw-r--r--share/qbs/modules/cpp/windows-mingw.qbs2
-rw-r--r--share/qbs/modules/cpp/windows-msvc.qbs3
-rw-r--r--share/qbs/modules/freedesktop/FreeDesktop.qbs124
-rw-r--r--share/qbs/modules/freedesktop/freedesktop.js69
-rw-r--r--share/qbs/modules/java/utils.js2
-rw-r--r--share/qbs/modules/protobuf/cpp/protobufcpp.qbs2
-rw-r--r--share/qbs/modules/qbs/common.qbs7
-rw-r--r--share/qbs/modules/xcode/xcode.js16
-rw-r--r--share/qbs/modules/xcode/xcode.qbs49
-rw-r--r--src/app/config-ui/main.cpp2
-rw-r--r--src/app/config-ui/mainwindow.cpp4
-rw-r--r--src/app/config/configcommandexecutor.cpp5
-rw-r--r--src/app/config/configcommandlineparser.h2
-rw-r--r--src/app/qbs-setup-android/android-setup.cpp37
-rw-r--r--src/app/qbs-setup-android/commandlineparser.cpp5
-rw-r--r--src/app/qbs-setup-qt/setupqt.cpp12
-rw-r--r--src/app/qbs-setup-toolchains/clangclprobe.cpp108
-rw-r--r--src/app/qbs-setup-toolchains/clangclprobe.h6
-rw-r--r--src/app/qbs-setup-toolchains/gccprobe.cpp32
-rw-r--r--src/app/qbs-setup-toolchains/gccprobe.h4
-rw-r--r--src/app/qbs-setup-toolchains/iarewprobe.cpp29
-rw-r--r--src/app/qbs-setup-toolchains/iarewprobe.h2
-rw-r--r--src/app/qbs-setup-toolchains/keilprobe.cpp337
-rw-r--r--src/app/qbs-setup-toolchains/keilprobe.h2
-rw-r--r--src/app/qbs-setup-toolchains/main.cpp1
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.cpp284
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.h12
-rw-r--r--src/app/qbs-setup-toolchains/probe.cpp46
-rw-r--r--src/app/qbs-setup-toolchains/probe.h2
-rw-r--r--src/app/qbs-setup-toolchains/sdccprobe.cpp37
-rw-r--r--src/app/qbs-setup-toolchains/sdccprobe.h4
-rw-r--r--src/app/qbs-setup-toolchains/xcodeprobe.cpp12
-rw-r--r--src/app/qbs-setup-toolchains/xcodeprobe.h2
-rw-r--r--src/app/qbs/commandlinefrontend.cpp3
-rw-r--r--src/app/qbs/parser/commandlineoption.cpp12
-rw-r--r--src/app/qbs/parser/parsercommand.cpp4
-rw-r--r--src/app/qbs/session.cpp11
-rw-r--r--src/app/qbs/sessionpacket.cpp4
-rw-r--r--src/app/qbs/sessionpacketreader.cpp10
-rw-r--r--src/app/qbs/sessionpacketreader.h6
-rw-r--r--src/app/qbs/stdinreader.cpp32
-rw-r--r--src/lib/corelib/api/changeset.cpp6
-rw-r--r--src/lib/corelib/api/changeset.h2
-rw-r--r--src/lib/corelib/api/internaljobs.cpp23
-rw-r--r--src/lib/corelib/api/internaljobs.h16
-rw-r--r--src/lib/corelib/api/jobs.cpp11
-rw-r--r--src/lib/corelib/api/jobs.h7
-rw-r--r--src/lib/corelib/api/project.cpp278
-rw-r--r--src/lib/corelib/api/project_p.h23
-rw-r--r--src/lib/corelib/api/projectfileupdater.cpp43
-rw-r--r--src/lib/corelib/api/projectfileupdater.h13
-rw-r--r--src/lib/corelib/api/qmljsrewriter.cpp14
-rw-r--r--src/lib/corelib/api/qmljsrewriter.h4
-rw-r--r--src/lib/corelib/api/rulecommand.cpp12
-rw-r--r--src/lib/corelib/api/runenvironment.cpp2
-rw-r--r--src/lib/corelib/api/runenvironment.h4
-rw-r--r--src/lib/corelib/api/transformerdata.cpp10
-rw-r--r--src/lib/corelib/buildgraph/artifactcleaner.cpp2
-rw-r--r--src/lib/corelib/buildgraph/artifactcleaner.h2
-rw-r--r--src/lib/corelib/buildgraph/artifactvisitor.cpp2
-rw-r--r--src/lib/corelib/buildgraph/buildgraph.cpp8
-rw-r--r--src/lib/corelib/buildgraph/buildgraphloader.cpp15
-rw-r--r--src/lib/corelib/buildgraph/buildgraphloader.h6
-rw-r--r--src/lib/corelib/buildgraph/depscanner.h2
-rw-r--r--src/lib/corelib/buildgraph/environmentscriptrunner.cpp6
-rw-r--r--src/lib/corelib/buildgraph/executor.cpp42
-rw-r--r--src/lib/corelib/buildgraph/executor.h5
-rw-r--r--src/lib/corelib/buildgraph/executorjob.cpp4
-rw-r--r--src/lib/corelib/buildgraph/executorjob.h2
-rw-r--r--src/lib/corelib/buildgraph/filedependency.cpp16
-rw-r--r--src/lib/corelib/buildgraph/inputartifactscanner.cpp24
-rw-r--r--src/lib/corelib/buildgraph/nodetreedumper.cpp4
-rw-r--r--src/lib/corelib/buildgraph/nodetreedumper.h4
-rw-r--r--src/lib/corelib/buildgraph/processcommandexecutor.cpp3
-rw-r--r--src/lib/corelib/buildgraph/productinstaller.cpp6
-rw-r--r--src/lib/corelib/buildgraph/productinstaller.h4
-rw-r--r--src/lib/corelib/buildgraph/projectbuilddata.cpp10
-rw-r--r--src/lib/corelib/buildgraph/qtmocscanner.cpp2
-rw-r--r--src/lib/corelib/buildgraph/requesteddependencies.cpp6
-rw-r--r--src/lib/corelib/buildgraph/rescuableartifactdata.h9
-rw-r--r--src/lib/corelib/buildgraph/rulecommands.cpp17
-rw-r--r--src/lib/corelib/buildgraph/rulecommands.h10
-rw-r--r--src/lib/corelib/buildgraph/rulegraph.cpp8
-rw-r--r--src/lib/corelib/buildgraph/rulenode.cpp12
-rw-r--r--src/lib/corelib/buildgraph/rulesapplicator.cpp19
-rw-r--r--src/lib/corelib/buildgraph/rulesapplicator.h4
-rw-r--r--src/lib/corelib/buildgraph/scriptclasspropertyiterator.h4
-rw-r--r--src/lib/corelib/buildgraph/timestampsupdater.cpp2
-rw-r--r--src/lib/corelib/buildgraph/timestampsupdater.h2
-rw-r--r--src/lib/corelib/buildgraph/transformer.cpp6
-rw-r--r--src/lib/corelib/buildgraph/transformer.h2
-rw-r--r--src/lib/corelib/buildgraph/transformerchangetracking.cpp4
-rw-r--r--src/lib/corelib/corelib.qbs2
-rw-r--r--src/lib/corelib/generators/generatordata.h4
-rw-r--r--src/lib/corelib/generators/generatorutils.h15
-rw-r--r--src/lib/corelib/generators/generatorversioninfo.cpp32
-rw-r--r--src/lib/corelib/generators/generatorversioninfo.h29
-rw-r--r--src/lib/corelib/generators/igeneratableprojectvisitor.h2
-rw-r--r--src/lib/corelib/generators/ixmlnodevisitor.h2
-rw-r--r--src/lib/corelib/generators/xmlprojectwriter.cpp3
-rw-r--r--src/lib/corelib/generators/xmlpropertygroup.cpp5
-rw-r--r--src/lib/corelib/generators/xmlpropertygroup.h2
-rw-r--r--src/lib/corelib/generators/xmlworkspacewriter.cpp3
-rw-r--r--src/lib/corelib/jsextensions/binaryfile.cpp2
-rw-r--r--src/lib/corelib/jsextensions/domxml.cpp5
-rw-r--r--src/lib/corelib/jsextensions/fileinfoextension.cpp14
-rw-r--r--src/lib/corelib/jsextensions/jsextensions.cpp2
-rw-r--r--src/lib/corelib/jsextensions/jsextensions.h2
-rw-r--r--src/lib/corelib/jsextensions/moduleproperties.cpp2
-rw-r--r--src/lib/corelib/jsextensions/propertylist.mm4
-rw-r--r--src/lib/corelib/jsextensions/utilitiesextension.cpp80
-rw-r--r--src/lib/corelib/language/artifactproperties.cpp5
-rw-r--r--src/lib/corelib/language/asttools.cpp4
-rw-r--r--src/lib/corelib/language/builtindeclarations.cpp2
-rw-r--r--src/lib/corelib/language/builtindeclarations.h2
-rw-r--r--src/lib/corelib/language/deprecationinfo.h6
-rw-r--r--src/lib/corelib/language/evaluator.h2
-rw-r--r--src/lib/corelib/language/identifiersearch.cpp4
-rw-r--r--src/lib/corelib/language/item.cpp14
-rw-r--r--src/lib/corelib/language/itempool.cpp4
-rw-r--r--src/lib/corelib/language/itemreadervisitorstate.cpp5
-rw-r--r--src/lib/corelib/language/language.cpp35
-rw-r--r--src/lib/corelib/language/language.h26
-rw-r--r--src/lib/corelib/language/moduleloader.cpp349
-rw-r--r--src/lib/corelib/language/moduleloader.h18
-rw-r--r--src/lib/corelib/language/modulemerger.cpp226
-rw-r--r--src/lib/corelib/language/modulemerger.h31
-rw-r--r--src/lib/corelib/language/moduleproviderinfo.h9
-rw-r--r--src/lib/corelib/language/projectresolver.cpp11
-rw-r--r--src/lib/corelib/language/projectresolver.h6
-rw-r--r--src/lib/corelib/language/property.h10
-rw-r--r--src/lib/corelib/language/propertydeclaration.cpp15
-rw-r--r--src/lib/corelib/language/propertymapinternal.cpp8
-rw-r--r--src/lib/corelib/language/qualifiedid.cpp4
-rw-r--r--src/lib/corelib/language/resolvedfilecontext.h2
-rw-r--r--src/lib/corelib/language/scriptengine.cpp13
-rw-r--r--src/lib/corelib/language/value.cpp10
-rw-r--r--src/lib/corelib/language/value.h8
-rw-r--r--src/lib/corelib/logging/logger.cpp11
-rw-r--r--src/lib/corelib/logging/logger.h4
-rw-r--r--src/lib/corelib/parser/qmljsast_p.h14
-rw-r--r--src/lib/corelib/parser/qmljsastvisitor.cpp8
-rw-r--r--src/lib/corelib/parser/qmljsengine_p.cpp7
-rw-r--r--src/lib/corelib/parser/qmljsengine_p.h9
-rw-r--r--src/lib/corelib/parser/qmljslexer.cpp30
-rw-r--r--src/lib/corelib/parser/qmljslexer_p.h2
-rw-r--r--src/lib/corelib/parser/qmljsmemorypool_p.h4
-rw-r--r--src/lib/corelib/parser/qmljsparser.cpp14
-rw-r--r--src/lib/corelib/tools/buildoptions.cpp14
-rw-r--r--src/lib/corelib/tools/clangclinfo.cpp176
-rw-r--r--src/lib/corelib/tools/clangclinfo.h61
-rw-r--r--src/lib/corelib/tools/cleanoptions.cpp16
-rw-r--r--src/lib/corelib/tools/codelocation.cpp18
-rw-r--r--src/lib/corelib/tools/error.cpp34
-rw-r--r--src/lib/corelib/tools/error.h4
-rw-r--r--src/lib/corelib/tools/executablefinder.cpp4
-rw-r--r--src/lib/corelib/tools/executablefinder.h2
-rw-r--r--src/lib/corelib/tools/fileinfo.cpp2
-rw-r--r--src/lib/corelib/tools/generateoptions.cpp14
-rw-r--r--src/lib/corelib/tools/hostosinfo.h22
-rw-r--r--src/lib/corelib/tools/id.cpp6
-rw-r--r--src/lib/corelib/tools/id.h2
-rw-r--r--src/lib/corelib/tools/installoptions.cpp14
-rw-r--r--src/lib/corelib/tools/joblimits.cpp20
-rw-r--r--src/lib/corelib/tools/jsonhelper.h6
-rw-r--r--src/lib/corelib/tools/launcherinterface.cpp4
-rw-r--r--src/lib/corelib/tools/launcherpackets.cpp2
-rw-r--r--src/lib/corelib/tools/msvcinfo.cpp419
-rw-r--r--src/lib/corelib/tools/msvcinfo.h28
-rw-r--r--src/lib/corelib/tools/persistence.cpp20
-rw-r--r--src/lib/corelib/tools/persistence.h2
-rw-r--r--src/lib/corelib/tools/processresult.cpp14
-rw-r--r--src/lib/corelib/tools/processutils.cpp3
-rw-r--r--src/lib/corelib/tools/profile.cpp10
-rw-r--r--src/lib/corelib/tools/profile.h2
-rw-r--r--src/lib/corelib/tools/progressobserver.h2
-rw-r--r--src/lib/corelib/tools/projectgeneratormanager.cpp8
-rw-r--r--src/lib/corelib/tools/qttools.h19
-rw-r--r--src/lib/corelib/tools/scannerpluginmanager.cpp4
-rw-r--r--src/lib/corelib/tools/set.h2
-rw-r--r--src/lib/corelib/tools/settings.cpp12
-rw-r--r--src/lib/corelib/tools/settings.h6
-rw-r--r--src/lib/corelib/tools/settingscreator.cpp9
-rw-r--r--src/lib/corelib/tools/settingscreator.h2
-rw-r--r--src/lib/corelib/tools/settingsmodel.cpp4
-rw-r--r--src/lib/corelib/tools/setupprojectparameters.cpp20
-rw-r--r--src/lib/corelib/tools/shellutils.cpp4
-rw-r--r--src/lib/corelib/tools/shellutils.h2
-rw-r--r--src/lib/corelib/tools/stlutils.h15
-rw-r--r--src/lib/corelib/tools/stringconstants.h1
-rw-r--r--src/lib/corelib/tools/stringutils.h4
-rw-r--r--src/lib/corelib/tools/toolchains.cpp7
-rw-r--r--src/lib/corelib/tools/tools.pri2
-rw-r--r--src/lib/corelib/tools/version.cpp70
-rw-r--r--src/lib/corelib/tools/version.h70
-rw-r--r--src/lib/corelib/tools/visualstudioversioninfo.cpp6
-rw-r--r--src/lib/corelib/tools/vsenvironmentdetector.cpp7
-rw-r--r--src/lib/scriptengine/use_scriptengine.pri10
-rw-r--r--src/libexec/qbs_processlauncher/launchersockethandler.cpp3
-rw-r--r--src/packages/archive/archive.qbs2
-rw-r--r--src/packages/chocolatey/chocolatey.qbs2
-rw-r--r--src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.cpp4
-rw-r--r--src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.cpp4
-rw-r--r--src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.h4
-rw-r--r--src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.cpp4
-rw-r--r--src/plugins/generator/iarew/iarew.pro1
-rw-r--r--src/plugins/generator/iarew/iarew.qbs1
-rw-r--r--src/plugins/generator/iarew/iarewfileversionproperty.cpp6
-rw-r--r--src/plugins/generator/iarew/iarewfileversionproperty.h5
-rw-r--r--src/plugins/generator/iarew/iarewgenerator.cpp2
-rw-r--r--src/plugins/generator/iarew/iarewgenerator.h4
-rw-r--r--src/plugins/generator/iarew/iarewgeneratorplugin.cpp2
-rw-r--r--src/plugins/generator/iarew/iarewoptionpropertygroup.cpp8
-rw-r--r--src/plugins/generator/iarew/iarewoptionpropertygroup.h3
-rw-r--r--src/plugins/generator/iarew/iarewproject.cpp2
-rw-r--r--src/plugins/generator/iarew/iarewproject.h4
-rw-r--r--src/plugins/generator/iarew/iarewsettingspropertygroup.cpp12
-rw-r--r--src/plugins/generator/iarew/iarewsettingspropertygroup.h4
-rw-r--r--src/plugins/generator/iarew/iarewsourcefilepropertygroup.h2
-rw-r--r--src/plugins/generator/iarew/iarewversioninfo.cpp77
-rw-r--r--src/plugins/generator/iarew/iarewversioninfo.h19
-rw-r--r--src/plugins/generator/keiluv/keiluv.pro1
-rw-r--r--src/plugins/generator/keiluv/keiluv.qbs1
-rw-r--r--src/plugins/generator/keiluv/keiluvgenerator.cpp2
-rw-r--r--src/plugins/generator/keiluv/keiluvgenerator.h4
-rw-r--r--src/plugins/generator/keiluv/keiluvgeneratorplugin.cpp2
-rw-r--r--src/plugins/generator/keiluv/keiluvproject.cpp7
-rw-r--r--src/plugins/generator/keiluv/keiluvproject.h4
-rw-r--r--src/plugins/generator/keiluv/keiluvversioninfo.cpp76
-rw-r--r--src/plugins/generator/keiluv/keiluvversioninfo.h17
-rw-r--r--src/plugins/generator/visualstudio/io/msbuildprojectwriter.cpp4
-rw-r--r--src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.cpp4
-rw-r--r--src/plugins/generator/visualstudio/msbuild/imsbuildgroup.cpp4
-rw-r--r--src/plugins/generator/visualstudio/msbuild/imsbuildnode.cpp4
-rw-r--r--src/plugins/generator/visualstudio/msbuild/imsbuildnodevisitor.h2
-rw-r--r--src/plugins/generator/visualstudio/msbuild/imsbuildproperty.cpp4
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.cpp8
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.cpp4
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildimport.cpp4
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.cpp4
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuilditem.cpp4
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp4
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.cpp4
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildproject.cpp4
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.cpp4
-rw-r--r--src/plugins/generator/visualstudio/msbuildtargetproject.cpp4
-rw-r--r--src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.cpp4
-rw-r--r--src/plugins/generator/visualstudio/solution/visualstudiosolution.cpp4
-rw-r--r--src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.cpp4
-rw-r--r--src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.cpp6
-rw-r--r--src/plugins/generator/visualstudio/visualstudiogenerator.cpp4
-rw-r--r--src/plugins/plugins.pri2
-rw-r--r--src/plugins/scanner/cpp/Lexer.cpp11
-rw-r--r--src/plugins/scanner/cpp/Token.cpp4
-rw-r--r--src/plugins/scanner/cpp/cppscanner.cpp4
-rw-r--r--src/shared/json/json.cpp8
-rw-r--r--tests/auto/api/testdata/multiplexing/multiplexing.qbs7
-rw-r--r--tests/auto/api/testdata/process-result/process-result.qbs1
-rw-r--r--tests/auto/api/tst_api.cpp195
-rw-r--r--tests/auto/api/tst_api.h2
-rw-r--r--tests/auto/blackbox/find/find-android.qbs49
-rw-r--r--tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c1
-rw-r--r--tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/AndroidManifest.xml2
-rw-r--r--tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/AndroidManifest.xml2
-rw-r--r--tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/AndroidManifest.xml2
-rw-r--r--tests/auto/blackbox/testdata-android/qml-app/src/main/AndroidManifest.xml2
-rw-r--r--tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/aggregateDependencyLinking.qbs2
-rw-r--r--tests/auto/blackbox/testdata-apple/overrideInfoPlist/Override-Info.plist10
-rw-r--r--tests/auto/blackbox/testdata-apple/overrideInfoPlist/main.c1
-rw-r--r--tests/auto/blackbox/testdata-apple/overrideInfoPlist/overrideInfoPlist.qbs16
-rw-r--r--tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs7
-rw-r--r--tests/auto/blackbox/testdata-qt/metatypes/metatypes.qbs28
-rw-r--r--tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.cpp3
-rw-r--r--tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.h8
-rw-r--r--tests/auto/blackbox/testdata-qt/metatypes/mocableclass2.cpp10
-rw-r--r--tests/auto/blackbox/testdata-qt/metatypes/unmocableclass.cpp7
-rw-r--r--tests/auto/blackbox/testdata-qt/qmltyperegistrar/example.qml58
-rw-r--r--tests/auto/blackbox/testdata-qt/qmltyperegistrar/main.cpp71
-rw-r--r--tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.cpp78
-rw-r--r--tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.h78
-rw-r--r--tests/auto/blackbox/testdata-qt/qmltyperegistrar/qmltyperegistrar.qbs33
-rw-r--r--tests/auto/blackbox/testdata-qt/qtscxml/qtscxml.qbs22
-rw-r--r--tests/auto/blackbox/testdata/build-variant-defaults/build-variant-defaults.qbs16
-rw-r--r--tests/auto/blackbox/testdata/build-variant-defaults/main.cpp1
-rw-r--r--tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile-probe-project.qbs22
-rw-r--r--tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile.py25
-rw-r--r--tests/auto/blackbox/testdata/conanfile-probe/testlib/conanfile.py25
-rw-r--r--tests/auto/blackbox/testdata/dependency-profile-mismatch/dependency-profile-mismatch.qbs12
-rw-r--r--tests/auto/blackbox/testdata/dependency-scanning-loop/dependency-scanning-loop.qbs34
-rw-r--r--tests/auto/blackbox/testdata/dependency-scanning-loop/main.cpp1
-rw-r--r--tests/auto/blackbox/testdata/empty-profile/empty-profile.qbs3
-rw-r--r--tests/auto/blackbox/testdata/empty-profile/main.cpp1
-rw-r--r--tests/auto/blackbox/testdata/freedesktop/freedesktop.qbs25
-rw-r--r--tests/auto/blackbox/testdata/freedesktop/main.cpp4
-rw-r--r--tests/auto/blackbox/testdata/freedesktop/myapp.appdata.xml15
-rw-r--r--tests/auto/blackbox/testdata/freedesktop/myapp.desktop4
-rw-r--r--tests/auto/blackbox/testdata/freedesktop/myapp.png0
-rw-r--r--tests/auto/blackbox/testdata/generate-linker-map-file/generate-linker-map-file.qbs3
-rw-r--r--tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs1
-rw-r--r--tests/auto/blackbox/testdata/host-os-properties/host-os-properties.qbs8
-rw-r--r--tests/auto/blackbox/testdata/host-os-properties/main.cpp7
-rw-r--r--tests/auto/blackbox/testdata/install-locations/install-locations.qbs12
-rw-r--r--tests/auto/blackbox/testdata/install-locations/theplugin.cpp3
-rw-r--r--tests/auto/blackbox/testdata/last-module-candidate-broken/last-module-candidate-broken.qbs5
-rw-r--r--tests/auto/blackbox/testdata/last-module-candidate-broken/main.cpp1
-rw-r--r--tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo1.qbs3
-rw-r--r--tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo2.qbs2
-rw-r--r--tests/auto/blackbox/testdata/list-property-order/modules/lower/lower.qbs4
-rw-r--r--tests/auto/blackbox/testdata/list-property-order/product.qbs1
-rw-r--r--tests/auto/blackbox/testdata/path-probe/BaseApp.qbs64
-rw-r--r--tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs3
-rw-r--r--tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs3
-rw-r--r--tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs3
-rw-r--r--tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs1
-rw-r--r--tests/auto/blackbox/testdata/path-probe/mult-files.qbs1
-rw-r--r--tests/auto/blackbox/testdata/path-probe/name-filter.qbs1
-rw-r--r--tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs1
-rw-r--r--tests/auto/blackbox/testdata/path-probe/non-existent.qbs1
-rw-r--r--tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs1
-rw-r--r--tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs1
-rw-r--r--tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs1
-rw-r--r--tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs3
-rw-r--r--tests/auto/blackbox/testdata/path-probe/single-file.qbs1
-rw-r--r--tests/auto/blackbox/testdata/probeProperties/probeProperties.qbs51
-rw-r--r--tests/auto/blackbox/testdata/property-evaluation-context/modules/base/base.qbs4
-rw-r--r--tests/auto/blackbox/testdata/property-evaluation-context/modules/top/top.qbs6
-rw-r--r--tests/auto/blackbox/testdata/property-evaluation-context/property-evaluation-context.qbs34
-rw-r--r--tests/auto/blackbox/testdata/protobuf/addressbook_cpp.qbs1
-rw-r--r--tests/auto/blackbox/testdata/protobuf/import.qbs1
-rw-r--r--tests/auto/blackbox/testdata/protobuf/needs-import-dir.qbs1
-rw-r--r--tests/auto/blackbox/testdata/response-files/response-files.qbs3
-rw-r--r--tests/auto/blackbox/testdata/sanitizer/sanitizer.cpp4
-rw-r--r--tests/auto/blackbox/testdata/sanitizer/sanitizer.qbs30
-rw-r--r--tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.h1
-rw-r--r--tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.qbs4
-rw-r--r--tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/main.cpp3
-rw-r--r--tests/auto/blackbox/testdata/scan-result-in-non-dependency/lib/lib.h3
-rw-r--r--tests/auto/blackbox/testdata/scan-result-in-non-dependency/other/other.qbs24
-rw-r--r--tests/auto/blackbox/testdata/scan-result-in-non-dependency/p.qbs6
-rw-r--r--tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.h1
-rw-r--r--tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.qbs4
-rw-r--r--tests/auto/blackbox/testdata/scan-result-in-other-product/app/main.cpp3
-rw-r--r--tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.h3
-rw-r--r--tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.qbs7
-rw-r--r--tests/auto/blackbox/testdata/scan-result-in-other-product/other/other.qbs24
-rw-r--r--tests/auto/blackbox/testdata/scan-result-in-other-product/p.qbs7
-rw-r--r--tests/auto/blackbox/testdata/undefined-target-platform/undefined-target-platform.qbs13
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp557
-rw-r--r--tests/auto/blackbox/tst_blackbox.h15
-rw-r--r--tests/auto/blackbox/tst_blackboxandroid.cpp257
-rw-r--r--tests/auto/blackbox/tst_blackboxapple.cpp163
-rw-r--r--tests/auto/blackbox/tst_blackboxapple.h1
-rw-r--r--tests/auto/blackbox/tst_blackboxbase.cpp20
-rw-r--r--tests/auto/blackbox/tst_blackboxbase.h9
-rw-r--r--tests/auto/blackbox/tst_blackboxjava.cpp3
-rw-r--r--tests/auto/blackbox/tst_blackboxqt.cpp76
-rw-r--r--tests/auto/blackbox/tst_blackboxqt.h4
-rw-r--r--tests/auto/blackbox/tst_clangdb.cpp4
-rw-r--r--tests/auto/buildgraph/tst_buildgraph.cpp10
-rw-r--r--tests/auto/language/testdata/erroneous/ambiguous-multiplex-dependency.qbs14
-rw-r--r--tests/auto/language/testdata/erroneous/dependency-profile-mismatch-2.qbs17
-rw-r--r--tests/auto/language/testdata/erroneous/dependency-profile-mismatch.qbs14
-rw-r--r--tests/auto/language/tst_language.cpp31
-rw-r--r--tests/auto/shared.h45
-rw-r--r--tests/benchmarker/benchmarker.cpp13
-rw-r--r--tests/benchmarker/benchmarker.h4
-rw-r--r--tests/benchmarker/commandlineparser.cpp8
-rw-r--r--tests/benchmarker/exception.h4
-rw-r--r--tests/benchmarker/valgrindrunner.cpp4
-rw-r--r--tests/benchmarker/valgrindrunner.h2
-rw-r--r--tests/fuzzy-test/commandlineparser.cpp4
-rw-r--r--tests/fuzzy-test/commandlineparser.h4
-rw-r--r--tests/fuzzy-test/fuzzytester.cpp3
-rw-r--r--tests/fuzzy-test/fuzzytester.h4
481 files changed, 8459 insertions, 3727 deletions
diff --git a/.clang-tidy b/.clang-tidy
index 7af193cc6..a1cfad4d5 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,6 +1,68 @@
---
-Checks: 'clang-diagnostic-*,clang-analyzer-*,-*,bugprone-*,clang-analyzer-*,cppcoreguidelines-c-copy-assignment-signature,cppcoreguidelines-interfaces-global-init,cppcoreguidelines-no-malloc,cppcoreguidelines-pro-bounds-constant-array-index,cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-type-const-cast,cppcoreguidelines-pro-type-cstyle-cast,cppcoreguidelines-pro-type-member-init,cppcoreguidelines-pro-type-union-access,cppcoreguidelines-slicing,cppcoreguidelines-special-member-functions,fuchsia-virtual-inheritance,google-build-explicit-make-pair,google-build-namespaces,google-global-names-in-headers,google-objc-*,google-readability-casting,google-readability-function-size,google-readability-namespace-comments,google-readability-todo,google-runtime-int,google-runtime-operator,misc-definitions-in-headers,misc-misplaced-const,misc-new-delete-overloads,misc-non-copyable-objects,misc-redundant-expression,misc-static-assert,misc-unconventional-assign-operator,misc-uniqueptr-reset-release,misc-unused-*,modernize-avoid-bind,modernize-deprecated-headers,modernize-loop-convert,modernize-make-*,modernize-pass-by-value,modernize-raw-string-literal,modernize-redundant-void-arg,modernize-replace-*,modernize-return-braced-init-list,modernize-shrink-to-fit,modernize-unary-static-assert,modernize-use-auto,modernize-use-bool-literals,modernize-use-emplace,modernize-use-equals-*,modernize-use-noexcept,modernize-use-nullptr,modernize-use-override,modernize-use-transparent-functors,modernize-use-using,performance-*,readability-avoid-const-params-in-decls,readability-container-size-empty,readability-delete-null-pointer,readability-deleted-default,readability-function-size,readability-identifier-naming,readability-inconsistent-declaration-parameter-name,readability-misleading-indentation,readability-misplaced-array-index,readability-non-const-parameter,readability-redundant-*,readability-simplify-boolean-expr,readability-static-definition-in-anonymous-namespace,readability-uniqueptr-delete-release'
-WarningsAsErrors: ''
+Checks: >
+ -*,
+ bugprone-*,
+ cppcoreguidelines-interfaces-global-init,
+ cppcoreguidelines-pro-type-cstyle-cast,
+ cppcoreguidelines-pro-type-member-init,
+ cppcoreguidelines-slicing,
+ fuchsia-virtual-inheritance,
+ google-build-explicit-make-pair,
+ google-build-namespaces,
+ google-global-names-in-headers,
+ google-objc-*,
+ google-readability-casting,
+ google-readability-namespace-comments,
+ google-runtime-operator,
+ misc-definitions-in-headers,
+ misc-misplaced-const,
+ misc-new-delete-overloads,
+ misc-non-copyable-objects,
+ misc-redundant-expression,
+ misc-static-assert,
+ misc-uniqueptr-reset-release,
+ misc-unused-*,
+ modernize-avoid-bind,
+ modernize-deprecated-headers,
+ modernize-loop-convert,
+ modernize-make-*,
+ modernize-pass-by-value,
+ modernize-redundant-void-arg,
+ modernize-replace-*,
+ modernize-return-braced-init-list,
+ modernize-shrink-to-fit,
+ modernize-unary-static-assert,
+ modernize-use-auto,
+ modernize-use-bool-literals,
+ modernize-use-emplace,
+ modernize-use-equals-*,
+ modernize-use-noexcept,
+ modernize-use-override,
+ modernize-use-transparent-functors,
+ modernize-use-using,
+ performance-*,
+ readability-avoid-const-params-in-decls,
+ readability-container-size-empty,
+ readability-delete-null-pointer,
+ readability-deleted-default,
+ readability-identifier-naming,
+ readability-misleading-indentation,
+ readability-misplaced-array-index,
+ readability-non-const-parameter,
+ readability-redundant-*,
+ -readability-redundant-member-init,
+ readability-simplify-boolean-expr,
+ readability-static-definition-in-anonymous-namespace,
+ readability-uniqueptr-delete-release
+
+WarningsAsErrors: >
+ bugprone-*,
+ google-*,
+ misc-unused-*,
+ modernize-*,
+ performance-*,
+ readability-redundant-control-flow
+
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
CheckOptions:
diff --git a/.travis.yml b/.travis.yml
index 208ae94a2..1818ff595 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,6 +4,7 @@
# DOCKER_USERNAME
#
language: cpp
+cache: ccache
git:
submodules: false
@@ -11,8 +12,8 @@ git:
env:
global:
- QT_INSTALL_DIR=~/Qt
- - QT_VERSION=5.12.5
- - QTCREATOR_VERSION=4.10.1
+ - QT_VERSION=5.12.6
+ - QTCREATOR_VERSION=4.10.2
stages:
- name: Build Qbs and and run autotests
@@ -23,51 +24,136 @@ jobs:
stage: Build Qbs and and run autotests
name: With Qbs on Ubuntu bionic (linux_gcc64)
env:
- SERVICE=bionic
+ BUILD_OPTIONS=modules.cpp.compilerWrapper:ccache
services:
- docker
- before_install:
- - docker-compose pull ${SERVICE}
+ before_script:
+ - docker-compose pull bionic
+ - ccache -M 5G
+ - ccache -s
+ after_script:
+ - ccache -s
script:
- - docker-compose run --rm ${SERVICE} scripts/build-qbs-with-qbs.sh
+ - docker-compose run bionic scripts/build-qbs-with-qbs.sh
- <<: *build-on-bionic
name: With QMake on Ubuntu bionic (linux_gcc64)
+ env:
+ BUILD_OPTIONS="CONFIG+=ccache"
script:
- - docker-compose run --rm ${SERVICE} scripts/build-qbs-with-qmake.sh
+ - docker-compose run bionic scripts/build-qbs-with-qmake.sh
- <<: *build-on-bionic
name: With Qbs on Ubuntu bionic (mingw32_w64)
+ env:
+ BUILD_OPTIONS="profile:qt-mingw32_w64 modules.cpp.compilerWrapper:ccache modules.cpp.treatWarningsAsErrors:true config:release"
+ script:
+ - docker-compose run bionic qbs build ${BUILD_OPTIONS}
+
+ - <<: *build-on-bionic
+ name: With Qbs on Ubuntu bionic (linux_clang64 & clang_tidy)
+ env:
+ BUILD_OPTIONS="profile:qt-clang_64 modules.cpp.compilerWrapper:ccache"
+ services:
+ - docker
+ script:
+ - docker-compose run --rm bionic scripts/run-analyzer.sh
+
+ - <<: *build-on-bionic
+ name: With Qbs and with Qt for Android
+ before_install:
+ - docker-compose pull bionic
+ - docker-compose pull bionic-android-513
+ - docker-compose pull bionic-android-514
script:
- - docker-compose run --rm ${SERVICE} qbs build profile:qt-mingw32_w64
+ - docker-compose run bionic qbs build modules.cpp.compilerWrapper:ccache modules.qbsbuildconfig.enableBundledQt:true config:release
+ - docker-compose run bionic-android-513 scripts/test-qt-for-android.sh release/install-root/usr/local/bin
+ - docker-compose run bionic-android-514 scripts/test-qt-for-android.sh release/install-root/usr/local/bin
- &build-on-macos
stage: Build Qbs and and run autotests
- name: With Qbs on macOS (xcode 10.3)
+ name: With Qbs on macOS (xcode 11.3)
os: osx
- osx_image: xcode10.3
+ osx_image: xcode11.3
addons:
homebrew:
packages:
+ - ccache
+ - grpc
+ - icoutils
+ - makensis
+ - protobuf
- p7zip
update: true
env:
# Address sanitizer slows autotests down too much.
# We would hit the maximum build time on Travis.
- BUILD_OPTIONS=modules.qbsbuildconfig.enableAddressSanitizer:false
+ BUILD_OPTIONS="modules.qbsbuildconfig.enableAddressSanitizer:false modules.cpp.compilerWrapper:ccache"
QMAKE_PATH=${QT_INSTALL_DIR}/${QT_VERSION}/clang_64/bin/qmake
PATH="${QT_INSTALL_DIR}/Qt Creator.app/Contents/MacOS:${PATH}"
QBS_BUILD_PROFILE=qt
before_install:
- - ./scripts/install-qt.sh -d ${QT_INSTALL_DIR} --version ${QT_VERSION} qtbase qtdeclarative qttools qtscript
+ - ./scripts/install-qt.sh -d ${QT_INSTALL_DIR} --version ${QT_VERSION} qtbase qtdeclarative qttools qtscript qtscxml
- ./scripts/install-qt.sh -d ${QT_INSTALL_DIR} --version ${QTCREATOR_VERSION} qtcreator
- - pip2 install --user beautifulsoup4 lxml
+ - pip3 install --user beautifulsoup4 lxml
+ before_script:
+ - ulimit -c unlimited -S # enable core dumps
script:
+ - ccache -s
- qbs setup-toolchains --detect
- qbs setup-qt ${QMAKE_PATH} qt
- - qbs config qt.baseProfile xcode-macosx-x86_64
+ - qbs config profiles.qt.baseProfile xcode-macosx-x86_64
- qbs config defaultProfile qt
+ - qbs config --list profiles
- scripts/build-qbs-with-qbs.sh
+ - ccache -s
+ # Find core dump and print traceback on failure
+ after_failure:
+ - |
+ for f in $(find /cores -maxdepth 1 -name 'core.*' -print); do
+ lldb --core $f --batch --one-line "bt"
+ done;
+
+
+ - <<: *build-on-macos
+ name: With Qbs on macOS (xcode 10.3)
+ osx_image: xcode10.3
+ if: branch = master
+
+ - <<: *build-on-macos
+ name: With Qbs on macOS (xcode 9.4)
+ osx_image: xcode9.4
+ if: branch = master
+
+ - &build-on-windows-with-docker
+ stage: Build Qbs and and run autotests
+ name: With Qbs on Windows with Docker (Visual Studio 2017)
+ if: branch = master
+ os: windows
+ services: docker
+ env:
+ CLCACHE_DIR="${HOME}/.ccache"
+ before-install:
+ - curl -sLo "/c/Program Files/Docker/docker-compose.exe" https://github.com/docker/compose/releases/download/1.25.3/docker-compose-Windows-x86_64.exe
+ - docker-compose pull windows
+ before_script:
+ - docker-compose run --rm windows clcache -s
+ script:
+ - >
+ docker-compose run --rm windows qbs build
+ -p dist
+ qbs.buildVariant:release
+ modules.cpp.compilerWrapper:clcache
+ modules.qbsbuildconfig.enableBundledQt:true
+ modules.qbsbuildconfig.enableProjectFileUpdates:true
+ modules.qbsbuildconfig.enableUnitTests:true
+ modules.cpp.treatWarningsAsErrors:true
+ project.withDocumentation:true
+ project.withExamples:true
+ config:release-64 profile:qt64
+ config:release profile:qt
+ after_script:
+ - docker-compose run --rm windows clcache -s
- &build-on-windows
stage: Build Qbs and and run autotests
@@ -75,19 +161,35 @@ jobs:
os: windows
env:
# Need to build in release mode. Otherwise autotests would be too slow.
- BUILD_OPTIONS="config:release"
- QT_INSTALL_DIR=C:/Qt
+ BUILD_OPTIONS="config:release modules.cpp.compilerWrapper:clcache"
QMAKE_PATH=${QT_INSTALL_DIR}/${QT_VERSION}/msvc2017_64/bin/qmake.exe
- PATH="/c/Qt/Tools/QtCreator/bin:${PATH}"
- WITH_DOCS=0
+ PATH="${QT_INSTALL_DIR}/Tools/QtCreator/bin:/c/Python38:/c/Python39:/c/Python38/Scripts:/c/Python39/Scripts:${PATH}"
QBS_BUILD_PROFILE=qt
+ CLCACHE_DIR="${HOME}/.ccache"
before_install:
# Install Qbs and Qt
- ./scripts/install-qt.sh -d ${QT_INSTALL_DIR} --version ${QT_VERSION} --toolchain win64_msvc2017_64 qtbase qtdeclarative qttools qtscript
- ./scripts/install-qt.sh -d ${QT_INSTALL_DIR} --version ${QTCREATOR_VERSION} qtcreator
+ - choco install python3
+ - pip3 install git+https://github.com/frerich/clcache.git@cae73d8255d78db8ba11e23c51fd2c9a89e7475b
+ - pip3 install conan beautifulsoup4 lxml
+ before_script:
+ - clcache -s
+ after_script:
+ - clcache -s
+ script:
+ - qbs setup-toolchains --detect
+ - qbs setup-qt ${QMAKE_PATH} qt
+ - qbs config qt.baseProfile MSVC2017-x64
+ - qbs config defaultProfile qt
+ - scripts/build-qbs-with-qbs.sh
+
+ - <<: *build-on-windows
+ name: With Qbs on Windows (clang-cl)
+ if: branch = master
script:
- qbs setup-toolchains --detect
- qbs setup-qt ${QMAKE_PATH} qt
- - qbs config qt.baseProfile MSVC2017-x86
+ - qbs config profiles.qt.baseProfile clang-cl-x86_64
- qbs config defaultProfile qt
- scripts/build-qbs-with-qbs.sh
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..86c2de06f
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,102 @@
+# Contributing to Qbs
+
+The main source code repository is hosted at
+[codereview.qt-project.org](https://codereview.qt-project.org/q/project:qbs/qbs).
+
+The Qbs source code is also mirrored on [code.qt.io](https://code.qt.io/cgit/qbs/qbs.git/)
+and on [GitHub](https://github.com/qbs/qbs). Please note that those mirrors
+are read-only and we do not accept pull-requests on GitHub. However, we gladly
+accept contributions via [Gerrit](https://codereview.qt-project.org/q/project:qbs/qbs).
+
+This document briefly describes steps required to be able to propose changes
+to the Qbs project.
+
+See the [Qt Contribution Guidelines](https://wiki.qt.io/Qt_Contribution_Guidelines)
+page, [Setting up Gerrit](https://wiki.qt.io/Setting_up_Gerrit) and
+[Gerrit Introduction](https://wiki.qt.io/Gerrit_Introduction) for more
+details about how to upload patches to Gerrit.
+
+## Preparations
+
+* [Set up](https://wiki.qt.io/Setting_up_Gerrit#How_to_get_started_-_Gerrit_registration)
+a Gerrit account
+* Tweak your SSH config as instructed [here](https://wiki.qt.io/Setting_up_Gerrit#Local_Setup)
+* Use the recommended Git settings, defined [here](https://wiki.qt.io/Setting_up_Gerrit#Configuring_Git)
+* Get the source code as described below
+
+## Cloning Qbs
+
+Clone Qbs from the [code.qt.io](https://code.qt.io/cgit/qbs/qbs.git/) mirror
+```
+git clone git://code.qt.io/qbs/qbs.git
+```
+Alternatively, you can clone from the mirror on the [GitHub](https://github.com/qbs/qbs)
+```
+git clone https://github.com/qbs/qbs.git
+```
+
+Set up the Gerrit remote
+```
+git remote add gerrit ssh://<gerrit-username>@codereview.qt-project.org:29418/qbs/qbs
+```
+
+## Setting up git hooks
+
+Install the hook generating Commit-Id files into your top level project directory:
+```
+gitdir=$(git rev-parse --git-dir); scp -P 29418 codereview.qt-project.org:hooks/commit-msg ${gitdir}/hooks/
+```
+
+This hook automatically adds a "Change-Id: …" line to the commit message. Change-Id is used
+to identify new Patch Sets for existing
+[Changes](https://wiki.qt.io/Gerrit_Introduction#Terminology).
+
+## Making changes
+
+Commit your changes in the usual way you do in Git.
+
+After making changes, you might want to ensure that Qbs can be built and autotests pass:
+```
+qbs build -p autotest-runner
+```
+See ["Appendix A: Building Qbs"](http://doc.qt.io/qbs/building-qbs.html) for details.
+
+In case your changes might significantly affect performance (in either way), the
+'qbs_benchmarker' tool can be used (Linux only, requires Valgrind to be installed):
+```
+qbs_benchmarker -r <QBS_REPO> -o <OLD_REVISION> -n <NEW_REVISION> -a <ACTIVITY> -p <PROJECT>
+```
+Use 'qbs_benchmarker --help' for details.
+
+## Pushing your changes to Gerrit
+
+After committing your changes locally, push them to Gerrit
+
+```
+git push gerrit HEAD:refs/for/master
+```
+
+Gerrit will print a URL that can be used to access the newly created Change.
+
+## Adding reviewers
+
+Use the "ADD REVIEWER" button on the Change's web page to ask people to do the
+review. To find possible reviewers, you can examine the Git history with
+'git log' and/or 'git blame' or ask on the mailing list: qbs@qt-project.org
+
+## Modifying Commits
+
+During the review process, it might be necessary to do some changes to the commit.
+To include you changes in the last commit, use
+```
+git commit --amend
+```
+This will edit the last commit instead of creating a new one. Make sure to preserve the
+Change-Id footer when amending commits. For details, see
+[Updating a Contribution With New Code](https://wiki.qt.io/Gerrit_Introduction#Updating_a_Contribution_With_New_Code)
+
+## Abandoning changes
+
+Changes which are inherently flawed or became inapplicable should be abandoned. You can do that
+on the Change's web page with the "ABANDON" button. Make sure to remove the abandoned commit
+from your working copy by using '[git reset](https://git-scm.com/docs/git-reset)'.
diff --git a/README b/README
deleted file mode 100644
index 5c11c8465..000000000
--- a/README
+++ /dev/null
@@ -1,8 +0,0 @@
-Qbs
-===
-Qbs is a cross-platform build tool.
-The project's homepage is http://wiki.qt.io/qbs
-Qbs product documentation is available at: http://doc.qt.io/qbs/index.html
-
-For more information about building Qbs from sources, see
-"Appendix A: Building Qbs" at: http://doc.qt.io/qbs/building-qbs.html.
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..c56d8c214
--- /dev/null
+++ b/README.md
@@ -0,0 +1,36 @@
+# Qbs
+
+Qbs is a build automation tool designed to conveniently manage the build
+process of software projects across multiple platforms. Qbs can be used for any
+software project, regardless of programming language, toolkit, or libraries used.
+
+## Documentation
+
+Qbs product documentation is available at [doc.qt.io/qbs](http://doc.qt.io/qbs/index.html)
+
+The project's homepage is [wiki.qt.io/qbs](http://wiki.qt.io/qbs)
+
+## Supported platforms
+
+Qbs binaries are available for Windows, macOS, Linux, and FreeBSD.
+
+For more information about how to install Qbs on your platform, see the
+[Installing](https://doc.qt.io/qbs/installing.html) page in the documentation.
+
+Qbs allows to build applications for different platforms, for the list of
+supported platforms and the details about each platform, see the
+[Target Platforms](https://doc.qt.io/qbs/platforms.html) page.
+
+## Building Qbs
+
+For information about building Qbs from sources, see
+["Appendix A: Building Qbs"](http://doc.qt.io/qbs/building-qbs.html).
+
+## Reporting Bugs
+
+Please report any bugs in our [bug tracker](https://bugreports.qt.io/browse/QBS).
+
+## Contributing
+
+See [Contributing to Qbs](CONTRIBUTING.md)
+
diff --git a/VERSION b/VERSION
index 15b989e39..092afa15d 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.16.0
+1.17.0
diff --git a/changelogs/changes-1.15.0.md b/changelogs/changes-1.15.0.md
new file mode 100644
index 000000000..cc95011a8
--- /dev/null
+++ b/changelogs/changes-1.15.0.md
@@ -0,0 +1,44 @@
+# General
+* Added a session command which offers a JSON-based API for interaction with
+ other tools via stdin/ stdout. This allows for proper Qbs support in IDEs that
+ do not use Qt or even C++.
+
+# Language
+* Probes are now evaluated before Profile items and can be used to create
+ profiles on project level.
+* AutotestRunner got a separate job pool.
+* Added a timeout property to Command, JavaScriptCommand and AutotestRunner.
+ This allows to identify and kill stuck commands.
+
+# C/C++ Support
+* Ensure proper support of Xcode 11.
+* Linker map files can be generated with all toolchains.
+* Bare metal toolchains can now generate listing files.
+* Improve the command line output filtering of bare metal toolchains.
+* Added support for clang in mingw mode on Windows.
+* Added msp430 support to GCC and IAR.
+* Added STM8 support to IAR and SDCC.
+* Added IDE project generators for IAR Embedded Workbench for ARM, AVR, 8051,
+ MSP430, and STM8 architectures.
+* Added IDE project generators for KEIL uVision v4 for ARM and 8051
+ architectures.
+* Added more bare metal project examples for various target platforms.
+* The IAR, KEIL and SDCC toolchains are now found automatically in various.
+ locations by the setup-toolchains command and by probes if no installPath is
+ set in the profile.
+
+# Infrastructure
+* Automated build and testing on Ubuntu, macOS and Windows.
+* Added Ubuntu bionic Docker image which replaces Debian stretch.
+* Updated Qt in the Ubuntu and Windows Docker images to 5.12.
+* When building Qbs, Qt libraries can now be bundled on Linux, macOS and
+ Windows.
+
+# Contributors
+* Alberto Mardegan <mardy@users.sourceforge.net>
+* Christian Kandeler <christian.kandeler@qt.io>
+* Denis Shienkov <denis.shienkov@gmail.com>
+* Ivan Komissarov <ABBAPOH@gmail.com>
+* Jochen Ulrich <jochenulrich@t-online.de>
+* Joerg Bornemann <joerg.bornemann@qt.io>
+* Richard Weickelt <richard@weickelt.de>
diff --git a/changelogs/changes-1.16.0.md b/changelogs/changes-1.16.0.md
new file mode 100644
index 000000000..23628b904
--- /dev/null
+++ b/changelogs/changes-1.16.0.md
@@ -0,0 +1,126 @@
+# General
+
+* A new freedesktop module helps UNIX application developers to follow the
+ freedesktop.org guidelines.
+* The Android module now allows resourcesDir, sourcesDir and assetsDir to be
+ specified as relative paths.
+* A new ConanfileProbe allows better and more flexible integration of Qbs and
+ the Conan package manager.
+* A new hostArchitecture property has been added to the qbs module.
+
+
+# Language
+
+* List properties in modules are now merged according to inter-module
+ dependencies. This is important when flags like cpp.staticLibraries are
+ contributed by multiple modules with dependencies between each other.
+ (QBS-1517).
+* Dependency matching of multiplexed products is now less strict and does not
+ require all multiplex properties to match. For instance, if product A is
+ multiplexed over qbs.architecture and qbs.buildVariant while product B is only
+ multiplexed over one of these axes, then Qbs no longer fails (QBS-1515).
+
+
+# C/C++ Support
+
+* The Renesas RL78 architecture is now supported in GCC and IAR and the
+ toolchains are auto-detected by qbs-setup-toolchains.
+* The Renesas RX as well as the RH850, V850, 78K are now supported in IAR and
+ the toolchains are auto-detected by qbs-setup-toolchains.
+* The MPLAB X32 GCC-based toolchain is now auto-detected on Windows.
+* Multiple occurrences of static libraries on the linker command line are now
+ pruned and the last instance always wins when using GCC or LLVM-based
+ toolchains. This avoids problems with excessively long linker command lines
+ (QBS-1273).
+* Clang-cl and MSVC toolchains use the compiler frontend instead of the linker
+ when linking. The old behavior can be restored by setting cpp.linkerMode to
+ "manual". This allows to use sanitizers with clang-cl by passing
+ "-fsanitise=xxx" via cpp.driverFlags (QBS-1522).
+* The clang-cl toolchain now uses "link.exe" as the default linker.
+ "lld-link.exe" can be explicitly selected by setting cpp.linkerVariant to
+ "lld" (QBS-1522).
+* The MSVC, clang-cl and MinGW toolchains are now automatically detected if the
+ profile does not set an explicit installation location, for instance because
+ no profile was given.
+* Installation of separate debug information can now be enabled and configured
+ by simply setting the installDebugInformation and debugInformationInstallDir
+ properties in the Application and Library convenience items. This works for
+ toolchains based upon GCC, MSVC or clang-cl.
+* Xcode version 11.4 is now supported on macOS.
+
+
+# Qt Support
+
+* Qbs now supports Qt 5.14 for Android which comes as a multi-architecture
+ package. The qbs-setup-android tool has been updated accordingly (QBS-1497).
+* JSON metatype files generated by moc (Qt >= 5.15) are supported by setting
+ Qt.core.generateMetaTypesFile and Qt.core.metaTypesInstallDir (QBS-1531).
+* Pure debug builds of Qt (>= 5.14) with MinGW are now properly supported. They
+ don't have the 'd' suffix (QTBUG-80792).
+* The QML type declaration mechanism introduced in Qt 5.15 is now supported by
+ the Qt.qml module (QBS-1531).
+* Generated qmltypes files are now named according to the product's targetName
+ property (QTBUG-82710).
+
+
+# Documentation
+
+* The how-to chapter has been extended with sections about debugging Qbs files
+ and about building separate debug information in C++ projects.
+* The item and module reference documentation has been improved for the
+ cpp.libraryPaths, cpp.dynamicLibraries (QBS-1516), qbs.toolchainType and
+ qbs.toolchain properties as well as the Export item and the Library
+ convenience item.
+* Documentation for various path probes has been added (QBS-1187).
+* The README was extended and a CONTRIBUTING file has been added which provides
+ useful information for potential contributors. This is important for people
+ looking at our github mirror.
+
+
+# Infrastructure
+
+* The Debian Docker image has been removed.
+* We are now using ccache and clcache in our CI pipelines to shrink the build
+ time.
+* Clang-tidy is now used to identify potential problems in the code base and a
+ lot of action was taken upon a lot of findings.
+* A Docker image for testing Qbs with Android and Qt has been added.
+
+
+# Important Bug Fixes
+
+* Fix nullpointer access and heap-use-after-free error (QBS-1485).
+* Select the right instance when Depends.profiles is used on a dependency with
+ an aggregator product (QBS-1513).
+* Fix crash when specifying a non-existing profile in Depends.profiles
+ (QBS-1514).
+* Try harder to detect GCC toolchains in qbs-setup-toolchains (QBS-1524).
+* Code signing for Core Foundation Bundles on macOS has been fixed.
+* Automatic artifact scanning now prefers artifacts from product dependencies if
+ multiple candidates are found. This improves dependency tracking in complex
+ projects (QBS-1532).
+* The grpcIncludePath property in the probufcpp module has been fixed
+ (QBS-1542).
+* Qbs does no longer crash when accessing a property of a non-existent module in
+ "IDE mode".
+
+
+# Contributors
+
+* Alberto Mardegan
+* Björn Schäpers
+* BogDan Vatra
+* Christian Kandeler
+* Christian Stenger
+* Denis Shienkov
+* Ivan Komissarov
+* Jochen Ulrich
+* Joerg Bornemann
+* Leon Buckel
+* Marius Sincovici
+* Maximilian Goldstein
+* Mitch Curtis
+* Oliver Wolff
+* Orgad Shaneh
+* Raphaël Cotty
+* Richard Weickelt
diff --git a/doc/appendix/json-api.qdoc b/doc/appendix/json-api.qdoc
index f8840de37..207798ddd 100644
--- a/doc/appendix/json-api.qdoc
+++ b/doc/appendix/json-api.qdoc
@@ -402,17 +402,12 @@
\header \li Property \li Type \li Mandatory
\row \li error \li \l ErrorInfo \li no
\row \li failed-files \li \l FilePath list \li no
- \row \li project-data \li \l TopLevelProjectData \li no
\endtable
If the \c error property is present, the operation has at least
partially failed and \c failed-files will list the files
that could not be added or removed.
- If the project data has changed as a result of the operation
- (which it should unless the operation failed completely), then
- the \c project-data property will contain the updated project data.
-
\section1 The \c get-run-environment Message
This request retrieves the full run environment for a specific
diff --git a/doc/doc.qbs b/doc/doc.qbs
index dd8377c6c..8d7da8d04 100644
--- a/doc/doc.qbs
+++ b/doc/doc.qbs
@@ -1,6 +1,7 @@
import qbs 1.0
import qbs.File
import qbs.FileInfo
+import qbs.Probes
Project {
references: ["man/man.qbs"]
@@ -16,8 +17,15 @@ Project {
Depends { name: "qbsbuildconfig" }
Depends { name: "qbsversion" }
+ Probes.BinaryProbe {
+ id: pythonProbe
+ names: ["python3", "python"] // on Windows, there's no python3
+ }
+ property string _pythonExe: pythonProbe.found ? pythonProbe.filePath : undefined
+
files: [
- "../README",
+ "../README.md",
+ "../CONTRIBUTING.md",
"classic.css",
"external-resources.qdoc",
"fixnavi.pl",
@@ -58,9 +66,11 @@ Project {
outputFileTags: ["qdoc-html", "qbsdoc.dummy"] // TODO: Hack. Rule injection to the rescue?
outputArtifacts: [{filePath: "dummy", fileTags: ["qbsdoc.dummy"]}]
prepare: {
+ if (!product._pythonExe)
+ throw "Python executable was not found";
var scriptPath = explicitlyDependsOn["qbsdoc.fiximports"][0].filePath;
var htmlDir = FileInfo.path(FileInfo.path(inputs["qdoc-png"][0].filePath));
- var fixCmd = new Command("python", [scriptPath, htmlDir]);
+ var fixCmd = new Command(product._pythonExe, [scriptPath, htmlDir]);
fixCmd.description = "fixing bogus QML import statements";
return [fixCmd];
}
diff --git a/doc/fix-qmlimports.py b/doc/fix-qmlimports.py
index 93fdb437a..bb022d25b 100755
--- a/doc/fix-qmlimports.py
+++ b/doc/fix-qmlimports.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#############################################################################
##
## Copyright (C) 2017 The Qt Company Ltd.
@@ -121,7 +121,7 @@ if __name__ == '__main__':
if not (fileCount % progStep):
print('.', end='')
sys.stdout.flush()
- with open(html, 'r+') as file_:
+ with open(html, 'r+', encoding='utf8') as file_:
try:
soup = BeautifulSoup(file_, 'lxml')
actions = []
@@ -145,7 +145,7 @@ if __name__ == '__main__':
if 'lxml' in str(e):
print('(If using pip, try \"pip install lxml\")', file=sys.stderr)
quit(1)
- for k, v in modified.iteritems():
+ for k, v in modified.items():
print ('\n\t', k, 'in %d files' % v, end='')
pb = pre_blocks.get(k, 0)
if pb:
diff --git a/doc/howtos.qdoc b/doc/howtos.qdoc
index f394719e0..696c444cb 100644
--- a/doc/howtos.qdoc
+++ b/doc/howtos.qdoc
@@ -37,6 +37,8 @@
\list
\li \l{How do I build a Qt-based project?}
\li \l{How do I make my app build against my library?}
+ \li \l{How do I build release with debug information?}
+ \li \l{How do I separate and install debugging symbols?}
\li \l{How do I use precompiled headers?}
\li \l{How do I make sure my generated sources are getting compiled?}
\li \l{How do I run my autotests?}
@@ -48,6 +50,8 @@
\li \l{How do I make the state of my Git repository available to my source files?}
\li \l{How do I limit the number of concurrent jobs for the linker only?}
\li \l{How do I add QML files to a project?}
+ \li \l{How do I define a reusable Group of files that can be included in other \QBS files?}
+ \li \l{How do I print the value of a property?}
\endlist
\section1 How do I build a Qt-based project?
@@ -127,6 +131,89 @@
}
\endcode
+ \section1 How do I build release with debug information?
+
+ You can simply use the \c{"profiling"} \l{qbs::buildVariant}{qbs.buildVariant}:
+ \code
+ qbs build qbs.buildVariant:profiling
+ \endcode
+
+ \section1 How do I separate and install debugging symbols?
+
+ First, you need to set the \l{cpp::debugInformation}{cpp.debugInformation} and
+ \l{cpp::separateDebugInformation}{cpp.separateDebugInformation}
+ properties to \c true or use some conditional expression in your product:
+ \code
+ CppApplication {
+ // ...
+ cpp.debugInformation: qbs.buildVariant !== "release"
+ cpp.separateDebugInformation: true
+ }
+ \endcode
+
+ Now, you can install your \l{Application}{application}, \l{DynamicLibrary}{dynamic library}
+ or \l{LoadableModule}{loadable module} among with its debugging symbols as follows:
+ \code
+ CppApplication {
+ // ...
+ install: true
+ installDir: "bin"
+ installDebugInformation: true
+ debugInformationInstallDir: "bin"
+ }
+ \endcode
+
+ If you are not using \l{List of Convenience Items}{convenience items},
+ you can install debug symbols manually using the \l{Group} item. If the
+ \l{cpp::separateDebugInformation}{cpp.separateDebugInformation} property is set to \c true,
+ \QBS will create debugging symbols with the corresponding file tags
+ \c "debuginfo_app" (for an application), \c "debuginfo_dll" (for a dynamic library),
+ or \c "debuginfo_loadablemodule" (for a macOS plugin).
+
+ \code
+ Product {
+ type: "application"
+ Depends { name: "cpp" }
+ cpp.debugInformation: qbs.buildVariant !== "release"
+ cpp.separateDebugInformation: true
+ Group {
+ fileTagsFilter: cpp.separateDebugInformation ? ["debuginfo_app"] : []
+ qbs.install: true
+ qbs.installDir: "bin"
+ qbs.installSourceBase: buildDirectory
+ }
+ }
+ \endcode
+
+ If you're building a shared library, you need to use the \c "debuginfo_dll" tag instead:
+ \code
+ Product {
+ type: "dynamic_library"
+ // ...
+ Group {
+ fileTagsFilter: cpp.separateDebugInformation ? ["debuginfo_dll"] : []
+ qbs.install: true
+ qbs.installDir: "lib"
+ qbs.installSourceBase: buildDirectory
+ }
+ }
+ \endcode
+
+ If you're building a macOS plugin, you need to use the \c "debuginfo_loadablemodule"
+ tag instead:
+ \code
+ Product {
+ type: "loadablemodule"
+ // ...
+ Group {
+ fileTagsFilter: cpp.separateDebugInformation ? ["debuginfo_loadablemodule"] : []
+ qbs.install: true
+ qbs.installDir: "PlugIns"
+ qbs.installSourceBase: buildDirectory
+ }
+ }
+ \endcode
+
\section1 How do I use precompiled headers?
If you use a \l Group item to add a precompiled header file to a product
@@ -491,4 +578,96 @@
In the example above, we declare each QML file as having the
\l {filetags-qtcore}{"qt.core.resource_data"} file tag. This ensures
that it is added to a generated resource file.
+
+ \section1 How do I define a reusable Group of files that can be included in other \QBS files?
+
+ Suppose you have an application and tests for that application, and that
+ the project is structured in the following way:
+
+ \badcode
+ ├── app
+ │ ├── app.qbs
+ │ ├── ...
+ │ └── qml
+ │ └── ui
+ │ ├── AboutPopup.qml
+ │ └── ...
+ ├── my-project.qbs
+ └── tests
+ ├── tst_app.cpp
+ ├── ...
+ └── tests.qbs
+ \endcode
+
+ Both projects need access to the QML files used by the
+ application. To demonstrate how this can be done, we'll create a file
+ named \c qml-ui.qbs and put it in the \c app/qml/ui directory:
+
+ \code
+ Group {
+ prefix: path + "/"
+ fileTags: ["qt.qml.qml", "qt.core.resource_data"]
+ files: [
+ "AboutPopup.qml",
+ // ...
+ ]
+ }
+ \endcode
+
+ This Group is a variation of the one in the
+ \l {How do I add QML files to a project?}{section above}.
+
+ If no prefix is specified, the file names listed in the \c files property
+ are resolved relative to the \e importing product's (e.g. \c app.qbs)
+ directory. For that reason, we set the prefix to inform \QBS that the file
+ names should be resolved relative to the \e imported item instead:
+ \c qml-ui.qbs. Conveniently, this also means that we don't need to specify
+ the path prefix for each file.
+
+ The application can then import the file like so:
+
+ \code
+ import "qml/ui/qml-ui.qbs" as QmlUiFiles
+
+ QtGuiApplication {
+ // ...
+
+ files: "main.cpp"
+
+ QmlUiFiles {}
+ }
+ \endcode
+
+ The tests can use a relative path to import the file:
+
+ \code
+ import "../app/qml/ui/qml-ui.qbs" as QmlUiFiles
+
+ QtGuiApplication {
+ // ...
+
+ files: "tst_app.cpp"
+
+ QmlUiFiles {}
+ }
+ \endcode
+
+ \section1 How do I print the value of a property?
+
+ Use the \l {Console API}{console API}. For example, suppose your project
+ is not built the way you expect it to be, and you suspect that
+ \c qbs.targetOS has the wrong value:
+
+ \code
+ readonly property bool unix: qbs.targetOS.contains("unix")
+ \endcode
+
+ To find out the value of \c qbs.targetOS, use \c {console.info()}:
+
+ \code
+ readonly property bool unix: {
+ console.info("qbs.targetOS: " + qbs.targetOS)
+ return qbs.targetOS.contains("unix")
+ }
+ \endcode
*/
diff --git a/doc/qbs.qdoc b/doc/qbs.qdoc
index 852329f73..db9a64af4 100644
--- a/doc/qbs.qdoc
+++ b/doc/qbs.qdoc
@@ -352,12 +352,12 @@
Module {
// ...
Rule {
- inputs {"cpp"]
- Artifact [
+ inputs: ["cpp"]
+ Artifact {
filePath: input.fileName + ".o"
- fileTags: {"obj"]
+ fileTags: ["obj"]
}
- prepare: [
+ prepare: {
// g++ -c main.cpp -o main.o ...
}
}
@@ -592,7 +592,7 @@
is required to build against the \QBS libraries.
\row
\li enableBundledQt
- \li \c true
+ \li \c false
\li Holds whether the Qt libraries that \QBS depends on will be bundled with \QBS during
the \c install step. This option is only implemented on macOS.
\row
@@ -694,7 +694,7 @@
A set of Docker images for developing \QBS (which are maintained by the \QBS team) is available
\l{https://hub.docker.com/u/qbsbuild/}{on Docker Hub}.
- Both Windows Server Core and Debian Linux container types are available.
+ Both Windows 10 and Debian Linux container types are available.
\note The source code for the \QBS development Docker images is located in the \c{docker/}
directory of the \QBS source tree, if you wish to build them yourself.
@@ -712,45 +712,46 @@
\li Latest stable release of \QBS for building \QBS with \QBS
\endlist
- Run the following command to download the \QBS development image based on Ubuntu 18.04 \e Bionic:
+ We are using docker-compose for building and running the Docker images because it simplifies
+ the Docker command line and ensures that the correct image tag is used. All available images
+ are listed in the \c docker-compose.yml file in the project root directory.
+
+ Run the following command to download the \QBS development image based on Ubuntu 18.04
+ \e Bionic:
\code
- docker pull qbsbuild/qbsdev:bionic
+ docker-compose pull bionic
\endcode
You can then create a new container with the \QBS source directory mounted from your host
machine's file system, by running:
\code
- docker run -it -v ${PWD}:/qbs -w /qbs qbsbuild/qbsdev:bionic
- \endcode
-
- You will now be in an interactive Linux shell where you can develop and build \QBS.
-
- For convenience, you can also run \c docker-compose from the project root directory:
-
- \code
docker-compose run --rm bionic
\endcode
- This will download and run the container in one go and mount the project root directory
- to \c /qbs in the container.
+ You will now be in an interactive Linux shell where you can develop and build \QBS.
\section2 Windows Containers
To build \QBS for Windows using Windows containers, your host OS must be running Windows 10 Pro
- and have Hyper-V enabled. \l{https://docs.docker.com/docker-for-windows/#switch-between-windows-and-linux-containers}{Switch your Docker environment to use Windows containers}, then run the
- following command to download the Windows 10 \QBS development image:
+ and have Hyper-V enabled. \l{https://docs.docker.com/docker-for-windows/#switch-between-windows-and-linux-containers}{Switch your Docker environment to use Windows containers}.
+
+ We are using docker-compose for building and running the Docker images because it simplifies
+ the Docker command line and ensures that the correct image tag is used. All available images
+ are listed in the \c docker-compose.yml file in the project root directory.
+
+ Run the following command to download the \QBS development image based on Windows 10:
\code
- docker pull qbsbuild/qbsdev:windowsservercore
+ docker-compose pull windows
\endcode
You can then create a new container with the \QBS source directory mounted from your host
machine's file system, by running:
\code
- docker run -it -v %CD%:C:\qbs -w C:\qbs qbsbuild/qbsdev:windowsservercore
+ docker-compose run --rm windows
\endcode
If you want to use Windows containers on a macOS or Linux host, you will have to create a
@@ -764,7 +765,7 @@
\code
eval $(docker-machine env windows)
- docker run -it -v C:$PWD:C:\\qbs -w C:\\qbs qbsbuild/qbsdev:windowsservercore
+ docker-compose run --rm windows
\endcode
\section2 Building Release Packages
@@ -772,14 +773,14 @@
Release packages for \QBS for Windows can be built using the following command on Windows:
\code
- docker run --rm -v %CD%:C:\qbs -w C:\qbs qbsbuild/qbsdev:windowsservercore cmd /c scripts\make-release-archives
+ docker-compose run --rm windows cmd /c scripts\make-release-archives
\endcode
For building release packages for Windows on macOS or Linux:
\code
eval $(docker-machine env windows)
- docker run --rm -v C:$PWD:C:\\qbs -w C:\\qbs qbsbuild/qbsdev:windowsservercore cmd /c scripts\\make-release-archives
+ docker-compose run --rm windows cmd /c scripts\\make-release-archives
\endcode
*/
@@ -1614,6 +1615,8 @@
To introduce a custom item \c MyItem, create the file \c{search-path/imports/MyItem.qbs}.
+ \note Item file names must start with a capital letter due to the fact that type names can
+ only start with a capital letter. Otherwise, the file will be silently ignored.
\section1 Making \QBS Aware of Custom Modules and Items
diff --git a/doc/reference/commands.qdoc b/doc/reference/commands.qdoc
index d34c20cb7..655412c0a 100644
--- a/doc/reference/commands.qdoc
+++ b/doc/reference/commands.qdoc
@@ -124,9 +124,11 @@
\li Time limit for the command execution in seconds. If the command does not finish within
the timeout, it is cancelled. In case of a \c Command, the process is requested to
terminate. If it does not terminate within three seconds, it is killed. A value below
- or equal to 0 means no timeout.
+ or equal to 0 means no timeout. \br
+ This property was introduced in Qbs 1.15.
\endtable
+
\section2 Command Properties
\table
diff --git a/doc/reference/items/convenience/application.qdoc b/doc/reference/items/convenience/application.qdoc
index c09d15918..e92247f5f 100644
--- a/doc/reference/items/convenience/application.qdoc
+++ b/doc/reference/items/convenience/application.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
\contentspage list-of-convenience-items.html
- \previouspage AppleApplicationDiskImage
+ \previouspage AppleDiskImage
\nextpage ApplicationExtension
\qmltype Application
\inherits Product
@@ -49,7 +49,7 @@
\qmlproperty bool Application::install
If \c{true}, the executable that is produced when building the application will be installed
- to \l installDir.
+ to \l{Application::installDir}{installDir}.
\defaultvalue \c false
\since Qbs 1.13
@@ -58,8 +58,8 @@
/*!
\qmlproperty string Application::installDir
- Where to install the executable that is produced when building the application, if \l install
- is enabled.
+ Where to install the executable that is produced when building the application, if
+ \l{Application::install}{install} is enabled.
The value is appended to \l{qbs::installPrefix}{qbs.installPrefix}
when constructing the actual installation directory.
@@ -67,3 +67,28 @@
\defaultvalue \c Applications if the app is a \l{bundle::isBundle}{bundle}, \c bin otherwise.
\since Qbs 1.13
*/
+
+/*!
+ \qmlproperty string Application::installDebugInformation
+
+ If \c{true}, the debug information will be installed to
+ \l{Application::debugInformationInstallDir}{debugInformationInstallDir}.
+
+ \defaultvalue \c false
+ \since Qbs 1.16
+ \sa{How do I separate and install debugging symbols?}
+*/
+
+/*!
+ \qmlproperty string Application::debugInformationInstallDir
+
+ Where to install the debug information if \l installDebugInformation is enabled.
+
+ The value is appended to \l{qbs::installPrefix}{qbs.installPrefix}
+ when constructing the actual installation directory.
+
+ \defaultvalue \l installDir.
+ \since Qbs 1.16
+
+ \sa{How do I separate and install debugging symbols?}
+*/
diff --git a/doc/reference/items/convenience/autotestrunner.qdoc b/doc/reference/items/convenience/autotestrunner.qdoc
index e8690ffe2..616d6459f 100644
--- a/doc/reference/items/convenience/autotestrunner.qdoc
+++ b/doc/reference/items/convenience/autotestrunner.qdoc
@@ -69,6 +69,27 @@
\endcode
\endlist
+
+ \section2 Setting Properties for individual Tests
+ \target autotestrunner-autotest-module
+
+ To control the behavior of individual tests, some properties of the \c AutotestRunner
+ can be overridden by depending on the \l autotest module and setting its properties:
+
+ \code
+ CppApplication {
+ name: "tst_mytest"
+ type: ["application", "autotest"]
+
+ Depends { name: "autotest" }
+
+ autotest.timeout: 60
+
+ // ...
+ }
+ \endcode
+
+
\section2 Relevant Job Pools
\target autotestrunner-job-pools
@@ -147,3 +168,16 @@
\defaultvalue empty
*/
+
+/*!
+ \qmlproperty int AutotestRunner::timeout
+
+ Time limit for the execution of the individual tests. If a test does not finish within
+ the time limit, the test is cancelled and considered failed. A value below or equal to 0
+ means no timeout.
+ A test can override this by setting the \l{autotest::timeout}{timeout} property
+ of the \l autotest module.
+
+ \defaultvalue -1
+ \since Qbs 1.15
+*/
diff --git a/doc/reference/items/convenience/cppapplication.qdoc b/doc/reference/items/convenience/cppapplication.qdoc
index 13bd523b7..7e71eec41 100644
--- a/doc/reference/items/convenience/cppapplication.qdoc
+++ b/doc/reference/items/convenience/cppapplication.qdoc
@@ -29,14 +29,14 @@
\previouspage AutotestRunner
\nextpage DynamicLibrary
\qmltype CppApplication
- \inherits Product
+ \inherits Application
\inqmlmodule QbsConvenienceItems
\ingroup list-of-items
\keyword QML.CppApplication
\brief C++ application.
- A CppApplication is a \l{Product}{product} that has a dependency on the
+ A CppApplication is an \l{Application}{application} that has a dependency on the
\l{cpp} module. It is entirely equivalent to the following:
\code
diff --git a/doc/reference/items/convenience/dynamiclibrary.qdoc b/doc/reference/items/convenience/dynamiclibrary.qdoc
index 488aef3eb..18a11bf11 100644
--- a/doc/reference/items/convenience/dynamiclibrary.qdoc
+++ b/doc/reference/items/convenience/dynamiclibrary.qdoc
@@ -29,7 +29,7 @@
\previouspage CppApplication
\nextpage InnoSetup
\qmltype DynamicLibrary
- \inherits Product
+ \inherits Library
\inqmlmodule QbsConvenienceItems
\ingroup list-of-items
\keyword QML.DynamicLibrary
@@ -37,7 +37,7 @@
\brief Dynamic library.
- A DynamicLibrary item is a \l{Product} of the \l{Product::}{type}
+ A DynamicLibrary item is a \l{Library}{library} of the \l{Product::}{type}
\c "dynamiclibrary".
For Android targets, the following applies:
@@ -47,51 +47,3 @@
\li There is a dependency on the \l{cpp} and \l{Android.ndk} modules.
\endlist
*/
-
-/*!
- \qmlproperty bool DynamicLibrary::install
-
- If \c{true}, the library will be installed to \l installDir.
-
- \defaultvalue \c false
- \since Qbs 1.13
-*/
-
-/*!
- \qmlproperty string DynamicLibrary::installDir
-
- Where to install the library, if \l install is enabled. On Unix, the symbolic links
- are also installed to this location.
-
- The value is appended to \l{qbs::installPrefix}{qbs.installPrefix}
- when constructing the actual installation directory.
-
- \defaultvalue \c Library/Frameworks if the library is a \l{bundle::isBundle}{bundle},
- otherwise \c bin for Windows and \c lib for Unix-like targets.
- \since Qbs 1.13
-*/
-
-/*!
- \qmlproperty bool DynamicLibrary::installImportLib
-
- If \c{true}, the import library will be installed to \l importLibInstallDir.
- This property is only relevant for Windows targets.
- Enable it if you want to create a development package.
-
- \defaultvalue \c false
- \since Qbs 1.13
-*/
-
-/*!
- \qmlproperty string DynamicLibrary::importLibInstallDir
-
- Where to install the import library, if \l installImportLib is enabled.
-
- The value is appended to \l{qbs::installPrefix}{qbs.installPrefix}
- when constructing the actual installation directory.
-
- This property is only relevant for Windows targets.
-
- \defaultvalue \c lib
- \since Qbs 1.13
-*/
diff --git a/doc/reference/items/convenience/javajarfile.qdoc b/doc/reference/items/convenience/javajarfile.qdoc
index 48643d80e..cda3e4ba0 100644
--- a/doc/reference/items/convenience/javajarfile.qdoc
+++ b/doc/reference/items/convenience/javajarfile.qdoc
@@ -27,7 +27,7 @@
/*!
\contentspage list-of-convenience-items.html
\previouspage JavaClassCollection
- \nextpage LoadableModule
+ \nextpage Library
\qmltype JavaJarFile
\inherits Product
\inqmlmodule QbsConvenienceItems
diff --git a/doc/reference/items/convenience/library.qdoc b/doc/reference/items/convenience/library.qdoc
new file mode 100644
index 000000000..fc3a75640
--- /dev/null
+++ b/doc/reference/items/convenience/library.qdoc
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \contentspage list-of-convenience-items.html
+ \previouspage JavaJarFile
+ \nextpage LoadableModule
+ \qmltype Library
+ \since Qbs 1.4
+ \inherits Product
+ \inqmlmodule QbsConvenienceItems
+ \ingroup list-of-items
+ \keyword QML.NativeBinary
+
+ \brief Generic library.
+
+ A Library item is a base item for native libraries and can have \l{Product::}{type} set to
+ one of the following values: \c "dynamiclibrary", \c "staticlibrary", \c "loadablemodule".
+
+ The default \l{Product::}{type} value is \c "dynamiclibrary" except for iOS prior to
+ version 8, in which case the default value is \c "staticlibrary".
+
+ This item can automatically install the library target (and library symlinks on Unix) and
+ separated debug information.
+
+ For Android targets, the following applies:
+ \list
+ \li The \l{Product::type}{Product.type} property value contains
+ \c "android.nativelibrary" in addition to \c "dynamiclibrary".
+ \li There is a dependency on the \l{cpp} and \l{Android.ndk} modules.
+ \endlist
+*/
+
+/*!
+ \qmlproperty bool Library::install
+
+ If \c{true}, the library will be installed to \l{Library::installDir}{installDir}.
+
+ \defaultvalue \c false
+ \since Qbs 1.13
+*/
+
+/*!
+ \qmlproperty string Library::installDir
+
+ Where to install the library, if \l{Library::install}{install} is enabled. On Unix,
+ the symbolic links are also installed to this location.
+
+ The value is appended to \l{qbs::installPrefix}{qbs.installPrefix}
+ when constructing the actual installation directory.
+
+ \defaultvalue \c Library/Frameworks if the library is a \l{bundle::isBundle}{bundle},
+ otherwise \c bin for Windows and \c lib for Unix-like targets.
+ \since Qbs 1.13
+*/
+
+/*!
+ \qmlproperty string Library::installDebugInformation
+
+ If \c{true}, the debug information will be installed to
+ \l{Library::debugInformationInstallDir}{debugInformationInstallDir}.
+
+ \defaultvalue \c false
+ \since Qbs 1.16
+ \sa{How do I separate and install debugging symbols?}
+*/
+
+/*!
+ \qmlproperty string Library::debugInformationInstallDir
+
+ Where to install the debug information if \l installDebugInformation is enabled.
+
+ The value is appended to \l{qbs::installPrefix}{qbs.installPrefix}
+ when constructing the actual installation directory.
+
+ \defaultvalue \l installDir.
+ \since Qbs 1.16
+
+ \sa{How do I separate and install debugging symbols?}
+*/
+
+/*!
+ \qmlproperty bool Library::installImportLib
+
+ If \c{true}, the import library will be installed to \l importLibInstallDir.
+ This property is only relevant for Windows targets.
+ Enable it if you want to create a development package.
+
+ \defaultvalue \c false
+ \since Qbs 1.13
+*/
+
+/*!
+ \qmlproperty string Library::importLibInstallDir
+
+ Where to install the import library, if \l installImportLib is enabled.
+
+ The value is appended to \l{qbs::installPrefix}{qbs.installPrefix}
+ when constructing the actual installation directory.
+
+ This property is only relevant for Windows targets.
+
+ \defaultvalue \c lib
+ \since Qbs 1.13
+*/
+
diff --git a/doc/reference/items/convenience/loadablemodule.qdoc b/doc/reference/items/convenience/loadablemodule.qdoc
index d02dbae1c..76022350d 100644
--- a/doc/reference/items/convenience/loadablemodule.qdoc
+++ b/doc/reference/items/convenience/loadablemodule.qdoc
@@ -27,10 +27,10 @@
****************************************************************************/
/*!
\contentspage list-of-convenience-items.html
- \previouspage JavaJarFile
+ \previouspage Library
\nextpage QtApplication
\qmltype LoadableModule
- \inherits Product
+ \inherits Library
\inqmlmodule QbsConvenienceItems
\ingroup list-of-items
\keyword QML.LoadableModule
diff --git a/doc/reference/items/convenience/qtapplication.qdoc b/doc/reference/items/convenience/qtapplication.qdoc
index 09640a8c1..21041c4cd 100644
--- a/doc/reference/items/convenience/qtapplication.qdoc
+++ b/doc/reference/items/convenience/qtapplication.qdoc
@@ -42,7 +42,7 @@
\code
CppApplication {
- Depends { name: "Qt.core" } }
+ Depends { name: "Qt.core" }
}
\endcode
diff --git a/doc/reference/items/convenience/staticlibrary.qdoc b/doc/reference/items/convenience/staticlibrary.qdoc
index cd459cf6e..eeaba0639 100644
--- a/doc/reference/items/convenience/staticlibrary.qdoc
+++ b/doc/reference/items/convenience/staticlibrary.qdoc
@@ -29,35 +29,13 @@
\previouspage QtGuiApplication
\nextpage XPCService
\qmltype StaticLibrary
- \inherits Product
+ \inherits Library
\inqmlmodule QbsConvenienceItems
\ingroup list-of-items
\keyword QML.StaticLibrary
\brief Static library.
- A StaticLibrary item is a \l{Product}{product} of the \l{Product::}{type}
+ A StaticLibrary item is a \l{Library}{library} of the \l{Product::}{type}
\c "staticlibrary".
*/
-
-/*!
- \qmlproperty bool StaticLibrary::install
-
- If \c{true}, the library will be installed to \l installDir.
-
- \defaultvalue \c false
- \since Qbs 1.13
-*/
-
-/*!
- \qmlproperty string StaticLibrary::installDir
-
- Where to install the library, if \l install is enabled.
-
- The value is appended to \l{qbs::installPrefix}{qbs.installPrefix}
- when constructing the actual installation directory.
-
- \defaultvalue \c Library/Frameworks if the library is a \l{bundle::isBundle}{bundle},
- \c lib otherwise.
- \since Qbs 1.13
-*/
diff --git a/doc/reference/items/language/export.qdoc b/doc/reference/items/language/export.qdoc
index d8ed4c33d..433b4ca83 100644
--- a/doc/reference/items/language/export.qdoc
+++ b/doc/reference/items/language/export.qdoc
@@ -56,16 +56,45 @@
}
\endcode
- The sources in product B will be able to use headers from product A without specifiying
+ The sources in product B will be able to use headers from product A without specifying
the full path to them, because the include path has been made known to the compiler via
A's Export item. Additionally, product B will be compiled with the define \c{USING_A}.
- \note This relationship is transitive, so a product C depending on product B will also
- get the include paths and preprocessor macros via A's Export item.
+ The dependent \l{Product}'s modules are not exported unless explicitly specified within the
+ \l{Export} item:
+ \code
+ Product {
+ name: "B-Exporting-A"
+ Depends { name: "A" }
+ Export {
+ Depends { name: "A" }
+ }
+ }
+ \endcode
+
+ The relationship of the exported dependencies is transitive. A product C depending on a
+ product B-Exporting-A will also get a direct dependency on A and thus inherit include
+ paths and preprocessor macros exported by A.
+
+ \code
+ Product {
+ name: "C"
+ Depends { name: "B-Exporting-A" }
+ }
+ \endcode
In contrast to Module items, \c{product} within Export items refers to the product which defines
the Export item. Use the \c{importingProduct} variable to refer to the product that
- pulls in the resulting module.
+ pulls in the resulting module:
+ \code
+ Product {
+ name: "D"
+ Export {
+ Depends { name: "cpp" }
+ cpp.includePaths: [product.sourceDirectory, importingProduct.buildDirectory]
+ }
+ }
+ \endcode
*/
/*!
diff --git a/doc/reference/items/probe/conanfile-probe.qdoc b/doc/reference/items/probe/conanfile-probe.qdoc
new file mode 100644
index 000000000..191d7c894
--- /dev/null
+++ b/doc/reference/items/probe/conanfile-probe.qdoc
@@ -0,0 +1,250 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Richard Weickelt
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \contentspage list-of-probes.html
+ \qmltype ConanfileProbe
+ \ingroup list-of-probes
+ \ingroup list-of-items
+ \inqmlmodule QbsLanguageItems
+ \keyword QML.ConanfileProbe
+
+ \brief Extracts information about dependencies from a Conan recipe file.
+
+ The \c ConanfileProbe interfaces \QBS to the \l{https://conan.io/}{Conan
+ package manager}. It runs
+ \l{https://docs.conan.io/en/latest/reference/commands/consumer/install.html}{conan
+ install} on a Conan recipe file such as \c conanfile.py or \c conanfile.txt
+ and extracts all available meta information about package dependencies using
+ the \l{https://docs.conan.io/en/latest/reference/generators/json.html}{json
+ generator}. The output may be used to set up \l{Profile} items or module
+ properties in products. \c ConanfileProbe can also be used to run other
+ Conan generators and to retrieve their output.
+
+ \section1 Examples
+
+ In the following examples we assume that our project contains a \c conanfile.py.
+ This file describes all dependencies of our project. The dependency packages are
+ expected to export meta information to be consumed by our project.
+
+ \section2 Including Files Generated by Conan
+
+ Conan has a built-in
+ \l{https://docs.conan.io/en/latest/reference/generators/qbs.html}{qbs
+ generator} that creates a project file containing dummy products. This is
+ the easiest way to access dependencies, but also the least flexible one. It
+ requires each Conan package to export correct meta information and works only
+ if the dependency is a library.
+
+ \qml
+ import qbs.Probes
+
+ Project {
+ Probes.ConanfileProbe {
+ id: conan
+ conanfilePath: project.sourceDirectory + "/conanfile.py"
+ generators: "qbs"
+ }
+
+ references: conan.generatedFilesPath + "/conanbuildinfo.qbs"
+
+ CppApplication {
+ type: "application"
+ files: "main.cpp"
+ Depends { name: "mylib" }
+ }
+ }
+ \endqml
+
+ \section2 Setting Module Properties in Products
+
+ When a product depends on a Conan package that does not have a
+ dedicated \l{List of Modules}{module}, package meta information may be
+ directly fed into the \l{cpp} module.
+
+ This approach is very flexible.
+
+ \qml
+ import qbs.Probes
+
+ CppApplication {
+ Probes.ConanfileProbe {
+ id: conan
+ conanfilePath: product.sourceDirectory + "/conanfile.py"
+ options: ({opt1: "True"; opt2: "TheValue"})
+ }
+ cpp.includePaths: conan.dependencies["myLib"].include_paths
+ cpp.libraryPaths: conan.dependencies["myLib"].lib_paths
+ cpp.dynamicLibraries: conan.dependencies["mylib"].libs
+ }
+ \endqml
+
+ \section2 Setting Up a Profile
+
+ When multiple products depend on one or more Conan packages, the dependency
+ information may be combined in a \l{Profile}. This is especially useful when
+ \QBS modules are available for some of the packages, but some of their
+ properties need to be initialized. Otherwise, it would have to be done
+ manually in global profiles.
+
+ \qml
+ import qbs.Probes
+
+ Project {
+ Probes.ConanfileProbe {
+ id: conan
+ conanfilePath: project.sourceDirectory + "/conanfile.py"
+ }
+ Profile {
+ name: "arm-gcc"
+ cpp.toolchainInstallPath: conan.dependencies["arm-none-eabi-gcc"].rootpath + "/bin"
+ cpp.toolchainPrefix: "arm-linux-gnueabi-"
+ qbs.toolchainType: "gcc"
+ }
+ }
+ \endqml
+
+ This allows fully automated dependency management, including compiler
+ toolchains and is very useful when teams work in heterougeneous
+ environments.
+
+*/
+
+/*!
+ \qmlproperty stringList ConanfileProbe::additionalArguments
+
+ Additional command line arguments that are appended to the \c{conan install}
+ command.
+
+ \defaultvalue []
+*/
+
+/*!
+ \qmlproperty path ConanfileProbe::conanfilePath
+
+ Path to a \c conanfile.py or \c conanfile.txt that is used by this probe.
+
+ This property cannot be set at the same time as \l{ConanfileProbe::}{packageReference}.
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty var ConanfileProbe::dependencies
+
+ This property contains the same information as
+ \l{ConanfileProbe::}{json}.dependencies, but instead of an array, \c
+ dependencies is a map with package names as keys for convenient access.
+
+ \readonly
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty path ConanfileProbe::executable
+
+ The name of or the path to the Conan executable.
+
+ \defaultvalue "conan.exe" on Windows, "conan" otherwise
+*/
+
+/*!
+ \qmlproperty path ConanfileProbe::generatedFilesPath
+
+ The path of the folder where Conan generators store their files. Each
+ instance of this probe creates a unique folder under
+ \l{Project::buildDirectory}{Project.buildDirectory}. The folder name is a
+ hash of the arguments supplied to \c{conan install}.
+
+ \readonly
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty stringList ConanfileProbe::generators
+
+ Conan generators to be executed by this probe. The
+ \l{https://docs.conan.io/en/latest/reference/generators/json.html}{JSON
+ generator} is always enabled. Generated files are written to the
+ \l{ConanfileProbe::generatedFilesPath}{generatedFilesPath} folder.
+
+ \sa {https://docs.conan.io/en/latest/reference/generators.html}{Available
+ generators}
+
+ \defaultvalue ["json"]
+*/
+
+/*!
+ \qmlproperty var ConanfileProbe::json
+
+ The parsed output of Conan's
+ \l{https://docs.conan.io/en/latest/reference/generators/json.html}{JSON
+ generator} as a JavaScript object.
+
+ \readonly
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty var ConanfileProbe::options
+
+ Options applied to \c{conan install} via the \c{-o} flag.
+ This property is an object in the form \c{key:value}.
+
+ Example:
+ \qml
+ options: ({someOpt: "True", someOtherOpt: "TheValue"})
+ \endqml
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty string ConanfileProbe::packageReference
+
+ Reference of a Conan package in the form \c{name/version@user/channel}.
+ Use this property if you want to probe an existing package in the local
+ cache or on a remote.
+
+ This property cannot be set at the same time as \l{ConanfileProbe::}{conanfilePath}.
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty var ConanfileProbe::settings
+
+ Settings applied to \c{conan install} via the \c{-s} flag.
+ This property is an object in the form \c{key:value}.
+
+ Example:
+ \qml
+ settings: ({os: "Linux", compiler: "gcc"})
+ \endqml
+
+ \nodefaultvalue
+*/
diff --git a/doc/reference/items/probe/library-probe.qdoc b/doc/reference/items/probe/library-probe.qdoc
new file mode 100644
index 000000000..2d1e35a51
--- /dev/null
+++ b/doc/reference/items/probe/library-probe.qdoc
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \contentspage list-of-probes.html
+ \qmltype LibraryProbe
+ \ingroup list-of-probes
+ \ingroup list-of-items
+ \keyword QML.IncludeProbe
+ \inherits PathProbe
+
+ \brief Locates library files outside the project.
+
+ On Windows, searches for library files within directories specified by the \c PATH environment
+ variable.
+
+ On Unix, searches for library files within directories specified by the \c LIBRARY_PATH
+ environment variable, as well as in \c "/usr/lib" and \c "/usr/local/lib".
+
+ On Linux, also searches in platform-specific directories, such as \c "/usr/lib64" and
+ \c "/usr/lib/x86_64-linux-gnu".
+
+ For example, LibraryProbe can be used to search for a \c zlib library as follows:
+
+ \code
+ import qbs.Probes
+
+ CppApplication {
+ Probes.LibraryProbe {
+ id: zlibProbe
+ names: "z"
+ }
+ cpp.libraryPaths: zlibProbe.found ? [zlibProbe.path] : []
+ cpp.dynamicLibraries: zlibProbe.found ? [zlibProbe.names] : []
+ files: 'main.cpp'
+ }
+ \endcode
+*/
diff --git a/doc/reference/items/probe/path-probe.qdoc b/doc/reference/items/probe/path-probe.qdoc
index eaaee9e54..936ce3180 100644
--- a/doc/reference/items/probe/path-probe.qdoc
+++ b/doc/reference/items/probe/path-probe.qdoc
@@ -81,7 +81,7 @@
For example, when searching for a library, it might be necessary to check its architecture:
\code
PathProbe {
- pathSuffixes: ["*.so", *.dll]
+ pathSuffixes: [".so", ".dll", ".dylib"]
candidateFilter: {
function getLibraryArchitecture(file) { ... }
return function(file) {
@@ -169,6 +169,24 @@
This property contains the result list of all paths that were checked before a file was found
(including the file names).
+ This property is set even if the Probe didn't find anything and can be used to give the user
+ a hint what went wrong:
+ \code
+ Module {
+ Probes.BinaryProbe {
+ id: pythonProbe
+ names: "python"
+ }
+ validate: {
+ if (!pythonProbe.found) {
+ throw ModUtils.ModuleError(
+ "Could not find python binary at any of the following locations:\n\t" +
+ pythonProbe.candidatePaths.join("\n\t"));
+ }
+ }
+ }
+ \endcode
+
\nodefaultvalue
*/
diff --git a/doc/reference/modules/android-sdk-module.qdoc b/doc/reference/modules/android-sdk-module.qdoc
index 7733ae75d..2c2e43eab 100644
--- a/doc/reference/modules/android-sdk-module.qdoc
+++ b/doc/reference/modules/android-sdk-module.qdoc
@@ -119,7 +119,7 @@
*/
/*!
- \qmlproperty string Android.sdk::assetsDir
+ \qmlproperty path Android.sdk::assetsDir
The base directory for Android assets in the respective product.
@@ -201,7 +201,7 @@
*/
/*!
- \qmlproperty string Android.sdk::resourcesDir
+ \qmlproperty path Android.sdk::resourcesDir
The base directory for Android resources in the respective product.
diff --git a/doc/reference/modules/autotest-module.qdoc b/doc/reference/modules/autotest-module.qdoc
index ddd9e0078..e25be6211 100644
--- a/doc/reference/modules/autotest-module.qdoc
+++ b/doc/reference/modules/autotest-module.qdoc
@@ -67,3 +67,14 @@
\nodefaultvalue
*/
+/*!
+ \qmlproperty int autotest::timeout
+
+ The time limit for the execution of the autotest. If not specified, the
+ \l{AutotestRunner::timeout}{timeout} property of the \l AutotestRunner
+ that invokes the autotest is used.
+
+ \nodefaultvalue
+ \since Qbs 1.15
+*/
+
diff --git a/doc/reference/modules/cpp-module.qdoc b/doc/reference/modules/cpp-module.qdoc
index 64a7c071f..ff8c0172e 100644
--- a/doc/reference/modules/cpp-module.qdoc
+++ b/doc/reference/modules/cpp-module.qdoc
@@ -390,6 +390,8 @@
\defaultvalue \c{true} for MSVC and with GCC or Clang on Apple platforms,
otherwise \c{false}.
+
+ \sa debugInformation, {How do I separate and install debugging symbols?}
*/
/*!
@@ -457,10 +459,16 @@
A list of library search paths.
+ The paths will be passed to the linker in the appropriate way. For
+ example, the \c {-L} argument will be used when using \c {ld}-like
+ linkers.
+
Relative paths are considered to be relative to the \c .qbs product file
they are used in.
\nodefaultvalue
+
+ \sa dynamicLibraries, {How do I create a module for a third-party library?}
*/
/*!
@@ -471,7 +479,21 @@
If the library is part of your project, consider using a \l{Depends} item
instead.
+ Each library can be specified in one of two ways:
+
+ \list
+ \li An absolute file path (for example, \c "/foo/bar.lib"), in which case
+ it is passed directly to the linker, ignoring \l libraryPaths.
+ \li A library basename (for example, \c "bar"), in which case
+ the directory that contains the library must be provided via
+ \l libraryPaths.
+ \endlist
+
+ Relative paths (\c "foo/bar.lib") are not allowed.
+
\nodefaultvalue
+
+ \sa libraryPaths, {How do I create a module for a third-party library?}
*/
/*!
@@ -593,6 +615,15 @@
*/
/*!
+ \qmlproperty string cpp::compilerVersion
+
+ Compiler version string consisting of major, minor and patch numbers,
+ separated by a dot.
+
+ \nodefaultvalue
+*/
+
+/*!
\qmlproperty int cpp::compilerVersionMajor
\since Qbs 1.4
@@ -1197,8 +1228,6 @@
\qmlproperty string cpp::linkerMode
\since Qbs 1.6
- \unixproperty
-
Controls whether to automatically use an appropriate compiler frontend
instead of the system linker when linking binaries.
@@ -1217,12 +1246,12 @@
\qmlproperty string cpp::linkerVariant
\since Qbs 1.13
- \unixproperty
-
- Set this property to force the use of a specific \c ld implementation. A non-empty value
- will result in the \c {-fuse-ld} option being emitted when linking with \c gcc or \c clang.
+ Set this property to force the use of a specific linker. A non-empty value
+ will result in the \c {-fuse-ld} option being emitted when linking with \c gcc,
+ \c clang or \c clang-cl.
- The possible values are \c "bfd", \c "gold" and \c "lld".
+ The possible values for \c clang and \c gcc are \c "bfd", \c "gold" and \c "lld",
+ the possible values for \c clang-cl are \c "link" and \c "lld".
\nodefaultvalue
*/
diff --git a/doc/reference/modules/freedesktop-module.qdoc b/doc/reference/modules/freedesktop-module.qdoc
new file mode 100644
index 000000000..48c95a0e0
--- /dev/null
+++ b/doc/reference/modules/freedesktop-module.qdoc
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Alberto Mardegan
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \contentspage index.html
+ \qmltype freedesktop
+ \inqmlmodule QbsModules
+ \since Qbs 1.16
+
+ \brief Provides support for some freedesktop.org specifications.
+
+ The \c freedesktop module contains properties and rules for building and working with
+ applications compliant to freedesktop.org specifications on UNIX platforms.
+ The areas in which this module can be of use include:
+
+ \list
+ \li Creation or post-processing of
+ \l{https://specifications.freedesktop.org/desktop-entry-spec/latest/}{\c{.desktop}
+ files}
+ \li Installation of \l{https://www.freedesktop.org/software/appstream/docs/chap-Metadata.html}{AppStream} metadata
+ \li Defining the location for
+ \l{https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#directory_layout}
+ {application icons}
+ \endlist
+
+ This module is available on all platforms but is currently only useful on UNIX platforms.
+
+ \section2 Example usage
+ \target example-freedesktop
+
+ \code
+ Application {
+ ...
+ Depends { name: "freedesktop" }
+
+ Group {
+ files: [
+ ...
+
+ // Declare the desktop and appstream files
+ "data/my-app.desktop",
+ "data/my-app.metainfo.xml",
+ ]
+ }
+
+ // Add/change some fields in the desktop file
+ freedesktop.desktopKeys: ({
+ 'Exec': FileInfo.joinPaths(qbs.installPrefix,
+ product.installDir,
+ product.targetName) + ' --argument',
+ 'X-Application-Version': product.version,
+ })
+
+ // Declare the application icon
+ Group {
+ files: "icons/my-application.svg"
+ fileTags: "freedesktop.appIcon"
+ }
+ }
+ \endcode
+
+ \section2 Relevant File Tags
+ \target filetags-freedesktop
+
+ \table
+ \header
+ \li Tag
+ \li Auto-tagged File Names
+ \li Since
+ \li Description
+ \row
+ \li \c{"freedesktop.desktopfile_source"}
+ \li \c{*.desktop}
+ \li 1.16
+ \li A source file with this tag is a \c{.desktop} file or fragment that
+ will be merged into the application's final \c{.desktop} file.
+ \row
+ \li \c{"freedesktop.desktopfile"}
+ \li -
+ \li 1.16
+ \li Attached to the output artifacts of the rule that produces the
+ merged \c{.desktop} file.
+ \row
+ \li \c{"freedesktop.appstream"}
+ \li \c{*.metainfo.xml}, \c{*.appdata.xml}
+ \li 1.16
+ \li Source files with this tag are AppStream metadata files which will
+ be installed under \l{qbs::}{installPrefix}\c{/share/metainfo}
+ \row
+ \li \c{"freedesktop.appIcon"}
+ \li -
+ \li 1.16
+ \li Source files with this tag are application icons and will be
+ installed under \l{qbs::}{installPrefix}\c{/share/icons/hicolor/scalable/apps}
+ \endtable
+*/
+
+/*!
+ \qmlproperty string freedesktop::name
+
+ The display name of the application which will be stored in the \c{.desktop} file.
+
+ \defaultvalue \l{Product::name}{product.name}
+*/
+
+/*!
+ \qmlproperty var freedesktop::desktopKeys
+
+ A dictionary of key-value pairs to add to the application's \c{.desktop}
+ file.
+
+ The contents of this property will be aggregated with the values from any
+ \c{.desktop} file. If this property and any \c{.desktop} files contain the
+ same key, this property will take precedence.
+
+ \nodefaultvalue
+*/
diff --git a/doc/reference/modules/qbs-module.qdoc b/doc/reference/modules/qbs-module.qdoc
index c1a0b2532..ac4633d00 100644
--- a/doc/reference/modules/qbs-module.qdoc
+++ b/doc/reference/modules/qbs-module.qdoc
@@ -113,11 +113,13 @@
The name of the build variant for the current build.
- Possible values are \c{"debug"} and \c{"release"}. A debug build usually
- contains additional debug symbols that are needed for debugging the
- application but that can be left out from the release version. Debug builds
- are used for testing and release builds for creating the final installation
- file.
+ Possible values are \c{"debug"}, \c{"release"} and \c{"profiling"}.
+ A debug build usually contains additional debug symbols that are needed for
+ debugging the application and has optimizations turned off. A profiling
+ build usually contains debug symbols and has optimizations turned on. This
+ is useful for profiling tools or when you need to retain debug symbols
+ in a release build. A release build is a build without debug information and
+ with optimizations enabled.
\defaultvalue \c{"release"} if
\l{qbs::configurationName}{qbs.configurationName} is \c{"release"}. Otherwise
@@ -129,7 +131,8 @@
Whether to generate debug information.
- \defaultvalue \c{true} for debug builds, \c{false} otherwise.
+ \defaultvalue \c{true} if \l{qbs::buildVariant}{qbs.buildVariant} is \c{"debug"} or
+ \c{"profiling"}. Otherwise \c{false}.
*/
/*!
@@ -151,7 +154,7 @@
\endlist
Typically, this property is enabled for debug builds and disabled for
- release builds.
+ release or profiling builds.
\defaultvalue \c{true} for debug builds, \c{false} otherwise.
*/
@@ -169,11 +172,12 @@
\li \c{"small"}
\endlist
- \defaultvalue \c{"none"} for debug builds, \c{"fast"} for release builds.
+ \defaultvalue \c{"none"} if \l{qbs::buildVariant}{qbs.buildVariant} is \c{"debug"}.
+ Otherwise \c{"fast"}.
*/
/*!
- \qmlproperty stringList qbs::targetPlatform
+ \qmlproperty string qbs::targetPlatform
\since 1.11
The OS you want to build the project for.
@@ -255,6 +259,9 @@
\li \c{"tvos-simulator"}
\li \c{["tvos-simulator", "tvos", "darwin", "bsd", "unix"]}
\row
+ \li \c{"unix"}
+ \li \c{["unix"]}
+ \row
\li \c{"vxworks"}
\li \c{["vxworks"]}
\row
@@ -266,6 +273,9 @@
\row
\li \c{"windows"}
\li \c{["windows"]}
+ \row
+ \li \c{undefined}
+ \li \c{[]}
\endtable
\sa {Target Platforms}
@@ -285,20 +295,130 @@
Commonly used values are: \c{"x86"}, \c{"x86_64"}, and \c{"arm"}.
+ \section2 Supported Processor Architectures
+
+ This table describes the possible values of the \l{qbs::}{architecture} property:
+ \table
+ \header
+ \li Architecture
+ \li Description
+ \row
+ \li \c{"78k"}
+ \li 16- and 8-bit accumulator-based register-bank CISC architecture
+ microcontroller family manufactured by Renesas Electronics
+ \row
+ \li \c{"arm"}
+ \li 32-bit RISC architecture for computer processors
+ developed by Acorn RISC Machine
+ \note There are a lot of sub-variants of the ARM architecture.
+ Some specialized \QBS modules differentiate between them,
+ making use of values such as \c "armv7a". Please consult the
+ respective module-specific documentation for information
+ on what kind of value to use.
+ \row
+ \li \c{"arm64"}
+ \li 64-bit RISC architecture for computer processors
+ developed by Acorn RISC Machine
+ \row
+ \li \c{"avr"}
+ \li 8-bit modified Harvard RISC architecture microcontroller
+ family manufactured by Microchip Technology
+ \row
+ \li \c{"avr32"}
+ \li 32-bit RISC architecture microcontroller family developed by Atmel
+ \row
+ \li \c{"ia64"}
+ \li 64-bit ISA architecture of the Itanium family processors
+ developed by Intel
+ \row
+ \li "mcs51"}
+ \li 8-bit Harvard architecture microcontroller family developed by Intel
+ \row
+ \li \c{"mips"}
+ \li 32-bit RISC microprocessor without interlocked pipelined stages
+ architecture developed by MIPS Computer Systems
+ \row
+ \li \c{"mips64"}
+ \li 64-bit RISC microprocessor without interlocked pipelined stages
+ architecture developed by MIPS Computer Systems
+ \row
+ \li \c{"msp430"}
+ \li 16-bit mixed-signal microcontroller family manufactured
+ by Texas Instruments
+ \row
+ \li \c{"ppc"}
+ \li 32-bit RISC architecture processor family developed by
+ Apple–IBM–Motorola alliance
+ \row
+ \li \c{"ppc64"}
+ \li 64-bit RISC architecture processor family developed by
+ Apple–IBM–Motorola alliance
+ \row
+ \li \c{"rh850"}
+ \li 32-bit automotive microcontroller family manufactured
+ by Renesas Electronics
+ \row
+ \li \c{"rl78"}
+ \li 16- and 8-bit accumulator-based register-bank CISC architecture
+ with 3-stage instruction pipelining microcontroller family manufactured
+ by Renesas Electronics
+ \row
+ \li \c{"rx"}
+ \li High performance 32-bit CISC microcontroller family manufactured
+ by Renesas Electronics
+ \row
+ \li \c{"s390x"}
+ \li 64- and 32-bit System/390 processor architecture developed by IBM
+ \row
+ \li \c{"sparc"}
+ \li 32-bit RISC architecture processor family developed by
+ Sun Microsystems and Fujitsu
+ \row
+ \li \c{"sparc64"}
+ \li 64-bit RISC architecture processor family developed by
+ Sun Microsystems and Fujitsu
+ \row
+ \li \c{"stm8"}
+ \li 8-bit microcontroller family manufactured by STMicroelectronics
+ \row
+ \li \c{"v850"}
+ \li 32-bit RISC microcontroller family manufactured by Renesas Electronics
+ \row
+ \li \c{"x86"}
+ \li 32-bit ISA architecture processor family developed by Intel
+ \row
+ \li \c{"x86_64"}
+ \li 64-bit ISA architecture processor family developed by AMD
+ \endtable
+
\nodefaultvalue
*/
/*!
- \qmlproperty string qbs::toolchainType
- \since Qbs 1.11
+ \qmlproperty stringList qbs::toolchain
- The toolchain that is going to be used for this build.
+ Contains the list of string values describing the toolchain and toolchain
+ family that is used to build a project.
- You should generally treat this property as \e{write-only} and avoid using
- it to test for the current toolchain. Instead, use the \l{qbs::}{toolchain}
- property for conditionals.
+ This property is deduced from the \l{qbs::}{toolchainType} property and is typically
+ used to test for a particular toolchain or toolchain family in conditionals:
- For example, instead of:
+ \code
+ Properties {
+ // flags for GCC
+ condition: qbs.toolchain.contains("gcc")
+ cpp.commonCompilerFlags: ...
+ }
+ Properties {
+ // flags for MSVC
+ condition: qbs.toolchain.contains("msvc")
+ cpp.commonCompilerFlags: ...
+ }
+ \endcode
+
+ Unlike \l{qbs::}{toolchainType}, which contains a single value, \c qbs.toolchain
+ is a string list which also contains the toolchain family. This allows to make
+ conditions and checks simpler. For example, instead of:
\code
(qbs.toolchainType === "xcode" || qbs.toolchainType === "clang" || qbs.toolchainType === "gcc")
@@ -310,22 +430,97 @@
qbs.toolchain.contains("gcc")
\endcode
- However, there are some cases when using \c toolchainType would be
- acceptable, such as when the resulting condition would be simpler while
- still being correct:
+ since XCode, GCC and Clang belong to the \c "gcc" family.
- \code
- (qbs.toolchainType === "gcc")
- \endcode
+ \section2 Relation between toolchainType and toolchain
+
+ This table describes the possible values and matching between the \l{qbs::}{toolchainType}
+ and the \c toolchain properties:
+ \table
+ \header
+ \li Toolchain Type
+ \li Toolchain
+ \row
+ \li \c{"clang"}
+ \li \c{["clang", "llvm", "gcc"]}
+ \row
+ \li \c{"clang-cl"}
+ \li \c{["clang-cl", "msvc"]}
+ \row
+ \li \c{"gcc"}
+ \li \c{["gcc"]}
+ \row
+ \li \c{"iar"}
+ \li \c{["iar"]}
+ \row
+ \li \c{"keil"}
+ \li \c{["keil"]}
+ \row
+ \li \c{"llvm"}
+ \li \c{["llvm", "gcc"]}
+ \row
+ \li \c{"mingw"}
+ \li \c{["mingw", "gcc"]}
+ \row
+ \li \c{"msvc"}
+ \li \c{["msvc"]}
+ \row
+ \li \c{"sdcc"}
+ \li \c{["sdcc"]}
+ \row
+ \li \c{"xcode"}
+ \li \c{["xcode", "clang", "llvm", "gcc"]}
+ \endtable
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty string qbs::toolchainType
+ \since Qbs 1.11
- versus:
+ The toolchain that is going to be used for this build.
+ For example, to build a project using the \c "clang" toolchain, simply do
\code
- (qbs.toolchain.contains("gcc") && !qbs.toolchain.contains("clang"))
+ qbs build qbs.toolchainType:clang
\endcode
- Typical values include: \c{"gcc"}, \c{"clang"}, \c{"mingw"}, \c{"msvc"}, and
- \c{"xcode"}.
+ You should generally treat this property as \e{write-only} and avoid using
+ it to test for the current toolchain. Instead, use the \l{qbs::}{toolchain}
+ property for conditionals.
+
+ Typical values include: \c{"gcc"}, \c{"clang"}, \c{"clang-cl"}, \c{"mingw"},
+ \c{"msvc"}, and \c{"xcode"}. Also see \l{Relation between toolchainType and toolchain}.
+
+ By default, \c qbs.toolchainType is automatically detected based on the
+ \l{qbs::}{targetOS} property:
+ \table
+ \header
+ \li Target OS
+ \li Toolchain
+ \row
+ \li \c{"darwin"}
+ \li \c{"xcode"}
+ \row
+ \li \c{"freebsd"}
+ \li \c{"clang"}
+ \row
+ \li \c{"haiku"}
+ \li \c{"gcc"}
+ \row
+ \li \c{"qnx"}
+ \li \c{"qcc"}
+ \row
+ \li \c{"unix"}
+ \li \c{"gcc"}
+ \row
+ \li \c{"vxworks"}
+ \li \c{"gcc"}
+ \row
+ \li \c{"windows"}
+ \li \c{"msvc"}
+ \endtable
\defaultvalue Determined automatically.
*/
@@ -374,6 +569,15 @@
*/
/*!
+ \qmlproperty string qbs::hostArchitecture
+ \since Qbs 1.16
+
+ Contains the host OS architecture.
+
+ \defaultvalue Determined automatically.
+*/
+
+/*!
\qmlproperty stringList qbs::hostOS
This property is set by \QBS internally and specifies the OS \QBS is running
@@ -460,7 +664,9 @@
\qmlproperty string qbs::hostPlatform
\since Qbs 1.11
- Do not use this property.
+ Contains the host OS platform.
+
+ \sa {qbs::hostArchitecture}{hostArchitecture}
\defaultvalue Determined automatically.
*/
@@ -523,17 +729,6 @@
*/
/*!
- \qmlproperty stringList qbs::toolchain
-
- The attributes of the toolchain that is going to be used for this build.
-
- Typical values include \c{"llvm"}, in addition to the possible values of
- \l{qbs::}{toolchainType}.
-
- \nodefaultvalue
-*/
-
-/*!
\qmlproperty string qbs::version
\readonly
\since Qbs 1.4.1
diff --git a/doc/reference/modules/qt-core-module.qdoc b/doc/reference/modules/qt-core-module.qdoc
index c8c3dc7de..35190c686 100644
--- a/doc/reference/modules/qt-core-module.qdoc
+++ b/doc/reference/modules/qt-core-module.qdoc
@@ -100,6 +100,12 @@
\li Source files with this tag trigger a re-execution of the rule running the \c moc
tool when their timestamp changes.
\row
+ \li \c{"qt.core.metatypes"}
+ \li n/a
+ \li 1.16
+ \li This tag is attached to the JSON files that are potentially created if
+ \l{Qt.core::generateMetaTypesFile}{generateMetaTypesFile} is enabled.
+ \row
\li \c{"qt.core.resource_data"}
\li -
\li 1.7
@@ -196,6 +202,28 @@
*/
/*!
+ \qmlproperty bool Qt.core::generateMetaTypesFile
+
+ If this property is enabled, a JSON file tagged as \c "qt.core.metatypes" will potentially
+ be generated from metatype information collected by \c moc.
+
+ \nodefaultvalue
+ \since Qbs 1.16
+*/
+
+/*!
+ \qmlproperty bool Qt.core::metaTypesInstallDir
+
+ The directory to install the metatypes file into. If this property is empty or undefined,
+ the metatypes file will not be installed. If the
+ \l{Qt.core::generateMetaTypesFile}{generateMetaTypesFile} property is not \c true, then
+ this property has no effect.
+
+ \nodefaultvalue
+ \since Qbs 1.16
+*/
+
+/*!
\qmlproperty path Qt.core::incPath
The base path of the Qt headers.
diff --git a/doc/reference/modules/qt-qml-module.qdoc b/doc/reference/modules/qt-qml-module.qdoc
index 722a2eb41..ba8dddf2f 100644
--- a/doc/reference/modules/qt-qml-module.qdoc
+++ b/doc/reference/modules/qt-qml-module.qdoc
@@ -60,10 +60,81 @@
\li 1.8
\li Source files with this tag serve as inputs to the QML plugin
scanner.
+ \row
+ \li \c{"qt.qml.types"}
+ \li n/a
+ \li 1.16
+ \li This tag is attached to the files created by the \c qmltyperegistrar
+ tool if the \l importName property is set.
\endtable
*/
/*!
+ \qmlproperty string Qt.qml::importName
+
+ Setting this value triggers QML type registration via the \c qmltyperegistrar tool,
+ which results in the creation of a file with the tag \c{"qt.qml.types"}.
+ The given string is the name under which the registered types can be imported
+ by QML code that wants to use them.
+
+ \note This functionality is only available with Qt 5.15 or later.
+
+ \since Qbs 1.16
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty string Qt.qml::importVersion
+
+ Specifies the version of the types to be registered.
+ Values consist of a major and an optional minor number, separated by dots.
+ This property has no effect if \l importName is not set.
+
+ \since Qbs 1.16
+ \defaultvalue \l {Product::version}{The product version}
+*/
+
+/*!
+ \qmlproperty string Qt.qml::typesFileName
+
+ Specifies the name of the file that declares the types registered for this product.
+ For applications, the default value is \c{<name>.qmltypes},
+ where \c{<name>} is the product's \l{Product::targetName}{target name}.
+ Otherwise, the default value is "plugins.qmltypes".
+ \note The naming conventions are still in flux.
+ When in doubt, consult the Qt documentation.
+
+ This property has no effect if \l importName is not set.
+
+ \since Qbs 1.16
+*/
+
+/*!
+ \qmlproperty string Qt.qml::typesInstallDir
+
+ The directory to install the qmltypes file into. If this property is empty or undefined,
+ the file will not be installed.
+ This property has no effect if \l importName is not set.
+
+ \since Qbs 1.16
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty stringList Qt.qml::extraMetaTypesFiles
+
+ Specifies extra metatypes files to pass to the \c qmltyperegistrar tool
+ via the \c{--foreign-types} option when registering QML types.
+ \note This property is only needed for external libraries, not products or modules
+ pulled via \c Depends items. In particular, you don't need to (and should not)
+ use it to collect the metatypes files of Qt modules. These are found automatically.
+ This property has no effect if \l importName is not set.
+
+ \since Qbs 1.16
+ \nodefaultvalue
+*/
+
+/*!
\qmlproperty string Qt.qml::qmlImportScannerName
The base name of the QML import scanner.
diff --git a/docker-compose.yml b/docker-compose.yml
index f53d516c2..2b777c6f3 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -2,8 +2,11 @@ version: "3.7"
x-default-service: &linux
working_dir: /qbs
+ environment:
+ - BUILD_OPTIONS
volumes:
- .:/qbs
+ - ~/.ccache:/home/devel/.ccache
network_mode: bridge
cap_add:
- SYS_PTRACE
@@ -12,21 +15,47 @@ services:
bionic:
<< : *linux
hostname: bionic
- image: ${DOCKER_USER:-qbsbuild}/qbsdev:bionic-5.12.5_1.14.0-1
+ image: ${DOCKER_USER:-qbsbuild}/qbsdev:bionic-5.12.6_1.14.1-5
build:
dockerfile: docker/bionic/Dockerfile
context: .
args:
- QT_VERSION: 5.12.5
- QTCREATOR_VERSION: 4.10.1
+ QT_VERSION: 5.12.6
+ QTCREATOR_VERSION: 4.10.2
- stretch:
+ bionic-android-513:
<< : *linux
- hostname: stretch
- image: ${DOCKER_USER:-qbsbuild}/qbsdev:stretch
+ hostname: bionic-android
+ image: ${DOCKER_USER:-qbsbuild}/qbsdev:bionic-android-5.13.2-1
build:
- dockerfile: docker/stretch/Dockerfile
+ dockerfile: docker/bionic/test-android.Dockerfile
context: .
args:
- QT_VERSION: 5.12.4
- QTCREATOR_VERSION: 4.9.2
+ QT_VERSION: 5.13.2
+
+ bionic-android-514:
+ << : *linux
+ hostname: bionic-android
+ image: ${DOCKER_USER:-qbsbuild}/qbsdev:bionic-android-5.14.0-1
+ build:
+ dockerfile: docker/bionic/test-android.Dockerfile
+ context: .
+ args:
+ QT_VERSION: 5.14.0
+
+ windows:
+ image: ${DOCKER_USER:-qbsbuild}/qbsdev:windowsservercore-5.12.7_1.15.0-0
+ build:
+ dockerfile: docker/windowsservercore/Dockerfile
+ context: .
+ args:
+ QT_VERSION: 5.12.7
+ QBS_VERSION: 1.15.0
+ working_dir: 'C:/qbs'
+ environment:
+ - BUILD_OPTIONS
+ - WITH_DOCS
+ volumes:
+ - .:C:\qbs
+ - ~/.ccache:C:\.ccache
+ network_mode: nat
diff --git a/docker/bionic/Dockerfile b/docker/bionic/Dockerfile
index ed0625fb1..204c27606 100644
--- a/docker/bionic/Dockerfile
+++ b/docker/bionic/Dockerfile
@@ -119,23 +119,44 @@ ENTRYPOINT ["/sbin/entrypoint.sh"]
# Qbs build dependencies
RUN apt-get update -qq && \
apt-get install -qq -y --no-install-recommends \
+ bison \
build-essential \
ca-certificates \
+ ccache \
+ clang-8 \
+ clang-tidy-8 \
curl \
+ flex \
git \
- libclang-3.9 \
+ help2man \
+ icoutils \
+ libclang-3.9-dev \
libdbus-1-3 \
libfreetype6 \
libfontconfig1 \
libgl1-mesa-dev \
libgl1-mesa-glx \
+ libprotobuf-dev \
+ libgrpc++-dev \
+ nsis \
pkg-config \
- help2man \
- python-pip \
- p7zip-full && \
- pip install beautifulsoup4 lxml # for building the documentation
-
-ENV LLVM_INSTALL_DIR=/usr/lib/llvm-3.9
+ protobuf-compiler \
+ protobuf-compiler-grpc \
+ psmisc \
+ python3-pip \
+ python3-setuptools \
+ p7zip-full \
+ subversion \
+ unzip \
+ zip && \
+ update-alternatives --install /usr/bin/clang clang /usr/bin/clang-8 100 && \
+ update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-8 100 && \
+ update-alternatives --install /usr/bin/clang-check clang-check /usr/bin/clang-check-8 100 && \
+ update-alternatives --install /usr/bin/python python /usr/bin/python3 100 && \
+ update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 100 && \
+ pip install beautifulsoup4 lxml pyyaml
+
+ENV LLVM_INSTALL_DIR=/usr/lib/llvm-8
#
@@ -143,7 +164,7 @@ ENV LLVM_INSTALL_DIR=/usr/lib/llvm-3.9
#
COPY scripts/install-qt.sh install-qt.sh
-RUN ./install-qt.sh --version ${QT_VERSION} qtbase qtdeclarative qtscript qttools qtx11extras icu && \
+RUN ./install-qt.sh --version ${QT_VERSION} qtbase qtdeclarative qtscript qttools qtx11extras qtscxml icu && \
./install-qt.sh --version ${QTCREATOR_VERSION} qtcreator && \
echo "export PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:/opt/Qt/Tools/QtCreator/bin:\${PATH}" > /etc/profile.d/qt.sh
@@ -168,8 +189,11 @@ RUN apt-get install -qq -y --no-install-recommends \
# Configure Qbs
USER $USER_NAME
RUN qbs-setup-toolchains /usr/bin/g++ gcc && \
+ qbs-setup-toolchains /usr/bin/clang clang && \
qbs-setup-qt /opt/Qt/${QT_VERSION}/gcc_64/bin/qmake qt-gcc_64 && \
qbs config profiles.qt-gcc_64.baseProfile gcc && \
+ qbs-setup-qt /opt/Qt/${QT_VERSION}/gcc_64/bin/qmake qt-clang_64 && \
+ qbs config profiles.qt-clang_64.baseProfile clang && \
qbs config defaultProfile qt-gcc_64 && \
\
qbs-setup-toolchains /usr/bin/x86_64-w64-mingw32-g++ mingw && \
diff --git a/docker/bionic/test-android.Dockerfile b/docker/bionic/test-android.Dockerfile
new file mode 100644
index 000000000..854c67a19
--- /dev/null
+++ b/docker/bionic/test-android.Dockerfile
@@ -0,0 +1,107 @@
+#
+# Android SDK/NDK + Qt for Android for testing Qbs
+#
+FROM ubuntu:bionic
+LABEL Description="Ubuntu test environment for Qbs and Qt for Android"
+
+# Allow colored output on command line.
+ENV TERM=xterm-color
+
+#
+# Make it possible to change UID/GID in the entrypoint script. The docker
+# container usually runs as root user on Linux hosts. When the Docker container
+# mounts a folder on the host and creates files there, those files would be
+# owned by root instead of the current user. Thus we create a user here who's
+# UID will be changed in the entrypoint script to match the UID of the current
+# host user.
+#
+ARG USER_UID=1000
+ARG USER_NAME=devel
+RUN apt-get update -qq && \
+ apt-get install -qq -y \
+ ca-certificates \
+ gosu \
+ sudo && \
+ groupadd -g ${USER_UID} ${USER_NAME} && \
+ useradd -s /bin/bash -u ${USER_UID} -g ${USER_NAME} -o -c "" -m ${USER_NAME} && \
+ usermod -a -G sudo ${USER_NAME} && \
+ echo "%devel ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers
+
+COPY docker/bionic/entrypoint.sh /sbin/entrypoint.sh
+ENTRYPOINT ["/sbin/entrypoint.sh"]
+
+# Qbs build dependencies
+RUN apt-get update -qq && \
+ apt-get install -qq -y --no-install-recommends \
+ ca-certificates \
+ curl \
+ libglib2.0-0 \
+ libgl1-mesa-glx \
+ openjdk-8-jdk-headless \
+ p7zip-full \
+ unzip
+
+ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
+RUN echo "export JAVA_HOME=${JAVA_HOME}" > /etc/profile.d/android.sh && \
+ echo "export PATH=${JAVA_HOME}:\${PATH}" >> /etc/profile.d/android.sh
+
+ENV ANDROID_HOME="/home/${USER_NAME}/android"
+ENV ANDROID_SDK_ROOT=${ANDROID_HOME}
+ENV ANDROID_NDK_ROOT=${ANDROID_HOME}/ndk-bundle
+ENV PATH="${JAVA_HOME}:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/tools/bin:$PATH"
+RUN echo "export ANDROID_HOME=/home/${USER_NAME}/android" >> /etc/profile.d/android.sh && \
+ echo "export ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT}" >> /etc/profile.d/android.sh && \
+ echo "export ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}" >> /etc/profile.d/android.sh && \
+ echo "export PATH=${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/tools/bin:\$PATH" >> /etc/profile.d/android.sh
+
+#
+# We ned to run the following steps as the target user
+#
+USER ${USER_NAME}
+RUN mkdir ${ANDROID_HOME}
+
+# Get Android SDK TOOLS
+ARG SDK_TOOLS_VERSION="4333796"
+RUN curl -s https://dl.google.com/android/repository/sdk-tools-linux-${SDK_TOOLS_VERSION}.zip > ${ANDROID_HOME}/sdk.zip && \
+ unzip ${ANDROID_HOME}/sdk.zip -d ${ANDROID_HOME} && \
+ rm -v ${ANDROID_HOME}/sdk.zip
+
+# Accept SDK license
+ARG ANDROID_PLATFORM="android-29"
+ARG BUILD_TOOLS="28.0.3"
+RUN yes | sdkmanager --verbose --licenses && \
+ sdkmanager --update && \
+ sdkmanager "platforms;${ANDROID_PLATFORM}" "build-tools;${BUILD_TOOLS}" "platform-tools" "tools" "ndk-bundle" && \
+ /usr/lib/jvm/java-8-openjdk-amd64/bin/keytool -genkey -keystore /home/${USER_NAME}/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname 'CN=Android Debug,O=Android,C=US'
+
+# Install ndk samples in ${ANDROID_NDK_ROOT}/samples
+RUN cd ${ANDROID_NDK_ROOT} && \
+ curl -sLO https://github.com/android/ndk-samples/archive/master.zip && \
+ unzip -q master.zip && \
+ rm -v master.zip && \
+ mv ndk-samples-master samples
+
+# Install android-BasicMediaDecoder in ${ANDROID_SDK_ROOT}/samples
+RUN mkdir ${ANDROID_SDK_ROOT}/samples && \
+ cd ${ANDROID_SDK_ROOT}/samples && \
+ curl -sLO https://github.com/googlearchive/android-BasicMediaDecoder/archive/master.zip && \
+ unzip -q master.zip && \
+ rm -v master.zip && \
+ mv android-BasicMediaDecoder-master android-BasicMediaDecoder
+
+USER root
+
+#
+# Install Qt and Qbs for Linux from qt.io
+#
+ARG QT_VERSION
+COPY scripts/install-qt.sh install-qt.sh
+RUN if [ "${QT_VERSION}" \< "5.14" ]; then \
+ QT_ABIS="android_armv7 android_arm64_v8a android_x86 android_x86_64"; \
+ else \
+ QT_ABIS="any"; \
+ fi; \
+ for abi in ${QT_ABIS}; do \
+ ./install-qt.sh --version ${QT_VERSION} --target android --toolchain ${abi} qtbase qtdeclarative qttools qtimageformats; \
+ done && \
+ echo "export QT_VERSION=${QT_VERSION}" >> /etc/profile.d/qt.sh
diff --git a/docker/docker.qbs b/docker/docker.qbs
index 5adc277e4..513a5fd8b 100644
--- a/docker/docker.qbs
+++ b/docker/docker.qbs
@@ -1,35 +1,8 @@
-import qbs
-Project {
- Product {
- Depends { name: "docker"; required: false }
-
- name: "qbs-docker-stretch"
- type: ["docker.docker-image"]
- builtByDefault: false
- condition: docker.present
-
- docker.imageTag: "qbsbuild/qbsdev:stretch"
-
- files: [
- "stretch/Dockerfile",
- "stretch/entrypoint.sh",
- ]
- }
-
- Product {
- Depends { name: "docker"; required: false }
-
- name: "qbs-docker-windowsservercore"
- type: ["docker.docker-image"]
- builtByDefault: false
- condition: docker.present
-
- docker.imageTag: "qbsbuild/qbsdev:windowsservercore"
-
- files: [
- "windowsservercore/Dockerfile",
- "windowsservercore/build-qt.bat",
- ]
- }
+// This is a convenience product to be able to use Qt Creator for editing the docker files.
+// For building and managing the images, use docker-compose as explained in
+// https://doc.qt.io/qbs/building-qbs.html#using-docker.
+Product {
+ name: "docker"
+ files: "**"
}
diff --git a/docker/stretch/Dockerfile b/docker/stretch/Dockerfile
deleted file mode 100644
index 736bd1ef7..000000000
--- a/docker/stretch/Dockerfile
+++ /dev/null
@@ -1,73 +0,0 @@
-#
-# Downloads and builds Qt from source. This is simpler than using the Qt online
-# installer. We do it in a separate stage to keep the number of dependencies low
-# in the final Docker image.
-#
-FROM debian:9
-LABEL Description="Debian development environment for Qbs with Qt and various dependencies for testing Qbs modules and functionality"
-ARG QT_VERSION
-ARG QTCREATOR_VERSION
-
-# Allow colored output on command line.
-ENV TERM=xterm-color
-
-#
-# Make it possible to change UID/GID in the entrypoint script. The docker
-# container usually runs as root user on Linux hosts. When the Docker container
-# mounts a folder on the host and creates files there, those files would be
-# owned by root instead of the current user. Thus we create a user here who's
-# UID will be changed in the entrypoint script to match the UID of the current
-# host user.
-#
-ARG USER_UID=1000
-ARG USER_NAME=devel
-RUN apt-get update -qq && \
- apt-get install -qq -y --no-install-recommends \
- ca-certificates \
- gosu \
- sudo && \
- groupadd -g ${USER_UID} ${USER_NAME} && \
- useradd -s /bin/bash -u ${USER_UID} -g ${USER_NAME} -o -c "" -m ${USER_NAME} && \
- usermod -a -G sudo ${USER_NAME} && \
- echo "%devel ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers
-
-COPY docker/stretch/entrypoint.sh entrypoint.sh
-ENTRYPOINT ["/entrypoint.sh"]
-
-
-# Build and run dependencies for Qbs
-RUN apt-get install -qq -y --no-install-recommends \
- build-essential \
- curl \
- git \
- help2man \
- libclang-3.9 \
- libdbus-1-3 \
- libgl1-mesa-glx \
- libfreetype6 \
- libfontconfig1 \
- libgl1-mesa-dev \
- make \
- pkg-config \
- python-pip \
- p7zip-full && \
- pip install beautifulsoup4 lxml # for building the documentation
-
-ENV LLVM_INSTALL_DIR=/usr/lib/llvm-3.9
-
-COPY scripts/install-qt.sh install-qt.sh
-
-RUN ./install-qt.sh --version ${QT_VERSION} qtbase qtdeclarative qtscript qttools qtx11extras icu && \
- ./install-qt.sh --version ${QTCREATOR_VERSION} qtcreator && \
- echo "export PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:/opt/Qt/Tools/QtCreator/bin:\${PATH}" > /etc/profile.d/qt.sh
-
-ENV PATH=/opt/Qt/${QT_VERSION}/gcc_64/bin:/opt/Qt/Tools/QtCreator/bin:${PATH}
-
-# Configure Qbs
-USER $USER_NAME
-RUN qbs-setup-toolchains --detect && \
- qbs-setup-qt /opt/Qt/${QT_VERSION}/gcc_64/bin/qmake qt && \
- qbs config defaultProfile qt
-
-# Switch back to root user for the entrypoint script.
-USER root
diff --git a/docker/windowsservercore/Dockerfile b/docker/windowsservercore/Dockerfile
index 43cf93736..be3777aa0 100644
--- a/docker/windowsservercore/Dockerfile
+++ b/docker/windowsservercore/Dockerfile
@@ -1,49 +1,51 @@
-FROM microsoft/windowsservercore:10.0.14393.1884 as build-env
+
+FROM mcr.microsoft.com/windows/servercore:1809
LABEL Description="Windows Server Core development environment for Qbs with Qt, Chocolatey and various dependencies for testing Qbs modules and functionality"
# Disable crash dialog for release-mode runtimes
RUN reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting" /v Disabled /t REG_DWORD /d 1 /f
RUN reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting" /v DontShowUI /t REG_DWORD /d 1 /f
-RUN @powershell -NoProfile -ExecutionPolicy Bypass -Command \
+RUN powershell -NoProfile -ExecutionPolicy Bypass -Command \
$Env:chocolateyVersion = '0.10.8' ; \
$Env:chocolateyUseWindowsCompression = 'false' ; \
- "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
-RUN choco install -y python2 --version 2.7.14 && refreshenv && python --version && pip --version
-RUN choco install -y vcredist140
-RUN choco install -y qbs --version 1.12.1 && qbs --version
-RUN choco install -y visualcpp-build-tools --version 14.0.25420.1 && dir "%PROGRAMFILES(X86)%\Microsoft Visual C++ Build Tools"
-RUN choco install -y unzip --version 6.0
-RUN choco install -y zip --version 3.0
-
-
-FROM build-env as qt-build-env
-LABEL Description="Environment for Building Qt"
-RUN choco install -y jom --version 1.1.2 && jom /version
-
-# Download and extract Qt source archives
-WORKDIR C:/
-RUN md src
-WORKDIR src
-COPY build-qt.bat .
-ADD http://download.qt.io/official_releases/qt/5.12/5.12.5/submodules/qtbase-everywhere-src-5.12.5.zip qtbase.zip
-ADD http://download.qt.io/official_releases/qt/5.12/5.12.5/submodules/qtscript-everywhere-src-5.12.5.zip qtscript.zip
-ADD http://download.qt.io/official_releases/qt/5.12/5.12.5/submodules/qttools-everywhere-src-5.12.5.zip qttools.zip
-RUN unzip qtbase.zip
-RUN unzip qtscript.zip
-RUN unzip qttools.zip
-RUN rename qtbase-everywhere-src-5.12.5 qtbase
-RUN rename qtscript-everywhere-src-5.12.5 qtscript
-RUN rename qttools-everywhere-src-5.12.5 qttools
-RUN build-qt.bat x86
-RUN build-qt.bat x64
-
-
-FROM build-env as qbs-build-env
-WORKDIR C:/
-COPY --from=qt-build-env C:/Qt C:/Qt/
-ENV QTDIR C:\\Qt\\x86
-ENV QTDIR64 C:\\Qt\\x64
+ "[Net.ServicePointManager]::SecurityProtocol = \"tls12, tls11, tls\"; iex ((New-Object System.Net.WebClient).DownloadString('http://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
+
+# Wait for vs_installer.exe, vs_installerservice.exe
+# or vs_installershell.exe because choco doesn't
+RUN powershell -NoProfile -InputFormat None -Command \
+ choco install visualcpp-build-tools --version 15.0.26228.20170424 -y; \
+ Write-Host 'Waiting for Visual C++ Build Tools to finish'; \
+ Wait-Process -Name vs_installer
+
+ARG QBS_VERSION
+RUN choco install -y python && \
+ choco install -y 7zip --version 19.0 && \
+ choco install -y git --version 2.24.0 --params "/GitAndUnixToolsOnPath" && \
+ choco install -y qbs --version %QBS_VERSION%
# for building the documentation
RUN pip install beautifulsoup4 lxml
+
+# clcache for speeding up MSVC builds
+ENV CLCACHE_DIR="C:/.ccache"
+RUN certutil -generateSSTFromWU roots.sst && \
+ certutil -addstore -f root roots.sst && \
+ del roots.sst && \
+ pip install --trusted-host=pypi.org \
+ git+https://github.com/frerich/clcache.git@cae73d8255d78db8ba11e23c51fd2c9a89e7475b
+
+########### Install Qt #############
+ARG QT_VERSION
+COPY scripts/install-qt.sh install-qt.sh
+
+RUN bash -c "./install-qt.sh -d /c/Qt --version ${QT_VERSION} --toolchain win64_msvc2017_64 qtbase qtdeclarative qttools qtscript"
+ENV QTDIR64=C:\\Qt\\${QT_VERSION}\\msvc2017_64
+
+RUN bash -c "./install-qt.sh -d /c/Qt --version ${QT_VERSION} --toolchain win32_msvc2017 qtbase qtdeclarative qttools qtscript"
+ENV QTDIR=C:\\Qt\\${QT_VERSION}\\msvc2017
+
+RUN qbs setup-toolchains --detect && \
+ qbs setup-qt %QTDIR64%/bin/qmake.exe qt64 && \
+ qbs setup-qt %QTDIR%/bin/qmake.exe qt && \
+ qbs config defaultProfile qt64
diff --git a/docker/windowsservercore/build-qt.bat b/docker/windowsservercore/build-qt.bat
deleted file mode 100644
index 0d7f432e6..000000000
--- a/docker/windowsservercore/build-qt.bat
+++ /dev/null
@@ -1,23 +0,0 @@
-setlocal
-set ARCH=%1
-call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %ARCH%
-md %ARCH%
-cd %ARCH%
-md qtbase
-cd qtbase
-call C:\src\qtbase\configure -opensource -confirm-license -prefix C:\Qt\%ARCH% -opengl desktop -release -nomake tests -nomake examples
-jom
-jom install
-cd ..
-md qttools\src\windeployqt
-cd qttools\src\windeployqt
-C:\Qt\%ARCH%\bin\qmake C:\src\qttools\src\windeployqt\windeployqt.pro
-jom
-jom install
-cd ..
-md qtscript
-cd qtscript
-C:\Qt\%ARCH%\bin\qmake C:\src\qtscript\qtscript.pro
-jom
-jom install
-endlocal
diff --git a/examples/app-and-lib/app/main.cpp b/examples/app-and-lib/app/main.cpp
index 9d1eda989..17f4226f3 100644
--- a/examples/app-and-lib/app/main.cpp
+++ b/examples/app-and-lib/app/main.cpp
@@ -48,7 +48,7 @@
**
****************************************************************************/
-#include <stdio.h>
+#include <cstdio>
#include <lib.h>
int main()
diff --git a/examples/app-and-lib/lib/lib.cpp b/examples/app-and-lib/lib/lib.cpp
index db312e2d2..bfa62ecf7 100644
--- a/examples/app-and-lib/lib/lib.cpp
+++ b/examples/app-and-lib/lib/lib.cpp
@@ -48,7 +48,7 @@
**
****************************************************************************/
-#include <stdio.h>
+#include <cstdio>
#ifndef CRUCIAL_DEFINE
# error CRUCIAL_DEFINE not defined
diff --git a/examples/baremetal/at90can128olimex/redblink/README.md b/examples/baremetal/at90can128olimex/redblink/README.md
index 0e9710e57..cbf51898d 100644
--- a/examples/baremetal/at90can128olimex/redblink/README.md
+++ b/examples/baremetal/at90can128olimex/redblink/README.md
@@ -1,4 +1,4 @@
-This examples demonstrates how to build a bare-metal application using
+This example demonstrates how to build a bare-metal application using
different AVR toolchains. It is designed for the OLIMEX AVR-CAN target
board (based on at90can128 chip) and simply flashes the red LED on the
board.
diff --git a/examples/baremetal/cc2540usbdongle/greenblink/system.h b/examples/baremetal/cc2540usbdongle/greenblink/system.h
index cdc6302d4..4f105dbd0 100644
--- a/examples/baremetal/cc2540usbdongle/greenblink/system.h
+++ b/examples/baremetal/cc2540usbdongle/greenblink/system.h
@@ -66,6 +66,9 @@ extern "C" {
#elif defined (__SDCC_mcs51)
#include <mcs51/compiler.h>
# define DEFINE_SFR(name, addr) __sfr __at(addr) name;
+# ifndef NOP
+# define NOP() __asm NOP __endasm
+# endif
# define system_nop() NOP()
#else
#error "Unsupported toolchain"
diff --git a/examples/baremetal/msp430f5529/redblink/README.md b/examples/baremetal/msp430f5529/redblink/README.md
index 3affbaf7e..2f63b2349 100644
--- a/examples/baremetal/msp430f5529/redblink/README.md
+++ b/examples/baremetal/msp430f5529/redblink/README.md
@@ -1,4 +1,4 @@
-This examples demonstrates how to build a bare-metal application using
+This example demonstrates how to build a bare-metal application using
different MSP430 toolchains. It is designed for the MSP-EXP430F5529LP
target board (based on msp430f5529 chip) and simply flashes the red
LED on the board.
diff --git a/examples/baremetal/stm32f4discovery/blueblink/blueblink.qbs b/examples/baremetal/stm32f4discovery/blueblink/blueblink.qbs
index 5ccf8b3b0..3e9298921 100644
--- a/examples/baremetal/stm32f4discovery/blueblink/blueblink.qbs
+++ b/examples/baremetal/stm32f4discovery/blueblink/blueblink.qbs
@@ -52,7 +52,7 @@ import qbs
CppApplication {
condition: {
- if (!qbs.architecture.contains("arm"))
+ if (!qbs.architecture.startsWith("arm"))
return false;
return qbs.toolchain.contains("gcc")
|| qbs.toolchain.contains("iar")
diff --git a/examples/cocoa-touch-application/CocoaTouchApplication.qbs b/examples/cocoa-touch-application/CocoaTouchApplication.qbs
index cf0a273d5..ec1772f1f 100644
--- a/examples/cocoa-touch-application/CocoaTouchApplication.qbs
+++ b/examples/cocoa-touch-application/CocoaTouchApplication.qbs
@@ -54,12 +54,9 @@ import qbs 1.0
CppApplication {
Depends { name: "xcode"; required: false }
Depends { condition: product.condition; name: "ib" }
- condition: qbs.hostOS.contains("macos") && xcode.present
+ condition: qbs.hostOS.contains("macos") && xcode.present && qbs.targetPlatform.contains("ios")
name: "Cocoa Touch Application"
- qbs.targetPlatform: "ios"
- qbs.architecture: "arm64"
-
cpp.useObjcPrecompiledHeader: true
cpp.minimumIosVersion: "8.0"
cpp.frameworks: [ "UIKit", "Foundation", "CoreGraphics" ]
diff --git a/examples/cocoa-touch-application/CocoaTouchApplication/MasterViewController.m b/examples/cocoa-touch-application/CocoaTouchApplication/MasterViewController.m
index 6024d67c4..ebac52dcd 100644
--- a/examples/cocoa-touch-application/CocoaTouchApplication/MasterViewController.m
+++ b/examples/cocoa-touch-application/CocoaTouchApplication/MasterViewController.m
@@ -43,7 +43,7 @@
self.title = NSLocalizedString(@"Master", @"Master");
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
self.clearsSelectionOnViewWillAppear = NO;
- self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0);
+ self.preferredContentSize = CGSizeMake(320.0, 600.0);
}
}
return self;
diff --git a/examples/code-generator/code-generator.qbs b/examples/code-generator/code-generator.qbs
index df15dec5e..1c2d2e445 100644
--- a/examples/code-generator/code-generator.qbs
+++ b/examples/code-generator/code-generator.qbs
@@ -55,6 +55,10 @@ Project {
name: "hwgen"
consoleApplication: true
files: ["hwgen.cpp"]
+ Properties {
+ condition: qbs.toolchain.contains("gcc") || qbs.toolchain.contains("clang-cl")
+ cpp.cxxFlags: ["-Wno-deprecated-declarations"]
+ }
}
// Generate and build a hello-world application.
diff --git a/examples/collidingmice/main.cpp b/examples/collidingmice/main.cpp
index 6604cc597..ffddf4c81 100644
--- a/examples/collidingmice/main.cpp
+++ b/examples/collidingmice/main.cpp
@@ -56,7 +56,7 @@
#include <QTime>
#include <QTimer>
-#include <math.h>
+#include <cmath>
static const int MouseCount = 7;
diff --git a/examples/collidingmice/mouse.cpp b/examples/collidingmice/mouse.cpp
index 8dbe28c49..7075ada38 100644
--- a/examples/collidingmice/mouse.cpp
+++ b/examples/collidingmice/mouse.cpp
@@ -54,7 +54,7 @@
#include <QPainter>
#include <QStyleOption>
-#include <math.h>
+#include <cmath>
static const double Pi = 3.14159265358979323846264338327950288419717;
static double TwoPi = 2.0 * Pi;
@@ -81,8 +81,7 @@ Mouse::Mouse()
QRectF Mouse::boundingRect() const
{
qreal adjust = 0.5;
- return QRectF(-18 - adjust, -22 - adjust,
- 36 + adjust, 60 + adjust);
+ return {-18 - adjust, -22 - adjust, 36 + adjust, 60 + adjust};
}
//! [1]
diff --git a/examples/collidingmice/mouse.h b/examples/collidingmice/mouse.h
index 4e6958c78..a98618ea5 100644
--- a/examples/collidingmice/mouse.h
+++ b/examples/collidingmice/mouse.h
@@ -59,13 +59,13 @@ class Mouse : public QGraphicsItem
public:
Mouse();
- QRectF boundingRect() const;
- QPainterPath shape() const;
+ QRectF boundingRect() const override;
+ QPainterPath shape() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
- QWidget *widget);
+ QWidget *widget) override;
protected:
- void advance(int step);
+ void advance(int step) override;
private:
qreal angle;
diff --git a/examples/grpc/client.cpp b/examples/grpc/client.cpp
index 55bcd866d..8fee915fb 100644
--- a/examples/grpc/client.cpp
+++ b/examples/grpc/client.cpp
@@ -51,7 +51,7 @@
class Client
{
public:
- Client(std::shared_ptr<grpc::Channel> channel)
+ Client(const std::shared_ptr<grpc::Channel> &channel)
: m_stub(PP::MyApi::NewStub(channel)) {}
int ping(int count) {
diff --git a/examples/grpc/ping-pong-grpc.qbs b/examples/grpc/ping-pong-grpc.qbs
index 8d8909350..dc42eb04d 100644
--- a/examples/grpc/ping-pong-grpc.qbs
+++ b/examples/grpc/ping-pong-grpc.qbs
@@ -40,8 +40,13 @@ Project {
protobuf.cpp.useGrpc: true
consoleApplication: true
cpp.cxxLanguageVersion: "c++17"
+ cpp.minimumMacosVersion: "10.8"
name: "client"
files: "client.cpp"
+ Properties {
+ condition: qbs.toolchain.contains("gcc")
+ cpp.cxxFlags: "-Wno-deprecated-declarations"
+ }
Group {
files: "ping-pong-grpc.proto"
fileTags: "protobuf.grpc"
@@ -55,8 +60,13 @@ Project {
protobuf.cpp.useGrpc: true
consoleApplication: true
cpp.cxxLanguageVersion: "c++17"
+ cpp.minimumMacosVersion: "10.8"
name: "server"
- files: "client.cpp"
+ files: "server.cpp"
+ Properties {
+ condition: qbs.toolchain.contains("gcc")
+ cpp.cxxFlags: "-Wno-deprecated-declarations"
+ }
Group {
files: "ping-pong-grpc.proto"
fileTags: "protobuf.grpc"
diff --git a/examples/helloworld-complex/hello.qbs b/examples/helloworld-complex/hello.qbs
index 725424e49..16e7eace0 100644
--- a/examples/helloworld-complex/hello.qbs
+++ b/examples/helloworld-complex/hello.qbs
@@ -74,7 +74,7 @@ Project {
cpp.defines: {
var defines = outer.concat([
'HAVE_MAIN_CPP',
- cpp.debugInformation ? '_DEBUG' : '_RELEASE'
+ cpp.debugInformation ? 'HAS_DEBUG' : 'HAS_RELEASE'
]);
if (project.hasSpecialFeature)
defines.push("HAS_SPECIAL_FEATURE");
diff --git a/examples/helloworld-complex/src/main.cpp b/examples/helloworld-complex/src/main.cpp
index f3dbcc4f7..8827c1e5e 100644
--- a/examples/helloworld-complex/src/main.cpp
+++ b/examples/helloworld-complex/src/main.cpp
@@ -54,7 +54,7 @@
#include "specialfeature.h"
#endif
-#include <stdio.h>
+#include <cstdio>
#ifndef HAVE_MAIN_CPP
# error missing define HAVE_MAIN_CPP
@@ -67,9 +67,9 @@
int main()
{
someUsefulFunction();
-#ifdef _DEBUG
+#if defined(HAS_DEBUG)
puts("Hello World! (debug version)");
-#else
+#elif defined(HAS_RELEASE)
puts("Hello World! (release version)");
#endif
#ifdef HAS_SPECIAL_FEATURE
diff --git a/examples/helloworld-qt/main.cpp b/examples/helloworld-qt/main.cpp
index 217fc12d0..e1e822591 100644
--- a/examples/helloworld-qt/main.cpp
+++ b/examples/helloworld-qt/main.cpp
@@ -55,5 +55,7 @@
int main()
{
- QTextStream(stdout) << QCoreApplication::translate("hello", "Hello, World!") << endl;
+ QTextStream ts(stdout);
+ ts << QCoreApplication::translate("hello", "Hello, World!\n");
+ ts.flush();
}
diff --git a/examples/protobuf/cpp/addressbook.qbs b/examples/protobuf/cpp/addressbook.qbs
index bd5afd377..3f699c7db 100644
--- a/examples/protobuf/cpp/addressbook.qbs
+++ b/examples/protobuf/cpp/addressbook.qbs
@@ -7,6 +7,8 @@ CppApplication {
Depends { name: "cpp" }
cpp.cxxLanguageVersion: "c++11"
+ cpp.minimumMacosVersion: "10.8"
+ cpp.warningLevel: "none"
Depends { id: protobuf; name: "protobuf.cpp"; required: false }
diff --git a/examples/protobuf/cpp/main.cpp b/examples/protobuf/cpp/main.cpp
index 703a9d302..8d2ca9763 100644
--- a/examples/protobuf/cpp/main.cpp
+++ b/examples/protobuf/cpp/main.cpp
@@ -96,7 +96,7 @@ void listPeople(const tutorial::AddressBook& address_book)
std::cout << "Person ID: " << person.id() << std::endl;
std::cout << " Name: " << person.name() << std::endl;
- if (person.email() != "") {
+ if (!person.email().empty()) {
std::cout << " E-mail address: " << person.email() << std::endl;
}
diff --git a/qbs-resources/modules/docker/docker.qbs b/qbs-resources/modules/docker/docker.qbs
deleted file mode 100644
index 1460cff3c..000000000
--- a/qbs-resources/modules/docker/docker.qbs
+++ /dev/null
@@ -1,50 +0,0 @@
-import qbs
-import qbs.FileInfo
-import qbs.Probes
-import qbs.Utilities
-
-Module {
- Probes.BinaryProbe {
- id: dockercli
- names: ["docker"]
- }
-
- property string dockerFilePath: dockercli.filePath
- property string imageTag
- property stringList buildFlags
-
- FileTagger {
- patterns: ["Dockerfile"]
- fileTags: ["docker.dockerfile"]
- }
-
- Rule {
- inputs: ["docker.dockerfile"]
-
- Artifact {
- // Let Docker handle the dependency management
- filePath: FileInfo.joinPaths(product.buildDirectory,
- Utilities.getHash(input.filePath), ".docker-image-dummy")
- fileTags: ["docker.docker-image"]
- }
-
- prepare: {
- var args = ["build"];
- var tag = product.docker.imageTag;
- if (tag)
- args.push("-t", tag);
- Array.prototype.push.apply(args, product.docker.buildFlags);
- args.push(".");
- var cmd = new Command(product.docker.dockerFilePath, args);
- cmd.workingDirectory = FileInfo.path(input.filePath);
- cmd.description = "building docker image "
- + FileInfo.fileName(cmd.workingDirectory) + (tag ? " (" + tag + ")" : "");
- return [cmd];
- }
- }
-
- validate: {
- if (!dockerFilePath)
- throw ModUtils.ModuleError("Could not find Docker.");
- }
-}
diff --git a/qbs.pro b/qbs.pro
index 3a716c7d3..b8faa2ab0 100644
--- a/qbs.pro
+++ b/qbs.pro
@@ -35,7 +35,10 @@ src_app.subdir = src/app
src_app.depends = corelib
src_libexec.subdir = src/libexec
src_plugins.subdir = src/plugins
-CONFIG(shared, static|shared): src_plugins.depends = corelib
+CONFIG(shared, static|shared) {
+ src_plugins.depends = corelib
+ src_app.depends += src_plugins
+}
tests.depends = static_res
static_res.file = static-res.pro
static_res.depends = src_app src_libexec src_plugins static.pro
diff --git a/qbs.qbs b/qbs.qbs
index f36bd0ee4..c409eefb6 100644
--- a/qbs.qbs
+++ b/qbs.qbs
@@ -4,7 +4,6 @@ Project {
minimumQbsVersion: "1.6"
qbsSearchPaths: ["qbs-resources"]
property bool withCode: true
- property bool withDocker: true
property bool withDocumentation: true
property bool withExamples: false
property bool withTests: withCode
@@ -12,18 +11,12 @@ Project {
property stringList autotestWrapper: []
references: [
+ "docker/docker.qbs",
"share/share.qbs",
"scripts/scripts.qbs",
]
SubProject {
- filePath: "docker/docker.qbs"
- Properties {
- condition: parent.withDocker
- }
- }
-
- SubProject {
filePath: "doc/doc.qbs"
Properties {
condition: parent.withDocumentation
diff --git a/scripts/build-qbs-with-qbs.sh b/scripts/build-qbs-with-qbs.sh
index 6b6f6d2a9..856cf71b6 100755
--- a/scripts/build-qbs-with-qbs.sh
+++ b/scripts/build-qbs-with-qbs.sh
@@ -53,8 +53,12 @@ BUILD_OPTIONS="\
modules.qbsbuildconfig.enableAddressSanitizer:true \
modules.qbsbuildconfig.enableProjectFileUpdates:true \
modules.qbsbuildconfig.enableUnitTests:true \
+ modules.cpp.treatWarningsAsErrors:true \
+ modules.cpp.separateDebugInformation:true \
+ modules.qbs.debugInformation:true \
project.withExamples:true \
- ${BUILD_OPTIONS}
+ ${BUILD_OPTIONS} \
+ config:release \
"
#
@@ -94,12 +98,19 @@ if [ -z "${QBS_AUTOTEST_PROFILE}" ]; then
# was set. Otherwise setup-qt automatically uses the default
# toolchain profile.
if [ ! -z "${QBS_BUILD_PROFILE}" ]; then
- QBS_BUILD_BASE_PROFILE=$(qbs config ${QBS_BUILD_PROFILE}.baseProfile | cut -d: -f2)
- qbs run -p qbs_app ${BUILD_OPTIONS} -- config \
- ${RUN_OPTIONS} \
- ${QBS_AUTOTEST_PROFILE}.baseProfile ${QBS_BUILD_BASE_PROFILE}
+ QBS_BUILD_BASE_PROFILE=$(qbs config profiles.${QBS_BUILD_PROFILE}.baseProfile | cut -d: -f2)
+ if [ ! -z "${QBS_BUILD_BASE_PROFILE}" ]; then
+ echo "Setting base profile for ${QBS_AUTOTEST_PROFILE} to ${QBS_BUILD_BASE_PROFILE}"
+ qbs run -p qbs_app ${BUILD_OPTIONS} -- config \
+ ${RUN_OPTIONS} \
+ profiles.${QBS_AUTOTEST_PROFILE}.baseProfile ${QBS_BUILD_BASE_PROFILE}
+ fi
fi
+ qbs run -p qbs_app ${BUILD_OPTIONS} -- config \
+ ${RUN_OPTIONS} \
+ --list
+
# QBS_AUTOTEST_PROFILE has been added to the environment
# which requires a resolve step
qbs resolve ${BUILD_OPTIONS}
@@ -111,5 +122,5 @@ fi
# timeout on Travis CI.
#
(while true; do echo "" && sleep 590; done) &
-trap "kill $!" EXIT
+trap "kill $!; wait $! 2>/dev/null || true; killall sleep || true" EXIT
qbs build -p "autotest-runner" ${BUILD_OPTIONS}
diff --git a/scripts/build-qbs-with-qmake.sh b/scripts/build-qbs-with-qmake.sh
index f06501e30..1e97d7695 100755
--- a/scripts/build-qbs-with-qmake.sh
+++ b/scripts/build-qbs-with-qmake.sh
@@ -50,7 +50,8 @@ export QBS_AUTOTEST_SETTINGS_DIR="${QBS_AUTOTEST_SETTINGS_DIR:-/tmp/qbs-settings
#
qmake -r qbs.pro \
CONFIG+=qbs_enable_unit_tests \
- CONFIG+=qbs_enable_project_file_updates
+ CONFIG+=qbs_enable_project_file_updates \
+ ${BUILD_OPTIONS}
make -j $(nproc --all)
make docs
diff --git a/scripts/make-release-archives.bat b/scripts/make-release-archives.bat
index 867fa773c..0970d2702 100644
--- a/scripts/make-release-archives.bat
+++ b/scripts/make-release-archives.bat
@@ -68,6 +68,7 @@ subst Q: "%CD%" && Q:
qbs build --settings-dir "%builddir%\.settings"^
-f qbs.qbs -d "%builddir%\build"^
-p dist qbs.buildVariant:release project.withDocumentation:false "products.qbs archive.includeTopLevelDir:true"^
+ modules.qbsbuildconfig.enableBundledQt:true^
config:release "qbs.installRoot:%builddir%\qbs-windows-x86-%version%" profile:qt^
config:release-64 "qbs.installRoot:%builddir%\qbs-windows-x86_64-%version%" profile:qt64 || exit /b
diff --git a/scripts/run-analyzer.sh b/scripts/run-analyzer.sh
index e3743f631..926e3453f 100755
--- a/scripts/run-analyzer.sh
+++ b/scripts/run-analyzer.sh
@@ -38,8 +38,6 @@
##
#############################################################################
-set -e
-
LLVM_INSTALL_DIR=${LLVM_INSTALL_DIR:-""}
# on Debian, it might be necessary to setup which version of clang-tidy and run-clang-tidy.py
@@ -59,10 +57,22 @@ if [ -z "$RUN_CLANG_TIDY" ] || [ -z "$CLANG_TIDY" ]; then
fi
fi
+NPROC=`which nproc`
+SYSCTL=`which sysctl`
+CPU_COUNT=2
+if [ ! -z "$NPROC" ]; then # Linux
+ CPU_COUNT=`$NPROC --all`
+elif [ ! -z "$SYSCTL" ]; then # macOS
+ CPU_COUNT=`$SYSCTL -n hw.ncpu`
+fi
+
BUILD_OPTIONS="\
${QBS_BUILD_PROFILE:+profile:${QBS_BUILD_PROFILE}} \
modules.qbsbuildconfig.enableProjectFileUpdates:true \
- modules.qbsbuildconfig.enableUnitTests:true \
+ modules.cpp.treatWarningsAsErrors:true \
+ modules.qbs.buildVariant:release \
+ project.withTests:false \
+ ${BUILD_OPTIONS} \
config:analyzer
"
@@ -73,8 +83,35 @@ if [ ! -f "$QBS_SRC_DIR/qbs.qbs" ]; then
exit 1
fi
+set -e
+set -o pipefail
+
qbs resolve -f "$QBS_SRC_DIR/qbs.qbs" $BUILD_OPTIONS
qbs build -f "$QBS_SRC_DIR/qbs.qbs" $BUILD_OPTIONS
qbs generate -g clangdb -f "$QBS_SRC_DIR/qbs.qbs" $BUILD_OPTIONS
-"$RUN_CLANG_TIDY" -p analyzer -clang-tidy-binary "$CLANG_TIDY" -header-filter=".*qbs.*\.h"
+SCRIPT="
+import json
+import os
+import sys
+
+dbFile = sys.argv[1]
+blacklist = ['json.cpp']
+seenFiles = set()
+patched_db = []
+with open(dbFile, 'r') as f:
+ db = json.load(f)
+ for item in db:
+ file = item['file']
+ if (os.path.basename(file) not in blacklist) and (file not in seenFiles):
+ seenFiles.add(file)
+ patched_db.append(item)
+
+with open(dbFile, 'w') as f:
+ f.write(json.dumps(patched_db, indent=2))
+"
+python3 -c "${SCRIPT}" analyzer/compile_commands.json
+
+RUN_CLANG_TIDY+=" -p analyzer -clang-tidy-binary ${CLANG_TIDY} -j ${CPU_COUNT} -header-filter=\".*qbs.*\.h$\" -quiet"
+${RUN_CLANG_TIDY} 2>/dev/null | tee results.txt
+echo "$(grep -c 'warning:' results.txt) warnings in total"
diff --git a/docker/stretch/entrypoint.sh b/scripts/test-qt-for-android.sh
index 04504ffcc..44a64db21 100755
--- a/docker/stretch/entrypoint.sh
+++ b/scripts/test-qt-for-android.sh
@@ -1,9 +1,9 @@
#!/usr/bin/env bash
-set -e
+set -eu
#############################################################################
##
-## Copyright (C) 2019 Richard Weickelt <richard@weickelt.de>
+## Copyright (C) 2019 Richard Weickelt.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qbs.
@@ -40,30 +40,43 @@ set -e
##
#############################################################################
+export PATH="$1:$PATH"
+
#
-# Try to determine the uid of the working directory and adjust the current
-# user's uid/gid accordingly.
+# These are set outside of this script, for instance in the Docker image
#
-WORKDIR_GID=$(stat -c "%g" .)
-WORKDIR_UID=$(stat -c "%u" .)
-USER_NAME=${USER_NAME:-devel}
-EXEC=""
+QT_INSTALL_DIR=/opt/Qt/${QT_VERSION}
+echo "Android SDK installed at ${ANDROID_SDK_ROOT}"
+echo "Android NDK installed at ${ANDROID_NDK_ROOT}"
+echo "Qt installed at ${QT_INSTALL_DIR}"
+
+# Cleaning profiles
+qbs config --unset profiles.qbs_autotests-android
+qbs config --unset profiles.qbs_autotests-android-qt
+
+# Setting auto test profiles
+qbs setup-android --ndk-dir ${ANDROID_HOME}/ndk-bundle --sdk-dir ${ANDROID_HOME} qbs_autotests-android
+qbs setup-android --ndk-dir ${ANDROID_HOME}/ndk-bundle --sdk-dir ${ANDROID_HOME} --qt-dir ${QT_INSTALL_DIR} qbs_autotests-android-qt
+
+export QBS_AUTOTEST_PROFILE=qbs_autotests-android
+export QBS_AUTOTEST_ALWAYS_LOG_STDERR=true
+
+if [ ! "${QT_VERSION}" \< "5.14.0" ]; then
+ echo "Using multi-arch data sets for qml tests (only for qt version >= 5.14) with all architectures"
+ qbs config --list
+ tst_blackbox-android
+
+ echo "Using multi-arch data sets for qml tests (only for qt version >= 5.14) with only armv7a and x86_64"
+ qbs config profiles.qbs_autotests-android-qt.qbs.architectures '["armv7a","x86_64"]'
+ qbs config --list
+ tst_blackbox-android
+fi;
-if [ "$(id -u ${USER_NAME})" != "0" ] && [ "${WORKDIR_UID}" != "0" ] ; then
+echo "Using single-arch (armv7a) data sets for qml tests"
+qbs config --unset profiles.qbs_autotests-android-qt.qbs.architectures
+qbs config profiles.qbs_autotests-android-qt.qbs.architecture armv7a
- export HOME=/home/${USER_NAME}
+qbs config --list
- if [ "$(id -u ${USER_NAME})" != "${WORKDIR_UID}" ]; then
- usermod -u ${WORKDIR_UID} ${USER_NAME}
- groupmod -g ${WORKDIR_GID} ${USER_NAME}
- chown -R -h ${WORKDIR_UID} /home;
- chgrp -R -h ${WORKDIR_GID} /home;
- fi
- EXEC="exec gosu ${USER_NAME}:${USER_NAME}"
-fi
+tst_blackbox-android
-if [ -z "$1" ]; then
- ${EXEC} bash --login
-else
- ${EXEC} bash --login -c "$*"
-fi
diff --git a/share/qbs/imports/qbs/ModUtils/utils.js b/share/qbs/imports/qbs/ModUtils/utils.js
index b48b5eb94..541f531ef 100644
--- a/share/qbs/imports/qbs/ModUtils/utils.js
+++ b/share/qbs/imports/qbs/ModUtils/utils.js
@@ -87,7 +87,7 @@ function artifactInstalledFilePath(artifact) {
throw "installSourceBase is not an absolute path";
if (!artifact.filePath.startsWith(installSourceBase))
throw "artifact file path doesn't start with the value of qbs.installSourceBase";
- return FileInfo.joinPaths(targetDir, artifact.filePath.substr(installSourceBase.length + 1));
+ return FileInfo.joinPaths(targetDir, artifact.filePath.substr(installSourceBase.length));
}
return FileInfo.joinPaths(targetDir, artifact.fileName);
}
diff --git a/share/qbs/imports/qbs/Probes/ClBinaryProbe.qbs b/share/qbs/imports/qbs/Probes/ClBinaryProbe.qbs
new file mode 100644
index 000000000..bcaa9d1f7
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/ClBinaryProbe.qbs
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** 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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.FileInfo
+import qbs.ModUtils
+import qbs.Utilities
+import "path-probe.js" as PathProbeConfigure
+
+BinaryProbe {
+ // input
+ property string preferredArchitecture;
+
+ configure: {
+ var _selectors;
+ var results = PathProbeConfigure.configure(_selectors, names, nameSuffixes, nameFilter,
+ candidateFilter, searchPaths, pathSuffixes,
+ platformSearchPaths, environmentPaths,
+ platformEnvironmentPaths, pathListSeparator);
+ if (!results.found) {
+ var msvcs = Utilities.installedMSVCs(preferredArchitecture);
+ if (msvcs.length >= 1) {
+ var result = {};
+ result.fileName = "cl.exe";
+ result.path = msvcs[0].binPath;
+ result.filePath = FileInfo.joinPaths(path, fileName);
+ result.candidatePaths = result.filePath;
+ results.found = true;
+ results.files = [result];
+ }
+ }
+
+ found = results.found;
+ allResults = results.files;
+
+ if (allResults.length === 1) {
+ var result = allResults[0];
+ candidatePaths = result.candidatePaths;
+ path = result.path;
+ filePath = result.filePath;
+ fileName = result.fileName;
+ }
+
+ }
+}
diff --git a/share/qbs/imports/qbs/Probes/ClangClBinaryProbe.qbs b/share/qbs/imports/qbs/Probes/ClangClBinaryProbe.qbs
new file mode 100644
index 000000000..f4916a37a
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/ClangClBinaryProbe.qbs
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** 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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.FileInfo
+import qbs.ModUtils
+import qbs.Utilities
+import "path-probe.js" as PathProbeConfigure
+
+BinaryProbe {
+ // output
+ property string vcvarsallPath;
+
+ configure: {
+ var _selectors;
+ var results = PathProbeConfigure.configure(_selectors, names, nameSuffixes, nameFilter,
+ candidateFilter, searchPaths, pathSuffixes,
+ platformSearchPaths, environmentPaths,
+ platformEnvironmentPaths, pathListSeparator);
+ var compilerPath;
+ if (results.found)
+ compilerPath = results.files[0].filePath;
+ var compilers = Utilities.installedClangCls(compilerPath);
+ if (compilers.length >= 1) {
+ var result = {};
+ result.fileName = "clang-cl.exe";
+ result.path = compilers[0].toolchainInstallPath;
+ result.filePath = FileInfo.joinPaths(result.path, result.fileName);
+ result.candidatePaths = result.filePath;
+ result.vcvarsallPath = compilers[0].vcvarsallPath;
+ results.found = true;
+ results.files = [result];
+ }
+
+ found = results.found;
+ allResults = results.files;
+
+ if (allResults.length === 1) {
+ var result = allResults[0];
+ candidatePaths = result.candidatePaths;
+ path = result.path;
+ filePath = result.filePath;
+ fileName = result.fileName;
+ vcvarsallPath = result.vcvarsallPath;
+ }
+ }
+}
diff --git a/share/qbs/imports/qbs/Probes/ClangClProbe.qbs b/share/qbs/imports/qbs/Probes/ClangClProbe.qbs
index c7687f0e9..8205e92fa 100644
--- a/share/qbs/imports/qbs/Probes/ClangClProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/ClangClProbe.qbs
@@ -39,7 +39,7 @@ PathProbe {
property string compilerFilePath
property string vcvarsallFilePath
property stringList enableDefinesByLanguage
- property string architecture
+ property string preferredArchitecture
property string _nullDevice: qbs.nullDevice
property string _pathListSeparator: qbs.pathListSeparator
@@ -48,6 +48,7 @@ PathProbe {
property int versionMinor
property int versionPatch
property stringList includePaths
+ property string architecture
property var buildEnv
property var compilerDefinesByLanguage
@@ -57,9 +58,9 @@ PathProbe {
languages = ["c"];
var info = languages.contains("c")
- ? Utilities.clangClCompilerInfo(compilerFilePath, architecture, vcvarsallFilePath, "c") : {};
+ ? Utilities.clangClCompilerInfo(compilerFilePath, preferredArchitecture, vcvarsallFilePath, "c") : {};
var infoCpp = languages.contains("cpp")
- ? Utilities.clangClCompilerInfo(compilerFilePath, architecture, vcvarsallFilePath, "cpp") : {};
+ ? Utilities.clangClCompilerInfo(compilerFilePath, preferredArchitecture, vcvarsallFilePath, "cpp") : {};
found = (!languages.contains("c") ||
(!!info && !!info.macros && !!info.buildEnvironment))
&& (!languages.contains("cpp") ||
@@ -84,5 +85,6 @@ PathProbe {
[], _nullDevice,
_pathListSeparator, "", "");
includePaths = defaultPaths.includePaths;
+ architecture = ModUtils.guessArchitecture(macros);
}
}
diff --git a/share/qbs/imports/qbs/Probes/ConanfileProbe.qbs b/share/qbs/imports/qbs/Probes/ConanfileProbe.qbs
new file mode 100644
index 000000000..e97e45f09
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/ConanfileProbe.qbs
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Richard Weickelt
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** 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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.Process
+import qbs.File
+import qbs.FileInfo
+import qbs.TextFile
+import qbs.Utilities
+
+Probe {
+ // Inputs
+ property stringList additionalArguments: []
+ property path conanfilePath
+ property path packageReference
+ property path executable: "conan" + (qbs.hostOS.contains("windows") ? ".exe": "")
+ property stringList generators: ["json"];
+ property var options
+ property var settings
+
+ // Output
+ property var dependencies
+ property path generatedFilesPath
+ property var json
+
+ // Internal
+ // Ensure that the probe is re-run automatically whenever conanfile changes
+ // by making a file system property part of the probe's signature.
+ property int _conanfileLastModified: conanfilePath ? File.lastModified(conanfilePath) : 0
+ property path _projectBuildDirectory: project.buildDirectory
+
+ configure: {
+ if (conanfilePath && packageReference)
+ throw("conanfilePath and packageReference must not be defined at the same time.");
+
+ if (!conanfilePath && !packageReference)
+ throw("Either conanfilePath or packageReference must be defined.");
+
+ var reference = packageReference || FileInfo.cleanPath(conanfilePath);
+ console.info("Probing '" + reference + "'. This might take a while...");
+ if (conanfilePath && !File.exists(reference))
+ throw("The conanfile '" + reference + "' does not exist.");
+
+ var args = [
+ "install", reference,
+ ];
+
+ if (options) {
+ if (typeof options !== "object")
+ throw("The property 'options' must be an object.");
+ Object.keys(options).forEach(function(key,index) {
+ args.push("-o");
+ args.push(key + "=" + options[key]);
+ });
+ }
+
+ if (settings) {
+ if (typeof settings !== "object")
+ throw("The property 'settings' must be an object.");
+ Object.keys(settings).forEach(function(key,index) {
+ args.push("-s");
+ args.push(key + "=" + settings[key]);
+ });
+ }
+
+ if (!generators.contains("json"))
+ generators.push("json");
+
+ for (var i = 0; i < generators.length; i++)
+ args = args.concat(["-g", generators[i]]);
+
+ for (var i = 0; i < additionalArguments.length; i++)
+ args.push(additionalArguments[i]);
+
+ generatedFilesPath = FileInfo.cleanPath(_projectBuildDirectory +
+ "/genconan/" +
+ Utilities.getHash(args.join()));
+
+ args = args.concat(["-if", generatedFilesPath]);
+ var p = new Process();
+ try {
+ p.exec(executable, args, true);
+ } finally {
+ p.close();
+ }
+
+ if (generators.contains("json")) {
+ if (!File.exists(generatedFilesPath + "/conanbuildinfo.json"))
+ throw("No conanbuildinfo.json has been generated.");
+
+ var jsonFile = new TextFile(generatedFilesPath + "/conanbuildinfo.json", TextFile.ReadOnly);
+ json = JSON.parse(jsonFile.readAll());
+ jsonFile.close();
+
+ dependencies = {};
+ for (var i = 0; i < json.dependencies.length; ++i) {
+ var dep = json.dependencies[i];
+ dependencies[dep.name] = dep;
+ }
+ }
+
+ found = true;
+ }
+}
diff --git a/share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs b/share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs
index 693fb6a01..9081f5efb 100644
--- a/share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs
@@ -3,6 +3,7 @@ import qbs.FileInfo
import "path-probe.js" as PathProbeConfigure
BinaryProbe {
+ nameSuffixes: undefined // _compilerName already contains ".exe" suffix on Windows
// Inputs
property string _compilerName
property string _toolchainPrefix
@@ -48,20 +49,30 @@ BinaryProbe {
configure: {
var selectors;
- var _results = PathProbeConfigure.configure(
+ var results = PathProbeConfigure.configure(
selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths,
pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths,
pathListSeparator);
- found = _results.found;
- var resultFile = _results.files[0];
- candidatePaths = resultFile.candidatePaths;
- path = resultFile.path;
- filePath = resultFile.filePath;
- fileName = resultFile.fileName;
- (nameSuffixes || [""]).forEach(function(suffix) {
- var end = _compilerName + suffix;
- if (fileName.endsWith(end))
- tcPrefix = fileName.slice(0, -end.length);
- });
+
+ found = results.found;
+ if (!found)
+ return;
+
+ var resultsMapper = function(result) {
+ (nameSuffixes || [""]).forEach(function(suffix) {
+ var end = _compilerName + suffix;
+ if (result.fileName.endsWith(end))
+ result.tcPrefix = result.fileName.slice(0, -end.length);
+ });
+ return result;
+ };
+ results.files = results.files.map(resultsMapper);
+ allResults = results.files;
+ var result = results.files[0];
+ candidatePaths = result.candidatePaths;
+ path = result.path;
+ filePath = result.filePath;
+ fileName = result.fileName;
+ tcPrefix = result.tcPrefix;
}
}
diff --git a/share/qbs/imports/qbs/Probes/LibraryProbe.qbs b/share/qbs/imports/qbs/Probes/LibraryProbe.qbs
index 26787d1b4..dfa9890a9 100644
--- a/share/qbs/imports/qbs/Probes/LibraryProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/LibraryProbe.qbs
@@ -29,6 +29,7 @@
****************************************************************************/
PathProbe {
+ property string endianness
nameSuffixes: {
if (qbs.targetOS.contains("windows"))
return [".lib"];
@@ -36,10 +37,34 @@ PathProbe {
return [".dylib", ".a"];
return [".so", ".a"];
}
- platformSearchPaths: qbs.targetOS.contains("unix") ? [
- "/usr/lib",
- "/usr/local/lib",
- ] : []
+ platformSearchPaths: {
+ var result = [];
+ if (qbs.targetOS.contains("unix")) {
+ if (qbs.targetOS.contains("linux") && qbs.architecture) {
+ if (qbs.architecture === "armv7")
+ result = ["/usr/lib/arm-linux-gnueabihf"]
+ else if (qbs.architecture === "arm64")
+ result = ["/usr/lib/aarch64-linux-gnu"]
+ else if (qbs.architecture === "mips" && endianness === "big")
+ result = ["/usr/lib/mips-linux-gnu"]
+ else if (qbs.architecture === "mips" && endianness === "little")
+ result = ["/usr/lib/mipsel-linux-gnu"]
+ else if (qbs.architecture === "mips64")
+ result = ["/usr/lib/mips64el-linux-gnuabi64"]
+ else if (qbs.architecture === "ppc")
+ result = ["/usr/lib/powerpc-linux-gnu"]
+ else if (qbs.architecture === "ppc64")
+ result = ["/usr/lib/powerpc64le-linux-gnu"]
+ else if (qbs.architecture === "x86_64")
+ result = ["/usr/lib64", "/usr/lib/x86_64-linux-gnu"]
+ else if (qbs.architecture === "x86")
+ result = ["/usr/lib32", "/usr/lib/i386-linux-gnu"]
+ }
+ result = result.concat(["/usr/lib", "/usr/local/lib"]);
+ }
+
+ return result;
+ }
nameFilter: {
if (qbs.targetOS.contains("unix")) {
return function(name) {
diff --git a/share/qbs/imports/qbs/Probes/NpmProbe.qbs b/share/qbs/imports/qbs/Probes/NpmProbe.qbs
index f6a99e826..3ca6a96c2 100644
--- a/share/qbs/imports/qbs/Probes/NpmProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/NpmProbe.qbs
@@ -57,18 +57,24 @@ NodeJsProbe {
hostOS.contains("windows"));
v.prepend(interpreterPath);
- var result = results.files[0];
- result.npmBin = results.found
- ? NodeJs.findLocation(result.filePath, "bin", v.value)
- : undefined;
- result.npmRoot = results.found
- ? NodeJs.findLocation(result.filePath, "root", v.value)
- : undefined;
- result.npmPrefix = results.found
- ? NodeJs.findLocation(result.filePath, "prefix", v.value)
- : undefined;
+ var resultsMapper = function(result) {
+ result.npmBin = result.found
+ ? NodeJs.findLocation(result.filePath, "bin", v.value)
+ : undefined;
+ result.npmRoot = result.found
+ ? NodeJs.findLocation(result.filePath, "root", v.value)
+ : undefined;
+ result.npmPrefix = result.found
+ ? NodeJs.findLocation(result.filePath, "prefix", v.value)
+ : undefined;
+ return result;
+ };
+ results.files = results.files.map(resultsMapper);
found = results.found;
+ allResults = results.files;
+
+ var result = results.files[0];
candidatePaths = result.candidatePaths;
path = result.path;
filePath = result.filePath;
diff --git a/share/qbs/imports/qbs/Probes/PathProbe.qbs b/share/qbs/imports/qbs/Probes/PathProbe.qbs
index d0edea682..424a621c6 100644
--- a/share/qbs/imports/qbs/Probes/PathProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/PathProbe.qbs
@@ -70,10 +70,12 @@ Probe {
found = results.found;
allResults = results.files;
- var result = allResults[0];
- candidatePaths = result.candidatePaths;
- path = result.path;
- filePath = result.filePath;
- fileName = result.fileName;
+ if (allResults.length === 1) {
+ var result = allResults[0];
+ candidatePaths = result.candidatePaths;
+ path = result.path;
+ filePath = result.filePath;
+ fileName = result.fileName;
+ }
}
}
diff --git a/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs b/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs
index a35e555cc..6a854a2e6 100644
--- a/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs
@@ -67,16 +67,23 @@ BinaryProbe {
hostOS.contains("windows"));
v.prepend(interpreterPath);
- var result = results.files[0];
- result.version = results.found
- ? TypeScript.findTscVersion(result.filePath, v.value)
- : undefined;
- if (FileInfo.fromNativeSeparators(packageManagerBinPath) !== result.path ||
- !File.exists(FileInfo.fromNativeSeparators(packageManagerRootPath, "typescript"))) {
- result = { found: false };
- }
+ var resultsMapper = function(result) {
+ result.version = result.found
+ ? TypeScript.findTscVersion(result.filePath, v.value)
+ : undefined;
+ if (FileInfo.fromNativeSeparators(packageManagerBinPath) !== result.path ||
+ !File.exists(
+ FileInfo.fromNativeSeparators(packageManagerRootPath, "typescript"))) {
+ result = { found: false };
+ }
+ return result;
+ };
+ results.files = results.files.map(resultsMapper);
found = results.found;
+ allResults = results.files;
+
+ var result = results.files[0];
candidatePaths = result.candidatePaths;
path = result.path;
filePath = result.filePath;
diff --git a/share/qbs/imports/qbs/base/Application.qbs b/share/qbs/imports/qbs/base/Application.qbs
index 694cfb83b..63ffc6283 100644
--- a/share/qbs/imports/qbs/base/Application.qbs
+++ b/share/qbs/imports/qbs/base/Application.qbs
@@ -66,4 +66,12 @@ NativeBinary {
qbs.installDir: installDir
qbs.installSourceBase: isBundle ? destinationDirectory : outer
}
+
+ Group {
+ condition: installDebugInformation
+ fileTagsFilter: ["debuginfo_app"]
+ qbs.install: true
+ qbs.installDir: debugInformationInstallDir
+ qbs.installSourceBase: destinationDirectory
+ }
}
diff --git a/share/qbs/imports/qbs/base/DynamicLibrary.qbs b/share/qbs/imports/qbs/base/DynamicLibrary.qbs
index 267519a42..818665e38 100644
--- a/share/qbs/imports/qbs/base/DynamicLibrary.qbs
+++ b/share/qbs/imports/qbs/base/DynamicLibrary.qbs
@@ -30,24 +30,4 @@
Library {
type: ["dynamiclibrary"].concat(isForAndroid ? ["android.nativelibrary"] : [])
-
- installDir: isBundle ? "Library/Frameworks" : qbs.targetOS.contains("windows")
- ? "bin" : "lib"
- property bool installImportLib: false
- property string importLibInstallDir: "lib"
-
- Group {
- condition: install
- fileTagsFilter: isBundle ? "bundle.content" : ["dynamiclibrary", "dynamiclibrary_symlink"]
- qbs.install: true
- qbs.installDir: installDir
- qbs.installSourceBase: isBundle ? destinationDirectory : outer
- }
-
- Group {
- condition: installImportLib
- fileTagsFilter: "dynamiclibrary_import"
- qbs.install: true
- qbs.installDir: importLibInstallDir
- }
}
diff --git a/share/qbs/imports/qbs/base/Library.qbs b/share/qbs/imports/qbs/base/Library.qbs
index 615c2319f..62e5f9d30 100644
--- a/share/qbs/imports/qbs/base/Library.qbs
+++ b/share/qbs/imports/qbs/base/Library.qbs
@@ -34,4 +34,57 @@ NativeBinary {
return ["staticlibrary"];
return ["dynamiclibrary"].concat(isForAndroid ? ["android.nativelibrary"] : []);
}
+
+ readonly property bool isDynamicLibrary: type.contains("dynamiclibrary")
+ readonly property bool isStaticLibrary: type.contains("staticlibrary")
+ readonly property bool isLoadableModule: type.contains("loadablemodule")
+
+ installDir: {
+ if (isBundle)
+ return "Library/Frameworks";
+ if (isDynamicLibrary)
+ return qbs.targetOS.contains("windows") ? "bin" : "lib";
+ if (isStaticLibrary)
+ return "lib";
+ }
+
+ property bool installImportLib: false
+ property string importLibInstallDir: "lib"
+
+ Group {
+ condition: install
+ fileTagsFilter: {
+ if (isBundle)
+ return ["bundle.content"];
+ if (isDynamicLibrary)
+ return ["dynamiclibrary", "dynamiclibrary_symlink"];
+ if (isStaticLibrary)
+ return ["staticlibrary"];
+ return [];
+ }
+ qbs.install: true
+ qbs.installDir: installDir
+ qbs.installSourceBase: isBundle ? destinationDirectory : outer
+ }
+
+ Group {
+ condition: installImportLib && type.contains("dynamiclibrary")
+ fileTagsFilter: "dynamiclibrary_import"
+ qbs.install: true
+ qbs.installDir: importLibInstallDir
+ }
+
+ Group {
+ condition: installDebugInformation
+ fileTagsFilter: {
+ if (isDynamicLibrary)
+ return ["debuginfo_dll"];
+ else if (isLoadableModule)
+ return ["debuginfo_loadablemodule"];
+ return [];
+ }
+ qbs.install: true
+ qbs.installDir: debugInformationInstallDir
+ qbs.installSourceBase: destinationDirectory
+ }
}
diff --git a/share/qbs/imports/qbs/base/NativeBinary.qbs b/share/qbs/imports/qbs/base/NativeBinary.qbs
index 3597f348f..0928e96bb 100644
--- a/share/qbs/imports/qbs/base/NativeBinary.qbs
+++ b/share/qbs/imports/qbs/base/NativeBinary.qbs
@@ -36,6 +36,9 @@ Product {
property bool install: false
property string installDir
+ property bool installDebugInformation: false
+ property string debugInformationInstallDir: installDir
+
Depends { name: "bundle"; condition: isForDarwin }
aggregate: {
diff --git a/share/qbs/imports/qbs/base/QtApplication.qbs b/share/qbs/imports/qbs/base/QtApplication.qbs
index 32800d294..b6776dca0 100644
--- a/share/qbs/imports/qbs/base/QtApplication.qbs
+++ b/share/qbs/imports/qbs/base/QtApplication.qbs
@@ -30,4 +30,8 @@
CppApplication {
Depends { name: "Qt.core" }
+ Properties {
+ condition: isForAndroid && Qt.android_support._multiAbi
+ targetName: name + "_" + Android.ndk.abi
+ }
}
diff --git a/share/qbs/imports/qbs/base/QtGuiApplication.qbs b/share/qbs/imports/qbs/base/QtGuiApplication.qbs
index 61bc69752..7b2abf017 100644
--- a/share/qbs/imports/qbs/base/QtGuiApplication.qbs
+++ b/share/qbs/imports/qbs/base/QtGuiApplication.qbs
@@ -28,6 +28,6 @@
**
****************************************************************************/
-CppApplication {
+QtApplication {
Depends { name: "Qt.gui" }
}
diff --git a/share/qbs/imports/qbs/base/StaticLibrary.qbs b/share/qbs/imports/qbs/base/StaticLibrary.qbs
index 4eea3c991..5a78a83b0 100644
--- a/share/qbs/imports/qbs/base/StaticLibrary.qbs
+++ b/share/qbs/imports/qbs/base/StaticLibrary.qbs
@@ -30,13 +30,4 @@
Library {
type: ["staticlibrary"]
-
- installDir: isBundle ? "Library/Frameworks" : "lib"
- Group {
- condition: install
- fileTagsFilter: isBundle ? "bundle.content" : "staticlibrary";
- qbs.install: true
- qbs.installDir: installDir
- qbs.installSourceBase: isBundle ? destinationDirectory : outer
- }
}
diff --git a/share/qbs/module-providers/Qt/setup-qt.js b/share/qbs/module-providers/Qt/setup-qt.js
index 3ddc214d3..67a4369ed 100644
--- a/share/qbs/module-providers/Qt/setup-qt.js
+++ b/share/qbs/module-providers/Qt/setup-qt.js
@@ -183,6 +183,11 @@ function guessMinimumWindowsVersion(qtProps) {
return qtProps.qtMajorVersion < 5 ? "5.0" : "5.1";
}
+function needsDSuffix(qtProps) {
+ return !isForMinGw(qtProps) || Utilities.versionCompare(qtProps.qtVersion, "5.14.0") < 0
+ || qtProps.configItems.contains("debug_and_release");
+}
+
function fillEntryPointLibs(qtProps, debug) {
result = [];
var isMinGW = isForMinGw(qtProps);
@@ -198,7 +203,7 @@ function fillEntryPointLibs(qtProps, debug) {
if (isMinGW)
qtmain += "lib";
qtmain += baseNameCandidate + qtProps.qtLibInfix;
- if (debug)
+ if (debug && needsDSuffix(qtProps))
qtmain += 'd';
if (isMinGW) {
qtmain += ".a";
@@ -219,6 +224,19 @@ function fillEntryPointLibs(qtProps, debug) {
return result;
}
+function abiToArchitecture(abi) {
+ switch (abi) {
+ case "armeabi-v7a":
+ return "armv7a";
+ case "arm64-v8a":
+ return "arm64";
+ case "x86":
+ case "x86_64":
+ default:
+ return abi;
+ }
+}
+
function getQtProperties(qmakeFilePath, qbs) {
var queryResult = queryQmake(qmakeFilePath);
var qtProps = {};
@@ -297,6 +315,14 @@ function getQtProperties(qmakeFilePath, qbs) {
if (!File.exists(qtProps.mkspecPath))
throw "mkspec '" + toNative(qtProps.mkspecPath) + "' does not exist";
+ // Starting with qt 5.14, android sdk provides multi-abi
+ if (Utilities.versionCompare(qtProps.qtVersion, "5.14.0") >= 0
+ && qtProps.mkspecPath.contains("android")) {
+ var qdeviceContent = readFileContent(FileInfo.joinPaths(qtProps.mkspecBasePath,
+ "qdevice.pri"));
+ qtProps.androidAbis = configVariable(qdeviceContent, "DEFAULT_ANDROID_ABIS").split(' ');
+ }
+
// determine MSVC version
if (isMsvcQt(qtProps)) {
var msvcMajor = configVariable(qconfigContent, "QT_MSVC_MAJOR_VERSION");
@@ -492,7 +518,7 @@ function isFramework(modInfo, qtProps) {
function libBaseName(modInfo, libName, debugBuild, qtProps) {
var name = libName;
if (qtProps.mkspecName.startsWith("win")) {
- if (debugBuild)
+ if (debugBuild && needsDSuffix(qtProps))
name += 'd';
if (!modInfo.isStaticLibrary && qtProps.qtMajorVersion < 5)
name += qtProps.qtMajorVersion;
@@ -591,7 +617,7 @@ function replaceQtLibNamesWithFilePath(modules, qtProps) {
}
}
-function doSetupLibraries(modInfo, qtProps, debugBuild, nonExistingPrlFiles) {
+function doSetupLibraries(modInfo, qtProps, debugBuild, nonExistingPrlFiles, androidAbi) {
if (!modInfo.hasLibrary)
return; // Can happen for Qt4 convenience modules, like "widgets".
@@ -631,11 +657,14 @@ function doSetupLibraries(modInfo, qtProps, debugBuild, nonExistingPrlFiles) {
var prlFilePath = modInfo.isPlugin
? FileInfo.joinPaths(qtProps.pluginPath, modInfo.pluginData.type)
: (modInfo.libDir ? modInfo.libDir : qtProps.libraryPath);
+ var libDir = prlFilePath;
if (isFramework(modInfo, qtProps)) {
prlFilePath = FileInfo.joinPaths(prlFilePath,
libraryBaseName(modInfo, qtProps, false) + ".framework");
+ libDir = prlFilePath;
+ if (Utilities.versionCompare(qtProps.qtVersion, "5.14") >= 0)
+ prlFilePath = FileInfo.joinPaths(prlFilePath, "Resources");
}
- var libDir = prlFilePath;
var baseName = libraryBaseName(modInfo, qtProps, debugBuild);
if (!qtProps.mkspecName.startsWith("win") && !isFramework(modInfo, qtProps))
baseName = "lib" + baseName;
@@ -644,7 +673,15 @@ function doSetupLibraries(modInfo, qtProps, debugBuild, nonExistingPrlFiles) {
&& !modInfo.isStaticLibrary && qtProps.qtMajorVersion < 5;
if (isNonStaticQt4OnWindows)
prlFilePath = prlFilePath.slice(0, prlFilePath.length - 1); // The prl file base name does *not* contain the version number...
+ if (androidAbi.length > 0
+ && modInfo.name !== "QtBootstrap"
+ && modInfo.name !== "QtQmlDevTools") {
+ prlFilePath += "_";
+ prlFilePath += androidAbi;
+ }
+
prlFilePath += ".prl";
+
try {
var prlFile = new TextFile(prlFilePath, TextFile.ReadOnly);
while (!prlFile.atEof()) {
@@ -738,9 +775,9 @@ function doSetupLibraries(modInfo, qtProps, debugBuild, nonExistingPrlFiles) {
modInfo.libFilePathRelease = libFilePath;
}
-function setupLibraries(qtModuleInfo, qtProps, nonExistingPrlFiles) {
- doSetupLibraries(qtModuleInfo, qtProps, true, nonExistingPrlFiles);
- doSetupLibraries(qtModuleInfo, qtProps, false, nonExistingPrlFiles);
+function setupLibraries(qtModuleInfo, qtProps, nonExistingPrlFiles, androidAbi) {
+ doSetupLibraries(qtModuleInfo, qtProps, true, nonExistingPrlFiles, androidAbi);
+ doSetupLibraries(qtModuleInfo, qtProps, false, nonExistingPrlFiles, androidAbi);
}
function allQt4Modules(qtProps) {
@@ -862,7 +899,7 @@ function allQt4Modules(qtProps) {
module.mustExist = false;
if (qtProps.staticBuild)
module.isStaticLibrary = true;
- setupLibraries(module, qtProps, nonExistingPrlFiles);
+ setupLibraries(module, qtProps, nonExistingPrlFiles, "");
}
replaceQtLibNamesWithFilePath(modules, qtProps);
@@ -1003,7 +1040,7 @@ function removeDuplicatedDependencyLibs(modules) {
traverse(rootModules[i], []);
}
-function allQt5Modules(qtProps) {
+function allQt5Modules(qtProps, androidAbi) {
var nonExistingPrlFiles = [];
var modules = [];
var modulesDir = FileInfo.joinPaths(qtProps.mkspecBasePath, "modules");
@@ -1120,7 +1157,7 @@ function allQt5Modules(qtProps) {
}
}
- setupLibraries(moduleInfo, qtProps, nonExistingPrlFiles);
+ setupLibraries(moduleInfo, qtProps, nonExistingPrlFiles, androidAbi);
modules.push(moduleInfo);
if (moduleInfo.qbsName === "testlib")
@@ -1144,7 +1181,6 @@ function extractQbsArchs(module, qtProps) {
var qbsArch = Utilities.canonicalArchitecture(qtProps.architecture);
if (qbsArch === "arm" && qtProps.mkspecPath.contains("android"))
qbsArch = "armv7a";
-
// Qt4 has "QT_ARCH = windows" in qconfig.pri for both MSVC and mingw.
if (qbsArch === "windows")
return []
@@ -1286,9 +1322,14 @@ function minVersionJsString(minVersion) {
return !minVersion ? "original" : toJSLiteral(minVersion);
}
-function replaceSpecialValues(content, module, qtProps) {
+function replaceSpecialValues(content, module, qtProps, abi) {
+ var architectures = [];
+ if (abi.length > 0)
+ architectures.push(abiToArchitecture(abi));
+ else
+ architectures = extractQbsArchs(module, qtProps);
var dict = {
- archs: toJSLiteral(extractQbsArchs(module, qtProps)),
+ archs: toJSLiteral(architectures),
targetPlatform: toJSLiteral(qbsTargetPlatformFromQtMkspec(qtProps)),
config: toJSLiteral(qtProps.configItems),
qtConfig: toJSLiteral(qtProps.qtConfigItems),
@@ -1372,10 +1413,21 @@ function replaceSpecialValues(content, module, qtProps) {
dict.className = toJSLiteral(module.pluginData.className);
dict["extends"] = toJSLiteral(module.pluginData["extends"]);
}
+ indent = " ";
+ var metaTypesFile = qtProps.libraryPath + "/metatypes/qt"
+ + qtProps.qtMajorVersion + module.qbsName + "_metatypes.json";
+ if (File.exists(metaTypesFile)) {
+ if (additionalContent)
+ additionalContent += "\n" + indent;
+ additionalContent += "Group {\n";
+ additionalContent += indent + indent + "files: " + JSON.stringify(metaTypesFile) + "\n"
+ + indent + indent + "filesAreTargets: true\n"
+ + indent + indent + "fileTags: [\"qt.core.metatypes\"]\n"
+ + indent + "}";
+ }
if (module.hasLibrary && !isFramework(module, qtProps)) {
if (additionalContent)
- additionalContent += "\n";
- indent = " ";
+ additionalContent += "\n" + indent;
additionalContent += "Group {\n";
if (module.isPlugin) {
additionalContent += indent + indent
@@ -1399,8 +1451,8 @@ function replaceSpecialValues(content, module, qtProps) {
return content;
}
-function copyTemplateFile(fileName, targetDirectory, qtProps, location, allFiles, module, pluginMap,
- nonEssentialPlugins)
+function copyTemplateFile(fileName, targetDirectory, qtProps, abi, location, allFiles, module,
+ pluginMap, nonEssentialPlugins)
{
if (!File.makePath(targetDirectory)) {
throw "Cannot create directory '" + toNative(targetDirectory) + "'.";
@@ -1409,12 +1461,13 @@ function copyTemplateFile(fileName, targetDirectory, qtProps, location, allFiles
TextFile.ReadOnly);
var newContent = sourceFile.readAll();
if (module) {
- newContent = replaceSpecialValues(newContent, module, qtProps);
+ newContent = replaceSpecialValues(newContent, module, qtProps, abi);
} else {
newContent = newContent.replace("@allPluginsByType@",
'(' + toJSLiteral(pluginMap) + ')');
newContent = newContent.replace("@nonEssentialPlugins@",
toJSLiteral(nonEssentialPlugins));
+ newContent = newContent.replace("@version@", toJSLiteral(qtProps.qtVersion));
}
sourceFile.close();
var targetPath = FileInfo.joinPaths(targetDirectory, fileName);
@@ -1428,74 +1481,102 @@ function setupOneQt(qmakeFilePath, outputBaseDir, uniquify, location, qbs) {
if (!File.exists(qmakeFilePath))
throw "The specified qmake file path '" + toNative(qmakeFilePath) + "' does not exist.";
var qtProps = getQtProperties(qmakeFilePath, qbs);
- var modules = qtProps.qtMajorVersion < 5 ? allQt4Modules(qtProps) : allQt5Modules(qtProps);
- var pluginsByType = {};
- var nonEssentialPlugins = [];
- for (var i = 0; i < modules.length; ++i) {
- var m = modules[i];
- if (m.isPlugin) {
- if (!pluginsByType[m.pluginData.type])
- pluginsByType[m.pluginData.type] = [];
- pluginsByType[m.pluginData.type].push(m.name);
- if (!m.pluginData.autoLoad)
- nonEssentialPlugins.push(m.name);
+ var androidAbis = [];
+ if (qtProps.androidAbis !== undefined)
+ // Multiple androidAbis detected: Qt >= 5.14
+ androidAbis = qtProps.androidAbis;
+ else
+ // Single abi detected: Qt < 5.14
+ androidAbis.push('');
+ if (androidAbis.length > 1)
+ console.info("Qt with multiple abi detected: '" + androidAbis + "'");
+
+ var relativeSearchPaths = [];
+ for (a = 0; a < androidAbis.length; ++a) {
+ if (androidAbis.length > 1)
+ console.info("Configuring abi '" + androidAbis[a] + "'...");
+ var modules = qtProps.qtMajorVersion < 5 ? allQt4Modules(qtProps) :
+ allQt5Modules(qtProps,androidAbis[a]);
+ var pluginsByType = {};
+ var nonEssentialPlugins = [];
+ for (var i = 0; i < modules.length; ++i) {
+ var m = modules[i];
+ if (m.isPlugin) {
+ if (!pluginsByType[m.pluginData.type])
+ pluginsByType[m.pluginData.type] = [];
+ pluginsByType[m.pluginData.type].push(m.name);
+ if (!m.pluginData.autoLoad)
+ nonEssentialPlugins.push(m.name);
+ }
}
- }
- var relativeSearchPath = uniquify ? Utilities.getHash(qmakeFilePath) : "";
- var qbsQtModuleBaseDir = FileInfo.joinPaths(outputBaseDir, relativeSearchPath, "modules", "Qt");
- if (File.exists(qbsQtModuleBaseDir))
- File.remove(qbsQtModuleBaseDir);
+ var relativeSearchPath = uniquify ? Utilities.getHash(qmakeFilePath) : "";
+ relativeSearchPath = FileInfo.joinPaths(relativeSearchPath, androidAbis[a]);
+ var qbsQtModuleBaseDir = FileInfo.joinPaths(outputBaseDir, relativeSearchPath,
+ "modules", "Qt");
+ if (File.exists(qbsQtModuleBaseDir))
+ File.remove(qbsQtModuleBaseDir);
+
+ var allFiles = [];
+ copyTemplateFile("QtModule.qbs", qbsQtModuleBaseDir, qtProps, androidAbis[a], location,
+ allFiles);
+ copyTemplateFile("QtPlugin.qbs", qbsQtModuleBaseDir, qtProps, androidAbis[a], location,
+ allFiles);
+ copyTemplateFile("plugin_support.qbs",
+ FileInfo.joinPaths(qbsQtModuleBaseDir, "plugin_support"), qtProps,
+ androidAbis[a], location, allFiles, undefined, pluginsByType,
+ nonEssentialPlugins);
- var allFiles = [];
- copyTemplateFile("QtModule.qbs", qbsQtModuleBaseDir, qtProps, location, allFiles);
- copyTemplateFile("QtPlugin.qbs", qbsQtModuleBaseDir, qtProps, location, allFiles);
- copyTemplateFile("plugin_support.qbs", FileInfo.joinPaths(qbsQtModuleBaseDir, "plugin_support"),
- qtProps, location, allFiles, undefined, pluginsByType, nonEssentialPlugins);
-
- for (i = 0; i < modules.length; ++i) {
- var module = modules[i];
- var qbsQtModuleDir = FileInfo.joinPaths(qbsQtModuleBaseDir, module.qbsName);
- var moduleTemplateFileName;
- if (module.qbsName === "core") {
- moduleTemplateFileName = "core.qbs";
- copyTemplateFile("moc.js", qbsQtModuleDir, qtProps, location, allFiles);
- copyTemplateFile("qdoc.js", qbsQtModuleDir, qtProps, location, allFiles);
- } else if (module.qbsName === "gui") {
- moduleTemplateFileName = "gui.qbs";
- } else if (module.qbsName === "scxml") {
- moduleTemplateFileName = "scxml.qbs";
- } else if (module.qbsName === "dbus") {
- moduleTemplateFileName = "dbus.qbs";
- copyTemplateFile("dbus.js", qbsQtModuleDir, qtProps, location, allFiles);
- } else if (module.qbsName === "qml") {
- moduleTemplateFileName = "qml.qbs";
- copyTemplateFile("qml.js", qbsQtModuleDir, qtProps, location, allFiles);
- var qmlcacheStr = "qmlcache";
- if (File.exists(FileInfo.joinPaths(qtProps.binaryPath,
- "qmlcachegen" + exeSuffix(qbs)))) {
- copyTemplateFile(qmlcacheStr + ".qbs",
- FileInfo.joinPaths(qbsQtModuleBaseDir, qmlcacheStr), qtProps,
- location, allFiles);
+ for (i = 0; i < modules.length; ++i) {
+ var module = modules[i];
+ var qbsQtModuleDir = FileInfo.joinPaths(qbsQtModuleBaseDir, module.qbsName);
+ var moduleTemplateFileName;
+ if (module.qbsName === "core") {
+ moduleTemplateFileName = "core.qbs";
+ copyTemplateFile("moc.js", qbsQtModuleDir, qtProps, androidAbis[a], location,
+ allFiles);
+ copyTemplateFile("qdoc.js", qbsQtModuleDir, qtProps, androidAbis[a], location,
+ allFiles);
+ } else if (module.qbsName === "gui") {
+ moduleTemplateFileName = "gui.qbs";
+ } else if (module.qbsName === "scxml") {
+ moduleTemplateFileName = "scxml.qbs";
+ } else if (module.qbsName === "dbus") {
+ moduleTemplateFileName = "dbus.qbs";
+ copyTemplateFile("dbus.js", qbsQtModuleDir, qtProps, androidAbis[a], location,
+ allFiles);
+ } else if (module.qbsName === "qml") {
+ moduleTemplateFileName = "qml.qbs";
+ copyTemplateFile("qml.js", qbsQtModuleDir, qtProps, androidAbis[a], location,
+ allFiles);
+ var qmlcacheStr = "qmlcache";
+ if (File.exists(FileInfo.joinPaths(qtProps.binaryPath,
+ "qmlcachegen" + exeSuffix(qbs)))) {
+ copyTemplateFile(qmlcacheStr + ".qbs",
+ FileInfo.joinPaths(qbsQtModuleBaseDir, qmlcacheStr), qtProps,
+ androidAbis[a], location, allFiles);
+ }
+ } else if (module.qbsName === "quick") {
+ moduleTemplateFileName = "quick.qbs";
+ copyTemplateFile("quick.js", qbsQtModuleDir, qtProps, androidAbis[a], location,
+ allFiles);
+ } else if (module.isPlugin) {
+ moduleTemplateFileName = "plugin.qbs";
+ } else {
+ moduleTemplateFileName = "module.qbs";
}
- } else if (module.qbsName === "quick") {
- moduleTemplateFileName = "quick.qbs";
- copyTemplateFile("quick.js", qbsQtModuleDir, qtProps, location, allFiles);
- } else if (module.isPlugin) {
- moduleTemplateFileName = "plugin.qbs";
- } else {
- moduleTemplateFileName = "module.qbs";
+ copyTemplateFile(moduleTemplateFileName, qbsQtModuleDir, qtProps, androidAbis[a],
+ location, allFiles, module);
}
- copyTemplateFile(moduleTemplateFileName, qbsQtModuleDir, qtProps, location, allFiles,
- module);
- }
- // Note that it's not strictly necessary to copy this one, as it has no variable content.
- // But we do it anyway for consistency.
- copyTemplateFile("android_support.qbs",
- FileInfo.joinPaths(qbsQtModuleBaseDir, "android_support"),
- qtProps, location, allFiles);
- return relativeSearchPath;
+ // Note that it's not strictly necessary to copy this one, as it has no variable content.
+ // But we do it anyway for consistency.
+ copyTemplateFile("android_support.qbs",
+ FileInfo.joinPaths(qbsQtModuleBaseDir, "android_support"),
+ qtProps, androidAbis[a], location, allFiles);
+ relativeSearchPaths.push(relativeSearchPath)
+ }
+ return relativeSearchPaths;
}
function doSetup(qmakeFilePaths, outputBaseDir, location, qbs) {
@@ -1503,19 +1584,20 @@ function doSetup(qmakeFilePaths, outputBaseDir, location, qbs) {
if (!qmakeFilePaths || qmakeFilePaths.length === 0)
return [];
var uniquifySearchPath = qmakeFilePaths.length > 1;
- var searchPaths = [];
+ var allSearchPaths = [];
for (var i = 0; i < qmakeFilePaths.length; ++i) {
try {
console.info("Setting up Qt at '" + toNative(qmakeFilePaths[i]) + "'...");
- var searchPath = setupOneQt(qmakeFilePaths[i], outputBaseDir, uniquifySearchPath,
- location, qbs);
- if (searchPath !== undefined) {
- searchPaths.push(searchPath);
+ var searchPaths = setupOneQt(qmakeFilePaths[i], outputBaseDir, uniquifySearchPath,
+ location, qbs);
+ if (searchPaths.length > 0) {
+ for (var j = 0; j < searchPaths.length; ++j )
+ allSearchPaths.push(searchPaths[j]);
console.info("Qt was set up successfully.");
}
} catch (e) {
console.warn("Error setting up Qt for '" + toNative(qmakeFilePaths[i]) + "': " + e);
}
}
- return searchPaths;
+ return allSearchPaths;
}
diff --git a/share/qbs/module-providers/Qt/templates/android_support.qbs b/share/qbs/module-providers/Qt/templates/android_support.qbs
index c5f842a1f..342018321 100644
--- a/share/qbs/module-providers/Qt/templates/android_support.qbs
+++ b/share/qbs/module-providers/Qt/templates/android_support.qbs
@@ -3,8 +3,10 @@ import qbs.FileInfo
import qbs.ModUtils
import qbs.TextFile
import qbs.Utilities
+import qbs.Process
Module {
+ version: @version@
property bool useMinistro: false
property string qmlRootDir: product.sourceDirectory
property stringList extraPrefixDirs
@@ -22,6 +24,8 @@ Module {
property string _templatesBaseDir: FileInfo.joinPaths(_qtInstallDir, "src", "android")
property string _deployQtOutDir: FileInfo.joinPaths(product.buildDirectory, "deployqt_out")
+ property bool _multiAbi: Utilities.versionCompare(version, "5.14") >= 0
+
Depends { name: "Android.sdk"; condition: _enableSdkSupport }
Depends { name: "Android.ndk"; condition: _enableNdkSupport }
Depends { name: "java"; condition: _enableSdkSupport }
@@ -44,6 +48,11 @@ Module {
condition: _enableNdkSupport && (Android.ndk.abi === "armeabi-v7a" || Android.ndk.abi === "x86")
cpp.defines: "ANDROID_HAS_WSTRING"
}
+ Properties {
+ condition: _enableSdkSupport
+ Android.sdk._archInName: _multiAbi
+ Android.sdk._bundledInAssets: _multiAbi
+ }
Rule {
condition: _enableSdkSupport
@@ -61,30 +70,55 @@ Module {
cmd.sourceCode = function() {
var theBinary;
var nativeLibs = inputs["android.nativelibrary"];
+ var architectures = [];
+ var triples = [];
+ var hostArch;
+ var targetArchitecture;
if (nativeLibs.length === 1) {
theBinary = nativeLibs[0];
+ hostArch = theBinary.Android.ndk.hostArch;
+ targetArchitecture = theBinary.Android.ndk.abi;
+ if (product.Qt.android_support._multiAbi) {
+ architectures.push(theBinary.Android.ndk.abi);
+ triples.push(theBinary.cpp.toolchainTriple);
+ }
} else {
for (i = 0; i < nativeLibs.length; ++i) {
var candidate = nativeLibs[i];
- if (!candidate.fileName.contains(candidate.product.targetName))
- continue;
- if (!theBinary) {
- theBinary = candidate;
- continue;
- }
- if (theBinary.product.name === product.name
- && candidate.product.name !== product.name) {
- continue; // We already have a better match.
- }
- if (candidate.product.name === product.name
- && theBinary.product.name !== product.name) {
- theBinary = candidate; // The new candidate is a better match.
- continue;
+ if (product.Qt.android_support._multiAbi) {
+ if (candidate.product.name === product.name) {
+ architectures.push(candidate.Android.ndk.abi);
+ triples.push(candidate.cpp.toolchainTriple);
+ hostArch = candidate.Android.ndk.hostArch;
+ targetArchitecture = candidate.Android.ndk.abi;
+ theBinary = candidate;
+ }
+ } else {
+ if (!candidate.fileName.contains(candidate.product.targetName))
+ continue;
+ if (!theBinary) {
+ theBinary = candidate;
+ hostArch = theBinary.Android.ndk.hostArch;
+ targetArchitecture = theBinary.Android.ndk.abi;
+ continue;
+ }
+ if (theBinary.product.name === product.name
+ && candidate.product.name !== product.name) {
+ continue; // We already have a better match.
+ }
+ if (candidate.product.name === product.name
+ && theBinary.product.name !== product.name) {
+ theBinary = candidate; // The new candidate is a better match.
+ hostArch = theBinary.Android.ndk.hostArch;
+ targetArchitecture = theBinary.Android.ndk.abi;
+ continue;
+ }
+
+ throw "Qt applications for Android support only one native binary "
+ + "per package.\n"
+ + "In particular, you cannot build a Qt app for more than "
+ + "one architecture at the same time.";
}
- throw "Qt applications for Android support only one native binary "
- + "per package.\n"
- + "In particular, you cannot build a Qt app for more than "
- + "one architecture at the same time.";
}
}
var f = new TextFile(output.filePath, TextFile.WriteOnly);
@@ -99,8 +133,20 @@ Module {
f.writeLine('"toolchain-prefix": "llvm",');
f.writeLine('"tool-prefix": "llvm",');
f.writeLine('"useLLVM": true,');
- f.writeLine('"ndk-host": "' + theBinary.Android.ndk.hostArch + '",');
- f.writeLine('"target-architecture": "' + theBinary.Android.ndk.abi + '",');
+ f.writeLine('"ndk-host": "' + hostArch + '",');
+ if (!product.Qt.android_support._multiAbi) {
+ f.writeLine('"target-architecture": "' + targetArchitecture + '",');
+ }
+ else {
+ var line = '"architectures": {';
+ for (var i in architectures) {
+ line = line + '"' + architectures[i] + '":"' + triples[i] + '"';
+ if (i < architectures.length-1)
+ line = line + ',';
+ }
+ line = line + "},";
+ f.writeLine(line);
+ }
f.writeLine('"qml-root-path": "' + product.Qt.android_support.qmlRootDir + '",');
var deploymentDeps = product.Qt.android_support.deploymentDependencies;
if (deploymentDeps && deploymentDeps.length > 0)
@@ -124,11 +170,16 @@ Module {
f.writeLine('"qml-import-paths": "' + product.qmlImportPaths.join(',') + '",');
// QBS-1429
- f.writeLine('"stdcpp-path": "' + (product.cpp.sharedStlFilePath
+ if (!product.Qt.android_support._multiAbi) {
+ f.writeLine('"stdcpp-path": "' + (product.cpp.sharedStlFilePath
? product.cpp.sharedStlFilePath : product.cpp.staticStlFilePath)
+ '",');
-
- f.writeLine('"application-binary": "' + theBinary.filePath + '"');
+ f.writeLine('"application-binary": "' + theBinary.filePath + '"');
+ } else {
+ f.writeLine('"stdcpp-path": "' + product.Android.sdk.ndkDir +
+ '/toolchains/llvm/prebuilt/' + hostArch + '/sysroot/usr/lib/",');
+ f.writeLine('"application-binary": "' + theBinary.product.name + '"');
+ }
f.writeLine("}");
f.close();
};
@@ -167,7 +218,12 @@ Module {
Rule {
condition: _enableSdkSupport
multiplex: true
- inputs: ["qt_androiddeployqt_input", "android.manifest_processed"]
+ property stringList defaultInputs: ["qt_androiddeployqt_input",
+ "android.manifest_processed"]
+ property stringList allInputs: ["qt_androiddeployqt_input", "android.manifest_processed",
+ "android.nativelibrary"]
+ inputsFromDependencies: "android.nativelibrary"
+ inputs: product.aggregate ? defaultInputs : allInputs
outputFileTags: [
"android.manifest_final", "android.resources", "android.assets", "bundled_jar",
"android.deployqt_list",
@@ -216,9 +272,21 @@ Module {
File.copy(product.Qt.android_support._templatesBaseDir
+ "/templates/res/values/libs.xml",
product.Qt.android_support._deployQtOutDir + "/res/values/libs.xml");
- try {
- File.remove(FileInfo.path(outputs["android.assets"][0].filePath));
- } catch (e) {
+ if (!product.Qt.android_support._multiAbi) {
+ try {
+ File.remove(FileInfo.path(outputs["android.assets"][0].filePath));
+ } catch (e) {
+ }
+ }
+ else {
+ for (var i in inputs["android.nativelibrary"]) {
+ var input = inputs["android.nativelibrary"][i];
+ File.copy(input.filePath,
+ FileInfo.joinPaths(product.Qt.android_support._deployQtOutDir,
+ "libs",
+ input.Android.ndk.abi,
+ input.fileName));
+ }
}
};
var androidDeployQtArgs = [
@@ -228,7 +296,7 @@ Module {
"--android-platform", product.Android.sdk.platform,
];
if (product.Qt.android_support.verboseAndroidDeployQt)
- args.push("--verbose");
+ androidDeployQtArgs.push("--verbose");
var androidDeployQtCmd = new Command(
product.Qt.android_support._androidDeployQtFilePath, androidDeployQtArgs);
androidDeployQtCmd.description = "running androiddeployqt";
@@ -286,7 +354,31 @@ Module {
File.remove(oldLibs[i]);
}
};
- return [copyCmd, androidDeployQtCmd, moveCmd];
+
+ // androiddeployqt doesn't strip the deployed libraries anymore so it has to done here
+ var stripLibsCmd = new JavaScriptCommand();
+ stripLibsCmd.description = "Stripping unneeded symbols from deployed qt libraries";
+ stripLibsCmd.sourceCode = function() {
+ var stripArgs = ["--strip-all"];
+ var architectures = [];
+ for (var i in inputs["android.nativelibrary"])
+ architectures.push(inputs["android.nativelibrary"][i].Android.ndk.abi);
+ for (var i in architectures) {
+ var abiDirPath = FileInfo.joinPaths(product.Android.sdk.apkContentsDir,
+ "lib", architectures[i]);
+ var files = File.directoryEntries(abiDirPath, File.Files);
+ for (var i = 0; i < files.length; ++i) {
+ var filePath = FileInfo.joinPaths(abiDirPath, files[i]);
+ if (FileInfo.suffix(filePath) == "so") {
+ stripArgs.push(filePath);
+ }
+ }
+ }
+ var process = new Process();
+ process.exec(product.cpp.stripPath, stripArgs, false);
+ }
+
+ return [copyCmd, androidDeployQtCmd, moveCmd, stripLibsCmd];
}
}
diff --git a/share/qbs/module-providers/Qt/templates/core.qbs b/share/qbs/module-providers/Qt/templates/core.qbs
index 8e990db22..f3bdf135a 100644
--- a/share/qbs/module-providers/Qt/templates/core.qbs
+++ b/share/qbs/module-providers/Qt/templates/core.qbs
@@ -52,6 +52,10 @@ Module {
property bool staticBuild: @staticBuild@
property stringList pluginMetaData: []
property bool enableKeywords: true
+ property bool generateMetaTypesFile
+ readonly property bool _generateMetaTypesFile: generateMetaTypesFile
+ && Utilities.versionCompare(version, "5.15") >= 0
+ property string metaTypesInstallDir
property stringList availableBuildVariants: @availableBuildVariants@
property string qtBuildVariant: {
@@ -209,7 +213,7 @@ Module {
cpp.windowsApiAdditionalPartitions: mkspecPath.startsWith("winrt-") ? ["phone"] : undefined
cpp.requireAppContainer: mkspecName.startsWith("winrt-")
- additionalProductTypes: ["qm"]
+ additionalProductTypes: ["qm", "qt.core.metatypes"]
validate: {
var validator = new ModUtils.PropertyValidator("Qt.core");
@@ -287,7 +291,7 @@ Module {
inputs: [objcppInput, cppInput]
auxiliaryInputs: "qt_plugin_metadata"
excludedInputs: "unmocable"
- outputFileTags: ["hpp", "unmocable"]
+ outputFileTags: ["hpp", "unmocable", "qt.core.metatypes.in"]
outputArtifacts: Moc.outputArtifacts.apply(Moc, arguments)
prepare: Moc.commands.apply(Moc, arguments)
}
@@ -296,7 +300,7 @@ Module {
inputs: "hpp"
auxiliaryInputs: ["qt_plugin_metadata", "cpp", "objcpp"];
excludedInputs: "unmocable"
- outputFileTags: ["hpp", "cpp", "moc_cpp", "unmocable"]
+ outputFileTags: ["hpp", "cpp", "moc_cpp", "unmocable", "qt.core.metatypes.in"]
outputArtifacts: Moc.outputArtifacts.apply(Moc, arguments)
prepare: Moc.commands.apply(Moc, arguments)
}
@@ -319,6 +323,27 @@ Module {
}
}
+ Rule {
+ multiplex: true
+ inputs: "qt.core.metatypes.in"
+ Artifact {
+ filePath: product.targetName.toLowerCase() + "_metatypes.json"
+ fileTags: "qt.core.metatypes"
+ qbs.install: product.Qt.core.metaTypesInstallDir
+ qbs.installDir: product.Qt.core.metaTypesInstallDir
+ }
+ prepare: {
+ var inputFilePaths = inputs["qt.core.metatypes.in"].map(function(a) {
+ return a.filePath;
+ });
+ var cmd = new Command(Moc.fullPath(product),
+ ["--collect-json", "-o", output.filePath].concat(inputFilePaths));
+ cmd.description = "generating " + output.fileName;
+ cmd.highlight = "codegen";
+ return cmd;
+ }
+ }
+
property path resourceSourceBase
property string resourcePrefix: "/"
property string resourceFileBaseName: product.targetName
diff --git a/share/qbs/module-providers/Qt/templates/moc.js b/share/qbs/module-providers/Qt/templates/moc.js
index aa67766b9..dfc72b7c1 100644
--- a/share/qbs/module-providers/Qt/templates/moc.js
+++ b/share/qbs/module-providers/Qt/templates/moc.js
@@ -30,7 +30,7 @@
var ModUtils = require("qbs.ModUtils");
-function args(product, input, outputFileName)
+function args(product, input, outputs)
{
var defines = product.cpp.compilerDefinesByLanguage;
if (input.fileTags.contains("objcpp"))
@@ -56,6 +56,15 @@ function args(product, input, outputFileName)
}
var pluginMetaData = product.Qt.core.pluginMetaData;
var args = [];
+ if (product.Qt.core._generateMetaTypesFile)
+ args.push("--output-json");
+ var outputFileName;
+ for (tag in outputs) {
+ if (tag !== "qt.core.metatypes.in") {
+ outputFileName = outputs[tag][0].filePath;
+ break;
+ }
+ }
args = args.concat(
defines.map(function(item) { return '-D' + item; }),
includePaths.map(function(item) { return '-I' + item; }),
@@ -90,12 +99,15 @@ function outputArtifacts(project, product, inputs, input)
+ input.completeBaseName + ".moc";
artifact.fileTags.push("hpp");
}
- return [artifact];
+ var artifacts = [artifact];
+ if (product.Qt.core._generateMetaTypesFile)
+ artifacts.push({filePath: artifact.filePath + ".json", fileTags: "qt.core.metatypes.in"});
+ return artifacts;
}
function commands(project, product, inputs, outputs, input, output)
{
- var cmd = new Command(fullPath(product), args(product, input, output.filePath));
+ var cmd = new Command(fullPath(product), args(product, input, outputs));
cmd.description = 'moc ' + input.fileName;
cmd.highlight = 'codegen';
return cmd;
diff --git a/share/qbs/module-providers/Qt/templates/qml.qbs b/share/qbs/module-providers/Qt/templates/qml.qbs
index c95c0f367..c63937649 100644
--- a/share/qbs/module-providers/Qt/templates/qml.qbs
+++ b/share/qbs/module-providers/Qt/templates/qml.qbs
@@ -60,6 +60,60 @@ QtModule {
fileTags: ["qt.qml.js"]
}
+ // Type registration
+ property string importName
+ property string importVersion: product.version
+ readonly property stringList _importVersionParts: (importVersion || "").split(".")
+ property string typesFileName: {
+ if (product.type && product.type.contains("application"))
+ return product.targetName + ".qmltypes";
+ return "plugins.qmltypes";
+ }
+ property string typesInstallDir
+ property stringList extraMetaTypesFiles
+ Properties {
+ condition: importName
+ Qt.core.generateMetaTypesFile: true
+ }
+ Qt.core.generateMetaTypesFile: original
+ Rule {
+ condition: importName
+ inputs: "qt.core.metatypes"
+ multiplex: true
+ explicitlyDependsOnFromDependencies: "qt.core.metatypes"
+ Artifact {
+ filePath: product.targetName.toLowerCase() + "_qmltyperegistrations.cpp"
+ fileTags: ["cpp", "unmocable"]
+ }
+ Artifact {
+ filePath: product.Qt.qml.typesFileName
+ fileTags: "qt.qml.types"
+ qbs.install: product.Qt.qml.typesInstallDir
+ qbs.installDir: product.Qt.qml.typesInstallDir
+ }
+ prepare: {
+ var versionParts = product.Qt.qml._importVersionParts;
+ var args = [
+ "--generate-qmltypes=" + outputs["qt.qml.types"][0].filePath,
+ "--import-name=" + product.Qt.qml.importName,
+ "--major-version=" + versionParts[0],
+ "--minor-version=" + (versionParts.length > 1 ? versionParts[1] : "0")
+ ];
+ var foreignTypes = product.Qt.qml.extraMetaTypesFiles || [];
+ var metaTypeArtifactsFromDeps = explicitlyDependsOn["qt.core.metatypes"] || [];
+ var filePathFromArtifact = function(a) { return a.filePath; };
+ foreignTypes = foreignTypes.concat(metaTypeArtifactsFromDeps.map(filePathFromArtifact));
+ if (foreignTypes.length > 0)
+ args.push("--foreign-types=" + foreignTypes.join(","));
+ args.push("-o", outputs.cpp[0].filePath);
+ args = args.concat(inputs["qt.core.metatypes"].map(filePathFromArtifact));
+ var cmd = new Command(product.Qt.core.binPath + "/qmltyperegistrar", args);
+ cmd.description = "running qmltyperegistrar";
+ cmd.highlight = "codegen";
+ return cmd;
+ }
+ }
+
Rule {
condition: linkPlugins
multiplex: true
@@ -130,4 +184,20 @@ QtModule {
return [cmd];
}
}
+
+ validate: {
+ if (importName) {
+ if (!importVersion)
+ throw "Qt.qml.importVersion must be set if Qt.qml.importName is set.";
+ var isInt = function(value) {
+ return !isNaN(value) && parseInt(Number(value)) == value
+ && !isNaN(parseInt(value, 10));
+ }
+ if (!isInt(_importVersionParts[0])
+ || (_importVersionParts.length > 1 && !isInt(_importVersionParts[1]))) {
+ throw "Qt.qml.importVersion must be of the form x.y, where x and y are integers.";
+ }
+
+ }
+ }
}
diff --git a/share/qbs/module-providers/Qt/templates/quick.qbs b/share/qbs/module-providers/Qt/templates/quick.qbs
index 5968949c8..bf04fe869 100644
--- a/share/qbs/module-providers/Qt/templates/quick.qbs
+++ b/share/qbs/module-providers/Qt/templates/quick.qbs
@@ -38,7 +38,7 @@ import 'quick.js' as QC
QtModule {
qtModuleName: @name@
- Depends { name: "Qt"; submodules: @dependencies@.concat("qml-private") }
+ Depends { name: "Qt"; submodules: @dependencies@ }
hasLibrary: @has_library@
architectures: @archs@
diff --git a/share/qbs/modules/Android/sdk/sdk.qbs b/share/qbs/modules/Android/sdk/sdk.qbs
index f8a046c3a..b4ad5766f 100644
--- a/share/qbs/modules/Android/sdk/sdk.qbs
+++ b/share/qbs/modules/Android/sdk/sdk.qbs
@@ -72,22 +72,25 @@ Module {
property string apkBaseName: packageName
property bool automaticSources: true
property bool legacyLayout: false
- property string sourceSetDir: legacyLayout
+ property path sourceSetDir: legacyLayout
? product.sourceDirectory
: FileInfo.joinPaths(product.sourceDirectory, "src/main")
- property string resourcesDir: FileInfo.joinPaths(sourceSetDir, "res")
- property string assetsDir: FileInfo.joinPaths(sourceSetDir, "assets")
- property string sourcesDir: FileInfo.joinPaths(sourceSetDir, legacyLayout ? "src" : "java")
+ property path resourcesDir: FileInfo.joinPaths(sourceSetDir, "res")
+ property path assetsDir: FileInfo.joinPaths(sourceSetDir, "assets")
+ property path sourcesDir: FileInfo.joinPaths(sourceSetDir, legacyLayout ? "src" : "java")
property string manifestFile: defaultManifestFile
readonly property string defaultManifestFile: FileInfo.joinPaths(sourceSetDir,
"AndroidManifest.xml")
property bool _enableRules: !product.multiplexConfigurationId && !!packageName
+ property bool _archInName: false
+ property bool _bundledInAssets: true
+
Group {
name: "java sources"
condition: Android.sdk.automaticSources
- prefix: Android.sdk.sourcesDir + '/'
+ prefix: FileInfo.resolvePath(product.sourceDirectory, Android.sdk.sourcesDir + '/')
files: "**/*.java"
}
@@ -95,7 +98,7 @@ Module {
name: "android resources"
condition: Android.sdk.automaticSources
fileTags: ["android.resources"]
- prefix: Android.sdk.resourcesDir + '/'
+ prefix: FileInfo.resolvePath(product.sourceDirectory, Android.sdk.resourcesDir + '/')
files: "**/*"
}
@@ -103,7 +106,7 @@ Module {
name: "android assets"
condition: Android.sdk.automaticSources
fileTags: ["android.assets"]
- prefix: Android.sdk.assetsDir + '/'
+ prefix: FileInfo.resolvePath(product.sourceDirectory, Android.sdk.assetsDir + '/')
files: "**/*"
}
@@ -277,6 +280,30 @@ Module {
rootElem.setAttribute("android:versionCode", product.Android.sdk.versionCode);
if (product.Android.sdk.versionName !== undefined)
rootElem.setAttribute("android:versionName", product.Android.sdk.versionName);
+
+ if (product.Android.sdk._bundledInAssets) {
+ // Remove <meta-data android:name="android.app.bundled_in_assets_resource_id"
+ // android:resource="@array/bundled_in_assets"/>
+ // custom AndroidManifest.xml because assets are in rcc files for qt >= 5.14
+ var appElem = rootElem.firstChild("application");
+ if (!appElem || !appElem.isElement() || appElem.tagName() != "application")
+ throw "No application tag found in '" + input.filePath + "'.";
+ var activityElem = appElem.firstChild("activity");
+ if (!activityElem || !activityElem.isElement() ||
+ activityElem.tagName() != "activity")
+ throw "No activity tag found in '" + input.filePath + "'.";
+ var metaDataElem = activityElem.firstChild("meta-data");
+ while (metaDataElem && metaDataElem.isElement()) {
+ if (SdkUtils.elementHasBundledAttributes(metaDataElem)) {
+ var elemToRemove = metaDataElem;
+ metaDataElem = metaDataElem.nextSibling("meta-data");
+ activityElem.removeChild(elemToRemove);
+ } else {
+ metaDataElem = metaDataElem.nextSibling("meta-data");
+ }
+ }
+ }
+
manifestData.save(output.filePath, 4);
}
return cmd;
@@ -415,7 +442,7 @@ Module {
var deploymentData = SdkUtils.gdbserverOrStlDeploymentData(product, inputs);
for (var i = 0; i < deploymentData.uniqueInputs.length; ++i) {
var input = deploymentData.uniqueInputs[i];
- var stripArgs = ["--strip-unneeded", "-o", deploymentData.outputFilePaths[i],
+ var stripArgs = ["--strip-all", "-o", deploymentData.outputFilePaths[i],
input.filePath];
var cmd = new Command(input.cpp.stripPath, stripArgs);
cmd.description = "deploying " + input.fileName;
diff --git a/share/qbs/modules/Android/sdk/utils.js b/share/qbs/modules/Android/sdk/utils.js
index 3af179df2..6d3837d57 100644
--- a/share/qbs/modules/Android/sdk/utils.js
+++ b/share/qbs/modules/Android/sdk/utils.js
@@ -98,7 +98,7 @@ function findParentDir(filePath, parentDirName)
function commonAaptPackageArgs(project, product, inputs, outputs, input, output,
explicitlyDependsOn) {
var manifestFilePath = inputs["android.manifest_final"][0].filePath;
- var args = ["package", "-f",
+ var args = ["package", "--auto-add-overlay", "-f",
"-M", manifestFilePath,
"-I", product.Android.sdk.androidJarFilePath];
var resources = inputs["android.resources"];
@@ -222,3 +222,10 @@ function gdbserverOrStlDeploymentData(product, inputs, type)
}
return data;
}
+
+function elementHasBundledAttributes(element)
+{
+ return element.hasAttribute("android:name") &&
+ (element.attribute("android:name") === "android.app.bundled_in_assets_resource_id") ||
+ (element.attribute("android:name") === "android.app.bundled_in_lib_resource_id");
+}
diff --git a/share/qbs/modules/bundle/BundleModule.qbs b/share/qbs/modules/bundle/BundleModule.qbs
index 1e83dc458..f285c6e61 100644
--- a/share/qbs/modules/bundle/BundleModule.qbs
+++ b/share/qbs/modules/bundle/BundleModule.qbs
@@ -523,7 +523,8 @@ Module {
"bundle.symlink.headers", "bundle.symlink.private-headers",
"bundle.symlink.resources", "bundle.symlink.executable",
"bundle.symlink.version", "bundle.hpp", "bundle.resource",
- "bundle.provisioningprofile", "bundle.content.copied", "bundle.application-executable"]
+ "bundle.provisioningprofile", "bundle.content.copied", "bundle.application-executable",
+ "bundle.code-signature"]
outputArtifacts: {
var i, artifacts = [];
if (ModUtils.moduleProperty(product, "isBundle")) {
@@ -611,6 +612,14 @@ Module {
ModUtils.moduleProperty(product, "bundleName"));
for (var i = 0; i < artifacts.length; ++i)
artifacts[i].bundle = { wrapperPath: wrapperPath };
+
+ if (product.qbs.hostOS.contains("darwin") && product.xcode
+ && product.xcode.signingIdentity) {
+ artifacts.push({
+ filePath: FileInfo.joinPaths(product.bundle.contentsFolderPath, "_CodeSignature/CodeResources"),
+ fileTags: ["bundle.code-signature", "bundle.content"]
+ });
+ }
}
return artifacts;
}
@@ -625,19 +634,8 @@ Module {
if (packageType === "FMWK")
bundleType = "framework";
- var bundles = outputs.bundle;
- for (i in bundles) {
- cmd = new Command("mkdir", ["-p", bundles[i].filePath]);
- cmd.description = "creating " + bundleType + " " + product.targetName;
- commands.push(cmd);
-
- cmd = new Command("touch", ["-c", bundles[i].filePath]);
- cmd.silent = true;
- commands.push(cmd);
- }
-
// Product is unbundled
- if (commands.length === 0) {
+ if (!product.bundle.isBundle) {
cmd = new JavaScriptCommand();
cmd.silent = true;
cmd.sourceCode = function () { };
@@ -764,44 +762,41 @@ Module {
commands.push(cmd);
if (product.moduleProperty("qbs", "hostOS").contains("darwin")) {
- for (i in bundles) {
- var actualSigningIdentity = product.moduleProperty("xcode", "actualSigningIdentity");
- var codesignDisplayName = product.moduleProperty("xcode", "actualSigningIdentityDisplayName");
- if (actualSigningIdentity) {
- // If this is a framework, we need to sign its versioned directory
- var subpath = "";
- var frameworkVersion = ModUtils.moduleProperty(product, "frameworkVersion");
- if (frameworkVersion) {
- subpath = ModUtils.moduleProperty(product, "contentsFolderPath");
- subpath = subpath.substring(subpath.indexOf(ModUtils.moduleProperty("qbs", "pathSeparator")));
- }
-
- var args = product.moduleProperty("xcode", "codesignFlags") || [];
- args.push("--force");
- args.push("--sign", actualSigningIdentity);
- args = args.concat(DarwinTools._codeSignTimestampFlags(product));
-
- for (var j in inputs.xcent) {
- args.push("--entitlements", inputs.xcent[j].filePath);
- break; // there should only be one
- }
- args.push(bundles[i].filePath + subpath);
-
- cmd = new Command(product.moduleProperty("xcode", "codesignPath"), args);
- cmd.description = "codesign "
- + ModUtils.moduleProperty(product, "bundleName")
- + " using " + codesignDisplayName
- + " (" + actualSigningIdentity + ")";
- commands.push(cmd);
+ var actualSigningIdentity = product.moduleProperty("xcode", "actualSigningIdentity");
+ var codesignDisplayName = product.moduleProperty("xcode", "actualSigningIdentityDisplayName");
+ if (actualSigningIdentity) {
+ var args = product.moduleProperty("xcode", "codesignFlags") || [];
+ args.push("--force");
+ args.push("--sign", actualSigningIdentity);
+ args = args.concat(DarwinTools._codeSignTimestampFlags(product));
+
+ for (var j in inputs.xcent) {
+ args.push("--entitlements", inputs.xcent[j].filePath);
+ break; // there should only be one
}
- if (bundleType === "application"
- && product.moduleProperty("qbs", "targetOS").contains("macos")) {
- cmd = new Command(ModUtils.moduleProperty(product, "lsregisterPath"),
- ["-f", bundles[i].filePath]);
- cmd.description = "register " + ModUtils.moduleProperty(product, "bundleName");
- commands.push(cmd);
+ // If this is a framework, we need to sign its versioned directory
+ if (bundleType === "framework") {
+ args.push(product.bundle.contentsFolderPath);
+ } else {
+ args.push(product.bundle.bundleName);
}
+
+ cmd = new Command(product.moduleProperty("xcode", "codesignPath"), args);
+ cmd.workingDirectory = product.destinationDirectory;
+ cmd.description = "codesign "
+ + ModUtils.moduleProperty(product, "bundleName")
+ + " using " + codesignDisplayName
+ + " (" + actualSigningIdentity + ")";
+ commands.push(cmd);
+ }
+
+ if (bundleType === "application"
+ && product.moduleProperty("qbs", "targetOS").contains("macos")) {
+ cmd = new Command(ModUtils.moduleProperty(product, "lsregisterPath"),
+ ["-f", product.bundle.bundleName]);
+ cmd.description = "register " + ModUtils.moduleProperty(product, "bundleName");
+ commands.push(cmd);
}
}
diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs
index bdd6d2750..173c3f3e5 100644
--- a/share/qbs/modules/cpp/CppModule.qbs
+++ b/share/qbs/modules/cpp/CppModule.qbs
@@ -193,6 +193,21 @@ Module {
property bool discardUnusedData
property bool removeDuplicateLibraries: true
+ property string linkerMode: "automatic"
+ PropertyOptions {
+ name: "linkerMode"
+ allowedValues: ["automatic", "manual"]
+ description: "Controls whether to automatically use an appropriate compiler frontend "
+ + "in place of the system linker when linking binaries. The default is \"automatic\", "
+ + "which chooses either the C++ compiler, C compiler, or system linker specified by "
+ + "the linkerName/linkerPath properties, depending on the type of object files "
+ + "present on the linker command line. \"manual\" allows you to explicitly specify "
+ + "the linker using the linkerName/linkerPath properties, and allows linker flags "
+ + "passed to the linkerFlags and platformLinkerFlags properties to be escaped "
+ + "manually (using -Wl or -Xlinker) instead of automatically based on the selected "
+ + "linker."
+ }
+
property stringList assemblerFlags
PropertyOptions {
name: "assemblerFlags"
diff --git a/share/qbs/modules/cpp/DarwinGCC.qbs b/share/qbs/modules/cpp/DarwinGCC.qbs
index 8f3fe72fc..9332603ec 100644
--- a/share/qbs/modules/cpp/DarwinGCC.qbs
+++ b/share/qbs/modules/cpp/DarwinGCC.qbs
@@ -176,7 +176,7 @@ UnixGCC {
? [minimumDarwinVersionCompilerFlag + "=" + minimumDarwinVersion] : []
readonly property stringList minimumDarwinVersionLinkerFlags:
- (minimumDarwinVersionLinkerFlag && minimumDarwinVersion)
+ (minimumDarwinVersionLinkerFlag && minimumDarwinVersion && compilerVersionMajor < 11)
? [minimumDarwinVersionLinkerFlag, minimumDarwinVersion] : []
readonly property var buildEnv: {
diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs
index 63d5db7b8..80de576a9 100644
--- a/share/qbs/modules/cpp/GenericGCC.qbs
+++ b/share/qbs/modules/cpp/GenericGCC.qbs
@@ -148,21 +148,6 @@ CppModule {
property string syslibroot: sysroot
property stringList sysrootFlags: sysroot ? ["--sysroot=" + sysroot] : []
- property string linkerMode: "automatic"
- PropertyOptions {
- name: "linkerMode"
- allowedValues: ["automatic", "manual"]
- description: "Controls whether to automatically use an appropriate compiler frontend "
- + "in place of the system linker when linking binaries. The default is \"automatic\", "
- + "which chooses either the C++ compiler, C compiler, or system linker specified by "
- + "the linkerName/linkerPath properties, depending on the type of object files "
- + "present on the linker command line. \"manual\" allows you to explicitly specify "
- + "the linker using the linkerName/linkerPath properties, and allows linker flags "
- + "passed to the linkerFlags and platformLinkerFlags properties to be escaped "
- + "manually (using -Wl or -Xlinker) instead of automatically based on the selected "
- + "linker."
- }
-
property string exportedSymbolsCheckMode: "ignore-undefined"
PropertyOptions {
name: "exportedSymbolsCheckMode"
diff --git a/share/qbs/modules/cpp/UnixGCC.qbs b/share/qbs/modules/cpp/UnixGCC.qbs
index e5b99cd98..68eacea3f 100644
--- a/share/qbs/modules/cpp/UnixGCC.qbs
+++ b/share/qbs/modules/cpp/UnixGCC.qbs
@@ -32,7 +32,7 @@ import qbs.File
GenericGCC {
condition: qbs.toolchain && qbs.toolchain.contains("gcc")
- && qbs.targetOS && qbs.targetOS.contains("unix")
+ && qbs.targetOS.contains("unix")
priority: -50
staticLibraryPrefix: "lib"
diff --git a/share/qbs/modules/cpp/android-gcc.qbs b/share/qbs/modules/cpp/android-gcc.qbs
index 3e44f4ff3..10190308a 100644
--- a/share/qbs/modules/cpp/android-gcc.qbs
+++ b/share/qbs/modules/cpp/android-gcc.qbs
@@ -182,7 +182,7 @@ LinuxGCC {
fileTags: "android.nativelibrary"
}
prepare: {
- var stripArgs = ["--strip-unneeded", "-o", output.filePath, input.filePath];
+ var stripArgs = ["--strip-all", "-o", output.filePath, input.filePath];
var stripCmd = new Command(product.cpp.stripPath, stripArgs);
stripCmd.description = "Stripping unneeded symbols from " + input.fileName;
return stripCmd;
diff --git a/share/qbs/modules/cpp/freebsd-gcc.qbs b/share/qbs/modules/cpp/freebsd-gcc.qbs
index b5a4b89f3..929c4e557 100644
--- a/share/qbs/modules/cpp/freebsd-gcc.qbs
+++ b/share/qbs/modules/cpp/freebsd-gcc.qbs
@@ -31,7 +31,7 @@
import "freebsd.js" as FreeBSD
UnixGCC {
- condition: qbs.targetOS && qbs.targetOS.contains("freebsd") &&
+ condition: qbs.targetOS.contains("freebsd") &&
qbs.toolchain && qbs.toolchain.contains("gcc")
priority: 1
diff --git a/share/qbs/modules/cpp/iar.js b/share/qbs/modules/cpp/iar.js
index d51668095..df161a2de 100644
--- a/share/qbs/modules/cpp/iar.js
+++ b/share/qbs/modules/cpp/iar.js
@@ -38,144 +38,198 @@ var TemporaryDir = require("qbs.TemporaryDir");
var TextFile = require("qbs.TextFile");
function compilerName(qbs) {
- switch (qbs.architecture) {
- case "arm":
- return "iccarm";
- case "mcs51":
+ var architecture = qbs.architecture;
+ if (architecture.startsWith("arm"))
+ return "iccarm";
+ else if (architecture === "mcs51")
return "icc8051";
- case "avr":
+ else if (architecture === "avr")
return "iccavr";
- case "stm8":
+ else if (architecture === "stm8")
return "iccstm8";
- case "msp430":
+ else if (architecture === "msp430")
return "icc430";
- case "rl78":
+ else if (architecture === "v850")
+ return "iccv850";
+ else if (architecture === "78k")
+ return "icc78k";
+ else if (architecture === "rl78")
return "iccrl78";
- }
+ else if (architecture === "rx")
+ return "iccrx";
+ else if (architecture === "rh850")
+ return "iccrh850";
throw "Unable to deduce compiler name for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
}
function assemblerName(qbs) {
- switch (qbs.architecture) {
- case "arm":
+ var architecture = qbs.architecture;
+ if (architecture.startsWith("arm"))
return "iasmarm";
- case "rl78":
+ else if (architecture === "rl78")
return "iasmrl78";
- case "mcs51":
+ else if (architecture === "rx")
+ return "iasmrx";
+ else if (architecture === "rh850")
+ return "iasmrh850";
+ else if (architecture === "mcs51")
return "a8051";
- case "avr":
+ else if (architecture === "avr")
return "aavr";
- case "stm8":
+ else if (architecture === "stm8")
return "iasmstm8";
- case "msp430":
+ else if (architecture === "msp430")
return "a430";
- }
+ else if (architecture === "v850")
+ return "av850";
+ else if (architecture === "78k")
+ return "a78k";
throw "Unable to deduce assembler name for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
}
function linkerName(qbs) {
- switch (qbs.architecture) {
- case "arm":
+ var architecture = qbs.architecture;
+ if (architecture.startsWith("arm")) {
return "ilinkarm";
- case "stm8":
+ } else if (architecture === "stm8") {
return "ilinkstm8";
- case "rl78":
+ } else if (architecture === "rl78") {
return "ilinkrl78";
- case "mcs51":
- case "avr":
- case "msp430":
+ } else if (architecture === "rx") {
+ return "ilinkrx";
+ } else if (architecture === "rh850") {
+ return "ilinkrh850";
+ } else if (architecture === "mcs51" || architecture === "avr"
+ || architecture === "msp430" || architecture === "v850"
+ || architecture === "78k") {
return "xlink";
}
throw "Unable to deduce linker name for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
}
function archiverName(qbs) {
- switch (qbs.architecture) {
- case "arm":
- case "stm8":
- case "rl78":
+ var architecture = qbs.architecture;
+ if (architecture.startsWith("arm")
+ || architecture === "stm8" || architecture === "rl78"
+ || architecture === "rx" || architecture === "rh850") {
return "iarchive";
- case "mcs51":
- case "avr":
- case "msp430":
+ } else if (architecture === "mcs51" || architecture === "avr"
+ || architecture === "msp430" || architecture === "v850"
+ || architecture === "78k") {
return "xlib";
}
throw "Unable to deduce archiver name for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
}
function staticLibrarySuffix(qbs) {
- switch (qbs.architecture) {
- case "arm":
- case "stm8":
- case "rl78":
+ var architecture = qbs.architecture;
+ if (architecture.startsWith("arm")
+ || architecture === "stm8" || architecture === "rl78"
+ || architecture === "rx" || architecture === "rh850") {
return ".a";
- case "mcs51":
+ } else if (architecture === "mcs51") {
return ".r51";
- case "avr":
+ } else if (architecture === "avr") {
return ".r90";
- case "msp430":
+ } else if (architecture === "msp430") {
return ".r43";
+ } else if (architecture === "v850") {
+ return ".r85";
+ } else if (architecture === "78k") {
+ return ".r26";
}
throw "Unable to deduce static library suffix for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
}
function executableSuffix(qbs) {
- switch (qbs.architecture) {
- case "arm":
- case "stm8":
- case "rl78":
+ var architecture = qbs.architecture;
+ var isDebug = qbs.debugInformation;
+ if (architecture.startsWith("arm")
+ || architecture === "stm8" || architecture === "rl78"
+ || architecture === "rx" || architecture === "rh850") {
return ".out";
- case "mcs51":
- return qbs.debugInformation ? ".d51" : ".a51";
- case "avr":
- return qbs.debugInformation ? ".d90" : ".a90";
- case "msp430":
- return qbs.debugInformation ? ".d43" : ".a43";
+ } else if (architecture === "mcs51") {
+ return isDebug ? ".d51" : ".a51";
+ } else if (architecture === "avr") {
+ return isDebug ? ".d90" : ".a90";
+ } else if (architecture === "msp430") {
+ return isDebug ? ".d43" : ".a43";
+ } else if (architecture === "v850") {
+ return isDebug ? ".d85" : ".a85";
+ } else if (architecture === "78k") {
+ return isDebug ? ".d26" : ".a26";
}
throw "Unable to deduce executable suffix for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
}
function objectSuffix(qbs) {
- switch (qbs.architecture) {
- case "arm":
- case "stm8":
- case "rl78":
+ var architecture = qbs.architecture;
+ if (architecture.startsWith("arm")
+ || architecture === "stm8" || architecture === "rl78"
+ || architecture === "rx" || architecture === "rh850") {
return ".o";
- case "mcs51":
+ } else if (architecture === "mcs51") {
return ".r51";
- case "avr":
+ } else if (architecture === "avr") {
return ".r90";
- case "msp430":
+ } else if (architecture === "msp430") {
return ".r43";
+ } else if (architecture === "v850") {
+ return ".r85";
+ } else if (architecture === "78k") {
+ return ".r26";
}
throw "Unable to deduce object file suffix for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
}
function imageFormat(qbs) {
- switch (qbs.architecture) {
- case "arm":
- case "stm8":
- case "rl78":
+ var architecture = qbs.architecture;
+ if (architecture.startsWith("arm")
+ || architecture === "stm8" || architecture === "rl78"
+ || architecture === "rx" || architecture === "rh850") {
return "elf";
- case "mcs51":
- case "avr":
- case "msp430":
+ } else if (architecture=== "mcs51" || architecture === "avr"
+ || architecture === "msp430" || architecture === "v850"
+ || architecture === "78k") {
return "ubrof";
}
throw "Unable to deduce image format for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
+}
+
+function guessArmArchitecture(core) {
+ var arch = "arm";
+ if (core === "__ARM4M__")
+ arch += "v4m";
+ else if (core === "__ARM4TM__")
+ arch += "v4tm";
+ else if (core === "__ARM5__")
+ arch += "v5";
+ else if (core === "__ARM5E__")
+ arch += "v5e";
+ else if (core === "__ARM6__")
+ arch += "v6";
+ else if (core === "__ARM6M__")
+ arch += "v6m";
+ else if (core === "__ARM6SM__")
+ arch += "v6sm";
+ else if (core === "__ARM7M__")
+ arch += "v7m";
+ else if (core === "__ARM7R__")
+ arch += "v7r";
+ return arch;
}
function guessArchitecture(macros) {
if (macros["__ICCARM__"] === "1")
- return "arm";
+ return guessArmArchitecture(macros["__CORE__"]);
else if (macros["__ICC8051__"] === "1")
return "mcs51";
else if (macros["__ICCAVR__"] === "1")
@@ -186,6 +240,14 @@ function guessArchitecture(macros) {
return "msp430";
else if (macros["__ICCRL78__"] === "1")
return "rl78";
+ else if (macros["__ICCRX__"] === "1")
+ return "rx";
+ else if (macros["__ICCRH850__"] === "1")
+ return "rh850";
+ else if (macros["__ICCV850__"] === "1")
+ return "v850";
+ else if (macros["__ICC78K__"] === "1")
+ return "78k";
}
function guessEndianness(macros) {
@@ -197,17 +259,14 @@ function guessEndianness(macros) {
function guessVersion(macros, architecture)
{
var version = parseInt(macros["__VER__"], 10);
- switch (architecture) {
- case "arm":
+ if (architecture.startsWith("arm")) {
return { major: parseInt(version / 1000000),
minor: parseInt(version / 1000) % 1000,
patch: parseInt(version) % 1000,
found: true }
- case "mcs51":
- case "avr":
- case "stm8":
- case "msp430":
- case "rl78":
+ } else if (architecture === "mcs51" || architecture === "avr" || architecture === "stm8"
+ || architecture === "msp430" || architecture === "rl78" || architecture === "rx"
+ || architecture === "rh850" || architecture === "v850" || architecture === "78k") {
return { major: parseInt(version / 100),
minor: parseInt(version % 100),
patch: 0,
@@ -219,12 +278,16 @@ function cppLanguageOption(compilerFilePath) {
var baseName = FileInfo.baseName(compilerFilePath);
switch (baseName) {
case "iccarm":
- case "rl78":
+ case "iccrl78":
+ case "iccrx":
+ case "iccrh850":
return "--c++";
case "icc8051":
case "iccavr":
case "iccstm8":
case "icc430":
+ case "iccv850":
+ case "icc78k":
return "--ec++";
}
throw "Unable to deduce C++ language option for unsupported compiler: '"
@@ -452,25 +515,29 @@ function compilerFlags(project, product, input, outputs, explicitlyDependsOn) {
break;
}
+ var architecture = input.qbs.architecture;
+
// Warning level flags.
switch (input.cpp.warningLevel) {
case "none":
args.push("--no_warnings");
break;
case "all":
- args.push("--deprecated_feature_warnings="
- +"+attribute_syntax,"
- +"+preprocessor_extensions,"
- +"+segment_pragmas");
- if (tag === "cpp")
- args.push("--warn_about_c_style_casts");
+ if (architecture !== "78k") {
+ args.push("--deprecated_feature_warnings="
+ +"+attribute_syntax,"
+ +"+preprocessor_extensions,"
+ +"+segment_pragmas");
+ if (tag === "cpp")
+ args.push("--warn_about_c_style_casts");
+ }
break;
}
if (input.cpp.treatWarningsAsErrors)
args.push("--warnings_are_errors");
// C language version flags.
- if (tag === "c") {
+ if (tag === "c" && (architecture !== "78k")) {
var knownValues = ["c89"];
var cLanguageVersion = Cpp.languageVersion(
input.cpp.cLanguageVersion, knownValues, "C");
@@ -485,15 +552,11 @@ function compilerFlags(project, product, input, outputs, explicitlyDependsOn) {
}
}
- // Architecture specific flags.
- switch (input.qbs.architecture) {
- case "arm":
- case "rl78":
- // Byte order flags.
- var endianness = input.cpp.endianness;
- if (endianness && input.qbs.architecture === "arm")
- args.push("--endian=" + endianness);
- if (tag === "cpp") {
+ // C++ language version flags.
+ if (tag === "cpp") {
+ if (architecture.startsWith("arm")
+ || architecture === "rl78" || architecture === "rx"
+ || architecture === "rh850") {
// Enable C++ language flags.
args.push("--c++");
// Exceptions flags.
@@ -502,16 +565,18 @@ function compilerFlags(project, product, input, outputs, explicitlyDependsOn) {
// RTTI flags.
if (!input.cpp.enableRtti)
args.push("--no_rtti");
- }
- break;
- case "stm8":
- case "mcs51":
- case "avr":
- case "msp430":
- // Enable C++ language flags.
- if (tag === "cpp")
+ } else if (architecture === "stm8" || architecture === "mcs51"
+ || architecture === "avr" || architecture === "msp430"
+ || architecture === "v850" || architecture === "78k") {
args.push("--ec++");
- break;
+ }
+ }
+
+ // Byte order flags.
+ if (architecture.startsWith("arm") || architecture === "rx") {
+ var endianness = input.cpp.endianness;
+ if (endianness)
+ args.push("--endian=" + endianness);
}
// Listing files generation flag.
@@ -554,9 +619,9 @@ function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) {
args.push("-r");
// Architecture specific flags.
- switch (input.qbs.architecture) {
- case "stm8":
- case "rl78":
+ var architecture = input.qbs.architecture;
+ if (architecture === "stm8" || architecture === "rl78"
+ || architecture === "rx" || architecture === "rh850") {
// Silent output generation flag.
args.push("--silent");
// Warning level flags.
@@ -564,13 +629,11 @@ function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) {
args.push("--no_warnings");
if (input.cpp.treatWarningsAsErrors)
args.push("--warnings_are_errors");
- break;
- default:
+ } else {
// Silent output generation flag.
args.push("-S");
// Warning level flags.
args.push("-w" + (input.cpp.warningLevel === "none" ? "-" : "+"));
- break;
}
// Listing files generation flag.
@@ -614,10 +677,10 @@ function linkerFlags(project, product, input, outputs) {
? inputs.linkerscript.map(function(a) { return a.filePath; }) : [];
// Architecture specific flags.
- switch (product.qbs.architecture) {
- case "arm":
- case "stm8":
- case "rl78":
+ var architecture = product.qbs.architecture;
+ if (architecture.startsWith("arm")
+ || architecture === "stm8" || architecture === "rl78"
+ || architecture === "rx" || architecture === "rh850") {
// Silent output generation flag.
args.push("--silent");
// Map file generation flag.
@@ -628,16 +691,15 @@ function linkerFlags(project, product, input, outputs) {
args.push("--entry", product.cpp.entryPoint);
// Linker scripts flags.
linkerScripts.forEach(function(script) { args.push("--config", script); });
- break;
- case "mcs51":
- case "avr":
- case "msp430":
+ } else if (architecture === "mcs51" || architecture === "avr"
+ || architecture === "msp430" || architecture === "v850"
+ || architecture === "78k") {
// Silent output generation flag.
args.push("-S");
// Debug information flag.
if (product.cpp.debugInformation)
args.push("-rt");
- // Map file generation flag.
+ // Map file generation flag.
if (product.cpp.generateLinkerMapFile)
args.push("-l", outputs.mem_map[0].filePath);
// Entry point flag.
@@ -645,7 +707,6 @@ function linkerFlags(project, product, input, outputs) {
args.push("-s", product.cpp.entryPoint);
// Linker scripts flags.
linkerScripts.forEach(function(script) { args.push("-f", script); });
- break;
}
// Misc flags.
diff --git a/share/qbs/modules/cpp/keil.js b/share/qbs/modules/cpp/keil.js
index befcc5a33..5865d7428 100644
--- a/share/qbs/modules/cpp/keil.js
+++ b/share/qbs/modules/cpp/keil.js
@@ -39,122 +39,192 @@ var TemporaryDir = require("qbs.TemporaryDir");
var TextFile = require("qbs.TextFile");
var Utilities = require("qbs.Utilities");
+function isMcsArchitecture(architecture) {
+ return architecture === "mcs51" || architecture === "mcs251";
+}
+
+function isC166Architecture(architecture) {
+ return architecture === "c166";
+}
+
+function isArmArchitecture(architecture) {
+ return architecture.startsWith("arm");
+}
+
function compilerName(qbs) {
- switch (qbs.architecture) {
- case "mcs51":
+ var architecture = qbs.architecture;
+ if (architecture === "mcs51")
return "c51";
- case "arm":
+ if (architecture === "mcs251")
+ return "c251";
+ if (isC166Architecture(architecture))
+ return "c166";
+ if (isArmArchitecture(architecture))
return "armcc";
- }
throw "Unable to deduce compiler name for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
}
function assemblerName(qbs) {
- switch (qbs.architecture) {
- case "mcs51":
+ var architecture = qbs.architecture;
+ if (architecture === "mcs51")
return "a51";
- case "arm":
+ if (architecture === "mcs251")
+ return "a251";
+ if (isC166Architecture(architecture))
+ return "a166";
+ if (isArmArchitecture(architecture))
return "armasm";
- }
throw "Unable to deduce assembler name for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
}
function linkerName(qbs) {
- switch (qbs.architecture) {
- case "mcs51":
+ var architecture = qbs.architecture;
+ if (architecture === "mcs51")
return "bl51";
- case "arm":
+ if (architecture === "mcs251")
+ return "l251";
+ if (isC166Architecture(architecture))
+ return "l166";
+ if (isArmArchitecture(architecture))
return "armlink";
- }
throw "Unable to deduce linker name for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
}
function archiverName(qbs) {
- switch (qbs.architecture) {
- case "mcs51":
+ var architecture = qbs.architecture;
+ if (architecture === "mcs51")
return "lib51";
- case "arm":
+ if (architecture === "mcs251")
+ return "lib251";
+ if (isC166Architecture(architecture))
+ return "lib166";
+ if (isArmArchitecture(architecture))
return "armar";
- }
throw "Unable to deduce archiver name for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
}
function staticLibrarySuffix(qbs) {
- switch (qbs.architecture) {
- case "mcs51":
- case "arm":
+ var architecture = qbs.architecture;
+ if (isMcsArchitecture(architecture) || isC166Architecture(architecture)
+ || isArmArchitecture(architecture)) {
return ".lib";
}
throw "Unable to deduce static library suffix for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
}
function executableSuffix(qbs) {
- switch (qbs.architecture) {
- case "mcs51":
+ var architecture = qbs.architecture;
+ if (isMcsArchitecture(architecture) || isC166Architecture(architecture))
return ".abs";
- case "arm":
+ if (isArmArchitecture(architecture))
return ".axf";
- }
throw "Unable to deduce executable suffix for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
}
function objectSuffix(qbs) {
- switch (qbs.architecture) {
- case "mcs51":
+ var architecture = qbs.architecture;
+ if (isMcsArchitecture(architecture) || isC166Architecture(architecture))
return ".obj";
- case "arm":
+ if (isArmArchitecture(architecture))
return ".o";
- }
throw "Unable to deduce object file suffix for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
+}
+
+function mapFileSuffix(qbs) {
+ var architecture = qbs.architecture;
+ if (isMcsArchitecture(architecture))
+ return ".m51";
+ if (isC166Architecture(architecture))
+ return ".m66";
+ return ".map";
}
function imageFormat(qbs) {
- switch (qbs.architecture) {
- case "mcs51":
+ var architecture = qbs.architecture;
+ if (isMcsArchitecture(architecture) || isC166Architecture(architecture))
// Keil OMF51 or OMF2 Object Module Format (which is an
// extension of the original Intel OMF51).
return "omf";
- case "arm":
+ if (isArmArchitecture(architecture))
return "elf";
- }
throw "Unable to deduce image format for unsupported architecture: '"
- + qbs.architecture + "'";
+ + architecture + "'";
+}
+
+function guessArmArchitecture(targetArchArm, targetArchThumb) {
+ var arch = "arm";
+ if (targetArchArm === "4" && targetArchThumb === "0")
+ arch += "v4";
+ else if (targetArchArm === "4" && targetArchThumb === "1")
+ arch += "v4t";
+ else if (targetArchArm === "5" && targetArchThumb === "2")
+ arch += "v5t";
+ else if (targetArchArm === "6" && targetArchThumb === "3")
+ arch += "v6";
+ else if (targetArchArm === "6" && targetArchThumb === "4")
+ arch += "v6t2";
+ else if (targetArchArm === "0" && targetArchThumb === "3")
+ arch += "v6m";
+ else if (targetArchArm === "7" && targetArchThumb === "4")
+ arch += "v7r";
+ else if (targetArchArm === "0" && targetArchThumb === "4")
+ arch += "v7m";
+ return arch;
}
function guessArchitecture(macros) {
if (macros["__C51__"])
return "mcs51";
- else if (macros["__CC_ARM"] === 1)
- return "arm";
+ else if (macros["__C251__"])
+ return "mcs251";
+ else if (macros["__C166__"])
+ return "c166";
+ else if (macros["__CC_ARM"] === "1")
+ return guessArmArchitecture(macros["__TARGET_ARCH_ARM"], macros["__TARGET_ARCH_THUMB"]);
}
function guessEndianness(macros) {
- if (macros["__C51__"]) {
+ if (macros["__C51__"] || macros["__C251__"]) {
// The 8051 processors are 8-bit. So, the data with an integer type
// represented by more than one byte is stored as big endian in the
// Keil toolchain. See for more info:
// * http://www.keil.com/support/man/docs/c51/c51_ap_2bytescalar.htm
// * http://www.keil.com/support/man/docs/c51/c51_ap_4bytescalar.htm
+ // * http://www.keil.com/support/man/docs/c251/c251_ap_2bytescalar.htm
+ // * http://www.keil.com/support/man/docs/c251/c251_ap_4bytescalar.htm
return "big";
+ } else if (macros["__C166__"]) {
+ // The C166 processors are 16-bit. So, the data with an integer type
+ // represented by more than one byte is stored as little endian in the
+ // Keil toolchain. See for more info:
+ // * http://www.keil.com/support/man/docs/c166/c166_ap_ints.htm
+ // * http://www.keil.com/support/man/docs/c166/c166_ap_longs.htm
+ return "little";
} else if (macros["__ARMCC_VERSION"]) {
return macros["__BIG_ENDIAN"] ? "big" : "little";
}
}
function guessVersion(macros) {
- if (macros["__C51__"]) {
- var mcsVersion = macros["__C51__"];
+ if (macros["__C51__"] || macros["__C251__"]) {
+ var mcsVersion = macros["__C51__"] || macros["__C251__"];
return { major: parseInt(mcsVersion / 100),
minor: parseInt(mcsVersion % 100),
patch: 0,
found: true }
+ } else if (macros["__C166__"]) {
+ var xcVersion = macros["__C166__"];
+ return { major: parseInt(xcVersion / 100),
+ minor: parseInt(xcVersion % 100),
+ patch: 0,
+ found: true }
} else if (macros["__CC_ARM"]) {
var armVersion = macros["__ARMCC_VERSION"];
return { major: parseInt(armVersion / 1000000),
@@ -164,23 +234,58 @@ function guessVersion(macros) {
}
}
-// Note: The KEIL 8051 compiler does not support the predefined
-// macros dumping. So, we do it with following trick where we try
-// to compile a temporary file and to parse the console output.
-function dumpC51CompilerMacros(compilerFilePath, tag) {
- // C51 compiler support only C language.
+function dumpMcsCompilerMacros(compilerFilePath, tag) {
+ // C51 or C251 compiler support only C language.
if (tag === "cpp")
return {};
+ // Note: The C51 or C251 compiler does not support the predefined
+ // macros dumping. So, we do it with the following trick, where we try
+ // to create and compile a special temporary file and to parse the console
+ // output with the own magic pattern: (""|"key"|"value"|"").
+
function createDumpMacrosFile() {
var td = new TemporaryDir();
var fn = FileInfo.fromNativeSeparators(td.path() + "/dump-macros.c");
var tf = new TextFile(fn, TextFile.WriteOnly);
tf.writeLine("#define VALUE_TO_STRING(x) #x");
tf.writeLine("#define VALUE(x) VALUE_TO_STRING(x)");
- tf.writeLine("#define VAR_NAME_VALUE(var) \"\"\"|\"#var\"|\"VALUE(var)");
- tf.writeLine("#ifdef __C51__");
- tf.writeLine("#pragma message(VAR_NAME_VALUE(__C51__))");
+
+ // Prepare for C51 compiler.
+ tf.writeLine("#if defined(__C51__) || defined(__CX51__)");
+ tf.writeLine("# define VAR_NAME_VALUE(var) \"(\"\"\"\"|\"#var\"|\"VALUE(var)\"|\"\"\"\")\"");
+ tf.writeLine("# if defined (__C51__)");
+ tf.writeLine("# pragma message (VAR_NAME_VALUE(__C51__))");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined(__CX51__)");
+ tf.writeLine("# pragma message (VAR_NAME_VALUE(__CX51__))");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined(__MODEL__)");
+ tf.writeLine("# pragma message (VAR_NAME_VALUE(__MODEL__))");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined(__STDC__)");
+ tf.writeLine("# pragma message (VAR_NAME_VALUE(__STDC__))");
+ tf.writeLine("# endif");
+ tf.writeLine("#endif");
+
+ // Prepare for C251 compiler.
+ tf.writeLine("#if defined(__C251__)");
+ tf.writeLine("# define VAR_NAME_VALUE(var) \"\"|#var|VALUE(var)|\"\"");
+ tf.writeLine("# if defined (__C251__)");
+ tf.writeLine("# warning (VAR_NAME_VALUE(__C251__))");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined (__MODEL__)");
+ tf.writeLine("# warning (VAR_NAME_VALUE(__MODEL__))");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined (__STDC__)");
+ tf.writeLine("# warning (VAR_NAME_VALUE(__STDC__))");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined (__FLOAT64__)");
+ tf.writeLine("# warning (VAR_NAME_VALUE(__FLOAT64__))");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined (__MODSRC__)");
+ tf.writeLine("# warning (VAR_NAME_VALUE(__MODSRC__))");
+ tf.writeLine("# endif");
tf.writeLine("#endif");
tf.close();
return fn;
@@ -191,12 +296,129 @@ function dumpC51CompilerMacros(compilerFilePath, tag) {
p.exec(compilerFilePath, [ fn ], false);
var map = {};
p.readStdOut().trim().split(/\r?\n/g).map(function(line) {
- var parts = line.split("\"|\"", 3);
- map[parts[1]] = parts[2];
+ var parts = line.split("\"|\"", 4);
+ if (parts.length === 4)
+ map[parts[1]] = parts[2];
});
return map;
}
+function dumpC166CompilerMacros(compilerFilePath, tag) {
+ // C166 compiler support only C language.
+ if (tag === "cpp")
+ return {};
+
+ // Note: The C166 compiler does not support the predefined
+ // macros dumping. Also, it does not support the '#pragma' and
+ // '#message|warning|error' directives properly (it is impossible
+ // to print to console the value of macro).
+ // So, we do it with the following trick, where we try
+ // to create and compile a special temporary file and to parse the console
+ // output with the own magic pattern, e.g:
+ //
+ // *** WARNING C320 IN LINE 41 OF c51.c: __C166__
+ // *** WARNING C2 IN LINE 42 OF c51.c: '757': unknown #pragma/control, line ignored
+ //
+ // where the '__C166__' is a key, and the '757' is a value.
+
+ function createDumpMacrosFile() {
+ var td = new TemporaryDir();
+ var fn = FileInfo.fromNativeSeparators(td.path() + "/dump-macros.c");
+ var tf = new TextFile(fn, TextFile.WriteOnly);
+
+ // Prepare for C166 compiler.
+ tf.writeLine("#if defined(__C166__)");
+ tf.writeLine("# if defined(__C166__)");
+ tf.writeLine("# warning __C166__");
+ tf.writeLine("# pragma __C166__");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined(__DUS__)");
+ tf.writeLine("# warning __DUS__");
+ tf.writeLine("# pragma __DUS__");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined(__MAC__)");
+ tf.writeLine("# warning __MAC__");
+ tf.writeLine("# pragma __MAC__");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined(__MOD167__)");
+ tf.writeLine("# warning __MOD167__");
+ tf.writeLine("# pragma __MOD167__");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined(__MODEL__)");
+ tf.writeLine("# warning __MODEL__");
+ tf.writeLine("# pragma __MODEL__");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined(__MODV2__)");
+ tf.writeLine("# warning __MODV2__");
+ tf.writeLine("# pragma __MODV2__");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined(__SAVEMAC__)");
+ tf.writeLine("# warning __SAVEMAC__");
+ tf.writeLine("# pragma __SAVEMAC__");
+ tf.writeLine("# endif");
+ tf.writeLine("# if defined(__STDC__)");
+ tf.writeLine("# warning __STDC__");
+ tf.writeLine("# pragma __STDC__");
+ tf.writeLine("# endif");
+ tf.writeLine("#endif");
+
+ tf.close();
+ return fn;
+ }
+
+ var fn = createDumpMacrosFile();
+ var p = new Process();
+ p.exec(compilerFilePath, [ fn ], false);
+ var lines = p.readStdOut().trim().split(/\r?\n/g);
+
+ var map = {};
+ for (var i = 0; i < lines.length; ++i) {
+ // First line should contains the macro key.
+ var keyLine = lines[i];
+ if (!keyLine.startsWith("***"))
+ continue;
+ var key;
+ if (keyLine.endsWith("__C166__"))
+ key = "__C166__";
+ else if (keyLine.endsWith("__DUS__"))
+ key = "__DUS__";
+ else if (keyLine.endsWith("__MAC__"))
+ key = "__MAC__";
+ else if (keyLine.endsWith("__MOD167__"))
+ key = "__MOD167__";
+ else if (keyLine.endsWith("__MODEL__"))
+ key = "__MODEL__";
+ else if (keyLine.endsWith("__MODV2__"))
+ key = "__MODV2__";
+ else if (keyLine.endsWith("__SAVEMAC__"))
+ key = "__SAVEMAC__";
+ else if (keyLine.endsWith("__STDC__"))
+ key = "__STDC__";
+ else
+ continue;
+
+ i += 1;
+ if (i >= lines.length)
+ break;
+
+ // Second line should contains the macro value.
+ var valueLine = lines[i];
+ if (!valueLine.startsWith("***"))
+ continue;
+
+ var startQuoteIndex = valueLine.indexOf("'");
+ if (startQuoteIndex === -1)
+ continue;
+ var stopQuoteIndex = valueLine.indexOf("'", startQuoteIndex + 1);
+ if (stopQuoteIndex === -1)
+ continue;
+
+ var value = valueLine.substring(startQuoteIndex + 1, stopQuoteIndex);
+ map[key] = value;
+ }
+ return map;
+}
+
function dumpArmCompilerMacros(compilerFilePath, tag, nullDevice) {
var args = [ "-E", "--list-macros", nullDevice ];
if (tag === "cpp")
@@ -215,18 +437,21 @@ function dumpArmCompilerMacros(compilerFilePath, tag, nullDevice) {
}
function dumpMacros(compilerFilePath, tag, nullDevice) {
- var map1 = dumpC51CompilerMacros(compilerFilePath, tag, nullDevice);
- var map2 = dumpArmCompilerMacros(compilerFilePath, tag, nullDevice);
+ var map1 = dumpMcsCompilerMacros(compilerFilePath, tag, nullDevice);
+ var map2 = dumpC166CompilerMacros(compilerFilePath, tag, nullDevice);
+ var map3 = dumpArmCompilerMacros(compilerFilePath, tag, nullDevice);
var map = {};
for (var key1 in map1)
map[key1] = map1[key1];
for (var key2 in map2)
map[key2] = map2[key2];
+ for (var key3 in map3)
+ map[key3] = map3[key3];
return map;
}
function dumpDefaultPaths(compilerFilePath, architecture) {
- var incDir = (architecture === "arm") ? "include" : "inc";
+ var incDir = (isArmArchitecture(architecture)) ? "include" : "inc";
var includePath = compilerFilePath.replace(/bin[\\\/](.*)$/i, incDir);
return {
"includePaths": [includePath]
@@ -242,9 +467,9 @@ function adjustPathsToWindowsSeparators(sourcePaths) {
}
function getMaxExitCode(architecture) {
- if (architecture === "mcs51")
+ if (isMcsArchitecture(architecture))
return 1;
- else if (architecture === "arm")
+ else if (isArmArchitecture(architecture))
return 0;
}
@@ -308,20 +533,28 @@ function filterStdOutput(cmd) {
var sourceLines = output.split("\n");
var filteredLines = [];
for (var i in sourceLines) {
- if (sourceLines[i].startsWith("***")
- || sourceLines[i].startsWith(">>")
- || sourceLines[i].startsWith(" ")
- || sourceLines[i].startsWith("Program Size:")
- || sourceLines[i].startsWith("A51 FATAL")
- || sourceLines[i].startsWith("C51 FATAL")
- || sourceLines[i].startsWith("ASSEMBLER INVOKED BY")
- || sourceLines[i].startsWith("LOC OBJ LINE SOURCE")
- ) {
+ var line = sourceLines[i];
+ if (line.startsWith("***")
+ || line.startsWith(">>")
+ || line.startsWith(" ")
+ || line.startsWith(" ACTION:")
+ || line.startsWith(" LINE:")
+ || line.startsWith(" ERROR:")
+ || line.startsWith("Program Size:")
+ || line.startsWith("A51 FATAL")
+ || line.startsWith("C51 FATAL")
+ || line.startsWith("C251 FATAL")
+ || line.startsWith("ASSEMBLER INVOKED BY")
+ || line.startsWith("LOC OBJ LINE SOURCE")) {
filteredLines.push(sourceLines[i]);
+ } else if (line.startsWith("C251 COMPILER")
+ || line.startsWith("C251 COMPILATION COMPLETE")
+ || line.startsWith("C251 TERMINATED")) {
+ continue;
} else {
var regexp = /^([0-9A-F]{4})/;
- if (regexp.exec(sourceLines[i]))
- filteredLines.push(sourceLines[i]);
+ if (regexp.exec(line))
+ filteredLines.push(line);
}
}
return filteredLines.join("\n");
@@ -339,7 +572,7 @@ function compilerOutputArtifacts(input, useListing) {
artifacts.push({
fileTags: ["lst"],
filePath: Utilities.getHash(input.baseDir) + "/"
- + (input.cpp.architecture === "mcs51"
+ + (isMcsArchitecture(input.cpp.architecture)
? input.fileName : input.baseName)
+ ".lst"
});
@@ -358,8 +591,7 @@ function applicationLinkerOutputArtifacts(product) {
fileTags: ["mem_map"],
filePath: FileInfo.joinPaths(
product.destinationDirectory,
- product.targetName
- + (product.cpp.architecture === "mcs51" ? ".m51" : ".map"))
+ product.targetName + product.cpp.mapFileSuffix)
};
return [app, mem_map];
}
@@ -399,7 +631,7 @@ function compilerFlags(project, product, input, outputs, explicitlyDependsOn) {
allIncludePaths = allIncludePaths.uniqueConcat(compilerIncludePaths);
var architecture = input.qbs.architecture;
- if (architecture === "mcs51") {
+ if (isMcsArchitecture(architecture) || isC166Architecture(architecture)) {
// Input.
args.push(FileInfo.toWindowsSeparators(input.filePath));
@@ -440,7 +672,8 @@ function compilerFlags(project, product, input, outputs, explicitlyDependsOn) {
break;
case "all":
args.push("WARNINGLEVEL (2)");
- args.push("FARWARNING");
+ if (architecture === "mcs51")
+ args.push("FARWARNING");
break;
}
@@ -449,7 +682,7 @@ function compilerFlags(project, product, input, outputs, explicitlyDependsOn) {
args.push("NOPRINT");
else
args.push("PRINT(" + FileInfo.toWindowsSeparators(outputs.lst[0].filePath) + ")");
- } else if (architecture === "arm") {
+ } else if (isArmArchitecture(architecture)) {
// Input.
args.push("-c", input.filePath);
@@ -571,7 +804,7 @@ function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) {
allIncludePaths = allIncludePaths.uniqueConcat(compilerIncludePaths);
var architecture = input.qbs.architecture;
- if (architecture === "mcs51") {
+ if (isMcsArchitecture(architecture) || isC166Architecture(architecture)) {
// Input.
args.push(FileInfo.toWindowsSeparators(input.filePath));
@@ -600,7 +833,7 @@ function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) {
args.push("NOPRINT");
else
args.push("PRINT(" + FileInfo.toWindowsSeparators(outputs.lst[0].filePath) + ")");
- } else if (architecture === "arm") {
+ } else if (isArmArchitecture(architecture)) {
// Input.
args.push(input.filePath);
@@ -653,8 +886,8 @@ function linkerFlags(project, product, input, outputs) {
var args = [];
var architecture = product.qbs.architecture;
- if (architecture === "mcs51") {
- // Note: The C51 linker does not distinguish an object files and
+ if (isMcsArchitecture(architecture) || isC166Architecture(architecture)) {
+ // Note: The C51/256/166 linker does not distinguish an object files and
// a libraries, it interpret all this stuff as an input objects,
// so, we need to pass it together in one string.
@@ -683,7 +916,7 @@ function linkerFlags(project, product, input, outputs) {
// Map file generation flag.
if (!product.cpp.generateLinkerMapFile)
args.push("NOMAP");
- } else if (architecture === "arm") {
+ } else if (isArmArchitecture(architecture)) {
// Inputs.
if (inputs.obj)
args = args.concat(inputs.obj.map(function(obj) { return obj.filePath }));
@@ -728,7 +961,7 @@ function archiverFlags(project, product, input, outputs) {
var args = [];
var architecture = product.qbs.architecture;
- if (architecture === "mcs51") {
+ if (isMcsArchitecture(architecture) || isC166Architecture(architecture)) {
// Library creation command.
args.push("TRANSFER");
@@ -749,7 +982,7 @@ function archiverFlags(project, product, input, outputs) {
// Note: We need to wrap a output file name with quotes. Otherwise
// the linker will ignore a specified file name.
args.push("TO", '"' + FileInfo.toWindowsSeparators(outputs.staticlibrary[0].filePath) + '"');
- } else if (architecture === "arm") {
+ } else if (isArmArchitecture(architecture)) {
// Note: The ARM archiver command line expect the output file
// first, and then a set of input objects.
@@ -780,7 +1013,6 @@ function prepareCompiler(project, product, inputs, outputs, input, output, expli
return [cmd];
}
-
function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
var args = assemblerFlags(project, product, input, outputs, explicitlyDependsOn);
var assemblerPath = input.cpp.assemblerPath;
diff --git a/share/qbs/modules/cpp/keil.qbs b/share/qbs/modules/cpp/keil.qbs
index 67ea5e675..357052777 100644
--- a/share/qbs/modules/cpp/keil.qbs
+++ b/share/qbs/modules/cpp/keil.qbs
@@ -88,6 +88,7 @@ CppModule {
executableSuffix: KEIL.executableSuffix(qbs)
property string objectSuffix: KEIL.objectSuffix(qbs)
+ property string mapFileSuffix: KEIL.mapFileSuffix(qbs)
imageFormat: KEIL.imageFormat(qbs)
diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js
index b67ab811f..c06286cbe 100644
--- a/share/qbs/modules/cpp/msvc.js
+++ b/share/qbs/modules/cpp/msvc.js
@@ -35,6 +35,22 @@ var ModUtils = require("qbs.ModUtils");
var Utilities = require("qbs.Utilities");
var WindowsUtils = require("qbs.WindowsUtils");
+function effectiveLinkerPath(product, inputs) {
+ if (product.cpp.linkerMode === "automatic") {
+ var compiler = product.cpp.compilerPath;
+ if (compiler) {
+ if (inputs.obj || inputs.staticlibrary) {
+ console.log("Found C/C++ objects, using compiler as a linker for " + product.name);
+ return compiler;
+ }
+ }
+
+ console.log("Found no C-language objects, choosing system linker for " + product.name);
+ }
+
+ return product.cpp.linkerPath;
+}
+
function handleCpuFeatures(input, flags) {
if (!input.qbs.architecture)
return;
@@ -90,6 +106,15 @@ function addLanguageVersionFlag(input, args) {
args.push(flag);
}
+function handleClangClArchitectureFlags(product, architecture, flags) {
+ if (product.qbs.toolchain.contains("clang-cl")) {
+ if (architecture === "x86")
+ flags.push("-m32");
+ else if (architecture === "x86_64")
+ flags.push("-m64");
+ }
+}
+
function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
var i;
var debugInformation = input.cpp.debugInformation;
@@ -135,6 +160,8 @@ function prepareCompiler(project, product, inputs, outputs, input, output, expli
break;
}
+ handleClangClArchitectureFlags(product, input.cpp.architecture, args);
+
if (debugInformation) {
if (product.cpp.separateDebugInformation)
args.push('/Zi');
@@ -150,6 +177,10 @@ function prepareCompiler(project, product, inputs, outputs, input, output, expli
args.push(rtl);
}
+ var driverFlags = product.cpp.driverFlags;
+ if (driverFlags)
+ args = args.concat(driverFlags);
+
// warnings:
var warningLevel = input.cpp.warningLevel;
if (warningLevel === 'none')
@@ -315,7 +346,6 @@ function collectLibraryDependencies(product) {
function traverse(dep) {
if (seen.hasOwnProperty(dep.name))
return;
- seen[dep.name] = true;
if (dep.parameters.cpp && dep.parameters.cpp.link === false)
return;
@@ -324,10 +354,12 @@ function collectLibraryDependencies(product) {
var dynamicLibraryArtifacts = staticLibraryArtifacts
? null : dep.artifacts["dynamiclibrary_import"];
if (staticLibraryArtifacts) {
+ seen[dep.name] = true;
dep.dependencies.forEach(traverse);
addArtifactFilePaths(dep, staticLibraryArtifacts);
addExternalLibs(dep);
} else if (dynamicLibraryArtifacts) {
+ seen[dep.name] = true;
addArtifactFilePaths(dep, dynamicLibraryArtifacts);
}
}
@@ -360,44 +392,71 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
return a.filePath;
});
var generateManifestFiles = !linkDLL && product.cpp.generateManifestFile;
- var canEmbedManifest = (product.cpp.compilerVersionMajor >= 17); // VS 2012
+ var useClangCl = product.qbs.toolchain.contains("clang-cl");
+ var canEmbedManifest = useClangCl || product.cpp.compilerVersionMajor >= 17 // VS 2012
+
+ var linkerPath = effectiveLinkerPath(product, inputs);
+ var useCompilerDriver = linkerPath === product.cpp.compilerPath;
+ // args variable is built as follows:
+ // [linkerWrapper] linkerPath /nologo [driverFlags driverLinkerFlags]
+ // allInputs libDeps [/link] linkerArgs
+ var args = []
+
+ if (useCompilerDriver) {
+ args.push('/nologo');
+ var driverFlags = product.cpp.driverFlags;
+ if (driverFlags)
+ args = args.concat(driverFlags);
+ var driverLinkerFlags = product.cpp.driverLinkerFlags;
+ if (driverLinkerFlags)
+ args = args.concat(driverLinkerFlags);
+ }
+
+ var allInputs = inputs.obj || [];
+ for (i in allInputs) {
+ var fileName = FileInfo.toWindowsSeparators(allInputs[i].filePath)
+ args.push(fileName)
+ }
- var args = ['/nologo']
+ var linkerArgs = ['/nologo']
if (linkDLL) {
- args.push('/DLL');
- args.push('/IMPLIB:' + FileInfo.toWindowsSeparators(outputs.dynamiclibrary_import[0].filePath));
+ linkerArgs.push('/DLL');
+ linkerArgs.push('/IMPLIB:' + FileInfo.toWindowsSeparators(outputs.dynamiclibrary_import[0].filePath));
}
if (debugInformation) {
- args.push("/DEBUG");
+ linkerArgs.push("/DEBUG");
var debugInfo = outputs.debuginfo_app || outputs.debuginfo_dll;
if (debugInfo)
- args.push("/PDB:" + debugInfo[0].fileName);
+ linkerArgs.push("/PDB:" + debugInfo[0].fileName);
} else {
- args.push('/INCREMENTAL:NO')
+ linkerArgs.push('/INCREMENTAL:NO')
}
switch (product.qbs.architecture) {
case "x86":
- args.push("/MACHINE:X86");
+ linkerArgs.push("/MACHINE:X86");
break;
case "x86_64":
- args.push("/MACHINE:X64");
+ linkerArgs.push("/MACHINE:X64");
break;
case "ia64":
- args.push("/MACHINE:IA64");
+ linkerArgs.push("/MACHINE:IA64");
break;
case "armv7":
- args.push("/MACHINE:ARM");
+ linkerArgs.push("/MACHINE:ARM");
break;
case "arm64":
- args.push("/MACHINE:ARM64");
+ linkerArgs.push("/MACHINE:ARM64");
break;
}
+ if (useCompilerDriver)
+ handleClangClArchitectureFlags(product, product.qbs.architecture, args);
+
var requireAppContainer = product.cpp.requireAppContainer;
if (requireAppContainer !== undefined)
- args.push("/APPCONTAINER" + (requireAppContainer ? "" : ":NO"));
+ linkerArgs.push("/APPCONTAINER" + (requireAppContainer ? "" : ":NO"));
var minimumWindowsVersion = product.cpp.minimumWindowsVersion;
var subsystemSwitch = undefined;
@@ -407,26 +466,29 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
subsystemSwitch = product.consoleApplication === false ? '/SUBSYSTEM:WINDOWS' : '/SUBSYSTEM:CONSOLE';
}
+ var useLldLink = useCompilerDriver && product.cpp.linkerVariant === "lld"
+ || !useCompilerDriver && product.cpp.linkerName === "lld-link.exe";
if (minimumWindowsVersion) {
var subsystemVersion = WindowsUtils.getWindowsVersionInFormat(minimumWindowsVersion,
'subsystem');
if (subsystemVersion) {
subsystemSwitch += ',' + subsystemVersion;
- if (product.cpp.linkerName !== "lld-link.exe") // llvm linker does not support /OSVERSION
- args.push('/OSVERSION:' + subsystemVersion);
+ // llvm linker does not support /OSVERSION
+ if (!useLldLink)
+ linkerArgs.push('/OSVERSION:' + subsystemVersion);
}
}
if (subsystemSwitch)
- args.push(subsystemSwitch);
+ linkerArgs.push(subsystemSwitch);
var linkerOutputNativeFilePath = FileInfo.toWindowsSeparators(primaryOutput.filePath);
var manifestFileNames = [];
if (generateManifestFiles) {
if (canEmbedManifest) {
- args.push("/MANIFEST:embed");
+ linkerArgs.push("/MANIFEST:embed");
additionalManifestInputs.forEach(function (manifestFileName) {
- args.push("/MANIFESTINPUT:" + manifestFileName);
+ linkerArgs.push("/MANIFESTINPUT:" + manifestFileName);
});
} else {
linkerOutputNativeFilePath
@@ -435,17 +497,11 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
+ primaryOutput.fileName);
var manifestFileName = linkerOutputNativeFilePath + ".manifest";
- args.push('/MANIFEST', '/MANIFESTFILE:' + manifestFileName);
+ linkerArgs.push('/MANIFEST', '/MANIFESTFILE:' + manifestFileName);
manifestFileNames = [manifestFileName].concat(additionalManifestInputs);
}
}
- var allInputs = inputs.obj || [];
- for (i in allInputs) {
- var fileName = FileInfo.toWindowsSeparators(allInputs[i].filePath)
- args.push(fileName)
- }
-
var wholeArchiveSupported = linkerSupportsWholeArchive(product);
var wholeArchiveRequested = false;
var libDeps = collectLibraryDependencies(product);
@@ -456,8 +512,16 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
if (lib === prevLib)
continue;
prevLib = lib;
- args.push((wholeArchiveSupported && dep.wholeArchive ? "/WHOLEARCHIVE:" : "")
- + FileInfo.toWindowsSeparators(lib));
+
+ if (wholeArchiveSupported && dep.wholeArchive) {
+ // need to pass libraries to the driver to avoid "no input files" error if no object
+ // files are specified; thus libraries are duplicated when using "WHOLEARCHIVE"
+ if (useCompilerDriver && allInputs.length === 0)
+ args.push(FileInfo.toWindowsSeparators(lib));
+ linkerArgs.push("/WHOLEARCHIVE:" + FileInfo.toWindowsSeparators(lib));
+ } else {
+ args.push(FileInfo.toWindowsSeparators(lib));
+ }
if (dep.wholeArchive)
wholeArchiveRequested = true;
}
@@ -468,30 +532,36 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
}
if (product.cpp.entryPoint)
- args.push("/ENTRY:" + product.cpp.entryPoint);
+ linkerArgs.push("/ENTRY:" + product.cpp.entryPoint);
- if (outputs.application && product.cpp.generateLinkerMapFile)
- args.push("/MAP:" + outputs.mem_map[0].filePath);
+ if (outputs.application && product.cpp.generateLinkerMapFile) {
+ if (useLldLink)
+ linkerArgs.push("/lldmap:" + outputs.mem_map[0].filePath);
+ else
+ linkerArgs.push("/MAP:" + outputs.mem_map[0].filePath);
+ }
- args.push('/OUT:' + linkerOutputNativeFilePath)
+ if (useCompilerDriver)
+ args.push('/Fe' + linkerOutputNativeFilePath);
+ else
+ linkerArgs.push('/OUT:' + linkerOutputNativeFilePath);
var libraryPaths = product.cpp.libraryPaths;
if (libraryPaths)
libraryPaths = [].uniqueConcat(libraryPaths);
for (i in libraryPaths) {
- args.push('/LIBPATH:' + FileInfo.toWindowsSeparators(libraryPaths[i]))
+ linkerArgs.push('/LIBPATH:' + FileInfo.toWindowsSeparators(libraryPaths[i]))
}
- handleDiscardProperty(product, args);
+ handleDiscardProperty(product, linkerArgs);
var linkerFlags = product.cpp.platformLinkerFlags.concat(product.cpp.linkerFlags);
- args = args.concat(linkerFlags);
+ linkerArgs = linkerArgs.concat(linkerFlags);
if (product.cpp.allowUnresolvedSymbols)
- args.push("/FORCE:UNRESOLVED");
+ linkerArgs.push("/FORCE:UNRESOLVED");
- var linkerPath = product.cpp.linkerPath;
var wrapperArgs = product.cpp.linkerWrapper;
if (wrapperArgs && wrapperArgs.length > 0) {
- args.unshift(linkerPath);
+ linkerArgs.unshift(linkerPath);
linkerPath = wrapperArgs.shift();
- args = wrapperArgs.concat(args);
+ linkerArgs = wrapperArgs.concat(linkerArgs);
}
var commands = [];
var warningCmd = new JavaScriptCommand();
@@ -509,6 +579,10 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
}
};
commands.push(warningCmd);
+
+ if (linkerArgs.length !== 0)
+ args = args.concat(useCompilerDriver ? ['/link'] : []).concat(linkerArgs);
+
var cmd = new Command(linkerPath, args)
cmd.description = 'linking ' + primaryOutput.fileName;
cmd.highlight = 'linker';
@@ -516,9 +590,13 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
cmd.relevantEnvironmentVariables = ["LINK", "_LINK_", "LIB", "TMP"];
cmd.workingDirectory = FileInfo.path(primaryOutput.filePath)
cmd.responseFileUsagePrefix = '@';
+ cmd.responseFileSeparator = useCompilerDriver ? ' ' : '\n';
cmd.stdoutFilterFunction = function(output) {
res = output.replace(/^.*performing full link.*\s*/, "");
- return res.replace(/^ *Creating library.*\r\n$/, "");
+ res = res.replace(/^ *Creating library.*\s*/, "");
+ res = res.replace(/^\s*Generating code\s*/, "");
+ res = res.replace(/^\s*Finished generating code\s*/, "");
+ return res;
};
commands.push(cmd);
diff --git a/share/qbs/modules/cpp/sdcc.js b/share/qbs/modules/cpp/sdcc.js
index 70d0506b9..147fa160f 100644
--- a/share/qbs/modules/cpp/sdcc.js
+++ b/share/qbs/modules/cpp/sdcc.js
@@ -90,10 +90,24 @@ function guessEndianness(macros) {
}
function guessVersion(macros) {
- return { major: parseInt(macros["__SDCC_VERSION_MAJOR"], 10),
- minor: parseInt(macros["__SDCC_VERSION_MINOR"], 10),
- patch: parseInt(macros["__SDCC_VERSION_PATCH"], 10),
- found: macros["SDCC"] }
+ if ("__SDCC_VERSION_MAJOR" in macros
+ && "__SDCC_VERSION_MINOR" in macros
+ && "__SDCC_VERSION_PATCH" in macros) {
+ return { major: parseInt(macros["__SDCC_VERSION_MAJOR"], 10),
+ minor: parseInt(macros["__SDCC_VERSION_MINOR"], 10),
+ patch: parseInt(macros["__SDCC_VERSION_PATCH"], 10),
+ found: macros["SDCC"] }
+ } else if ("__SDCC" in macros) {
+ var versions = macros["__SDCC"].split("_");
+ if (versions.length === 3) {
+ return {
+ major: parseInt(versions[0], 10),
+ minor: parseInt(versions[1], 10),
+ patch: parseInt(versions[2], 10),
+ found: macros["SDCC"] };
+ }
+ }
+ return { found: false };
}
function dumpMacros(compilerFilePath, architecture) {
diff --git a/share/qbs/modules/cpp/sdcc.qbs b/share/qbs/modules/cpp/sdcc.qbs
index ec763ba47..1dec2555d 100644
--- a/share/qbs/modules/cpp/sdcc.qbs
+++ b/share/qbs/modules/cpp/sdcc.qbs
@@ -105,7 +105,7 @@ CppModule {
}
FileTagger {
- condition: qbs.architecture === "arm";
+ condition: qbs.architecture === "stm8";
patterns: "*.s"
fileTags: ["asm"]
}
diff --git a/share/qbs/modules/cpp/windows-clang-cl.qbs b/share/qbs/modules/cpp/windows-clang-cl.qbs
index 1b2833060..a34a67ad2 100644
--- a/share/qbs/modules/cpp/windows-clang-cl.qbs
+++ b/share/qbs/modules/cpp/windows-clang-cl.qbs
@@ -40,7 +40,7 @@ MsvcBaseModule {
qbs.toolchain && qbs.toolchain.contains('clang-cl')
priority: 100
- Probes.BinaryProbe {
+ Probes.ClangClBinaryProbe {
id: clangPathProbe
condition: !toolchainInstallPath && !_skipAllChecks
names: ["clang-cl"]
@@ -52,9 +52,11 @@ MsvcBaseModule {
compilerFilePath: compilerPath
vcvarsallFilePath: vcvarsallPath
enableDefinesByLanguage: enableCompilerDefinesByLanguage
- architecture: qbs.architecture
+ preferredArchitecture: qbs.architecture
}
+ qbs.architecture: clangClProbe.found ? clangClProbe.architecture : original
+
compilerVersionMajor: clangClProbe.versionMajor
compilerVersionMinor: clangClProbe.versionMinor
compilerVersionPatch: clangClProbe.versionPatch
@@ -65,7 +67,18 @@ MsvcBaseModule {
: undefined
buildEnv: clangClProbe.buildEnv
- property string vcvarsallPath
+ property string linkerVariant
+ PropertyOptions {
+ name: "linkerVariant"
+ allowedValues: ["lld", "link"]
+ description: "Allows to specify the linker variant. Maps to clang-cl's -fuse-ld option."
+ }
+ Properties {
+ condition: linkerVariant
+ driverLinkerFlags: "-fuse-ld=" + linkerVariant
+ }
+
+ property string vcvarsallPath : clangPathProbe.found ? clangPathProbe.vcvarsallPath : undefined
compilerName: "clang-cl.exe"
linkerName: "lld-link.exe"
diff --git a/share/qbs/modules/cpp/windows-mingw.qbs b/share/qbs/modules/cpp/windows-mingw.qbs
index fe9fd4bf8..ffed76cdd 100644
--- a/share/qbs/modules/cpp/windows-mingw.qbs
+++ b/share/qbs/modules/cpp/windows-mingw.qbs
@@ -44,7 +44,7 @@ MingwBaseModule {
property string windresName: "windres" + compilerExtension
property path windresPath: {
- var filePath = toolchainPrefix + windresName;
+ var filePath = toolchainPathPrefix + windresName;
if (!File.exists(filePath))
filePath = FileInfo.joinPaths(toolchainInstallPath, windresName);
return filePath;
diff --git a/share/qbs/modules/cpp/windows-msvc.qbs b/share/qbs/modules/cpp/windows-msvc.qbs
index 59032d28a..d5b5baf92 100644
--- a/share/qbs/modules/cpp/windows-msvc.qbs
+++ b/share/qbs/modules/cpp/windows-msvc.qbs
@@ -38,8 +38,9 @@ MsvcBaseModule {
qbs.toolchain && qbs.toolchain.contains('msvc')
priority: 50
- Probes.BinaryProbe {
+ Probes.ClBinaryProbe {
id: compilerPathProbe
+ preferredArchitecture: qbs.architecture
condition: !toolchainInstallPath && !_skipAllChecks
names: ["cl"]
}
diff --git a/share/qbs/modules/freedesktop/FreeDesktop.qbs b/share/qbs/modules/freedesktop/FreeDesktop.qbs
new file mode 100644
index 000000000..bb2ba79f4
--- /dev/null
+++ b/share/qbs/modules/freedesktop/FreeDesktop.qbs
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Alberto Mardegan <mardy@users.sourceforge.net>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** 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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs
+import qbs.ModUtils
+import qbs.TextFile
+import "freedesktop.js" as Fdo
+
+Module {
+ id: fdoModule
+
+ property string name: product.name
+
+ property var desktopKeys
+
+ readonly property var defaultDesktopKeys: {
+ return {
+ 'Type': 'Application',
+ 'Name': product.freedesktop.name,
+ 'Exec': product.targetName,
+ 'Terminal': 'false',
+ 'Version': '1.1',
+ }
+ }
+ property bool _fdoSupported: qbs.targetOS.contains("unix") && !qbs.targetOS.contains("darwin")
+
+ additionalProductTypes: "freedesktop.desktopfile"
+
+ FileTagger {
+ patterns: [ "*.desktop" ]
+ fileTags: [ "freedesktop.desktopfile_source" ]
+ }
+
+ Rule {
+ condition: _fdoSupported
+
+ inputs: [ "freedesktop.desktopfile_source" ]
+ outputFileTags: [ "freedesktop.desktopfile" ]
+
+ Artifact {
+ fileTags: [ "freedesktop.desktopfile" ]
+ filePath: input.fileName
+ }
+
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = input.fileName + "->" + output.fileName;
+ cmd.highlight = "codegen";
+ cmd.sourceCode = function() {
+ var aggregateDesktopKeys = Fdo.parseDesktopFile(input.filePath);
+ var desktopKeys = ModUtils.moduleProperty(product, "desktopKeys") || {}
+ var mainSection = aggregateDesktopKeys['Desktop Entry'];
+ for (key in desktopKeys) {
+ if (desktopKeys.hasOwnProperty(key)) {
+ mainSection[key] = desktopKeys[key];
+ }
+ }
+
+ var defaultValues = product.freedesktop.defaultDesktopKeys
+ for (key in defaultValues) {
+ if (!(key in mainSection)) {
+ mainSection[key] = defaultValues[key];
+ }
+ }
+
+ Fdo.dumpDesktopFile(output.filePath, aggregateDesktopKeys);
+ }
+ return [cmd];
+ }
+ }
+
+ Group {
+ condition: fdoModule._fdoSupported
+ fileTagsFilter: [ "freedesktop.desktopfile" ]
+ qbs.install: true
+ qbs.installDir: "share/applications"
+ }
+
+ Group {
+ condition: fdoModule._fdoSupported
+ fileTagsFilter: [ "freedesktop.appIcon" ]
+ qbs.install: true
+ qbs.installDir: "share/icons/hicolor/scalable/apps"
+ }
+
+ FileTagger {
+ patterns: [ "*.metainfo.xml", "*.appdata.xml" ]
+ fileTags: [ "freedesktop.appstream" ]
+ }
+
+ Group {
+ condition: fdoModule._fdoSupported
+ fileTagsFilter: [ "freedesktop.appstream" ]
+ qbs.install: true
+ qbs.installDir: "share/metainfo"
+ }
+}
diff --git a/share/qbs/modules/freedesktop/freedesktop.js b/share/qbs/modules/freedesktop/freedesktop.js
new file mode 100644
index 000000000..d3c60b191
--- /dev/null
+++ b/share/qbs/modules/freedesktop/freedesktop.js
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Alberto Mardegan <mardy@users.sourceforge.net>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** 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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+var TextFile = require("qbs.TextFile");
+
+function parseDesktopFile(filePath) {
+ var file = new TextFile(filePath);
+ var fileValues = {};
+ var currentSection = {};
+ var sectionRex = /\[(.+)\]/g;
+ while (!file.atEof()) {
+ var line = file.readLine().trim();
+ if (line.length == 0) continue;
+ if (line[0] == '#') continue;
+ var match = sectionRex.exec(line);
+ if (match) {
+ var currentSectionName = match[1];
+ fileValues[currentSectionName] = {};
+ currentSection = fileValues[currentSectionName];
+ continue;
+ }
+ var parts = line.split('=', 2);
+ currentSection[parts[0]] = parts[1]
+ }
+ file.close();
+ return fileValues
+}
+
+function dumpDesktopFile(filePath, keys) {
+ var file = new TextFile(filePath, TextFile.WriteOnly);
+ for (var sectionName in keys) {
+ file.writeLine('[' + sectionName + ']');
+ var section = keys[sectionName];
+ for (var key in section) {
+ var line = key + '=' + section[key];
+ file.writeLine(line);
+ }
+ // Write an empty line between sections (and before EOF)
+ file.writeLine('');
+ }
+ file.close();
+}
diff --git a/share/qbs/modules/java/utils.js b/share/qbs/modules/java/utils.js
index ae0c1356b..0e11b7d3e 100644
--- a/share/qbs/modules/java/utils.js
+++ b/share/qbs/modules/java/utils.js
@@ -136,7 +136,7 @@ function findJdkVersion(compilerFilePath) {
var p = new Process();
try {
p.exec(compilerFilePath, ["-version"]);
- var re = /^javac (([0-9]+(?:\.[0-9]+){0,2})(_([0-9]+))?)$/m;
+ var re = /^javac (([0-9]+(?:\.[0-9]+){0,2})(_([0-9]+))?)(.*)?$/m;
var match = p.readStdErr().trim().match(re);
if (!match)
match = p.readStdOut().trim().match(re);
diff --git a/share/qbs/modules/protobuf/cpp/protobufcpp.qbs b/share/qbs/modules/protobuf/cpp/protobufcpp.qbs
index 0c511f2aa..4d5228813 100644
--- a/share/qbs/modules/protobuf/cpp/protobufcpp.qbs
+++ b/share/qbs/modules/protobuf/cpp/protobufcpp.qbs
@@ -42,7 +42,7 @@ ProtobufBase {
cpp.includePaths: {
var result = [outputDir, includePath];
if (useGrpc)
- result.push("grpcIncludePath");
+ result.push(grpcIncludePath);
return result;
}
diff --git a/share/qbs/modules/qbs/common.qbs b/share/qbs/modules/qbs/common.qbs
index 63bc29f8e..8ddfc582d 100644
--- a/share/qbs/modules/qbs/common.qbs
+++ b/share/qbs/modules/qbs/common.qbs
@@ -48,8 +48,8 @@ Module {
property string buildVariant: defaultBuildVariant
property bool enableDebugCode: buildVariant == "debug"
- property bool debugInformation: (buildVariant == "debug")
- property string optimization: (buildVariant == "debug" ? "none" : "fast")
+ property bool debugInformation: (buildVariant !== "release")
+ property string optimization: (buildVariant === "debug" ? "none" : "fast")
readonly property string hostPlatform: undefined // set internally
readonly property stringList hostOS: Utilities.canonicalPlatform(hostPlatform)
property string hostOSVersion: {
@@ -61,6 +61,7 @@ Module {
return version + "." + hostOSBuildVersion;
}
}
+ readonly property string hostArchitecture: undefined // set internally
property string hostOSBuildVersion: {
if (hostOS.contains("macos")) {
@@ -106,7 +107,7 @@ Module {
PropertyOptions {
name: "buildVariant"
- allowedValues: ['debug', 'release']
+ allowedValues: ['debug', 'release', 'profiling']
description: "name of the build variant"
}
diff --git a/share/qbs/modules/xcode/xcode.js b/share/qbs/modules/xcode/xcode.js
index bda41ade9..d20d9cf0c 100644
--- a/share/qbs/modules/xcode/xcode.js
+++ b/share/qbs/modules/xcode/xcode.js
@@ -114,7 +114,7 @@ function sdkInfoList(sdksPath) {
if (!plist || !plist["CanonicalName"] || !plist["Version"])
return false;
- var re = /^([0-9]+)\.([0-9]+)$/;
+ var re = /^[0-9]+\.[0-9]+(\.[0-9]+)?$/;
return plist["Version"].match(re);
}
@@ -132,19 +132,7 @@ function sdkInfoList(sdksPath) {
}
// Sort by SDK version number
- sdkInfo.sort(function (a, b) {
- var re = /^([0-9]+)\.([0-9]+)$/;
- a = a["Version"].match(re);
- if (a)
- a = {major: a[1], minor: a[2]};
- b = b["Version"].match(re);
- if (b)
- b = {major: b[1], minor: b[2]};
-
- if (a.major === b.major)
- return a.minor - b.minor;
- return a.major - b.major;
- });
+ sdkInfo.sort(function (a, b) { return Utilities.versionCompare(a["Version"], b["Version"]); });
return sdkInfo;
}
diff --git a/share/qbs/modules/xcode/xcode.qbs b/share/qbs/modules/xcode/xcode.qbs
index 922580505..7bbb29c6e 100644
--- a/share/qbs/modules/xcode/xcode.qbs
+++ b/share/qbs/modules/xcode/xcode.qbs
@@ -6,6 +6,7 @@ import qbs.DarwinTools
import qbs.ModUtils
import qbs.Probes
import qbs.PropertyList
+import qbs.Utilities
import 'xcode.js' as Xcode
Module {
@@ -48,6 +49,12 @@ Module {
return _sdkSettings["Version"];
}
}
+ readonly property string shortSdkVersion: {
+ var v = sdkVersion;
+ if (v && v.split('.').length > 2)
+ v = v.slice(0, v.lastIndexOf('.'));
+ return v;
+ }
readonly property string latestSdkName: {
if (_latestSdk) {
@@ -75,13 +82,13 @@ Module {
property string signingIdentity
readonly property string actualSigningIdentity: {
- if (_actualSigningIdentity && _actualSigningIdentity.length === 1)
- return _actualSigningIdentity[0][0];
+ if (_actualSigningIdentity && _actualSigningIdentity.length === 2)
+ return _actualSigningIdentity[0];
}
readonly property string actualSigningIdentityDisplayName: {
- if (_actualSigningIdentity && _actualSigningIdentity.length === 1)
- return _actualSigningIdentity[0][1];
+ if (_actualSigningIdentity && _actualSigningIdentity.length === 2)
+ return _actualSigningIdentity[1];
}
property string signingTimestamp: "none"
@@ -116,8 +123,8 @@ Module {
+ ".platform")
readonly property path sdkPath: FileInfo.joinPaths(sdksPath,
DarwinTools.applePlatformDirectoryName(
- qbs.targetOS, platformType, sdkVersion)
- + ".sdk")
+ qbs.targetOS, platformType,
+ shortSdkVersion) + ".sdk")
// private properties
readonly property path toolchainsPath: FileInfo.joinPaths(developerPath, "Toolchains")
@@ -131,15 +138,29 @@ Module {
readonly property stringList _actualSigningIdentity: {
if (/^[A-Fa-f0-9]{40}$/.test(signingIdentity)) {
- return signingIdentity;
+ return [signingIdentity, signingIdentity];
}
- var identities = Xcode.findSigningIdentities(securityPath, signingIdentity);
- if (identities && identities.length > 1) {
- throw "Signing identity '" + signingIdentity + "' is ambiguous";
+ var result = [];
+
+ if (signingIdentity) {
+ var identities = Utilities.signingIdentities();
+ for (var key in identities) {
+ if (identities[key].subjectInfo.CN === signingIdentity) {
+ result.push([key, signingIdentity]);
+ }
+ }
+
+ if (result.length == 0) {
+ throw "Unable to find signingIdentity '" + signingIdentity + "'";
+ }
+
+ if (result.length > 1) {
+ throw "Signing identity '" + signingIdentity + "' is ambiguous";
+ }
}
- return identities;
+ return result[0];
}
property path provisioningProfilesPath: {
@@ -191,14 +212,14 @@ Module {
validator.setRequiredProperty("platformPath", platformPath);
validator.setRequiredProperty("sdksPath", sdkPath);
validator.setRequiredProperty("sdkPath", sdkPath);
- validator.addVersionValidator("sdkVersion", sdkVersion, 2, 2);
+ validator.addVersionValidator("sdkVersion", sdkVersion, 2, 3);
validator.addCustomValidator("sdkName", sdkName, function (value) {
return value === DarwinTools.applePlatformDirectoryName(
- qbs.targetOS, platformType, sdkVersion, false).toLowerCase();
+ qbs.targetOS, platformType, shortSdkVersion, false).toLowerCase();
}, "is '" + sdkName + "', but target OS is [" + qbs.targetOS.join(",")
+ "] and Xcode SDK version is '" + sdkVersion + "'");
validator.addCustomValidator("sdk", sdk, function (value) {
- return value === sdkName || (value + sdkVersion) === sdkName;
+ return value === sdkName || (value + shortSdkVersion) === sdkName;
}, "is '" + sdk + "', but canonical SDK name is '" + sdkName + "'");
validator.validate();
}
diff --git a/src/app/config-ui/main.cpp b/src/app/config-ui/main.cpp
index a7c2662e6..dcf538989 100644
--- a/src/app/config-ui/main.cpp
+++ b/src/app/config-ui/main.cpp
@@ -47,8 +47,6 @@
#include <cstdlib>
#include <iostream>
-using qbs::Internal::Tr;
-
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
diff --git a/src/app/config-ui/mainwindow.cpp b/src/app/config-ui/mainwindow.cpp
index 2bf7fad5e..febf170a2 100644
--- a/src/app/config-ui/mainwindow.cpp
+++ b/src/app/config-ui/mainwindow.cpp
@@ -119,10 +119,10 @@ MainWindow::MainWindow(const QString &settingsDir, qbs::Settings::Scope scope, Q
saveAction->setShortcut(QKeySequence::Save);
connect(saveAction, &QAction::triggered, this, &MainWindow::saveSettings);
const auto expandAllAction = new QAction(tr("&Expand All"), this);
- expandAllAction->setShortcut(Qt::CTRL | Qt::Key_E);
+ expandAllAction->setShortcut(int(Qt::CTRL) | int(Qt::Key_E));
connect(expandAllAction, &QAction::triggered, this, &MainWindow::expandAll);
const auto collapseAllAction = new QAction(tr("C&ollapse All"), this);
- collapseAllAction->setShortcut(Qt::CTRL | Qt::Key_O);
+ collapseAllAction->setShortcut(int(Qt::CTRL) | int(Qt::Key_O));
connect(collapseAllAction, &QAction::triggered, this, &MainWindow::collapseAll);
const auto exitAction = new QAction(tr("E&xit"), this);
exitAction->setShortcut(QKeySequence::Quit);
diff --git a/src/app/config/configcommandexecutor.cpp b/src/app/config/configcommandexecutor.cpp
index 1290ba2f0..f2d9fc59e 100644
--- a/src/app/config/configcommandexecutor.cpp
+++ b/src/app/config/configcommandexecutor.cpp
@@ -41,8 +41,9 @@
#include "configcommand.h"
#include "../shared/logging/consolelogger.h"
-#include <tools/settingsrepresentation.h>
#include <tools/error.h>
+#include <tools/qttools.h>
+#include <tools/settingsrepresentation.h>
#include <QtCore/qdir.h>
#include <QtCore/qfile.h>
@@ -131,7 +132,7 @@ void ConfigCommandExecutor::exportSettings(const QString &filename)
const auto keys = m_settings->allKeys(m_scope);
for (const QString &key : keys)
stream << key << ": " << qbs::settingsValueToRepresentation(m_settings->value(key, m_scope))
- << endl;
+ << Qt::endl;
}
void ConfigCommandExecutor::importSettings(const QString &filename)
diff --git a/src/app/config/configcommandlineparser.h b/src/app/config/configcommandlineparser.h
index b567134fd..f1f026678 100644
--- a/src/app/config/configcommandlineparser.h
+++ b/src/app/config/configcommandlineparser.h
@@ -60,7 +60,7 @@ public:
class Error
{
public:
- Error(const QString &message) : m_message(message) { }
+ Error(QString message) : m_message(std::move(message)) { }
QString message() const { return m_message; }
private:
QString m_message;
diff --git a/src/app/qbs-setup-android/android-setup.cpp b/src/app/qbs-setup-android/android-setup.cpp
index 029628419..a0a9d2948 100644
--- a/src/app/qbs-setup-android/android-setup.cpp
+++ b/src/app/qbs-setup-android/android-setup.cpp
@@ -45,6 +45,7 @@
#include <tools/profile.h>
#include <tools/settings.h>
#include <tools/version.h>
+#include <tools/qttools.h>
#include <QtCore/qbytearraylist.h>
#include <QtCore/qcoreapplication.h>
@@ -94,10 +95,10 @@ static QString mapArch(const QString &androidName)
}
struct QtAndroidInfo {
- bool isValid() const { return !arch.isEmpty(); }
+ bool isValid() const { return !archs.isEmpty(); }
QString qmakePath;
- QString arch;
+ QStringList archs;
QString platform;
};
@@ -111,19 +112,30 @@ static QtAndroidInfo getInfoForQtDir(const QString &qtDir)
if (!qdevicepri.open(QIODevice::ReadOnly))
return info;
while (!qdevicepri.atEnd()) {
+ // For Qt < 5.14 use DEFAULT_ANDROID_TARGET_ARCH (which is the abi) to compute
+ // the architecture
+ // DEFAULT_ANDROID_ABIS doesn't exit
+ // For Qt >= 5.14:
+ // DEFAULT_ANDROID_TARGET_ARCH doesn't exist, use DEFAULT_ANDROID_ABIS to compute
+ // the architectures
const QByteArray line = qdevicepri.readLine().simplified();
const bool isArchLine = line.startsWith("DEFAULT_ANDROID_TARGET_ARCH");
+ const bool isAbisLine = line.startsWith("DEFAULT_ANDROID_ABIS");
const bool isPlatformLine = line.startsWith("DEFAULT_ANDROID_PLATFORM");
- if (!isArchLine && !isPlatformLine)
+ if (!isArchLine && !isPlatformLine && !isAbisLine)
continue;
const QList<QByteArray> elems = line.split('=');
if (elems.size() != 2)
continue;
const QString rhs = QString::fromLatin1(elems.at(1).trimmed());
- if (isArchLine)
- info.arch = mapArch(rhs);
- else
+ if (isArchLine) {
+ info.archs << mapArch(rhs);
+ } else if (isAbisLine) {
+ for (const QString &abi: rhs.split(QLatin1Char(' ')))
+ info.archs << mapArch(abi);
+ } else {
info.platform = rhs;
+ }
}
return info;
}
@@ -136,13 +148,16 @@ static QtInfoPerArch getQtAndroidInfo(const QString &qtSdkDir)
return archs;
QStringList qtDirs(qtSdkDir);
- QDirIterator dit(qtSdkDir, QStringList() << QStringLiteral("android_*"), QDir::Dirs);
+ const QStringList nameFilters{QStringLiteral("android_*"), QStringLiteral("android")};
+ QDirIterator dit(qtSdkDir, nameFilters, QDir::Dirs);
while (dit.hasNext())
qtDirs << dit.next();
for (const auto &qtDir : qtDirs) {
const QtAndroidInfo info = getInfoForQtDir(qtDir);
- if (info.isValid())
- archs.insert(info.arch, info);
+ if (info.isValid()) {
+ for (const QString &arch: info.archs)
+ archs.insert(arch, info);
+ }
}
return archs;
}
@@ -224,8 +239,10 @@ static void setupNdk(qbs::Settings *settings, const QString &profileName, const
qmakeFilePaths << qtAndroidInfo.qmakePath;
platform = maximumPlatform(platform, qtAndroidInfo.platform);
}
- if (!qmakeFilePaths.empty())
+ if (!qmakeFilePaths.empty()) {
+ qmakeFilePaths.removeDuplicates();
mainProfile.setValue(qls("moduleProviders.Qt.qmakeFilePaths"), qmakeFilePaths);
+ }
if (!platform.isEmpty())
mainProfile.setValue(qls("Android.ndk.platform"), platform);
}
diff --git a/src/app/qbs-setup-android/commandlineparser.cpp b/src/app/qbs-setup-android/commandlineparser.cpp
index 0aecc8773..8beeeb601 100644
--- a/src/app/qbs-setup-android/commandlineparser.cpp
+++ b/src/app/qbs-setup-android/commandlineparser.cpp
@@ -43,10 +43,7 @@
#include <QtCore/qfileinfo.h>
-CommandLineParser::CommandLineParser()
-{
-
-}
+CommandLineParser::CommandLineParser() = default;
using qbs::Internal::Tr;
diff --git a/src/app/qbs-setup-qt/setupqt.cpp b/src/app/qbs-setup-qt/setupqt.cpp
index 947cbc5fc..07e1a81b5 100644
--- a/src/app/qbs-setup-qt/setupqt.cpp
+++ b/src/app/qbs-setup-qt/setupqt.cpp
@@ -47,6 +47,7 @@
#include <tools/set.h>
#include <tools/settings.h>
#include <tools/stlutils.h>
+#include <tools/toolchains.h>
#include <tools/version.h>
#include <QtCore/qbytearraymatcher.h>
@@ -196,7 +197,7 @@ static bool isToolchainProfile(const Profile &profile)
{
const auto actual = Internal::Set<QString>::fromList(
profile.allKeys(Profile::KeySelectionRecursive));
- Internal::Set<QString> expected = Internal::Set<QString> { QStringLiteral("qbs.toolchain") };
+ Internal::Set<QString> expected{ QStringLiteral("qbs.toolchainType") };
if (HostOsInfo::isMacosHost())
expected.insert(QStringLiteral("qbs.targetPlatform")); // match only Xcode profiles
return Internal::Set<QString>(actual).unite(expected) == actual;
@@ -230,8 +231,13 @@ static Match compatibility(const QtEnvironment &env, const Profile &toolchainPro
{
Match match = MatchFull;
- const auto toolchainNames = Internal::Set<QString>::fromList(
- toolchainProfile.value(QStringLiteral("qbs.toolchain")).toStringList());
+ const auto toolchainType =
+ toolchainProfile.value(QStringLiteral("qbs.toolchainType")).toString();
+ const auto toolchain = !toolchainType.isEmpty()
+ ? canonicalToolchain(toolchainType)
+ : toolchainProfile.value(QStringLiteral("qbs.toolchain")).toStringList();
+
+ const auto toolchainNames = Internal::Set<QString>::fromList(toolchain);
const auto qtToolchainNames = Internal::Set<QString>::fromList(env.qbsToolchain);
if (areProfilePropertiesIncompatible(toolchainNames, qtToolchainNames)) {
auto intersection = toolchainNames;
diff --git a/src/app/qbs-setup-toolchains/clangclprobe.cpp b/src/app/qbs-setup-toolchains/clangclprobe.cpp
index 816d28546..d1a3a9ac5 100644
--- a/src/app/qbs-setup-toolchains/clangclprobe.cpp
+++ b/src/app/qbs-setup-toolchains/clangclprobe.cpp
@@ -44,7 +44,9 @@
#include "../shared/logging/consolelogger.h"
#include <logging/translator.h>
+#include <tools/clangclinfo.h>
#include <tools/hostosinfo.h>
+#include <tools/msvcinfo.h>
#include <tools/profile.h>
#include <tools/qttools.h>
#include <tools/settings.h>
@@ -54,17 +56,13 @@
using qbs::Settings;
using qbs::Profile;
+using qbs::Internal::ClangClInfo;
using qbs::Internal::HostOsInfo;
using qbs::Internal::Tr;
namespace {
-QString getToolchainInstallPath(const QFileInfo &compiler)
-{
- return compiler.path(); // 1 level up
-}
-
Profile createProfileHelper(
Settings *settings,
const QString &profileName,
@@ -75,9 +73,7 @@ Profile createProfileHelper(
Profile profile(profileName, settings);
profile.removeProfile();
profile.setValue(QStringLiteral("qbs.architecture"), architecture);
- profile.setValue(
- QStringLiteral("qbs.toolchain"),
- QStringList{QStringLiteral("clang-cl"), QStringLiteral("msvc")});
+ profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("clang-cl"));
profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), toolchainInstallPath);
profile.setValue(QStringLiteral("cpp.vcvarsallPath"), vcvarsallPath);
qbsInfo() << Tr::tr("Profile '%1' created for '%2'.")
@@ -85,47 +81,6 @@ Profile createProfileHelper(
return profile;
}
-std::vector<MSVCInstallInfo> compatibleMsvcs()
-{
- auto msvcs = installedMSVCs();
- auto filter = [](const MSVCInstallInfo &info)
- {
- const auto versions = info.version.split(QLatin1Char('.'));
- if (versions.empty())
- return true;
- bool ok = false;
- const int major = versions.at(0).toInt(&ok);
- return !(ok && major >= 15); // support MSVC2017 and above
- };
- const auto it = std::remove_if(msvcs.begin(), msvcs.end(), filter);
- msvcs.erase(it, msvcs.end());
- for (const auto &msvc: msvcs) {
- auto vcvarsallPath = msvc.findVcvarsallBat();
- if (vcvarsallPath.isEmpty())
- continue;
- }
- return msvcs;
-}
-
-QString findCompatibleVcsarsallBat()
-{
- for (const auto &msvc: compatibleMsvcs()) {
- const auto vcvarsallPath = msvc.findVcvarsallBat();
- if (!vcvarsallPath.isEmpty())
- return vcvarsallPath;
- }
- return {};
-}
-
-QString wow6432Key()
-{
-#ifdef Q_OS_WIN64
- return QStringLiteral("\\Wow6432Node");
-#else
- return {};
-#endif
-}
-
QString findClangCl()
{
const auto compilerName = HostOsInfo::appendExecutableSuffix(QStringLiteral("clang-cl"));
@@ -133,27 +88,6 @@ QString findClangCl()
if (!compilerFromPath.isEmpty())
return compilerFromPath;
- const QSettings registry(
- QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\LLVM\\LLVM").arg(wow6432Key()),
- QSettings::NativeFormat);
- const auto key = QStringLiteral(".");
- if (registry.contains(key)) {
- const auto compilerPath = QDir::fromNativeSeparators(registry.value(key).toString())
- + QStringLiteral("/bin/") + compilerName;
- if (QFileInfo(compilerPath).exists())
- return compilerPath;
- }
-
- // this branch can be useful in case user had two LLVM installations (e.g. 32bit & 64bit)
- // but uninstalled one - in that case, registry will be empty
- static const char * const envVarCandidates[] = {"ProgramFiles", "ProgramFiles(x86)"};
- for (const auto &envVar : envVarCandidates) {
- const auto value
- = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv(envVar)));
- const auto compilerPath = value + QStringLiteral("/LLVM/bin/") + compilerName;
- if (QFileInfo(compilerPath).exists())
- return compilerPath;
- }
return {};
}
@@ -162,51 +96,39 @@ QString findClangCl()
void createClangClProfile(const QFileInfo &compiler, Settings *settings,
const QString &profileName)
{
- const auto compilerName = QStringLiteral("clang-cl");
- const auto vcvarsallPath = findCompatibleVcsarsallBat();
- if (vcvarsallPath.isEmpty()) {
- qbsWarning()
- << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.")
- .arg(compilerName);
+ const auto clangCl = ClangClInfo::fromCompilerFilePath(
+ compiler.filePath(), ConsoleLogger::instance());
+ if (clangCl.isEmpty())
return;
- }
-
- const auto toolchainInstallPath = getToolchainInstallPath(compiler);
const auto hostArch = QString::fromStdString(HostOsInfo::hostOSArchitecture());
- createProfileHelper(settings, profileName, toolchainInstallPath, vcvarsallPath, hostArch);
+ createProfileHelper(
+ settings, profileName, clangCl.toolchainInstallPath, clangCl.vcvarsallPath, hostArch);
}
/*!
\brief Creates a clang-cl profile based on auto-detected vsversion.
\internal
*/
-void clangClProbe(Settings *settings, QList<Profile> &profiles)
+void clangClProbe(Settings *settings, std::vector<Profile> &profiles)
{
const auto compilerName = QStringLiteral("clang-cl");
qbsInfo() << Tr::tr("Trying to detect %1...").arg(compilerName);
- const QString compilerFilePath = findClangCl();
- if (compilerFilePath.isEmpty()) {
+ const auto clangCls = ClangClInfo::installedCompilers(
+ {findClangCl()}, ConsoleLogger::instance());
+ if (clangCls.empty()) {
qbsInfo() << Tr::tr("%1 was not found.").arg(compilerName);
return;
}
- const QFileInfo compiler(compilerFilePath);
- const auto vcvarsallPath = findCompatibleVcsarsallBat();
- if (vcvarsallPath.isEmpty()) {
- qbsWarning()
- << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.")
- .arg(compilerName);
- return;
- }
+ const auto clangCl = clangCls.front();
const QString architectures[] = {
QStringLiteral("x86_64"),
QStringLiteral("x86")
};
- const auto toolchainInstallPath = getToolchainInstallPath(compiler);
for (const auto &arch: architectures) {
const auto profileName = QStringLiteral("clang-cl-%1").arg(arch);
auto profile = createProfileHelper(
- settings, profileName, toolchainInstallPath, vcvarsallPath, arch);
+ settings, profileName, clangCl.toolchainInstallPath, clangCl.vcvarsallPath, arch);
profiles.push_back(std::move(profile));
}
}
diff --git a/src/app/qbs-setup-toolchains/clangclprobe.h b/src/app/qbs-setup-toolchains/clangclprobe.h
index 1afbbb1b8..2de1c0a64 100644
--- a/src/app/qbs-setup-toolchains/clangclprobe.h
+++ b/src/app/qbs-setup-toolchains/clangclprobe.h
@@ -40,7 +40,9 @@
#ifndef QBS_SETUPTOOLCHAINS_CLANGCLPROBE_H
#define QBS_SETUPTOOLCHAINS_CLANGCLPROBE_H
-#include <QtCore/qlist.h>
+#include <QString>
+
+#include <vector>
QT_BEGIN_NAMESPACE
class QFileInfo;
@@ -54,6 +56,6 @@ class Settings;
void createClangClProfile(const QFileInfo &compiler, qbs::Settings *settings,
const QString &profileName);
-void clangClProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles);
+void clangClProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles);
#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/gccprobe.cpp b/src/app/qbs-setup-toolchains/gccprobe.cpp
index 78439cbcb..6cbe246a5 100644
--- a/src/app/qbs-setup-toolchains/gccprobe.cpp
+++ b/src/app/qbs-setup-toolchains/gccprobe.cpp
@@ -111,7 +111,7 @@ class ToolchainDetails
public:
explicit ToolchainDetails(const QFileInfo &compiler)
{
- auto baseName = compiler.completeBaseName();
+ auto baseName = HostOsInfo::stripExecutableSuffix(compiler.fileName());
// Extract the version sub-string if it exists. We assume that a version
// sub-string located after the compiler prefix && suffix. E.g. this code
// parses a version from the compiler names, like this:
@@ -138,9 +138,9 @@ public:
};
static void setCommonProperties(Profile &profile, const QFileInfo &compiler,
- const QStringList &toolchainTypes, const ToolchainDetails &details)
+ const QString &toolchainType, const ToolchainDetails &details)
{
- if (toolchainTypes.contains(QStringLiteral("mingw")))
+ if (toolchainType == QStringLiteral("mingw"))
profile.setValue(QStringLiteral("qbs.targetPlatform"),
QStringLiteral("windows"));
@@ -149,7 +149,7 @@ static void setCommonProperties(Profile &profile, const QFileInfo &compiler,
profile.setValue(QStringLiteral("cpp.toolchainInstallPath"),
compiler.absolutePath());
- profile.setValue(QStringLiteral("qbs.toolchain"), toolchainTypes);
+ profile.setValue(QStringLiteral("qbs.toolchainType"), toolchainType);
if (!standardCompilerFileNames().contains(
HostOsInfo::appendExecutableSuffix(details.suffix))) {
@@ -453,12 +453,12 @@ static QStringList mplabX32RegistrySearchPaths()
}
Profile createGccProfile(const QFileInfo &compiler, Settings *settings,
- const QStringList &toolchainTypes,
+ const QString &toolchainType,
const QString &profileName)
{
const QString machineName = gccMachineName(compiler);
- if (toolchainTypes.contains(QLatin1String("mingw"))) {
+ if (toolchainType == QLatin1String("mingw")) {
if (!validMinGWMachines().contains(machineName)) {
throw ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.")
.arg(machineName));
@@ -470,9 +470,9 @@ Profile createGccProfile(const QFileInfo &compiler, Settings *settings,
const ToolchainDetails details(compiler);
- setCommonProperties(profile, compiler, toolchainTypes, details);
+ setCommonProperties(profile, compiler, toolchainType, details);
- if (HostOsInfo::isWindowsHost() && toolchainTypes.contains(QLatin1String("clang"))) {
+ if (HostOsInfo::isWindowsHost() && toolchainType == QLatin1String("clang")) {
const QStringList profileNames = settings->profiles();
bool foundMingw = false;
for (const QString &profileName : profileNames) {
@@ -497,7 +497,7 @@ Profile createGccProfile(const QFileInfo &compiler, Settings *settings,
}
}
- if (!toolchainTypes.contains(QLatin1String("clang"))) {
+ if (toolchainType != QLatin1String("clang")) {
// Check whether auxiliary tools reside within the toolchain's install path.
// This might not be the case when using icecc or another compiler wrapper.
const QString compilerDirPath = compiler.absolutePath();
@@ -520,7 +520,7 @@ Profile createGccProfile(const QFileInfo &compiler, Settings *settings,
return profile;
}
-void gccProbe(Settings *settings, QList<Profile> &profiles, const QString &compilerName)
+void gccProbe(Settings *settings, std::vector<Profile> &profiles, const QString &compilerName)
{
qbsInfo() << Tr::tr("Trying to detect %1...").arg(compilerName);
@@ -582,11 +582,15 @@ void gccProbe(Settings *settings, QList<Profile> &profiles, const QString &compi
}
for (const auto &candidate : qAsConst(candidates)) {
- const QStringList toolchainTypes = toolchainTypeFromCompilerName(
+ const QString toolchainType = toolchainTypeFromCompilerName(
candidate.baseName());
const QString profileName = buildProfileName(candidate);
- auto profile = createGccProfile(candidate, settings,
- toolchainTypes, profileName);
- profiles.push_back(std::move(profile));
+ try {
+ auto profile = createGccProfile(candidate, settings,
+ toolchainType, profileName);
+ profiles.push_back(std::move(profile));
+ } catch (const qbs::ErrorInfo &info) {
+ qbsWarning() << Tr::tr("Skipping %1: %2").arg(profileName, info.toString());
+ }
}
}
diff --git a/src/app/qbs-setup-toolchains/gccprobe.h b/src/app/qbs-setup-toolchains/gccprobe.h
index 4344c5836..98e7eaa1f 100644
--- a/src/app/qbs-setup-toolchains/gccprobe.h
+++ b/src/app/qbs-setup-toolchains/gccprobe.h
@@ -53,10 +53,10 @@ class Settings;
qbs::Profile createGccProfile(const QFileInfo &compiler,
qbs::Settings *settings,
- const QStringList &toolchainTypes,
+ const QString &toolchainType,
const QString &profileName = QString());
-void gccProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles,
+void gccProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles,
const QString &compilerName);
#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/iarewprobe.cpp b/src/app/qbs-setup-toolchains/iarewprobe.cpp
index 26ee57da9..de7b62574 100644
--- a/src/app/qbs-setup-toolchains/iarewprobe.cpp
+++ b/src/app/qbs-setup-toolchains/iarewprobe.cpp
@@ -59,7 +59,9 @@ static QStringList knownIarCompilerNames()
{
return {QStringLiteral("icc8051"), QStringLiteral("iccarm"),
QStringLiteral("iccavr"), QStringLiteral("iccstm8"),
- QStringLiteral("icc430"), QStringLiteral("iccrl78")};
+ QStringLiteral("icc430"), QStringLiteral("iccrl78"),
+ QStringLiteral("iccrx"), QStringLiteral("iccrh850"),
+ QStringLiteral("iccv850"), QStringLiteral("icc78k")};
}
static QString guessIarArchitecture(const QFileInfo &compiler)
@@ -77,6 +79,14 @@ static QString guessIarArchitecture(const QFileInfo &compiler)
return QStringLiteral("msp430");
if (baseName == QLatin1String("iccrl78"))
return QStringLiteral("rl78");
+ if (baseName == QLatin1String("iccrx"))
+ return QStringLiteral("rx");
+ if (baseName == QLatin1String("iccrh850"))
+ return QStringLiteral("rh850");
+ if (baseName == QLatin1String("iccv850"))
+ return QStringLiteral("v850");
+ if (baseName == QLatin1String("icc78k"))
+ return QStringLiteral("78k");
return {};
}
@@ -148,7 +158,11 @@ static Version dumpIarCompilerVersion(const QFileInfo &compiler)
|| arch == QLatin1String("mcs51")
|| arch == QLatin1String("stm8")
|| arch == QLatin1String("msp430")
- || arch == QLatin1String("rl78")) {
+ || arch == QLatin1String("rl78")
+ || arch == QLatin1String("rx")
+ || arch == QLatin1String("rh850")
+ || arch == QLatin1String("v850")
+ || arch == QLatin1String("78k")) {
return Version{verCode / 100, verCode % 100};
}
@@ -195,6 +209,10 @@ static std::vector<ToolchainInstallInfo> installedIarsFromRegistry()
{QStringLiteral("EWSTM8"), QStringLiteral("\\stm8\\bin\\iccstm8.exe")},
{QStringLiteral("EW430"), QStringLiteral("\\430\\bin\\icc430.exe")},
{QStringLiteral("EWRL78"), QStringLiteral("\\rl78\\bin\\iccrl78.exe")},
+ {QStringLiteral("EWRX"), QStringLiteral("\\rx\\bin\\iccrx.exe")},
+ {QStringLiteral("EWRH850"), QStringLiteral("\\rh850\\bin\\iccrh850.exe")},
+ {QStringLiteral("EWV850"), QStringLiteral("\\v850\\bin\\iccv850.exe")},
+ {QStringLiteral("EW78K"), QStringLiteral("\\78k\\bin\\icc78k.exe")},
};
QSettings registry(QLatin1String(kRegistryNode), QSettings::NativeFormat);
@@ -215,8 +233,7 @@ static std::vector<ToolchainInstallInfo> installedIarsFromRegistry()
const QFileInfo iarPath(rootPath + entry.subExePath);
if (iarPath.exists()) {
// Note: threeLevelKey is a guessed toolchain version.
- const QString version = threeLevelKey;
- infos.push_back({iarPath, Version::fromString(version)});
+ infos.push_back({iarPath, Version::fromString(threeLevelKey)});
}
}
registry.endGroup();
@@ -245,10 +262,10 @@ void createIarProfile(const QFileInfo &compiler, Settings *settings,
QString profileName)
{
const ToolchainInstallInfo info = {compiler, Version{}};
- createIarProfileHelper(info, settings, profileName);
+ createIarProfileHelper(info, settings, std::move(profileName));
}
-void iarProbe(Settings *settings, QList<Profile> &profiles)
+void iarProbe(Settings *settings, std::vector<Profile> &profiles)
{
qbsInfo() << Tr::tr("Trying to detect IAR toolchains...");
diff --git a/src/app/qbs-setup-toolchains/iarewprobe.h b/src/app/qbs-setup-toolchains/iarewprobe.h
index b604d6c6b..a1a51daa4 100644
--- a/src/app/qbs-setup-toolchains/iarewprobe.h
+++ b/src/app/qbs-setup-toolchains/iarewprobe.h
@@ -56,6 +56,6 @@ bool isIarCompiler(const QString &compilerName);
void createIarProfile(const QFileInfo &compiler, qbs::Settings *settings,
QString profileName);
-void iarProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles);
+void iarProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles);
#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/keilprobe.cpp b/src/app/qbs-setup-toolchains/keilprobe.cpp
index 08f0f2167..67b14a802 100644
--- a/src/app/qbs-setup-toolchains/keilprobe.cpp
+++ b/src/app/qbs-setup-toolchains/keilprobe.cpp
@@ -47,6 +47,7 @@
#include <tools/hostosinfo.h>
#include <tools/profile.h>
+#include <QtCore/qdir.h>
#include <QtCore/qprocess.h>
#include <QtCore/qsettings.h>
#include <QtCore/qtemporaryfile.h>
@@ -57,7 +58,8 @@ using Internal::HostOsInfo;
static QStringList knownKeilCompilerNames()
{
- return {QStringLiteral("c51"), QStringLiteral("armcc")};
+ return {QStringLiteral("c51"), QStringLiteral("c251"),
+ QStringLiteral("c166"), QStringLiteral("armcc")};
}
static QString guessKeilArchitecture(const QFileInfo &compiler)
@@ -65,6 +67,10 @@ static QString guessKeilArchitecture(const QFileInfo &compiler)
const auto baseName = compiler.baseName();
if (baseName == QLatin1String("c51"))
return QStringLiteral("mcs51");
+ if (baseName == QLatin1String("c251"))
+ return QStringLiteral("mcs251");
+ if (baseName == QLatin1String("c166"))
+ return QStringLiteral("c166");
if (baseName == QLatin1String("armcc"))
return QStringLiteral("arm");
return {};
@@ -100,74 +106,173 @@ static Profile createKeilProfileHelper(const ToolchainInstallInfo &info,
return profile;
}
-static Version dumpKeilCompilerVersion(const QFileInfo &compiler)
+static Version dumpMcsCompilerVersion(const QFileInfo &compiler)
{
- const QString arch = guessKeilArchitecture(compiler);
- if (arch == QLatin1String("mcs51")) {
- QTemporaryFile fakeIn;
- if (!fakeIn.open()) {
- qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2")
- .arg(fakeIn.fileName(), fakeIn.errorString());
- return Version{};
- }
- fakeIn.write("#define VALUE_TO_STRING(x) #x\n");
- fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n");
- fakeIn.write("#define VAR_NAME_VALUE(var) \"\"\"|\"#var\"|\"VALUE(var)\n");
- fakeIn.write("#ifdef __C51__\n");
- fakeIn.write("#pragma message(VAR_NAME_VALUE(__C51__))\n");
- fakeIn.write("#endif\n");
- fakeIn.write("#ifdef __CX51__\n");
- fakeIn.write("#pragma message(VAR_NAME_VALUE(__CX51__))\n");
- fakeIn.write("#endif\n");
- fakeIn.close();
-
- const QStringList args = {fakeIn.fileName()};
- QProcess p;
- p.start(compiler.absoluteFilePath(), args);
- p.waitForFinished(3000);
- const auto es = p.exitStatus();
- if (es != QProcess::NormalExit) {
- const QByteArray out = p.readAll();
- qbsWarning() << Tr::tr("Compiler dumping failed:\n%1")
- .arg(QString::fromUtf8(out));
- return Version{};
- }
+ QTemporaryFile fakeIn;
+ if (!fakeIn.open()) {
+ qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2")
+ .arg(fakeIn.fileName(), fakeIn.errorString());
+ return Version{};
+ }
- const QByteArray dump = p.readAllStandardOutput();
- const int verCode = extractVersion(dump, "\"__C51__\"|\"");
- if (verCode < 0) {
- qbsWarning() << Tr::tr("No '__C51__' token was found"
- " in the compiler dump:\n%1")
- .arg(QString::fromUtf8(dump));
- return Version{};
- }
- return Version{verCode / 100, verCode % 100};
- } else if (arch == QLatin1String("arm")) {
- const QStringList args = {QStringLiteral("-E"),
- QStringLiteral("--list-macros"),
- QStringLiteral("nul")};
- QProcess p;
- p.start(compiler.absoluteFilePath(), args);
- p.waitForFinished(3000);
- const auto es = p.exitStatus();
- if (es != QProcess::NormalExit) {
- const QByteArray out = p.readAll();
- qbsWarning() << Tr::tr("Compiler dumping failed:\n%1")
- .arg(QString::fromUtf8(out));
- return Version{};
+ fakeIn.write("#define VALUE_TO_STRING(x) #x\n");
+ fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n");
+
+ // Prepare for C51 compiler.
+ fakeIn.write("#if defined(__C51__) || defined(__CX51__)\n");
+ fakeIn.write("# define VAR_NAME_VALUE(var) \"(\"\"\"\"|\"#var\"|\"VALUE(var)\"|\"\"\"\")\"\n");
+ fakeIn.write("# if defined (__C51__)\n");
+ fakeIn.write("# pragma message (VAR_NAME_VALUE(__C51__))\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("# if defined(__CX51__)\n");
+ fakeIn.write("# pragma message (VAR_NAME_VALUE(__CX51__))\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("#endif\n");
+
+ // Prepare for C251 compiler.
+ fakeIn.write("#if defined(__C251__)\n");
+ fakeIn.write("# define VAR_NAME_VALUE(var) \"\"|#var|VALUE(var)|\"\"\n");
+ fakeIn.write("# if defined(__C251__)\n");
+ fakeIn.write("# warning (VAR_NAME_VALUE(__C251__))\n");
+ fakeIn.write("# endif\n");
+ fakeIn.write("#endif\n");
+
+ fakeIn.close();
+
+ const QStringList args = {fakeIn.fileName()};
+ QProcess p;
+ p.start(compiler.absoluteFilePath(), args);
+ p.waitForFinished(3000);
+
+ const QStringList knownKeys = {QStringLiteral("__C51__"),
+ QStringLiteral("__CX51__"),
+ QStringLiteral("__C251__")};
+
+ auto extractVersion = [&knownKeys](const QByteArray &output) {
+ QTextStream stream(output);
+ QString line;
+ while (stream.readLineInto(&line)) {
+ if (!line.startsWith(QLatin1String("***")))
+ continue;
+ enum { KEY_INDEX = 1, VALUE_INDEX = 2, ALL_PARTS = 4 };
+ const QStringList parts = line.split(QLatin1String("\"|\""));
+ if (parts.count() != ALL_PARTS)
+ continue;
+ if (!knownKeys.contains(parts.at(KEY_INDEX)))
+ continue;
+ return parts.at(VALUE_INDEX).toInt();
}
+ return -1;
+ };
+
+ const QByteArray dump = p.readAllStandardOutput();
+ const int verCode = extractVersion(dump);
+ if (verCode < 0) {
+ qbsWarning() << Tr::tr("No %1 tokens was found"
+ " in the compiler dump:\n%2")
+ .arg(knownKeys.join(QLatin1Char(',')))
+ .arg(QString::fromUtf8(dump));
+ return Version{};
+ }
+ return Version{verCode / 100, verCode % 100};
+}
- const QByteArray dump = p.readAll();
- const int verCode = extractVersion(dump, "__ARMCC_VERSION ");
- if (verCode < 0) {
- qbsWarning() << Tr::tr("No '__ARMCC_VERSION' token was found "
- "in the compiler dump:\n%1")
- .arg(QString::fromUtf8(dump));
- return Version{};
+static Version dumpC166CompilerVersion(const QFileInfo &compiler)
+{
+ QTemporaryFile fakeIn;
+ if (!fakeIn.open()) {
+ qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2")
+ .arg(fakeIn.fileName(), fakeIn.errorString());
+ return Version{};
+ }
+
+ fakeIn.write("#if defined(__C166__)\n");
+ fakeIn.write("# warning __C166__\n");
+ fakeIn.write("# pragma __C166__\n");
+ fakeIn.write("#endif\n");
+
+ fakeIn.close();
+
+ const QStringList args = {fakeIn.fileName()};
+ QProcess p;
+ p.start(compiler.absoluteFilePath(), args);
+ p.waitForFinished(3000);
+
+ // Extract the compiler version pattern in the form, like:
+ //
+ // *** WARNING C320 IN LINE 41 OF c51.c: __C166__
+ // *** WARNING C2 IN LINE 42 OF c51.c: '757': unknown #pragma/control, line ignored
+ //
+ // where the '__C166__' is a key, and the '757' is a value (aka version).
+ auto extractVersion = [](const QString &output) {
+ const QStringList lines = output.split(QStringLiteral("\r\n"));
+ for (auto it = lines.cbegin(); it != lines.cend();) {
+ if (it->startsWith(QLatin1String("***")) && it->endsWith(QLatin1String("__C166__"))) {
+ ++it;
+ if (it == lines.cend() || !it->startsWith(QLatin1String("***")))
+ break;
+ const int startIndex = it->indexOf(QLatin1Char('\''));
+ if (startIndex == -1)
+ break;
+ const int stopIndex = it->indexOf(QLatin1Char('\''), startIndex + 1);
+ if (stopIndex == -1)
+ break;
+ const QString v = it->mid(startIndex + 1, stopIndex - startIndex - 1);
+ return v.toInt();
+ }
+ ++it;
}
- return Version{verCode / 1000000, (verCode / 10000) % 100, verCode % 10000};
+ return -1;
+ };
+
+ const QByteArray dump = p.readAllStandardOutput();
+ const int verCode = extractVersion(QString::fromUtf8(dump));
+ if (verCode < 0) {
+ qbsWarning() << Tr::tr("No __C166__ token was found"
+ " in the compiler dump:\n%1")
+ .arg(QString::fromUtf8(dump));
+ return Version{};
}
+ return Version{verCode / 100, verCode % 100};
+}
+static Version dumpArmCompilerVersion(const QFileInfo &compiler)
+{
+ const QStringList args = {QStringLiteral("-E"),
+ QStringLiteral("--list-macros"),
+ QStringLiteral("nul")};
+ QProcess p;
+ p.start(compiler.absoluteFilePath(), args);
+ p.waitForFinished(3000);
+ const auto es = p.exitStatus();
+ if (es != QProcess::NormalExit) {
+ const QByteArray out = p.readAll();
+ qbsWarning() << Tr::tr("Compiler dumping failed:\n%1")
+ .arg(QString::fromUtf8(out));
+ return Version{};
+ }
+
+ const QByteArray dump = p.readAll();
+ const int verCode = extractVersion(dump, "__ARMCC_VERSION ");
+ if (verCode < 0) {
+ qbsWarning() << Tr::tr("No '__ARMCC_VERSION' token was found "
+ "in the compiler dump:\n%1")
+ .arg(QString::fromUtf8(dump));
+ return Version{};
+ }
+ return Version{verCode / 1000000, (verCode / 10000) % 100, verCode % 10000};
+}
+
+static Version dumpKeilCompilerVersion(const QFileInfo &compiler)
+{
+ const QString arch = guessKeilArchitecture(compiler);
+ if (arch == QLatin1String("mcs51") || arch == QLatin1String("mcs251")) {
+ return dumpMcsCompilerVersion(compiler);
+ } else if (arch == QLatin1String("c166")) {
+ return dumpC166CompilerVersion(compiler);
+ } else if (arch == QLatin1String("arm")) {
+ return dumpArmCompilerVersion(compiler);
+ }
return Version{};
}
@@ -188,6 +293,51 @@ static std::vector<ToolchainInstallInfo> installedKeilsFromPath()
return infos;
}
+// Parse the 'tools.ini' file to fetch a toolchain version.
+// Note: We can't use QSettings here!
+static QString extractVersion(const QString &toolsIniFile, const QString &section)
+{
+ QFile f(toolsIniFile);
+ if (!f.open(QIODevice::ReadOnly))
+ return {};
+ QTextStream in(&f);
+ enum State { Enter, Lookup, Exit } state = Enter;
+ while (!in.atEnd()) {
+ const QString line = in.readLine().trimmed();
+ // Search for section.
+ const int firstBracket = line.indexOf(QLatin1Char('['));
+ const int lastBracket = line.lastIndexOf(QLatin1Char(']'));
+ const bool hasSection = (firstBracket == 0 && lastBracket != -1
+ && (lastBracket + 1) == line.size());
+ switch (state) {
+ case Enter: {
+ if (hasSection) {
+ const auto content = line.midRef(firstBracket + 1,
+ lastBracket - firstBracket - 1);
+ if (content == section)
+ state = Lookup;
+ }
+ }
+ break;
+ case Lookup: {
+ if (hasSection)
+ return {}; // Next section found.
+ const int versionIndex = line.indexOf(QLatin1String("VERSION="));
+ if (versionIndex < 0)
+ continue;
+ QString version = line.mid(8);
+ if (version.startsWith(QLatin1Char('V')))
+ version.remove(0, 1);
+ return version;
+ }
+ break;
+ default:
+ return {};
+ }
+ }
+ return {};
+}
+
static std::vector<ToolchainInstallInfo> installedKeilsFromRegistry()
{
std::vector<ToolchainInstallInfo> infos;
@@ -195,48 +345,49 @@ static std::vector<ToolchainInstallInfo> installedKeilsFromRegistry()
if (HostOsInfo::isWindowsHost()) {
#ifdef Q_OS_WIN64
- static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Keil\\Products";
+ static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\" \
+ "Windows\\CurrentVersion\\Uninstall\\Keil \u00B5Vision4";
#else
- static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Keil\\Products";
+ static const char kRegistryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" \
+ "Windows\\CurrentVersion\\Uninstall\\Keil \u00B5Vision4";
#endif
- // Dictionary for know toolchains.
- static const struct Entry {
- QString productKey;
- QString subExePath;
- } knowToolchains[] = {
- {QStringLiteral("MDK"), QStringLiteral("\\ARMCC\\bin\\armcc.exe")},
- {QStringLiteral("C51"), QStringLiteral("\\BIN\\c51.exe")},
- };
-
QSettings registry(QLatin1String(kRegistryNode), QSettings::NativeFormat);
const auto productGroups = registry.childGroups();
for (const QString &productKey : productGroups) {
- const auto entryEnd = std::end(knowToolchains);
- const auto entryIt = std::find_if(std::begin(knowToolchains), entryEnd,
- [productKey](const Entry &entry) {
- return entry.productKey == productKey;
- });
- if (entryIt == entryEnd)
+ if (!productKey.startsWith(QStringLiteral("App")))
continue;
-
registry.beginGroup(productKey);
- const QString rootPath = registry.value(QStringLiteral("Path"))
+ const QString productPath = registry.value(QStringLiteral("ProductDir"))
.toString();
- if (!rootPath.isEmpty()) {
- // Build full compiler path.
- const QFileInfo keilPath(rootPath + entryIt->subExePath);
- if (keilPath.exists()) {
- QString version = registry.value(QStringLiteral("Version"))
- .toString();
- if (version.startsWith(QLatin1Char('V')))
- version.remove(0, 1);
- infos.push_back({keilPath, Version::fromString(version)});
+ // Fetch the toolchain executable path.
+ QFileInfo keilPath;
+ if (productPath.endsWith(QStringLiteral("ARM")))
+ keilPath.setFile(productPath + QStringLiteral("\\ARMCC\\bin\\armcc.exe"));
+ else if (productPath.endsWith(QStringLiteral("C51")))
+ keilPath.setFile(productPath + QStringLiteral("\\BIN\\c51.exe"));
+ else if (productPath.endsWith(QStringLiteral("C251")))
+ keilPath.setFile(productPath + QStringLiteral("\\BIN\\c251.exe"));
+ else if (productPath.endsWith(QStringLiteral("C166")))
+ keilPath.setFile(productPath + QStringLiteral("\\BIN\\c166.exe"));
+
+ if (keilPath.exists()) {
+ // Fetch the toolchain version.
+ const QDir rootPath(registry.value(QStringLiteral("Directory")).toString());
+ const QString toolsIniFilePath = rootPath.absoluteFilePath(
+ QStringLiteral("tools.ini"));
+ for (auto index = 1; index <= 2; ++index) {
+ const QString section = registry.value(
+ QStringLiteral("Section %1").arg(index)).toString();
+ const QString version = extractVersion(toolsIniFilePath, section);
+ if (!version.isEmpty()) {
+ infos.push_back({keilPath, Version::fromString(version)});
+ break;
+ }
}
}
registry.endGroup();
}
-
}
std::sort(infos.begin(), infos.end());
@@ -255,10 +406,10 @@ void createKeilProfile(const QFileInfo &compiler, Settings *settings,
QString profileName)
{
const ToolchainInstallInfo info = {compiler, Version{}};
- createKeilProfileHelper(info, settings, profileName);
+ createKeilProfileHelper(info, settings, std::move(profileName));
}
-void keilProbe(Settings *settings, QList<Profile> &profiles)
+void keilProbe(Settings *settings, std::vector<Profile> &profiles)
{
qbsInfo() << Tr::tr("Trying to detect KEIL toolchains...");
diff --git a/src/app/qbs-setup-toolchains/keilprobe.h b/src/app/qbs-setup-toolchains/keilprobe.h
index c7e66ee24..fec650ab0 100644
--- a/src/app/qbs-setup-toolchains/keilprobe.h
+++ b/src/app/qbs-setup-toolchains/keilprobe.h
@@ -56,6 +56,6 @@ bool isKeilCompiler(const QString &compilerName);
void createKeilProfile(const QFileInfo &compiler, qbs::Settings *settings,
QString profileName);
-void keilProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles);
+void keilProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles);
#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/main.cpp b/src/app/qbs-setup-toolchains/main.cpp
index 87a2a842a..475bcf07b 100644
--- a/src/app/qbs-setup-toolchains/main.cpp
+++ b/src/app/qbs-setup-toolchains/main.cpp
@@ -49,7 +49,6 @@
#include <cstdlib>
#include <iostream>
-using qbs::Internal::Tr;
using qbs::Settings;
static void printUsage(const QString &usageString)
diff --git a/src/app/qbs-setup-toolchains/msvcprobe.cpp b/src/app/qbs-setup-toolchains/msvcprobe.cpp
index c8108bfd2..bb54add9f 100644
--- a/src/app/qbs-setup-toolchains/msvcprobe.cpp
+++ b/src/app/qbs-setup-toolchains/msvcprobe.cpp
@@ -50,15 +50,10 @@
#include <tools/qttools.h>
#include <tools/settings.h>
#include <tools/version.h>
-#include <tools/visualstudioversioninfo.h>
#include <tools/vsenvironmentdetector.h>
#include <QtCore/qdir.h>
#include <QtCore/qfileinfo.h>
-#include <QtCore/qjsonarray.h>
-#include <QtCore/qjsondocument.h>
-#include <QtCore/qjsonobject.h>
-#include <QtCore/qprocess.h>
#include <QtCore/qsettings.h>
#include <QtCore/qstringlist.h>
@@ -87,70 +82,18 @@ static void setQtHelperProperties(Profile &p, const MSVC *msvc)
p.setValue(QStringLiteral("cpp.compilerVersion"), msvc->compilerVersion.toString());
}
-static void addMSVCPlatform(Settings *settings, QList<Profile> &profiles, QString name, MSVC *msvc)
+static void addMSVCPlatform(Settings *settings, std::vector<Profile> &profiles, QString name, MSVC *msvc)
{
qbsInfo() << Tr::tr("Setting up profile '%1'.").arg(name);
- Profile p(name, settings);
+ Profile p(std::move(name), settings);
p.removeProfile();
p.setValue(QStringLiteral("qbs.targetPlatform"), QStringLiteral("windows"));
- p.setValue(QStringLiteral("qbs.toolchain"), QStringList(QStringLiteral("msvc")));
+ p.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("msvc"));
p.setValue(QStringLiteral("cpp.toolchainInstallPath"), msvc->binPath);
setQtHelperProperties(p, msvc);
profiles.push_back(p);
}
-struct MSVCArchInfo
-{
- QString arch;
- QString binPath;
-};
-
-static std::vector<MSVCArchInfo> findSupportedArchitectures(const MSVC &msvc)
-{
- std::vector<MSVCArchInfo> result;
- auto addResult = [&result](const MSVCArchInfo &ai) {
- if (QFile::exists(ai.binPath + QLatin1String("/cl.exe")))
- result.push_back(ai);
- };
- if (msvc.internalVsVersion.majorVersion() < 15) {
- static const QStringList knownArchitectures = QStringList()
- << QStringLiteral("x86")
- << QStringLiteral("amd64_x86")
- << QStringLiteral("amd64")
- << QStringLiteral("x86_amd64")
- << QStringLiteral("ia64")
- << QStringLiteral("x86_ia64")
- << QStringLiteral("x86_arm")
- << QStringLiteral("amd64_arm");
- for (const QString &knownArchitecture : knownArchitectures) {
- MSVCArchInfo ai;
- ai.arch = knownArchitecture;
- ai.binPath = msvc.binPathForArchitecture(knownArchitecture);
- addResult(ai);
- }
- } else {
- QDir vcInstallDir(msvc.vcInstallPath);
- const auto hostArchs = vcInstallDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
- for (const QString &hostArch : hostArchs) {
- QDir subdir = vcInstallDir;
- if (!subdir.cd(hostArch))
- continue;
- const QString shortHostArch = hostArch.mid(4).toLower();
- const auto archs = subdir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
- for (const QString &arch : archs) {
- MSVCArchInfo ai;
- ai.binPath = subdir.absoluteFilePath(arch);
- if (shortHostArch == arch)
- ai.arch = arch;
- else
- ai.arch = shortHostArch + QLatin1Char('_') + arch;
- addResult(ai);
- }
- }
- }
- return result;
-}
-
static QString wow6432Key()
{
#ifdef Q_OS_WIN64
@@ -160,203 +103,7 @@ static QString wow6432Key()
#endif
}
-static QString vswhereFilePath()
-{
- static const std::vector<const char *> envVarCandidates{"ProgramFiles", "ProgramFiles(x86)"};
- for (const char * const envVar : envVarCandidates) {
- const QString value = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv(envVar)));
- const QString cmd = value
- + QStringLiteral("/Microsoft Visual Studio/Installer/vswhere.exe");
- if (QFileInfo(cmd).exists())
- return cmd;
- }
- return {};
-}
-
-enum class ProductType { VisualStudio, BuildTools };
-static std::vector<MSVCInstallInfo> retrieveInstancesFromVSWhere(ProductType productType)
-{
- std::vector<MSVCInstallInfo> result;
- const QString cmd = vswhereFilePath();
- if (cmd.isEmpty())
- return result;
- QProcess vsWhere;
- QStringList args = productType == ProductType::VisualStudio
- ? QStringList({QStringLiteral("-all"), QStringLiteral("-legacy"),
- QStringLiteral("-prerelease")})
- : QStringList({QStringLiteral("-products"),
- QStringLiteral("Microsoft.VisualStudio.Product.BuildTools")});
- args << QStringLiteral("-format") << QStringLiteral("json") << QStringLiteral("-utf8");
- vsWhere.start(cmd, args);
- if (!vsWhere.waitForStarted(-1))
- return result;
- if (!vsWhere.waitForFinished(-1)) {
- qbsWarning() << Tr::tr("The vswhere tool failed to run: %1").arg(vsWhere.errorString());
- return result;
- }
- if (vsWhere.exitCode() != 0) {
- qbsWarning() << Tr::tr("The vswhere tool failed to run: %1")
- .arg(QString::fromLocal8Bit(vsWhere.readAllStandardError()));
- return result;
- }
- QJsonParseError parseError;
- QJsonDocument jsonOutput = QJsonDocument::fromJson(vsWhere.readAllStandardOutput(),
- &parseError);
- if (parseError.error != QJsonParseError::NoError) {
- qbsWarning() << Tr::tr("The vswhere tool produced invalid JSON output: %1")
- .arg(parseError.errorString());
- return result;
- }
- const auto jsonArray = jsonOutput.array();
- for (const QJsonValue &v : jsonArray) {
- const QJsonObject o = v.toObject();
- MSVCInstallInfo info;
- info.version = o.value(QStringLiteral("installationVersion")).toString();
- if (productType == ProductType::BuildTools) {
- // For build tools, the version is e.g. "15.8.28010.2036", rather than "15.0".
- const int dotIndex = info.version.indexOf(QLatin1Char('.'));
- if (dotIndex != -1)
- info.version = info.version.left(dotIndex);
- }
- info.installDir = o.value(QStringLiteral("installationPath")).toString();
- if (!info.version.isEmpty() && !info.installDir.isEmpty())
- result.push_back(info);
- }
- return result;
-}
-
-static std::vector<MSVCInstallInfo> installedMSVCsFromVsWhere()
-{
- const std::vector<MSVCInstallInfo> vsInstallations
- = retrieveInstancesFromVSWhere(ProductType::VisualStudio);
- const std::vector<MSVCInstallInfo> buildToolInstallations
- = retrieveInstancesFromVSWhere(ProductType::BuildTools);
- std::vector<MSVCInstallInfo> all;
- std::copy(vsInstallations.begin(), vsInstallations.end(), std::back_inserter(all));
- std::copy(buildToolInstallations.begin(), buildToolInstallations.end(),
- std::back_inserter(all));
- return all;
-}
-
-static std::vector<MSVCInstallInfo> installedMSVCsFromRegistry()
-{
- std::vector<MSVCInstallInfo> result;
-
- // Detect Visual Studio
- const QSettings vsRegistry(
- QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key()
- + QStringLiteral("\\Microsoft\\VisualStudio\\SxS\\VS7"),
- QSettings::NativeFormat);
- const auto vsNames = vsRegistry.childKeys();
- for (const QString &vsName : vsNames) {
- MSVCInstallInfo entry;
- entry.version = vsName;
- entry.installDir = vsRegistry.value(vsName).toString();
- result.push_back(entry);
- }
-
- // Detect Visual C++ Build Tools
- QSettings vcbtRegistry(
- QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key()
- + QStringLiteral("\\Microsoft\\VisualCppBuildTools"),
- QSettings::NativeFormat);
- const QStringList &vcbtRegistryChildGroups = vcbtRegistry.childGroups();
- for (const QString &childGroup : vcbtRegistryChildGroups) {
- vcbtRegistry.beginGroup(childGroup);
- bool ok;
- int installed = vcbtRegistry.value(QStringLiteral("Installed")).toInt(&ok);
- if (ok && installed) {
- MSVCInstallInfo entry;
- entry.version = childGroup;
- const QSettings vsRegistry(
- QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key()
- + QStringLiteral("\\Microsoft\\VisualStudio\\") + childGroup
- + QStringLiteral("\\Setup\\VC"),
- QSettings::NativeFormat);
- entry.installDir = vsRegistry.value(QStringLiteral("ProductDir")).toString();
- result.push_back(entry);
- }
- vcbtRegistry.endGroup();
- }
-
- return result;
-}
-
-QString MSVCInstallInfo::findVcvarsallBat() const
-{
- static const auto vcvarsall2017 = QStringLiteral("VC/Auxiliary/Build/vcvarsall.bat");
- // 2015, 2013 and 2012
- static const auto vcvarsallOld = QStringLiteral("VC/vcvarsall.bat");
- QDir dir(installDir);
- if (dir.exists(vcvarsall2017))
- return dir.absoluteFilePath(vcvarsall2017);
- if (dir.exists(vcvarsallOld))
- return dir.absoluteFilePath(vcvarsallOld);
- return {};
-}
-
-std::vector<MSVCInstallInfo> installedMSVCs()
-{
- const auto installInfos = installedMSVCsFromVsWhere();
- if (installInfos.empty())
- return installedMSVCsFromRegistry();
- return installInfos;
-}
-
-static std::vector<MSVC> installedCompilers()
-{
- std::vector<MSVC> msvcs;
- std::vector<MSVCInstallInfo> installInfos = installedMSVCsFromVsWhere();
- if (installInfos.empty())
- installInfos = installedMSVCsFromRegistry();
- for (const MSVCInstallInfo &installInfo : installInfos) {
- MSVC msvc;
- msvc.internalVsVersion = Version::fromString(installInfo.version, true);
- if (!msvc.internalVsVersion.isValid())
- continue;
-
- QDir vsInstallDir(installInfo.installDir);
- msvc.vsInstallPath = vsInstallDir.absolutePath();
- if (vsInstallDir.dirName() != QStringLiteral("VC")
- && !vsInstallDir.cd(QStringLiteral("VC"))) {
- continue;
- }
-
- msvc.version = QString::number(Internal::VisualStudioVersionInfo(
- msvc.internalVsVersion).marketingVersion());
- if (msvc.version.isEmpty()) {
- qbsWarning() << Tr::tr("Unknown MSVC version %1 found.").arg(installInfo.version);
- continue;
- }
-
- if (msvc.internalVsVersion.majorVersion() < 15) {
- QDir vcInstallDir = vsInstallDir;
- if (!vcInstallDir.cd(QStringLiteral("bin")))
- continue;
- msvc.vcInstallPath = vcInstallDir.absolutePath();
- msvcs.push_back(msvc);
- } else {
- QDir vcInstallDir = vsInstallDir;
- vcInstallDir.cd(QStringLiteral("Tools/MSVC"));
- const auto vcVersionStrs = vcInstallDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
- for (const QString &vcVersionStr : vcVersionStrs) {
- const Version vcVersion = Version::fromString(vcVersionStr);
- if (!vcVersion.isValid())
- continue;
- QDir specificVcInstallDir = vcInstallDir;
- if (!specificVcInstallDir.cd(vcVersionStr)
- || !specificVcInstallDir.cd(QStringLiteral("bin"))) {
- continue;
- }
- msvc.vcInstallPath = specificVcInstallDir.absolutePath();
- msvcs.push_back(msvc);
- }
- }
- }
- return msvcs;
-}
-
-void msvcProbe(Settings *settings, QList<Profile> &profiles)
+void msvcProbe(Settings *settings, std::vector<Profile> &profiles)
{
qbsInfo() << Tr::tr("Detecting MSVC toolchains...");
@@ -381,7 +128,7 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles)
sdk.vcInstallPath.chop(1);
if (sdk.isDefault)
defaultWinSDK = sdk;
- const auto ais = findSupportedArchitectures(sdk);
+ const auto ais = MSVC::findSupportedArchitectures(sdk);
for (const MSVCArchInfo &ai : ais) {
WinSDK specificSDK = sdk;
specificSDK.architecture = ai.arch;
@@ -399,24 +146,7 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles)
}
// 2) Installed MSVCs
- std::vector<MSVC> msvcs;
- const auto instMsvcs = installedCompilers();
- for (const MSVC &msvc : instMsvcs) {
- if (msvc.internalVsVersion.majorVersion() < 15) {
- // Check existence of various install scripts
- const QString vcvars32bat = msvc.vcInstallPath + QLatin1String("/vcvars32.bat");
- if (!QFileInfo(vcvars32bat).isFile())
- continue;
- }
-
- const auto ais = findSupportedArchitectures(msvc);
- for (const MSVCArchInfo &ai : ais) {
- MSVC specificMSVC = msvc;
- specificMSVC.architecture = ai.arch;
- specificMSVC.binPath = ai.binPath;
- msvcs.push_back(specificMSVC);
- }
- }
+ std::vector<MSVC> msvcs = MSVC::installedCompilers(ConsoleLogger::instance());
for (const MSVC &msvc : qAsConst(msvcs)) {
qbsInfo() << Tr::tr(" MSVC %1 (%2) detected in\n"
@@ -470,7 +200,7 @@ void createMsvcProfile(const QFileInfo &compiler, Settings *settings,
const auto compilerFilePath = compiler.absoluteFilePath();
MSVC msvc(compilerFilePath, MSVC::architectureFromClPath(compilerFilePath));
msvc.init();
- QList<Profile> dummy;
+ std::vector<Profile> dummy;
addMSVCPlatform(settings, dummy, profileName, &msvc);
qbsInfo() << Tr::tr("Profile '%1' created for '%2'.")
.arg(profileName, QDir::toNativeSeparators(compilerFilePath));
diff --git a/src/app/qbs-setup-toolchains/msvcprobe.h b/src/app/qbs-setup-toolchains/msvcprobe.h
index f63dd5dc8..981bbc561 100644
--- a/src/app/qbs-setup-toolchains/msvcprobe.h
+++ b/src/app/qbs-setup-toolchains/msvcprobe.h
@@ -53,19 +53,9 @@ class Profile;
class Settings;
}
-struct MSVCInstallInfo
-{
- QString version;
- QString installDir;
-
- QString findVcvarsallBat() const;
-};
-
-std::vector<MSVCInstallInfo> installedMSVCs();
-
void createMsvcProfile(const QFileInfo &compiler, qbs::Settings *settings,
const QString &profileName);
-void msvcProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles);
+void msvcProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles);
#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/probe.cpp b/src/app/qbs-setup-toolchains/probe.cpp
index 205306acd..add7ba05c 100644
--- a/src/app/qbs-setup-toolchains/probe.cpp
+++ b/src/app/qbs-setup-toolchains/probe.cpp
@@ -50,6 +50,7 @@
#include <tools/error.h>
#include <tools/hostosinfo.h>
#include <tools/profile.h>
+#include <tools/qttools.h>
#include <tools/settings.h>
#include <tools/toolchains.h>
@@ -96,32 +97,32 @@ QString findExecutable(const QString &fileName)
return {};
}
-QStringList toolchainTypeFromCompilerName(const QString &compilerName)
+QString toolchainTypeFromCompilerName(const QString &compilerName)
{
if (compilerName == QLatin1String("cl.exe"))
- return canonicalToolchain(QStringLiteral("msvc"));
+ return QStringLiteral("msvc");
if (compilerName == QLatin1String("clang-cl.exe"))
- return canonicalToolchain(QLatin1String("clang-cl"));
+ return QStringLiteral("clang-cl");
const auto types = { QStringLiteral("clang"), QStringLiteral("llvm"),
QStringLiteral("mingw"), QStringLiteral("gcc") };
for (const auto &type : types) {
if (compilerName.contains(type))
- return canonicalToolchain(type);
+ return type;
}
if (compilerName == QLatin1String("g++"))
- return canonicalToolchain(QStringLiteral("gcc"));
+ return QStringLiteral("gcc");
if (isIarCompiler(compilerName))
- return canonicalToolchain(QStringLiteral("iar"));
+ return QStringLiteral("iar");
if (isKeilCompiler(compilerName))
- return canonicalToolchain(QStringLiteral("keil"));
+ return QStringLiteral("keil");
if (isSdccCompiler(compilerName))
- return canonicalToolchain(QStringLiteral("sdcc"));
+ return QStringLiteral("sdcc");
return {};
}
void probe(Settings *settings)
{
- QList<Profile> profiles;
+ std::vector<Profile> profiles;
if (HostOsInfo::isWindowsHost()) {
msvcProbe(settings, profiles);
clangClProbe(settings, profiles);
@@ -137,10 +138,10 @@ void probe(Settings *settings)
sdccProbe(settings, profiles);
if (profiles.empty()) {
- qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << endl;
+ qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << Qt::endl;
} else if (profiles.size() == 1 && settings->defaultProfile().isEmpty()) {
const QString profileName = profiles.front().name();
- qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << endl;
+ qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << Qt::endl;
settings->setValue(QStringLiteral("defaultProfile"), profileName);
}
}
@@ -157,23 +158,22 @@ void createProfile(const QString &profileName, const QString &toolchainType,
.arg(compilerFilePath));
}
- QStringList toolchainTypes;
- if (toolchainType.isEmpty())
- toolchainTypes = toolchainTypeFromCompilerName(compiler.fileName());
- else
- toolchainTypes = canonicalToolchain(toolchainType);
+ const QString realToolchainType = !toolchainType.isEmpty()
+ ? toolchainType
+ : toolchainTypeFromCompilerName(compiler.fileName());
+ const QStringList toolchain = canonicalToolchain(realToolchainType);
- if (toolchainTypes.contains(QLatin1String("msvc")))
+ if (toolchain.contains(QLatin1String("msvc")))
createMsvcProfile(compiler, settings, profileName);
- else if (toolchainTypes.contains(QLatin1String("clang-cl")))
+ else if (toolchain.contains(QLatin1String("clang-cl")))
createClangClProfile(compiler, settings, profileName);
- else if (toolchainTypes.contains(QLatin1String("gcc")))
- createGccProfile(compiler, settings, toolchainTypes, profileName);
- else if (toolchainTypes.contains(QLatin1String("iar")))
+ else if (toolchain.contains(QLatin1String("gcc")))
+ createGccProfile(compiler, settings, realToolchainType, profileName);
+ else if (toolchain.contains(QLatin1String("iar")))
createIarProfile(compiler, settings, profileName);
- else if (toolchainTypes.contains(QLatin1String("keil")))
+ else if (toolchain.contains(QLatin1String("keil")))
createKeilProfile(compiler, settings, profileName);
- else if (toolchainTypes.contains(QLatin1String("sdcc")))
+ else if (toolchain.contains(QLatin1String("sdcc")))
createSdccProfile(compiler, settings, profileName);
else
throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type."));
diff --git a/src/app/qbs-setup-toolchains/probe.h b/src/app/qbs-setup-toolchains/probe.h
index 235d7a899..bce150bd7 100644
--- a/src/app/qbs-setup-toolchains/probe.h
+++ b/src/app/qbs-setup-toolchains/probe.h
@@ -57,7 +57,7 @@ QStringList systemSearchPaths();
QString findExecutable(const QString &fileName);
-QStringList toolchainTypeFromCompilerName(const QString &compilerName);
+QString toolchainTypeFromCompilerName(const QString &compilerName);
void createProfile(const QString &profileName, const QString &toolchainType,
const QString &compilerFilePath, qbs::Settings *settings);
diff --git a/src/app/qbs-setup-toolchains/sdccprobe.cpp b/src/app/qbs-setup-toolchains/sdccprobe.cpp
index eccd3ccae..977d834c4 100644
--- a/src/app/qbs-setup-toolchains/sdccprobe.cpp
+++ b/src/app/qbs-setup-toolchains/sdccprobe.cpp
@@ -116,8 +116,8 @@ static std::vector<Profile> createSdccProfileHelper(
if (actualArch != QString::fromLatin1(knownArch))
continue;
- QString fullProfileName = profileName;
- if (fullProfileName.isEmpty()) {
+ QString fullProfileName;
+ if (profileName.isEmpty()) {
// Create a full profile name in case we is
// in auto-detecting mode.
if (!info.compilerVersion.isValid()) {
@@ -133,7 +133,7 @@ static std::vector<Profile> createSdccProfileHelper(
// Append the detected actual architecture name
// to the proposed profile name.
fullProfileName = QStringLiteral("%1-%2").arg(
- fullProfileName, actualArch);
+ profileName, actualArch);
}
Profile profile(fullProfileName, settings);
@@ -151,6 +151,21 @@ static std::vector<Profile> createSdccProfileHelper(
return profiles;
}
+static Version dumpOldSddcCompilerVersion(const QByteArray &macroDump)
+{
+ const auto keyToken = QByteArrayLiteral("__SDCC ");
+ const int startIndex = macroDump.indexOf(keyToken);
+ if (startIndex == -1)
+ return Version{};
+ const int endIndex = macroDump.indexOf('\n', startIndex);
+ if (endIndex == -1)
+ return Version{};
+ const auto keyLength = keyToken.length();
+ return Version::fromString(QString::fromLatin1(
+ macroDump.mid(startIndex + keyLength,
+ endIndex - startIndex - keyLength).replace('_', '.')));
+}
+
static Version dumpSdccCompilerVersion(const QFileInfo &compiler)
{
const QByteArray dump = dumpSdccMacros(compiler);
@@ -161,10 +176,14 @@ static Version dumpSdccCompilerVersion(const QFileInfo &compiler)
const int minor = extractVersion(dump, "__SDCC_VERSION_MINOR ");
const int patch = extractVersion(dump, "__SDCC_VERSION_PATCH ");
if (major < 0 || minor < 0 || patch < 0) {
- qbsWarning() << Tr::tr("No '__SDCC_VERSION_xxx' token was found "
- "in the compiler dump:\n%1")
- .arg(QString::fromUtf8(dump));
- return Version{};
+ const auto version = dumpOldSddcCompilerVersion(dump);
+ if (!version.isValid()) {
+ qbsWarning() << Tr::tr("No '__SDCC_VERSION_xxx' or '__SDCC' token was found "
+ "in the compiler dump:\n%1")
+ .arg(QString::fromUtf8(dump));
+ return Version{};
+ }
+ return version;
}
return Version{major, minor, patch};
@@ -252,13 +271,13 @@ bool isSdccCompiler(const QString &compilerName)
}
void createSdccProfile(const QFileInfo &compiler, Settings *settings,
- QString profileName)
+ const QString &profileName)
{
const ToolchainInstallInfo info = {compiler, Version{}};
createSdccProfileHelper(info, settings, profileName);
}
-void sdccProbe(Settings *settings, QList<Profile> &profiles)
+void sdccProbe(Settings *settings, std::vector<Profile> &profiles)
{
qbsInfo() << Tr::tr("Trying to detect SDCC toolchains...");
diff --git a/src/app/qbs-setup-toolchains/sdccprobe.h b/src/app/qbs-setup-toolchains/sdccprobe.h
index aa2c613f3..4c913ddeb 100644
--- a/src/app/qbs-setup-toolchains/sdccprobe.h
+++ b/src/app/qbs-setup-toolchains/sdccprobe.h
@@ -68,8 +68,8 @@ inline bool operator==(const SdccInstallInfo &lhs, const SdccInstallInfo &rhs)
bool isSdccCompiler(const QString &compilerName);
void createSdccProfile(const QFileInfo &compiler, qbs::Settings *settings,
- QString profileName);
+ const QString &profileName);
-void sdccProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles);
+void sdccProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles);
#endif // Header guard
diff --git a/src/app/qbs-setup-toolchains/xcodeprobe.cpp b/src/app/qbs-setup-toolchains/xcodeprobe.cpp
index a0f6f80d1..97b043f92 100644
--- a/src/app/qbs-setup-toolchains/xcodeprobe.cpp
+++ b/src/app/qbs-setup-toolchains/xcodeprobe.cpp
@@ -110,7 +110,7 @@ namespace {
class XcodeProbe
{
public:
- XcodeProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles)
+ XcodeProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles)
: settings(settings), profiles(profiles)
{ }
@@ -120,7 +120,7 @@ public:
void detectAll();
private:
qbs::Settings *settings;
- QList<qbs::Profile> &profiles;
+ std::vector<qbs::Profile> &profiles;
QStringList developerPaths;
};
@@ -172,11 +172,7 @@ void XcodeProbe::setupDefaultToolchains(const QString &devPath, const QString &x
Profile installationProfile(xcodeName, settings);
installationProfile.removeProfile();
- installationProfile.setValue(QStringLiteral("qbs.toolchain"), QStringList()
- << QStringLiteral("xcode")
- << QStringLiteral("clang")
- << QStringLiteral("llvm")
- << QStringLiteral("gcc"));
+ installationProfile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("xcode"));
if (devPath != defaultDeveloperPath)
installationProfile.setValue(QStringLiteral("xcode.developerPath"), devPath);
profiles.push_back(installationProfile);
@@ -229,7 +225,7 @@ void XcodeProbe::detectAll()
}
} // end anonymous namespace
-void xcodeProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles)
+void xcodeProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles)
{
XcodeProbe probe(settings, profiles);
probe.detectAll();
diff --git a/src/app/qbs-setup-toolchains/xcodeprobe.h b/src/app/qbs-setup-toolchains/xcodeprobe.h
index ab501036b..fc15d177e 100644
--- a/src/app/qbs-setup-toolchains/xcodeprobe.h
+++ b/src/app/qbs-setup-toolchains/xcodeprobe.h
@@ -47,6 +47,6 @@ class Profile;
class Settings;
}
-void xcodeProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles);
+void xcodeProbe(qbs::Settings *settings, std::vector<qbs::Profile> &profiles);
#endif // Header guard
diff --git a/src/app/qbs/commandlinefrontend.cpp b/src/app/qbs/commandlinefrontend.cpp
index 8be06f3af..d8b4d9ca8 100644
--- a/src/app/qbs/commandlinefrontend.cpp
+++ b/src/app/qbs/commandlinefrontend.cpp
@@ -78,6 +78,7 @@ CommandLineFrontend::CommandLineFrontend(const CommandLineParser &parser, Settin
CommandLineFrontend::~CommandLineFrontend()
{
m_cancelTimer->stop();
+ delete m_observer;
}
// Called from interrupt handler. Don't do anything non-trivial here.
@@ -653,7 +654,7 @@ ProductData CommandLineFrontend::getTheOneRunnableProduct()
}
QBS_CHECK(false);
}
- QBS_CHECK(m_parser.products().size() == 0);
+ QBS_CHECK(m_parser.products().isEmpty());
QList<ProductData> runnableProducts;
const auto products = m_projects.front().projectData().allProducts();
diff --git a/src/app/qbs/parser/commandlineoption.cpp b/src/app/qbs/parser/commandlineoption.cpp
index 0c13662f0..a09f36c2c 100644
--- a/src/app/qbs/parser/commandlineoption.cpp
+++ b/src/app/qbs/parser/commandlineoption.cpp
@@ -47,9 +47,7 @@
namespace qbs {
using namespace Internal;
-CommandLineOption::~CommandLineOption()
-{
-}
+CommandLineOption::~CommandLineOption() = default;
void CommandLineOption::parse(CommandType command, const QString &representation, QStringList &input)
{
@@ -546,9 +544,7 @@ QString LogTimeOption::longRepresentation() const
}
-SettingsDirOption::SettingsDirOption()
-{
-}
+SettingsDirOption::SettingsDirOption() = default;
QString SettingsDirOption::description(CommandType command) const
{
@@ -627,9 +623,7 @@ QString RespectProjectJobLimitsOption::longRepresentation() const
return QStringLiteral("--enforce-project-job-limits");
}
-CommandEchoModeOption::CommandEchoModeOption()
-{
-}
+CommandEchoModeOption::CommandEchoModeOption() = default;
QString CommandEchoModeOption::description(CommandType command) const
{
diff --git a/src/app/qbs/parser/parsercommand.cpp b/src/app/qbs/parser/parsercommand.cpp
index c7185a725..799bf5dcf 100644
--- a/src/app/qbs/parser/parsercommand.cpp
+++ b/src/app/qbs/parser/parsercommand.cpp
@@ -53,9 +53,7 @@
namespace qbs {
using namespace Internal;
-Command::~Command()
-{
-}
+Command::~Command() = default;
void Command::parse(QStringList &input)
{
diff --git a/src/app/qbs/session.cpp b/src/app/qbs/session.cpp
index 30e71dfd5..75f0e3bc9 100644
--- a/src/app/qbs/session.cpp
+++ b/src/app/qbs/session.cpp
@@ -148,7 +148,7 @@ private:
struct ProductSelection {
ProductSelection(Project::ProductSelection s) : selection(s) {}
- ProductSelection(const QList<ProductData> &p) : products(p) {}
+ ProductSelection(QList<ProductData> p) : products(std::move(p)) {}
Project::ProductSelection selection = Project::ProductSelectionDefaultOnly;
QList<ProductData> products;
@@ -186,7 +186,10 @@ Session::Session()
#ifdef Q_OS_WIN32
// Make sure the line feed character appears as itself.
if (_setmode(_fileno(stdout), _O_BINARY) == -1) {
- std::cerr << "Failed to set stdout to binary mode: " << std::strerror(errno) << std::endl;
+ constexpr size_t errmsglen = FILENAME_MAX;
+ char errmsg[errmsglen];
+ strerror_s(errmsg, errmsglen, errno);
+ std::cerr << "Failed to set stdout to binary mode: " << errmsg << std::endl;
qApp->exit(EXIT_FAILURE);
}
#endif
@@ -248,7 +251,7 @@ void Session::setupProject(const QJsonObject &request)
if (m_currentJob) {
if (qobject_cast<SetupProjectJob *>(m_currentJob)
&& m_currentJob->state() == AbstractJob::StateCanceling) {
- m_resolveRequest = std::move(request);
+ m_resolveRequest = request;
return;
}
sendErrorReply("project-resolved",
@@ -258,7 +261,7 @@ void Session::setupProject(const QJsonObject &request)
m_moduleProperties = modulePropertiesFromRequest(request);
auto params = SetupProjectParameters::fromJson(request);
const ProjectDataMode dataMode = dataModeFromRequest(request);
- m_settings.reset(new Settings(params.settingsDirectory()));
+ m_settings = std::make_unique<Settings>(params.settingsDirectory());
const Preferences prefs(m_settings.get());
const QString appDir = QDir::cleanPath(QCoreApplication::applicationDirPath());
params.setSearchPaths(prefs.searchPaths(appDir + QLatin1String(
diff --git a/src/app/qbs/sessionpacket.cpp b/src/app/qbs/sessionpacket.cpp
index ce9fdaf76..dd6d1726e 100644
--- a/src/app/qbs/sessionpacket.cpp
+++ b/src/app/qbs/sessionpacket.cpp
@@ -99,8 +99,8 @@ QJsonObject SessionPacket::helloMessage()
{
return QJsonObject{
{StringConstants::type(), QLatin1String("hello")},
- {QLatin1String("api-level"), 1},
- {QLatin1String("api-compat-level"), 1}
+ {QLatin1String("api-level"), 2},
+ {QLatin1String("api-compat-level"), 2}
};
}
diff --git a/src/app/qbs/sessionpacketreader.cpp b/src/app/qbs/sessionpacketreader.cpp
index fe4b73f69..e99ea01ed 100644
--- a/src/app/qbs/sessionpacketreader.cpp
+++ b/src/app/qbs/sessionpacketreader.cpp
@@ -52,12 +52,12 @@ public:
SessionPacket currentPacket;
};
-SessionPacketReader::SessionPacketReader(QObject *parent) : QObject(parent), d(new Private) { }
+SessionPacketReader::SessionPacketReader(QObject *parent)
+ : QObject(parent)
+ , d(std::make_unique<Private>())
+{ }
-SessionPacketReader::~SessionPacketReader()
-{
- delete d;
-}
+SessionPacketReader::~SessionPacketReader() = default;
void SessionPacketReader::start()
{
diff --git a/src/app/qbs/sessionpacketreader.h b/src/app/qbs/sessionpacketreader.h
index 87d70cf39..f186fbc8c 100644
--- a/src/app/qbs/sessionpacketreader.h
+++ b/src/app/qbs/sessionpacketreader.h
@@ -43,6 +43,8 @@
#include <QtCore/qjsonobject.h>
#include <QtCore/qobject.h>
+#include <memory>
+
namespace qbs {
namespace Internal {
@@ -51,7 +53,7 @@ class SessionPacketReader : public QObject
Q_OBJECT
public:
explicit SessionPacketReader(QObject *parent = nullptr);
- ~SessionPacketReader();
+ ~SessionPacketReader() override;
void start();
@@ -61,7 +63,7 @@ signals:
private:
class Private;
- Private * const d;
+ const std::unique_ptr<Private> d;
};
} // namespace Internal
diff --git a/src/app/qbs/stdinreader.cpp b/src/app/qbs/stdinreader.cpp
index 4f784505d..5f00d7de4 100644
--- a/src/app/qbs/stdinreader.cpp
+++ b/src/app/qbs/stdinreader.cpp
@@ -43,13 +43,13 @@
#include <QtCore/qfile.h>
#include <QtCore/qsocketnotifier.h>
+#include <QtCore/qtimer.h>
#include <cerrno>
#include <cstring>
#ifdef Q_OS_WIN32
#include <qt_windows.h>
-#include <QtCore/qtimer.h>
#else
#include <fcntl.h>
#endif
@@ -69,11 +69,11 @@ private:
emit errorOccurred(tr("Cannot read from standard input."));
return;
}
+#ifdef Q_OS_UNIX
const auto emitError = [this] {
emit errorOccurred(tr("Failed to make standard input non-blocking: %1")
.arg(QLatin1String(std::strerror(errno))));
};
-#ifdef Q_OS_UNIX
const int flags = fcntl(0, F_GETFL, 0);
if (flags == -1) {
emitError();
@@ -87,6 +87,18 @@ private:
connect(&m_notifier, &QSocketNotifier::activated, this, [this] {
emit dataAvailable(m_stdIn.readAll());
});
+
+ // Neither the aboutToClose() nor the readChannelFinished() signals
+ // are triggering, so we need a timer to check whether the controlling
+ // process disappeared.
+ const auto stdinClosedChecker = new QTimer(this);
+ connect(stdinClosedChecker, &QTimer::timeout, this, [this, stdinClosedChecker] {
+ if (m_stdIn.atEnd()) {
+ stdinClosedChecker->stop();
+ emit errorOccurred(tr("Input channel closed unexpectedly."));
+ }
+ });
+ stdinClosedChecker->start(1000);
}
QFile m_stdIn;
@@ -112,14 +124,22 @@ private:
// (how would we abort that one?), but ideally we'd like
// to have a signal-based approach like in the Unix variant.
const auto timer = new QTimer(this);
- connect(timer, &QTimer::timeout, this, [this] {
+ connect(timer, &QTimer::timeout, this, [this, timer] {
char buf[1024];
DWORD bytesAvail;
- PeekNamedPipe(m_stdinHandle, nullptr, 0, nullptr, &bytesAvail, nullptr);
+ if (!PeekNamedPipe(m_stdinHandle, nullptr, 0, nullptr, &bytesAvail, nullptr)) {
+ timer->stop();
+ emit errorOccurred(tr("Failed to read from input channel."));
+ return;
+ }
while (bytesAvail > 0) {
DWORD bytesRead;
- ReadFile(m_stdinHandle, buf, std::min<DWORD>(bytesAvail, sizeof buf), &bytesRead,
- nullptr);
+ if (!ReadFile(m_stdinHandle, buf, std::min<DWORD>(bytesAvail, sizeof buf),
+ &bytesRead, nullptr)) {
+ timer->stop();
+ emit errorOccurred(tr("Failed to read from input channel."));
+ return;
+ }
emit dataAvailable(QByteArray(buf, bytesRead));
bytesAvail -= bytesRead;
}
diff --git a/src/lib/corelib/api/changeset.cpp b/src/lib/corelib/api/changeset.cpp
index 5d375fd65..773af328d 100644
--- a/src/lib/corelib/api/changeset.cpp
+++ b/src/lib/corelib/api/changeset.cpp
@@ -48,8 +48,8 @@ ChangeSet::ChangeSet()
{
}
-ChangeSet::ChangeSet(const QList<EditOp> &operations)
- : m_string(nullptr), m_cursor(nullptr), m_operationList(operations), m_error(false)
+ChangeSet::ChangeSet(QList<EditOp> operations)
+ : m_string(nullptr), m_cursor(nullptr), m_operationList(std::move(operations)), m_error(false)
{
}
@@ -393,5 +393,5 @@ void ChangeSet::apply_helper()
m_cursor->endEditBlock();
}
-} // namespace Internal {
+} // namespace QbsQmlJS
diff --git a/src/lib/corelib/api/changeset.h b/src/lib/corelib/api/changeset.h
index 13d3908d4..23248c48e 100644
--- a/src/lib/corelib/api/changeset.h
+++ b/src/lib/corelib/api/changeset.h
@@ -86,7 +86,7 @@ public:
public:
ChangeSet();
- ChangeSet(const QList<EditOp> &operations);
+ ChangeSet(QList<EditOp> operations);
bool empty() const;
diff --git a/src/lib/corelib/api/internaljobs.cpp b/src/lib/corelib/api/internaljobs.cpp
index c74c3d8a4..c53cf3e33 100644
--- a/src/lib/corelib/api/internaljobs.cpp
+++ b/src/lib/corelib/api/internaljobs.cpp
@@ -225,9 +225,7 @@ InternalSetupProjectJob::InternalSetupProjectJob(const Logger &logger)
{
}
-InternalSetupProjectJob::~InternalSetupProjectJob()
-{
-}
+InternalSetupProjectJob::~InternalSetupProjectJob() = default;
void InternalSetupProjectJob::init(const TopLevelProjectPtr &existingProject,
const SetupProjectParameters &parameters)
@@ -350,12 +348,10 @@ BuildGraphTouchingJob::BuildGraphTouchingJob(const Logger &logger, QObject *pare
{
}
-BuildGraphTouchingJob::~BuildGraphTouchingJob()
-{
-}
+BuildGraphTouchingJob::~BuildGraphTouchingJob() = default;
void BuildGraphTouchingJob::setup(const TopLevelProjectPtr &project,
- const QList<ResolvedProductPtr> &products, bool dryRun)
+ const QVector<ResolvedProductPtr> &products, bool dryRun)
{
m_project = project;
m_products = products;
@@ -374,14 +370,14 @@ InternalBuildJob::InternalBuildJob(const Logger &logger, QObject *parent)
}
void InternalBuildJob::build(const TopLevelProjectPtr &project,
- const QList<ResolvedProductPtr> &products, const BuildOptions &buildOptions)
+ const QVector<ResolvedProductPtr> &products, const BuildOptions &buildOptions)
{
setup(project, products, buildOptions.dryRun());
setTimed(buildOptions.logElapsedTime());
m_executor = new Executor(logger());
m_executor->setProject(project);
- m_executor->setProducts(std::vector<ResolvedProductPtr>(products.cbegin(), products.cend()));
+ m_executor->setProducts(products);
m_executor->setBuildOptions(buildOptions);
m_executor->setProgressObserver(observer());
@@ -418,7 +414,8 @@ InternalCleanJob::InternalCleanJob(const Logger &logger, QObject *parent)
}
void InternalCleanJob::init(const TopLevelProjectPtr &project,
- const QList<ResolvedProductPtr> &products, const CleanOptions &options)
+ const QVector<ResolvedProductPtr> &products,
+ const CleanOptions &options)
{
setup(project, products, options.dryRun());
setTimed(options.logElapsedTime());
@@ -443,12 +440,10 @@ InternalInstallJob::InternalInstallJob(const Logger &logger)
{
}
-InternalInstallJob::~InternalInstallJob()
-{
-}
+InternalInstallJob::~InternalInstallJob() = default;
void InternalInstallJob::init(const TopLevelProjectPtr &project,
- const std::vector<ResolvedProductPtr> &products, const InstallOptions &options)
+ const QVector<ResolvedProductPtr> &products, const InstallOptions &options)
{
m_project = project;
m_products = products;
diff --git a/src/lib/corelib/api/internaljobs.h b/src/lib/corelib/api/internaljobs.h
index 58127eb05..d66835941 100644
--- a/src/lib/corelib/api/internaljobs.h
+++ b/src/lib/corelib/api/internaljobs.h
@@ -151,7 +151,7 @@ class BuildGraphTouchingJob : public InternalJob
{
Q_OBJECT
public:
- const QList<ResolvedProductPtr> &products() const { return m_products; }
+ const QVector<ResolvedProductPtr> &products() const { return m_products; }
const TopLevelProjectPtr &project() const { return m_project; }
signals:
@@ -162,13 +162,13 @@ protected:
BuildGraphTouchingJob(const Logger &logger, QObject *parent = nullptr);
~BuildGraphTouchingJob() override;
- void setup(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products,
+ void setup(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products,
bool dryRun);
void storeBuildGraph();
private:
TopLevelProjectPtr m_project;
- QList<ResolvedProductPtr> m_products;
+ QVector<ResolvedProductPtr> m_products;
bool m_dryRun;
};
@@ -179,7 +179,7 @@ class InternalBuildJob : public BuildGraphTouchingJob
public:
InternalBuildJob(const Logger &logger, QObject *parent = nullptr);
- void build(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products,
+ void build(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products,
const BuildOptions &buildOptions);
private:
@@ -196,8 +196,8 @@ class InternalCleanJob : public BuildGraphTouchingJob
public:
InternalCleanJob(const Logger &logger, QObject *parent = nullptr);
- void init(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products,
- const CleanOptions &options);
+ void init(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products,
+ const CleanOptions &options);
private:
void start() override;
@@ -213,14 +213,14 @@ public:
InternalInstallJob(const Logger &logger);
~InternalInstallJob() override;
- void init(const TopLevelProjectPtr &project, const std::vector<ResolvedProductPtr> &products,
+ void init(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products,
const InstallOptions &options);
private:
void start() override;
TopLevelProjectPtr m_project;
- std::vector<ResolvedProductPtr> m_products;
+ QVector<ResolvedProductPtr> m_products;
InstallOptions m_options;
};
diff --git a/src/lib/corelib/api/jobs.cpp b/src/lib/corelib/api/jobs.cpp
index 32b7accc7..7a845b0ac 100644
--- a/src/lib/corelib/api/jobs.cpp
+++ b/src/lib/corelib/api/jobs.cpp
@@ -309,7 +309,7 @@ BuildJob::BuildJob(const Logger &logger, QObject *parent)
this, &BuildJob::reportProcessResult);
}
-void BuildJob::build(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products,
+void BuildJob::build(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products,
const BuildOptions &options)
{
if (!lockProject(project))
@@ -340,7 +340,7 @@ CleanJob::CleanJob(const Logger &logger, QObject *parent)
{
}
-void CleanJob::clean(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products,
+void CleanJob::clean(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products,
const qbs::CleanOptions &options)
{
if (!lockProject(project))
@@ -361,15 +361,14 @@ InstallJob::InstallJob(const Logger &logger, QObject *parent)
}
void InstallJob::install(const TopLevelProjectPtr &project,
- const QList<ResolvedProductPtr> &products, const InstallOptions &options)
+ const QVector<ResolvedProductPtr> &products,
+ const InstallOptions &options)
{
if (!lockProject(project))
return;
auto wrapper = qobject_cast<InternalJobThreadWrapper *>(internalJob());
auto installJob = qobject_cast<InternalInstallJob *>(wrapper->synchronousJob());
- installJob->init(project,
- std::vector<ResolvedProductPtr>(products.cbegin(), products.cend()),
- options);
+ installJob->init(project, products, options);
wrapper->start();
}
diff --git a/src/lib/corelib/api/jobs.h b/src/lib/corelib/api/jobs.h
index 36c6b7a80..64929489e 100644
--- a/src/lib/corelib/api/jobs.h
+++ b/src/lib/corelib/api/jobs.h
@@ -136,7 +136,7 @@ private:
BuildJob(const Internal::Logger &logger, QObject *parent);
void build(const Internal::TopLevelProjectPtr &project,
- const QList<qbs::Internal::ResolvedProductPtr> &products,
+ const QVector<Internal::ResolvedProductPtr> &products,
const BuildOptions &options);
void handleLauncherError(const ErrorInfo &error);
@@ -153,7 +153,7 @@ private:
CleanJob(const Internal::Logger &logger, QObject *parent);
void clean(const Internal::TopLevelProjectPtr &project,
- const QList<Internal::ResolvedProductPtr> &products, const CleanOptions &options);
+ const QVector<Internal::ResolvedProductPtr> &products, const CleanOptions &options);
};
class QBS_EXPORT InstallJob : public AbstractJob
@@ -164,7 +164,8 @@ private:
InstallJob(const Internal::Logger &logger, QObject *parent);
void install(const Internal::TopLevelProjectPtr &project,
- const QList<Internal::ResolvedProductPtr> &products, const InstallOptions &options);
+ const QVector<Internal::ResolvedProductPtr> &products,
+ const InstallOptions &options);
};
} // namespace qbs
diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp
index d0fe7296e..2b07f1a8d 100644
--- a/src/lib/corelib/api/project.cpp
+++ b/src/lib/corelib/api/project.cpp
@@ -131,7 +131,7 @@ ProjectData ProjectPrivate::projectData()
return m_projectData;
}
-static void addDependencies(QList<ResolvedProductPtr> &products)
+static void addDependencies(QVector<ResolvedProductPtr> &products)
{
for (int i = 0; i < products.size(); ++i) {
const ResolvedProductPtr &product = products.at(i);
@@ -142,11 +142,11 @@ static void addDependencies(QList<ResolvedProductPtr> &products)
}
}
-BuildJob *ProjectPrivate::buildProducts(const QList<ResolvedProductPtr> &products,
+BuildJob *ProjectPrivate::buildProducts(const QVector<ResolvedProductPtr> &products,
const BuildOptions &options, bool needsDepencencyResolving,
QObject *jobOwner)
{
- QList<ResolvedProductPtr> productsToBuild = products;
+ QVector<ResolvedProductPtr> productsToBuild = products;
if (needsDepencencyResolving)
addDependencies(productsToBuild);
@@ -156,7 +156,7 @@ BuildJob *ProjectPrivate::buildProducts(const QList<ResolvedProductPtr> &product
return job;
}
-CleanJob *ProjectPrivate::cleanProducts(const QList<ResolvedProductPtr> &products,
+CleanJob *ProjectPrivate::cleanProducts(const QVector<ResolvedProductPtr> &products,
const CleanOptions &options, QObject *jobOwner)
{
const auto job = new CleanJob(logger, jobOwner);
@@ -165,10 +165,10 @@ CleanJob *ProjectPrivate::cleanProducts(const QList<ResolvedProductPtr> &product
return job;
}
-InstallJob *ProjectPrivate::installProducts(const QList<ResolvedProductPtr> &products,
+InstallJob *ProjectPrivate::installProducts(const QVector<ResolvedProductPtr> &products,
const InstallOptions &options, bool needsDepencencyResolving, QObject *jobOwner)
{
- QList<ResolvedProductPtr> productsToInstall = products;
+ QVector<ResolvedProductPtr> productsToInstall = products;
if (needsDepencencyResolving)
addDependencies(productsToInstall);
const auto job = new InstallJob(logger, jobOwner);
@@ -177,9 +177,9 @@ InstallJob *ProjectPrivate::installProducts(const QList<ResolvedProductPtr> &pro
return job;
}
-QList<ResolvedProductPtr> ProjectPrivate::internalProducts(const QList<ProductData> &products) const
+QVector<ResolvedProductPtr> ProjectPrivate::internalProducts(const QList<ProductData> &products) const
{
- QList<ResolvedProductPtr> internalProducts;
+ QVector<ResolvedProductPtr> internalProducts;
for (const ProductData &product : products) {
if (product.isEnabled())
internalProducts.push_back(internalProduct(product));
@@ -187,20 +187,21 @@ QList<ResolvedProductPtr> ProjectPrivate::internalProducts(const QList<ProductDa
return internalProducts;
}
-static QList<ResolvedProductPtr> enabledInternalProducts(const ResolvedProjectConstPtr &project,
+static QVector<ResolvedProductPtr> enabledInternalProducts(const ResolvedProjectConstPtr &project,
bool includingNonDefault)
{
- QList<ResolvedProductPtr> products;
+ QVector<ResolvedProductPtr> products;
for (const ResolvedProductPtr &p : project->products) {
if (p->enabled && (includingNonDefault || p->builtByDefault()))
products.push_back(p);
}
- for (const ResolvedProjectConstPtr &subProject : qAsConst(project->subProjects))
+ for (const auto &subProject : qAsConst(project->subProjects))
products << enabledInternalProducts(subProject, includingNonDefault);
return products;
}
-QList<ResolvedProductPtr> ProjectPrivate::allEnabledInternalProducts(bool includingNonDefault) const
+QVector<ResolvedProductPtr> ProjectPrivate::allEnabledInternalProducts(
+ bool includingNonDefault) const
{
return enabledInternalProducts(internalProject, includingNonDefault);
}
@@ -218,7 +219,7 @@ static ResolvedProductPtr internalProductForProject(const ResolvedProjectConstPt
if (matches(product, resolvedProduct))
return resolvedProduct;
}
- for (const ResolvedProjectConstPtr &subProject : qAsConst(project->subProjects)) {
+ for (const auto &subProject : qAsConst(project->subProjects)) {
const ResolvedProductPtr &p = internalProductForProject(subProject, product);
if (p)
return p;
@@ -272,13 +273,13 @@ GroupData ProjectPrivate::createGroupDataFromGroup(const GroupPtr &resolvedGroup
group.d->name = resolvedGroup->name;
group.d->prefix = resolvedGroup->prefix;
group.d->location = resolvedGroup->location;
- for (const SourceArtifactConstPtr &sa : resolvedGroup->files) {
+ for (const auto &sa : resolvedGroup->files) {
ArtifactData artifact = createApiSourceArtifact(sa);
setupInstallData(artifact, product);
group.d->sourceArtifacts.push_back(artifact);
}
if (resolvedGroup->wildcards) {
- for (const SourceArtifactConstPtr &sa : resolvedGroup->wildcards->files) {
+ for (const auto &sa : resolvedGroup->wildcards->files) {
ArtifactData artifact = createApiSourceArtifact(sa);
setupInstallData(artifact, product);
group.d->sourceArtifactsFromWildcards.push_back(artifact);
@@ -355,7 +356,7 @@ void ProjectPrivate::addGroup(const ProductData &product, const QString &groupNa
QList<ProductData> products = findProductsByName(product.name());
if (products.empty())
throw ErrorInfo(Tr::tr("Product '%1' does not exist.").arg(product.name()));
- const QList<ResolvedProductPtr> resolvedProducts = internalProducts(products);
+ const auto resolvedProducts = internalProducts(products);
QBS_CHECK(products.size() == resolvedProducts.size());
for (const GroupPtr &resolvedGroup : resolvedProducts.front()->groups) {
@@ -367,28 +368,6 @@ void ProjectPrivate::addGroup(const ProductData &product, const QString &groupNa
ProjectFileGroupInserter groupInserter(products.front(), groupName);
groupInserter.apply();
-
- m_projectData.d.detach(); // The data we already gave out must stay as it is.
-
- updateInternalCodeLocations(internalProject, groupInserter.itemPosition(),
- groupInserter.lineOffset());
- updateExternalCodeLocations(m_projectData, groupInserter.itemPosition(),
- groupInserter.lineOffset());
-
- products = findProductsByName(products.front().name()); // These are new objects.
- QBS_CHECK(products.size() == resolvedProducts.size());
- for (int i = 0; i < products.size(); ++i) {
- const GroupPtr resolvedGroup = ResolvedGroup::create();
- resolvedGroup->location = groupInserter.itemPosition();
- resolvedGroup->enabled = true;
- resolvedGroup->name = groupName;
- resolvedGroup->properties = resolvedProducts[i]->moduleProperties;
- resolvedGroup->overrideTags = false;
- resolvedProducts.at(i)->groups << resolvedGroup;
- QList<GroupData> &groupData = products.at(i).d->groups;
- groupData << createGroupDataFromGroup(resolvedGroup, resolvedProducts.at(i));
- std::sort(groupData.begin(), groupData.end());
- }
}
ProjectPrivate::GroupUpdateContext ProjectPrivate::getGroupContext(const ProductData &product,
@@ -484,15 +463,6 @@ ProjectPrivate::FileListUpdateContext ProjectPrivate::getFileListContext(const P
return filesContext;
}
-static SourceArtifactPtr createSourceArtifact(const QString &filePath,
- const ResolvedProductPtr &product, const GroupPtr &group, bool wildcard)
-{
- const SourceArtifactPtr artifact
- = ProjectResolver::createSourceArtifact(product, filePath, group, wildcard);
- ProjectResolver::applyFileTaggers(artifact, product);
- return artifact;
-}
-
void ProjectPrivate::addFiles(const ProductData &product, const GroupData &group,
const QStringList &filePaths)
{
@@ -503,7 +473,7 @@ void ProjectPrivate::addFiles(const ProductData &product, const GroupData &group
// due to conditions.
for (const GroupPtr &group : qAsConst(groupContext.resolvedGroups)) {
for (const QString &filePath : qAsConst(filesContext.absoluteFilePaths)) {
- for (const SourceArtifactConstPtr &sa : group->files) {
+ for (const auto &sa : group->files) {
if (sa->absoluteFilePath == filePath) {
throw ErrorInfo(Tr::tr("File '%1' already exists in group '%2'.")
.arg(filePath, group->name));
@@ -516,57 +486,6 @@ void ProjectPrivate::addFiles(const ProductData &product, const GroupData &group
group.isValid() ? groupContext.groups.front() : GroupData(),
filesContext.relativeFilePaths);
adder.apply();
-
- m_projectData.d.detach();
- updateInternalCodeLocations(internalProject, adder.itemPosition(), adder.lineOffset());
- updateExternalCodeLocations(m_projectData, adder.itemPosition(), adder.lineOffset());
-
- QHash<QString, std::pair<SourceArtifactPtr, ResolvedProductPtr>> addedSourceArtifacts;
- for (int i = 0; i < groupContext.resolvedGroups.size(); ++i) {
- const ResolvedProductPtr &resolvedProduct = groupContext.resolvedProducts.at(i);
- const GroupPtr &resolvedGroup = groupContext.resolvedGroups.at(i);
- for (const QString &file : qAsConst(filesContext.absoluteFilePaths)) {
- const SourceArtifactPtr sa = createSourceArtifact(file, resolvedProduct, resolvedGroup,
- false);
- addedSourceArtifacts.insert(file, std::make_pair(sa, resolvedProduct));
- }
- for (const QString &file : qAsConst(filesContext.absoluteFilePathsFromWildcards)) {
- QBS_CHECK(resolvedGroup->wildcards);
- const SourceArtifactPtr sa = createSourceArtifact(file, resolvedProduct, resolvedGroup,
- true);
- addedSourceArtifacts.insert(file, std::make_pair(sa, resolvedProduct));
- }
- if (resolvedProduct->enabled) {
- for (const auto &pair : qAsConst(addedSourceArtifacts))
- createArtifact(resolvedProduct, pair.first);
- }
- }
- doSanityChecks(internalProject, logger);
- QList<ArtifactData> sourceArtifacts;
- QList<ArtifactData> sourceArtifactsFromWildcards;
- for (const QString &fp : qAsConst(filesContext.absoluteFilePaths)) {
- const auto pair = addedSourceArtifacts.value(fp);
- const SourceArtifactConstPtr sa = pair.first;
- QBS_CHECK(sa);
- ArtifactData artifactData = createApiSourceArtifact(sa);
- setupInstallData(artifactData, pair.second);
- sourceArtifacts << artifactData;
- }
- for (const QString &fp : qAsConst(filesContext.absoluteFilePathsFromWildcards)) {
- const auto pair = addedSourceArtifacts.value(fp);
- const SourceArtifactConstPtr sa = pair.first;
- QBS_CHECK(sa);
- ArtifactData artifactData = createApiSourceArtifact(sa);
- setupInstallData(artifactData, pair.second);
- sourceArtifactsFromWildcards << artifactData;
- }
- for (const GroupData &g : qAsConst(groupContext.groups)) {
- g.d->sourceArtifacts << sourceArtifacts;
- std::sort(g.d->sourceArtifacts.begin(), g.d->sourceArtifacts.end());
- g.d->sourceArtifactsFromWildcards << sourceArtifactsFromWildcards;
- std::sort(g.d->sourceArtifactsFromWildcards.begin(),
- g.d->sourceArtifactsFromWildcards.end());
- }
}
void ProjectPrivate::removeFiles(const ProductData &product, const GroupData &group,
@@ -595,134 +514,17 @@ void ProjectPrivate::removeFiles(const ProductData &product, const GroupData &gr
group.isValid() ? groupContext.groups.front() : GroupData(),
filesContext.relativeFilePaths);
remover.apply();
-
- for (int i = 0; i < groupContext.resolvedProducts.size(); ++i) {
- removeFilesFromBuildGraph(groupContext.resolvedProducts.at(i), sourceArtifacts);
- for (const SourceArtifactPtr &sa : sourceArtifacts)
- removeOne(groupContext.resolvedGroups.at(i)->files, sa);
- }
- doSanityChecks(internalProject, logger);
-
- m_projectData.d.detach();
- updateInternalCodeLocations(internalProject, remover.itemPosition(), remover.lineOffset());
- updateExternalCodeLocations(m_projectData, remover.itemPosition(), remover.lineOffset());
- for (const GroupData &g : qAsConst(groupContext.groups)) {
- for (int i = g.d->sourceArtifacts.size() - 1; i >= 0; --i) {
- if (filesContext.absoluteFilePaths.contains(g.d->sourceArtifacts.at(i).filePath()))
- g.d->sourceArtifacts.removeAt(i);
- }
- }
}
void ProjectPrivate::removeGroup(const ProductData &product, const GroupData &group)
{
GroupUpdateContext context = getGroupContext(product, group);
-
ProjectFileGroupRemover remover(context.products.front(), context.groups.front());
remover.apply();
- for (int i = 0; i < context.resolvedProducts.size(); ++i) {
- const ResolvedProductPtr &product = context.resolvedProducts.at(i);
- const GroupPtr &group = context.resolvedGroups.at(i);
- removeFilesFromBuildGraph(product, group->allFiles());
- const bool removed = removeOne(product->groups, group);
- QBS_CHECK(removed);
- }
- doSanityChecks(internalProject, logger);
-
- m_projectData.d.detach();
- updateInternalCodeLocations(internalProject, remover.itemPosition(), remover.lineOffset());
- updateExternalCodeLocations(m_projectData, remover.itemPosition(), remover.lineOffset());
- for (int i = 0; i < context.products.size(); ++i) {
- const bool removed = context.products.at(i).d->groups.removeOne(context.groups.at(i));
- QBS_CHECK(removed);
- }
}
#endif // QBS_ENABLE_PROJECT_FILE_UPDATES
-void ProjectPrivate::removeFilesFromBuildGraph(const ResolvedProductConstPtr &product,
- const std::vector<SourceArtifactPtr> &files)
-{
- if (!product->enabled)
- return;
- QBS_CHECK(internalProject->buildData);
- ArtifactSet allRemovedArtifacts;
- for (const SourceArtifactPtr &sa : files) {
- ArtifactSet removedArtifacts;
- Artifact * const artifact = lookupArtifact(product, sa->absoluteFilePath);
- if (artifact) { // Can be null if the executor has not yet applied the respective rule.
- internalProject->buildData->removeArtifactAndExclusiveDependents(artifact, logger,
- true, &removedArtifacts);
- }
- allRemovedArtifacts.unite(removedArtifacts);
- }
- EmptyDirectoriesRemover(product->topLevelProject(), logger)
- .removeEmptyParentDirectories(allRemovedArtifacts);
- qDeleteAll(allRemovedArtifacts);
-}
-
-static void updateLocationIfNecessary(CodeLocation &location, const CodeLocation &changeLocation,
- int lineOffset)
-{
- if (location.filePath() == changeLocation.filePath()
- && location.line() >= changeLocation.line()) {
- location = CodeLocation(location.filePath(), location.line() + lineOffset,
- location.column());
- }
-}
-
-void ProjectPrivate::updateInternalCodeLocations(const ResolvedProjectPtr &project,
- const CodeLocation &changeLocation, int lineOffset)
-{
- if (lineOffset == 0)
- return;
- updateLocationIfNecessary(project->location, changeLocation, lineOffset);
- for (const ResolvedProjectPtr &subProject : qAsConst(project->subProjects))
- updateInternalCodeLocations(subProject, changeLocation, lineOffset);
- for (const ResolvedProductPtr &product : project->products) {
- updateLocationIfNecessary(product->location, changeLocation, lineOffset);
- for (const GroupPtr &group : product->groups)
- updateLocationIfNecessary(group->location, changeLocation, lineOffset);
- for (const RulePtr &rule : qAsConst(product->rules)) {
- updateLocationIfNecessary(rule->prepareScript.location(), changeLocation, lineOffset);
- for (const RuleArtifactPtr &artifact : rule->artifacts) {
- for (auto &binding : artifact->bindings) {
- updateLocationIfNecessary(binding.location, changeLocation, lineOffset);
- }
- }
- }
- for (const ResolvedScannerConstPtr &scanner : product->scanners) {
- updateLocationIfNecessary(scanner->searchPathsScript.location(), changeLocation,
- lineOffset);
- updateLocationIfNecessary(scanner->scanScript.location(), changeLocation, lineOffset);
- }
- for (const ResolvedModuleConstPtr &module : product->modules) {
- updateLocationIfNecessary(module->setupBuildEnvironmentScript.location(),
- changeLocation, lineOffset);
- updateLocationIfNecessary(module->setupRunEnvironmentScript.location(),
- changeLocation, lineOffset);
- }
- }
-}
-
-void ProjectPrivate::updateExternalCodeLocations(const ProjectData &project,
- const CodeLocation &changeLocation, int lineOffset)
-{
- if (lineOffset == 0)
- return;
- updateLocationIfNecessary(project.d->location, changeLocation, lineOffset);
- const auto subProjects = project.subProjects();
- for (const ProjectData &subProject : subProjects)
- updateExternalCodeLocations(subProject, changeLocation, lineOffset);
- const auto products = project.products();
- for (const ProductData &product : products) {
- updateLocationIfNecessary(product.d->location, changeLocation, lineOffset);
- const auto groups = product.groups();
- for (const GroupData &group : groups)
- updateLocationIfNecessary(group.d->location, changeLocation, lineOffset);
- }
-}
-
void ProjectPrivate::prepareChangeToProject()
{
if (internalProject->locked)
@@ -851,7 +653,7 @@ void ProjectPrivate::retrieveProjectData(ProjectData &projectData,
projectData.d->name = internalProject->name;
projectData.d->location = internalProject->location;
projectData.d->enabled = internalProject->enabled;
- for (const ResolvedProductConstPtr &resolvedProduct : internalProject->products) {
+ for (const auto &resolvedProduct : internalProject->products) {
ProductData product;
product.d->type = resolvedProduct->fileTags.toStringList();
product.d->name = resolvedProduct->name;
@@ -904,8 +706,7 @@ void ProjectPrivate::retrieveProjectData(ProjectData &projectData,
product.d->isValid = true;
projectData.d->products << product;
}
- for (const ResolvedProjectConstPtr &internalSubProject
- : qAsConst(internalProject->subProjects)) {
+ for (const auto &internalSubProject : qAsConst(internalProject->subProjects)) {
if (!internalSubProject->enabled)
continue;
ProjectData subProject;
@@ -931,13 +732,9 @@ Project::Project(const TopLevelProjectPtr &internalProject, const Logger &logger
{
}
-Project::Project(const Project &other) : d(other.d)
-{
-}
+Project::Project(const Project &other) = default;
-Project::~Project()
-{
-}
+Project::~Project() = default;
/*!
* \brief Returns true if and only if this object was retrieved from a successful \c SetupProjectJob.
@@ -957,11 +754,7 @@ QString Project::profile() const
return d->internalProject->profile();
}
-Project &Project::operator=(const Project &other)
-{
- d = other.d;
- return *this;
-}
+Project &Project::operator=(const Project &other) = default;
/*!
* \brief Sets up a \c Project from a source file, possibly re-using previously stored information.
@@ -996,10 +789,7 @@ SetupProjectJob *Project::setupProject(const SetupProjectParameters &parameters,
return job;
}
-Project::Project()
-{
-}
-
+Project::Project() = default;
/*!
* \brief Retrieves information for this project.
@@ -1227,9 +1017,9 @@ Project::BuildGraphInfo Project::getBuildGraphInfo(const QString &bgFilePath,
for (const QString &prop : requestedProperties) {
QStringList components = prop.split(QLatin1Char('.'));
const QString propName = components.takeLast();
- props.push_back(std::make_pair(components.join(QLatin1Char('.')), propName));
+ props.emplace_back(components.join(QLatin1Char('.')), propName);
}
- for (const ResolvedProductConstPtr &product : project->allProducts()) {
+ for (const auto &product : project->allProducts()) {
if (props.empty())
break;
if (product->profile() != project->profile())
@@ -1283,10 +1073,10 @@ ErrorInfo Project::addGroup(const ProductData &product, const QString &groupName
QBS_CHECK(isValid());
d->prepareChangeToProject();
d->addGroup(product, groupName);
- d->internalProject->lastStartResolveTime = FileTime::currentTime();
d->internalProject->store(d->logger);
return {};
- } catch (ErrorInfo errorInfo) {
+ } catch (const ErrorInfo &exception) {
+ auto errorInfo = exception;
errorInfo.prepend(Tr::tr("Failure adding group '%1' to product '%2'.")
.arg(groupName, product.name()));
return errorInfo;
@@ -1310,10 +1100,10 @@ ErrorInfo Project::addFiles(const ProductData &product, const GroupData &group,
QBS_CHECK(isValid());
d->prepareChangeToProject();
d->addFiles(product, group, filePaths);
- d->internalProject->lastStartResolveTime = FileTime::currentTime();
d->internalProject->store(d->logger);
return {};
- } catch (ErrorInfo errorInfo) {
+ } catch (const ErrorInfo &exception) {
+ auto errorInfo = exception;
errorInfo.prepend(Tr::tr("Failure adding files to product."));
return errorInfo;
}
@@ -1336,10 +1126,10 @@ ErrorInfo Project::removeFiles(const ProductData &product, const GroupData &grou
QBS_CHECK(isValid());
d->prepareChangeToProject();
d->removeFiles(product, group, filePaths);
- d->internalProject->lastStartResolveTime = FileTime::currentTime();
d->internalProject->store(d->logger);
return {};
- } catch (ErrorInfo errorInfo) {
+ } catch (const ErrorInfo &exception) {
+ auto errorInfo = exception;
errorInfo.prepend(Tr::tr("Failure removing files from product '%1'.").arg(product.name()));
return errorInfo;
}
@@ -1357,10 +1147,10 @@ ErrorInfo Project::removeGroup(const ProductData &product, const GroupData &grou
QBS_CHECK(isValid());
d->prepareChangeToProject();
d->removeGroup(product, group);
- d->internalProject->lastStartResolveTime = FileTime::currentTime();
d->internalProject->store(d->logger);
return {};
- } catch (ErrorInfo errorInfo) {
+ } catch (const ErrorInfo &exception) {
+ auto errorInfo = exception;
errorInfo.prepend(Tr::tr("Failure removing group '%1' from product '%2'.")
.arg(group.name(), product.name()));
return errorInfo;
diff --git a/src/lib/corelib/api/project_p.h b/src/lib/corelib/api/project_p.h
index 58f61a5bc..60c8311f3 100644
--- a/src/lib/corelib/api/project_p.h
+++ b/src/lib/corelib/api/project_p.h
@@ -62,22 +62,22 @@ namespace Internal {
class ProjectPrivate : public QSharedData
{
public:
- ProjectPrivate(const TopLevelProjectPtr &internalProject, const Logger &logger)
- : internalProject(internalProject), logger(logger)
+ ProjectPrivate(TopLevelProjectPtr internalProject, Logger logger)
+ : internalProject(std::move(internalProject)), logger(std::move(logger))
{
}
ProjectData projectData();
- BuildJob *buildProducts(const QList<ResolvedProductPtr> &products, const BuildOptions &options,
+ BuildJob *buildProducts(const QVector<ResolvedProductPtr> &products, const BuildOptions &options,
bool needsDepencencyResolving,
QObject *jobOwner);
- CleanJob *cleanProducts(const QList<ResolvedProductPtr> &products, const CleanOptions &options,
+ CleanJob *cleanProducts(const QVector<ResolvedProductPtr> &products, const CleanOptions &options,
QObject *jobOwner);
- InstallJob *installProducts(const QList<ResolvedProductPtr> &products,
+ InstallJob *installProducts(const QVector<ResolvedProductPtr> &products,
const InstallOptions &options, bool needsDepencencyResolving,
QObject *jobOwner);
- QList<ResolvedProductPtr> internalProducts(const QList<ProductData> &products) const;
- QList<ResolvedProductPtr> allEnabledInternalProducts(bool includingNonDefault) const;
+ QVector<ResolvedProductPtr> internalProducts(const QList<ProductData> &products) const;
+ QVector<ResolvedProductPtr> allEnabledInternalProducts(bool includingNonDefault) const;
ResolvedProductPtr internalProduct(const ProductData &product) const;
ProductData findProductData(const ProductData &product) const;
QList<ProductData> findProductsByName(const QString &name) const;
@@ -92,7 +92,7 @@ public:
void setupInstallData(ArtifactData &artifact, const ResolvedProductConstPtr &product);
struct GroupUpdateContext {
- QList<ResolvedProductPtr> resolvedProducts;
+ QVector<ResolvedProductPtr> resolvedProducts;
QList<GroupPtr> resolvedGroups;
QList<ProductData> products;
QList<GroupData> groups;
@@ -114,12 +114,7 @@ public:
void removeFiles(const ProductData &product, const GroupData &group,
const QStringList &filePaths);
void removeGroup(const ProductData &product, const GroupData &group);
- void removeFilesFromBuildGraph(const ResolvedProductConstPtr &product,
- const std::vector<SourceArtifactPtr> &files);
- void updateInternalCodeLocations(const ResolvedProjectPtr &project,
- const CodeLocation &changeLocation, int lineOffset);
- void updateExternalCodeLocations(const ProjectData &project,
- const CodeLocation &changeLocation, int lineOffset);
+
void prepareChangeToProject();
RuleCommandList ruleCommandListForTransformer(const Transformer *transformer);
diff --git a/src/lib/corelib/api/projectfileupdater.cpp b/src/lib/corelib/api/projectfileupdater.cpp
index 04f8e630f..0bc5bc7c4 100644
--- a/src/lib/corelib/api/projectfileupdater.cpp
+++ b/src/lib/corelib/api/projectfileupdater.cpp
@@ -115,7 +115,7 @@ private:
};
-ProjectFileUpdater::ProjectFileUpdater(const QString &projectFile) : m_projectFile(projectFile)
+ProjectFileUpdater::ProjectFileUpdater(QString projectFile) : m_projectFile(std::move(projectFile))
{
}
@@ -201,11 +201,10 @@ void ProjectFileUpdater::apply()
}
-ProjectFileGroupInserter::ProjectFileGroupInserter(const ProductData &product,
- const QString &groupName)
+ProjectFileGroupInserter::ProjectFileGroupInserter(ProductData product, QString groupName)
: ProjectFileUpdater(product.location().filePath())
- , m_product(product)
- , m_groupName(groupName)
+ , m_product(std::move(product))
+ , m_groupName(std::move(groupName))
{
}
@@ -222,7 +221,7 @@ void ProjectFileGroupInserter::doApply(QString &fileContent, UiProgram *ast)
Rewriter rewriter(fileContent, &changeSet, QStringList());
QString groupItemString;
const int productItemIndentation
- = itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1;
+ = int(itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1);
const int groupItemIndentation = productItemIndentation + 4;
const QString groupItemIndentationString = QString(groupItemIndentation, QLatin1Char(' '));
groupItemString += groupItemIndentationString + QLatin1String("Group {\n");
@@ -252,7 +251,7 @@ static QString getNodeRepresentation(const QString &fileContent, const QbsQmlJS:
{
const quint32 start = node->firstSourceLocation().offset;
const quint32 end = node->lastSourceLocation().end();
- return fileContent.mid(start, end - start);
+ return fileContent.mid(start, int(end - start));
}
static const ChangeSet::EditOp &getEditOp(const ChangeSet &changeSet)
@@ -273,12 +272,12 @@ static int getBindingLine(const ChangeSet &changeSet, const QString &fileContent
}
-ProjectFileFilesAdder::ProjectFileFilesAdder(const ProductData &product, const GroupData &group,
- const QStringList &files)
+ProjectFileFilesAdder::ProjectFileFilesAdder(ProductData product, GroupData group,
+ QStringList files)
: ProjectFileUpdater(product.location().filePath())
- , m_product(product)
- , m_group(group)
- , m_files(files)
+ , m_product(std::move(product))
+ , m_group(std::move(group))
+ , m_files(std::move(files))
{
}
@@ -319,7 +318,7 @@ void ProjectFileFilesAdder::doApply(QString &fileContent, UiProgram *ast)
}
const int itemIndentation
- = itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1;
+ = int(itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1);
const int bindingIndentation = itemIndentation + 4;
const int arrayElemIndentation = bindingIndentation + 4;
@@ -405,12 +404,12 @@ void ProjectFileFilesAdder::doApply(QString &fileContent, UiProgram *ast)
changeSet.apply(&fileContent);
}
-ProjectFileFilesRemover::ProjectFileFilesRemover(const ProductData &product, const GroupData &group,
- const QStringList &files)
+ProjectFileFilesRemover::ProjectFileFilesRemover(ProductData product, GroupData group,
+ QStringList files)
: ProjectFileUpdater(product.location().filePath())
- , m_product(product)
- , m_group(group)
- , m_files(files)
+ , m_product(std::move(product))
+ , m_group(std::move(group))
+ , m_files(std::move(files))
{
}
@@ -444,7 +443,7 @@ void ProjectFileFilesRemover::doApply(QString &fileContent, UiProgram *ast)
Rewriter rewriter(fileContent, &changeSet, QStringList());
const int itemIndentation
- = itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1;
+ = int(itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1);
const int bindingIndentation = itemIndentation + 4;
const int arrayElemIndentation = bindingIndentation + 4;
@@ -512,10 +511,10 @@ void ProjectFileFilesRemover::doApply(QString &fileContent, UiProgram *ast)
}
-ProjectFileGroupRemover::ProjectFileGroupRemover(const ProductData &product, const GroupData &group)
+ProjectFileGroupRemover::ProjectFileGroupRemover(ProductData product, GroupData group)
: ProjectFileUpdater(product.location().filePath())
- , m_product(product)
- , m_group(group)
+ , m_product(std::move(product))
+ , m_group(std::move(group))
{
}
diff --git a/src/lib/corelib/api/projectfileupdater.h b/src/lib/corelib/api/projectfileupdater.h
index c0d46c747..3459d788e 100644
--- a/src/lib/corelib/api/projectfileupdater.h
+++ b/src/lib/corelib/api/projectfileupdater.h
@@ -61,7 +61,7 @@ public:
int lineOffset() const { return m_lineOffset; }
protected:
- ProjectFileUpdater(const QString &projectFile);
+ ProjectFileUpdater(QString projectFile);
QString projectFile() const { return m_projectFile; }
@@ -92,7 +92,7 @@ private:
class ProjectFileGroupInserter : public ProjectFileUpdater
{
public:
- ProjectFileGroupInserter(const ProductData &product, const QString &groupName);
+ ProjectFileGroupInserter(ProductData product, QString groupName);
private:
void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override;
@@ -105,8 +105,7 @@ private:
class ProjectFileFilesAdder : public ProjectFileUpdater
{
public:
- ProjectFileFilesAdder(const ProductData &product, const GroupData &group,
- const QStringList &files);
+ ProjectFileFilesAdder(ProductData product, GroupData group, QStringList files);
private:
void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override;
@@ -119,8 +118,8 @@ private:
class ProjectFileFilesRemover : public ProjectFileUpdater
{
public:
- ProjectFileFilesRemover(const ProductData &product, const GroupData &group,
- const QStringList &files);
+ ProjectFileFilesRemover(ProductData product, GroupData group,
+ QStringList files);
private:
void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override;
@@ -133,7 +132,7 @@ private:
class ProjectFileGroupRemover : public ProjectFileUpdater
{
public:
- ProjectFileGroupRemover(const ProductData &product, const GroupData &group);
+ ProjectFileGroupRemover(ProductData product, GroupData group);
private:
void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override;
diff --git a/src/lib/corelib/api/qmljsrewriter.cpp b/src/lib/corelib/api/qmljsrewriter.cpp
index 16817d682..5551e5650 100644
--- a/src/lib/corelib/api/qmljsrewriter.cpp
+++ b/src/lib/corelib/api/qmljsrewriter.cpp
@@ -63,12 +63,12 @@ static QString toString(UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Cha
}
-Rewriter::Rewriter(const QString &originalText,
+Rewriter::Rewriter(QString originalText,
ChangeSet *changeSet,
- const QStringList &propertyOrder)
- : m_originalText(originalText)
+ QStringList propertyOrder)
+ : m_originalText(std::move(originalText))
, m_changeSet(changeSet)
- , m_propertyOrder(propertyOrder)
+ , m_propertyOrder(std::move(propertyOrder))
{
Q_ASSERT(changeSet);
}
@@ -260,7 +260,7 @@ UiObjectMemberList *Rewriter::searchMemberToInsertAfter(UiObjectMemberList *memb
idx = propertyOrder.size() - 1;
for (; idx > 0; --idx) {
- const QString prop = propertyOrder.at(idx - 1);
+ const QString &prop = propertyOrder.at(idx - 1);
UiObjectMemberList *candidate = orderedMembers.value(prop, 0);
if (candidate != nullptr)
return candidate;
@@ -649,7 +649,7 @@ Rewriter::Range Rewriter::addObject(UiObjectInitializer *ast, const QString &con
textToInsert += content;
m_changeSet->insert(insertionPoint, QLatin1String("\n") + textToInsert);
- return Range(insertionPoint, insertionPoint);
+ return {insertionPoint, insertionPoint};
}
Rewriter::Range Rewriter::addObject(UiArrayBinding *ast, const QString &content)
@@ -672,7 +672,7 @@ Rewriter::Range Rewriter::addObject(UiArrayBinding *ast, const QString &content,
m_changeSet->insert(insertionPoint, textToInsert);
- return Range(insertionPoint, insertionPoint);
+ return {insertionPoint, insertionPoint};
}
void Rewriter::removeObjectMember(UiObjectMember *member, UiObjectMember *parent)
diff --git a/src/lib/corelib/api/qmljsrewriter.h b/src/lib/corelib/api/qmljsrewriter.h
index 797b05459..3788035f2 100644
--- a/src/lib/corelib/api/qmljsrewriter.h
+++ b/src/lib/corelib/api/qmljsrewriter.h
@@ -60,9 +60,9 @@ public:
using Range = ChangeSet::Range;
public:
- Rewriter(const QString &originalText,
+ Rewriter(QString originalText,
ChangeSet *changeSet,
- const QStringList &propertyOrder);
+ QStringList propertyOrder);
Range addBinding(AST::UiObjectInitializer *ast,
const QString &propertyName,
diff --git a/src/lib/corelib/api/rulecommand.cpp b/src/lib/corelib/api/rulecommand.cpp
index bc12140f3..e01cde7cc 100644
--- a/src/lib/corelib/api/rulecommand.cpp
+++ b/src/lib/corelib/api/rulecommand.cpp
@@ -65,17 +65,11 @@ RuleCommand::RuleCommand() : d(new Internal::RuleCommandPrivate)
{
}
-RuleCommand::RuleCommand(const RuleCommand &other) : d(other.d) {}
+RuleCommand::RuleCommand(const RuleCommand &other) = default;
-RuleCommand::~RuleCommand()
-{
-}
+RuleCommand::~RuleCommand() = default;
-RuleCommand& RuleCommand::operator=(const RuleCommand &other)
-{
- d = other.d;
- return *this;
-}
+RuleCommand& RuleCommand::operator=(const RuleCommand &other) = default;
/*!
* Returns the type of this object. If the value is \c InvalidType, the object is invalid.
diff --git a/src/lib/corelib/api/runenvironment.cpp b/src/lib/corelib/api/runenvironment.cpp
index df5b4337d..94a74dac2 100644
--- a/src/lib/corelib/api/runenvironment.cpp
+++ b/src/lib/corelib/api/runenvironment.cpp
@@ -62,8 +62,8 @@
#include <QtCore/qtemporaryfile.h>
#include <QtCore/qvariant.h>
+#include <cstdlib>
#include <regex>
-#include <stdlib.h>
namespace qbs {
using namespace Internal;
diff --git a/src/lib/corelib/api/runenvironment.h b/src/lib/corelib/api/runenvironment.h
index 69603bf76..c5123ca9c 100644
--- a/src/lib/corelib/api/runenvironment.h
+++ b/src/lib/corelib/api/runenvironment.h
@@ -52,6 +52,8 @@ class QString;
class QStringList;
QT_END_NAMESPACE
+class TestApi;
+
namespace qbs {
class ErrorInfo;
class InstallOptions;
@@ -66,7 +68,7 @@ class QBS_EXPORT RunEnvironment
{
friend class CommandLineFrontend;
friend class Project;
- friend class TestApi;
+ friend class ::TestApi;
public:
~RunEnvironment();
diff --git a/src/lib/corelib/api/transformerdata.cpp b/src/lib/corelib/api/transformerdata.cpp
index b4ee61d0c..9724e641b 100644
--- a/src/lib/corelib/api/transformerdata.cpp
+++ b/src/lib/corelib/api/transformerdata.cpp
@@ -44,14 +44,10 @@
namespace qbs {
TransformerData::TransformerData() : d(new Internal::TransformerDataPrivate) { }
-TransformerData::TransformerData(const TransformerData &other) : d(other.d) {}
-TransformerData::~TransformerData() { }
+TransformerData::TransformerData(const TransformerData &other) = default;
+TransformerData::~TransformerData() = default;
-TransformerData& TransformerData::operator=(const TransformerData &other)
-{
- d = other.d;
- return *this;
-}
+TransformerData& TransformerData::operator=(const TransformerData &other) = default;
QList<ArtifactData> TransformerData::inputs() const { return d->inputs; }
QList<ArtifactData> TransformerData::outputs() const { return d->outputs; }
diff --git a/src/lib/corelib/buildgraph/artifactcleaner.cpp b/src/lib/corelib/buildgraph/artifactcleaner.cpp
index 000dfda02..03b327232 100644
--- a/src/lib/corelib/buildgraph/artifactcleaner.cpp
+++ b/src/lib/corelib/buildgraph/artifactcleaner.cpp
@@ -162,7 +162,7 @@ ArtifactCleaner::ArtifactCleaner(Logger logger, ProgressObserver *observer)
}
void ArtifactCleaner::cleanup(const TopLevelProjectPtr &project,
- const QList<ResolvedProductPtr> &products, const CleanOptions &options)
+ const QVector<ResolvedProductPtr> &products, const CleanOptions &options)
{
m_hasError = false;
diff --git a/src/lib/corelib/buildgraph/artifactcleaner.h b/src/lib/corelib/buildgraph/artifactcleaner.h
index 5112a75d6..8d0bef275 100644
--- a/src/lib/corelib/buildgraph/artifactcleaner.h
+++ b/src/lib/corelib/buildgraph/artifactcleaner.h
@@ -54,7 +54,7 @@ class ArtifactCleaner
{
public:
ArtifactCleaner(Logger logger, ProgressObserver *observer);
- void cleanup(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products,
+ void cleanup(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products,
const CleanOptions &options);
private:
diff --git a/src/lib/corelib/buildgraph/artifactvisitor.cpp b/src/lib/corelib/buildgraph/artifactvisitor.cpp
index c28f07424..22c987572 100644
--- a/src/lib/corelib/buildgraph/artifactvisitor.cpp
+++ b/src/lib/corelib/buildgraph/artifactvisitor.cpp
@@ -61,7 +61,7 @@ void ArtifactVisitor::visitProduct(const ResolvedProductConstPtr &product)
void ArtifactVisitor::visitProject(const ResolvedProjectConstPtr &project)
{
- for (const ResolvedProductConstPtr &product : project->allProducts())
+ for (const auto &product : project->allProducts())
visitProduct(product);
}
diff --git a/src/lib/corelib/buildgraph/buildgraph.cpp b/src/lib/corelib/buildgraph/buildgraph.cpp
index 3726c654d..0d5e8a1f0 100644
--- a/src/lib/corelib/buildgraph/buildgraph.cpp
+++ b/src/lib/corelib/buildgraph/buildgraph.cpp
@@ -278,7 +278,7 @@ private:
}
return result;
}
- for (const ResolvedModuleConstPtr &dependency : product->modules) {
+ for (const auto &dependency : product->modules) {
if (dependency->isProduct)
continue;
QScriptValue obj = engine->newObject(engine->modulePropertyScriptClass());
@@ -661,7 +661,7 @@ void provideFullFileTagsAndProperties(Artifact *artifact)
artifact->properties = artifact->product->moduleProperties;
FileTags allTags = artifact->pureFileTags.empty()
? artifact->product->fileTagsForFileName(artifact->fileName()) : artifact->pureFileTags;
- for (const ArtifactPropertiesConstPtr &props : artifact->product->artifactProperties) {
+ for (const auto &props : artifact->product->artifactProperties) {
if (allTags.intersects(props->fileTagsFilter())) {
artifact->properties = props->propertyMap();
allTags += props->extraFileTags();
@@ -733,7 +733,7 @@ static void doSanityChecksForProduct(const ResolvedProductConstPtr &product,
CycleDetector cycleDetector(logger);
cycleDetector.visitProduct(product);
const ProductBuildData * const buildData = product->buildData.get();
- for (const ResolvedModuleConstPtr &m : product->modules)
+ for (const auto &m : product->modules)
QBS_CHECK(m->product == product.get());
qCDebug(lcBuildGraph) << "enabled:" << product->enabled << "build data:" << buildData;
if (product->enabled)
@@ -836,7 +836,7 @@ static void doSanityChecks(const ResolvedProjectPtr &project,
for (const ResolvedProjectPtr &subProject : qAsConst(project->subProjects))
doSanityChecks(subProject, allProducts, productNames, logger);
- for (const ResolvedProductConstPtr &product : project->products) {
+ for (const auto &product : project->products) {
QBS_CHECK(product->project == project);
QBS_CHECK(product->topLevelProject() == project->topLevelProject());
doSanityChecksForProduct(product, allProducts, logger);
diff --git a/src/lib/corelib/buildgraph/buildgraphloader.cpp b/src/lib/corelib/buildgraph/buildgraphloader.cpp
index bf6c30dcd..58a34b616 100644
--- a/src/lib/corelib/buildgraph/buildgraphloader.cpp
+++ b/src/lib/corelib/buildgraph/buildgraphloader.cpp
@@ -71,6 +71,7 @@
#include <algorithm>
#include <functional>
+#include <memory>
#include <unordered_map>
namespace qbs {
@@ -273,7 +274,7 @@ static void updateProductAndRulePointers(const ResolvedProductPtr &newProduct)
const auto it = ruleMap.find(oldRule);
if (it != ruleMap.cend())
return it->second;
- for (const RuleConstPtr &r : qAsConst(newProduct->rules)) {
+ for (const auto &r : qAsConst(newProduct->rules)) {
if (*r == *oldRule) {
ruleMap.insert(std::make_pair(oldRule, r));
return r;
@@ -362,7 +363,7 @@ void BuildGraphLoader::trackProjectChanges()
ChildListHash childLists;
if (!changedProducts.empty()) {
oldBuildData = std::make_shared<ProjectBuildData>(restoredProject->buildData.get());
- for (const ResolvedProductConstPtr &product : qAsConst(allRestoredProducts)) {
+ for (const auto &product : qAsConst(allRestoredProducts)) {
if (!product->buildData)
continue;
@@ -451,7 +452,7 @@ void BuildGraphLoader::trackProjectChanges()
updateGeneratedArtifacts(product.get());
}
- for (const ResolvedProductConstPtr &changedProduct : qAsConst(changedProducts)) {
+ for (const auto &changedProduct : qAsConst(changedProducts)) {
rescueOldBuildData(changedProduct,
m_freshProductsByName.value(changedProduct->uniqueName()),
childLists, rescuableArtifactData.value(changedProduct->uniqueName()));
@@ -614,7 +615,7 @@ bool BuildGraphLoader::hasProductFileChanged(const std::vector<ResolvedProductPt
FileInfo::path(group->location.filePath()),
product->topLevelProject()->buildDirectory);
Set<QString> wcFiles;
- for (const SourceArtifactConstPtr &sourceArtifact : group->wildcards->files)
+ for (const auto &sourceArtifact : group->wildcards->files)
wcFiles += sourceArtifact->absoluteFilePath;
if (files == wcFiles)
continue;
@@ -741,9 +742,9 @@ static bool dependenciesAreEqual(const ResolvedProductConstPtr &p1,
return false;
Set<QString> names1;
Set<QString> names2;
- for (const ResolvedProductConstPtr &dep : qAsConst(p1->dependencies))
+ for (const auto &dep : qAsConst(p1->dependencies))
names1 << dep->uniqueName();
- for (const ResolvedProductConstPtr &dep : qAsConst(p2->dependencies))
+ for (const auto &dep : qAsConst(p2->dependencies))
names2 << dep->uniqueName();
return names1 == names2;
}
@@ -909,7 +910,7 @@ void BuildGraphLoader::rescueOldBuildData(const ResolvedProductConstPtr &restore
if (!restoredProduct->buildData)
return;
if (!newlyResolvedProduct->buildData)
- newlyResolvedProduct->buildData.reset(new ProductBuildData);
+ newlyResolvedProduct->buildData = std::make_unique<ProductBuildData>();
qCDebug(lcBuildGraph) << "rescue data of product" << restoredProduct->uniqueName();
QBS_CHECK(newlyResolvedProduct->buildData);
diff --git a/src/lib/corelib/buildgraph/buildgraphloader.h b/src/lib/corelib/buildgraph/buildgraphloader.h
index 9363b8358..c62ba7fa7 100644
--- a/src/lib/corelib/buildgraph/buildgraphloader.h
+++ b/src/lib/corelib/buildgraph/buildgraphloader.h
@@ -121,9 +121,9 @@ private:
bool checkConfigCompatibility();
struct ChildrenInfo {
- ChildrenInfo() {}
- ChildrenInfo(const ArtifactSet &c1, const ArtifactSet &c2)
- : children(c1), childrenAddedByScanner(c2) {}
+ ChildrenInfo() = default;
+ ChildrenInfo(ArtifactSet c1, ArtifactSet c2)
+ : children(std::move(c1)), childrenAddedByScanner(std::move(c2)) {}
ArtifactSet children;
ArtifactSet childrenAddedByScanner;
};
diff --git a/src/lib/corelib/buildgraph/depscanner.h b/src/lib/corelib/buildgraph/depscanner.h
index ffc0b83de..6b18004f9 100644
--- a/src/lib/corelib/buildgraph/depscanner.h
+++ b/src/lib/corelib/buildgraph/depscanner.h
@@ -61,7 +61,7 @@ class ScriptEngine;
class DependencyScanner
{
public:
- virtual ~DependencyScanner() {}
+ virtual ~DependencyScanner() = default;
QString id() const;
diff --git a/src/lib/corelib/buildgraph/environmentscriptrunner.cpp b/src/lib/corelib/buildgraph/environmentscriptrunner.cpp
index 7d82efb41..9dafbf296 100644
--- a/src/lib/corelib/buildgraph/environmentscriptrunner.cpp
+++ b/src/lib/corelib/buildgraph/environmentscriptrunner.cpp
@@ -129,12 +129,12 @@ void EnvironmentScriptRunner::setupEnvironment()
return;
QMap<QString, const ResolvedModule *> moduleMap;
- for (const ResolvedModuleConstPtr &module : m_product->modules)
+ for (const auto &module : m_product->modules)
moduleMap.insert(module->name, module.get());
QHash<const ResolvedModule*, QList<const ResolvedModule*> > moduleParents;
QHash<const ResolvedModule*, QList<const ResolvedModule*> > moduleChildren;
- for (const ResolvedModuleConstPtr &module : m_product->modules) {
+ for (const auto &module : m_product->modules) {
for (const QString &moduleName : qAsConst(module->moduleDependencies)) {
const ResolvedModule * const depmod = moduleMap.value(moduleName);
QBS_ASSERT(depmod, return);
@@ -144,7 +144,7 @@ void EnvironmentScriptRunner::setupEnvironment()
}
QList<const ResolvedModule *> rootModules;
- for (const ResolvedModuleConstPtr &module : m_product->modules) {
+ for (const auto &module : m_product->modules) {
if (moduleParents.value(module.get()).isEmpty()) {
QBS_ASSERT(module, return);
rootModules.push_back(module.get());
diff --git a/src/lib/corelib/buildgraph/executor.cpp b/src/lib/corelib/buildgraph/executor.cpp
index de81ada20..377222d21 100644
--- a/src/lib/corelib/buildgraph/executor.cpp
+++ b/src/lib/corelib/buildgraph/executor.cpp
@@ -102,12 +102,8 @@ Executor::Executor(Logger logger, QObject *parent)
Executor::~Executor()
{
- // jobs must be destroyed before deleting the shared scan result cache
- for (ExecutorJob *job : qAsConst(m_availableJobs))
- delete job;
- const auto processingJobs = m_processingJobs.keys();
- for (ExecutorJob *job : processingJobs)
- delete job;
+ // jobs must be destroyed before deleting the m_inputArtifactScanContext
+ m_allJobs.clear();
delete m_inputArtifactScanContext;
delete m_productInstaller;
}
@@ -153,7 +149,7 @@ void Executor::retrieveSourceFileTimestamp(Artifact *artifact) const
void Executor::build()
{
try {
- m_partialBuild = m_productsToBuild.size() != m_allProducts.size();
+ m_partialBuild = size_t(m_productsToBuild.size()) != m_allProducts.size();
doBuild();
} catch (const ErrorInfo &e) {
handleError(e);
@@ -170,7 +166,7 @@ void Executor::setProject(const TopLevelProjectPtr &project)
m_projectsByName.insert(std::make_pair(p->name, p.get()));
}
-void Executor::setProducts(const std::vector<ResolvedProductPtr> &productsToBuild)
+void Executor::setProducts(const QVector<ResolvedProductPtr> &productsToBuild)
{
m_productsToBuild = productsToBuild;
m_productsByName.clear();
@@ -266,8 +262,7 @@ void Executor::doBuild()
doSanityChecks();
QBS_CHECK(!m_project->buildData->evaluationContext);
- m_project->buildData->evaluationContext
- = RulesEvaluationContextPtr(new RulesEvaluationContext(m_logger));
+ m_project->buildData->evaluationContext = std::make_shared<RulesEvaluationContext>(m_logger);
m_evalContext = m_project->buildData->evaluationContext;
m_elapsedTimeRules = m_elapsedTimeScanners = m_elapsedTimeInstalling = 0;
@@ -700,7 +695,7 @@ bool Executor::transformerHasMatchingInputFiles(const TransformerConstPtr &trans
void Executor::setupJobLimits()
{
Settings settings(m_buildOptions.settingsDirectory());
- for (const ResolvedProductConstPtr &p : m_productsToBuild) {
+ for (const auto &p : qAsConst(m_productsToBuild)) {
const Preferences prefs(&settings, p->profile());
const JobLimits &jobLimitsFromSettings = prefs.jobLimits();
JobLimits effectiveJobLimits;
@@ -737,7 +732,7 @@ void Executor::setupProgressObserver()
if (!m_progressObserver)
return;
int totalEffort = 1; // For the effort after the last rule application;
- for (const ResolvedProductConstPtr &product : qAsConst(m_productsToBuild)) {
+ for (const auto &product : qAsConst(m_productsToBuild)) {
QBS_CHECK(product->buildData);
const auto filtered = filterByType<RuleNode>(product->buildData->allNodes());
totalEffort += std::distance(filtered.begin(), filtered.end());
@@ -749,7 +744,7 @@ void Executor::doSanityChecks()
{
QBS_CHECK(m_project);
QBS_CHECK(!m_productsToBuild.empty());
- for (const ResolvedProductConstPtr &product : qAsConst(m_productsToBuild)) {
+ for (const auto &product : qAsConst(m_productsToBuild)) {
QBS_CHECK(product->buildData);
QBS_CHECK(product->topLevelProject() == m_project.get());
}
@@ -768,10 +763,13 @@ void Executor::handleError(const ErrorInfo &error)
void Executor::addExecutorJobs()
{
- qCDebug(lcExec) << "preparing executor for" << m_buildOptions.maxJobCount()
- << "jobs in parallel";
- for (int i = 1; i <= m_buildOptions.maxJobCount(); i++) {
- const auto job = new ExecutorJob(m_logger, this);
+ const int count = m_buildOptions.maxJobCount();
+ qCDebug(lcExec) << "preparing executor for" << count << "jobs in parallel";
+ m_allJobs.reserve(count);
+ m_availableJobs.reserve(count);
+ for (int i = 1; i <= count; i++) {
+ m_allJobs.push_back(std::make_unique<ExecutorJob>(m_logger));
+ const auto job = m_allJobs.back().get();
job->setMainThreadScriptEngine(m_evalContext->engine());
job->setObjectName(QStringLiteral("J%1").arg(i));
job->setDryRun(m_buildOptions.dryRun());
@@ -1084,7 +1082,7 @@ void Executor::checkForUnbuiltProducts()
if (m_buildOptions.executeRulesOnly())
return;
std::vector<ResolvedProductPtr> unbuiltProducts;
- for (const ResolvedProductPtr &product : m_productsToBuild) {
+ for (const ResolvedProductPtr &product : qAsConst(m_productsToBuild)) {
bool productBuilt = true;
for (BuildGraphNode *rootNode : qAsConst(product->buildData->rootNodes())) {
if (rootNode->buildState != BuildGraphNode::Built) {
@@ -1206,7 +1204,7 @@ void Executor::prepareAllNodes()
node->buildState = BuildGraphNode::Untouched;
}
}
- for (const ResolvedProductPtr &product : m_productsToBuild) {
+ for (const ResolvedProductPtr &product : qAsConst(m_productsToBuild)) {
QBS_CHECK(product->buildData);
for (Artifact * const artifact : filterByType<Artifact>(product->buildData->allNodes()))
prepareArtifact(artifact);
@@ -1228,7 +1226,7 @@ void Executor::syncFileDependencies()
"removing from lookup table";
m_project->buildData->removeFromLookupTable(dep);
bool isReferencedByArtifact = false;
- for (const ResolvedProductConstPtr &product : m_allProducts) {
+ for (const auto &product : m_allProducts) {
if (!product->buildData)
continue;
const auto artifactList = filterByType<Artifact>(product->buildData->allNodes());
@@ -1310,7 +1308,7 @@ void Executor::prepareProducts()
{
ProductPrioritySetter prioritySetter(m_allProducts);
prioritySetter.apply();
- for (const ResolvedProductPtr &product : m_productsToBuild) {
+ for (const ResolvedProductPtr &product : qAsConst(m_productsToBuild)) {
EnvironmentScriptRunner(product.get(), m_evalContext.get(), m_project->environment)
.setupForBuild();
}
@@ -1319,7 +1317,7 @@ void Executor::prepareProducts()
void Executor::setupRootNodes()
{
m_roots.clear();
- for (const ResolvedProductPtr &product : m_productsToBuild)
+ for (const ResolvedProductPtr &product : qAsConst(m_productsToBuild))
m_roots += product->buildData->rootNodes();
}
diff --git a/src/lib/corelib/buildgraph/executor.h b/src/lib/corelib/buildgraph/executor.h
index 1fd591176..cc879e125 100644
--- a/src/lib/corelib/buildgraph/executor.h
+++ b/src/lib/corelib/buildgraph/executor.h
@@ -81,7 +81,7 @@ public:
~Executor() override;
void setProject(const TopLevelProjectPtr &project);
- void setProducts(const std::vector<ResolvedProductPtr> &productsToBuild);
+ void setProducts(const QVector<ResolvedProductPtr> &productsToBuild);
void setBuildOptions(const BuildOptions &buildOptions);
void setProgressObserver(ProgressObserver *observer) { m_progressObserver = observer; }
@@ -166,10 +166,11 @@ private:
BuildOptions m_buildOptions;
Logger m_logger;
ProgressObserver *m_progressObserver;
+ std::vector<std::unique_ptr<ExecutorJob>> m_allJobs;
QList<ExecutorJob*> m_availableJobs;
ExecutorState m_state;
TopLevelProjectPtr m_project;
- std::vector<ResolvedProductPtr> m_productsToBuild;
+ QVector<ResolvedProductPtr> m_productsToBuild;
std::vector<ResolvedProductPtr> m_allProducts;
std::unordered_map<QString, const ResolvedProduct *> m_productsByName;
std::unordered_map<QString, const ResolvedProject *> m_projectsByName;
diff --git a/src/lib/corelib/buildgraph/executorjob.cpp b/src/lib/corelib/buildgraph/executorjob.cpp
index 79f17377d..bc96cbb6e 100644
--- a/src/lib/corelib/buildgraph/executorjob.cpp
+++ b/src/lib/corelib/buildgraph/executorjob.cpp
@@ -71,9 +71,7 @@ ExecutorJob::ExecutorJob(const Logger &logger, QObject *parent)
reset();
}
-ExecutorJob::~ExecutorJob()
-{
-}
+ExecutorJob::~ExecutorJob() = default;
void ExecutorJob::setMainThreadScriptEngine(ScriptEngine *engine)
{
diff --git a/src/lib/corelib/buildgraph/executorjob.h b/src/lib/corelib/buildgraph/executorjob.h
index bc8954072..1f8f0cd73 100644
--- a/src/lib/corelib/buildgraph/executorjob.h
+++ b/src/lib/corelib/buildgraph/executorjob.h
@@ -65,7 +65,7 @@ class ExecutorJob : public QObject
{
Q_OBJECT
public:
- ExecutorJob(const Logger &logger, QObject *parent);
+ explicit ExecutorJob(const Logger &logger, QObject *parent = nullptr);
~ExecutorJob() override;
void setMainThreadScriptEngine(ScriptEngine *engine);
diff --git a/src/lib/corelib/buildgraph/filedependency.cpp b/src/lib/corelib/buildgraph/filedependency.cpp
index 9420fa96b..cbee758c7 100644
--- a/src/lib/corelib/buildgraph/filedependency.cpp
+++ b/src/lib/corelib/buildgraph/filedependency.cpp
@@ -44,13 +44,9 @@
namespace qbs {
namespace Internal {
-FileResourceBase::FileResourceBase()
-{
-}
+FileResourceBase::FileResourceBase() = default;
-FileResourceBase::~FileResourceBase()
-{
-}
+FileResourceBase::~FileResourceBase() = default;
void FileResourceBase::setTimestamp(const FileTime &t)
@@ -86,13 +82,9 @@ void FileResourceBase::store(PersistentPool &pool)
}
-FileDependency::FileDependency()
-{
-}
+FileDependency::FileDependency() = default;
-FileDependency::~FileDependency()
-{
-}
+FileDependency::~FileDependency() = default;
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/buildgraph/inputartifactscanner.cpp b/src/lib/corelib/buildgraph/inputartifactscanner.cpp
index 81cbe2178..1d00e29e1 100644
--- a/src/lib/corelib/buildgraph/inputartifactscanner.cpp
+++ b/src/lib/corelib/buildgraph/inputartifactscanner.cpp
@@ -77,6 +77,7 @@ static void resolveDepencency(const RawScannedDependency &dependency,
FileDependency *fileDependencyArtifact = nullptr;
Artifact *dependencyInProduct = nullptr;
Artifact *dependencyInOtherProduct = nullptr;
+ bool productOfDependencyIsDependency = false;
const auto files = project->topLevelProject()
->buildData->lookupFiles(absDirPath, dependency.fileName());
for (FileResourceBase *lookupResult : files) {
@@ -86,10 +87,13 @@ static void resolveDepencency(const RawScannedDependency &dependency,
break;
case FileResourceBase::FileTypeArtifact: {
auto const foundArtifact = static_cast<Artifact *>(lookupResult);
- if (foundArtifact->product == product)
+ if (foundArtifact->product == product) {
dependencyInProduct = foundArtifact;
- else
+ } else if (!productOfDependencyIsDependency) {
dependencyInOtherProduct = foundArtifact;
+ productOfDependencyIsDependency
+ = contains(product->dependencies, dependencyInOtherProduct->product.lock());
+ }
break;
}
}
@@ -102,6 +106,14 @@ static void resolveDepencency(const RawScannedDependency &dependency,
|| (result->file = dependencyInOtherProduct)
|| (result->file = fileDependencyArtifact)) {
result->filePath = result->file->filePath();
+
+ if (result->file == dependencyInOtherProduct && !productOfDependencyIsDependency) {
+ qCDebug(lcDepScan) << "product" << dependencyInOtherProduct->product->fullDisplayName()
+ << "of scanned dependency" << result->filePath
+ << "is not a dependency of product" << product->fullDisplayName()
+ << ". The file dependency might get lost during change tracking.";
+ }
+
return;
}
@@ -349,6 +361,8 @@ void InputArtifactScanner::handleDependency(ResolvedDependency &dependency)
if (m_artifact == dependency.file)
return;
+ if (artifactDependency && artifactDependency->transformer == m_artifact->transformer)
+ return;
if (fileDependency) {
m_artifact->fileDependencies << fileDependency;
@@ -372,16 +386,14 @@ void InputArtifactScanner::scanWithScannerPlugin(DependencyScanner *scanner,
const QStringList &dependencies = scanner->collectDependencies(
inputArtifact, fileToBeScanned, m_fileTagsForScanner.constData());
for (const QString &s : dependencies)
- scanResult->deps.push_back(RawScannedDependency(s));
+ scanResult->deps.emplace_back(s);
}
InputArtifactScannerContext::DependencyScannerCacheItem::DependencyScannerCacheItem() : valid(false)
{
}
-InputArtifactScannerContext::DependencyScannerCacheItem::~DependencyScannerCacheItem()
-{
-}
+InputArtifactScannerContext::DependencyScannerCacheItem::~DependencyScannerCacheItem() = default;
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/buildgraph/nodetreedumper.cpp b/src/lib/corelib/buildgraph/nodetreedumper.cpp
index 89975baf2..8475a46cf 100644
--- a/src/lib/corelib/buildgraph/nodetreedumper.cpp
+++ b/src/lib/corelib/buildgraph/nodetreedumper.cpp
@@ -51,13 +51,13 @@
namespace qbs {
namespace Internal {
-static unsigned int indentWidth() { return 4; }
+static int indentWidth() { return 4; }
NodeTreeDumper::NodeTreeDumper(QIODevice &outDevice) : m_outDevice(outDevice)
{
}
-void NodeTreeDumper::start(const QList<ResolvedProductPtr> &products)
+void NodeTreeDumper::start(const QVector<ResolvedProductPtr> &products)
{
m_indentation = 0;
for (const ResolvedProductPtr &p : products) {
diff --git a/src/lib/corelib/buildgraph/nodetreedumper.h b/src/lib/corelib/buildgraph/nodetreedumper.h
index 4175ce727..38ccd6dae 100644
--- a/src/lib/corelib/buildgraph/nodetreedumper.h
+++ b/src/lib/corelib/buildgraph/nodetreedumper.h
@@ -57,7 +57,7 @@ class NodeTreeDumper : public BuildGraphVisitor
public:
NodeTreeDumper(QIODevice &outDevice);
- void start(const QList<ResolvedProductPtr> &products);
+ void start(const QVector<ResolvedProductPtr> &products);
private:
bool visit(Artifact *artifact) override;
@@ -74,7 +74,7 @@ private:
QIODevice &m_outDevice;
ResolvedProductPtr m_currentProduct;
NodeSet m_visited;
- unsigned int m_indentation = 0;
+ int m_indentation = 0;
};
} // namespace Internal
diff --git a/src/lib/corelib/buildgraph/processcommandexecutor.cpp b/src/lib/corelib/buildgraph/processcommandexecutor.cpp
index 79edda320..7cde8553c 100644
--- a/src/lib/corelib/buildgraph/processcommandexecutor.cpp
+++ b/src/lib/corelib/buildgraph/processcommandexecutor.cpp
@@ -166,6 +166,7 @@ bool ProcessCommandExecutor::doStart()
.arg(responseFile.fileName())));
return false;
}
+ const auto separator = cmd->responseFileSeparator().toUtf8();
for (int i = cmd->responseFileArgumentIndex(); i < cmd->arguments().size(); ++i) {
const QString arg = cmd->arguments().at(i);
if (arg.startsWith(cmd->responseFileUsagePrefix())) {
@@ -179,7 +180,7 @@ bool ProcessCommandExecutor::doStart()
} else {
responseFile.write(qbs::Internal::shellQuote(arg).toLocal8Bit());
}
- responseFile.write("\n");
+ responseFile.write(separator);
}
responseFile.close();
m_responseFileName = responseFile.fileName();
diff --git a/src/lib/corelib/buildgraph/productinstaller.cpp b/src/lib/corelib/buildgraph/productinstaller.cpp
index d4acc9ace..80a76d7f5 100644
--- a/src/lib/corelib/buildgraph/productinstaller.cpp
+++ b/src/lib/corelib/buildgraph/productinstaller.cpp
@@ -60,7 +60,7 @@ namespace qbs {
namespace Internal {
ProductInstaller::ProductInstaller(TopLevelProjectPtr project,
- std::vector<ResolvedProductPtr> products, InstallOptions options,
+ QVector<ResolvedProductPtr> products, InstallOptions options,
ProgressObserver *observer, Logger logger)
: m_project(std::move(project)),
m_products(std::move(products)),
@@ -96,7 +96,7 @@ void ProductInstaller::install()
removeInstallRoot();
QList<const Artifact *> artifactsToInstall;
- for (const ResolvedProductConstPtr &product : qAsConst(m_products)) {
+ for (const auto &product : qAsConst(m_products)) {
QBS_CHECK(product->buildData);
for (const Artifact *artifact : filterByType<Artifact>(product->buildData->allNodes())) {
if (artifact->properties->qbsPropertyValue(StringConstants::installProperty()).toBool())
@@ -250,5 +250,5 @@ void ProductInstaller::handleError(const QString &message)
m_logger.qbsWarning() << message;
}
-} // namespace Intern
+} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/buildgraph/productinstaller.h b/src/lib/corelib/buildgraph/productinstaller.h
index 09828cfe9..c07e0b7cf 100644
--- a/src/lib/corelib/buildgraph/productinstaller.h
+++ b/src/lib/corelib/buildgraph/productinstaller.h
@@ -56,7 +56,7 @@ class ProductInstaller
{
public:
ProductInstaller(TopLevelProjectPtr project,
- std::vector<ResolvedProductPtr> products,
+ QVector<ResolvedProductPtr> products,
InstallOptions options, ProgressObserver *observer, Logger logger);
void install();
@@ -72,7 +72,7 @@ private:
void handleError(const QString &message);
const TopLevelProjectConstPtr m_project;
- const std::vector<ResolvedProductPtr> m_products;
+ const QVector<ResolvedProductPtr> m_products;
InstallOptions m_options;
ProgressObserver * const m_observer;
Logger m_logger;
diff --git a/src/lib/corelib/buildgraph/projectbuilddata.cpp b/src/lib/corelib/buildgraph/projectbuilddata.cpp
index 31012e23e..0ac6b1537 100644
--- a/src/lib/corelib/buildgraph/projectbuilddata.cpp
+++ b/src/lib/corelib/buildgraph/projectbuilddata.cpp
@@ -60,6 +60,8 @@
#include <tools/qttools.h>
#include <tools/stlutils.h>
+#include <memory>
+
namespace qbs {
namespace Internal {
@@ -276,7 +278,7 @@ void BuildDataResolver::resolveBuildData(const TopLevelProjectPtr &resolvedProje
{
QBS_CHECK(!resolvedProject->buildData);
m_project = resolvedProject;
- resolvedProject->buildData.reset(new ProjectBuildData);
+ resolvedProject->buildData = std::make_unique<ProjectBuildData>();
resolvedProject->buildData->evaluationContext = evalContext;
const std::vector<ResolvedProductPtr> &allProducts = resolvedProject->allProducts();
evalContext->initializeObserver(Tr::tr("Setting up build graph for configuration %1")
@@ -390,7 +392,7 @@ void BuildDataResolver::resolveProductBuildData(const ResolvedProductPtr &produc
evalContext()->checkForCancelation();
- product->buildData.reset(new ProductBuildData);
+ product->buildData = std::make_unique<ProductBuildData>();
ArtifactSetByFileTag artifactsPerFileTag;
for (const auto &dependency : qAsConst(product->dependencies)) {
@@ -411,7 +413,7 @@ void BuildDataResolver::resolveProductBuildData(const ResolvedProductPtr &produc
artifactsPerFileTag["qbs"].insert(qbsFileArtifact);
// read sources
- for (const SourceArtifactConstPtr &sourceArtifact : product->allEnabledFiles()) {
+ for (const auto &sourceArtifact : product->allEnabledFiles()) {
QString filePath = sourceArtifact->absoluteFilePath;
if (lookupArtifact(product, filePath))
continue; // ignore duplicate artifacts
@@ -443,7 +445,7 @@ void BuildDataResolver::connectRulesToDependencies(const ResolvedProductPtr &pro
std::vector<RuleNode *> ruleNodes;
for (RuleNode *ruleNode : filterByType<RuleNode>(product->buildData->allNodes()))
ruleNodes.push_back(ruleNode);
- for (const ResolvedProductConstPtr &dep : dependencies) {
+ for (const auto &dep : dependencies) {
if (!dep->buildData)
continue;
for (RuleNode *depRuleNode : filterByType<RuleNode>(dep->buildData->allNodes())) {
diff --git a/src/lib/corelib/buildgraph/qtmocscanner.cpp b/src/lib/corelib/buildgraph/qtmocscanner.cpp
index c834c60e6..4e054a636 100644
--- a/src/lib/corelib/buildgraph/qtmocscanner.cpp
+++ b/src/lib/corelib/buildgraph/qtmocscanner.cpp
@@ -167,7 +167,7 @@ static RawScanResult runScanner(ScannerPlugin *scanner, const Artifact *artifact
if (FileInfo::exists(localFilePath))
includedFilePath = localFilePath;
}
- scanData.rawScanResult.deps.push_back(RawScannedDependency(includedFilePath));
+ scanData.rawScanResult.deps.emplace_back(includedFilePath);
}
scanner->close(opaq);
diff --git a/src/lib/corelib/buildgraph/requesteddependencies.cpp b/src/lib/corelib/buildgraph/requesteddependencies.cpp
index f993b2518..b95c8db94 100644
--- a/src/lib/corelib/buildgraph/requesteddependencies.cpp
+++ b/src/lib/corelib/buildgraph/requesteddependencies.cpp
@@ -48,9 +48,9 @@ namespace Internal {
static Set<QString> depNamesForProduct(const ResolvedProduct *p)
{
Set<QString> names;
- for (const ResolvedProductConstPtr &dep : p->dependencies)
+ for (const auto &dep : p->dependencies)
names.insert(dep->uniqueName());
- for (const ResolvedModuleConstPtr &m : p->modules) {
+ for (const auto &m : p->modules) {
if (!m->isProduct)
names.insert(m->name);
}
@@ -73,7 +73,7 @@ bool RequestedDependencies::isUpToDate(const TopLevelProject *project) const
{
if (m_depsPerProduct.empty())
return true;
- for (const ResolvedProductConstPtr &product : project->allProducts()) {
+ for (const auto &product : project->allProducts()) {
const auto it = m_depsPerProduct.find(product->uniqueName());
if (it == m_depsPerProduct.cend())
continue;
diff --git a/src/lib/corelib/buildgraph/rescuableartifactdata.h b/src/lib/corelib/buildgraph/rescuableartifactdata.h
index 3e4d6e25f..6dd10f76c 100644
--- a/src/lib/corelib/buildgraph/rescuableartifactdata.h
+++ b/src/lib/corelib/buildgraph/rescuableartifactdata.h
@@ -84,9 +84,12 @@ public:
struct ChildData
{
- ChildData(const QString &n = QString(), const QString &m = QString(),
- const QString &c = QString(), bool byScanner = false)
- : productName(n), productMultiplexId(m), childFilePath(c), addedByScanner(byScanner)
+ ChildData(QString n = QString(), QString m = QString(),
+ QString c = QString(), bool byScanner = false)
+ : productName(std::move(n))
+ , productMultiplexId(std::move(m))
+ , childFilePath(std::move(c))
+ , addedByScanner(byScanner)
{}
template<PersistentPool::OpType opType> void completeSerializationOp(PersistentPool &pool)
diff --git a/src/lib/corelib/buildgraph/rulecommands.cpp b/src/lib/corelib/buildgraph/rulecommands.cpp
index 31ff6be4b..8fa3255f1 100644
--- a/src/lib/corelib/buildgraph/rulecommands.cpp
+++ b/src/lib/corelib/buildgraph/rulecommands.cpp
@@ -70,6 +70,7 @@ static QString responseFileUsagePrefixProperty()
{
return QStringLiteral("responseFileUsagePrefix");
}
+static QString responseFileSeparatorProperty() { return QStringLiteral("responseFileSeparator"); }
static QString silentProperty() { return QStringLiteral("silent"); }
static QString stderrFilePathProperty() { return QStringLiteral("stderrFilePath"); }
static QString stderrFilterFunctionProperty() { return QStringLiteral("stderrFilterFunction"); }
@@ -78,7 +79,7 @@ static QString stdoutFilterFunctionProperty() { return QStringLiteral("stdoutFil
static QString timeoutProperty() { return QStringLiteral("timeout"); }
static QString workingDirProperty() { return QStringLiteral("workingDirectory"); }
-static QString invokedSourceCode(const QScriptValue codeOrFunction)
+static QString invokedSourceCode(const QScriptValue &codeOrFunction)
{
const QString &code = codeOrFunction.toString();
return codeOrFunction.isFunction() ? QStringLiteral("(") + code + QStringLiteral(")()") : code;
@@ -94,9 +95,7 @@ AbstractCommand::AbstractCommand()
{
}
-AbstractCommand::~AbstractCommand()
-{
-}
+AbstractCommand::~AbstractCommand() = default;
bool AbstractCommand::equals(const AbstractCommand *other) const
{
@@ -218,6 +217,8 @@ static QScriptValue js_Command(QScriptContext *context, QScriptEngine *engine)
engine->toScriptValue(commandPrototype->responseFileArgumentIndex()));
cmd.setProperty(responseFileUsagePrefixProperty(),
engine->toScriptValue(commandPrototype->responseFileUsagePrefix()));
+ cmd.setProperty(responseFileSeparatorProperty(),
+ engine->toScriptValue(commandPrototype->responseFileSeparator()));
cmd.setProperty(stdoutFilePathProperty(),
engine->toScriptValue(commandPrototype->stdoutFilePath()));
cmd.setProperty(stderrFilePathProperty(),
@@ -241,6 +242,7 @@ ProcessCommand::ProcessCommand()
: m_maxExitCode(0)
, m_responseFileThreshold(defaultResponseFileThreshold())
, m_responseFileArgumentIndex(0)
+ , m_responseFileSeparator(QStringLiteral("\n"))
{
}
@@ -279,6 +281,7 @@ bool ProcessCommand::equals(const AbstractCommand *otherAbstractCommand) const
&& m_responseFileThreshold == other->m_responseFileThreshold
&& m_responseFileArgumentIndex == other->m_responseFileArgumentIndex
&& m_responseFileUsagePrefix == other->m_responseFileUsagePrefix
+ && m_responseFileSeparator == other->m_responseFileSeparator
&& m_stdoutFilePath == other->m_stdoutFilePath
&& m_stderrFilePath == other->m_stderrFilePath
&& m_relevantEnvVars == other->m_relevantEnvVars
@@ -313,6 +316,8 @@ void ProcessCommand::fillFromScriptValue(const QScriptValue *scriptValue, const
.toInt32();
m_responseFileUsagePrefix = scriptValue->property(responseFileUsagePrefixProperty())
.toString();
+ m_responseFileSeparator = scriptValue->property(responseFileSeparatorProperty())
+ .toString();
QStringList envList = scriptValue->property(environmentProperty()).toVariant()
.toStringList();
getEnvironmentFromList(envList);
@@ -399,9 +404,7 @@ void JavaScriptCommand::setupForJavaScript(QScriptValue targetObject)
targetObject.setProperty(StringConstants::javaScriptCommandType(), ctor);
}
-JavaScriptCommand::JavaScriptCommand()
-{
-}
+JavaScriptCommand::JavaScriptCommand() = default;
bool JavaScriptCommand::equals(const AbstractCommand *otherAbstractCommand) const
{
diff --git a/src/lib/corelib/buildgraph/rulecommands.h b/src/lib/corelib/buildgraph/rulecommands.h
index d4d70d591..725cd6d89 100644
--- a/src/lib/corelib/buildgraph/rulecommands.h
+++ b/src/lib/corelib/buildgraph/rulecommands.h
@@ -136,6 +136,7 @@ public:
int responseFileThreshold() const { return m_responseFileThreshold; }
int responseFileArgumentIndex() const { return m_responseFileArgumentIndex; }
QString responseFileUsagePrefix() const { return m_responseFileUsagePrefix; }
+ QString responseFileSeparator() const { return m_responseFileSeparator; }
QProcessEnvironment environment() const { return m_environment; }
QStringList relevantEnvVars() const;
void clearRelevantEnvValues() { m_relevantEnvValues.clear(); }
@@ -158,10 +159,10 @@ private:
{
pool.serializationOp<opType>(m_program, m_arguments, m_environment, m_workingDir,
m_stdoutFilterFunction, m_stderrFilterFunction,
- m_responseFileUsagePrefix, m_maxExitCode,
- m_responseFileThreshold, m_responseFileArgumentIndex,
- m_relevantEnvVars, m_relevantEnvValues, m_stdoutFilePath,
- m_stderrFilePath);
+ m_responseFileUsagePrefix, m_responseFileSeparator,
+ m_maxExitCode, m_responseFileThreshold,
+ m_responseFileArgumentIndex, m_relevantEnvVars,
+ m_relevantEnvValues, m_stdoutFilePath, m_stderrFilePath);
}
QString m_program;
@@ -173,6 +174,7 @@ private:
int m_responseFileThreshold; // When to use response files? In bytes of (program name + arguments).
int m_responseFileArgumentIndex;
QString m_responseFileUsagePrefix;
+ QString m_responseFileSeparator;
QProcessEnvironment m_environment;
QStringList m_relevantEnvVars;
QProcessEnvironment m_relevantEnvValues;
diff --git a/src/lib/corelib/buildgraph/rulegraph.cpp b/src/lib/corelib/buildgraph/rulegraph.cpp
index 23227ca09..23f22b7f2 100644
--- a/src/lib/corelib/buildgraph/rulegraph.cpp
+++ b/src/lib/corelib/buildgraph/rulegraph.cpp
@@ -46,9 +46,7 @@
namespace qbs {
namespace Internal {
-RuleGraph::RuleGraph()
-{
-}
+RuleGraph::RuleGraph() = default;
void RuleGraph::build(const std::vector<RulePtr> &rules, const FileTags &productFileTags)
{
@@ -63,7 +61,7 @@ void RuleGraph::build(const std::vector<RulePtr> &rules, const FileTags &product
m_parents.resize(rules.size());
m_children.resize(rules.size());
- for (const RuleConstPtr &rule : qAsConst(m_rules)) {
+ for (const auto &rule : qAsConst(m_rules)) {
FileTags inFileTags = rule->inputs;
inFileTags += rule->auxiliaryInputs;
inFileTags += rule->explicitlyDependsOn;
@@ -100,7 +98,7 @@ void RuleGraph::dump() const
QByteArray indent;
printf("---rule graph dump:\n");
Set<int> rootRules;
- for (const RuleConstPtr &rule : qAsConst(m_rules))
+ for (const auto &rule : qAsConst(m_rules))
if (m_parents[rule->ruleGraphId].empty())
rootRules += rule->ruleGraphId;
for (int idx : qAsConst(rootRules))
diff --git a/src/lib/corelib/buildgraph/rulenode.cpp b/src/lib/corelib/buildgraph/rulenode.cpp
index bf25b1da8..0558ba144 100644
--- a/src/lib/corelib/buildgraph/rulenode.cpp
+++ b/src/lib/corelib/buildgraph/rulenode.cpp
@@ -56,13 +56,9 @@
namespace qbs {
namespace Internal {
-RuleNode::RuleNode()
-{
-}
+RuleNode::RuleNode() = default;
-RuleNode::~RuleNode()
-{
-}
+RuleNode::~RuleNode() = default;
void RuleNode::accept(BuildGraphVisitor *visitor)
{
@@ -182,7 +178,7 @@ void RuleNode::apply(const Logger &logger,
if (removedInputForcesOutputRemoval)
outputArtifactsToRemove += parent;
else
- connectionsToBreak.push_back(std::make_pair(parent, artifact));
+ connectionsToBreak.emplace_back(parent, artifact);
}
disconnect(this, artifact);
}
@@ -262,7 +258,7 @@ ArtifactSet RuleNode::currentInputArtifacts() const
}
}
- for (const ResolvedProductConstPtr &dep : qAsConst(product->dependencies)) {
+ for (const auto &dep : qAsConst(product->dependencies)) {
if (!dep->buildData)
continue;
for (Artifact * const a : filterByType<Artifact>(dep->buildData->allNodes())) {
diff --git a/src/lib/corelib/buildgraph/rulesapplicator.cpp b/src/lib/corelib/buildgraph/rulesapplicator.cpp
index 16aa0c001..0d36e1e21 100644
--- a/src/lib/corelib/buildgraph/rulesapplicator.cpp
+++ b/src/lib/corelib/buildgraph/rulesapplicator.cpp
@@ -79,12 +79,13 @@ namespace Internal {
RulesApplicator::RulesApplicator(
ResolvedProductPtr product,
- std::unordered_map<QString, const ResolvedProduct *> productsByName,
- std::unordered_map<QString, const ResolvedProject *> projectsByName,
+ const std::unordered_map<QString, const ResolvedProduct *> &productsByName,
+ const std::unordered_map<QString, const ResolvedProject *> &projectsByName,
Logger logger)
: m_product(std::move(product))
- , m_productsByName(std::move(productsByName))
- , m_projectsByName(std::move(projectsByName))
+ // m_productsByName and m_projectsByName are references, cannot move-construct
+ , m_productsByName(productsByName)
+ , m_projectsByName(projectsByName)
, m_mocScanner(nullptr)
, m_logger(std::move(logger))
{
@@ -213,13 +214,13 @@ void RulesApplicator::doApply(const ArtifactSet &inputArtifacts, QScriptValue &p
ScriptEngine::argumentList(Rule::argumentNamesForOutputArtifacts(), scope()));
} else {
Set<QString> outputFilePaths;
- for (const RuleArtifactConstPtr &ruleArtifact : m_rule->artifacts) {
+ for (const auto &ruleArtifact : m_rule->artifacts) {
const OutputArtifactInfo outputInfo = createOutputArtifactFromRuleArtifact(
ruleArtifact, inputArtifacts, &outputFilePaths);
if (!outputInfo.artifact)
continue;
outputArtifacts.push_back(outputInfo.artifact);
- ruleArtifactArtifactMap.push_back({ ruleArtifact.get(), outputInfo });
+ ruleArtifactArtifactMap.emplace_back(ruleArtifact.get(), outputInfo);
}
if (m_rule->artifacts.empty()) {
outputArtifacts.push_back(createOutputArtifactFromRuleArtifact(
@@ -287,7 +288,7 @@ void RulesApplicator::doApply(const ArtifactSet &inputArtifacts, QScriptValue &p
}
const QVariant value = scriptValue.toVariant();
setConfigProperty(artifactModulesCfg, binding.name, value);
- outputArtifact->pureProperties.push_back(std::make_pair(binding.name, value));
+ outputArtifact->pureProperties.emplace_back(binding.name, value);
}
outputArtifact->properties->setValue(artifactModulesCfg);
if (!outputInfo.newlyCreated && (outputArtifact->fileTags() != outputInfo.oldFileTags
@@ -354,7 +355,7 @@ ArtifactSet RulesApplicator::collectAdditionalInputs(const FileTags &tags, const
}
if (inputsSources.testFlag(Dependencies)) {
- for (const ResolvedProductConstPtr &depProduct : product->dependencies) {
+ for (const auto &depProduct : product->dependencies) {
for (Artifact * const ta : depProduct->targetArtifacts()) {
if (ta->fileTags().contains(fileTag)
&& !ta->fileTags().intersects(rule->excludedInputs)) {
@@ -607,7 +608,7 @@ public:
for (const auto &e : m_propertyValues) {
const QStringList key{e.module, e.name};
setConfigProperty(artifactCfg, key, e.value);
- outputArtifact->pureProperties.push_back(std::make_pair(key, e.value));
+ outputArtifact->pureProperties.emplace_back(key, e.value);
}
outputArtifact->properties->setValue(artifactCfg);
}
diff --git a/src/lib/corelib/buildgraph/rulesapplicator.h b/src/lib/corelib/buildgraph/rulesapplicator.h
index 1160f3d09..da7815014 100644
--- a/src/lib/corelib/buildgraph/rulesapplicator.h
+++ b/src/lib/corelib/buildgraph/rulesapplicator.h
@@ -63,8 +63,8 @@ class RulesApplicator
{
public:
RulesApplicator(ResolvedProductPtr product,
- std::unordered_map<QString, const ResolvedProduct *> productsByName,
- std::unordered_map<QString, const ResolvedProject *> projectsByName,
+ const std::unordered_map<QString, const ResolvedProduct *> &productsByName,
+ const std::unordered_map<QString, const ResolvedProject *> &projectsByName,
Logger logger);
~RulesApplicator();
diff --git a/src/lib/corelib/buildgraph/scriptclasspropertyiterator.h b/src/lib/corelib/buildgraph/scriptclasspropertyiterator.h
index f6154f993..b57072236 100644
--- a/src/lib/corelib/buildgraph/scriptclasspropertyiterator.h
+++ b/src/lib/corelib/buildgraph/scriptclasspropertyiterator.h
@@ -57,10 +57,10 @@ class ScriptClassPropertyIterator : public QScriptClassPropertyIterator
{
public:
ScriptClassPropertyIterator(const QScriptValue &object, const QVariantMap &properties,
- const std::vector<QString> &additionalProperties)
+ std::vector<QString> additionalProperties)
: QScriptClassPropertyIterator(object),
m_it(properties),
- m_additionalProperties(additionalProperties)
+ m_additionalProperties(std::move(additionalProperties))
{
}
diff --git a/src/lib/corelib/buildgraph/timestampsupdater.cpp b/src/lib/corelib/buildgraph/timestampsupdater.cpp
index d31f57445..3f5279dd2 100644
--- a/src/lib/corelib/buildgraph/timestampsupdater.cpp
+++ b/src/lib/corelib/buildgraph/timestampsupdater.cpp
@@ -83,7 +83,7 @@ private:
};
void TimestampsUpdater::updateTimestamps(const TopLevelProjectPtr &project,
- const QList<ResolvedProductPtr> &products, const Logger &logger)
+ const QVector<ResolvedProductPtr> &products, const Logger &logger)
{
TimestampsUpdateVisitor v;
for (const ResolvedProductPtr &product : products)
diff --git a/src/lib/corelib/buildgraph/timestampsupdater.h b/src/lib/corelib/buildgraph/timestampsupdater.h
index cfe20df12..8184ca708 100644
--- a/src/lib/corelib/buildgraph/timestampsupdater.h
+++ b/src/lib/corelib/buildgraph/timestampsupdater.h
@@ -51,7 +51,7 @@ class TimestampsUpdater
{
public:
void updateTimestamps(const TopLevelProjectPtr &project,
- const QList<ResolvedProductPtr> &products, const Logger &logger);
+ const QVector<ResolvedProductPtr> &products, const Logger &logger);
};
} // namespace Internal
diff --git a/src/lib/corelib/buildgraph/transformer.cpp b/src/lib/corelib/buildgraph/transformer.cpp
index cc0b4c923..29f2bcdf0 100644
--- a/src/lib/corelib/buildgraph/transformer.cpp
+++ b/src/lib/corelib/buildgraph/transformer.cpp
@@ -62,9 +62,7 @@ Transformer::Transformer() : alwaysRun(false)
{
}
-Transformer::~Transformer()
-{
-}
+Transformer::~Transformer() = default;
static QScriptValue js_baseName(QScriptContext *ctx, QScriptEngine *engine,
const Artifact *artifact)
@@ -196,7 +194,7 @@ void Transformer::setupInputs(QScriptValue targetScriptValue, const ArtifactSet
targetScriptValue.setProperty(StringConstants::inputVar(), inputScriptValue);
}
-void Transformer::setupInputs(QScriptValue targetScriptValue)
+void Transformer::setupInputs(const QScriptValue &targetScriptValue)
{
setupInputs(targetScriptValue, inputs, rule->module->name);
}
diff --git a/src/lib/corelib/buildgraph/transformer.h b/src/lib/corelib/buildgraph/transformer.h
index 2f6a8e56d..8772ed868 100644
--- a/src/lib/corelib/buildgraph/transformer.h
+++ b/src/lib/corelib/buildgraph/transformer.h
@@ -95,7 +95,7 @@ public:
const Artifact *artifact,
const QString &defaultModuleName);
ResolvedProductPtr product() const;
- void setupInputs(QScriptValue targetScriptValue);
+ void setupInputs(const QScriptValue &targetScriptValue);
void setupOutputs(QScriptValue targetScriptValue);
void setupExplicitlyDependsOn(QScriptValue targetScriptValue);
void createCommands(ScriptEngine *engine, const PrivateScriptFunction &script,
diff --git a/src/lib/corelib/buildgraph/transformerchangetracking.cpp b/src/lib/corelib/buildgraph/transformerchangetracking.cpp
index 505f0cbba..e44c31639 100644
--- a/src/lib/corelib/buildgraph/transformerchangetracking.cpp
+++ b/src/lib/corelib/buildgraph/transformerchangetracking.cpp
@@ -71,7 +71,7 @@ private:
const char *context) const;
bool isExportedModuleUpToDate(const QString &productName, const ExportedModule &module) const;
bool areExportedModulesUpToDate(
- const std::unordered_map<QString, ExportedModule> exportedModules) const;
+ const std::unordered_map<QString, ExportedModule> &exportedModules) const;
const Artifact *getArtifact(const QString &filePath, const QString &productName) const;
const ResolvedProduct *getProduct(const QString &name) const;
@@ -207,7 +207,7 @@ bool TrafoChangeTracker::isExportedModuleUpToDate(const QString &productName,
}
bool TrafoChangeTracker::areExportedModulesUpToDate(
- const std::unordered_map<QString, ExportedModule> exportedModules) const
+ const std::unordered_map<QString, ExportedModule> &exportedModules) const
{
for (const auto &kv : exportedModules) {
if (!isExportedModuleUpToDate(kv.first, kv.second))
diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs
index bd44ac3ed..619c0f0e3 100644
--- a/src/lib/corelib/corelib.qbs
+++ b/src/lib/corelib/corelib.qbs
@@ -395,6 +395,8 @@ QbsLibrary {
"buildgraphlocker.cpp",
"buildgraphlocker.h",
"buildoptions.cpp",
+ "clangclinfo.cpp",
+ "clangclinfo.h",
"cleanoptions.cpp",
"codelocation.cpp",
"commandechomode.cpp",
diff --git a/src/lib/corelib/generators/generatordata.h b/src/lib/corelib/generators/generatordata.h
index da65815ad..fd9bdde31 100644
--- a/src/lib/corelib/generators/generatordata.h
+++ b/src/lib/corelib/generators/generatordata.h
@@ -99,7 +99,7 @@ template <typename U> struct IMultiplexableContainer {
}
protected:
- IMultiplexableContainer() { }
+ IMultiplexableContainer() = default;
};
struct QBS_EXPORT GeneratableProductData : public IMultiplexableContainer<ProductData> {
@@ -114,7 +114,7 @@ struct QBS_EXPORT GeneratableProjectData : public IMultiplexableContainer<Projec
struct Id {
private:
friend struct GeneratableProjectData;
- Id() { }
+ Id() = default;
QString value;
public:
diff --git a/src/lib/corelib/generators/generatorutils.h b/src/lib/corelib/generators/generatorutils.h
index 9348ab18c..58e59cbf8 100644
--- a/src/lib/corelib/generators/generatorutils.h
+++ b/src/lib/corelib/generators/generatorutils.h
@@ -41,14 +41,17 @@ namespace gen {
namespace utils {
enum class Architecture {
- Arm,
- Avr,
- Mcs51,
- Stm8,
- Msp430,
- Unknown
+ Unknown = 0,
+ Arm = 1 << 1,
+ Avr = 1 << 2,
+ Mcs51 = 1 << 3,
+ Stm8 = 1 << 4,
+ Msp430 = 1 << 5
};
+Q_DECLARE_FLAGS(ArchitectureFlags, Architecture)
+Q_DECLARE_OPERATORS_FOR_FLAGS(ArchitectureFlags)
+
QBS_EXPORT QString architectureName(Architecture arch);
QBS_EXPORT Architecture architecture(const Project &qbsProject);
QBS_EXPORT QString buildConfigurationName(const Project &qbsProject);
diff --git a/src/lib/corelib/generators/generatorversioninfo.cpp b/src/lib/corelib/generators/generatorversioninfo.cpp
index 3e2106b57..c5c8db03f 100644
--- a/src/lib/corelib/generators/generatorversioninfo.cpp
+++ b/src/lib/corelib/generators/generatorversioninfo.cpp
@@ -42,42 +42,10 @@
namespace qbs {
namespace gen {
-VersionInfo::VersionInfo(const Version &version,
- const std::set<utils::Architecture> &archs)
- : m_version(version), m_archs(archs)
-{
-}
-
-bool VersionInfo::operator<(const VersionInfo &other) const
-{
- return m_version < other.m_version;
-}
-
-bool VersionInfo::operator==(const VersionInfo &other) const
-{
- return m_version == other.m_version
- && m_archs == other.m_archs;
-}
-
-Version VersionInfo::version() const
-{
- return m_version;
-}
-
-bool VersionInfo::containsArchitecture(utils::Architecture arch) const
-{
- return m_archs.find(arch) != m_archs.cend();
-}
-
int VersionInfo::marketingVersion() const
{
return m_version.majorVersion();
}
-quint32 qHash(const VersionInfo &info)
-{
- return qHash(info.version().toString());
-}
-
} // namespace gen
} // namespace qbs
diff --git a/src/lib/corelib/generators/generatorversioninfo.h b/src/lib/corelib/generators/generatorversioninfo.h
index 65bfcf685..38616eb98 100644
--- a/src/lib/corelib/generators/generatorversioninfo.h
+++ b/src/lib/corelib/generators/generatorversioninfo.h
@@ -45,7 +45,7 @@
#include <tools/qbs_export.h>
#include <tools/version.h>
-#include <set>
+#include <QFlags>
namespace qbs {
namespace gen {
@@ -53,24 +53,31 @@ namespace gen {
class QBS_EXPORT VersionInfo
{
public:
- VersionInfo(const Version &version,
- const std::set<utils::Architecture> &archs);
- virtual ~VersionInfo() = default;
+ constexpr VersionInfo(const Version &version, utils::ArchitectureFlags archs)
+ : m_version(version), m_archs(archs)
+ {
+ }
- bool operator<(const VersionInfo &other) const;
- bool operator==(const VersionInfo &other) const;
+ constexpr bool operator<(const VersionInfo &other) const { return m_version < other.m_version; }
+ constexpr bool operator==(const VersionInfo &other) const
+ {
+ return m_version == other.m_version && m_archs == other.m_archs;
+ }
- Version version() const;
- bool containsArchitecture(utils::Architecture arch) const;
+ constexpr Version version() const { return m_version; }
+ constexpr bool containsArchitecture(utils::Architecture arch) const { return m_archs & arch; }
- virtual int marketingVersion() const;
+ int marketingVersion() const;
private:
Version m_version;
- std::set<utils::Architecture> m_archs;
+ utils::ArchitectureFlags m_archs;
};
-quint32 qHash(const VersionInfo &info);
+inline quint32 qHash(const VersionInfo &info)
+{
+ return qHash(info.version().toString());
+}
} // namespace gen
} // namespace qbs
diff --git a/src/lib/corelib/generators/igeneratableprojectvisitor.h b/src/lib/corelib/generators/igeneratableprojectvisitor.h
index c3bd28580..dbf73b4e0 100644
--- a/src/lib/corelib/generators/igeneratableprojectvisitor.h
+++ b/src/lib/corelib/generators/igeneratableprojectvisitor.h
@@ -46,7 +46,7 @@ namespace qbs {
class IGeneratableProjectVisitor {
public:
- virtual ~IGeneratableProjectVisitor() { }
+ virtual ~IGeneratableProjectVisitor() = default;
// Collapsed configurations
virtual void visitProject(const GeneratableProject &project) {
diff --git a/src/lib/corelib/generators/ixmlnodevisitor.h b/src/lib/corelib/generators/ixmlnodevisitor.h
index d3d118975..278f4cf2e 100644
--- a/src/lib/corelib/generators/ixmlnodevisitor.h
+++ b/src/lib/corelib/generators/ixmlnodevisitor.h
@@ -47,7 +47,7 @@ class Workspace;
class QBS_EXPORT INodeVisitor
{
public:
- virtual ~INodeVisitor() {}
+ virtual ~INodeVisitor() = default;
virtual void visitWorkspaceStart(const Workspace *workspace) { Q_UNUSED(workspace) }
virtual void visitWorkspaceEnd(const Workspace *workspace) { Q_UNUSED(workspace) }
diff --git a/src/lib/corelib/generators/xmlprojectwriter.cpp b/src/lib/corelib/generators/xmlprojectwriter.cpp
index 5554e5935..190e1304f 100644
--- a/src/lib/corelib/generators/xmlprojectwriter.cpp
+++ b/src/lib/corelib/generators/xmlprojectwriter.cpp
@@ -33,6 +33,7 @@
#include "xmlproperty.h"
#include "xmlpropertygroup.h"
+#include <memory>
#include <ostream>
namespace qbs {
@@ -42,7 +43,7 @@ namespace xml {
ProjectWriter::ProjectWriter(std::ostream *device)
: m_device(device)
{
- m_writer.reset(new QXmlStreamWriter(&m_buffer));
+ m_writer = std::make_unique<QXmlStreamWriter>(&m_buffer);
m_writer->setAutoFormatting(true);
}
diff --git a/src/lib/corelib/generators/xmlpropertygroup.cpp b/src/lib/corelib/generators/xmlpropertygroup.cpp
index 398d68e77..c9e6a97c1 100644
--- a/src/lib/corelib/generators/xmlpropertygroup.cpp
+++ b/src/lib/corelib/generators/xmlpropertygroup.cpp
@@ -45,10 +45,9 @@ void PropertyGroup::appendProperty(QByteArray name, QVariant value)
appendChild<Property>(std::move(name), std::move(value));
}
-void PropertyGroup::appendMultiLineProperty(
- QByteArray key, QStringList values, QChar sep)
+void PropertyGroup::appendMultiLineProperty(QByteArray key, const QStringList &values, QChar sep)
{
- const auto line = values.join(std::move(sep));
+ const auto line = values.join(sep);
appendProperty(std::move(key), QVariant::fromValue(line));
}
diff --git a/src/lib/corelib/generators/xmlpropertygroup.h b/src/lib/corelib/generators/xmlpropertygroup.h
index e63b515fc..e7e051a87 100644
--- a/src/lib/corelib/generators/xmlpropertygroup.h
+++ b/src/lib/corelib/generators/xmlpropertygroup.h
@@ -52,7 +52,7 @@ public:
explicit PropertyGroup(QByteArray name);
void appendProperty(QByteArray name, QVariant value);
- void appendMultiLineProperty(QByteArray key, QStringList values,
+ void appendMultiLineProperty(QByteArray key, const QStringList &values,
QChar sep = QLatin1Char(','));
void accept(INodeVisitor *visitor) const final;
diff --git a/src/lib/corelib/generators/xmlworkspacewriter.cpp b/src/lib/corelib/generators/xmlworkspacewriter.cpp
index c88cb06d0..d21b63c42 100644
--- a/src/lib/corelib/generators/xmlworkspacewriter.cpp
+++ b/src/lib/corelib/generators/xmlworkspacewriter.cpp
@@ -33,6 +33,7 @@
#include "xmlworkspace.h"
#include "xmlworkspacewriter.h"
+#include <memory>
#include <ostream>
namespace qbs {
@@ -42,7 +43,7 @@ namespace xml {
WorkspaceWriter::WorkspaceWriter(std::ostream *device)
: m_device(device)
{
- m_writer.reset(new QXmlStreamWriter(&m_buffer));
+ m_writer = std::make_unique<QXmlStreamWriter>(&m_buffer);
m_writer->setAutoFormatting(true);
}
diff --git a/src/lib/corelib/jsextensions/binaryfile.cpp b/src/lib/corelib/jsextensions/binaryfile.cpp
index 5f28f689b..f02f0bff6 100644
--- a/src/lib/corelib/jsextensions/binaryfile.cpp
+++ b/src/lib/corelib/jsextensions/binaryfile.cpp
@@ -235,7 +235,7 @@ void BinaryFile::write(const QVariantList &data)
QByteArray bytes;
std::for_each(data.constBegin(), data.constEnd(), [&bytes](const QVariant &v) {
- bytes.append(v.toUInt() & 0xFF); });
+ bytes.append(char(v.toUInt() & 0xFF)); });
const qint64 size = m_file->write(bytes);
if (Q_UNLIKELY(size == -1)) {
diff --git a/src/lib/corelib/jsextensions/domxml.cpp b/src/lib/corelib/jsextensions/domxml.cpp
index 118e8d5e1..86e1574c6 100644
--- a/src/lib/corelib/jsextensions/domxml.cpp
+++ b/src/lib/corelib/jsextensions/domxml.cpp
@@ -85,7 +85,7 @@ public:
Q_INVOKABLE QScriptValue previousSibling(const QString & tagName = QString()) const;
Q_INVOKABLE QScriptValue nextSibling(const QString & tagName = QString()) const;
- Q_INVOKABLE QScriptValue appendChild(QScriptValue newChild);
+ Q_INVOKABLE QScriptValue appendChild(const QScriptValue &newChild);
Q_INVOKABLE QScriptValue insertBefore(const QScriptValue& newChild, const QScriptValue& refChild);
Q_INVOKABLE QScriptValue insertAfter(const QScriptValue& newChild, const QScriptValue& refChild);
Q_INVOKABLE QScriptValue replaceChild(const QScriptValue& newChild, const QScriptValue& oldChild);
@@ -314,7 +314,6 @@ void XmlDomNode::setData(const QString &v) const
if (m_domNode.isCharacterData())
return m_domNode.toCharacterData().setData(v);
context()->throwError(QStringLiteral("Node '%1' is not a character data node").arg(m_domNode.nodeName()));
- return;
}
void XmlDomNode::clear()
@@ -365,7 +364,7 @@ QScriptValue XmlDomNode::nextSibling(const QString &tagName) const
return engine()->newQObject(new XmlDomNode(m_domNode.nextSiblingElement(tagName)), QScriptEngine::ScriptOwnership);
}
-QScriptValue XmlDomNode::appendChild(QScriptValue newChild)
+QScriptValue XmlDomNode::appendChild(const QScriptValue &newChild)
{
auto newNode = qobject_cast<XmlDomNode*>(newChild.toQObject());
if (!newNode) {
diff --git a/src/lib/corelib/jsextensions/fileinfoextension.cpp b/src/lib/corelib/jsextensions/fileinfoextension.cpp
index 0f2570ed0..038f3db41 100644
--- a/src/lib/corelib/jsextensions/fileinfoextension.cpp
+++ b/src/lib/corelib/jsextensions/fileinfoextension.cpp
@@ -53,6 +53,16 @@
namespace qbs {
namespace Internal {
+// removes duplicate separators from the path
+static QString uniqueSeparators(QString path)
+{
+ const auto it = std::unique(path.begin(), path.end(), [](QChar c1, QChar c2) {
+ return c1 == c2 && c1 == QLatin1Char('/');
+ });
+ path.resize(int(it - path.begin()));
+ return path;
+}
+
class FileInfoExtension : public QObject, QScriptable
{
Q_OBJECT
@@ -268,9 +278,7 @@ QScriptValue FileInfoExtension::js_joinPaths(QScriptContext *context, QScriptEng
paths.push_back(arg);
}
}
- return engine->toScriptValue(QString::fromStdString(
- std::regex_replace(paths.join(QLatin1Char('/')).toStdString(),
- std::regex("/{2,}"), std::string("/"))));
+ return engine->toScriptValue(uniqueSeparators(paths.join(QLatin1Char('/'))));
}
} // namespace Internal
diff --git a/src/lib/corelib/jsextensions/jsextensions.cpp b/src/lib/corelib/jsextensions/jsextensions.cpp
index e5fbd3de8..052fb79e4 100644
--- a/src/lib/corelib/jsextensions/jsextensions.cpp
+++ b/src/lib/corelib/jsextensions/jsextensions.cpp
@@ -75,7 +75,7 @@ static InitializerMap &initializers()
return theMap;
}
-void JsExtensions::setupExtensions(const QStringList &names, QScriptValue scope)
+void JsExtensions::setupExtensions(const QStringList &names, const QScriptValue &scope)
{
for (const QString &name : names)
initializers().value(name)(scope);
diff --git a/src/lib/corelib/jsextensions/jsextensions.h b/src/lib/corelib/jsextensions/jsextensions.h
index 8977dbe8a..f1ebfbdc3 100644
--- a/src/lib/corelib/jsextensions/jsextensions.h
+++ b/src/lib/corelib/jsextensions/jsextensions.h
@@ -54,7 +54,7 @@ namespace Internal {
class JsExtensions
{
public:
- static void setupExtensions(const QStringList &names, QScriptValue scope);
+ static void setupExtensions(const QStringList &names, const QScriptValue &scope);
static QScriptValue loadExtension(QScriptEngine *engine, const QString &name);
static bool hasExtension(const QString &name);
static QStringList extensionNames();
diff --git a/src/lib/corelib/jsextensions/moduleproperties.cpp b/src/lib/corelib/jsextensions/moduleproperties.cpp
index c0fd8ca84..f721e0016 100644
--- a/src/lib/corelib/jsextensions/moduleproperties.cpp
+++ b/src/lib/corelib/jsextensions/moduleproperties.cpp
@@ -195,7 +195,7 @@ static QScriptValue js_moduleDependencies(QScriptContext *, ScriptEngine *engine
QScriptValue result = engine->newArray();
quint32 idx = 0;
for (const QString &depName : qAsConst(module->moduleDependencies)) {
- for (const ResolvedModuleConstPtr &dep : module->product->modules) {
+ for (const auto &dep : module->product->modules) {
if (dep->name != depName)
continue;
QScriptValue obj = engine->newObject(engine->modulePropertyScriptClass());
diff --git a/src/lib/corelib/jsextensions/propertylist.mm b/src/lib/corelib/jsextensions/propertylist.mm
index 6ac9d56c9..2ae422c41 100644
--- a/src/lib/corelib/jsextensions/propertylist.mm
+++ b/src/lib/corelib/jsextensions/propertylist.mm
@@ -95,7 +95,7 @@ public:
QVariant propertyListObject;
int propertyListFormat;
- void readFromData(QScriptContext *context, QByteArray data);
+ void readFromData(QScriptContext *context, const QByteArray &data);
QByteArray writeToData(QScriptContext *context, const QString &format);
};
@@ -263,7 +263,7 @@ QString PropertyList::toJSON(const QString &style) const
namespace qbs {
namespace Internal {
-void PropertyListPrivate::readFromData(QScriptContext *context, QByteArray data)
+void PropertyListPrivate::readFromData(QScriptContext *context, const QByteArray &data)
{
@autoreleasepool {
NSPropertyListFormat format;
diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp
index b425bb4a2..6c693cb61 100644
--- a/src/lib/corelib/jsextensions/utilitiesextension.cpp
+++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp
@@ -72,6 +72,7 @@ struct fat_arch_64 {
#ifdef Q_OS_WIN
+#include <tools/clangclinfo.h>
#include <tools/msvcinfo.h>
#include <tools/vsenvironmentdetector.h>
#endif
@@ -88,6 +89,10 @@ struct fat_arch_64 {
namespace qbs {
namespace Internal {
+class DummyLogSink : public ILogSink {
+ void doPrintMessage(LoggerLevel, const QString &, const QString &) override { }
+};
+
class UtilitiesExtension : public QObject, QScriptable
{
Q_OBJECT
@@ -110,6 +115,8 @@ public:
static QScriptValue js_signingIdentities(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_msvcCompilerInfo(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_clangClCompilerInfo(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_installedMSVCs(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_installedClangCls(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_versionCompare(QScriptContext *context, QScriptEngine *engine);
@@ -132,7 +139,7 @@ QScriptValue UtilitiesExtension::js_canonicalPlatform(QScriptContext *context,
{
const QScriptValue value = context->argument(0);
if (value.isUndefined() || value.isNull())
- return value;
+ return engine->toScriptValue(QStringList());
if (context->argumentCount() == 1 && value.isString()) {
return engine->toScriptValue([&value] {
@@ -529,7 +536,11 @@ QScriptValue UtilitiesExtension::js_clangClCompilerInfo(QScriptContext *context,
QStringLiteral("clangClCompilerInfo expects 4 arguments"));
const QString compilerFilePath = context->argument(0).toString();
- QString arch = context->argument(1).toString();
+ // architecture cannot be empty as vcvarsall.bat requires at least 1 arg, so fallback
+ // to host architecture if none is present
+ QString arch = !context->argument(1).isNull() && !context->argument(1).isUndefined()
+ ? context->argument(1).toString()
+ : QString::fromStdString(HostOsInfo::hostOSArchitecture());
QString vcvarsallPath = context->argument(2).toString();
const QString compilerLanguage = context->argumentCount() > 3
? context->argument(3).toString()
@@ -551,6 +562,67 @@ QScriptValue UtilitiesExtension::js_clangClCompilerInfo(QScriptContext *context,
#endif
}
+QScriptValue UtilitiesExtension::js_installedMSVCs(QScriptContext *context, QScriptEngine *engine)
+{
+#ifndef Q_OS_WIN
+ Q_UNUSED(engine);
+ return context->throwError(QScriptContext::UnknownError,
+ QStringLiteral("installedMSVCs is not available on this platform"));
+#else
+ if (Q_UNLIKELY(context->argumentCount() != 1)) {
+ return context->throwError(QScriptContext::SyntaxError,
+ QStringLiteral("installedMSVCs expects 1 arguments"));
+ }
+
+ const auto value0 = context->argument(0);
+ const auto hostArch = QString::fromStdString(HostOsInfo::hostOSArchitecture());
+ const auto preferredArch = !value0.isNull() && !value0.isUndefined()
+ ? value0.toString()
+ : hostArch;
+
+ DummyLogSink dummySink;
+ Logger dummyLogger(&dummySink);
+ auto msvcs = MSVC::installedCompilers(dummyLogger);
+
+ const auto predicate = [&preferredArch, &hostArch](const MSVC &msvc)
+ {
+ auto archPair = MSVC::getHostTargetArchPair(msvc.architecture);
+ return archPair.first != hostArch || preferredArch != archPair.second;
+ };
+ msvcs.erase(std::remove_if(msvcs.begin(), msvcs.end(), predicate), msvcs.end());
+ QVariantList result;
+ for (const auto &msvc: msvcs)
+ result.append(msvc.toVariantMap());
+ return engine->toScriptValue(result);
+#endif
+}
+
+QScriptValue UtilitiesExtension::js_installedClangCls(
+ QScriptContext *context, QScriptEngine *engine)
+{
+#ifndef Q_OS_WIN
+ Q_UNUSED(engine);
+ return context->throwError(QScriptContext::UnknownError,
+ QStringLiteral("installedClangCls is not available on this platform"));
+#else
+ if (Q_UNLIKELY(context->argumentCount() != 1)) {
+ return context->throwError(QScriptContext::SyntaxError,
+ QStringLiteral("installedClangCls expects 1 arguments"));
+ }
+
+ const auto value0 = context->argument(0);
+ const auto path = !value0.isNull() && !value0.isUndefined() ? value0.toString() : QString();
+
+ DummyLogSink dummySink;
+ Logger dummyLogger(&dummySink);
+ auto compilers = ClangClInfo::installedCompilers({path}, dummyLogger);
+ QVariantList result;
+ for (const auto &compiler: compilers)
+ result.append(compiler.toVariantMap());
+ return engine->toScriptValue(result);
+#endif
+}
+
QScriptValue UtilitiesExtension::js_versionCompare(QScriptContext *context, QScriptEngine *engine)
{
if (context->argumentCount() == 2) {
@@ -851,6 +923,10 @@ void initializeJsExtensionUtilities(QScriptValue extensionObject)
engine->newFunction(UtilitiesExtension::js_msvcCompilerInfo, 1));
environmentObj.setProperty(QStringLiteral("clangClCompilerInfo"),
engine->newFunction(UtilitiesExtension::js_clangClCompilerInfo, 1));
+ environmentObj.setProperty(QStringLiteral("installedMSVCs"),
+ engine->newFunction(UtilitiesExtension::js_installedMSVCs, 1));
+ environmentObj.setProperty(QStringLiteral("installedClangCls"),
+ engine->newFunction(UtilitiesExtension::js_installedClangCls, 1));
environmentObj.setProperty(QStringLiteral("versionCompare"),
engine->newFunction(UtilitiesExtension::js_versionCompare, 2));
environmentObj.setProperty(QStringLiteral("qmlTypeInfo"),
diff --git a/src/lib/corelib/language/artifactproperties.cpp b/src/lib/corelib/language/artifactproperties.cpp
index dd61bf1a2..011e58d88 100644
--- a/src/lib/corelib/language/artifactproperties.cpp
+++ b/src/lib/corelib/language/artifactproperties.cpp
@@ -48,9 +48,7 @@ ArtifactPropertiesPtr ArtifactProperties::create()
return ArtifactPropertiesPtr(new ArtifactProperties);
}
-ArtifactProperties::ArtifactProperties()
-{
-}
+ArtifactProperties::ArtifactProperties() = default;
FileTags ArtifactProperties::extraFileTags() const
{
@@ -66,6 +64,7 @@ bool operator==(const ArtifactProperties &ap1, const ArtifactProperties &ap2)
{
return ap1.fileTagsFilter() == ap2.fileTagsFilter()
&& ap1.extraFileTags() == ap2.extraFileTags()
+ && !ap1.propertyMap() == !ap2.propertyMap()
&& *ap1.propertyMap() == *ap2.propertyMap();
}
diff --git a/src/lib/corelib/language/asttools.cpp b/src/lib/corelib/language/asttools.cpp
index 617c8b95b..1b6abac7f 100644
--- a/src/lib/corelib/language/asttools.cpp
+++ b/src/lib/corelib/language/asttools.cpp
@@ -61,13 +61,13 @@ QString textOf(const QString &source, QbsQmlJS::AST::Node *node)
if (!node)
return {};
return source.mid(node->firstSourceLocation().begin(),
- node->lastSourceLocation().end() - node->firstSourceLocation().begin());
+ int(node->lastSourceLocation().end() - node->firstSourceLocation().begin()));
}
QStringRef textRefOf(const QString &source, QbsQmlJS::AST::Node *node)
{
const quint32 firstBegin = node->firstSourceLocation().begin();
- return source.midRef(firstBegin, node->lastSourceLocation().end() - firstBegin);
+ return source.midRef(firstBegin, int(node->lastSourceLocation().end() - firstBegin));
}
} // namespace Internal
diff --git a/src/lib/corelib/language/builtindeclarations.cpp b/src/lib/corelib/language/builtindeclarations.cpp
index 68355df51..13783d3b9 100644
--- a/src/lib/corelib/language/builtindeclarations.cpp
+++ b/src/lib/corelib/language/builtindeclarations.cpp
@@ -125,7 +125,7 @@ ItemDeclaration BuiltinDeclarations::declarationsForType(ItemType type) const
}
ItemType BuiltinDeclarations::typeForName(const QString &typeName,
- const CodeLocation location) const
+ const CodeLocation &location) const
{
const auto it = m_typeMap.constFind(typeName);
if (it == m_typeMap.constEnd())
diff --git a/src/lib/corelib/language/builtindeclarations.h b/src/lib/corelib/language/builtindeclarations.h
index 988f9ab81..9d7aee982 100644
--- a/src/lib/corelib/language/builtindeclarations.h
+++ b/src/lib/corelib/language/builtindeclarations.h
@@ -62,7 +62,7 @@ public:
QStringList allTypeNames() const;
ItemDeclaration declarationsForType(ItemType type) const;
ItemType typeForName(const QString &typeName,
- const CodeLocation location = CodeLocation()) const;
+ const CodeLocation &location = CodeLocation()) const;
QString nameForType(ItemType itemType) const;
QStringList argumentNamesForScriptFunction(ItemType itemType, const QString &scriptName) const;
diff --git a/src/lib/corelib/language/deprecationinfo.h b/src/lib/corelib/language/deprecationinfo.h
index 502715b84..89cd07f4a 100644
--- a/src/lib/corelib/language/deprecationinfo.h
+++ b/src/lib/corelib/language/deprecationinfo.h
@@ -50,11 +50,11 @@ class DeprecationInfo
{
public:
explicit DeprecationInfo(const Version &removalVersion,
- const QString &additionalUserInfo = QString())
+ QString additionalUserInfo = QString())
: m_removalVersion(removalVersion)
- , m_additionalUserInfo(additionalUserInfo)
+ , m_additionalUserInfo(std::move(additionalUserInfo))
{}
- DeprecationInfo() {}
+ DeprecationInfo() = default;
bool isValid() const { return m_removalVersion.isValid(); }
Version removalVersion() const { return m_removalVersion; }
diff --git a/src/lib/corelib/language/evaluator.h b/src/lib/corelib/language/evaluator.h
index d8931a37e..f8535d0d7 100644
--- a/src/lib/corelib/language/evaluator.h
+++ b/src/lib/corelib/language/evaluator.h
@@ -64,7 +64,7 @@ class QBS_AUTOTEST_EXPORT Evaluator : private ItemObserver
public:
Evaluator(ScriptEngine *scriptEngine);
- virtual ~Evaluator();
+ ~Evaluator() override;
ScriptEngine *engine() const { return m_scriptEngine; }
QScriptValue property(const Item *item, const QString &name);
diff --git a/src/lib/corelib/language/identifiersearch.cpp b/src/lib/corelib/language/identifiersearch.cpp
index 973aae6a8..49ceab36c 100644
--- a/src/lib/corelib/language/identifiersearch.cpp
+++ b/src/lib/corelib/language/identifiersearch.cpp
@@ -43,9 +43,7 @@
namespace qbs {
namespace Internal {
-IdentifierSearch::IdentifierSearch()
-{
-}
+IdentifierSearch::IdentifierSearch() = default;
void IdentifierSearch::start(QbsQmlJS::AST::Node *node)
{
diff --git a/src/lib/corelib/language/item.cpp b/src/lib/corelib/language/item.cpp
index 9f754bdd7..a86cfeac1 100644
--- a/src/lib/corelib/language/item.cpp
+++ b/src/lib/corelib/language/item.cpp
@@ -203,15 +203,15 @@ bool Item::isOfTypeOrhasParentOfType(ItemType type) const
PropertyDeclaration Item::propertyDeclaration(const QString &name, bool allowExpired) const
{
- PropertyDeclaration decl = m_propertyDeclarations.value(name);
- if (decl.isValid())
- return decl;
+ auto it = m_propertyDeclarations.find(name);
+ if (it != m_propertyDeclarations.end())
+ return it.value();
if (allowExpired) {
- decl = m_expiredPropertyDeclarations.value(name);
- if (decl.isValid())
- return decl;
+ it = m_expiredPropertyDeclarations.find(name);
+ if (it != m_expiredPropertyDeclarations.end())
+ return it.value();
}
- return m_prototype ? m_prototype->propertyDeclaration(name) : decl;
+ return m_prototype ? m_prototype->propertyDeclaration(name) : PropertyDeclaration();
}
void Item::addModule(const Item::Module &module)
diff --git a/src/lib/corelib/language/itempool.cpp b/src/lib/corelib/language/itempool.cpp
index 3da8b947b..ccd22fe2e 100644
--- a/src/lib/corelib/language/itempool.cpp
+++ b/src/lib/corelib/language/itempool.cpp
@@ -43,9 +43,7 @@
namespace qbs {
namespace Internal {
-ItemPool::ItemPool()
-{
-}
+ItemPool::ItemPool() = default;
ItemPool::~ItemPool()
{
diff --git a/src/lib/corelib/language/itemreadervisitorstate.cpp b/src/lib/corelib/language/itemreadervisitorstate.cpp
index ca6ba2e12..20ddb5cfb 100644
--- a/src/lib/corelib/language/itemreadervisitorstate.cpp
+++ b/src/lib/corelib/language/itemreadervisitorstate.cpp
@@ -81,10 +81,7 @@ public:
{
}
- ASTCacheValue(const ASTCacheValue &other)
- : d(other.d)
- {
- }
+ ASTCacheValue(const ASTCacheValue &other) = default;
void setProcessingFlag(bool b) { d->processing = b; }
bool isProcessing() const { return d->processing; }
diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp
index 40549b836..3b3e7401e 100644
--- a/src/lib/corelib/language/language.cpp
+++ b/src/lib/corelib/language/language.cpp
@@ -188,15 +188,9 @@ void ResolvedGroup::store(PersistentPool &pool)
* \sa Rule
*/
-ScriptFunction::ScriptFunction()
-{
-
-}
-
-ScriptFunction::~ScriptFunction()
-{
+ScriptFunction::ScriptFunction() = default;
-}
+ScriptFunction::~ScriptFunction() = default;
/*!
* \variable ScriptFunction::script
@@ -282,7 +276,7 @@ QString Rule::toString() const
FileTags Rule::staticOutputFileTags() const
{
FileTags result;
- for (const RuleArtifactConstPtr &artifact : artifacts)
+ for (const auto &artifact : artifacts)
result.unite(artifact->fileTags);
return result;
}
@@ -312,9 +306,7 @@ ResolvedProduct::ResolvedProduct()
{
}
-ResolvedProduct::~ResolvedProduct()
-{
-}
+ResolvedProduct::~ResolvedProduct() = default;
void ResolvedProduct::accept(BuildGraphVisitor *visitor) const
{
@@ -331,7 +323,7 @@ void ResolvedProduct::accept(BuildGraphVisitor *visitor) const
std::vector<SourceArtifactPtr> ResolvedProduct::allFiles() const
{
std::vector<SourceArtifactPtr> lst;
- for (const GroupConstPtr &group : groups)
+ for (const auto &group : groups)
lst << group->allFiles();
return lst;
}
@@ -343,7 +335,7 @@ std::vector<SourceArtifactPtr> ResolvedProduct::allFiles() const
std::vector<SourceArtifactPtr> ResolvedProduct::allEnabledFiles() const
{
std::vector<SourceArtifactPtr> lst;
- for (const GroupConstPtr &group : groups) {
+ for (const auto &group : groups) {
if (group->enabled)
lst << group->allFiles();
}
@@ -364,7 +356,7 @@ FileTags ResolvedProduct::fileTagsForFileName(const QString &fileName) const
return result;
}
} else {
- priority.reset(new int(tagger->priority()));
+ priority = std::make_unique<int>(tagger->priority());
}
result.unite(tagger->fileTags());
break;
@@ -524,9 +516,7 @@ ResolvedProject::ResolvedProject() : enabled(true), m_topLevelProject(nullptr)
{
}
-ResolvedProject::~ResolvedProject()
-{
-}
+ResolvedProject::~ResolvedProject() = default;
void ResolvedProject::accept(BuildGraphVisitor *visitor) const
{
@@ -551,7 +541,7 @@ TopLevelProject *ResolvedProject::topLevelProject()
std::vector<ResolvedProjectPtr> ResolvedProject::allSubProjects() const
{
std::vector<ResolvedProjectPtr> projectList = subProjects;
- for (const ResolvedProjectConstPtr &subProject : subProjects)
+ for (const auto &subProject : subProjects)
projectList << subProject->allSubProjects();
return projectList;
}
@@ -559,7 +549,7 @@ std::vector<ResolvedProjectPtr> ResolvedProject::allSubProjects() const
std::vector<ResolvedProductPtr> ResolvedProject::allProducts() const
{
std::vector<ResolvedProductPtr> productList = products;
- for (const ResolvedProjectConstPtr &subProject : qAsConst(subProjects))
+ for (const auto &subProject : qAsConst(subProjects))
productList << subProject->allProducts();
return productList;
}
@@ -765,7 +755,7 @@ void SourceWildCards::expandPatterns(Set<QString> &result, const GroupConstPtr &
if (baseDir.startsWith(buildDir))
return;
- dirTimeStamps.push_back({ baseDir, FileInfo(baseDir).lastModified() });
+ dirTimeStamps.emplace_back(baseDir, FileInfo(baseDir).lastModified());
QStringList changed_parts = parts;
bool recursive = false;
@@ -810,7 +800,7 @@ void SourceWildCards::expandPatterns(Set<QString> &result, const GroupConstPtr &
expandPatterns(result, group, changed_parts, filePath, buildDir);
} else {
if (parentDir != baseDir)
- dirTimeStamps.push_back({parentDir, FileInfo(baseDir).lastModified()});
+ dirTimeStamps.emplace_back(parentDir, FileInfo(baseDir).lastModified());
result += QDir::cleanPath(filePath);
}
}
@@ -867,6 +857,7 @@ bool operator==(const SourceArtifactInternal &sa1, const SourceArtifactInternal
&& sa1.fileTags == sa2.fileTags
&& sa1.overrideFileTags == sa2.overrideFileTags
&& sa1.targetOfModule == sa2.targetOfModule
+ && !sa1.properties == !sa2.properties
&& *sa1.properties == *sa2.properties;
}
diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h
index 65879dd56..bbd851333 100644
--- a/src/lib/corelib/language/language.h
+++ b/src/lib/corelib/language/language.h
@@ -99,7 +99,7 @@ public:
private:
FileTagger(const QStringList &patterns, FileTags fileTags, int priority);
- FileTagger() {}
+ FileTagger() = default;
void setPatterns(const QStringList &patterns);
@@ -139,20 +139,20 @@ public:
}
private:
- Probe() {}
- Probe(const QString &globalId,
+ Probe() = default;
+ Probe(QString globalId,
const CodeLocation &location,
bool condition,
- const QString &configureScript,
- const QVariantMap &properties,
- const QVariantMap &initialProperties,
- const std::vector<QString> &importedFilesUsed)
- : m_globalId(globalId)
+ QString configureScript,
+ QVariantMap properties,
+ QVariantMap initialProperties,
+ std::vector<QString> importedFilesUsed)
+ : m_globalId(std::move(globalId))
, m_location(location)
- , m_configureScript(configureScript)
- , m_properties(properties)
- , m_initialProperties(initialProperties)
- , m_importedFilesUsed(importedFilesUsed)
+ , m_configureScript(std::move(configureScript))
+ , m_properties(std::move(properties))
+ , m_initialProperties(std::move(initialProperties))
+ , m_importedFilesUsed(std::move(importedFilesUsed))
, m_condition(condition)
{}
@@ -378,7 +378,7 @@ public:
}
private:
- ResolvedModule() {}
+ ResolvedModule() = default;
};
bool operator==(const ResolvedModule &m1, const ResolvedModule &m2);
inline bool operator!=(const ResolvedModule &m1, const ResolvedModule &m2) { return !(m1 == m2); }
diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp
index 9c8f9da1d..56fbc198e 100644
--- a/src/lib/corelib/language/moduleloader.cpp
+++ b/src/lib/corelib/language/moduleloader.cpp
@@ -71,20 +71,24 @@
#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
+#include <QtCore/qglobalstatic.h>
#include <QtCore/qdiriterator.h>
#include <QtCore/qjsondocument.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qtemporaryfile.h>
#include <QtCore/qtextstream.h>
+#include <QtCore/qthreadstorage.h>
#include <QtScript/qscriptvalueiterator.h>
#include <algorithm>
+#include <memory>
#include <utility>
namespace qbs {
namespace Internal {
-static QString shadowProductPrefix() { return QStringLiteral("__shadow__"); }
+using MultiplexConfigurationByIdTable = QThreadStorage<QHash<QString, QVariantMap> >;
+Q_GLOBAL_STATIC(MultiplexConfigurationByIdTable, multiplexConfigurationsById);
static void handlePropertyError(const ErrorInfo &error, const SetupProjectParameters &params,
Logger &logger)
@@ -94,6 +98,20 @@ static void handlePropertyError(const ErrorInfo &error, const SetupProjectParame
logger.printWarning(error);
}
+static bool multiplexConfigurationIntersects(const QVariantMap &lhs, const QVariantMap &rhs)
+{
+ QBS_CHECK(!lhs.isEmpty() && !rhs.isEmpty());
+
+ for (auto lhsProperty = lhs.constBegin(); lhsProperty != lhs.constEnd(); lhsProperty++) {
+ const auto rhsProperty = rhs.find(lhsProperty.key());
+ const bool isCommonProperty = rhsProperty != rhs.constEnd();
+ if (isCommonProperty && lhsProperty.value() != rhsProperty.value())
+ return false;
+ }
+
+ return true;
+}
+
class ModuleLoader::ItemModuleList : public QList<Item::Module> {};
static QString probeGlobalId(Item *probe)
@@ -292,7 +310,7 @@ ModuleLoaderResult ModuleLoader::load(const SetupProjectParameters &parameters)
= m_elapsedTimePropertyChecking = 0;
m_elapsedTimeProbes = 0;
m_probesEncountered = m_probesRun = m_probesCachedCurrent = m_probesCachedOld = 0;
- m_settings.reset(new Settings(parameters.settingsDirectory()));
+ m_settings = std::make_unique<Settings>(parameters.settingsDirectory());
const auto keys = m_parameters.overriddenValues().keys();
for (const QString &key : keys) {
@@ -381,9 +399,9 @@ class PropertyDeclarationCheck : public ValueHandler
Logger &m_logger;
public:
PropertyDeclarationCheck(const Set<Item *> &disabledItems,
- const SetupProjectParameters &params, Logger &logger)
+ SetupProjectParameters params, Logger &logger)
: m_disabledItems(disabledItems)
- , m_params(params)
+ , m_params(std::move(params))
, m_logger(logger)
{
}
@@ -616,7 +634,7 @@ void ModuleLoader::handleTopLevelProject(ModuleLoaderResult *loadResult, Item *p
for (ProductContext * const p : productSorter.sortedProducts()) {
try {
handleProduct(p);
- if (p->name.startsWith(shadowProductPrefix()))
+ if (p->name.startsWith(StringConstants::shadowProductPrefix()))
tlp.probes << p->info.probes;
} catch (const ErrorInfo &err) {
handleProductError(err, p);
@@ -688,6 +706,9 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult,
m_qbsVersion.toString()));
}
+ for (Item * const child : projectItem->children())
+ child->setScope(projectContext.scope);
+
resolveProbes(&dummyProductContext, projectItem);
projectContext.topLevelProject->probes << dummyProductContext.info.probes;
@@ -695,7 +716,6 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult,
QList<Item *> multiplexedProducts;
for (Item * const child : projectItem->children()) {
- child->setScope(projectContext.scope);
if (child->type() == ItemType::Product)
multiplexedProducts << multiplexProductItem(&dummyProductContext, child);
}
@@ -762,9 +782,24 @@ QString ModuleLoader::MultiplexInfo::toIdString(size_t row) const
const VariantValuePtr &mpvalue = mprow.at(column);
multiplexConfiguration.insert(propertyName, mpvalue->value());
}
- return QString::fromUtf8(QJsonDocument::fromVariant(multiplexConfiguration)
- .toJson(QJsonDocument::Compact)
- .toBase64());
+ QString id = QString::fromUtf8(QJsonDocument::fromVariant(multiplexConfiguration)
+ .toJson(QJsonDocument::Compact)
+ .toBase64());
+ // Cache for later use in:multiplexIdToVariantMap()
+ multiplexConfigurationsById->localData().insert(id, multiplexConfiguration);
+ return id;
+}
+
+QVariantMap ModuleLoader::MultiplexInfo::multiplexIdToVariantMap(const QString &multiplexId)
+{
+ if (multiplexId.isEmpty())
+ return QVariantMap();
+
+ QVariantMap result = multiplexConfigurationsById->localData().value(multiplexId);
+ // We assume that MultiplexInfo::toIdString() has been called for this
+ // particular multiplex configuration.
+ QBS_CHECK(!result.isEmpty());
+ return result;
}
void qbs::Internal::ModuleLoader::ModuleLoader::dump(const ModuleLoader::MultiplexInfo &mpi)
@@ -1085,66 +1120,111 @@ void ModuleLoader::adjustDependenciesForMultiplexing(const ProductContext &produ
StringConstants::profilesProperty(), &profilesPropertyIsSet);
const auto productRange = m_productsByName.equal_range(name);
- std::vector<const ProductContext *> dependencies;
+ if (productRange.first == productRange.second) {
+ // Dependency is a module. Nothing to adjust.
+ return;
+ }
+
+ std::vector<const ProductContext *> multiplexedDependencies;
bool hasNonMultiplexedDependency = false;
for (auto it = productRange.first; it != productRange.second; ++it) {
- if (!it->second->multiplexConfigurationId.isEmpty()) {
- dependencies.push_back(it->second);
- if (productIsMultiplexed && !profilesPropertyIsSet)
- break;
- } else {
+ if (!it->second->multiplexConfigurationId.isEmpty())
+ multiplexedDependencies.push_back(it->second);
+ else
hasNonMultiplexedDependency = true;
- break;
- }
}
+ bool hasMultiplexedDependencies = !multiplexedDependencies.empty();
// These are the allowed cases:
// (1) Normal dependency with no multiplexing whatsoever.
// (2) Both product and dependency are multiplexed.
+ // (2a) The profiles property is not set, we want to depend on the best
+ // matching variant.
+ // (2b) The profiles property is set, we want to depend on all variants
+ // with a matching profile.
// (3) The product is not multiplexed, but the dependency is.
- // (3a) The dependency has an aggregator. We want to depend on the aggregator.
- // (3b) The dependency does not have an aggregator. We want to depend on all the
- // multiplexed variants.
- // (4) The product is multiplexed, but the dependency is not. This case is implicitly
- // handled, because we don't have to adapt any Depends items.
+ // (3a) The profiles property is not set, the dependency has an aggregator.
+ // We want to depend on the aggregator.
+ // (3b) The profiles property is not set, the dependency does not have an
+ // aggregator. We want to depend on all the multiplexed variants.
+ // (3c) The profiles property is set, we want to depend on all variants
+ // with a matching profile regardless of whether an aggregator exists or not.
+ // (4) The product is multiplexed, but the dependency is not. We don't have to adapt
+ // any Depends items.
// (5) The product is a "shadow product". In that case, we know which product
// it should have a dependency on, and we make sure we depend on that.
- // (1) and (3a)
- if (!productIsMultiplexed && hasNonMultiplexedDependency)
+ // (1) and (4)
+ if (!hasMultiplexedDependencies)
+ return;
+
+ // (3a)
+ if (!productIsMultiplexed && hasNonMultiplexedDependency && !profilesPropertyIsSet)
return;
QStringList multiplexIds;
const ShadowProductInfo shadowProductInfo = getShadowProductInfo(product);
const bool isShadowProduct = shadowProductInfo.first && shadowProductInfo.second == name;
- for (const ProductContext *dependency : dependencies) {
+ const auto productMultiplexConfig =
+ MultiplexInfo::multiplexIdToVariantMap(product.multiplexConfigurationId);
+
+ for (const ProductContext *dependency : multiplexedDependencies) {
const bool depMatchesShadowProduct = isShadowProduct
&& dependency->item == product.item->parent();
const QString depMultiplexId = dependency->multiplexConfigurationId;
if (depMatchesShadowProduct) { // (5)
dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(),
VariantValue::create(depMultiplexId));
- multiplexIds.clear();
- break;
- }
- if (productIsMultiplexed && !profilesPropertyIsSet) { // (2)
- const ValuePtr &multiplexId = product.item->property(
- StringConstants::multiplexConfigurationIdProperty());
- dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(),
- multiplexId);
- break;
+ return;
}
+ if (productIsMultiplexed && !profilesPropertyIsSet) { // 2a
+ if (dependency->multiplexConfigurationId == product.multiplexConfigurationId) {
+ const ValuePtr &multiplexId = product.item->property(
+ StringConstants::multiplexConfigurationIdProperty());
+ dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(),
+ multiplexId);
+ return;
- // (3b) (or (2) if Depends.profiles is set).
- const bool profileMatch = !profilesPropertyIsSet || profiles.empty()
- || profiles.contains(dependency->profileName);
- if (profileMatch)
- multiplexIds << depMultiplexId;
- }
- if (!multiplexIds.empty()) {
- dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(),
- VariantValue::create(multiplexIds));
+ } else {
+ // Otherwise collect partial matches and decide later
+ const auto dependencyMultiplexConfig =
+ MultiplexInfo::multiplexIdToVariantMap(dependency->multiplexConfigurationId);
+
+ if (multiplexConfigurationIntersects(dependencyMultiplexConfig, productMultiplexConfig))
+ multiplexIds << dependency->multiplexConfigurationId;
+ }
+ } else {
+ // (2b), (3b) or (3c)
+ const bool profileMatch = !profilesPropertyIsSet || profiles.empty()
+ || profiles.contains(dependency->profileName);
+ if (profileMatch)
+ multiplexIds << depMultiplexId;
+ }
}
+ if (multiplexIds.empty()) {
+ const QString productName = ResolvedProduct::fullDisplayName(
+ product.name, product.multiplexConfigurationId);
+ throw ErrorInfo(Tr::tr("Dependency from product '%1' to product '%2' not fulfilled. "
+ "There are no eligible multiplex candidates.").arg(productName,
+ name),
+ dependsItem->location());
+ }
+
+ // In case of (2a), at most 1 match is allowed
+ if (productIsMultiplexed && !profilesPropertyIsSet && multiplexIds.size() > 1) {
+ const QString productName = ResolvedProduct::fullDisplayName(
+ product.name, product.multiplexConfigurationId);
+ QStringList candidateNames;
+ for (const auto &id : qAsConst(multiplexIds))
+ candidateNames << ResolvedProduct::fullDisplayName(name, id);
+ throw ErrorInfo(Tr::tr("Dependency from product '%1' to product '%2' is ambiguous. "
+ "Eligible multiplex candidates: %3.").arg(
+ productName, name, candidateNames.join(QLatin1String(", "))),
+ dependsItem->location());
+ }
+
+ dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(),
+ VariantValue::create(multiplexIds));
}
void ModuleLoader::prepareProduct(ProjectContext *projectContext, Item *productItem)
@@ -1216,7 +1296,8 @@ void ModuleLoader::prepareProduct(ProjectContext *projectContext, Item *productI
// evaluate the product's exported properties in isolation in the project resolver.
Item * const importer = Item::create(productItem->pool(), ItemType::Product);
importer->setProperty(QStringLiteral("name"),
- VariantValue::create(shadowProductPrefix() + productContext.name));
+ VariantValue::create(StringConstants::shadowProductPrefix()
+ + productContext.name));
importer->setFile(productItem->file());
importer->setLocation(productItem->location());
importer->setScope(projectContext->scope);
@@ -1281,7 +1362,6 @@ void ModuleLoader::createSortedModuleList(const Item::Module &parentModule, Item
for (const Item::Module &dep : parentModule.item->modules())
createSortedModuleList(dep, modules);
modules.push_back(parentModule);
- return;
}
Item::Modules ModuleLoader::modulesSortedByDependency(const Item *productItem)
@@ -1350,8 +1430,7 @@ void ModuleLoader::handleProduct(ModuleLoader::ProductContext *productContext)
// set by the dependency module's merger (namely, scopes of defining items; see
// ModuleMerger::replaceItemInScopes()).
Item::Modules topSortedModules = modulesSortedByDependency(item);
- for (Item::Module &module : topSortedModules)
- ModuleMerger(m_logger, item, module).start();
+ ModuleMerger::merge(m_logger, item, productContext->name, &topSortedModules);
// Re-sort the modules by name. This is more stable; see QBS-818.
// The list of modules in the product now has the same order as before,
@@ -1585,7 +1664,7 @@ void ModuleLoader::handleSubProject(ModuleLoader::ProjectContext *projectContext
const Item::PropertyMap &overriddenProperties = propertiesItem->properties();
for (Item::PropertyMap::ConstIterator it = overriddenProperties.constBegin();
it != overriddenProperties.constEnd(); ++it) {
- loadedItem->setProperty(it.key(), overriddenProperties.value(it.key()));
+ loadedItem->setProperty(it.key(), it.value());
}
}
@@ -1806,7 +1885,7 @@ ProbeConstPtr ModuleLoader::findCurrentProbe(
bool condition,
const QVariantMap &initialProperties) const
{
- const QList<ProbeConstPtr> &cachedProbes = m_currentProbes.value(location);
+ const std::vector<ProbeConstPtr> &cachedProbes = m_currentProbes.value(location);
for (const ProbeConstPtr &probe : cachedProbes) {
if (probeMatches(probe, condition, initialProperties, QString(), CompareScript::No))
return probe;
@@ -1964,7 +2043,7 @@ bool ModuleLoader::mergeExportItems(const ProductContext &productContext)
productContext.project->topLevelProject->productModules.insert(productContext.name, pmi);
if (hasDependenciesOnProductType)
m_exportsWithDeferredDependsItems.insert(merged);
- return exportItems.size() > 0;
+ return !exportItems.empty();
}
Item *ModuleLoader::loadItemFromFile(const QString &filePath,
@@ -2171,9 +2250,10 @@ void ModuleLoader::setSearchPathsForProduct(ModuleLoader::ProductContext *produc
ModuleLoader::ShadowProductInfo ModuleLoader::getShadowProductInfo(
const ModuleLoader::ProductContext &product) const
{
- const bool isShadowProduct = product.name.startsWith(shadowProductPrefix());
+ const bool isShadowProduct = product.name.startsWith(StringConstants::shadowProductPrefix());
return std::make_pair(isShadowProduct, isShadowProduct
- ? product.name.mid(shadowProductPrefix().size()) : QString());
+ ? product.name.mid(StringConstants::shadowProductPrefix().size())
+ : QString());
}
void ModuleLoader::collectProductsByName(const TopLevelProjectContext &topLevelProject)
@@ -2705,7 +2785,7 @@ void ModuleLoader::resolveParameterDeclarations(const Item *module)
for (Item *param : moduleChildren) {
if (param->type() != ItemType::Parameter)
continue;
- const auto paramDecls = param->propertyDeclarations();
+ const auto &paramDecls = param->propertyDeclarations();
for (auto it = paramDecls.begin(); it != paramDecls.end(); ++it)
decls.insert(it.key(), it.value());
}
@@ -2756,7 +2836,8 @@ QVariantMap ModuleLoader::extractParameters(Item *dependsItem) const
QScriptValue sv = m_evaluator->scriptValue(dependsItem);
try {
result = safeToVariant(sv);
- } catch (ErrorInfo ei) {
+ } catch (const ErrorInfo &exception) {
+ auto ei = exception;
ei.prepend(Tr::tr("Error in dependency parameter."), dependsItem->location());
throw ei;
}
@@ -3024,72 +3105,67 @@ Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext,
const CodeLocation &dependsItemLocation, const QualifiedId &moduleName,
FallbackMode fallbackMode, bool isRequired, Item *moduleInstance)
{
- bool triedToLoadModule = false;
+ auto existingPaths = findExistingModulePaths(m_reader->allSearchPaths(), moduleName);
+
+ if (existingPaths.isEmpty()) { // no suitable names found, try to use providers
+ 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";
+ existingPaths = findExistingModulePaths(m_reader->allSearchPaths(), moduleName);
+ }
+ }
+
const QString fullName = moduleName.toString();
+ bool triedToLoadModule = false;
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());
- while (dirIter.hasNext())
- moduleFileNames += dirIter.next();
-
- m_moduleDirListCache.insert(dirPath, moduleFileNames);
- }
- for (const QString &filePath : qAsConst(moduleFileNames)) {
- triedToLoadModule = true;
+ candidates.reserve(size_t(existingPaths.size()));
+ for (int i = 0; i < existingPaths.size(); ++i) {
+ const QString &dirPath = existingPaths.at(i);
+ QStringList &moduleFileNames = getModuleFileNames(dirPath);
+ for (auto it = moduleFileNames.begin(); it != moduleFileNames.end(); ) {
+ const QString &filePath = *it;
+ bool triedToLoad = true;
Item *module = loadModuleFile(productContext, fullName, isBaseModule(moduleName),
- filePath, &triedToLoadModule, moduleInstance);
+ filePath, &triedToLoad, moduleInstance);
if (module)
candidates.emplace_back(module, 0, i);
- if (!triedToLoadModule)
- m_moduleDirListCache[dirPath].removeOne(filePath);
+ if (!triedToLoad)
+ it = moduleFileNames.erase(it);
+ else
+ ++it;
+ triedToLoadModule = triedToLoadModule || triedToLoad;
}
}
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, QStringLiteral("not found"), nullptr);
- if (Q_UNLIKELY(triedToLoadModule))
+ if (Q_UNLIKELY(triedToLoadModule)) {
throw ErrorInfo(Tr::tr("Module %1 could not be loaded.").arg(fullName),
dependsItemLocation);
+ }
return nullptr;
}
@@ -3119,6 +3195,17 @@ Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext,
return moduleItem;
}
+QStringList &ModuleLoader::getModuleFileNames(const QString &dirPath)
+{
+ QStringList &moduleFileNames = m_moduleDirListCache[dirPath];
+ if (moduleFileNames.empty()) {
+ QDirIterator dirIter(dirPath, StringConstants::qbsFileWildcards());
+ while (dirIter.hasNext())
+ moduleFileNames += dirIter.next();
+ }
+ return moduleFileNames;
+}
+
// returns QVariant::Invalid for types that do not need conversion
static QVariant::Type variantType(PropertyDeclaration::Type t)
{
@@ -3227,7 +3314,7 @@ Item *ModuleLoader::getModulePrototype(ProductContext *productContext,
}
}
Item * const module = loadItemFromFile(filePath, CodeLocation());
- prototypeList.push_back(std::make_pair(module, productContext->profileName));
+ prototypeList.emplace_back(module, productContext->profileName);
if (module->type() != ItemType::Module) {
qCDebug(lcModuleLoader).nospace()
<< "Alleged module " << fullModuleName << " has type '"
@@ -3285,6 +3372,9 @@ void ModuleLoader::setupBaseModulePrototype(Item *prototype)
prototype->setProperty(QStringLiteral("hostPlatform"),
VariantValue::create(QString::fromStdString(
HostOsInfo::hostOSIdentifier())));
+ prototype->setProperty(QStringLiteral("hostArchitecture"),
+ VariantValue::create(QString::fromStdString(
+ HostOsInfo::hostOSArchitecture())));
prototype->setProperty(QStringLiteral("libexecPath"),
VariantValue::create(m_parameters.libexecPath()));
@@ -3327,7 +3417,7 @@ static std::vector<std::pair<QualifiedId, ItemValuePtr>> instanceItemProperties(
if (itemValue->item()->type() == ItemType::ModulePrefix)
f(itemValue->item());
else
- result.push_back(std::make_pair(name, itemValue));
+ result.emplace_back(name, itemValue);
name.removeLast();
}
};
@@ -3496,7 +3586,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It
if (Q_UNLIKELY(configureScript->sourceCode() == StringConstants::undefinedValue()))
throw ErrorInfo(Tr::tr("Probe.configure must be set."), probe->location());
using ProbeProperty = std::pair<QString, QScriptValue>;
- QList<ProbeProperty> probeBindings;
+ std::vector<ProbeProperty> probeBindings;
QVariantMap initialProperties;
for (Item *obj = probe; obj; obj = obj->prototype()) {
const Item::PropertyMap &props = obj->properties();
@@ -3505,7 +3595,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It
if (name == StringConstants::configureProperty())
continue;
const QScriptValue value = m_evaluator->value(probe, name);
- probeBindings += ProbeProperty(name, value);
+ probeBindings << ProbeProperty(name, value);
if (name != StringConstants::conditionProperty())
initialProperties.insert(name, value.toVariant());
}
@@ -3516,7 +3606,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It
const QString &sourceCode = configureScript->sourceCode().toString();
ProbeConstPtr resolvedProbe;
if (parent->type() == ItemType::Project
- || productContext->name.startsWith(shadowProductPrefix())) {
+ || productContext->name.startsWith(StringConstants::shadowProductPrefix())) {
resolvedProbe = findOldProjectProbe(probeId, condition, initialProperties, sourceCode);
} else {
const QString &uniqueProductName = productContext->uniqueName();
@@ -3544,7 +3634,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It
engine->currentContext()->pushScope(fileCtxScopes.fileScope);
engine->currentContext()->pushScope(fileCtxScopes.importScope);
configureScope = engine->newObject();
- for (const ProbeProperty &b : qAsConst(probeBindings))
+ for (const ProbeProperty &b : probeBindings)
configureScope.setProperty(b.first, b.second);
engine->currentContext()->pushScope(configureScope);
engine->clearRequestedProperties();
@@ -3560,7 +3650,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It
importedFilesUsedInConfigure = resolvedProbe->importedFilesUsed();
}
QVariantMap properties;
- for (const ProbeProperty &b : qAsConst(probeBindings)) {
+ for (const ProbeProperty &b : probeBindings) {
QVariant newValue;
if (resolvedProbe) {
newValue = resolvedProbe->properties().value(b.first);
@@ -3678,12 +3768,36 @@ QString ModuleLoader::findExistingModulePath(const QString &searchPath,
const QualifiedId &moduleName)
{
QString dirPath = searchPath + QStringLiteral("/modules");
+
+ // isFileCaseCorrect is a very expensive call on macOS, so we cache the value for the
+ // modules and search paths we've already processed
+ auto &moduleInfo = m_existingModulePathCache[{searchPath, moduleName}];
+ if (moduleInfo.first) // poor man's std::optional<QString>
+ return moduleInfo.second;
+
for (const QString &moduleNamePart : moduleName) {
dirPath = FileInfo::resolvePath(dirPath, moduleNamePart);
- if (!FileInfo::exists(dirPath) || !FileInfo::isFileCaseCorrect(dirPath))
- return {};
+ if (!FileInfo::exists(dirPath) || !FileInfo::isFileCaseCorrect(dirPath)) {
+ moduleInfo.first = true;
+ return moduleInfo.second = QString();
+ }
}
- return dirPath;
+
+ moduleInfo.first = true;
+ return moduleInfo.second = dirPath;
+}
+
+QStringList ModuleLoader::findExistingModulePaths(
+ const QStringList &searchPaths, const QualifiedId &moduleName)
+{
+ QStringList result;
+ result.reserve(searchPaths.size());
+ for (const auto &path: searchPaths) {
+ const QString dirPath = findExistingModulePath(path, moduleName);
+ if (!dirPath.isEmpty())
+ result.append(dirPath);
+ }
+ return result;
}
QVariantMap ModuleLoader::moduleProviderConfig(ModuleLoader::ProductContext &product)
@@ -3769,6 +3883,7 @@ ModuleLoader::ModuleProviderResult ModuleLoader::findModuleProvider(const Qualif
const QString searchPathBaseDir = ModuleProviderInfo::outputDirPath(projectBuildDir, name);
const QVariant moduleConfig = moduleProviderConfig(product).value(name.toString());
QTextStream stream(&dummyItemFile);
+ using Qt::endl;
stream.setCodec("UTF-8");
stream << "import qbs.FileInfo" << endl;
stream << "import qbs.Utilities" << endl;
diff --git a/src/lib/corelib/language/moduleloader.h b/src/lib/corelib/language/moduleloader.h
index 85a2467f2..942f93c83 100644
--- a/src/lib/corelib/language/moduleloader.h
+++ b/src/lib/corelib/language/moduleloader.h
@@ -218,7 +218,7 @@ private:
{
Q_DISABLE_COPY(TopLevelProjectContext)
public:
- TopLevelProjectContext() {}
+ TopLevelProjectContext() = default;
~TopLevelProjectContext() { qDeleteAll(projects); }
std::vector<ProjectContext *> projects;
@@ -252,6 +252,7 @@ private:
VariantValuePtr multiplexedType;
QString toIdString(size_t row) const;
+ static QVariantMap multiplexIdToVariantMap(const QString &multiplexId);
};
void dump(const MultiplexInfo &mpi);
@@ -317,6 +318,7 @@ private:
Item *searchAndLoadModuleFile(ProductContext *productContext,
const CodeLocation &dependsItemLocation, const QualifiedId &moduleName,
FallbackMode fallbackMode, bool isRequired, Item *moduleInstance);
+ QStringList &getModuleFileNames(const QString &dirPath);
Item *loadModuleFile(ProductContext *productContext, const QString &fullModuleName,
bool isBaseModule, const QString &filePath, bool *triedToLoad, Item *moduleInstance);
Item *getModulePrototype(ProductContext *productContext, const QString &fullModuleName,
@@ -337,8 +339,9 @@ private:
QStringList readExtraSearchPaths(Item *item, bool *wasSet = nullptr);
void copyProperties(const Item *sourceProject, Item *targetProject);
Item *wrapInProjectIfNecessary(Item *item);
- static QString findExistingModulePath(const QString &searchPath,
- const QualifiedId &moduleName);
+ QString findExistingModulePath(const QString &searchPath, const QualifiedId &moduleName);
+ QStringList findExistingModulePaths(
+ const QStringList &searchPaths, const QualifiedId &moduleName);
enum class ModuleProviderLookup { Regular, Fallback };
struct ModuleProviderResult
@@ -411,6 +414,7 @@ private:
ItemReader *m_reader;
Evaluator *m_evaluator;
QMap<QString, QStringList> m_moduleDirListCache;
+ QHash<std::pair<QString, QualifiedId>, std::pair<bool, QString>> m_existingModulePathCache;
// The keys are file paths, the values are module prototype items accompanied by a profile.
std::unordered_map<QString, std::vector<std::pair<Item *, QString>>> m_modulePrototypes;
@@ -425,8 +429,8 @@ private:
struct DependsChainEntry
{
- DependsChainEntry(const QualifiedId &name, const CodeLocation &location)
- : name(name), location(location)
+ DependsChainEntry(QualifiedId name, const CodeLocation &location)
+ : name(std::move(name)), location(location)
{
}
@@ -437,10 +441,10 @@ private:
class DependsChainManager;
std::vector<DependsChainEntry> m_dependsChain;
- QHash<QString, QList<ProbeConstPtr>> m_oldProjectProbes;
+ QHash<QString, std::vector<ProbeConstPtr>> m_oldProjectProbes;
QHash<QString, std::vector<ProbeConstPtr>> m_oldProductProbes;
FileTime m_lastResolveTime;
- QHash<CodeLocation, QList<ProbeConstPtr>> m_currentProbes;
+ QHash<CodeLocation, std::vector<ProbeConstPtr>> m_currentProbes;
QVariantMap m_storedProfiles;
QVariantMap m_localProfiles;
std::multimap<QString, const ProductContext *> m_productsByName;
diff --git a/src/lib/corelib/language/modulemerger.cpp b/src/lib/corelib/language/modulemerger.cpp
index 053e90d53..c5deaae04 100644
--- a/src/lib/corelib/language/modulemerger.cpp
+++ b/src/lib/corelib/language/modulemerger.cpp
@@ -50,15 +50,18 @@
namespace qbs {
namespace Internal {
-ModuleMerger::ModuleMerger(Logger &logger, Item *root, Item::Module &moduleToMerge)
+ModuleMerger::ModuleMerger(Logger &logger, Item *productItem, const QString &productName,
+ const Item::Modules::iterator &modulesBegin,
+ const Item::Modules::iterator &modulesEnd)
: m_logger(logger)
- , m_rootItem(root)
- , m_mergedModule(moduleToMerge)
- , m_required(moduleToMerge.required)
- , m_isBaseModule(moduleToMerge.name.first() == StringConstants::qbsModule())
- , m_versionRange(moduleToMerge.versionRange)
+ , m_productItem(productItem)
+ , m_mergedModule(*modulesBegin)
+ , m_isBaseModule(m_mergedModule.name.first() == StringConstants::qbsModule())
+ , m_isShadowProduct(productName.startsWith(StringConstants::shadowProductPrefix()))
+ , m_modulesBegin(std::next(modulesBegin))
+ , m_modulesEnd(modulesEnd)
{
- QBS_CHECK(moduleToMerge.item->type() == ItemType::ModuleInstance);
+ QBS_CHECK(modulesBegin->item->type() == ItemType::ModuleInstance);
}
void ModuleMerger::replaceItemInValues(QualifiedId moduleName, Item *containerItem, Item *toReplace)
@@ -83,48 +86,39 @@ void ModuleMerger::replaceItemInValues(QualifiedId moduleName, Item *containerIt
}
}
-void ModuleMerger::replaceItemInScopes(Item *toReplace)
-{
- // In insertProperties(), we potentially call setDefiningItem() with the "wrong"
- // (to-be-replaced) module instance as an argument. If such module instances
- // are dependencies of other modules, they have the depending module's instance
- // as their "instance scope", which is the scope of their scope. This function takes
- // care that the "wrong" definingItem of values in sub-modules still has the "right"
- // instance scope, namely our merged module instead of some other instance.
- for (const Item::Module &module : toReplace->modules()) {
- for (const ValuePtr &property : module.item->properties()) {
- ValuePtr v = property;
- do {
- if (v->definingItem() && v->definingItem()->scope()
- && v->definingItem()->scope()->scope() == toReplace) {
- v->definingItem()->scope()->setScope(m_mergedModule.item);
- }
- v = v->next();
- } while (v);
- }
- }
-}
-
void ModuleMerger::start()
{
+ // Iterate over any module that our product depends on. These modules
+ // may depend on m_mergedModule and contribute property assignments.
+ Item::PropertyMap props;
+ for (auto module = m_modulesBegin; module != m_modulesEnd; module++)
+ mergeModule(&props, *module);
+
+ // Module property assignments in the product have the highest priority
+ // and are thus prepended.
Item::Module m;
- m.item = m_rootItem;
- const Item::PropertyMap props = dfs(m, Item::PropertyMap());
- if (m_required)
- m_mergedModule.required = true;
- m_mergedModule.versionRange.narrowDown(m_versionRange);
- Item::PropertyMap mergedProps = m_mergedModule.item->properties();
+ m.item = m_productItem;
+ mergeModule(&props, m);
+ // The module's prototype is the essential unmodified module as loaded
+ // from the cache.
Item *moduleProto = m_mergedModule.item->prototype();
while (moduleProto->prototype())
moduleProto = moduleProto->prototype();
+ // The prototype item might contain default values which get appended in
+ // case of list properties. Scalar properties will only be set if not
+ // already specified above.
+ Item::PropertyMap mergedProps = m_mergedModule.item->properties();
for (auto it = props.constBegin(); it != props.constEnd(); ++it) {
appendPrototypeValueToNextChain(moduleProto, it.key(), it.value());
mergedProps[it.key()] = it.value();
}
+
m_mergedModule.item->setProperties(mergedProps);
+ // Update all sibling instances of the to-be-merged module to behave identical
+ // to the merged module.
for (Item *moduleInstanceContainer : qAsConst(m_moduleInstanceContainers)) {
Item::Modules modules;
for (const Item::Module &dep : moduleInstanceContainer->modules()) {
@@ -133,11 +127,9 @@ void ModuleMerger::start()
if (isTheModule && m.item != m_mergedModule.item) {
QBS_CHECK(m.item->type() == ItemType::ModuleInstance);
replaceItemInValues(m.name, moduleInstanceContainer, m.item);
- replaceItemInScopes(m.item);
m.item = m_mergedModule.item;
- if (m_required)
- m.required = true;
- m.versionRange.narrowDown(m_versionRange);
+ m.required = m_mergedModule.required;
+ m.versionRange = m_mergedModule.versionRange;
}
modules << m;
}
@@ -145,94 +137,26 @@ void ModuleMerger::start()
}
}
-Item::PropertyMap ModuleMerger::dfs(const Item::Module &m, Item::PropertyMap props)
+void ModuleMerger::mergeModule(Item::PropertyMap *dstProps, const Item::Module &module)
{
- Item *moduleInstance = nullptr;
- size_t numberOfOutprops = m.item->modules().size();
- for (const Item::Module &dep : m.item->modules()) {
- if (dep.name == m_mergedModule.name) {
- --numberOfOutprops;
- moduleInstance = dep.item;
- insertProperties(&props, moduleInstance, ScalarProperties);
- m_moduleInstanceContainers << m.item;
- if (dep.required)
- m_required = true;
- m_versionRange.narrowDown(dep.versionRange);
- break;
- }
- }
-
- std::vector<Item::PropertyMap> outprops;
- outprops.reserve(numberOfOutprops);
- for (const Item::Module &dep : m.item->modules()) {
- if (dep.item != moduleInstance)
- outprops.push_back(dfs(dep, props));
- }
-
- if (!outprops.empty()) {
- props = outprops.front();
- for (size_t i = 1; i < outprops.size(); ++i)
- mergeOutProps(&props, outprops.at(i));
- }
-
- if (moduleInstance)
- insertProperties(&props, moduleInstance, ListProperties);
-
- const bool isNonPresentModule = m.item->type() != ItemType::Product
- && !m.item->isPresentModule();
- return isNonPresentModule ? Item::PropertyMap() : props;
-}
-
-void ModuleMerger::mergeOutProps(Item::PropertyMap *dst, const Item::PropertyMap &src)
-{
- for (auto it = src.constBegin(); it != src.constEnd(); ++it) {
- ValuePtr &v = (*dst)[it.key()];
- if (!v) {
- v = it.value();
- QBS_ASSERT(it.value(), continue);
- continue;
- }
- if (v->type() != Value::JSSourceValueType)
- continue;
- if (it.value()->type() != Value::JSSourceValueType)
- continue;
- // possible conflict
- const JSSourceValuePtr dstVal = std::static_pointer_cast<JSSourceValue>(v);
- JSSourceValuePtr srcVal = std::static_pointer_cast<JSSourceValue>(it.value());
-
- const PropertyDeclaration pd = m_decls.value(srcVal);
- QBS_CHECK(pd.isValid());
-
- if (pd.isScalar()) {
- if (dstVal->sourceCode() != srcVal->sourceCode()) {
- m_logger.qbsWarning() << Tr::tr("Conflicting scalar values at %1 and %2.").arg(
- dstVal->location().toString(),
- srcVal->location().toString());
- // TODO: yield error with a hint how to solve the conflict.
- }
- v = it.value();
- } else {
- lastInNextChain(dstVal)->setNext(srcVal);
- }
- }
-}
+ const Item::Module *dep = findModule(module.item, m_mergedModule.name);
+ if (!dep)
+ return;
-void ModuleMerger::insertProperties(Item::PropertyMap *dst, Item *srcItem, PropertiesType type)
-{
- Set<const Item *> &seenInstances = type == ScalarProperties
- ? m_seenInstancesTopDown : m_seenInstancesBottomUp;
+ const bool mergingProductItem = (module.item == m_productItem);
+ Item *srcItem = dep->item;
Item *origSrcItem = srcItem;
do {
- if (seenInstances.insert(srcItem).second) {
- for (Item::PropertyMap::const_iterator it = srcItem->properties().constBegin();
- it != srcItem->properties().constEnd(); ++it) {
+ if (m_seenInstances.insert(srcItem).second) {
+ for (auto it = srcItem->properties().constBegin();
+ it != srcItem->properties().constEnd(); ++it) {
const ValuePtr &srcVal = it.value();
if (srcVal->type() == Value::ItemValueType)
continue;
if (it.key() == StringConstants::qbsSourceDirPropertyInternal())
continue;
const PropertyDeclaration srcDecl = srcItem->propertyDeclaration(it.key());
- if (!srcDecl.isValid() || srcDecl.isScalar() != (type == ScalarProperties))
+ if (!srcDecl.isValid())
continue;
// Scalar variant values could stem from product multiplexing, in which case
@@ -242,21 +166,51 @@ void ModuleMerger::insertProperties(Item::PropertyMap *dst, Item *srcItem, Prope
continue;
}
- ValuePtr &v = (*dst)[it.key()];
- if (v && type == ScalarProperties)
- continue;
- ValuePtr clonedVal = srcVal->clone();
- m_decls[clonedVal] = srcDecl;
- clonedVal->setDefiningItem(origSrcItem);
- if (v) {
- QBS_CHECK(!clonedVal->next());
- clonedVal->setNext(v);
+ ValuePtr clonedSrcVal = srcVal->clone();
+ clonedSrcVal->setDefiningItem(origSrcItem);
+
+ ValuePtr &dstVal = (*dstProps)[it.key()];
+ if (dstVal) {
+ if (srcDecl.isScalar()) {
+ // Scalar properties get replaced.
+ if ((dstVal->type() == Value::JSSourceValueType)
+ && (srcVal->type() == Value::JSSourceValueType)) {
+ // Warn only about conflicting source code values
+ const JSSourceValuePtr dstJsVal =
+ std::static_pointer_cast<JSSourceValue>(dstVal);
+ const JSSourceValuePtr srcJsVal =
+ std::static_pointer_cast<JSSourceValue>(srcVal);
+ const bool overriddenInProduct =
+ m_mergedModule.item->properties().contains(it.key());
+
+ if (dstJsVal->sourceCode() != srcJsVal->sourceCode()
+ && !mergingProductItem && !overriddenInProduct
+ && !m_isShadowProduct) {
+ m_logger.qbsWarning()
+ << Tr::tr("Conflicting scalar values at %1 and %2.").arg(
+ dstJsVal->location().toString(),
+ srcJsVal->location().toString());
+ }
+ }
+ } else {
+ // List properties get prepended
+ QBS_CHECK(!clonedSrcVal->next());
+ clonedSrcVal->setNext(dstVal);
+ }
}
- v = clonedVal;
+ dstVal = clonedSrcVal;
}
}
srcItem = srcItem->prototype();
} while (srcItem && srcItem->type() == ItemType::ModuleInstance);
+
+ // Update dependency constraints
+ if (dep->required)
+ m_mergedModule.required = true;
+ m_mergedModule.versionRange.narrowDown(dep->versionRange);
+
+ // We need to touch the unmerged module instances later once more
+ m_moduleInstanceContainers << module.item;
}
void ModuleMerger::appendPrototypeValueToNextChain(Item *moduleProto, const QString &propertyName,
@@ -288,5 +242,23 @@ ValuePtr ModuleMerger::lastInNextChain(const ValuePtr &v)
return n;
}
+const Item::Module *ModuleMerger::findModule(const Item *item, const QualifiedId &name)
+{
+ for (const auto &module : item->modules()) {
+ if (module.name == name)
+ return &module;
+ }
+ return nullptr;
+}
+
+void ModuleMerger::merge(Logger &logger, Item *product, const QString &productName,
+ Item::Modules *topSortedModules)
+{
+ for (auto it = topSortedModules->begin(); it != topSortedModules->end(); ++it)
+ ModuleMerger(logger, product, productName, it, topSortedModules->end()).start();
+}
+
+
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/modulemerger.h b/src/lib/corelib/language/modulemerger.h
index 3cc3ba08a..469dc86c4 100644
--- a/src/lib/corelib/language/modulemerger.h
+++ b/src/lib/corelib/language/modulemerger.h
@@ -54,32 +54,33 @@ namespace Internal {
class ModuleMerger {
public:
- ModuleMerger(Logger &logger, Item *root, Item::Module &moduleToMerge);
- void start();
+ static void merge(Logger &logger, Item *productItem, const QString &productName,
+ Item::Modules *topSortedModules);
private:
- Item::PropertyMap dfs(const Item::Module &m, Item::PropertyMap props);
- void mergeOutProps(Item::PropertyMap *dst, const Item::PropertyMap &src);
+ ModuleMerger(Logger &logger, Item *productItem, const QString &productName,
+ const Item::Modules::iterator &modulesBegin,
+ const Item::Modules::iterator &modulesEnd);
+
void appendPrototypeValueToNextChain(Item *moduleProto, const QString &propertyName,
const ValuePtr &sv);
- static ValuePtr lastInNextChain(const ValuePtr &v);
-
- enum PropertiesType { ScalarProperties, ListProperties };
- void insertProperties(Item::PropertyMap *dst, Item *srcItem, PropertiesType type);
+ void mergeModule(Item::PropertyMap *props, const Item::Module &m);
void replaceItemInValues(QualifiedId moduleName, Item *containerItem, Item *toReplace);
- void replaceItemInScopes(Item *toReplace);
+ void start();
+
+ static ValuePtr lastInNextChain(const ValuePtr &v);
+ static const Item::Module *findModule(const Item *item, const QualifiedId &name);
Logger &m_logger;
- Item * const m_rootItem;
+ Item * const m_productItem;
Item::Module &m_mergedModule;
Item *m_clonedModulePrototype = nullptr;
- QHash<ValuePtr, PropertyDeclaration> m_decls;
- Set<const Item *> m_seenInstancesTopDown;
- Set<const Item *> m_seenInstancesBottomUp;
+ Set<const Item *> m_seenInstances;
Set<Item *> m_moduleInstanceContainers;
- bool m_required;
const bool m_isBaseModule;
- VersionRange m_versionRange;
+ const bool m_isShadowProduct;
+ const Item::Modules::iterator m_modulesBegin;
+ const Item::Modules::iterator m_modulesEnd;
};
} // namespace Internal
diff --git a/src/lib/corelib/language/moduleproviderinfo.h b/src/lib/corelib/language/moduleproviderinfo.h
index fef9d9765..4f757d3d9 100644
--- a/src/lib/corelib/language/moduleproviderinfo.h
+++ b/src/lib/corelib/language/moduleproviderinfo.h
@@ -55,9 +55,12 @@ 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)
+ ModuleProviderInfo(QualifiedId name, QVariantMap config,
+ QStringList searchPaths, bool transientOutput)
+ : name(std::move(name))
+ , config(std::move(config))
+ , searchPaths(std::move(searchPaths))
+ , transientOutput(transientOutput)
{}
static QString outputBaseDirName() { return QStringLiteral("genmodules"); }
diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp
index 049472310..fd6063381 100644
--- a/src/lib/corelib/language/projectresolver.cpp
+++ b/src/lib/corelib/language/projectresolver.cpp
@@ -71,6 +71,7 @@
#include <QtCore/qregexp.h>
#include <algorithm>
+#include <memory>
#include <queue>
namespace qbs {
@@ -126,9 +127,7 @@ ProjectResolver::ProjectResolver(Evaluator *evaluator, ModuleLoaderResult loadRe
QBS_CHECK(FileInfo::isAbsolute(m_setupParams.buildRoot()));
}
-ProjectResolver::~ProjectResolver()
-{
-}
+ProjectResolver::~ProjectResolver() = default;
void ProjectResolver::setProgressObserver(ProgressObserver *observer)
{
@@ -812,7 +811,7 @@ void ProjectResolver::resolveGroupFully(Item *item, ProjectResolver::ProjectCont
group->targetOfModule = moduleProp->value().toString();
ErrorInfo fileError;
if (!patterns.empty()) {
- group->wildcards = std::unique_ptr<SourceWildCards>(new SourceWildCards);
+ group->wildcards = std::make_unique<SourceWildCards>();
SourceWildCards *wildcards = group->wildcards.get();
wildcards->group = group.get();
wildcards->excludePatterns = m_evaluator->stringListValue(
@@ -988,7 +987,7 @@ void ProjectResolver::resolveShadowProduct(Item *item, ProjectResolver::ProjectC
try {
adaptExportedPropertyValues(item);
} catch (const ErrorInfo &) {}
- m_productExportInfo.push_back(std::make_pair(m_productContext->product, item));
+ m_productExportInfo.emplace_back(m_productContext->product, item);
}
void ProjectResolver::setupExportedProperties(const Item *item, const QString &namePrefix,
@@ -1460,7 +1459,7 @@ void ProjectResolver::matchArtifactProperties(const ResolvedProductPtr &product,
const std::vector<SourceArtifactPtr> &artifacts)
{
for (const SourceArtifactPtr &artifact : artifacts) {
- for (const ArtifactPropertiesConstPtr &artifactProperties : product->artifactProperties) {
+ for (const auto &artifactProperties : product->artifactProperties) {
if (!artifact->isTargetOfModule()
&& artifact->fileTags.intersects(artifactProperties->fileTagsFilter())) {
artifact->properties = artifactProperties->propertyMap();
diff --git a/src/lib/corelib/language/projectresolver.h b/src/lib/corelib/language/projectresolver.h
index 428ba144d..a1e24a555 100644
--- a/src/lib/corelib/language/projectresolver.h
+++ b/src/lib/corelib/language/projectresolver.h
@@ -139,9 +139,9 @@ private:
struct ProductDependencyInfo
{
- ProductDependencyInfo(const ResolvedProductPtr &product,
- const QVariantMap &parameters = QVariantMap())
- : product(product), parameters(parameters)
+ ProductDependencyInfo(ResolvedProductPtr product,
+ QVariantMap parameters = QVariantMap())
+ : product(std::move(product)), parameters(std::move(parameters))
{
}
diff --git a/src/lib/corelib/language/property.h b/src/lib/corelib/language/property.h
index 204704672..78061bf6f 100644
--- a/src/lib/corelib/language/property.h
+++ b/src/lib/corelib/language/property.h
@@ -65,9 +65,13 @@ public:
{
}
- Property(const QString &product, const QString &module, const QString &property,
- const QVariant &v, Kind k)
- : productName(product), moduleName(module), propertyName(property), value(v), kind(k)
+ Property(QString product, QString module, QString property,
+ QVariant v, Kind k)
+ : productName(std::move(product))
+ , moduleName(std::move(module))
+ , propertyName(std::move(property))
+ , value(std::move(v))
+ , kind(k)
{
}
diff --git a/src/lib/corelib/language/propertydeclaration.cpp b/src/lib/corelib/language/propertydeclaration.cpp
index 5ea6a3d88..abe6a1626 100644
--- a/src/lib/corelib/language/propertydeclaration.cpp
+++ b/src/lib/corelib/language/propertydeclaration.cpp
@@ -84,20 +84,11 @@ PropertyDeclaration::PropertyDeclaration(const QString &name, Type type,
d->flags = flags;
}
-PropertyDeclaration::PropertyDeclaration(const PropertyDeclaration &other)
- : d(other.d)
-{
-}
+PropertyDeclaration::PropertyDeclaration(const PropertyDeclaration &other) = default;
-PropertyDeclaration::~PropertyDeclaration()
-{
-}
+PropertyDeclaration::~PropertyDeclaration() = default;
-PropertyDeclaration &PropertyDeclaration::operator=(const PropertyDeclaration &other)
-{
- d = other.d;
- return *this;
-}
+PropertyDeclaration &PropertyDeclaration::operator=(const PropertyDeclaration &other) = default;
bool PropertyDeclaration::isValid() const
{
diff --git a/src/lib/corelib/language/propertymapinternal.cpp b/src/lib/corelib/language/propertymapinternal.cpp
index 2a35e2a6a..fe0f672c5 100644
--- a/src/lib/corelib/language/propertymapinternal.cpp
+++ b/src/lib/corelib/language/propertymapinternal.cpp
@@ -58,13 +58,9 @@ namespace Internal {
* \sa ResolvedProduct
* \sa SourceArtifact
*/
-PropertyMapInternal::PropertyMapInternal()
-{
-}
+PropertyMapInternal::PropertyMapInternal() = default;
-PropertyMapInternal::PropertyMapInternal(const PropertyMapInternal &other) : m_value(other.m_value)
-{
-}
+PropertyMapInternal::PropertyMapInternal(const PropertyMapInternal &other) = default;
QVariant PropertyMapInternal::moduleProperty(const QString &moduleName, const QString &key,
bool *isPresent) const
diff --git a/src/lib/corelib/language/qualifiedid.cpp b/src/lib/corelib/language/qualifiedid.cpp
index 5cc315bb1..9eb0e9463 100644
--- a/src/lib/corelib/language/qualifiedid.cpp
+++ b/src/lib/corelib/language/qualifiedid.cpp
@@ -44,9 +44,7 @@
namespace qbs {
namespace Internal {
-QualifiedId::QualifiedId()
-{
-}
+QualifiedId::QualifiedId() = default;
QualifiedId::QualifiedId(const QString &singlePartName)
: QStringList(singlePartName)
diff --git a/src/lib/corelib/language/resolvedfilecontext.h b/src/lib/corelib/language/resolvedfilecontext.h
index 81a3f7472..d783cf725 100644
--- a/src/lib/corelib/language/resolvedfilecontext.h
+++ b/src/lib/corelib/language/resolvedfilecontext.h
@@ -65,7 +65,7 @@ public:
pool.serializationOp<opType>(m_filePath, m_jsExtensions, m_searchPaths, m_jsImports);
}
private:
- ResolvedFileContext() {}
+ ResolvedFileContext() = default;
ResolvedFileContext(const FileContextBase &ctx);
};
diff --git a/src/lib/corelib/language/scriptengine.cpp b/src/lib/corelib/language/scriptengine.cpp
index 7c531e764..e79ec54d7 100644
--- a/src/lib/corelib/language/scriptengine.cpp
+++ b/src/lib/corelib/language/scriptengine.cpp
@@ -478,19 +478,18 @@ QScriptValue ScriptEngine::js_require(QScriptContext *context, QScriptEngine *qt
return context->throwError(
ScriptEngine::tr("require: internal error. No search paths."));
- const QString uri = moduleName;
if (engine->m_logger.debugEnabled()) {
engine->m_logger.qbsDebug()
- << "[require] loading extension " << uri;
+ << "[require] loading extension " << moduleName;
}
- QString uriAsPath = uri;
- uriAsPath.replace(QLatin1Char('.'), QLatin1Char('/'));
+ QString moduleNameAsPath = moduleName;
+ moduleNameAsPath.replace(QLatin1Char('.'), QLatin1Char('/'));
const QStringList searchPaths = engine->m_extensionSearchPathsStack.top();
- const QString dirPath = findExtensionDir(searchPaths, uriAsPath);
+ const QString dirPath = findExtensionDir(searchPaths, moduleNameAsPath);
if (dirPath.isEmpty()) {
- if (uri.startsWith(QStringLiteral("qbs.")))
- return loadInternalExtension(context, engine, uri);
+ if (moduleName.startsWith(QStringLiteral("qbs.")))
+ return loadInternalExtension(context, engine, moduleName);
} else {
QDirIterator dit(dirPath, StringConstants::jsFileWildcards(),
QDir::Files | QDir::Readable);
diff --git a/src/lib/corelib/language/value.cpp b/src/lib/corelib/language/value.cpp
index 656f38874..342fbd89a 100644
--- a/src/lib/corelib/language/value.cpp
+++ b/src/lib/corelib/language/value.cpp
@@ -61,9 +61,7 @@ Value::Value(const Value &other)
{
}
-Value::~Value()
-{
-}
+Value::~Value() = default;
Item *Value::definingItem() const
{
@@ -115,9 +113,7 @@ JSSourceValuePtr JSSourceValue::create(bool createdByPropertiesBlock)
return JSSourceValuePtr(new JSSourceValue(createdByPropertiesBlock));
}
-JSSourceValue::~JSSourceValue()
-{
-}
+JSSourceValue::~JSSourceValue() = default;
ValuePtr JSSourceValue::clone() const
{
@@ -200,7 +196,7 @@ VariantValuePtr VariantValue::create(const QVariant &v)
ValuePtr VariantValue::clone() const
{
- return VariantValuePtr(new VariantValue(*this));
+ return std::make_shared<VariantValue>(*this);
}
const VariantValuePtr &VariantValue::falseValue()
diff --git a/src/lib/corelib/language/value.h b/src/lib/corelib/language/value.h
index f27406f2d..d3a748d92 100644
--- a/src/lib/corelib/language/value.h
+++ b/src/lib/corelib/language/value.h
@@ -151,14 +151,14 @@ public:
struct PropertyData
{
PropertyData() = default;
- PropertyData(const QString &v, const CodeLocation &l) : value(v), location(l) {}
+ PropertyData(QString v, const CodeLocation &l) : value(std::move(v)), location(l) {}
QString value;
CodeLocation location;
};
- Alternative() { }
- Alternative(const PropertyData &c, const PropertyData &o, const JSSourceValuePtr &v)
- : condition(c), overrideListProperties(o), value(v) {}
+ Alternative() = default;
+ Alternative(PropertyData c, PropertyData o, JSSourceValuePtr v)
+ : condition(std::move(c)), overrideListProperties(std::move(o)), value(std::move(v)) {}
Alternative clone() const
{
return Alternative(condition, overrideListProperties,
diff --git a/src/lib/corelib/logging/logger.cpp b/src/lib/corelib/logging/logger.cpp
index 71ca6a96c..2ed29c4c2 100644
--- a/src/lib/corelib/logging/logger.cpp
+++ b/src/lib/corelib/logging/logger.cpp
@@ -50,9 +50,9 @@
#include <QtCore/qvariant.h>
#include <cstdarg>
+#include <cstdio>
#include <mutex>
#include <set>
-#include <stdio.h>
namespace qbs {
namespace Internal {
@@ -183,17 +183,20 @@ LogWriter operator<<(LogWriter w, const QVariant &variant)
LogWriter operator<<(LogWriter w, int n)
{
- return w << QString::number(n);
+ w.write(QString::number(n));
+ return w;
}
LogWriter operator<<(LogWriter w, qint64 n)
{
- return w << QString::number(n);
+ w.write(QString::number(n));
+ return w;
}
LogWriter operator<<(LogWriter w, bool b)
{
- return w << QString::fromLatin1(b ? "true" : "false");
+ w.write(QString::fromLatin1(b ? "true" : "false"));
+ return w;
}
LogWriter operator<<(LogWriter w, const MessageTag &tag)
diff --git a/src/lib/corelib/logging/logger.h b/src/lib/corelib/logging/logger.h
index b0b5dd6f3..389dc7e05 100644
--- a/src/lib/corelib/logging/logger.h
+++ b/src/lib/corelib/logging/logger.h
@@ -70,7 +70,7 @@ public:
// a << chain prints the accumulated data
LogWriter(const LogWriter &other);
~LogWriter();
- const LogWriter &operator=(const LogWriter &other);
+ const LogWriter &operator=(const LogWriter &other); // NOLINT
void write(char c);
void write(const char *str);
@@ -90,7 +90,7 @@ private:
class QBS_EXPORT MessageTag
{
public:
- explicit MessageTag(const QString &tag) : m_tag(tag) {}
+ explicit MessageTag(QString tag) : m_tag(std::move(tag)) {}
const QString &tag() const { return m_tag; }
diff --git a/src/lib/corelib/parser/qmljsast_p.h b/src/lib/corelib/parser/qmljsast_p.h
index 8c6f32140..dcee233da 100644
--- a/src/lib/corelib/parser/qmljsast_p.h
+++ b/src/lib/corelib/parser/qmljsast_p.h
@@ -221,7 +221,7 @@ public:
// NOTE: node destructors are never called,
// instead we block free the memory
// (see the NodePool class)
- virtual ~Node() {}
+ virtual ~Node() = default;
virtual ExpressionNode *expressionCast();
virtual BinaryExpression *binaryExpressionCast();
@@ -245,7 +245,7 @@ public:
class QML_PARSER_EXPORT ExpressionNode: public Node
{
public:
- ExpressionNode() {}
+ ExpressionNode() = default;
ExpressionNode *expressionCast() override;
};
@@ -253,7 +253,7 @@ public:
class QML_PARSER_EXPORT Statement: public Node
{
public:
- Statement() {}
+ Statement() = default;
Statement *statementCast() override;
};
@@ -2303,7 +2303,7 @@ public:
return imports->firstSourceLocation();
else if (members)
return members->firstSourceLocation();
- return SourceLocation();
+ return {};
}
SourceLocation lastSourceLocation() const override
@@ -2312,7 +2312,7 @@ public:
return members->lastSourceLocation();
else if (imports)
return imports->lastSourceLocation();
- return SourceLocation();
+ return {};
}
// attributes
@@ -2519,7 +2519,7 @@ public:
else if (const auto varStmt = cast<const VariableStatement *>(sourceElement))
return varStmt->firstSourceLocation();
- return SourceLocation();
+ return {};
}
SourceLocation lastSourceLocation() const override
@@ -2529,7 +2529,7 @@ public:
else if (const auto varStmt = cast<const VariableStatement *>(sourceElement))
return varStmt->lastSourceLocation();
- return SourceLocation();
+ return {};
}
void accept0(Visitor *visitor) override;
diff --git a/src/lib/corelib/parser/qmljsastvisitor.cpp b/src/lib/corelib/parser/qmljsastvisitor.cpp
index fcb84ec7e..f034a147e 100644
--- a/src/lib/corelib/parser/qmljsastvisitor.cpp
+++ b/src/lib/corelib/parser/qmljsastvisitor.cpp
@@ -42,13 +42,9 @@
namespace QbsQmlJS {
namespace AST {
-Visitor::Visitor()
-{
-}
+Visitor::Visitor() = default;
-Visitor::~Visitor()
-{
-}
+Visitor::~Visitor() = default;
} // namespace AST
} // namespace QbsQmlJS
diff --git a/src/lib/corelib/parser/qmljsengine_p.cpp b/src/lib/corelib/parser/qmljsengine_p.cpp
index 211743190..92ac6452a 100644
--- a/src/lib/corelib/parser/qmljsengine_p.cpp
+++ b/src/lib/corelib/parser/qmljsengine_p.cpp
@@ -117,12 +117,9 @@ double integerFromString(const QString &str, int radix)
}
-Engine::Engine()
- : _lexer(nullptr), _directives(nullptr)
-{ }
+Engine::Engine() = default;
-Engine::~Engine()
-{ }
+Engine::~Engine() = default;
void Engine::setCode(const QString &code)
{ _code = code; }
diff --git a/src/lib/corelib/parser/qmljsengine_p.h b/src/lib/corelib/parser/qmljsengine_p.h
index 6ff53a6e9..c55d525f8 100644
--- a/src/lib/corelib/parser/qmljsengine_p.h
+++ b/src/lib/corelib/parser/qmljsengine_p.h
@@ -59,6 +59,7 @@
#include <QtCore/qstring.h>
#include <set>
+#include <utility>
namespace QbsQmlJS {
@@ -74,8 +75,8 @@ public:
DiagnosticMessage()
: kind(Error) {}
- DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, const QString &message)
- : kind(kind), loc(loc), message(message) {}
+ DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, QString message)
+ : kind(kind), loc(loc), message(std::move(message)) {}
bool isWarning() const
{ return kind == Warning; }
@@ -90,8 +91,8 @@ public:
class QBS_AUTOTEST_EXPORT Engine
{
- Lexer *_lexer;
- Directives *_directives;
+ Lexer *_lexer{nullptr};
+ Directives *_directives{nullptr};
MemoryPool _pool;
QList<AST::SourceLocation> _comments;
QString _extraCode;
diff --git a/src/lib/corelib/parser/qmljslexer.cpp b/src/lib/corelib/parser/qmljslexer.cpp
index dc6ac8a0f..815f1ef0d 100644
--- a/src/lib/corelib/parser/qmljslexer.cpp
+++ b/src/lib/corelib/parser/qmljslexer.cpp
@@ -78,8 +78,8 @@ static QChar convertHex(QChar c1, QChar c2)
static QChar convertUnicode(QChar c1, QChar c2, QChar c3, QChar c4)
{
- return QChar((convertHex(c3.unicode()) << 4) + convertHex(c4.unicode()),
- (convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
+ return {uchar((convertHex(c3.unicode()) << 4) + convertHex(c4.unicode())),
+ uchar((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()))};
}
Lexer::Lexer(Engine *engine)
@@ -178,7 +178,7 @@ int Lexer::lex()
_tokenSpell = QStringRef();
_tokenKind = scanToken();
- _tokenLength = _codePtr - _tokenStartPtr - 1;
+ _tokenLength = int(_codePtr - _tokenStartPtr - 1);
_delimited = false;
_restrictedKeyword = false;
@@ -397,7 +397,8 @@ again:
scanChar();
if (_engine) {
- _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 4,
+ _engine->addComment(tokenOffset() + 2,
+ int(_codePtr - _tokenStartPtr - 1 - 4),
tokenStartLine(), tokenStartColumn() + 2);
}
@@ -412,7 +413,7 @@ again:
scanChar();
}
if (_engine) {
- _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2,
+ _engine->addComment(tokenOffset() + 2, int(_codePtr - _tokenStartPtr - 1 - 2),
tokenStartLine(), tokenStartColumn() + 2);
}
goto again;
@@ -554,7 +555,8 @@ again:
if (_char == QLatin1Char('\n') || _char == QLatin1Char('\\')) {
break;
} else if (_char == quote) {
- _tokenSpell = _engine->midRef(startCode - _code.unicode() - 1, _codePtr - startCode);
+ _tokenSpell = _engine->midRef(
+ int(startCode - _code.unicode() - 1), int(_codePtr - startCode));
scanChar();
return T_STRING_LITERAL;
@@ -706,7 +708,7 @@ again:
if (! identifierWithEscapeChars) {
identifierWithEscapeChars = true;
_tokenText.resize(0);
- _tokenText.insert(0, _tokenStartPtr, _codePtr - _tokenStartPtr - 1);
+ _tokenText.insert(0, _tokenStartPtr, int(_codePtr - _tokenStartPtr - 1));
_validTokenText = true;
}
@@ -719,7 +721,7 @@ again:
return T_ERROR;
}
} else {
- _tokenLength = _codePtr - _tokenStartPtr - 1;
+ _tokenLength = int(_codePtr - _tokenStartPtr - 1);
int kind = T_IDENTIFIER;
@@ -727,10 +729,12 @@ again:
kind = classify(_tokenStartPtr, _tokenLength, _qmlMode);
if (_engine) {
- if (kind == T_IDENTIFIER && identifierWithEscapeChars)
+ if (kind == T_IDENTIFIER && identifierWithEscapeChars) {
_tokenSpell = _engine->newStringRef(_tokenText);
- else
- _tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength);
+ } else {
+ _tokenSpell = _engine->midRef(
+ int(_tokenStartPtr - _code.unicode()), _tokenLength);
+ }
}
return kind;
@@ -891,7 +895,7 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
scanChar();
}
- _tokenLength = _codePtr - _tokenStartPtr - 1;
+ _tokenLength = int(_codePtr - _tokenStartPtr - 1);
return true;
case '\\':
@@ -995,7 +999,7 @@ int Lexer::tokenEndLine() const
int Lexer::tokenEndColumn() const
{
- return _codePtr - _lastLinePtr;
+ return int(_codePtr - _lastLinePtr);
}
QString Lexer::tokenText() const
diff --git a/src/lib/corelib/parser/qmljslexer_p.h b/src/lib/corelib/parser/qmljslexer_p.h
index e9dff1dd4..cf41fb255 100644
--- a/src/lib/corelib/parser/qmljslexer_p.h
+++ b/src/lib/corelib/parser/qmljslexer_p.h
@@ -62,7 +62,7 @@ class Engine;
class QML_PARSER_EXPORT Directives {
public:
- virtual ~Directives() {}
+ virtual ~Directives() = default;
virtual void pragmaLibrary()
{
diff --git a/src/lib/corelib/parser/qmljsmemorypool_p.h b/src/lib/corelib/parser/qmljsmemorypool_p.h
index 897348712..f7de7bbfb 100644
--- a/src/lib/corelib/parser/qmljsmemorypool_p.h
+++ b/src/lib/corelib/parser/qmljsmemorypool_p.h
@@ -154,8 +154,8 @@ class QML_PARSER_EXPORT Managed
void operator = (const Managed &other);
public:
- Managed() {}
- ~Managed() {}
+ Managed() = default;
+ ~Managed() = default;
void *operator new(size_t size, MemoryPool *pool) { return pool->allocate(size); }
void operator delete(void *) {}
diff --git a/src/lib/corelib/parser/qmljsparser.cpp b/src/lib/corelib/parser/qmljsparser.cpp
index 6390c8a9d..d2c87c7cb 100644
--- a/src/lib/corelib/parser/qmljsparser.cpp
+++ b/src/lib/corelib/parser/qmljsparser.cpp
@@ -40,7 +40,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qcoreapplication.h>
-#include <string.h>
+#include <cstring>
#include "qmljsengine_p.h"
#include "qmljslexer_p.h"
@@ -328,7 +328,7 @@ case 26: {
} break;
case 27: {
- const auto node = new (pool) AST::UiObjectInitializer((AST::UiObjectMemberList*)0);
+ const auto node = new (pool) AST::UiObjectInitializer(nullptr);
node->lbraceToken = loc(1);
node->rbraceToken = loc(2);
sym(1).Node = node;
@@ -614,7 +614,7 @@ case 80: {
} break;
case 81: {
- const auto node = new (pool) AST::ArrayLiteral((AST::Elision *) 0);
+ const auto node = new (pool) AST::ArrayLiteral(static_cast<AST::Elision *>(nullptr));
node->lbracketToken = loc(1);
node->rbracketToken = loc(2);
sym(1).Node = node;
@@ -635,8 +635,7 @@ case 83: {
} break;
case 84: {
- const auto node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
- (AST::Elision *) 0);
+ const auto node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (), nullptr);
node->lbracketToken = loc(1);
node->commaToken = loc(3);
node->rbracketToken = loc(4);
@@ -700,7 +699,7 @@ case 89: {
} break;
case 90: {
- sym(1).Node = new (pool) AST::ElementList((AST::Elision *) 0, sym(1).Expression);
+ sym(1).Node = new (pool) AST::ElementList(nullptr, sym(1).Expression);
} break;
case 91: {
@@ -708,8 +707,7 @@ case 91: {
} break;
case 92: {
- const auto node = new (pool) AST::ElementList(sym(1).ElementList,
- (AST::Elision *) 0, sym(3).Expression);
+ const auto node = new (pool) AST::ElementList(sym(1).ElementList, nullptr, sym(3).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
diff --git a/src/lib/corelib/tools/buildoptions.cpp b/src/lib/corelib/tools/buildoptions.cpp
index 75417ab0b..e4e9ba17f 100644
--- a/src/lib/corelib/tools/buildoptions.cpp
+++ b/src/lib/corelib/tools/buildoptions.cpp
@@ -91,19 +91,11 @@ BuildOptions::BuildOptions() : d(new Internal::BuildOptionsPrivate)
{
}
-BuildOptions::BuildOptions(const BuildOptions &other) : d(other.d)
-{
-}
+BuildOptions::BuildOptions(const BuildOptions &other) = default;
-BuildOptions &BuildOptions::operator=(const BuildOptions &other)
-{
- d = other.d;
- return *this;
-}
+BuildOptions &BuildOptions::operator=(const BuildOptions &other) = default;
-BuildOptions::~BuildOptions()
-{
-}
+BuildOptions::~BuildOptions() = default;
/*!
* \brief If non-empty, qbs pretends that only these files have changed.
diff --git a/src/lib/corelib/tools/clangclinfo.cpp b/src/lib/corelib/tools/clangclinfo.cpp
new file mode 100644
index 000000000..4e1022c28
--- /dev/null
+++ b/src/lib/corelib/tools/clangclinfo.cpp
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** 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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "clangclinfo.h"
+
+#include "hostosinfo.h"
+#include "msvcinfo.h"
+#include "stlutils.h"
+
+namespace qbs {
+namespace Internal {
+
+static std::vector<MSVCInstallInfo> compatibleMsvcs(Logger &logger)
+{
+ auto msvcs = MSVCInstallInfo::installedMSVCs(logger);
+ auto filter = [](const MSVCInstallInfo &info)
+ {
+ const auto versions = info.version.split(QLatin1Char('.'));
+ if (versions.empty())
+ return true;
+ bool ok = false;
+ const int major = versions.at(0).toInt(&ok);
+ return !(ok && major >= 15); // support MSVC2017 and above
+ };
+ const auto it = std::remove_if(msvcs.begin(), msvcs.end(), filter);
+ msvcs.erase(it, msvcs.end());
+ for (const auto &msvc: msvcs) {
+ auto vcvarsallPath = msvc.findVcvarsallBat();
+ if (vcvarsallPath.isEmpty())
+ continue;
+ }
+ return msvcs;
+}
+
+static QString findCompatibleVcsarsallBat(const std::vector<MSVCInstallInfo> &msvcs)
+{
+ for (const auto &msvc: msvcs) {
+ const auto vcvarsallPath = msvc.findVcvarsallBat();
+ if (!vcvarsallPath.isEmpty())
+ return vcvarsallPath;
+ }
+ return {};
+}
+
+static QString wow6432Key()
+{
+#ifdef Q_OS_WIN64
+ return QStringLiteral("\\Wow6432Node");
+#else
+ return {};
+#endif
+}
+
+static QString getToolchainInstallPath(const QFileInfo &compiler)
+{
+ return compiler.path(); // 1 level up
+}
+
+QVariantMap ClangClInfo::toVariantMap() const
+{
+ return {
+ {QStringLiteral("toolchainInstallPath"), toolchainInstallPath},
+ {QStringLiteral("vcvarsallPath"), vcvarsallPath},
+ };
+}
+
+ClangClInfo ClangClInfo::fromCompilerFilePath(const QString &path, Logger &logger)
+{
+ const auto compilerName = QStringLiteral("clang-cl");
+ const auto vcvarsallPath = findCompatibleVcsarsallBat(compatibleMsvcs(logger));
+ if (vcvarsallPath.isEmpty()) {
+ logger.qbsWarning()
+ << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.")
+ .arg(compilerName);
+ return {};
+ }
+
+ const auto toolchainInstallPath = getToolchainInstallPath(path);
+ return {toolchainInstallPath, vcvarsallPath};
+}
+
+std::vector<ClangClInfo> ClangClInfo::installedCompilers(
+ const std::vector<QString> &extraPaths, Logger &logger)
+{
+ std::vector<QString> compilerPaths;
+ compilerPaths.reserve(extraPaths.size());
+ std::copy_if(extraPaths.begin(), extraPaths.end(),
+ std::back_inserter(compilerPaths),
+ [](const QString &path){ return !path.isEmpty(); });
+ const auto compilerName = HostOsInfo::appendExecutableSuffix(QStringLiteral("clang-cl"));
+
+ const QSettings registry(
+ QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\LLVM\\LLVM").arg(wow6432Key()),
+ QSettings::NativeFormat);
+ const auto key = QStringLiteral(".");
+ if (registry.contains(key)) {
+ const auto compilerPath = QDir::fromNativeSeparators(registry.value(key).toString())
+ + QStringLiteral("/bin/") + compilerName;
+ if (QFileInfo(compilerPath).exists())
+ compilerPaths.push_back(compilerPath);
+ }
+
+ // this branch can be useful in case user had two LLVM installations (e.g. 32bit & 64bit)
+ // but uninstalled one - in that case, registry will be empty
+ static const char * const envVarCandidates[] = {"ProgramFiles", "ProgramFiles(x86)"};
+ for (const auto &envVar : envVarCandidates) {
+ const auto value
+ = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv(envVar)));
+ const auto compilerPath = value + QStringLiteral("/LLVM/bin/") + compilerName;
+ if (QFileInfo(compilerPath).exists() && !contains(compilerPaths, compilerPath))
+ compilerPaths.push_back(compilerPath);
+ }
+
+ const auto msvcs = compatibleMsvcs(logger);
+ const auto vcvarsallPath = findCompatibleVcsarsallBat(msvcs);
+ if (vcvarsallPath.isEmpty()) {
+ logger.qbsWarning()
+ << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.")
+ .arg(compilerName);
+ return {};
+ }
+
+ std::vector<ClangClInfo> result;
+ result.reserve(compilerPaths.size() + msvcs.size());
+
+ for (const auto &path: compilerPaths)
+ result.push_back({getToolchainInstallPath(path), vcvarsallPath});
+
+ // If we didn't find custom LLVM installation, try to find if it's installed with Visual Studio
+ for (const auto &msvc : msvcs) {
+ const auto compilerPath = QStringLiteral("%1/VC/Tools/Llvm/bin/%2")
+ .arg(msvc.installDir, compilerName);
+ if (QFileInfo(compilerPath).exists()) {
+ const auto vcvarsallPath = msvc.findVcvarsallBat();
+ if (vcvarsallPath.isEmpty()) {
+ logger.qbsWarning()
+ << Tr::tr("Found LLVM in %1, but vcvarsall.bat is missing.")
+ .arg(msvc.installDir);
+ }
+
+ result.push_back({getToolchainInstallPath(compilerPath), vcvarsallPath});
+ }
+ }
+
+ return result;
+}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/lib/corelib/tools/clangclinfo.h b/src/lib/corelib/tools/clangclinfo.h
new file mode 100644
index 000000000..76ae169f2
--- /dev/null
+++ b/src/lib/corelib/tools/clangclinfo.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** 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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QBS_CLANGCLINFO_H
+#define QBS_CLANGCLINFO_H
+
+#include "logging/logger.h"
+
+#include <QtCore/qstring.h>
+
+#include <vector>
+
+namespace qbs {
+namespace Internal {
+
+class ClangClInfo
+{
+public:
+ QString toolchainInstallPath;
+ QString vcvarsallPath;
+
+ bool isEmpty() const { return toolchainInstallPath.isEmpty() && vcvarsallPath.isEmpty(); }
+
+ QBS_EXPORT QVariantMap toVariantMap() const;
+
+ QBS_EXPORT static ClangClInfo fromCompilerFilePath(const QString &path, Logger &logger);
+ QBS_EXPORT static std::vector<ClangClInfo> installedCompilers(
+ const std::vector<QString> &extraPaths, qbs::Internal::Logger &logger);
+};
+
+} // namespace Internal
+} // namespace qbs
+
+#endif // QBS_CLANGCLINFO_H
diff --git a/src/lib/corelib/tools/cleanoptions.cpp b/src/lib/corelib/tools/cleanoptions.cpp
index b888fb1e8..affc9b3f7 100644
--- a/src/lib/corelib/tools/cleanoptions.cpp
+++ b/src/lib/corelib/tools/cleanoptions.cpp
@@ -58,7 +58,7 @@ public:
bool logElapsedTime;
};
-}
+} // namespace Internal
/*!
* \class CleanOptions
@@ -79,23 +79,15 @@ CleanOptions::CleanOptions() : d(new Internal::CleanOptionsPrivate)
{
}
-CleanOptions::CleanOptions(const CleanOptions &other) : d(other.d)
-{
-}
+CleanOptions::CleanOptions(const CleanOptions &other) = default;
CleanOptions::CleanOptions(CleanOptions &&other) Q_DECL_NOEXCEPT = default;
-CleanOptions &CleanOptions::operator=(const CleanOptions &other)
-{
- d = other.d;
- return *this;
-}
+CleanOptions &CleanOptions::operator=(const CleanOptions &other) = default;
CleanOptions &CleanOptions::operator=(CleanOptions &&other) Q_DECL_NOEXCEPT = default;
-CleanOptions::~CleanOptions()
-{
-}
+CleanOptions::~CleanOptions() = default;
/*!
* \brief Returns true iff qbs will not actually remove any files, but just show what would happen.
diff --git a/src/lib/corelib/tools/codelocation.cpp b/src/lib/corelib/tools/codelocation.cpp
index 5eff378e1..542408795 100644
--- a/src/lib/corelib/tools/codelocation.cpp
+++ b/src/lib/corelib/tools/codelocation.cpp
@@ -75,9 +75,7 @@ public:
int column = 0;
};
-CodeLocation::CodeLocation()
-{
-}
+CodeLocation::CodeLocation() = default;
CodeLocation::CodeLocation(const QString &aFilePath, int aLine, int aColumn, bool checkPath)
: d(new CodeLocationPrivate)
@@ -88,19 +86,11 @@ CodeLocation::CodeLocation(const QString &aFilePath, int aLine, int aColumn, boo
d->column = aColumn;
}
-CodeLocation::CodeLocation(const CodeLocation &other) : d(other.d)
-{
-}
+CodeLocation::CodeLocation(const CodeLocation &other) = default;
-CodeLocation &CodeLocation::operator=(const CodeLocation &other)
-{
- d = other.d;
- return *this;
-}
+CodeLocation &CodeLocation::operator=(const CodeLocation &other) = default;
-CodeLocation::~CodeLocation()
-{
-}
+CodeLocation::~CodeLocation() = default;
QString CodeLocation::filePath() const
{
diff --git a/src/lib/corelib/tools/error.cpp b/src/lib/corelib/tools/error.cpp
index fc0b9377e..ff7ce46cf 100644
--- a/src/lib/corelib/tools/error.cpp
+++ b/src/lib/corelib/tools/error.cpp
@@ -89,6 +89,8 @@ ErrorItem::ErrorItem() : d(new ErrorItemPrivate)
{
}
+ErrorItem::ErrorItem(ErrorItem &&rhs) noexcept = default;
+
ErrorItem::ErrorItem(const QString &description, const CodeLocation &codeLocation,
bool isBacktraceItem)
: d(new ErrorItemPrivate)
@@ -98,19 +100,12 @@ ErrorItem::ErrorItem(const QString &description, const CodeLocation &codeLocatio
d->isBacktraceItem = isBacktraceItem;
}
-ErrorItem::ErrorItem(const ErrorItem &rhs) : d(rhs.d)
-{
-}
+ErrorItem::ErrorItem(const ErrorItem &rhs) = default;
-ErrorItem &ErrorItem::operator=(const ErrorItem &other)
-{
- d = other.d;
- return *this;
-}
+ErrorItem &ErrorItem::operator=(const ErrorItem &other) = default;
+ErrorItem &ErrorItem::operator=(ErrorItem &&other) noexcept = default;
-ErrorItem::~ErrorItem()
-{
-}
+ErrorItem::~ErrorItem() = default;
QString ErrorItem::description() const
{
@@ -194,9 +189,9 @@ ErrorInfo::ErrorInfo() : d(new ErrorInfoPrivate)
{
}
-ErrorInfo::ErrorInfo(const ErrorInfo &rhs) : d(rhs.d)
-{
-}
+ErrorInfo::ErrorInfo(const ErrorInfo &rhs) = default;
+
+ErrorInfo::ErrorInfo(ErrorInfo &&rhs) noexcept = default;
ErrorInfo::ErrorInfo(const QString &description, const CodeLocation &location, bool internalError)
: d(new ErrorInfoPrivate)
@@ -223,16 +218,11 @@ ErrorInfo::ErrorInfo(const QString &description, const QStringList &backtrace)
}
}
+ErrorInfo &ErrorInfo::operator=(ErrorInfo &&other) noexcept = default;
-ErrorInfo &ErrorInfo::operator =(const ErrorInfo &other)
-{
- d = other.d;
- return *this;
-}
+ErrorInfo &ErrorInfo::operator =(const ErrorInfo &other) = default;
-ErrorInfo::~ErrorInfo()
-{
-}
+ErrorInfo::~ErrorInfo() = default;
void ErrorInfo::appendBacktrace(const QString &description, const CodeLocation &location)
{
diff --git a/src/lib/corelib/tools/error.h b/src/lib/corelib/tools/error.h
index abad85bad..36cf5e0ea 100644
--- a/src/lib/corelib/tools/error.h
+++ b/src/lib/corelib/tools/error.h
@@ -63,7 +63,9 @@ class QBS_EXPORT ErrorItem
public:
ErrorItem();
ErrorItem(const ErrorItem &rhs);
+ ErrorItem(ErrorItem &&rhs) noexcept;
ErrorItem &operator=(const ErrorItem &other);
+ ErrorItem &operator=(ErrorItem &&other) noexcept;
~ErrorItem();
QString description() const;
@@ -89,10 +91,12 @@ class QBS_EXPORT ErrorInfo
public:
ErrorInfo();
ErrorInfo(const ErrorInfo &rhs);
+ ErrorInfo(ErrorInfo &&rhs) noexcept;
ErrorInfo(const QString &description, const CodeLocation &location = CodeLocation(),
bool internalError = false);
ErrorInfo(const QString &description, const QStringList &backtrace);
ErrorInfo &operator=(const ErrorInfo &other);
+ ErrorInfo &operator=(ErrorInfo &&other) noexcept;
~ErrorInfo();
void appendBacktrace(const QString &description, const CodeLocation &location = CodeLocation());
diff --git a/src/lib/corelib/tools/executablefinder.cpp b/src/lib/corelib/tools/executablefinder.cpp
index 4342c82f0..0dc06dd86 100644
--- a/src/lib/corelib/tools/executablefinder.cpp
+++ b/src/lib/corelib/tools/executablefinder.cpp
@@ -64,9 +64,9 @@ static QStringList populateExecutableSuffixes()
QStringList ExecutableFinder::m_executableSuffixes = populateExecutableSuffixes();
-ExecutableFinder::ExecutableFinder(ResolvedProductPtr product, QProcessEnvironment env)
+ExecutableFinder::ExecutableFinder(ResolvedProductPtr product, const QProcessEnvironment &env)
: m_product(std::move(product))
- , m_environment(std::move(env))
+ , m_environment(env) // QProcessEnvironment doesn't have move-ctor, copy here
{
}
diff --git a/src/lib/corelib/tools/executablefinder.h b/src/lib/corelib/tools/executablefinder.h
index 9467756fc..ae834d911 100644
--- a/src/lib/corelib/tools/executablefinder.h
+++ b/src/lib/corelib/tools/executablefinder.h
@@ -53,7 +53,7 @@ namespace Internal {
class ExecutableFinder
{
public:
- ExecutableFinder(ResolvedProductPtr product, QProcessEnvironment env);
+ ExecutableFinder(ResolvedProductPtr product, const QProcessEnvironment &env);
QString findExecutable(const QString &path, const QString &workingDirPath);
diff --git a/src/lib/corelib/tools/fileinfo.cpp b/src/lib/corelib/tools/fileinfo.cpp
index 8b0eedc27..1918117d6 100644
--- a/src/lib/corelib/tools/fileinfo.cpp
+++ b/src/lib/corelib/tools/fileinfo.cpp
@@ -50,7 +50,7 @@
#include <QtCore/qregexp.h>
#if defined(Q_OS_UNIX)
-#include <errno.h>
+#include <cerrno>
#include <sys/stat.h>
#include <unistd.h>
#elif defined(Q_OS_WIN)
diff --git a/src/lib/corelib/tools/generateoptions.cpp b/src/lib/corelib/tools/generateoptions.cpp
index 019e2eb48..596e0acb9 100644
--- a/src/lib/corelib/tools/generateoptions.cpp
+++ b/src/lib/corelib/tools/generateoptions.cpp
@@ -68,19 +68,11 @@ GenerateOptions::GenerateOptions() : d(new Internal::GenerateOptionsPrivate)
{
}
-GenerateOptions::GenerateOptions(const GenerateOptions &other) : d(other.d)
-{
-}
+GenerateOptions::GenerateOptions(const GenerateOptions &other) = default;
-GenerateOptions &GenerateOptions::operator=(const GenerateOptions &other)
-{
- d = other.d;
- return *this;
-}
+GenerateOptions &GenerateOptions::operator=(const GenerateOptions &other) = default;
-GenerateOptions::~GenerateOptions()
-{
-}
+GenerateOptions::~GenerateOptions() = default;
/*!
* Returns the name of the generator used to create the external build system files.
diff --git a/src/lib/corelib/tools/hostosinfo.h b/src/lib/corelib/tools/hostosinfo.h
index d7f718c19..0876d39ec 100644
--- a/src/lib/corelib/tools/hostosinfo.h
+++ b/src/lib/corelib/tools/hostosinfo.h
@@ -112,6 +112,13 @@ public:
return finalName;
}
+ static QString stripExecutableSuffix(const QString &executable)
+ {
+ constexpr QLatin1String suffix(QBS_HOST_EXE_SUFFIX, sizeof(QBS_HOST_EXE_SUFFIX) - 1);
+ return !suffix.isEmpty() && executable.endsWith(suffix)
+ ? executable.chopped(suffix.size()) : executable;
+ }
+
static QString dynamicLibraryName(const QString &libraryBaseName)
{
return QLatin1String(QBS_HOST_DYNAMICLIB_PREFIX) + libraryBaseName
@@ -194,22 +201,21 @@ std::vector<std::string> HostOsInfo::hostOSIdentifiers()
std::vector<std::string> HostOsInfo::canonicalOSIdentifiers(const std::string &name)
{
std::vector<std::string> list { name };
- if (contains(std::vector<std::string> {"ios-simulator"}, name))
+ if (contains({"ios-simulator"}, name))
list << canonicalOSIdentifiers("ios");
- if (contains(std::vector<std::string> {"tvos-simulator"}, name))
+ if (contains({"tvos-simulator"}, name))
list << canonicalOSIdentifiers("tvos");
- if (contains(std::vector<std::string> {"watchos-simulator"}, name))
+ if (contains({"watchos-simulator"}, name))
list << canonicalOSIdentifiers("watchos");
- if (contains(std::vector<std::string> {"macos", "ios", "tvos", "watchos"}, name))
+ if (contains({"macos", "ios", "tvos", "watchos"}, name))
list << canonicalOSIdentifiers("darwin");
- if (contains(std::vector<std::string> {"darwin", "freebsd", "netbsd", "openbsd"}, name))
+ if (contains({"darwin", "freebsd", "netbsd", "openbsd"}, name))
list << canonicalOSIdentifiers("bsd");
- if (contains(std::vector<std::string> {"android"}, name))
+ if (contains({"android"}, name))
list << canonicalOSIdentifiers("linux");
// Note: recognized non-Unix platforms include: windows, haiku, vxworks
- if (contains(std::vector<std::string> {
- "bsd", "aix", "hpux", "solaris", "linux", "hurd", "qnx", "integrity"}, name))
+ if (contains({"bsd", "aix", "hpux", "solaris", "linux", "hurd", "qnx", "integrity"}, name))
list << canonicalOSIdentifiers("unix");
return list;
diff --git a/src/lib/corelib/tools/id.cpp b/src/lib/corelib/tools/id.cpp
index 6dd1147f2..33cfd60f7 100644
--- a/src/lib/corelib/tools/id.cpp
+++ b/src/lib/corelib/tools/id.cpp
@@ -269,9 +269,9 @@ Id Id::withPrefix(const char *prefix) const
bool Id::operator==(const char *name) const
{
- const char *string = getStringFromId(m_id);
- if (string && name)
- return strcmp(string, name) == 0;
+ const auto string = getStringFromId(m_id);
+ if (!string.isNull() && name)
+ return strcmp(string.data(), name) == 0;
else
return false;
}
diff --git a/src/lib/corelib/tools/id.h b/src/lib/corelib/tools/id.h
index f0c3b1588..aa327833f 100644
--- a/src/lib/corelib/tools/id.h
+++ b/src/lib/corelib/tools/id.h
@@ -75,7 +75,7 @@ public:
bool operator>(Id id) const { return m_id > id.m_id; }
bool alphabeticallyBefore(Id other) const;
int uniqueIdentifier() const { return m_id; }
- static Id fromUniqueIdentifier(int uid) { return Id(uid); }
+ static Id fromUniqueIdentifier(int uid) { return {uid}; }
static Id fromSetting(const QVariant &variant); // Good to use.
private:
diff --git a/src/lib/corelib/tools/installoptions.cpp b/src/lib/corelib/tools/installoptions.cpp
index 93fd54efe..5e112e6de 100644
--- a/src/lib/corelib/tools/installoptions.cpp
+++ b/src/lib/corelib/tools/installoptions.cpp
@@ -92,23 +92,15 @@ InstallOptions::InstallOptions() : d(new Internal::InstallOptionsPrivate)
{
}
-InstallOptions::InstallOptions(const InstallOptions &other) : d(other.d)
-{
-}
+InstallOptions::InstallOptions(const InstallOptions &other) = default;
InstallOptions::InstallOptions(InstallOptions &&other) Q_DECL_NOEXCEPT = default;
-InstallOptions &InstallOptions::operator=(const InstallOptions &other)
-{
- d = other.d;
- return *this;
-}
+InstallOptions &InstallOptions::operator=(const InstallOptions &other) = default;
InstallOptions &InstallOptions::operator=(InstallOptions &&other) Q_DECL_NOEXCEPT = default;
-InstallOptions::~InstallOptions()
-{
-}
+InstallOptions::~InstallOptions() = default;
/*!
* \brief The default install root, relative to the build directory.
diff --git a/src/lib/corelib/tools/joblimits.cpp b/src/lib/corelib/tools/joblimits.cpp
index 1a3e3a498..54c8c98ba 100644
--- a/src/lib/corelib/tools/joblimits.cpp
+++ b/src/lib/corelib/tools/joblimits.cpp
@@ -87,13 +87,9 @@ JobLimit::JobLimit() : JobLimit(QString(), -1)
JobLimit::JobLimit(const QString &pool, int limit) : d(new Internal::JobLimitPrivate(pool, limit))
{
}
-JobLimit::JobLimit(const JobLimit &other) : d(other.d) { }
-JobLimit &JobLimit::operator=(const JobLimit &other)
-{
- d = other.d;
- return *this;
-}
-JobLimit::~JobLimit() {}
+JobLimit::JobLimit(const JobLimit &other) = default;
+JobLimit &JobLimit::operator=(const JobLimit &other) = default;
+JobLimit::~JobLimit() = default;
QString JobLimit::pool() const { return d->jobLimit.first; }
int JobLimit::limit() const { return d->jobLimit.second; }
@@ -108,13 +104,9 @@ void JobLimit::store(Internal::PersistentPool &pool)
}
JobLimits::JobLimits() : d(new Internal::JobLimitsPrivate) { }
-JobLimits::JobLimits(const JobLimits &other) : d(other.d) { }
-JobLimits &JobLimits::operator=(const JobLimits &other)
-{
- d = other.d;
- return *this;
-}
-JobLimits::~JobLimits() {}
+JobLimits::JobLimits(const JobLimits &other) = default;
+JobLimits &JobLimits::operator=(const JobLimits &other) = default;
+JobLimits::~JobLimits() = default;
void JobLimits::setJobLimit(const JobLimit &limit)
{
diff --git a/src/lib/corelib/tools/jsonhelper.h b/src/lib/corelib/tools/jsonhelper.h
index d87802c0a..991d6bd6c 100644
--- a/src/lib/corelib/tools/jsonhelper.h
+++ b/src/lib/corelib/tools/jsonhelper.h
@@ -78,9 +78,9 @@ template<> inline QProcessEnvironment fromJson(const QJsonValue &v)
template<typename T> inline void setValueFromJson(T &targetValue, const QJsonObject &data,
const char *jsonProperty)
{
- const QJsonValue v = data.value(QLatin1String(jsonProperty));
- if (!v.isNull())
- targetValue = fromJson<T>(v);
+ const auto it = data.find(QLatin1String(jsonProperty));
+ if (it != data.end())
+ targetValue = fromJson<T>(*it);
}
} // namespace Internal
diff --git a/src/lib/corelib/tools/launcherinterface.cpp b/src/lib/corelib/tools/launcherinterface.cpp
index f4e80c5e2..50ac659a9 100644
--- a/src/lib/corelib/tools/launcherinterface.cpp
+++ b/src/lib/corelib/tools/launcherinterface.cpp
@@ -108,9 +108,7 @@ void LauncherInterface::doStart()
return;
}
m_process = new LauncherProcess(this);
- connect(m_process,
- static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error),
- this, &LauncherInterface::handleProcessError);
+ connect(m_process, &QProcess::errorOccurred, this, &LauncherInterface::handleProcessError);
connect(m_process,
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
this, &LauncherInterface::handleProcessFinished);
diff --git a/src/lib/corelib/tools/launcherpackets.cpp b/src/lib/corelib/tools/launcherpackets.cpp
index aaa931a49..9c7946d73 100644
--- a/src/lib/corelib/tools/launcherpackets.cpp
+++ b/src/lib/corelib/tools/launcherpackets.cpp
@@ -45,7 +45,7 @@
namespace qbs {
namespace Internal {
-LauncherPacket::~LauncherPacket() { }
+LauncherPacket::~LauncherPacket() = default;
QByteArray LauncherPacket::serialize() const
{
diff --git a/src/lib/corelib/tools/msvcinfo.cpp b/src/lib/corelib/tools/msvcinfo.cpp
index cffec85b2..462f921a4 100644
--- a/src/lib/corelib/tools/msvcinfo.cpp
+++ b/src/lib/corelib/tools/msvcinfo.cpp
@@ -38,14 +38,20 @@
****************************************************************************/
#include "msvcinfo.h"
+#include "visualstudioversioninfo.h"
+#include <logging/logger.h>
#include <tools/error.h>
#include <tools/profile.h>
#include <tools/stringconstants.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qdir.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonobject.h>
#include <QtCore/qprocess.h>
+#include <QtCore/qsettings.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qtemporaryfile.h>
@@ -54,6 +60,7 @@
#endif
#include <algorithm>
+#include <memory>
#include <mutex>
using namespace qbs;
@@ -129,16 +136,18 @@ public:
#ifdef Q_OS_WIN
static QStringList parseCommandLine(const QString &commandLine)
{
- QStringList list;
- const auto buf = new wchar_t[commandLine.size() + 1];
- buf[commandLine.toWCharArray(buf)] = 0;
+ const auto buf = std::make_unique<wchar_t[]>(size_t(commandLine.size()) + 1);
+ buf[size_t(commandLine.toWCharArray(buf.get()))] = 0;
int argCount = 0;
- LPWSTR *args = CommandLineToArgvW(buf, &argCount);
+ const auto argsDeleter = [](LPWSTR *p){ LocalFree(p); };
+ const auto args = std::unique_ptr<LPWSTR[], decltype(argsDeleter)>(
+ CommandLineToArgvW(buf.get(), &argCount), argsDeleter);
if (!args)
throw ErrorInfo(mkStr("Could not parse command line arguments: ") + commandLine);
+ QStringList list;
+ list.reserve(argCount);
for (int i = 0; i < argCount; ++i)
- list.push_back(QString::fromWCharArray(args[i]));
- delete[] buf;
+ list.push_back(QString::fromWCharArray(args[size_t(i)]));
return list;
}
#endif
@@ -163,7 +172,7 @@ static QVariantMap getMsvcDefines(const QString &compilerFilePath,
QStringList out = QString::fromLocal8Bit(runProcess(compilerFilePath, QStringList()
<< QStringLiteral("/nologo")
<< backendSwitch
- << QString::fromWCharArray(_wgetenv(L"COMSPEC"))
+ << qEnvironmentVariable("COMSPEC")
<< QStringLiteral("/c")
<< languageSwitch
<< QStringLiteral("NUL"),
@@ -206,30 +215,32 @@ static QVariantMap getMsvcDefines(const QString &compilerFilePath,
static QVariantMap getClangClDefines(
const QString &compilerFilePath,
const QProcessEnvironment &compilerEnv,
- MSVC::CompilerLanguage language)
+ MSVC::CompilerLanguage language,
+ const QString &arch)
{
#ifdef Q_OS_WIN
QFileInfo clInfo(compilerFilePath);
- QFileInfo clangInfo(clInfo.absolutePath() + QLatin1String("/clang.exe"));
+ QFileInfo clangInfo(clInfo.absolutePath() + QLatin1String("/clang-cl.exe"));
if (!clangInfo.exists())
throw ErrorInfo(QStringLiteral("%1 does not exist").arg(clangInfo.absoluteFilePath()));
- QString languageSwitch;
- switch (language) {
- case MSVC::CLanguage:
- languageSwitch = QStringLiteral("c");
- break;
- case MSVC::CPlusPlusLanguage:
- languageSwitch = QStringLiteral("c++");
- break;
- }
QStringList args = {
- QStringLiteral("-dM"),
- QStringLiteral("-E"),
- QStringLiteral("-x"),
- languageSwitch,
- QStringLiteral("NUL"),
+ QStringLiteral("/d1PP"), // dump macros
+ QStringLiteral("/E") // preprocess to stdout
};
+
+ if (language == MSVC::CLanguage)
+ args.append(QStringLiteral("/TC"));
+ else if (language == MSVC::CPlusPlusLanguage)
+ args.append(QStringLiteral("/TP"));
+
+ if (arch == QLatin1String("x86"))
+ args.append(QStringLiteral("-m32"));
+ else if (arch == QLatin1String("x86_64"))
+ args.append(QStringLiteral("-m64"));
+
+ args.append(QStringLiteral("NUL")); // filename
+
const auto lines = QString::fromLocal8Bit(
runProcess(
clangInfo.absoluteFilePath(),
@@ -239,10 +250,8 @@ static QVariantMap getClangClDefines(
QVariantMap result;
for (const auto &line: lines) {
static const auto defineString = QLatin1String("#define ");
- if (!line.startsWith(defineString)) {
- throw ErrorInfo(QStringLiteral("Unexpected compiler frontend output: ")
- + lines.join(QLatin1Char('\n')));
- }
+ if (!line.startsWith(defineString))
+ continue;
QStringView view(line.data() + defineString.size());
const auto it = std::find(view.begin(), view.end(), QLatin1Char(' '));
if (it == view.end()) {
@@ -253,15 +262,230 @@ static QVariantMap getClangClDefines(
QStringView value(it + 1, view.end());
result.insert(key.toString(), value.isEmpty() ? QVariant() : QVariant(value.toString()));
}
+ if (result.isEmpty()) {
+ throw ErrorInfo(QStringLiteral("Cannot determine macroses from compiler frontend output: ")
+ + lines.join(QLatin1Char('\n')));
+ }
return result;
#else
Q_UNUSED(compilerFilePath);
Q_UNUSED(compilerEnv);
Q_UNUSED(language);
+ Q_UNUSED(arch);
return {};
#endif
}
+static QString formatVswhereOutput(const QString &out, const QString &err)
+{
+ QString ret;
+ if (!out.isEmpty()) {
+ ret.append(Tr::tr("stdout")).append(QLatin1String(":\n"));
+ for (const QString &line : out.split(QLatin1Char('\n')))
+ ret.append(QLatin1Char('\t')).append(line).append(QLatin1Char('\n'));
+ }
+ if (!err.isEmpty()) {
+ ret.append(Tr::tr("stderr")).append(QLatin1String(":\n"));
+ for (const QString &line : err.split(QLatin1Char('\n')))
+ ret.append(QLatin1Char('\t')).append(line).append(QLatin1Char('\n'));
+ }
+ return ret;
+}
+
+static QString wow6432Key()
+{
+#ifdef Q_OS_WIN64
+ return QStringLiteral("\\Wow6432Node");
+#else
+ return {};
+#endif
+}
+
+static QString vswhereFilePath()
+{
+ static const std::vector<const char *> envVarCandidates{"ProgramFiles", "ProgramFiles(x86)"};
+ for (const char * const envVar : envVarCandidates) {
+ const QString value = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv(envVar)));
+ const QString cmd = value
+ + QStringLiteral("/Microsoft Visual Studio/Installer/vswhere.exe");
+ if (QFileInfo(cmd).exists())
+ return cmd;
+ }
+ return {};
+}
+
+enum class ProductType { VisualStudio, BuildTools };
+static std::vector<MSVCInstallInfo> retrieveInstancesFromVSWhere(
+ ProductType productType, Logger &logger)
+{
+ std::vector<MSVCInstallInfo> result;
+ const QString cmd = vswhereFilePath();
+ if (cmd.isEmpty())
+ return result;
+ QProcess vsWhere;
+ QStringList args = productType == ProductType::VisualStudio
+ ? QStringList({QStringLiteral("-all"), QStringLiteral("-legacy"),
+ QStringLiteral("-prerelease")})
+ : QStringList({QStringLiteral("-products"),
+ QStringLiteral("Microsoft.VisualStudio.Product.BuildTools")});
+ args << QStringLiteral("-format") << QStringLiteral("json") << QStringLiteral("-utf8");
+ vsWhere.start(cmd, args);
+ if (!vsWhere.waitForStarted(-1))
+ return result;
+ if (!vsWhere.waitForFinished(-1)) {
+ logger.qbsWarning() << Tr::tr("The vswhere tool failed to run").append(QLatin1String(": "))
+ .append(vsWhere.errorString());
+ return result;
+ }
+ if (vsWhere.exitCode() != 0) {
+ const QString stdOut = QString::fromLocal8Bit(vsWhere.readAllStandardOutput());
+ const QString stdErr = QString::fromLocal8Bit(vsWhere.readAllStandardError());
+ logger.qbsWarning() << Tr::tr("The vswhere tool failed to run").append(QLatin1String(".\n"))
+ .append(formatVswhereOutput(stdOut, stdErr));
+ return result;
+ }
+ QJsonParseError parseError;
+ QJsonDocument jsonOutput = QJsonDocument::fromJson(vsWhere.readAllStandardOutput(),
+ &parseError);
+ if (parseError.error != QJsonParseError::NoError) {
+ logger.qbsWarning() << Tr::tr("The vswhere tool produced invalid JSON output: %1")
+ .arg(parseError.errorString());
+ return result;
+ }
+ const auto jsonArray = jsonOutput.array();
+ for (const QJsonValue &v : jsonArray) {
+ const QJsonObject o = v.toObject();
+ MSVCInstallInfo info;
+ info.version = o.value(QStringLiteral("installationVersion")).toString();
+ if (productType == ProductType::BuildTools) {
+ // For build tools, the version is e.g. "15.8.28010.2036", rather than "15.0".
+ const int dotIndex = info.version.indexOf(QLatin1Char('.'));
+ if (dotIndex != -1)
+ info.version = info.version.left(dotIndex);
+ }
+ info.installDir = o.value(QStringLiteral("installationPath")).toString();
+ if (!info.version.isEmpty() && !info.installDir.isEmpty())
+ result.push_back(info);
+ }
+ return result;
+}
+
+static std::vector<MSVCInstallInfo> installedMSVCsFromVsWhere(Logger &logger)
+{
+ const std::vector<MSVCInstallInfo> vsInstallations
+ = retrieveInstancesFromVSWhere(ProductType::VisualStudio, logger);
+ const std::vector<MSVCInstallInfo> buildToolInstallations
+ = retrieveInstancesFromVSWhere(ProductType::BuildTools, logger);
+ std::vector<MSVCInstallInfo> all;
+ std::copy(vsInstallations.begin(), vsInstallations.end(), std::back_inserter(all));
+ std::copy(buildToolInstallations.begin(), buildToolInstallations.end(),
+ std::back_inserter(all));
+ return all;
+}
+
+static std::vector<MSVCInstallInfo> installedMSVCsFromRegistry()
+{
+ std::vector<MSVCInstallInfo> result;
+
+ // Detect Visual Studio
+ const QSettings vsRegistry(
+ QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key()
+ + QStringLiteral("\\Microsoft\\VisualStudio\\SxS\\VS7"),
+ QSettings::NativeFormat);
+ const auto vsNames = vsRegistry.childKeys();
+ for (const QString &vsName : vsNames) {
+ MSVCInstallInfo entry;
+ entry.version = vsName;
+ entry.installDir = vsRegistry.value(vsName).toString();
+ result.push_back(entry);
+ }
+
+ // Detect Visual C++ Build Tools
+ QSettings vcbtRegistry(
+ QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key()
+ + QStringLiteral("\\Microsoft\\VisualCppBuildTools"),
+ QSettings::NativeFormat);
+ const QStringList &vcbtRegistryChildGroups = vcbtRegistry.childGroups();
+ for (const QString &childGroup : vcbtRegistryChildGroups) {
+ vcbtRegistry.beginGroup(childGroup);
+ bool ok;
+ int installed = vcbtRegistry.value(QStringLiteral("Installed")).toInt(&ok);
+ if (ok && installed) {
+ MSVCInstallInfo entry;
+ entry.version = childGroup;
+ const QSettings vsRegistry(
+ QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key()
+ + QStringLiteral("\\Microsoft\\VisualStudio\\") + childGroup
+ + QStringLiteral("\\Setup\\VC"),
+ QSettings::NativeFormat);
+ entry.installDir = vsRegistry.value(QStringLiteral("ProductDir")).toString();
+ result.push_back(entry);
+ }
+ vcbtRegistry.endGroup();
+ }
+
+ return result;
+}
+
+/*
+ Returns the list of compilers present in all MSVC installations
+ (Visual Studios or Build Tools) without the architecture, e.g.
+ [VC\Tools\MSVC\14.16.27023, VC\Tools\MSVC\14.14.26428, ...]
+*/
+static std::vector<MSVC> installedCompilersHelper(Logger &logger)
+{
+ std::vector<MSVC> msvcs;
+ std::vector<MSVCInstallInfo> installInfos = installedMSVCsFromVsWhere(logger);
+ if (installInfos.empty())
+ installInfos = installedMSVCsFromRegistry();
+ for (const MSVCInstallInfo &installInfo : installInfos) {
+ MSVC msvc;
+ msvc.internalVsVersion = Version::fromString(installInfo.version, true);
+ if (!msvc.internalVsVersion.isValid())
+ continue;
+
+ QDir vsInstallDir(installInfo.installDir);
+ msvc.vsInstallPath = vsInstallDir.absolutePath();
+ if (vsInstallDir.dirName() != QStringLiteral("VC")
+ && !vsInstallDir.cd(QStringLiteral("VC"))) {
+ continue;
+ }
+
+ msvc.version = QString::number(Internal::VisualStudioVersionInfo(
+ msvc.internalVsVersion).marketingVersion());
+ if (msvc.version.isEmpty()) {
+ logger.qbsWarning()
+ << Tr::tr("Unknown MSVC version %1 found.").arg(installInfo.version);
+ continue;
+ }
+
+ if (msvc.internalVsVersion.majorVersion() < 15) {
+ QDir vcInstallDir = vsInstallDir;
+ if (!vcInstallDir.cd(QStringLiteral("bin")))
+ continue;
+ msvc.vcInstallPath = vcInstallDir.absolutePath();
+ msvcs.push_back(msvc);
+ } else {
+ QDir vcInstallDir = vsInstallDir;
+ vcInstallDir.cd(QStringLiteral("Tools/MSVC"));
+ const auto vcVersionStrs = vcInstallDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
+ for (const QString &vcVersionStr : vcVersionStrs) {
+ const Version vcVersion = Version::fromString(vcVersionStr);
+ if (!vcVersion.isValid())
+ continue;
+ QDir specificVcInstallDir = vcInstallDir;
+ if (!specificVcInstallDir.cd(vcVersionStr)
+ || !specificVcInstallDir.cd(QStringLiteral("bin"))) {
+ continue;
+ }
+ msvc.vcInstallPath = specificVcInstallDir.absolutePath();
+ msvcs.push_back(msvc);
+ }
+ }
+ }
+ return msvcs;
+}
+
void MSVC::init()
{
determineCompilerVersion();
@@ -280,6 +504,28 @@ QString MSVC::architectureFromClPath(const QString &clPath)
return parentDirName;
}
+QString MSVC::canonicalArchitecture(const QString &arch)
+{
+ if (arch == QLatin1String("x64") || arch == QLatin1String("amd64"))
+ return QStringLiteral("x86_64");
+ return arch;
+}
+
+std::pair<QString, QString> MSVC::getHostTargetArchPair(const QString &arch)
+{
+ QString hostArch;
+ QString targetArch;
+ const int index = arch.indexOf(QLatin1Char('_'));
+ if (index != -1) {
+ hostArch = arch.mid(0, index);
+ targetArch = arch.mid(index);
+ } else {
+ hostArch = arch;
+ targetArch = arch;
+ }
+ return {canonicalArchitecture(hostArch), canonicalArchitecture(targetArch)};
+}
+
QString MSVC::binPathForArchitecture(const QString &arch) const
{
QString archSubDir;
@@ -301,10 +547,106 @@ QVariantMap MSVC::compilerDefines(const QString &compilerFilePath,
{
const auto compilerName = QFileInfo(compilerFilePath).fileName().toLower();
if (compilerName == QLatin1String("clang-cl.exe"))
- return getClangClDefines(compilerFilePath, environment, language);
+ return getClangClDefines(compilerFilePath, environment, language, architecture);
return getMsvcDefines(compilerFilePath, environment, language);
}
+std::vector<MSVCArchInfo> MSVC::findSupportedArchitectures(const MSVC &msvc)
+{
+ std::vector<MSVCArchInfo> result;
+ auto addResult = [&result](const MSVCArchInfo &ai) {
+ if (QFile::exists(ai.binPath + QLatin1String("/cl.exe")))
+ result.push_back(ai);
+ };
+ if (msvc.internalVsVersion.majorVersion() < 15) {
+ static const QStringList knownArchitectures = QStringList()
+ << QStringLiteral("x86")
+ << QStringLiteral("amd64_x86")
+ << QStringLiteral("amd64")
+ << QStringLiteral("x86_amd64")
+ << QStringLiteral("ia64")
+ << QStringLiteral("x86_ia64")
+ << QStringLiteral("x86_arm")
+ << QStringLiteral("amd64_arm");
+ for (const QString &knownArchitecture : knownArchitectures) {
+ MSVCArchInfo ai;
+ ai.arch = knownArchitecture;
+ ai.binPath = msvc.binPathForArchitecture(knownArchitecture);
+ addResult(ai);
+ }
+ } else {
+ QDir vcInstallDir(msvc.vcInstallPath);
+ const auto hostArchs = vcInstallDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
+ for (const QString &hostArch : hostArchs) {
+ QDir subdir = vcInstallDir;
+ if (!subdir.cd(hostArch))
+ continue;
+ const QString shortHostArch = hostArch.mid(4).toLower();
+ const auto archs = subdir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
+ for (const QString &arch : archs) {
+ MSVCArchInfo ai;
+ ai.binPath = subdir.absoluteFilePath(arch);
+ if (shortHostArch == arch)
+ ai.arch = arch;
+ else
+ ai.arch = shortHostArch + QLatin1Char('_') + arch;
+ addResult(ai);
+ }
+ }
+ }
+ return result;
+}
+
+QVariantMap MSVC::toVariantMap() const
+{
+ return {
+ {QStringLiteral("version"), version},
+ {QStringLiteral("internalVsVersion"), internalVsVersion.toString()},
+ {QStringLiteral("vsInstallPath"), vsInstallPath},
+ {QStringLiteral("vcInstallPath"), vcInstallPath},
+ {QStringLiteral("binPath"), binPath},
+ {QStringLiteral("architecture"), architecture},
+ };
+}
+
+/*!
+ \internal
+ Returns the list of all compilers present in all MSVC installations
+ separated by host/target arch, e.g.
+ [
+ VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64,
+ VC\Tools\MSVC\14.16.27023\bin\Hostx64\x86,
+ VC\Tools\MSVC\14.16.27023\bin\Hostx64\arm,
+ VC\Tools\MSVC\14.16.27023\bin\Hostx64\arm64,
+ VC\Tools\MSVC\14.16.27023\bin\Hostx86\x64,
+ ...
+ ]
+ \note that MSVC.architecture can be either "x64" or "amd64" (depending on the MSVC version)
+ in case of 64-bit platform (but we use the "x86_64" name...)
+*/
+std::vector<MSVC> MSVC::installedCompilers(Logger &logger)
+{
+ std::vector<MSVC> msvcs;
+ const auto instMsvcs = installedCompilersHelper(logger);
+ for (const MSVC &msvc : instMsvcs) {
+ if (msvc.internalVsVersion.majorVersion() < 15) {
+ // Check existence of various install scripts
+ const QString vcvars32bat = msvc.vcInstallPath + QLatin1String("/vcvars32.bat");
+ if (!QFileInfo(vcvars32bat).isFile())
+ continue;
+ }
+
+ const auto ais = findSupportedArchitectures(msvc);
+ for (const MSVCArchInfo &ai : ais) {
+ MSVC specificMSVC = msvc;
+ specificMSVC.architecture = ai.arch;
+ specificMSVC.binPath = ai.binPath;
+ msvcs.push_back(specificMSVC);
+ }
+ }
+ return msvcs;
+}
+
void MSVC::determineCompilerVersion()
{
QString cppFilePath;
@@ -332,3 +674,24 @@ void MSVC::determineCompilerVersion()
compilerVersion = Version(versionStr.mid(0, 2).toInt(), versionStr.mid(2, 2).toInt(),
versionStr.mid(4).toInt());
}
+
+QString MSVCInstallInfo::findVcvarsallBat() const
+{
+ static const auto vcvarsall2017 = QStringLiteral("VC/Auxiliary/Build/vcvarsall.bat");
+ // 2015, 2013 and 2012
+ static const auto vcvarsallOld = QStringLiteral("VC/vcvarsall.bat");
+ QDir dir(installDir);
+ if (dir.exists(vcvarsall2017))
+ return dir.absoluteFilePath(vcvarsall2017);
+ if (dir.exists(vcvarsallOld))
+ return dir.absoluteFilePath(vcvarsallOld);
+ return {};
+}
+
+std::vector<MSVCInstallInfo> MSVCInstallInfo::installedMSVCs(Logger &logger)
+{
+ const auto installInfos = installedMSVCsFromVsWhere(logger);
+ if (installInfos.empty())
+ return installedMSVCsFromRegistry();
+ return installInfos;
+}
diff --git a/src/lib/corelib/tools/msvcinfo.h b/src/lib/corelib/tools/msvcinfo.h
index b5cf04e84..de4470bf0 100644
--- a/src/lib/corelib/tools/msvcinfo.h
+++ b/src/lib/corelib/tools/msvcinfo.h
@@ -53,6 +53,14 @@
namespace qbs {
namespace Internal {
+class Logger;
+
+struct MSVCArchInfo
+{
+ QString arch;
+ QString binPath;
+};
+
/**
* Represents one MSVC installation for one specific target architecture.
* There are potentially multiple MSVCs in one Visual Studio installation.
@@ -75,7 +83,7 @@ public:
QString architecture;
QProcessEnvironment environment;
- MSVC() { }
+ MSVC() = default;
MSVC(const QString &clPath, QString arch):
architecture(std::move(arch))
@@ -90,11 +98,19 @@ public:
QBS_EXPORT void init();
QBS_EXPORT static QString architectureFromClPath(const QString &clPath);
+ QBS_EXPORT static QString canonicalArchitecture(const QString &arch);
+ QBS_EXPORT static std::pair<QString, QString> getHostTargetArchPair(const QString &arch);
QBS_EXPORT QString binPathForArchitecture(const QString &arch) const;
QBS_EXPORT QString clPathForArchitecture(const QString &arch) const;
QBS_EXPORT QVariantMap compilerDefines(const QString &compilerFilePath,
CompilerLanguage language) const;
+ QBS_EXPORT static std::vector<MSVCArchInfo> findSupportedArchitectures(const MSVC &msvc);
+
+ QBS_EXPORT QVariantMap toVariantMap() const;
+
+ QBS_EXPORT static std::vector<MSVC> installedCompilers(Logger &logger);
+
private:
void determineCompilerVersion();
};
@@ -110,6 +126,16 @@ public:
}
};
+struct QBS_EXPORT MSVCInstallInfo
+{
+ QString version;
+ QString installDir;
+
+ QString findVcvarsallBat() const;
+
+ static std::vector<MSVCInstallInfo> installedMSVCs(Logger &logger);
+};
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/tools/persistence.cpp b/src/lib/corelib/tools/persistence.cpp
index ea8adf023..3f2b57e01 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-127";
+static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-128";
NoBuildGraphError::NoBuildGraphError(const QString &filePath)
: ErrorInfo(Tr::tr("Build graph not found for configuration '%1'. Expected location was '%2'.")
@@ -62,10 +62,7 @@ PersistentPool::PersistentPool(Logger &logger) : m_logger(logger)
m_stream.setVersion(QDataStream::Qt_4_8);
}
-PersistentPool::~PersistentPool()
-{
- closeStream();
-}
+PersistentPool::~PersistentPool() = default;
void PersistentPool::load(const QString &filePath)
{
@@ -89,7 +86,7 @@ void PersistentPool::load(const QString &filePath)
}
m_stream >> m_headData.projectConfig;
- file.release();
+ m_file = std::move(file);
m_loadedRaw.clear();
m_loaded.clear();
m_storageIndices.clear();
@@ -116,7 +113,8 @@ void PersistentPool::setupWriteStream(const QString &filePath)
"Cannot open file '%1' for writing: %2").arg(filePath, file->errorString()));
}
- m_stream.setDevice(file.release());
+ m_stream.setDevice(file.get());
+ m_file = std::move(file);
m_stream << QByteArray(qstrlen(QBS_PERSISTENCE_MAGIC), 0) << m_headData.projectConfig;
m_lastStoredObjectId = 0;
m_lastStoredStringId = 0;
@@ -140,14 +138,6 @@ void PersistentPool::finalizeWriteStream()
}
}
-void PersistentPool::closeStream()
-{
- delete m_stream.device();
- m_stream.setDevice(nullptr);
-}
-
-
-
void PersistentPool::storeVariant(const QVariant &variant)
{
const auto type = static_cast<quint32>(variant.type());
diff --git a/src/lib/corelib/tools/persistence.h b/src/lib/corelib/tools/persistence.h
index 4bda59f7c..e00310321 100644
--- a/src/lib/corelib/tools/persistence.h
+++ b/src/lib/corelib/tools/persistence.h
@@ -128,7 +128,6 @@ public:
void load(const QString &filePath);
void setupWriteStream(const QString &filePath);
void finalizeWriteStream();
- void closeStream();
void clear();
const HeadData &headData() const { return m_headData; }
@@ -167,6 +166,7 @@ private:
static const PersistentObjectId ValueNotFoundId = -1;
static const PersistentObjectId EmptyValueId = -2;
+ std::unique_ptr<QIODevice> m_file;
QDataStream m_stream;
HeadData m_headData;
std::vector<void *> m_loadedRaw;
diff --git a/src/lib/corelib/tools/processresult.cpp b/src/lib/corelib/tools/processresult.cpp
index 3fb2f8dbc..d5591a7ed 100644
--- a/src/lib/corelib/tools/processresult.cpp
+++ b/src/lib/corelib/tools/processresult.cpp
@@ -53,19 +53,11 @@ ProcessResult::ProcessResult() : d(new Internal::ProcessResultPrivate)
{
}
-ProcessResult::ProcessResult(const ProcessResult &other) : d(other.d)
-{
-}
+ProcessResult::ProcessResult(const ProcessResult &other) = default;
-ProcessResult &ProcessResult::operator=(const ProcessResult &other)
-{
- d = other.d;
- return *this;
-}
+ProcessResult &ProcessResult::operator=(const ProcessResult &other) = default;
-ProcessResult::~ProcessResult()
-{
-}
+ProcessResult::~ProcessResult() = default;
/*!
* \brief Returns true iff the command finished successfully.
diff --git a/src/lib/corelib/tools/processutils.cpp b/src/lib/corelib/tools/processutils.cpp
index 04a061e0c..b27592f88 100644
--- a/src/lib/corelib/tools/processutils.cpp
+++ b/src/lib/corelib/tools/processutils.cpp
@@ -92,7 +92,8 @@ QString processNameByPid(qint64 pid)
char buf[PATH_MAX];
memset(buf, 0, sizeof(buf));
sprintf(exePath, "/proc/%lld/exe", pid);
- readlink(exePath, buf, sizeof(buf));
+ if (readlink(exePath, buf, sizeof(buf)) < 0)
+ return {};
return FileInfo::fileName(QString::fromUtf8(buf));
#elif defined(Q_OS_BSD4)
# if defined(Q_OS_NETBSD)
diff --git a/src/lib/corelib/tools/profile.cpp b/src/lib/corelib/tools/profile.cpp
index 7e594fd2d..2eac25091 100644
--- a/src/lib/corelib/tools/profile.cpp
+++ b/src/lib/corelib/tools/profile.cpp
@@ -63,13 +63,13 @@ namespace qbs {
/*!
* \brief Creates an object giving access to the settings for profile \c name.
*/
-Profile::Profile(const QString &name, Settings *settings, const QVariantMap &profiles)
- : m_name(name),
+Profile::Profile(QString name, Settings *settings, QVariantMap profiles)
+ : m_name(std::move(name)),
m_settings(settings),
- m_values(profiles.value(name).toMap()),
- m_profiles(profiles)
+ m_values(profiles.value(m_name).toMap()),
+ m_profiles(std::move(profiles))
{
- QBS_ASSERT(name == cleanName(name), return);
+ QBS_ASSERT(m_name == cleanName(m_name), return);
}
bool Profile::exists() const
diff --git a/src/lib/corelib/tools/profile.h b/src/lib/corelib/tools/profile.h
index aa8b7ef10..0eee23ae4 100644
--- a/src/lib/corelib/tools/profile.h
+++ b/src/lib/corelib/tools/profile.h
@@ -55,7 +55,7 @@ class Settings;
class QBS_EXPORT Profile
{
public:
- Profile(const QString &name, Settings *settings, const QVariantMap &profiles = QVariantMap());
+ Profile(QString name, Settings *settings, QVariantMap profiles = QVariantMap());
bool exists() const;
QVariant value(const QString &key, const QVariant &defaultValue = QVariant(),
diff --git a/src/lib/corelib/tools/progressobserver.h b/src/lib/corelib/tools/progressobserver.h
index 72b9694ba..fc49d9eed 100644
--- a/src/lib/corelib/tools/progressobserver.h
+++ b/src/lib/corelib/tools/progressobserver.h
@@ -51,7 +51,7 @@ namespace Internal {
class ProgressObserver
{
public:
- virtual ~ProgressObserver() { }
+ virtual ~ProgressObserver() = default;
virtual void initialize(const QString &task, int maximum) = 0;
virtual void setProgressValue(int value) = 0;
diff --git a/src/lib/corelib/tools/projectgeneratormanager.cpp b/src/lib/corelib/tools/projectgeneratormanager.cpp
index 3991adfb9..53d72bcd1 100644
--- a/src/lib/corelib/tools/projectgeneratormanager.cpp
+++ b/src/lib/corelib/tools/projectgeneratormanager.cpp
@@ -52,9 +52,7 @@ namespace qbs {
using namespace Internal;
-ProjectGeneratorManager::~ProjectGeneratorManager()
-{
-}
+ProjectGeneratorManager::~ProjectGeneratorManager() = default;
ProjectGeneratorManager *ProjectGeneratorManager::instance()
{
@@ -62,9 +60,7 @@ ProjectGeneratorManager *ProjectGeneratorManager::instance()
return &generatorPlugin;
}
-ProjectGeneratorManager::ProjectGeneratorManager()
-{
-}
+ProjectGeneratorManager::ProjectGeneratorManager() = default;
QStringList ProjectGeneratorManager::loadedGeneratorNames()
{
diff --git a/src/lib/corelib/tools/qttools.h b/src/lib/corelib/tools/qttools.h
index c3b4d3a9f..04fd7d95e 100644
--- a/src/lib/corelib/tools/qttools.h
+++ b/src/lib/corelib/tools/qttools.h
@@ -42,6 +42,7 @@
#include <QtCore/qhash.h>
#include <QtCore/qstringlist.h>
+#include <QtCore/qtextstream.h>
#include <functional>
@@ -66,8 +67,16 @@ template<typename T1, typename T2> struct hash<std::pair<T1, T2>>
} // namespace std
QT_BEGIN_NAMESPACE
+
uint qHash(const QStringList &list);
uint qHash(const QProcessEnvironment &env);
+
+#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
+namespace Qt {
+inline QTextStream &endl(QTextStream &stream) { return stream << QT_PREPEND_NAMESPACE(endl); }
+} // namespace Qt
+#endif
+
QT_END_NAMESPACE
namespace qbs {
@@ -82,6 +91,16 @@ QSet<T> toSet(const QList<T> &list)
#endif
}
+template<class T>
+QList<T> toList(const QSet<T> &set)
+{
+#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
+ return set.toList();
+#else
+ return QList<T>(set.begin(), set.end());
+#endif
+}
+
} // namespace qbs
diff --git a/src/lib/corelib/tools/scannerpluginmanager.cpp b/src/lib/corelib/tools/scannerpluginmanager.cpp
index d6b564832..378f0e11b 100644
--- a/src/lib/corelib/tools/scannerpluginmanager.cpp
+++ b/src/lib/corelib/tools/scannerpluginmanager.cpp
@@ -51,9 +51,7 @@ public:
std::map<FileTag, std::vector<ScannerPlugin* >> scannerPlugins;
};
-ScannerPluginManager::~ScannerPluginManager()
-{
-}
+ScannerPluginManager::~ScannerPluginManager() = default;
ScannerPluginManager *ScannerPluginManager::instance()
{
diff --git a/src/lib/corelib/tools/set.h b/src/lib/corelib/tools/set.h
index eb3bf6632..d2af77d73 100644
--- a/src/lib/corelib/tools/set.h
+++ b/src/lib/corelib/tools/set.h
@@ -98,7 +98,7 @@ public:
const_iterator constBegin() const { return m_data.cbegin(); }
const_iterator constEnd() const { return m_data.cend(); }
- Set() { }
+ Set() = default;
Set(const std::initializer_list<T> &list);
Set &unite(const Set &other);
diff --git a/src/lib/corelib/tools/settings.cpp b/src/lib/corelib/tools/settings.cpp
index 7312cd622..fccb9c9b2 100644
--- a/src/lib/corelib/tools/settings.cpp
+++ b/src/lib/corelib/tools/settings.cpp
@@ -91,8 +91,8 @@ Settings::Settings(const QString &baseDir) : Settings(baseDir, systemSettingsBas
Settings::Settings(const QString &baseDir, const QString &systemBaseDir)
: m_settings(SettingsCreator(baseDir).getQSettings()),
- m_systemSettings(new QSettings(systemBaseDir + QStringLiteral("/qbs.conf"),
- QSettings::IniFormat)),
+ m_systemSettings(std::make_unique<QSettings>(systemBaseDir + QStringLiteral("/qbs.conf"),
+ QSettings::IniFormat)),
m_baseDir(baseDir)
{
// Actual qbs settings are stored transparently within a group, because QSettings
@@ -100,11 +100,7 @@ Settings::Settings(const QString &baseDir, const QString &systemBaseDir)
m_settings->beginGroup(QStringLiteral("org/qt-project/qbs"));
}
-Settings::~Settings()
-{
- delete m_settings;
- delete m_systemSettings;
-}
+Settings::~Settings() = default;
QVariant Settings::value(const QString &key, Scopes scopes, const QVariant &defaultValue) const
{
@@ -241,7 +237,7 @@ void Settings::fixupKeys(QStringList &keys) const
QSettings *Settings::settingsForScope(Settings::Scope scope) const
{
- return scope == UserScope ? m_settings : m_systemSettings;
+ return scope == UserScope ? m_settings.get() : m_systemSettings.get();
}
QSettings *Settings::targetForWriting() const
diff --git a/src/lib/corelib/tools/settings.h b/src/lib/corelib/tools/settings.h
index d4de08490..638216669 100644
--- a/src/lib/corelib/tools/settings.h
+++ b/src/lib/corelib/tools/settings.h
@@ -45,6 +45,8 @@
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
+#include <memory>
+
QT_BEGIN_NAMESPACE
class QSettings;
class QStringList;
@@ -94,8 +96,8 @@ private:
QSettings *targetForWriting() const;
void checkForWriteError();
- QSettings * const m_settings;
- QSettings * const m_systemSettings;
+ const std::unique_ptr<QSettings> m_settings;
+ const std::unique_ptr<QSettings> m_systemSettings;
const QString m_baseDir;
Scope m_scopeForWriting = UserScope;
};
diff --git a/src/lib/corelib/tools/settingscreator.cpp b/src/lib/corelib/tools/settingscreator.cpp
index eaaf2802c..36e67440c 100644
--- a/src/lib/corelib/tools/settingscreator.cpp
+++ b/src/lib/corelib/tools/settingscreator.cpp
@@ -1,3 +1,4 @@
+#include <memory>
#include <utility>
/****************************************************************************
@@ -64,11 +65,11 @@ SettingsCreator::SettingsCreator(QString baseDir)
{
}
-QSettings *SettingsCreator::getQSettings()
+std::unique_ptr<QSettings> SettingsCreator::getQSettings()
{
createQSettings();
migrate();
- return m_settings.release();
+ return std::move(m_settings);
}
void SettingsCreator::migrate()
@@ -104,7 +105,7 @@ void SettingsCreator::migrate()
// Adapt all paths in settings that point to the old location. At the time of this writing,
// that's only preferences.qbsSearchPaths as written by libqtprofilesetup, but we don't want
// to hardcode that here.
- m_settings.reset(new QSettings(m_newSettingsFilePath, format()));
+ m_settings = std::make_unique<QSettings>(m_newSettingsFilePath, format());
const auto allKeys = m_settings->allKeys();
for (const QString &key : allKeys) {
QVariant v = m_settings->value(key);
@@ -136,7 +137,7 @@ void SettingsCreator::createQSettings()
m_newSettingsDir = m_settingsBaseDir + QLatin1String("/qbs/") + m_qbsVersion.toString();
m_settingsFileName = fi.fileName();
m_newSettingsFilePath = m_newSettingsDir + QLatin1Char('/') + m_settingsFileName;
- m_settings.reset(new QSettings(m_newSettingsFilePath, tmp->format()));
+ m_settings = std::make_unique<QSettings>(m_newSettingsFilePath, tmp->format());
}
Version SettingsCreator::predecessor() const
diff --git a/src/lib/corelib/tools/settingscreator.h b/src/lib/corelib/tools/settingscreator.h
index 39da80a7f..ab491105c 100644
--- a/src/lib/corelib/tools/settingscreator.h
+++ b/src/lib/corelib/tools/settingscreator.h
@@ -58,7 +58,7 @@ class SettingsCreator
public:
SettingsCreator(QString baseDir);
- QSettings *getQSettings();
+ std::unique_ptr<QSettings> getQSettings();
private:
void migrate();
diff --git a/src/lib/corelib/tools/settingsmodel.cpp b/src/lib/corelib/tools/settingsmodel.cpp
index d67f1da5c..7283e959c 100644
--- a/src/lib/corelib/tools/settingsmodel.cpp
+++ b/src/lib/corelib/tools/settingsmodel.cpp
@@ -125,7 +125,7 @@ public:
SettingsModel::SettingsModel(const QString &settingsDir, Settings::Scope scope, QObject *parent)
: QAbstractItemModel(parent), d(new SettingsModelPrivate)
{
- d->settings.reset(new qbs::Settings(settingsDir));
+ d->settings = std::make_unique<qbs::Settings>(settingsDir);
d->settings->setScopeForWriting(scope);
d->readSettings();
}
@@ -155,7 +155,7 @@ void SettingsModel::updateSettingsDir(const QString &settingsDir)
{
const Settings::Scope scope = d->scope();
beginResetModel();
- d->settings.reset(new qbs::Settings(settingsDir));
+ d->settings = std::make_unique<qbs::Settings>(settingsDir);
d->settings->setScopeForWriting(scope);
d->readSettings();
endResetModel();
diff --git a/src/lib/corelib/tools/setupprojectparameters.cpp b/src/lib/corelib/tools/setupprojectparameters.cpp
index 41af7b926..a06ffc4bd 100644
--- a/src/lib/corelib/tools/setupprojectparameters.cpp
+++ b/src/lib/corelib/tools/setupprojectparameters.cpp
@@ -107,21 +107,15 @@ SetupProjectParameters::SetupProjectParameters() : d(new Internal::SetupProjectP
{
}
-SetupProjectParameters::SetupProjectParameters(const SetupProjectParameters &other) : d(other.d)
-{
-}
+SetupProjectParameters::SetupProjectParameters(const SetupProjectParameters &other) = default;
-SetupProjectParameters::SetupProjectParameters(SetupProjectParameters &&other) Q_DECL_NOEXCEPT = default;
+SetupProjectParameters::SetupProjectParameters(
+ SetupProjectParameters &&other) Q_DECL_NOEXCEPT = default;
-SetupProjectParameters::~SetupProjectParameters()
-{
-}
+SetupProjectParameters::~SetupProjectParameters() = default;
-SetupProjectParameters &SetupProjectParameters::operator=(const SetupProjectParameters &other)
-{
- d = other.d;
- return *this;
-}
+SetupProjectParameters &SetupProjectParameters::operator=(
+ const SetupProjectParameters &other) = default;
namespace Internal {
template<> ErrorHandlingMode fromJson(const QJsonValue &v)
@@ -355,7 +349,7 @@ static void provideValuesTree(const QVariantMap &values, QVariantMap *valueTree)
valueTree->clear();
for (QVariantMap::const_iterator it = values.constBegin(); it != values.constEnd(); ++it) {
- const QString name = it.key();
+ const QString &name = it.key();
int idx = name.lastIndexOf(QLatin1Char('.'));
const QStringList nameElements = (idx == -1)
? QStringList() << name
diff --git a/src/lib/corelib/tools/shellutils.cpp b/src/lib/corelib/tools/shellutils.cpp
index 01c177cce..dae98f337 100644
--- a/src/lib/corelib/tools/shellutils.cpp
+++ b/src/lib/corelib/tools/shellutils.cpp
@@ -205,12 +205,12 @@ void CommandLine::setProgram(const std::string &program, bool raw)
void CommandLine::appendArgument(const QString &value)
{
- m_arguments.push_back(value);
+ m_arguments.emplace_back(value);
}
void CommandLine::appendArgument(const std::string &value)
{
- m_arguments.push_back(QString::fromStdString(value));
+ m_arguments.emplace_back(QString::fromStdString(value));
}
void CommandLine::appendArguments(const QList<QString> &args)
diff --git a/src/lib/corelib/tools/shellutils.h b/src/lib/corelib/tools/shellutils.h
index 6f1d82afb..f4ad35044 100644
--- a/src/lib/corelib/tools/shellutils.h
+++ b/src/lib/corelib/tools/shellutils.h
@@ -77,7 +77,7 @@ public:
private:
struct Argument
{
- Argument(const QString &value = QString()) : value(value) { }
+ Argument(QString value = QString()) : value(std::move(value)) { }
QString value;
bool isFilePath = false;
bool shouldQuote = true;
diff --git a/src/lib/corelib/tools/stlutils.h b/src/lib/corelib/tools/stlutils.h
index ad00070cf..5c21c0672 100644
--- a/src/lib/corelib/tools/stlutils.h
+++ b/src/lib/corelib/tools/stlutils.h
@@ -54,11 +54,18 @@ C sorted(const C &container)
return result;
}
-template <class C>
-bool contains(const C &container, const typename C::value_type &v)
+template <class C, class T>
+bool contains(const C &container, const T &v)
{
- const auto &end = container.cend();
- return std::find(container.cbegin(), end, v) != end;
+ const auto &end = std::cend(container);
+ return std::find(std::cbegin(container), end, v) != end;
+}
+
+template <class T, size_t N, class U>
+bool contains(const T (&container)[N], const U &v)
+{
+ const auto &end = std::cend(container);
+ return std::find(std::cbegin(container), end, v) != end;
}
template <class C>
diff --git a/src/lib/corelib/tools/stringconstants.h b/src/lib/corelib/tools/stringconstants.h
index 79cbcd125..f2bc78446 100644
--- a/src/lib/corelib/tools/stringconstants.h
+++ b/src/lib/corelib/tools/stringconstants.h
@@ -153,6 +153,7 @@ public:
QBS_STRING_CONSTANT(searchPathsProperty, "searchPaths")
QBS_STRING_CONSTANT(setupBuildEnvironmentProperty, "setupBuildEnvironment")
QBS_STRING_CONSTANT(setupRunEnvironmentProperty, "setupRunEnvironment")
+ QBS_STRING_CONSTANT(shadowProductPrefix, "__shadow__")
QBS_STRING_CONSTANT(sourceCodeProperty, "sourceCode")
QBS_STRING_CONSTANT(sourceDirectoryProperty, "sourceDirectory")
QBS_STRING_CONSTANT(submodulesProperty, "submodules")
diff --git a/src/lib/corelib/tools/stringutils.h b/src/lib/corelib/tools/stringutils.h
index 7b551a544..59acdccbd 100644
--- a/src/lib/corelib/tools/stringutils.h
+++ b/src/lib/corelib/tools/stringutils.h
@@ -77,14 +77,14 @@ static inline std::string trimmed(const std::string &s)
// trim from start
static const auto ltrim = [](std::string &s) -> std::string & {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
- std::not1(std::ptr_fun<int, int>(std::isspace))));
+ [](char c){ return !std::isspace(c); }));
return s;
};
// trim from end
static const auto rtrim = [](std::string &s) -> std::string & {
s.erase(std::find_if(s.rbegin(), s.rend(),
- std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
+ [](char c){ return !std::isspace(c); }).base(), s.end());
return s;
};
diff --git a/src/lib/corelib/tools/toolchains.cpp b/src/lib/corelib/tools/toolchains.cpp
index 0d793f8aa..6263fb199 100644
--- a/src/lib/corelib/tools/toolchains.cpp
+++ b/src/lib/corelib/tools/toolchains.cpp
@@ -49,9 +49,11 @@ namespace qbs {
namespace Internal {
static const QString clangToolchain() { return QStringLiteral("clang"); }
+static const QString clangClToolchain() { return QStringLiteral("clang-cl"); }
static const QString gccToolchain() { return QStringLiteral("gcc"); }
static const QString llvmToolchain() { return QStringLiteral("llvm"); }
static const QString mingwToolchain() { return QStringLiteral("mingw"); }
+static const QString msvcToolchain() { return QStringLiteral("msvc"); }
}
using namespace Internal;
@@ -64,7 +66,8 @@ QStringList canonicalToolchain(const QStringList &toolchain)
llvmToolchain(),
mingwToolchain(),
gccToolchain(),
- QStringLiteral("msvc")
+ clangClToolchain(),
+ msvcToolchain()
};
// Canonicalize each toolchain in the toolchain list,
@@ -110,6 +113,8 @@ QStringList canonicalToolchain(const QString &name)
else if (toolchainName == llvmToolchain() ||
toolchainName == mingwToolchain()) {
toolchains << canonicalToolchain(QStringLiteral("gcc"));
+ } else if (toolchainName == clangClToolchain()) {
+ toolchains << canonicalToolchain(msvcToolchain());
}
return toolchains;
}
diff --git a/src/lib/corelib/tools/tools.pri b/src/lib/corelib/tools/tools.pri
index 89d752671..00d87ecc7 100644
--- a/src/lib/corelib/tools/tools.pri
+++ b/src/lib/corelib/tools/tools.pri
@@ -10,6 +10,7 @@ QBS_SYSTEM_SETTINGS_DIR = $$(QBS_SYSTEM_SETTINGS_DIR)
HEADERS += \
$$PWD/architectures.h \
$$PWD/buildgraphlocker.h \
+ $$PWD/clangclinfo.h \
$$PWD/codelocation.h \
$$PWD/commandechomode.h \
$$PWD/dynamictypecheck.h \
@@ -68,6 +69,7 @@ HEADERS += \
SOURCES += \
$$PWD/architectures.cpp \
$$PWD/buildgraphlocker.cpp \
+ $$PWD/clangclinfo.cpp \
$$PWD/codelocation.cpp \
$$PWD/commandechomode.cpp \
$$PWD/error.cpp \
diff --git a/src/lib/corelib/tools/version.cpp b/src/lib/corelib/tools/version.cpp
index dfb7f49b7..f653256b3 100644
--- a/src/lib/corelib/tools/version.cpp
+++ b/src/lib/corelib/tools/version.cpp
@@ -44,50 +44,6 @@
namespace qbs {
-Version::Version(int major, int minor, int patch, int buildNr)
- : m_major(major), m_minor(minor), m_patch(patch), m_build(buildNr)
-{
-}
-
-int Version::majorVersion() const
-{
- return m_major;
-}
-
-void Version::setMajorVersion(int major)
-{
- m_major = major;
-}
-
-int Version::minorVersion() const
-{
- return m_minor;
-}
-
-void Version::setMinorVersion(int minor)
-{
- m_minor = minor;
-}
-int Version::patchLevel() const
-{
- return m_patch;
-}
-
-void Version::setPatchLevel(int patch)
-{
- m_patch = patch;
-}
-
-int Version::buildNumber() const
-{
- return m_build;
-}
-
-void Version::setBuildNumber(int nr)
-{
- m_build = nr;
-}
-
Version Version::fromString(const QString &versionString, bool buildNumberAllowed)
{
QString pattern = QStringLiteral("(\\d+)"); // At least one number.
@@ -118,32 +74,6 @@ QString Version::toString(const QChar &separator, const QChar &buildSeparator) c
QString::number(m_patch), separator);
}
-int compare(const Version &lhs, const Version &rhs)
-{
- if (lhs.majorVersion() < rhs.majorVersion())
- return -1;
- if (lhs.majorVersion() > rhs.majorVersion())
- return 1;
- if (lhs.minorVersion() < rhs.minorVersion())
- return -1;
- if (lhs.minorVersion() > rhs.minorVersion())
- return 1;
- if (lhs.patchLevel() < rhs.patchLevel())
- return -1;
- if (lhs.patchLevel() > rhs.patchLevel())
- return 1;
- if (lhs.buildNumber() < rhs.buildNumber())
- return -1;
- if (lhs.buildNumber() > rhs.buildNumber())
- return 1;
- return 0;
-}
-
-VersionRange::VersionRange(const Version &minVersion, const Version &maxVersion)
- : minimum(minVersion), maximum(maxVersion)
-{
-}
-
VersionRange &VersionRange::narrowDown(const VersionRange &other)
{
if (other.minimum > minimum)
diff --git a/src/lib/corelib/tools/version.h b/src/lib/corelib/tools/version.h
index a0239a6e4..63ad3f88c 100644
--- a/src/lib/corelib/tools/version.h
+++ b/src/lib/corelib/tools/version.h
@@ -54,22 +54,24 @@ namespace qbs {
class QBS_EXPORT Version
{
public:
- explicit Version(int majorVersion = 0, int minorVersion = 0, int patchLevel = 0,
- int buildNr = 0);
+ constexpr explicit Version(int majorVersion = 0, int minorVersion = 0, int patchLevel = 0,
+ int buildNr = 0)
+ : m_major(majorVersion), m_minor(minorVersion), m_patch(patchLevel), m_build(buildNr)
+ { }
- bool isValid() const { return m_major || m_minor || m_patch || m_build; }
+ constexpr bool isValid() const { return m_major || m_minor || m_patch || m_build; }
- int majorVersion() const;
- void setMajorVersion(int majorVersion);
+ constexpr int majorVersion() const { return m_major; }
+ constexpr void setMajorVersion(int majorVersion) { m_major = majorVersion; }
- int minorVersion() const;
- void setMinorVersion(int minorVersion);
+ constexpr int minorVersion() const { return m_minor; }
+ constexpr void setMinorVersion(int minorVersion) { m_minor = minorVersion;}
- int patchLevel() const;
- void setPatchLevel(int patchLevel);
+ constexpr int patchLevel() const { return m_patch; }
+ constexpr void setPatchLevel(int patchLevel) { m_patch = patchLevel; }
- int buildNumber() const;
- void setBuildNumber(int nr);
+ constexpr int buildNumber() const { return m_build; }
+ constexpr void setBuildNumber(int nr) { m_build = nr; }
static Version fromString(const QString &versionString, bool buildNumberAllowed = false);
QString toString(const QChar &separator = QLatin1Char('.'),
@@ -85,8 +87,10 @@ private:
class VersionRange
{
public:
- VersionRange() = default;
- VersionRange(const Version &minVersion, const Version &maxVersion);
+ constexpr VersionRange() = default;
+ constexpr VersionRange(const Version &minVersion, const Version &maxVersion)
+ : minimum(minVersion), maximum(maxVersion)
+ { }
Version minimum;
Version maximum; // exclusive
@@ -94,13 +98,39 @@ public:
VersionRange &narrowDown(const VersionRange &other);
};
-QBS_EXPORT int compare(const Version &lhs, const Version &rhs);
-inline bool operator==(const Version &lhs, const Version &rhs) { return compare(lhs, rhs) == 0; }
-inline bool operator!=(const Version &lhs, const Version &rhs) { return !operator==(lhs, rhs); }
-inline bool operator<(const Version &lhs, const Version &rhs) { return compare(lhs, rhs) < 0; }
-inline bool operator>(const Version &lhs, const Version &rhs) { return compare(lhs, rhs) > 0; }
-inline bool operator<=(const Version &lhs, const Version &rhs) { return !operator>(lhs, rhs); }
-inline bool operator>=(const Version &lhs, const Version &rhs) { return !operator<(lhs, rhs); }
+constexpr inline int compare(const Version &lhs, const Version &rhs)
+{
+ if (lhs.majorVersion() < rhs.majorVersion())
+ return -1;
+ if (lhs.majorVersion() > rhs.majorVersion())
+ return 1;
+ if (lhs.minorVersion() < rhs.minorVersion())
+ return -1;
+ if (lhs.minorVersion() > rhs.minorVersion())
+ return 1;
+ if (lhs.patchLevel() < rhs.patchLevel())
+ return -1;
+ if (lhs.patchLevel() > rhs.patchLevel())
+ return 1;
+ if (lhs.buildNumber() < rhs.buildNumber())
+ return -1;
+ if (lhs.buildNumber() > rhs.buildNumber())
+ return 1;
+ return 0;
+}
+
+constexpr inline bool operator==(const Version &lhs, const Version &rhs)
+{ return compare(lhs, rhs) == 0; }
+constexpr inline bool operator!=(const Version &lhs, const Version &rhs)
+{ return !operator==(lhs, rhs); }
+constexpr inline bool operator<(const Version &lhs, const Version &rhs)
+{ return compare(lhs, rhs) < 0; }
+constexpr inline bool operator>(const Version &lhs, const Version &rhs)
+{ return compare(lhs, rhs) > 0; }
+constexpr inline bool operator<=(const Version &lhs, const Version &rhs)
+{ return !operator>(lhs, rhs); }
+constexpr inline bool operator>=(const Version &lhs, const Version &rhs)
+{ return !operator<(lhs, rhs); }
} // namespace qbs
diff --git a/src/lib/corelib/tools/visualstudioversioninfo.cpp b/src/lib/corelib/tools/visualstudioversioninfo.cpp
index d4f8844fa..b5ee3e719 100644
--- a/src/lib/corelib/tools/visualstudioversioninfo.cpp
+++ b/src/lib/corelib/tools/visualstudioversioninfo.cpp
@@ -46,9 +46,7 @@
namespace qbs {
namespace Internal {
-VisualStudioVersionInfo::VisualStudioVersionInfo()
-{
-}
+VisualStudioVersionInfo::VisualStudioVersionInfo() = default;
VisualStudioVersionInfo::VisualStudioVersionInfo(const Version &version)
: m_version(version)
@@ -176,7 +174,7 @@ QString VisualStudioVersionInfo::platformToolsetVersion() const
{16, QStringLiteral("v142")}, // VS 2019
{15, QStringLiteral("v141")} // VS 2017
};
- for (auto p : table) {
+ for (const auto &p : table) {
if (p.first == m_version.majorVersion())
return p.second;
}
diff --git a/src/lib/corelib/tools/vsenvironmentdetector.cpp b/src/lib/corelib/tools/vsenvironmentdetector.cpp
index f8f98e7b7..95451435a 100644
--- a/src/lib/corelib/tools/vsenvironmentdetector.cpp
+++ b/src/lib/corelib/tools/vsenvironmentdetector.cpp
@@ -193,13 +193,13 @@ bool VsEnvironmentDetector::startDetection(const std::vector<MSVC *> &compatible
static void batClearVars(QTextStream &s, const QStringList &varnames)
{
for (const QString &varname : varnames)
- s << "set " << varname << '=' << endl;
+ s << "set " << varname << '=' << Qt::endl;
}
static void batPrintVars(QTextStream &s, const QStringList &varnames)
{
for (const QString &varname : varnames)
- s << "echo " << varname << "=%" << varname << '%' << endl;
+ s << "echo " << varname << "=%" << varname << '%' << Qt::endl;
}
static QString vcArchitecture(const MSVC *msvc)
@@ -232,7 +232,10 @@ void VsEnvironmentDetector::writeBatchFile(QIODevice *device, const QString &vcv
<< QStringLiteral("INCLUDE") << QStringLiteral("LIB") << QStringLiteral("WindowsSdkDir")
<< QStringLiteral("WindowsSDKVersion") << QStringLiteral("VSINSTALLDIR");
QTextStream s(device);
+ using Qt::endl;
s << "@echo off" << endl;
+ // Avoid execution of powershell (in vsdevcmd.bat), which is not in the cleared PATH
+ s << "set VSCMD_SKIP_SENDTELEMETRY=1" << endl;
for (const MSVC *msvc : msvcs) {
s << "echo --" << msvc->architecture << "--" << endl
<< "setlocal" << endl;
diff --git a/src/lib/scriptengine/use_scriptengine.pri b/src/lib/scriptengine/use_scriptengine.pri
index 6450e171f..e8f82a949 100644
--- a/src/lib/scriptengine/use_scriptengine.pri
+++ b/src/lib/scriptengine/use_scriptengine.pri
@@ -3,7 +3,15 @@
isEmpty(QBSLIBDIR) {
QBSLIBDIR = $$shadowed($$PWD/../../../$${QBS_LIBRARY_DIRNAME})
}
- LIBS += -L$$QBSLIBDIR -lqbsscriptengine$$qtPlatformTargetSuffix()
+
+ LIBS += -L$$QBSLIBDIR
+ macos {
+ LIBS += -lqbsscriptengine
+ }
+ else {
+ LIBS += -lqbsscriptengine$$qtPlatformTargetSuffix()
+ }
+
}
INCLUDEPATH += \
diff --git a/src/libexec/qbs_processlauncher/launchersockethandler.cpp b/src/libexec/qbs_processlauncher/launchersockethandler.cpp
index 53bd81a9a..dac1b0b2e 100644
--- a/src/libexec/qbs_processlauncher/launchersockethandler.cpp
+++ b/src/libexec/qbs_processlauncher/launchersockethandler.cpp
@@ -273,8 +273,7 @@ void LauncherSocketHandler::sendPacket(const LauncherPacket &packet)
Process *LauncherSocketHandler::setupProcess(quintptr token)
{
const auto p = new Process(token, this);
- connect(p, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error),
- this, &LauncherSocketHandler::handleProcessError);
+ connect(p, &QProcess::errorOccurred, this, &LauncherSocketHandler::handleProcessError);
connect(p, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
this, &LauncherSocketHandler::handleProcessFinished);
connect(p, &Process::failedToStop, this, &LauncherSocketHandler::handleStopFailure);
diff --git a/src/packages/archive/archive.qbs b/src/packages/archive/archive.qbs
index 468606368..9a9b09ba7 100644
--- a/src/packages/archive/archive.qbs
+++ b/src/packages/archive/archive.qbs
@@ -69,7 +69,7 @@ QbsProduct {
inputFilePaths.sort();
var tf;
try {
- tf = new TextFile(outputFilePath, TextFile.ReadWrite);
+ tf = new TextFile(outputFilePath, TextFile.WriteOnly);
for (var i = 0; i < inputFilePaths.length; ++i) {
var relativePath = FileInfo.relativePath(baseDirectory, inputFilePaths[i]);
tf.writeLine(relativePath);
diff --git a/src/packages/chocolatey/chocolatey.qbs b/src/packages/chocolatey/chocolatey.qbs
index 27cc1e489..e878f8e0d 100644
--- a/src/packages/chocolatey/chocolatey.qbs
+++ b/src/packages/chocolatey/chocolatey.qbs
@@ -14,7 +14,7 @@ Product {
id: choco
condition: qbs.targetOS.contains("windows")
names: ["choco"]
- platformPaths: { // TODO: Change to platformSearchPaths in qbs 1.15
+ platformSearchPaths: {
var chocolateyInstall = Environment.getEnv("ChocolateyInstall");
if (chocolateyInstall)
return [FileInfo.joinPaths(chocolateyInstall, "bin")];
diff --git a/src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.cpp b/src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.cpp
index bc13ec480..93be2804b 100644
--- a/src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.cpp
+++ b/src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.cpp
@@ -58,9 +58,7 @@ using namespace Internal;
const QString ClangCompilationDatabaseGenerator::DefaultDatabaseFileName =
QStringLiteral("compile_commands.json");
-ClangCompilationDatabaseGenerator::ClangCompilationDatabaseGenerator()
-{
-}
+ClangCompilationDatabaseGenerator::ClangCompilationDatabaseGenerator() = default;
QString ClangCompilationDatabaseGenerator::generatorName() const
{
diff --git a/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.cpp b/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.cpp
index 911873cf4..0bbfbaafb 100644
--- a/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.cpp
+++ b/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.cpp
@@ -499,7 +499,7 @@ void ArmGeneralSettingsGroup::buildLibraryOptionsTwoPage(
}
void ArmGeneralSettingsGroup::buildLibraryConfigPage(
- const QString baseDirectory,
+ const QString &baseDirectory,
const ProductData &qbsProduct)
{
const LibraryConfigPageOptions opts(baseDirectory, qbsProduct);
@@ -523,7 +523,7 @@ void ArmGeneralSettingsGroup::buildLibraryConfigPage(
}
void ArmGeneralSettingsGroup::buildOutputPage(
- const QString baseDirectory,
+ const QString &baseDirectory,
const ProductData &qbsProduct)
{
const OutputPageOptions opts(baseDirectory, qbsProduct);
diff --git a/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.h b/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.h
index 420e98008..0b1564b3c 100644
--- a/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.h
+++ b/src/plugins/generator/iarew/archs/arm/armgeneralsettingsgroup_v8.h
@@ -49,9 +49,9 @@ private:
void buildTargetPage(const ProductData &qbsProduct);
void buildLibraryOptionsOnePage(const ProductData &qbsProduct);
void buildLibraryOptionsTwoPage(const ProductData &qbsProduct);
- void buildLibraryConfigPage(const QString baseDirectory,
+ void buildLibraryConfigPage(const QString &baseDirectory,
const ProductData &qbsProduct);
- void buildOutputPage(const QString baseDirectory,
+ void buildOutputPage(const QString &baseDirectory,
const ProductData &qbsProduct);
};
diff --git a/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.cpp b/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.cpp
index 2d3780e4f..8a9d13b9b 100644
--- a/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.cpp
+++ b/src/plugins/generator/iarew/archs/stm8/stm8linkersettingsgroup_v3.cpp
@@ -175,7 +175,7 @@ struct OptimizationsPageOptions final
QLatin1String("--merge_duplicate_sections"));
}
- bool mergeDuplicateSections = 0;
+ bool mergeDuplicateSections = true;
};
// Output page options.
@@ -192,7 +192,7 @@ struct OutputPageOptions final
}
QString outputFile;
- bool enableDebugInfo = 1;
+ bool enableDebugInfo = true;
};
// List page options.
diff --git a/src/plugins/generator/iarew/iarew.pro b/src/plugins/generator/iarew/iarew.pro
index 074635047..542449510 100644
--- a/src/plugins/generator/iarew/iarew.pro
+++ b/src/plugins/generator/iarew/iarew.pro
@@ -37,7 +37,6 @@ SOURCES += \
$$PWD/iarewsourcefilespropertygroup.cpp \
$$PWD/iarewtoolchainpropertygroup.cpp \
$$PWD/iarewutils.cpp \
- $$PWD/iarewversioninfo.cpp \
$$PWD/iarewworkspace.cpp \
$$PWD/iarewworkspacewriter.cpp
diff --git a/src/plugins/generator/iarew/iarew.qbs b/src/plugins/generator/iarew/iarew.qbs
index 7b2270426..82c95ea5d 100644
--- a/src/plugins/generator/iarew/iarew.qbs
+++ b/src/plugins/generator/iarew/iarew.qbs
@@ -31,7 +31,6 @@ QbsPlugin {
"iarewtoolchainpropertygroup.h",
"iarewutils.cpp",
"iarewutils.h",
- "iarewversioninfo.cpp",
"iarewversioninfo.h",
"iarewworkspace.cpp",
"iarewworkspace.h",
diff --git a/src/plugins/generator/iarew/iarewfileversionproperty.cpp b/src/plugins/generator/iarew/iarewfileversionproperty.cpp
index 446b385b8..4324405a1 100644
--- a/src/plugins/generator/iarew/iarewfileversionproperty.cpp
+++ b/src/plugins/generator/iarew/iarewfileversionproperty.cpp
@@ -33,21 +33,21 @@
namespace qbs {
-static QByteArray buildFileVersion(const IarewVersionInfo &versionInfo)
+static QByteArray buildFileVersion(const gen::VersionInfo &versionInfo)
{
switch (versionInfo.marketingVersion()) {
case 3:
case 7:
case 8:
case 10:
- return QByteArrayLiteral('3');
+ return QByteArrayLiteral("3");
default:
return {};
}
}
IarewFileVersionProperty::IarewFileVersionProperty(
- const IarewVersionInfo &versionInfo)
+ const gen::VersionInfo &versionInfo)
{
setName(QByteArrayLiteral("fileVersion"));
const QByteArray fileVersion = buildFileVersion(versionInfo);
diff --git a/src/plugins/generator/iarew/iarewfileversionproperty.h b/src/plugins/generator/iarew/iarewfileversionproperty.h
index d377979fa..2ed56c1e6 100644
--- a/src/plugins/generator/iarew/iarewfileversionproperty.h
+++ b/src/plugins/generator/iarew/iarewfileversionproperty.h
@@ -31,17 +31,16 @@
#ifndef QBS_IAREWFILEVERSIONPROPERTY_H
#define QBS_IAREWFILEVERSIONPROPERTY_H
+#include <generators/generatorversioninfo.h>
#include <generators/xmlproperty.h>
namespace qbs {
-class IarewVersionInfo;
-
class IarewFileVersionProperty final : public gen::xml::Property
{
public:
explicit IarewFileVersionProperty(
- const IarewVersionInfo &versionInfo);
+ const gen::VersionInfo &versionInfo);
};
} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewgenerator.cpp b/src/plugins/generator/iarew/iarewgenerator.cpp
index e6b308182..c5345a6dd 100644
--- a/src/plugins/generator/iarew/iarewgenerator.cpp
+++ b/src/plugins/generator/iarew/iarewgenerator.cpp
@@ -96,7 +96,7 @@ static void writeWorkspace(const std::shared_ptr<IarewWorkspace> &wokspace,
QFileInfo(workspaceFilePath).fileName());
}
-IarewGenerator::IarewGenerator(const IarewVersionInfo &versionInfo)
+IarewGenerator::IarewGenerator(const gen::VersionInfo &versionInfo)
: m_versionInfo(versionInfo)
{
}
diff --git a/src/plugins/generator/iarew/iarewgenerator.h b/src/plugins/generator/iarew/iarewgenerator.h
index f8c1298f0..fa1d93bc3 100644
--- a/src/plugins/generator/iarew/iarewgenerator.h
+++ b/src/plugins/generator/iarew/iarewgenerator.h
@@ -44,7 +44,7 @@ class IarewWorkspace;
class IarewGenerator final : public ProjectGenerator, private IGeneratableProjectVisitor
{
public:
- explicit IarewGenerator(const IarewVersionInfo &versionInfo);
+ explicit IarewGenerator(const gen::VersionInfo &versionInfo);
QString generatorName() const final;
void generate() final;
@@ -59,7 +59,7 @@ private:
const GeneratableProjectData &projectData,
const GeneratableProductData &productData) final;
- const IarewVersionInfo m_versionInfo;
+ const gen::VersionInfo m_versionInfo;
std::shared_ptr<IarewWorkspace> m_workspace;
QString m_workspaceFilePath;
std::map<QString, std::shared_ptr<IarewProject>> m_projects;
diff --git a/src/plugins/generator/iarew/iarewgeneratorplugin.cpp b/src/plugins/generator/iarew/iarewgeneratorplugin.cpp
index bd75c7ad5..bdd15c485 100644
--- a/src/plugins/generator/iarew/iarewgeneratorplugin.cpp
+++ b/src/plugins/generator/iarew/iarewgeneratorplugin.cpp
@@ -45,7 +45,7 @@
static void QbsIarewGeneratorPluginLoad()
{
- for (const auto &info : qbs::IarewVersionInfo::knownVersions()) {
+ for (const auto &info : qbs::IarewVersionInfo::knownVersions) {
qbs::ProjectGeneratorManager::registerGenerator(
std::make_shared<qbs::IarewGenerator>(info));
}
diff --git a/src/plugins/generator/iarew/iarewoptionpropertygroup.cpp b/src/plugins/generator/iarew/iarewoptionpropertygroup.cpp
index 8b9f79f1c..c44b30ed2 100644
--- a/src/plugins/generator/iarew/iarewoptionpropertygroup.cpp
+++ b/src/plugins/generator/iarew/iarewoptionpropertygroup.cpp
@@ -33,20 +33,20 @@
namespace qbs {
IarewOptionPropertyGroup::IarewOptionPropertyGroup(
- QByteArray name, const QVariantList &states, int version)
+ const QByteArray &name, QVariantList states, int version)
: gen::xml::PropertyGroup(QByteArrayLiteral("option"))
{
// Append name property item.
appendChild<gen::xml::Property>(QByteArrayLiteral("name"),
- std::move(name));
+ name);
// Append version property item.
if (version >= 0)
appendChild<gen::xml::Property>(QByteArrayLiteral("version"),
- std::move(version));
+ version);
// Append state property items.
- for (const auto &state : states) {
+ for (auto &state : states) {
if (state.isNull())
continue;
appendChild<gen::xml::Property>(QByteArrayLiteral("state"),
diff --git a/src/plugins/generator/iarew/iarewoptionpropertygroup.h b/src/plugins/generator/iarew/iarewoptionpropertygroup.h
index d24fe3a9d..d80df2838 100644
--- a/src/plugins/generator/iarew/iarewoptionpropertygroup.h
+++ b/src/plugins/generator/iarew/iarewoptionpropertygroup.h
@@ -41,8 +41,7 @@ class IarewOptionPropertyGroup final
: public gen::xml::PropertyGroup
{
public:
- explicit IarewOptionPropertyGroup(
- QByteArray name, const QVariantList &states,
+ explicit IarewOptionPropertyGroup(const QByteArray &name, QVariantList states,
int version = -1);
};
diff --git a/src/plugins/generator/iarew/iarewproject.cpp b/src/plugins/generator/iarew/iarewproject.cpp
index 3e6a03ac2..f33ae4fcb 100644
--- a/src/plugins/generator/iarew/iarewproject.cpp
+++ b/src/plugins/generator/iarew/iarewproject.cpp
@@ -46,7 +46,7 @@ namespace qbs {
IarewProject::IarewProject(const GeneratableProject &genProject,
const GeneratableProductData &genProduct,
- const IarewVersionInfo &versionInfo)
+ const gen::VersionInfo &versionInfo)
{
Q_ASSERT(genProject.projects.size() == genProject.commandLines.size());
Q_ASSERT(genProject.projects.size() == genProduct.data.size());
diff --git a/src/plugins/generator/iarew/iarewproject.h b/src/plugins/generator/iarew/iarewproject.h
index 567a58c55..df260fcd8 100644
--- a/src/plugins/generator/iarew/iarewproject.h
+++ b/src/plugins/generator/iarew/iarewproject.h
@@ -39,14 +39,12 @@
namespace qbs {
-class IarewVersionInfo;
-
class IarewProject final : public gen::xml::Project
{
public:
explicit IarewProject(const GeneratableProject &genProject,
const GeneratableProductData &genProduct,
- const IarewVersionInfo &versionInfo);
+ const gen::VersionInfo &versionInfo);
private:
std::vector<std::unique_ptr<gen::xml::PropertyGroupFactory>> m_factories;
};
diff --git a/src/plugins/generator/iarew/iarewsettingspropertygroup.cpp b/src/plugins/generator/iarew/iarewsettingspropertygroup.cpp
index 3e7b6dae7..a07d59e0f 100644
--- a/src/plugins/generator/iarew/iarewsettingspropertygroup.cpp
+++ b/src/plugins/generator/iarew/iarewsettingspropertygroup.cpp
@@ -63,9 +63,10 @@ IarewSettingsPropertyGroup::IarewSettingsPropertyGroup()
QByteArrayLiteral("debug"), QVariant{});
}
-void IarewSettingsPropertyGroup::setName(QByteArray name)
+void IarewSettingsPropertyGroup::setName(const QByteArray &name)
{
- m_nameProperty->setValue(std::move(name));
+ // There is no way to move-construct a QVariant from T, thus name is shallow-copied
+ m_nameProperty->setValue(QVariant(name));
}
QByteArray IarewSettingsPropertyGroup::name() const
@@ -95,12 +96,11 @@ void IarewSettingsPropertyGroup::setDataDebugInfo(int debugInfo)
}
void IarewSettingsPropertyGroup::addOptionsGroup(
- QByteArray name,
- const QVariantList &states,
+ const QByteArray &name,
+ QVariantList states,
int version)
{
- m_dataPropertyGroup->appendChild<IarewOptionPropertyGroup>(
- std::move(name), states, std::move(version));
+ m_dataPropertyGroup->appendChild<IarewOptionPropertyGroup>(name, std::move(states), version);
}
} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewsettingspropertygroup.h b/src/plugins/generator/iarew/iarewsettingspropertygroup.h
index 4dea76f1a..b1feebcc7 100644
--- a/src/plugins/generator/iarew/iarewsettingspropertygroup.h
+++ b/src/plugins/generator/iarew/iarewsettingspropertygroup.h
@@ -40,7 +40,7 @@ class IarewSettingsPropertyGroup : public gen::xml::PropertyGroup
public:
explicit IarewSettingsPropertyGroup();
- void setName(QByteArray name);
+ void setName(const QByteArray &name);
QByteArray name() const;
void setArchiveVersion(int archiveVersion);
@@ -50,7 +50,7 @@ protected:
void setDataVersion(int dataVersion);
void setDataDebugInfo(int debugInfo);
- void addOptionsGroup(QByteArray name, const QVariantList &states,
+ void addOptionsGroup(const QByteArray &name, QVariantList states,
int version = -1);
private:
diff --git a/src/plugins/generator/iarew/iarewsourcefilepropertygroup.h b/src/plugins/generator/iarew/iarewsourcefilepropertygroup.h
index 5f88cec27..6d0083573 100644
--- a/src/plugins/generator/iarew/iarewsourcefilepropertygroup.h
+++ b/src/plugins/generator/iarew/iarewsourcefilepropertygroup.h
@@ -36,7 +36,7 @@
namespace qbs {
class ArtifactData;
-class GeneratableProject;
+struct GeneratableProject;
class IarewSourceFilePropertyGroup final
: public gen::xml::PropertyGroup
diff --git a/src/plugins/generator/iarew/iarewversioninfo.cpp b/src/plugins/generator/iarew/iarewversioninfo.cpp
deleted file mode 100644
index 41a788e98..000000000
--- a/src/plugins/generator/iarew/iarewversioninfo.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
-** 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$
-**
-****************************************************************************/
-
-#include "iarewversioninfo.h"
-
-#include <QtCore/qdebug.h>
-
-namespace qbs {
-
-IarewVersionInfo::IarewVersionInfo(
- const Version &version,
- const std::set<gen::utils::Architecture> &archs)
- : gen::VersionInfo(version, archs)
-{
-}
-
-std::set<IarewVersionInfo> IarewVersionInfo::knownVersions()
-{
- static const std::set<IarewVersionInfo> known = {
- {Version(8), {gen::utils::Architecture::Arm}},
- {Version(7), {gen::utils::Architecture::Avr,
- gen::utils::Architecture::Msp430}},
- {Version(10), {gen::utils::Architecture::Mcs51}},
- {Version(3), {gen::utils::Architecture::Stm8}},
- };
- return known;
-}
-
-int IarewVersionInfo::marketingVersion() const
-{
- const auto mv = gen::VersionInfo::marketingVersion();
- for (const IarewVersionInfo &known : knownVersions()) {
- if (known.version().majorVersion() == mv)
- return mv;
- }
- qWarning() << QStringLiteral("Unrecognized IAR EW version: ")
- << version().toString();
- return 0;
-}
-
-} // namespace qbs
diff --git a/src/plugins/generator/iarew/iarewversioninfo.h b/src/plugins/generator/iarew/iarewversioninfo.h
index 4fd1b1fbc..3dc459557 100644
--- a/src/plugins/generator/iarew/iarewversioninfo.h
+++ b/src/plugins/generator/iarew/iarewversioninfo.h
@@ -44,18 +44,17 @@
#include <generators/generatorversioninfo.h>
namespace qbs {
-
-class IarewVersionInfo final : public gen::VersionInfo
-{
-public:
- IarewVersionInfo(const Version &version,
- const std::set<gen::utils::Architecture> &archs);
-
- int marketingVersion() const final;
-
- static std::set<IarewVersionInfo> knownVersions();
+namespace IarewVersionInfo {
+
+constexpr gen::VersionInfo knownVersions[] = {
+ {Version(8), {gen::utils::Architecture::Arm}},
+ {Version(7), {gen::utils::Architecture::Avr,
+ gen::utils::Architecture::Msp430}},
+ {Version(10), {gen::utils::Architecture::Mcs51}},
+ {Version(3), {gen::utils::Architecture::Stm8}},
};
+} // namespace IarewVersionInfo
} // namespace qbs
#endif // QBS_IAREWVERSIONINFO_H
diff --git a/src/plugins/generator/keiluv/keiluv.pro b/src/plugins/generator/keiluv/keiluv.pro
index 52d7c0ed4..052277ef8 100644
--- a/src/plugins/generator/keiluv/keiluv.pro
+++ b/src/plugins/generator/keiluv/keiluv.pro
@@ -28,7 +28,6 @@ SOURCES += \
$$PWD/keiluvproject.cpp \
$$PWD/keiluvprojectwriter.cpp \
$$PWD/keiluvutils.cpp \
- $$PWD/keiluvversioninfo.cpp \
$$PWD/keiluvworkspace.cpp \
$$PWD/keiluvworkspacewriter.cpp
diff --git a/src/plugins/generator/keiluv/keiluv.qbs b/src/plugins/generator/keiluv/keiluv.qbs
index 65bf6d65b..65f8fa029 100644
--- a/src/plugins/generator/keiluv/keiluv.qbs
+++ b/src/plugins/generator/keiluv/keiluv.qbs
@@ -21,7 +21,6 @@ QbsPlugin {
"keiluvprojectwriter.h",
"keiluvutils.cpp",
"keiluvutils.h",
- "keiluvversioninfo.cpp",
"keiluvversioninfo.h",
"keiluvworkspace.cpp",
"keiluvworkspace.h",
diff --git a/src/plugins/generator/keiluv/keiluvgenerator.cpp b/src/plugins/generator/keiluv/keiluvgenerator.cpp
index e3c959e8d..f98f55abe 100644
--- a/src/plugins/generator/keiluv/keiluvgenerator.cpp
+++ b/src/plugins/generator/keiluv/keiluvgenerator.cpp
@@ -84,7 +84,7 @@ static void writeWorkspace(const std::shared_ptr<KeiluvWorkspace> &wokspace,
QFileInfo(workspaceFilePath).fileName());
}
-KeiluvGenerator::KeiluvGenerator(const KeiluvVersionInfo &versionInfo)
+KeiluvGenerator::KeiluvGenerator(const gen::VersionInfo &versionInfo)
: m_versionInfo(versionInfo)
{
}
diff --git a/src/plugins/generator/keiluv/keiluvgenerator.h b/src/plugins/generator/keiluv/keiluvgenerator.h
index 769519562..25b89b9c8 100644
--- a/src/plugins/generator/keiluv/keiluvgenerator.h
+++ b/src/plugins/generator/keiluv/keiluvgenerator.h
@@ -45,7 +45,7 @@ class KeiluvGenerator final : public ProjectGenerator,
private IGeneratableProjectVisitor
{
public:
- explicit KeiluvGenerator(const KeiluvVersionInfo &versionInfo);
+ explicit KeiluvGenerator(const gen::VersionInfo &versionInfo);
QString generatorName() const final;
void generate() final;
@@ -60,7 +60,7 @@ private:
const GeneratableProjectData &projectData,
const GeneratableProductData &productData) final;
- const KeiluvVersionInfo m_versionInfo;
+ const gen::VersionInfo m_versionInfo;
std::shared_ptr<KeiluvWorkspace> m_workspace;
QString m_workspaceFilePath;
std::map<QString, std::shared_ptr<KeiluvProject>> m_projects;
diff --git a/src/plugins/generator/keiluv/keiluvgeneratorplugin.cpp b/src/plugins/generator/keiluv/keiluvgeneratorplugin.cpp
index 91b73ef71..abbccc3da 100644
--- a/src/plugins/generator/keiluv/keiluvgeneratorplugin.cpp
+++ b/src/plugins/generator/keiluv/keiluvgeneratorplugin.cpp
@@ -45,7 +45,7 @@
static void QbsKeiluvGeneratorPluginLoad()
{
- for (const auto &info : qbs::KeiluvVersionInfo::knownVersions()) {
+ for (const auto &info : qbs::KeiluvVersionInfo::knownVersions) {
qbs::ProjectGeneratorManager::registerGenerator(
std::make_shared<qbs::KeiluvGenerator>(info));
}
diff --git a/src/plugins/generator/keiluv/keiluvproject.cpp b/src/plugins/generator/keiluv/keiluvproject.cpp
index 476ce8e69..89db73b1f 100644
--- a/src/plugins/generator/keiluv/keiluvproject.cpp
+++ b/src/plugins/generator/keiluv/keiluvproject.cpp
@@ -40,7 +40,7 @@
namespace qbs {
-static QString keilProjectSchema(const KeiluvVersionInfo &info)
+static QString keilProjectSchema(const gen::VersionInfo &info)
{
const auto v = info.marketingVersion();
switch (v) {
@@ -51,10 +51,9 @@ static QString keilProjectSchema(const KeiluvVersionInfo &info)
}
}
-KeiluvProject::KeiluvProject(
- const qbs::GeneratableProject &genProject,
+KeiluvProject::KeiluvProject(const qbs::GeneratableProject &genProject,
const qbs::GeneratableProductData &genProduct,
- const KeiluvVersionInfo &versionInfo)
+ const gen::VersionInfo &versionInfo)
{
Q_ASSERT(genProject.projects.size() == genProject.commandLines.size());
Q_ASSERT(genProject.projects.size() == genProduct.data.size());
diff --git a/src/plugins/generator/keiluv/keiluvproject.h b/src/plugins/generator/keiluv/keiluvproject.h
index 98b2815ed..da86f71fd 100644
--- a/src/plugins/generator/keiluv/keiluvproject.h
+++ b/src/plugins/generator/keiluv/keiluvproject.h
@@ -40,15 +40,13 @@
namespace qbs {
-class KeiluvVersionInfo;
-
class KeiluvProject final : public gen::xml::Project
{
public:
explicit KeiluvProject(
const qbs::GeneratableProject &genProject,
const qbs::GeneratableProductData &genProduct,
- const KeiluvVersionInfo &versionInfo);
+ const gen::VersionInfo &versionInfo);
private:
std::vector<std::unique_ptr<gen::xml::PropertyGroupFactory>> m_factories;
};
diff --git a/src/plugins/generator/keiluv/keiluvversioninfo.cpp b/src/plugins/generator/keiluv/keiluvversioninfo.cpp
deleted file mode 100644
index 973d0a420..000000000
--- a/src/plugins/generator/keiluv/keiluvversioninfo.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Denis Shienkov <denis.shienkov@gmail.com>
-** 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$
-**
-****************************************************************************/
-
-#include "keiluvconstants.h"
-#include "keiluvversioninfo.h"
-
-#include <QtCore/qdebug.h>
-
-namespace qbs {
-
-KeiluvVersionInfo::KeiluvVersionInfo(
- const Version &version,
- const std::set<gen::utils::Architecture> &archs)
- : gen::VersionInfo(version, archs)
-{
-}
-
-std::set<KeiluvVersionInfo> KeiluvVersionInfo::knownVersions()
-{
- static const std::set<KeiluvVersionInfo> known = {
- {Version(KeiluvConstants::v5::kUVisionVersion),
- {gen::utils::Architecture::Mcs51,
- gen::utils::Architecture::Arm}},
- };
- return known;
-}
-
-int KeiluvVersionInfo::marketingVersion() const
-{
- const auto mv = gen::VersionInfo::marketingVersion();
- for (const KeiluvVersionInfo &known : knownVersions()) {
- if (known.version().majorVersion() == mv)
- return mv;
- }
- qWarning() << QStringLiteral("Unrecognized KEIL UV version: ")
- << version().toString();
- return 0;
-}
-
-} // namespace qbs
diff --git a/src/plugins/generator/keiluv/keiluvversioninfo.h b/src/plugins/generator/keiluv/keiluvversioninfo.h
index a64513492..cc379c3d7 100644
--- a/src/plugins/generator/keiluv/keiluvversioninfo.h
+++ b/src/plugins/generator/keiluv/keiluvversioninfo.h
@@ -40,22 +40,21 @@
#ifndef QBS_KEILUVVERSIONINFO_H
#define QBS_KEILUVVERSIONINFO_H
+#include "keiluvconstants.h"
+
#include <generators/generatorutils.h>
#include <generators/generatorversioninfo.h>
namespace qbs {
+namespace KeiluvVersionInfo {
-class KeiluvVersionInfo final : public gen::VersionInfo
-{
-public:
- KeiluvVersionInfo(const Version &version,
- const std::set<gen::utils::Architecture> &archs);
-
- int marketingVersion() const final;
-
- static std::set<KeiluvVersionInfo> knownVersions();
+constexpr gen::VersionInfo knownVersions[] = {
+ {Version(KeiluvConstants::v5::kUVisionVersion),
+ {gen::utils::Architecture::Mcs51,
+ gen::utils::Architecture::Arm}},
};
+} // namespace KeiluvVersionInfo
} // namespace qbs
#endif // QBS_KEILUVVERSIONINFO_H
diff --git a/src/plugins/generator/visualstudio/io/msbuildprojectwriter.cpp b/src/plugins/generator/visualstudio/io/msbuildprojectwriter.cpp
index 634bb2381..12fbe2da5 100644
--- a/src/plugins/generator/visualstudio/io/msbuildprojectwriter.cpp
+++ b/src/plugins/generator/visualstudio/io/msbuildprojectwriter.cpp
@@ -43,6 +43,8 @@
#include <QtCore/qxmlstream.h>
+#include <memory>
+
namespace qbs {
static const QString kMSBuildSchemaURI =
@@ -87,7 +89,7 @@ MSBuildProjectWriter::MSBuildProjectWriter(std::ostream *device)
: d(new MSBuildProjectWriterPrivate)
{
d->device = device;
- d->writer.reset(new QXmlStreamWriter(&d->buffer));
+ d->writer = std::make_unique<QXmlStreamWriter>(&d->buffer);
d->writer->setAutoFormatting(true);
}
diff --git a/src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.cpp b/src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.cpp
index e980249d6..625489ac6 100644
--- a/src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.cpp
+++ b/src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.cpp
@@ -64,9 +64,7 @@ VisualStudioSolutionWriter::VisualStudioSolutionWriter(std::ostream *device)
d->device = device;
}
-VisualStudioSolutionWriter::~VisualStudioSolutionWriter()
-{
-}
+VisualStudioSolutionWriter::~VisualStudioSolutionWriter() = default;
std::string VisualStudioSolutionWriter::projectBaseDirectory() const
{
diff --git a/src/plugins/generator/visualstudio/msbuild/imsbuildgroup.cpp b/src/plugins/generator/visualstudio/msbuild/imsbuildgroup.cpp
index c51f0e517..81078ecb9 100644
--- a/src/plugins/generator/visualstudio/msbuild/imsbuildgroup.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/imsbuildgroup.cpp
@@ -45,9 +45,7 @@ IMSBuildGroup::IMSBuildGroup(MSBuildProject *parent)
{
}
-IMSBuildGroup::~IMSBuildGroup()
-{
-}
+IMSBuildGroup::~IMSBuildGroup() = default;
QString IMSBuildGroup::condition() const
{
diff --git a/src/plugins/generator/visualstudio/msbuild/imsbuildnode.cpp b/src/plugins/generator/visualstudio/msbuild/imsbuildnode.cpp
index 4c70405c2..f563f7b07 100644
--- a/src/plugins/generator/visualstudio/msbuild/imsbuildnode.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/imsbuildnode.cpp
@@ -32,8 +32,6 @@
namespace qbs {
-IMSBuildNode::~IMSBuildNode()
-{
-}
+IMSBuildNode::~IMSBuildNode() = default;
} // namespace qbs
diff --git a/src/plugins/generator/visualstudio/msbuild/imsbuildnodevisitor.h b/src/plugins/generator/visualstudio/msbuild/imsbuildnodevisitor.h
index fe75c23f9..84239d648 100644
--- a/src/plugins/generator/visualstudio/msbuild/imsbuildnodevisitor.h
+++ b/src/plugins/generator/visualstudio/msbuild/imsbuildnodevisitor.h
@@ -46,7 +46,7 @@ class MSBuildPropertyGroup;
class IMSBuildNodeVisitor
{
public:
- virtual ~IMSBuildNodeVisitor() {}
+ virtual ~IMSBuildNodeVisitor() = default;
virtual void visitStart(const MSBuildImport *import) = 0;
virtual void visitEnd(const MSBuildImport *import) = 0;
diff --git a/src/plugins/generator/visualstudio/msbuild/imsbuildproperty.cpp b/src/plugins/generator/visualstudio/msbuild/imsbuildproperty.cpp
index 6e54f1e43..be18f1a5b 100644
--- a/src/plugins/generator/visualstudio/msbuild/imsbuildproperty.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/imsbuildproperty.cpp
@@ -46,9 +46,7 @@ IMSBuildProperty::IMSBuildProperty(QObject *parent)
{
}
-IMSBuildProperty::~IMSBuildProperty()
-{
-}
+IMSBuildProperty::~IMSBuildProperty() = default;
QString IMSBuildProperty::condition() const
{
diff --git a/src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.cpp b/src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.cpp
index 26c08cacb..4cbb01d04 100644
--- a/src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.cpp
@@ -29,6 +29,8 @@
****************************************************************************/
#include "msbuildfileitem.h"
+
+#include <memory>
#include "../msbuilditemmetadata.h"
namespace qbs {
@@ -43,12 +45,10 @@ MSBuildFileItem::MSBuildFileItem(const QString &name, IMSBuildItemGroup *parent)
: MSBuildItem(name, parent)
, d(new MSBuildFileItemPrivate)
{
- d->filter.reset(new MSBuildItemMetadata(QStringLiteral("Filter"), QVariant()));
+ d->filter = std::make_unique<MSBuildItemMetadata>(QStringLiteral("Filter"), QVariant());
}
-MSBuildFileItem::~MSBuildFileItem()
-{
-}
+MSBuildFileItem::~MSBuildFileItem() = default;
QString MSBuildFileItem::filePath() const
{
diff --git a/src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.cpp b/src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.cpp
index f7c506651..0b9c2c86a 100644
--- a/src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.cpp
@@ -68,9 +68,7 @@ MSBuildFilter::MSBuildFilter(const QString &name,
setExtensions(extensions);
}
-MSBuildFilter::~MSBuildFilter()
-{
-}
+MSBuildFilter::~MSBuildFilter() = default;
QUuid MSBuildFilter::identifier() const
{
diff --git a/src/plugins/generator/visualstudio/msbuild/msbuildimport.cpp b/src/plugins/generator/visualstudio/msbuild/msbuildimport.cpp
index a0c693aff..000af4496 100644
--- a/src/plugins/generator/visualstudio/msbuild/msbuildimport.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildimport.cpp
@@ -55,9 +55,7 @@ MSBuildImport::MSBuildImport(MSBuildImportGroup *parent)
{
}
-MSBuildImport::~MSBuildImport()
-{
-}
+MSBuildImport::~MSBuildImport() = default;
QString MSBuildImport::project() const
{
diff --git a/src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.cpp b/src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.cpp
index 73e1922db..d84d81783 100644
--- a/src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.cpp
@@ -47,9 +47,7 @@ MSBuildImportGroup::MSBuildImportGroup(MSBuildProject *parent)
{
}
-MSBuildImportGroup::~MSBuildImportGroup()
-{
-}
+MSBuildImportGroup::~MSBuildImportGroup() = default;
QString MSBuildImportGroup::label() const
{
diff --git a/src/plugins/generator/visualstudio/msbuild/msbuilditem.cpp b/src/plugins/generator/visualstudio/msbuild/msbuilditem.cpp
index b11b62295..ed181a453 100644
--- a/src/plugins/generator/visualstudio/msbuild/msbuilditem.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuilditem.cpp
@@ -51,9 +51,7 @@ MSBuildItem::MSBuildItem(const QString &name, IMSBuildItemGroup *parent)
setName(name);
}
-MSBuildItem::~MSBuildItem()
-{
-}
+MSBuildItem::~MSBuildItem() = default;
QString MSBuildItem::name() const
{
diff --git a/src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp b/src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp
index 5228e850e..1479577c5 100644
--- a/src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp
@@ -40,9 +40,7 @@ MSBuildItemDefinitionGroup::MSBuildItemDefinitionGroup(MSBuildProject *parent)
{
}
-MSBuildItemDefinitionGroup::~MSBuildItemDefinitionGroup()
-{
-}
+MSBuildItemDefinitionGroup::~MSBuildItemDefinitionGroup() = default;
void MSBuildItemDefinitionGroup::accept(IMSBuildNodeVisitor *visitor) const
{
diff --git a/src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.cpp b/src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.cpp
index c4e80ecc7..48f919709 100644
--- a/src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.cpp
@@ -49,9 +49,7 @@ MSBuildItemGroup::MSBuildItemGroup(MSBuildProject *parent)
{
}
-MSBuildItemGroup::~MSBuildItemGroup()
-{
-}
+MSBuildItemGroup::~MSBuildItemGroup() = default;
QString MSBuildItemGroup::label() const
{
diff --git a/src/plugins/generator/visualstudio/msbuild/msbuildproject.cpp b/src/plugins/generator/visualstudio/msbuild/msbuildproject.cpp
index c872622b9..11b5b81ea 100644
--- a/src/plugins/generator/visualstudio/msbuild/msbuildproject.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildproject.cpp
@@ -52,9 +52,7 @@ MSBuildProject::MSBuildProject(QObject *parent)
{
}
-MSBuildProject::~MSBuildProject()
-{
-}
+MSBuildProject::~MSBuildProject() = default;
QString MSBuildProject::defaultTargets() const
{
diff --git a/src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.cpp b/src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.cpp
index 4f9c72939..5acb73dad 100644
--- a/src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.cpp
@@ -48,9 +48,7 @@ MSBuildPropertyGroup::MSBuildPropertyGroup(MSBuildProject *parent)
{
}
-MSBuildPropertyGroup::~MSBuildPropertyGroup()
-{
-}
+MSBuildPropertyGroup::~MSBuildPropertyGroup() = default;
QString MSBuildPropertyGroup::label() const
{
diff --git a/src/plugins/generator/visualstudio/msbuildtargetproject.cpp b/src/plugins/generator/visualstudio/msbuildtargetproject.cpp
index 154f8dccc..bcd654061 100644
--- a/src/plugins/generator/visualstudio/msbuildtargetproject.cpp
+++ b/src/plugins/generator/visualstudio/msbuildtargetproject.cpp
@@ -83,9 +83,7 @@ MSBuildTargetProject::MSBuildTargetProject(const GeneratableProject &project,
propertySheetsImportGroup();
}
-MSBuildTargetProject::~MSBuildTargetProject()
-{
-}
+MSBuildTargetProject::~MSBuildTargetProject() = default;
const Internal::VisualStudioVersionInfo &MSBuildTargetProject::versionInfo() const
{
diff --git a/src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.cpp b/src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.cpp
index f3a6a0cbd..4623b5d4d 100644
--- a/src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.cpp
+++ b/src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.cpp
@@ -46,9 +46,7 @@ IVisualStudioSolutionProject::IVisualStudioSolutionProject(QObject *parent)
{
}
-IVisualStudioSolutionProject::~IVisualStudioSolutionProject()
-{
-}
+IVisualStudioSolutionProject::~IVisualStudioSolutionProject() = default;
QUuid IVisualStudioSolutionProject::guid() const
{
diff --git a/src/plugins/generator/visualstudio/solution/visualstudiosolution.cpp b/src/plugins/generator/visualstudio/solution/visualstudiosolution.cpp
index c09ef1f4f..89b266647 100644
--- a/src/plugins/generator/visualstudio/solution/visualstudiosolution.cpp
+++ b/src/plugins/generator/visualstudio/solution/visualstudiosolution.cpp
@@ -57,9 +57,7 @@ VisualStudioSolution::VisualStudioSolution(const Internal::VisualStudioVersionIn
{
}
-VisualStudioSolution::~VisualStudioSolution()
-{
-}
+VisualStudioSolution::~VisualStudioSolution() = default;
Internal::VisualStudioVersionInfo VisualStudioSolution::versionInfo() const
{
diff --git a/src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.cpp b/src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.cpp
index d66f47cf7..ab5db088d 100644
--- a/src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.cpp
+++ b/src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.cpp
@@ -48,9 +48,7 @@ VisualStudioSolutionFileProject::VisualStudioSolutionFileProject(const QString &
setFilePath(filePath);
}
-VisualStudioSolutionFileProject::~VisualStudioSolutionFileProject()
-{
-}
+VisualStudioSolutionFileProject::~VisualStudioSolutionFileProject() = default;
QString VisualStudioSolutionFileProject::name() const
{
diff --git a/src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.cpp b/src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.cpp
index 1e4f5fd01..5cbb0cd61 100644
--- a/src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.cpp
+++ b/src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.cpp
@@ -51,9 +51,7 @@ VisualStudioSolutionGlobalSection::VisualStudioSolutionGlobalSection(const QStri
setName(name);
}
-VisualStudioSolutionGlobalSection::~VisualStudioSolutionGlobalSection()
-{
-}
+VisualStudioSolutionGlobalSection::~VisualStudioSolutionGlobalSection() = default;
QString VisualStudioSolutionGlobalSection::name() const
{
@@ -82,7 +80,7 @@ std::vector<std::pair<QString, QString> > VisualStudioSolutionGlobalSection::pro
void VisualStudioSolutionGlobalSection::appendProperty(const QString &key, const QString &value)
{
- d->properties.push_back({ key, value });
+ d->properties.emplace_back(key, value);
}
} // namespace qbs
diff --git a/src/plugins/generator/visualstudio/visualstudiogenerator.cpp b/src/plugins/generator/visualstudio/visualstudiogenerator.cpp
index ace55b6e6..2ce54e73e 100644
--- a/src/plugins/generator/visualstudio/visualstudiogenerator.cpp
+++ b/src/plugins/generator/visualstudio/visualstudiogenerator.cpp
@@ -158,9 +158,7 @@ VisualStudioGenerator::VisualStudioGenerator(const VisualStudioVersionInfo &vers
Q_ASSERT(d->versionInfo.usesSolutions());
}
-VisualStudioGenerator::~VisualStudioGenerator()
-{
-}
+VisualStudioGenerator::~VisualStudioGenerator() = default;
QString VisualStudioGenerator::generatorName() const
{
diff --git a/src/plugins/plugins.pri b/src/plugins/plugins.pri
index 43d7dcfac..b09619ca6 100644
--- a/src/plugins/plugins.pri
+++ b/src/plugins/plugins.pri
@@ -11,7 +11,7 @@ TEMPLATE = lib
CONFIG += c++14
CONFIG(static, static|shared): CONFIG += create_prl
-unix: CONFIG += plugin
+CONFIG += plugin
!isEmpty(QBS_PLUGINS_INSTALL_DIR): \
installPrefix = $${QBS_PLUGINS_INSTALL_DIR}
diff --git a/src/plugins/scanner/cpp/Lexer.cpp b/src/plugins/scanner/cpp/Lexer.cpp
index 4e06f93b4..5bf5b2367 100644
--- a/src/plugins/scanner/cpp/Lexer.cpp
+++ b/src/plugins/scanner/cpp/Lexer.cpp
@@ -70,8 +70,7 @@ Lexer::Lexer(const char *firstChar, const char *lastChar)
setSource(firstChar, lastChar);
}
-Lexer::~Lexer()
-{ }
+Lexer::~Lexer() = default;
void Lexer::setSource(const char *firstChar, const char *lastChar)
{
@@ -225,7 +224,7 @@ void Lexer::scan_helper(Token *tok)
goto _Lagain;
case '"': case '\'': {
- const char quote = ch;
+ const unsigned char quote = ch;
tok->f.kind = quote == '"'
? T_STRING_LITERAL
@@ -403,7 +402,7 @@ void Lexer::scan_helper(Token *tok)
bool doxy = false;
if (_yychar == '*' || _yychar == '!') {
- const char ch = _yychar;
+ const unsigned char ch = _yychar;
yyinp();
@@ -609,7 +608,7 @@ void Lexer::scan_helper(Token *tok)
ch = _yychar;
yyinp();
- const char quote = ch;
+ const unsigned char quote = ch;
tok->f.kind = quote == '"'
? T_WIDE_STRING_LITERAL
@@ -668,4 +667,4 @@ void Lexer::scan_helper(Token *tok)
} // switch
}
-}
+} // namespace CPlusPlus
diff --git a/src/plugins/scanner/cpp/Token.cpp b/src/plugins/scanner/cpp/Token.cpp
index f8b017fdb..603918f63 100644
--- a/src/plugins/scanner/cpp/Token.cpp
+++ b/src/plugins/scanner/cpp/Token.cpp
@@ -118,9 +118,7 @@ Token::Token() :
{
}
-Token::~Token()
-{
-}
+Token::~Token() = default;
void Token::reset()
{
diff --git a/src/plugins/scanner/cpp/cppscanner.cpp b/src/plugins/scanner/cpp/cppscanner.cpp
index 1cebc52eb..4b7f0eb03 100644
--- a/src/plugins/scanner/cpp/cppscanner.cpp
+++ b/src/plugins/scanner/cpp/cppscanner.cpp
@@ -66,7 +66,7 @@ using namespace CPlusPlus;
struct ScanResult
{
char *fileName;
- unsigned int size;
+ int size;
int flags;
};
@@ -163,7 +163,7 @@ static void scanCppFile(void *opaq, CPlusPlus::Lexer &yylex, bool scanForFileTag
yylex.setScanAngleStringLiteralTokens(false);
if (!tk.newline() && (tk.is(T_STRING_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL))) {
- scanResult.size = tk.length() - 2;
+ scanResult.size = int(tk.length() - 2);
if (tk.is(T_STRING_LITERAL))
scanResult.flags = SC_LOCAL_INCLUDE_FLAG;
else
diff --git a/src/shared/json/json.cpp b/src/shared/json/json.cpp
index 3a838a177..949e2745f 100644
--- a/src/shared/json/json.cpp
+++ b/src/shared/json/json.cpp
@@ -46,8 +46,8 @@
#include <utility>
#include <vector>
-#include <limits.h>
-#include <string.h>
+#include <climits>
+#include <cstring>
#include "json.h"
@@ -4127,7 +4127,7 @@ bool Parser::parseObject()
DEBUG << "numEntries" << parsedObject.offsets.size();
int table = objectOffset;
// finalize the object
- if (parsedObject.offsets.size()) {
+ if (!parsedObject.offsets.empty()) {
int tableSize = static_cast<int>(parsedObject.offsets.size()) * sizeof(uint32_t);
table = reserveSpace(tableSize);
memcpy(data + table, &*parsedObject.offsets.begin(), tableSize);
@@ -4218,7 +4218,7 @@ bool Parser::parseArray()
DEBUG << "size =" << values.size();
int table = arrayOffset;
// finalize the object
- if (values.size()) {
+ if (!values.empty()) {
int tableSize = static_cast<int>(values.size() * sizeof(Value));
table = reserveSpace(tableSize);
memcpy(data + table, values.data(), tableSize);
diff --git a/tests/auto/api/testdata/multiplexing/multiplexing.qbs b/tests/auto/api/testdata/multiplexing/multiplexing.qbs
index 243c73d46..75958ed60 100644
--- a/tests/auto/api/testdata/multiplexing/multiplexing.qbs
+++ b/tests/auto/api/testdata/multiplexing/multiplexing.qbs
@@ -74,6 +74,13 @@ Project {
qbs.architectures: ["TRS-80", "C64"]
qbs.buildVariants: ["debug", "release"]
}
+ Product {
+ name: "multiplex-without-aggregator-4-depends-2"
+ multiplexByQbsProperties: ["architectures", "buildVariants"]
+ qbs.architectures: ["TRS-80", "C64"]
+ qbs.buildVariants: ["debug", "release"]
+ Depends { name: "multiplex-without-aggregator-2" }
+ }
}
Product {
diff --git a/tests/auto/api/testdata/process-result/process-result.qbs b/tests/auto/api/testdata/process-result/process-result.qbs
index 52eb1a3ec..5b71ecaaa 100644
--- a/tests/auto/api/testdata/process-result/process-result.qbs
+++ b/tests/auto/api/testdata/process-result/process-result.qbs
@@ -1,6 +1,7 @@
Project {
CppApplication {
name: "app"
+ consoleApplication: true
files: ["main.cpp"]
}
Product {
diff --git a/tests/auto/api/tst_api.cpp b/tests/auto/api/tst_api.cpp
index 34f5090d7..151690c63 100644
--- a/tests/auto/api/tst_api.cpp
+++ b/tests/auto/api/tst_api.cpp
@@ -144,7 +144,7 @@ static bool waitForFinished(qbs::AbstractJob *job, int timeout = 0)
TestApi::TestApi()
: m_logSink(new LogSink)
- , m_sourceDataDir(QDir::cleanPath(SRCDIR "/testdata"))
+ , m_sourceDataDir(testDataSourceDir(SRCDIR "/testdata"))
, m_workingDataDir(testWorkDir(QStringLiteral("api")))
{
}
@@ -502,6 +502,8 @@ void TestApi::canonicalToolchainList()
QStringList({"xcode", "clang", "llvm", "gcc"}));
QCOMPARE(qbs::canonicalToolchain(QStringList({"clang", "llvm", "gcc"})),
QStringList({"clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"clang-cl", "msvc"})),
+ QStringList({"clang-cl", "msvc"}));
QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm", "gcc"})),
QStringList({"llvm", "gcc"}));
QCOMPARE(qbs::canonicalToolchain(QStringList({"mingw", "gcc"})),
@@ -516,6 +518,8 @@ void TestApi::canonicalToolchainList()
QStringList({"xcode", "clang", "llvm", "gcc"}));
QCOMPARE(qbs::canonicalToolchain(QStringList({"clang"})),
QStringList({"clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"clang-cl"})),
+ QStringList({"clang-cl", "msvc"}));
QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm"})),
QStringList({"llvm", "gcc"}));
QCOMPARE(qbs::canonicalToolchain(QStringList({"mingw"})),
@@ -623,30 +627,24 @@ static qbs::Project::ProductSelection defaultProducts()
return qbs::Project::ProductSelectionDefaultOnly;
}
-static void printProjectData(const qbs::ProjectData &project)
-{
- const auto products = project.products();
- for (const qbs::ProductData &p : products) {
- qDebug(" Product '%s' at %s", qPrintable(p.name()), qPrintable(p.location().toString()));
- const auto groups = p.groups();
- for (const qbs::GroupData &g : groups) {
- qDebug(" Group '%s' at %s", qPrintable(g.name()), qPrintable(g.location().toString()));
- qDebug(" Files: %s", qPrintable(g.allFilePaths().join(QLatin1String(", "))));
- }
- }
-}
-
void TestApi::changeContent()
{
qbs::SetupProjectParameters setupParams = defaultSetupParameters("project-editing");
- std::unique_ptr<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams,
- m_logSink, 0));
- waitForFinished(job.get());
- QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString()));
- qbs::Project project = job->project();
- qbs::ProjectData projectData = project.projectData();
- QCOMPARE(projectData.allProducts().size(), 1);
- qbs::ProductData product = projectData.allProducts().front();
+ std::unique_ptr<qbs::SetupProjectJob> job;
+ qbs::Project project;
+ qbs::ProjectData projectData;
+ qbs::ProductData product;
+
+ const auto resolve = [&] {
+ job.reset(project.setupProject(setupParams, m_logSink, 0));
+ waitForFinished(job.get());
+ QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString()));
+ project = job->project();
+ projectData = project.projectData();
+ QCOMPARE(projectData.allProducts().size(), 1);
+ product = projectData.allProducts().front();
+ };
+ resolve();
QVERIFY(product.groups().size() >= 8);
// Error handling: Invalid product.
@@ -659,12 +657,16 @@ void TestApi::changeContent()
QVERIFY(errorInfo.hasError());
QVERIFY(errorInfo.toString().contains("empty"));
+ WAIT_FOR_NEW_TIMESTAMP();
errorInfo = project.addGroup(product, "New Group 1");
VERIFY_NO_ERROR(errorInfo);
errorInfo = project.addGroup(product, "New Group 2");
VERIFY_NO_ERROR(errorInfo);
+ resolve();
+ QVERIFY(product.groups().size() >= 10);
+
// Error handling: Group already inserted.
errorInfo = project.addGroup(product, "New Group 1");
QVERIFY(errorInfo.hasError());
@@ -677,20 +679,14 @@ void TestApi::changeContent()
QVERIFY2(errorInfo.toString().contains("more than once"), qPrintable(errorInfo.toString()));
// Add files to empty array literal.
- projectData = project.projectData();
- QVERIFY(projectData.products().size() == 1);
- product = projectData.products().front();
- QVERIFY(product.groups().size() >= 10);
+ WAIT_FOR_NEW_TIMESTAMP();
qbs::GroupData group = findGroup(product, "New Group 1");
QVERIFY(group.isValid());
errorInfo = project.addFiles(product, group, QStringList() << "file.h" << "file.cpp");
VERIFY_NO_ERROR(errorInfo);
// Error handling: Add the same file again.
- projectData = project.projectData();
- QVERIFY(projectData.products().size() == 1);
- product = projectData.products().front();
- QVERIFY(product.groups().size() >= 10);
+ resolve();
group = findGroup(product, "New Group 1");
QVERIFY(group.isValid());
errorInfo = project.addFiles(product, group, QStringList() << "file.cpp");
@@ -698,14 +694,12 @@ void TestApi::changeContent()
QVERIFY2(errorInfo.toString().contains("already"), qPrintable(errorInfo.toString()));
// Remove one of the newly added files again.
+ WAIT_FOR_NEW_TIMESTAMP();
errorInfo = project.removeFiles(product, group, QStringList("file.h"));
VERIFY_NO_ERROR(errorInfo);
// Error handling: Try to remove the same file again.
- projectData = project.projectData();
- QVERIFY(projectData.products().size() == 1);
- product = projectData.products().front();
- QVERIFY(product.groups().size() >= 10);
+ resolve();
group = findGroup(product, "New Group 1");
QVERIFY(group.isValid());
errorInfo = project.removeFiles(product, group, QStringList() << "file.h");
@@ -720,38 +714,34 @@ void TestApi::changeContent()
QVERIFY2(errorInfo.toString().contains("complex"), qPrintable(errorInfo.toString()));
// Remove file from product's 'files' binding.
+ WAIT_FOR_NEW_TIMESTAMP();
errorInfo = project.removeFiles(product, qbs::GroupData(), QStringList("main.cpp"));
VERIFY_NO_ERROR(errorInfo);
+ resolve();
// Add file to non-empty array literal.
- projectData = project.projectData();
- QVERIFY(projectData.products().size() == 1);
- product = projectData.products().front();
+ WAIT_FOR_NEW_TIMESTAMP();
group = findGroup(product, "Existing Group 1");
QVERIFY(group.isValid());
errorInfo = project.addFiles(product, group, QStringList() << "newfile1.txt");
VERIFY_NO_ERROR(errorInfo);
+ resolve();
// Add files to list represented as a single string.
- projectData = project.projectData();
- QVERIFY(projectData.products().size() == 1);
- product = projectData.products().front();
+ WAIT_FOR_NEW_TIMESTAMP();
errorInfo = project.addFiles(product, qbs::GroupData(), QStringList() << "newfile2.txt");
VERIFY_NO_ERROR(errorInfo);
+ resolve();
// Add files to list represented as an identifier.
- projectData = project.projectData();
- QVERIFY(projectData.products().size() == 1);
- product = projectData.products().front();
+ WAIT_FOR_NEW_TIMESTAMP();
group = findGroup(product, "Existing Group 2");
QVERIFY(group.isValid());
errorInfo = project.addFiles(product, group, QStringList() << "newfile3.txt");
VERIFY_NO_ERROR(errorInfo);
+ resolve();
// Add files to list represented as a block of code (not yet implemented).
- projectData = project.projectData();
- QVERIFY(projectData.products().size() == 1);
- product = projectData.products().front();
group = findGroup(product, "Existing Group 3");
QVERIFY(group.isValid());
errorInfo = project.addFiles(product, group, QStringList() << "newfile4.txt");
@@ -759,18 +749,14 @@ void TestApi::changeContent()
QVERIFY2(errorInfo.toString().contains("complex"), qPrintable(errorInfo.toString()));
// Add file to group with directory prefix.
- projectData = project.projectData();
- QVERIFY(projectData.products().size() == 1);
- product = projectData.products().front();
+ WAIT_FOR_NEW_TIMESTAMP();
group = findGroup(product, "Existing Group 4");
QVERIFY(group.isValid());
errorInfo = project.addFiles(product, group, QStringList() << "file.txt");
VERIFY_NO_ERROR(errorInfo);
+ resolve();
// Error handling: Add file to group with non-directory prefix.
- projectData = project.projectData();
- QVERIFY(projectData.products().size() == 1);
- product = projectData.products().front();
group = findGroup(product, "Existing Group 5");
QVERIFY(group.isValid());
errorInfo = project.addFiles(product, group, QStringList() << "newfile1.txt");
@@ -778,16 +764,12 @@ void TestApi::changeContent()
QVERIFY2(errorInfo.toString().contains("prefix"), qPrintable(errorInfo.toString()));
// Remove group.
- projectData = project.projectData();
- QVERIFY(projectData.products().size() == 1);
- product = projectData.products().front();
+ WAIT_FOR_NEW_TIMESTAMP();
group = findGroup(product, "Existing Group 5");
QVERIFY(group.isValid());
errorInfo = project.removeGroup(product, group);
VERIFY_NO_ERROR(errorInfo);
- projectData = project.projectData();
- QVERIFY(projectData.products().size() == 1);
- QVERIFY(projectData.products().front().groups().size() >= 9);
+ resolve();
// Error handling: Try to remove the same group again.
errorInfo = project.removeGroup(product, group);
@@ -805,9 +787,7 @@ void TestApi::changeContent()
newFile.close();
errorInfo = project.addFiles(product, group, QStringList() << newFile.fileName());
VERIFY_NO_ERROR(errorInfo);
- projectData = project.projectData();
- QVERIFY(projectData.products().size() == 1);
- product = projectData.products().front();
+ resolve();
group = findGroup(product, "Group with wildcards");
QVERIFY(group.isValid());
QCOMPARE(group.sourceArtifactsFromWildcards().size(), 1);
@@ -838,46 +818,13 @@ void TestApi::changeContent()
QVERIFY(rcvr.descriptions.contains("compiling file.cpp"));
QVERIFY(!rcvr.descriptions.contains("compiling main.cpp"));
- // Now check whether the data updates were done correctly.
- projectData = project.projectData();
- job.reset(project.setupProject(setupParams, m_logSink, 0));
- waitForFinished(job.get());
- QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString()));
- project = job->project();
- qbs::ProjectData newProjectData = project.projectData();
-
- // Can't use Project::operator== here, as the target artifacts will differ due to the build
- // not having run yet.
- bool projectDataMatches = newProjectData.products().size() == 1
- && projectData.products().size() == 1
- && newProjectData.products().front().groups() == projectData.products().front().groups();
- if (!projectDataMatches) {
- qDebug("This is the assumed project:");
- printProjectData(projectData);
- qDebug("This is the actual project:");
- printProjectData(newProjectData);
- }
- QVERIFY(projectDataMatches); // Will fail if e.g. code locations don't match.
-
- // Now try building again and check if the newly resolved product behaves the same way.
- buildJob.reset(project.buildAllProducts(buildOptions, defaultProducts(), this));
- connect(buildJob.get(), &qbs::BuildJob::reportCommandDescription,
- &rcvr, &BuildDescriptionReceiver::handleDescription);
- waitForFinished(buildJob.get());
- QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString()));
- QVERIFY(rcvr.descriptions.contains("compiling file.cpp"));
- QVERIFY(!rcvr.descriptions.contains("compiling main.cpp"));
-
- // Now, after the build, the project data must be entirely identical.
- QVERIFY(projectData == project.projectData());
-
// Error handling: Try to change the project during a build.
buildJob.reset(project.buildAllProducts(buildOptions, defaultProducts(), this));
- errorInfo = project.addGroup(newProjectData.products().front(), "blubb");
+ errorInfo = project.addGroup(projectData.products().front(), "blubb");
QVERIFY(errorInfo.hasError());
QVERIFY2(errorInfo.toString().contains("in progress"), qPrintable(errorInfo.toString()));
waitForFinished(buildJob.get());
- errorInfo = project.addGroup(newProjectData.products().front(), "blubb");
+ errorInfo = project.addGroup(projectData.products().front(), "blubb");
VERIFY_NO_ERROR(errorInfo);
project = qbs::Project();
@@ -888,16 +835,11 @@ void TestApi::changeContent()
setupParams.setProjectFilePath(QDir::cleanPath(m_workingDataDir +
"/project-editing/project-with-no-files.qbs"));
- job.reset(project.setupProject(setupParams, m_logSink, 0));
- waitForFinished(job.get());
- QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString()));
- project = job->project();
- projectData = project.projectData();
- QCOMPARE(projectData.allProducts().size(), 1);
- product = projectData.allProducts().front();
+ resolve();
+ WAIT_FOR_NEW_TIMESTAMP();
errorInfo = project.addFiles(product, qbs::GroupData(), QStringList("main.cpp"));
VERIFY_NO_ERROR(errorInfo);
- projectData = project.projectData();
+ resolve();
rcvr.descriptions.clear();
buildJob.reset(project.buildAllProducts(buildOptions, defaultProducts(), this));
connect(buildJob.get(), &qbs::BuildJob::reportCommandDescription,
@@ -908,18 +850,6 @@ void TestApi::changeContent()
job.reset(project.setupProject(setupParams, m_logSink, 0));
waitForFinished(job.get());
QVERIFY2(!job->error().hasError(), qPrintable(job->error().toString()));
- // Can't use Project::operator== here, as the target artifacts will differ due to the build
- // not having run yet.
- newProjectData = job->project().projectData();
- projectDataMatches = newProjectData.products().size() == 1
- && projectData.products().size() == 1
- && newProjectData.products().front().groups() == projectData.products().front().groups();
- if (!projectDataMatches) {
- printProjectData(projectData);
- qDebug("\n====\n");
- printProjectData(newProjectData);
- }
- QVERIFY(projectDataMatches);
}
#endif // QBS_ENABLE_PROJECT_FILE_UPDATES
@@ -1129,7 +1059,7 @@ void TestApi::excludedInputs()
QCOMPARE(dummyCount, 3);
}
-static qbs::ErrorInfo forceRuleEvaluation(const qbs::Project project)
+static qbs::ErrorInfo forceRuleEvaluation(const qbs::Project &project)
{
qbs::BuildOptions buildOptions;
buildOptions.setDryRun(true);
@@ -1537,7 +1467,7 @@ void TestApi::linkDynamicAndStaticLibs()
// The dependent static libs should not appear in the link command for the executable.
const SettingsPtr s = settings();
const qbs::Profile buildProfile(profileName(), s.get());
- if (buildProfile.value("qbs.toolchain").toStringList().contains("gcc")) {
+ if (profileToolchain(buildProfile).contains("gcc")) {
static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " ");
QString appLinkCmd;
for (const QString &line : qAsConst(bdr.descriptionLines)) {
@@ -1570,7 +1500,7 @@ void TestApi::linkStaticAndDynamicLibs()
// executable. The -rpath-link line for libdynamic1.so must be there.
const SettingsPtr s = settings();
const qbs::Profile buildProfile(profileName(), s.get());
- if (buildProfile.value("qbs.toolchain").toStringList().contains("gcc")) {
+ if (profileToolchain(buildProfile).contains("gcc")) {
static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " ");
QString appLinkCmd;
for (const QString &line : qAsConst(bdr.descriptionLines)) {
@@ -2037,6 +1967,31 @@ void TestApi::multiplexing()
QVERIFY(product.dependencies().empty());
selector.clear();
+ selector.name = "multiplex-without-aggregator-4-depends-2";
+ selector.qbsProperties["architecture"] = "C64";
+ selector.qbsProperties["buildVariant"] = "debug";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().size(), 1);
+ selector.qbsProperties["buildVariant"] = "release";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().size(), 1);
+ selector.qbsProperties["architecture"] = "TRS-80";
+ selector.qbsProperties["buildVariant"] = "debug";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().size(), 1);
+ selector.qbsProperties["buildVariant"] = "release";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().size(), 1);
+
+ selector.clear();
selector.name = "multiplex-with-aggregator-2";
selector.qbsProperties["architecture"] = "C64";
product = takeMatchingProduct(products, selector);
@@ -3054,7 +3009,7 @@ void TestApi::uic()
qbs::ErrorInfo TestApi::doBuildProject(
const QString &projectFilePath, BuildDescriptionReceiver *buildDescriptionReceiver,
ProcessResultReceiver *procResultReceiver, TaskReceiver *taskReceiver,
- const qbs::BuildOptions &options, const QVariantMap overriddenValues)
+ const qbs::BuildOptions &options, const QVariantMap &overriddenValues)
{
qbs::SetupProjectParameters params = defaultSetupParameters(projectFilePath);
params.setOverriddenValues(overriddenValues);
diff --git a/tests/auto/api/tst_api.h b/tests/auto/api/tst_api.h
index aa00ddc99..39eada57a 100644
--- a/tests/auto/api/tst_api.h
+++ b/tests/auto/api/tst_api.h
@@ -161,7 +161,7 @@ private:
ProcessResultReceiver *procResultReceiver = 0,
TaskReceiver *taskReceiver = 0,
const qbs::BuildOptions &options = qbs::BuildOptions(),
- const QVariantMap overriddenValues = QVariantMap());
+ const QVariantMap &overriddenValues = QVariantMap());
LogSink * const m_logSink;
const QString m_sourceDataDir;
diff --git a/tests/auto/blackbox/find/find-android.qbs b/tests/auto/blackbox/find/find-android.qbs
index 26dedc60f..de5c78d10 100644
--- a/tests/auto/blackbox/find/find-android.qbs
+++ b/tests/auto/blackbox/find/find-android.qbs
@@ -3,12 +3,23 @@ import qbs.TextFile
Product {
property string packageName: ""
qbs.targetPlatform: "android"
+ multiplexByQbsProperties: ["architectures"]
+
+ Properties {
+ condition: qbs.architectures && qbs.architectures.length > 1
+ aggregate: true
+ multiplexedType: "json_arch"
+ }
Depends { name: "Android.sdk"; required: false }
Depends { name: "Android.ndk"; required: false }
type: ["json"]
+
Rule {
multiplex: true
+ property stringList inputTags: "json_arch"
+ inputsFromDependencies: inputTags
+ inputs: product.aggregate ? [] : inputTags
Artifact {
filePath: ["android.json"]
fileTags: ["json"]
@@ -18,17 +29,50 @@ Product {
cmd.description = output.filePath;
cmd.sourceCode = function() {
var tools = {};
+
+ for (var i in inputs["json_arch"]) {
+ var tf = new TextFile(inputs["json_arch"][i].filePath, TextFile.ReadOnly);
+ var json = JSON.parse(tf.readAll());
+ tools["ndk"] = json["ndk"];
+ tools["ndk-samples"] = json["ndk-samples"];
+ tf.close();
+ }
+
if (product.moduleProperty("Android.sdk", "present")) {
tools["sdk"] = product.moduleProperty("Android.sdk", "sdkDir");
tools["sdk-build-tools-dx"] = product.Android.sdk.dxFilePath;
}
+ if (product.java && product.java.present)
+ tools["jar"] = product.java.jarFilePath;
+
+ var tf;
+ try {
+ tf = new TextFile(output.filePath, TextFile.WriteOnly);
+ tf.writeLine(JSON.stringify(tools, undefined, 4));
+ } finally {
+ if (tf)
+ tf.close();
+ }
+ };
+ return cmd;
+ }
+ }
+ Rule {
+ multiplex: true
+ Artifact {
+ filePath: ["android_arch.json"]
+ fileTags: ["json_arch"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = output.filePath;
+ cmd.sourceCode = function() {
+ var tools = {};
if (product.moduleProperty("Android.ndk", "present")) {
tools["ndk"] = product.moduleProperty("Android.ndk", "ndkDir");
tools["ndk-samples"] = product.Android.ndk.ndkSamplesDir;
}
- if (product.java && product.java.present)
- tools["jar"] = product.java.jarFilePath;
var tf;
try {
@@ -43,3 +87,4 @@ Product {
}
}
}
+
diff --git a/tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c b/tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c
index 6b625858b..f49b4f90f 100644
--- a/tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c
+++ b/tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c
@@ -4,5 +4,6 @@
jstring
Java_minimalnative_MinimalNative_stringFromNative(JNIEnv* env, jobject thiz)
{
+ (void)thiz;
return (*env)->NewStringUTF(env, "This message comes from native code.");
}
diff --git a/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/AndroidManifest.xml b/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/AndroidManifest.xml
index 289969409..272fe55de 100644
--- a/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/AndroidManifest.xml
+++ b/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product1/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.qt.dummy1" android:versionCode="1" android:versionName="1.0">
- <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="19"/>
+ <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
<uses-feature android:glEsVersion="0x00020000"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:allowBackup="true" android:hasCode="true">
diff --git a/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/AndroidManifest.xml b/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/AndroidManifest.xml
index ef0fbe54f..871aadbe6 100644
--- a/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/AndroidManifest.xml
+++ b/tests/auto/blackbox/testdata-android/multiple-apks-per-project/product2/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.qt.dummy2" android:versionCode="1" android:versionName="1.0">
- <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="19"/>
+ <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
<uses-feature android:glEsVersion="0x00020000"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:allowBackup="true" android:hasCode="true">
diff --git a/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/AndroidManifest.xml b/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/AndroidManifest.xml
index 6694afc18..f184a8f1f 100644
--- a/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/AndroidManifest.xml
+++ b/tests/auto/blackbox/testdata-android/multiple-libs-per-apk/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.qt.dummy" android:versionCode="1" android:versionName="1.0">
- <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="19"/>
+ <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
<uses-feature android:glEsVersion="0x00020000"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:allowBackup="true" android:hasCode="true">
diff --git a/tests/auto/blackbox/testdata-android/qml-app/src/main/AndroidManifest.xml b/tests/auto/blackbox/testdata-android/qml-app/src/main/AndroidManifest.xml
index 066ec0a63..542794825 100644
--- a/tests/auto/blackbox/testdata-android/qml-app/src/main/AndroidManifest.xml
+++ b/tests/auto/blackbox/testdata-android/qml-app/src/main/AndroidManifest.xml
@@ -67,7 +67,7 @@
</application>
- <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="16"/>
+ <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
diff --git a/tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/aggregateDependencyLinking.qbs b/tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/aggregateDependencyLinking.qbs
index e7c8867bd..a65dcd023 100644
--- a/tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/aggregateDependencyLinking.qbs
+++ b/tests/auto/blackbox/testdata-apple/aggregateDependencyLinking/aggregateDependencyLinking.qbs
@@ -14,6 +14,7 @@ Project {
// This will generate 2 multiplex configs and an aggregate.
qbs.architectures: ["x86", "x86_64"]
qbs.buildVariant: "debug"
+ cpp.minimumMacosVersion: "10.8"
}
CppApplication {
@@ -30,6 +31,7 @@ Project {
qbs.architecture: "x86_64"
qbs.buildVariant: "debug"
+ cpp.minimumMacosVersion: "10.8"
multiplexByQbsProperties: []
}
}
diff --git a/tests/auto/blackbox/testdata-apple/overrideInfoPlist/Override-Info.plist b/tests/auto/blackbox/testdata-apple/overrideInfoPlist/Override-Info.plist
new file mode 100644
index 000000000..f2621e983
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/overrideInfoPlist/Override-Info.plist
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>DefaultValue</key>
+ <string>The default value</string>
+ <key>OverriddenValue</key>
+ <string>The default value</string>
+</dict>
+</plist>
diff --git a/tests/auto/blackbox/testdata-apple/overrideInfoPlist/main.c b/tests/auto/blackbox/testdata-apple/overrideInfoPlist/main.c
new file mode 100644
index 000000000..76e819701
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/overrideInfoPlist/main.c
@@ -0,0 +1 @@
+int main() { return 0; }
diff --git a/tests/auto/blackbox/testdata-apple/overrideInfoPlist/overrideInfoPlist.qbs b/tests/auto/blackbox/testdata-apple/overrideInfoPlist/overrideInfoPlist.qbs
new file mode 100644
index 000000000..e70584ed8
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/overrideInfoPlist/overrideInfoPlist.qbs
@@ -0,0 +1,16 @@
+CppApplication {
+ Depends { name: "bundle" }
+ cpp.minimumMacosVersion: "10.7"
+ files: ["main.c", "Override-Info.plist"]
+
+ Properties {
+ condition: qbs.targetOS.contains("darwin")
+ bundle.isBundle: true
+ bundle.identifierPrefix: "com.test"
+
+ bundle.infoPlist: ({
+ "CFBundleName": "My Bundle",
+ "OverriddenValue": "The overridden value",
+ })
+ }
+}
diff --git a/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs b/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs
index fbab6d0b1..fa4c67b96 100644
--- a/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs
+++ b/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs
@@ -43,8 +43,11 @@ Project {
}
for (var i = 0; i < a.length; ++i) {
- if (a[i] !== b[i]) {
- throw msg;
+ var version1 = a[i].split('.');
+ var version2 = b[i].split('.');
+ for (var j = 0; j < version1.length; ++j) {
+ if (version1[j] !== version2[j])
+ throw msg;
}
}
}
diff --git a/tests/auto/blackbox/testdata-qt/metatypes/metatypes.qbs b/tests/auto/blackbox/testdata-qt/metatypes/metatypes.qbs
new file mode 100644
index 000000000..bbc98c934
--- /dev/null
+++ b/tests/auto/blackbox/testdata-qt/metatypes/metatypes.qbs
@@ -0,0 +1,28 @@
+import qbs.Utilities
+
+StaticLibrary {
+ name: "mylib"
+
+ Depends { name: "Qt.core" }
+
+ qbs.installPrefix: "some-prefix"
+
+ Probe {
+ id: capabilitiesChecker
+ property string version: Qt.core.version
+ configure: {
+ if (Utilities.versionCompare(version, "5.15") >= 0)
+ console.info("can generate");
+ else
+ console.info("cannot generate");
+ found = true;
+ }
+ }
+
+ files: [
+ "mocableclass1.cpp",
+ "mocableclass1.h",
+ "mocableclass2.cpp",
+ "unmocableclass.cpp",
+ ]
+}
diff --git a/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.cpp b/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.cpp
new file mode 100644
index 000000000..06adc8ca5
--- /dev/null
+++ b/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.cpp
@@ -0,0 +1,3 @@
+#include "mocableclass1.h"
+
+MocableClass1::MocableClass1(QObject *parent) : QObject(parent) {}
diff --git a/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.h b/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.h
new file mode 100644
index 000000000..020c15179
--- /dev/null
+++ b/tests/auto/blackbox/testdata-qt/metatypes/mocableclass1.h
@@ -0,0 +1,8 @@
+#include <QObject>
+
+class MocableClass1 : public QObject
+{
+ Q_OBJECT
+public:
+ MocableClass1(QObject *parent = nullptr);
+};
diff --git a/tests/auto/blackbox/testdata-qt/metatypes/mocableclass2.cpp b/tests/auto/blackbox/testdata-qt/metatypes/mocableclass2.cpp
new file mode 100644
index 000000000..bf538913a
--- /dev/null
+++ b/tests/auto/blackbox/testdata-qt/metatypes/mocableclass2.cpp
@@ -0,0 +1,10 @@
+#include <QObject>
+
+class MocableClass2 : public QObject
+{
+ Q_OBJECT
+public:
+ MocableClass2(QObject *parent) : QObject(parent) {}
+};
+
+#include <mocableclass2.moc>
diff --git a/tests/auto/blackbox/testdata-qt/metatypes/unmocableclass.cpp b/tests/auto/blackbox/testdata-qt/metatypes/unmocableclass.cpp
new file mode 100644
index 000000000..34330d189
--- /dev/null
+++ b/tests/auto/blackbox/testdata-qt/metatypes/unmocableclass.cpp
@@ -0,0 +1,7 @@
+#include <QObject>
+
+class UnmocableClass : public QObject
+{
+public:
+ UnmocableClass(QObject *parent) : QObject(parent) {}
+};
diff --git a/tests/auto/blackbox/testdata-qt/qmltyperegistrar/example.qml b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/example.qml
new file mode 100644
index 000000000..ef97df12d
--- /dev/null
+++ b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/example.qml
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// ![0]
+import People 1.0
+
+Person {
+ name: "Bob Jones"
+ shoeSize: 12
+}
+// ![0]
diff --git a/tests/auto/blackbox/testdata-qt/qmltyperegistrar/main.cpp b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/main.cpp
new file mode 100644
index 000000000..6c3920f04
--- /dev/null
+++ b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/main.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QCoreApplication>
+#include <QQmlEngine>
+#include <QQmlComponent>
+#include <QDebug>
+#include "person.h"
+
+int main(int argc, char ** argv)
+{
+ QCoreApplication app(argc, argv);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine, QUrl("qrc:example.qml"));
+ auto *person = qobject_cast<Person *>(component.create());
+ if (person) {
+ qWarning() << "The person's name is" << person->name();
+ qWarning() << "They wear a" << person->shoeSize() << "sized shoe";
+ } else {
+ qWarning() << component.errors();
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.cpp b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.cpp
new file mode 100644
index 000000000..de4a33dd0
--- /dev/null
+++ b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "person.h"
+
+// ![0]
+Person::Person(QObject *parent)
+: QObject(parent), m_shoeSize(0)
+{
+}
+
+QString Person::name() const
+{
+ return m_name;
+}
+
+void Person::setName(const QString &n)
+{
+ m_name = n;
+}
+
+int Person::shoeSize() const
+{
+ return m_shoeSize;
+}
+
+void Person::setShoeSize(int s)
+{
+ m_shoeSize = s;
+}
+
+// ![0]
diff --git a/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.h b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.h
new file mode 100644
index 000000000..530c335de
--- /dev/null
+++ b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/person.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef PERSON_H
+#define PERSON_H
+
+#include <QObject>
+#include <QtQml/qqml.h>
+
+//![0]
+class Person : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name WRITE setName)
+ Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize)
+ QML_ELEMENT
+public:
+ Person(QObject *parent = nullptr);
+
+ QString name() const;
+ void setName(const QString &);
+
+ int shoeSize() const;
+ void setShoeSize(int);
+
+private:
+ QString m_name;
+ int m_shoeSize;
+};
+//![0]
+
+#endif // PERSON_H
diff --git a/tests/auto/blackbox/testdata-qt/qmltyperegistrar/qmltyperegistrar.qbs b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/qmltyperegistrar.qbs
new file mode 100644
index 000000000..68dc83743
--- /dev/null
+++ b/tests/auto/blackbox/testdata-qt/qmltyperegistrar/qmltyperegistrar.qbs
@@ -0,0 +1,33 @@
+import qbs.Utilities
+
+CppApplication {
+ name: "myapp"
+ Depends { name: "Qt.qml" }
+
+ Qt.qml.importVersion: "1"
+ cpp.includePaths: sourceDirectory
+ qbs.installPrefix: ""
+
+ files: [
+ "main.cpp",
+ "person.cpp",
+ "person.h",
+ ]
+
+ Group {
+ files: "example.qml"
+ fileTags: "qt.core.resource_data"
+ }
+
+ Probe {
+ id: versionProbe
+ property string version: Qt.core.version
+ configure: {
+ if (Utilities.versionCompare(version, "5.15") >= 0)
+ console.info("has registrar");
+ else
+ console.info("does not have registrar");
+ found = true;
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata-qt/qtscxml/qtscxml.qbs b/tests/auto/blackbox/testdata-qt/qtscxml/qtscxml.qbs
index 38ed5fac9..90b968ec9 100644
--- a/tests/auto/blackbox/testdata-qt/qtscxml/qtscxml.qbs
+++ b/tests/auto/blackbox/testdata-qt/qtscxml/qtscxml.qbs
@@ -39,18 +39,22 @@ Project {
prepare: {
var cmd = new Command(input.filePath);
cmd.description = "running " + input.filePath;
- var pathVar;
- var pathValue;
+
+ var envVars = {};
if (product.qbs.hostOS.contains("windows")) {
- pathVar = "PATH";
- pathValue = FileInfo.toWindowsSeparators(input["Qt.core"].binPath);
+ envVars["PATH"] = FileInfo.toWindowsSeparators(input["Qt.core"].binPath);
+ } else if (product.qbs.hostOS.contains("macos")) {
+ envVars["DYLD_LIBRARY_PATH"] = input["Qt.core"].libPath;
+ envVars["DYLD_FRAMEWORK_PATH"] = input["Qt.core"].libPath;
} else {
- pathVar = "LD_LIBRARY_PATH";
- pathValue = input["Qt.core"].libPath;
+ envVars["LD_LIBRARY_PATH"] = input["Qt.core"].libPath;
+ }
+ for (var varName in envVars) {
+ var oldValue = Environment.getEnv(varName) || "";
+ var newValue = envVars[varName] + product.qbs.pathListSeparator + oldValue;
+ cmd.environment.push(varName + '=' + newValue);
}
- var oldValue = Environment.getEnv(pathVar) || "";
- var newValue = pathValue + product.qbs.pathListSeparator + oldValue;
- cmd.environment = [pathVar + '=' + newValue];
+
return [cmd];
}
}
diff --git a/tests/auto/blackbox/testdata/build-variant-defaults/build-variant-defaults.qbs b/tests/auto/blackbox/testdata/build-variant-defaults/build-variant-defaults.qbs
new file mode 100644
index 000000000..4015817ca
--- /dev/null
+++ b/tests/auto/blackbox/testdata/build-variant-defaults/build-variant-defaults.qbs
@@ -0,0 +1,16 @@
+CppApplication {
+ property bool validate: {
+ var valid = true;
+ if (qbs.buildVariant === "release") {
+ valid = !qbs.enableDebugCode && !qbs.debugInformation && qbs.optimization === "fast";
+ } else if (qbs.buildVariant === "debug") {
+ valid = qbs.enableDebugCode && qbs.debugInformation && qbs.optimization === "none";
+ } else if (qbs.buildVariant === "profiling") {
+ valid = !qbs.enableDebugCode && qbs.debugInformation && qbs.optimization === "fast";
+ }
+
+ if (!valid)
+ throw "Invalid defaults";
+ return valid;
+ }
+}
diff --git a/tests/auto/blackbox/testdata/build-variant-defaults/main.cpp b/tests/auto/blackbox/testdata/build-variant-defaults/main.cpp
new file mode 100644
index 000000000..76e819701
--- /dev/null
+++ b/tests/auto/blackbox/testdata/build-variant-defaults/main.cpp
@@ -0,0 +1 @@
+int main() { return 0; }
diff --git a/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile-probe-project.qbs b/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile-probe-project.qbs
new file mode 100644
index 000000000..ab1c68385
--- /dev/null
+++ b/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile-probe-project.qbs
@@ -0,0 +1,22 @@
+import qbs.Probes
+import qbs.TextFile
+
+Project {
+
+ Probes.ConanfileProbe {
+ id: conan
+ conanfilePath: path + "/conanfile.py"
+ options: ({opt: "True"})
+ settings: ({os: "AIX"})
+ }
+
+ property var check: {
+ tf = new TextFile(buildDirectory + "/results.json", TextFile.WriteOnly);
+ var o = {
+ json: conan.json.deps_env_info["ENV_VAR"],
+ dependencies: conan.dependencies["testlib"].libs,
+ generatedFilesPath: conan.generatedFilesPath
+ };
+ tf.write(JSON.stringify(o));
+ }
+}
diff --git a/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile.py b/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile.py
new file mode 100644
index 000000000..630cf0283
--- /dev/null
+++ b/tests/auto/blackbox/testdata/conanfile-probe/testapp/conanfile.py
@@ -0,0 +1,25 @@
+from conans import ConanFile
+
+class TestApp(ConanFile):
+ name = "testapp"
+ description = "Our project package, to be inspected by the Qbs ConanfileProbe"
+ license = "none"
+ version = "6.6.6"
+
+ settings = "os"
+ options = {"opt": [True, False]}
+ default_options = {"opt": False}
+
+ requires = "testlib/1.2.3@qbs/testing"
+
+ def configure(self):
+ self.options["testlib"].opt = self.options.opt
+
+ def source(self):
+ pass
+
+ def build(self):
+ pass
+
+ def package(self):
+ pass
diff --git a/tests/auto/blackbox/testdata/conanfile-probe/testlib/conanfile.py b/tests/auto/blackbox/testdata/conanfile-probe/testlib/conanfile.py
new file mode 100644
index 000000000..983c22599
--- /dev/null
+++ b/tests/auto/blackbox/testdata/conanfile-probe/testlib/conanfile.py
@@ -0,0 +1,25 @@
+from conans import ConanFile
+
+class Testlib(ConanFile):
+ name = "testlib"
+ description = "Represents an arbitrary package, for instance on bintray"
+ license = "none"
+ version = "1.2.3"
+
+ settings = "os"
+ options = {"opt": [True, False]}
+ default_options = {"opt": False}
+
+ def source(self):
+ pass
+
+ def build(self):
+ pass
+
+ def package(self):
+ pass
+
+ def package_info(self):
+ self.cpp_info.libs = ["testlib1","testlib2"]
+ self.env_info.ENV_VAR = "TESTLIB_ENV_VAL"
+ self.user_info.user_var = "testlib_user_val"
diff --git a/tests/auto/blackbox/testdata/dependency-profile-mismatch/dependency-profile-mismatch.qbs b/tests/auto/blackbox/testdata/dependency-profile-mismatch/dependency-profile-mismatch.qbs
deleted file mode 100644
index 8a6f733c0..000000000
--- a/tests/auto/blackbox/testdata/dependency-profile-mismatch/dependency-profile-mismatch.qbs
+++ /dev/null
@@ -1,12 +0,0 @@
-Project {
- property string mainProfile
- property string depProfile
- Product {
- name: "dep"
- qbs.profiles: [project.depProfile]
- }
- Product {
- name: "main"
- Depends { name: "dep"; profiles: [project.mainProfile]; }
- }
-}
diff --git a/tests/auto/blackbox/testdata/dependency-scanning-loop/dependency-scanning-loop.qbs b/tests/auto/blackbox/testdata/dependency-scanning-loop/dependency-scanning-loop.qbs
new file mode 100644
index 000000000..ac8e7258c
--- /dev/null
+++ b/tests/auto/blackbox/testdata/dependency-scanning-loop/dependency-scanning-loop.qbs
@@ -0,0 +1,34 @@
+import qbs.FileInfo
+import qbs.TextFile
+
+CppApplication {
+ name: "app"
+ cpp.includePaths: buildDirectory
+ Group {
+ files: "main.cpp"
+ fileTags: ["cpp", "custom.in"]
+ }
+ Rule {
+ inputs: "custom.in"
+ Artifact {
+ filePath: FileInfo.completeBaseName(input.filePath) + ".h"
+ fileTags: "hpp"
+ }
+ Artifact {
+ filePath: "custom.txt"
+ fileTags: "whatever"
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating " + outputs.hpp[0].fileName;
+ cmd.sourceCode = function() {
+ var f = new TextFile(outputs.hpp[0].filePath, TextFile.WriteOnly);
+ f.writeLine("int main() {}");
+ f.close();
+ f = new TextFile(outputs.whatever[0].filePath, TextFile.WriteOnly);
+ f.close();
+ }
+ return cmd;
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/dependency-scanning-loop/main.cpp b/tests/auto/blackbox/testdata/dependency-scanning-loop/main.cpp
new file mode 100644
index 000000000..5e8dda41b
--- /dev/null
+++ b/tests/auto/blackbox/testdata/dependency-scanning-loop/main.cpp
@@ -0,0 +1 @@
+#include <main.h>
diff --git a/tests/auto/blackbox/testdata/empty-profile/empty-profile.qbs b/tests/auto/blackbox/testdata/empty-profile/empty-profile.qbs
new file mode 100644
index 000000000..da7536315
--- /dev/null
+++ b/tests/auto/blackbox/testdata/empty-profile/empty-profile.qbs
@@ -0,0 +1,3 @@
+CppApplication {
+ files: ["main.cpp"]
+}
diff --git a/tests/auto/blackbox/testdata/empty-profile/main.cpp b/tests/auto/blackbox/testdata/empty-profile/main.cpp
new file mode 100644
index 000000000..76e819701
--- /dev/null
+++ b/tests/auto/blackbox/testdata/empty-profile/main.cpp
@@ -0,0 +1 @@
+int main() { return 0; }
diff --git a/tests/auto/blackbox/testdata/freedesktop/freedesktop.qbs b/tests/auto/blackbox/testdata/freedesktop/freedesktop.qbs
new file mode 100644
index 000000000..60c3d304f
--- /dev/null
+++ b/tests/auto/blackbox/testdata/freedesktop/freedesktop.qbs
@@ -0,0 +1,25 @@
+import qbs 1.0
+
+Project {
+ CppApplication {
+ name: "main"
+ install: true
+ files: [
+ "main.cpp",
+ "myapp.desktop",
+ "myapp.appdata.xml",
+ ]
+
+ Depends { name: "freedesktop" }
+
+ freedesktop.name: "My App"
+ freedesktop.desktopKeys: ({
+ 'Icon': "myapp.png"
+ })
+
+ Group {
+ files: "myapp.png"
+ fileTags: "freedesktop.appIcon"
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/freedesktop/main.cpp b/tests/auto/blackbox/testdata/freedesktop/main.cpp
new file mode 100644
index 000000000..905869dfa
--- /dev/null
+++ b/tests/auto/blackbox/testdata/freedesktop/main.cpp
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/tests/auto/blackbox/testdata/freedesktop/myapp.appdata.xml b/tests/auto/blackbox/testdata/freedesktop/myapp.appdata.xml
new file mode 100644
index 000000000..3cf0a5641
--- /dev/null
+++ b/tests/auto/blackbox/testdata/freedesktop/myapp.appdata.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<component type="desktop">
+ <id>myapp.desktop</id>
+ <metadata_license>CC0</metadata_license>
+ <name>MyApp</name>
+ <summary>The coolest app ever</summary>
+
+ <description>
+ <p>This is a cool application.</p>
+ </description>
+
+ <url type="homepage">https://software.house/myapp</url>
+ <project_license>GPL-2.0+</project_license>
+ <developer_name>Coding Wizard</developer_name>
+</component>
diff --git a/tests/auto/blackbox/testdata/freedesktop/myapp.desktop b/tests/auto/blackbox/testdata/freedesktop/myapp.desktop
new file mode 100644
index 000000000..dac3014c3
--- /dev/null
+++ b/tests/auto/blackbox/testdata/freedesktop/myapp.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+GenericName=Image Editor
+Comment=Create images and edit photographs
+Icon=overridden.png
diff --git a/tests/auto/blackbox/testdata/freedesktop/myapp.png b/tests/auto/blackbox/testdata/freedesktop/myapp.png
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/freedesktop/myapp.png
diff --git a/tests/auto/blackbox/testdata/generate-linker-map-file/generate-linker-map-file.qbs b/tests/auto/blackbox/testdata/generate-linker-map-file/generate-linker-map-file.qbs
index 815e64853..8c971a747 100644
--- a/tests/auto/blackbox/testdata/generate-linker-map-file/generate-linker-map-file.qbs
+++ b/tests/auto/blackbox/testdata/generate-linker-map-file/generate-linker-map-file.qbs
@@ -2,11 +2,14 @@ Project {
CppApplication {
name: "app-map"
files: ["main.cpp"]
+ // lld-link has different flag for map files, test it by switching to "lld" linkerVariant
+ Properties { condition: qbs.toolchain.contains("clang-cl"); cpp.linkerVariant: "lld" }
cpp.generateLinkerMapFile: true
}
CppApplication {
name: "app-nomap"
files: ["main.cpp"]
+ Properties { condition: qbs.toolchain.contains("clang-cl"); cpp.linkerVariant: "lld" }
cpp.generateLinkerMapFile: false
}
CppApplication {
diff --git a/tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs b/tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs
index 8ee3dd9c9..b7a594c13 100644
--- a/tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs
+++ b/tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs
@@ -7,6 +7,7 @@ CppApplication {
Depends { name: "cpp" }
cpp.cxxLanguageVersion: "c++11"
+ cpp.minimumMacosVersion: "10.8"
cpp.warningLevel: "none"
Depends { name: "protobuf.cpp"; required: false }
diff --git a/tests/auto/blackbox/testdata/host-os-properties/host-os-properties.qbs b/tests/auto/blackbox/testdata/host-os-properties/host-os-properties.qbs
new file mode 100644
index 000000000..b6b862d1c
--- /dev/null
+++ b/tests/auto/blackbox/testdata/host-os-properties/host-os-properties.qbs
@@ -0,0 +1,8 @@
+CppApplication {
+ consoleApplication: true
+ cpp.defines: [
+ 'HOST_ARCHITECTURE="' + qbs.hostArchitecture + '"',
+ 'HOST_PLATFORM="' + qbs.hostPlatform + '"'
+ ]
+ files: "main.cpp"
+}
diff --git a/tests/auto/blackbox/testdata/host-os-properties/main.cpp b/tests/auto/blackbox/testdata/host-os-properties/main.cpp
new file mode 100644
index 000000000..b0c239e20
--- /dev/null
+++ b/tests/auto/blackbox/testdata/host-os-properties/main.cpp
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main() {
+ printf("HOST_ARCHITECTURE = %s\n", HOST_ARCHITECTURE);
+ printf("HOST_PLATFORM = %s\n", HOST_PLATFORM);
+ return 0;
+}
diff --git a/tests/auto/blackbox/testdata/install-locations/install-locations.qbs b/tests/auto/blackbox/testdata/install-locations/install-locations.qbs
index ed0e1810a..722b233c4 100644
--- a/tests/auto/blackbox/testdata/install-locations/install-locations.qbs
+++ b/tests/auto/blackbox/testdata/install-locations/install-locations.qbs
@@ -13,7 +13,9 @@ Project {
CppApplication {
name: "theapp"
install: true
+ installDebugInformation: true
files: "main.cpp"
+ cpp.separateDebugInformation: true
Group {
fileTagsFilter: "application"
fileTags: "some-tag"
@@ -23,7 +25,17 @@ Project {
name: "thelib"
install: true
installImportLib: true
+ installDebugInformation: true
Depends { name: "cpp" }
+ cpp.separateDebugInformation: true
files: "thelib.cpp"
}
+ LoadableModule {
+ name: "theplugin"
+ install: true
+ installDebugInformation: true
+ Depends { name: "cpp" }
+ cpp.separateDebugInformation: true
+ files: "theplugin.cpp"
+ }
}
diff --git a/tests/auto/blackbox/testdata/install-locations/theplugin.cpp b/tests/auto/blackbox/testdata/install-locations/theplugin.cpp
new file mode 100644
index 000000000..ac1ede090
--- /dev/null
+++ b/tests/auto/blackbox/testdata/install-locations/theplugin.cpp
@@ -0,0 +1,3 @@
+#include "../dllexport.h"
+
+DLL_EXPORT void pluginFunc() {}
diff --git a/tests/auto/blackbox/testdata/last-module-candidate-broken/last-module-candidate-broken.qbs b/tests/auto/blackbox/testdata/last-module-candidate-broken/last-module-candidate-broken.qbs
new file mode 100644
index 000000000..db7dc2265
--- /dev/null
+++ b/tests/auto/blackbox/testdata/last-module-candidate-broken/last-module-candidate-broken.qbs
@@ -0,0 +1,5 @@
+CppApplication {
+ qbsSearchPaths: "qbs"
+ Depends { name: "Foo" }
+ files: "main.cpp"
+}
diff --git a/tests/auto/blackbox/testdata/last-module-candidate-broken/main.cpp b/tests/auto/blackbox/testdata/last-module-candidate-broken/main.cpp
new file mode 100644
index 000000000..76e819701
--- /dev/null
+++ b/tests/auto/blackbox/testdata/last-module-candidate-broken/main.cpp
@@ -0,0 +1 @@
+int main() { return 0; }
diff --git a/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo1.qbs b/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo1.qbs
new file mode 100644
index 000000000..ba08b862b
--- /dev/null
+++ b/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo1.qbs
@@ -0,0 +1,3 @@
+Module {
+ condition: false
+}
diff --git a/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo2.qbs b/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo2.qbs
new file mode 100644
index 000000000..0bc383b86
--- /dev/null
+++ b/tests/auto/blackbox/testdata/last-module-candidate-broken/qbs/modules/Foo/Foo2.qbs
@@ -0,0 +1,2 @@
+Group {
+}
diff --git a/tests/auto/blackbox/testdata/list-property-order/modules/lower/lower.qbs b/tests/auto/blackbox/testdata/list-property-order/modules/lower/lower.qbs
index c7462676d..c47a40aea 100644
--- a/tests/auto/blackbox/testdata/list-property-order/modules/lower/lower.qbs
+++ b/tests/auto/blackbox/testdata/list-property-order/modules/lower/lower.qbs
@@ -1,5 +1,5 @@
Module {
- property stringList listProp
+ property stringList listProp: [ "lower" ]
Rule {
inputs: ["intype"]
@@ -10,7 +10,7 @@ Module {
prepare: {
var cmd = new JavaScriptCommand();
cmd.sourceCode = function() {
- console.info("listProp = " + JSON.stringify(product.lower.listProp));
+ console.warn("listProp = " + JSON.stringify(product.lower.listProp));
};
cmd.silent = true;
return [cmd];
diff --git a/tests/auto/blackbox/testdata/list-property-order/product.qbs b/tests/auto/blackbox/testdata/list-property-order/product.qbs
index e92494693..bec122214 100644
--- a/tests/auto/blackbox/testdata/list-property-order/product.qbs
+++ b/tests/auto/blackbox/testdata/list-property-order/product.qbs
@@ -4,6 +4,7 @@ Product {
Depends { name: "higher1" }
Depends { name: "higher2" }
Depends { name: "higher3" }
+ lower.listProp: ["product"]
Group {
files: ["dummy.txt"]
fileTags: ["intype"]
diff --git a/tests/auto/blackbox/testdata/path-probe/BaseApp.qbs b/tests/auto/blackbox/testdata/path-probe/BaseApp.qbs
index 84c00c240..93172579f 100644
--- a/tests/auto/blackbox/testdata/path-probe/BaseApp.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/BaseApp.qbs
@@ -28,6 +28,7 @@
**
****************************************************************************/
+import qbs.FileInfo
import qbs.Probes
CppApplication {
@@ -40,6 +41,7 @@ CppApplication {
property var inputCandidateFilter
property stringList outputFilePaths
+ property var outputCandidatePaths
Probes.PathProbe {
id: probe
@@ -49,6 +51,7 @@ CppApplication {
nameFilter: inputNameFilter
candidateFilter: inputCandidateFilter
searchPaths: inputSearchPaths
+ platformSearchPaths: []
}
property bool validate: {
@@ -56,19 +59,72 @@ CppApplication {
if (lhs.length !== rhs.length)
return false;
for (var i = 0; i < lhs.length; ++i) {
- if (lhs[i] !== rhs[i])
+ if (Array.isArray(lhs[i]) && Array.isArray(rhs[i])) {
+ if (!compareArrays(lhs[i], rhs[i]))
+ return false;
+ } else if (lhs[i] !== rhs[i]) {
return false;
+ }
}
return true;
};
- if (!probe.found)
+ if (outputCandidatePaths) {
+ var actual = probe.allResults.map(function(file) { return file.candidatePaths; });
+ if (!compareArrays(actual, outputCandidatePaths)) {
+ throw "Invalid canndidatePaths: actual = " + JSON.stringify(actual)
+ + ", expected = " + JSON.stringify(outputCandidatePaths);
+ }
+ }
+
+ if (!probe.found) {
+ if (probe.filePath) {
+ throw "Invalid filePath: actual = " + JSON.stringify(probe.filePath)
+ + ", expected = 'undefined'";
+ }
+ if (probe.fileName) {
+ throw "Invalid fileName: actual = " + JSON.stringify(probe.fileName)
+ + ", expected = 'undefined'";
+ }
+ if (probe.path) {
+ throw "Invalid path: actual = " + JSON.stringify(probe.path)
+ + ", expected = 'undefined'";
+ }
+
throw "Probe failed to find files";
+ }
if (outputFilePaths) {
var actual = probe.allResults.map(function(file) { return file.filePath; });
- if (!compareArrays(actual, outputFilePaths))
- throw "Invalid filePaths: actual = " + actual + ", expected = " + outputFilePaths;
+ if (!compareArrays(actual, outputFilePaths)) {
+ throw "Invalid filePaths: actual = " + JSON.stringify(actual)
+ + ", expected = " + JSON.stringify(outputFilePaths);
+ }
+ }
+
+ if (probe.allResults.length !== 1)
+ return;
+
+ // check that single-file interface matches the first value in allResults
+ var expectedFilePath = probe.allResults[0].filePath;
+ if (probe.filePath !== expectedFilePath) {
+ throw "Invalid filePath: actual = " + probe.filePath
+ + ", expected = " + expectedFilePath;
+ }
+ var expectedFileName = probe.allResults[0].fileName;
+ if (probe.fileName !== expectedFileName) {
+ throw "Invalid fileName: actual = " + probe.fileName
+ + ", expected = " + expectedFileName;
+ }
+ var expectedPath = probe.allResults[0].path;
+ if (probe.path !== expectedPath) {
+ throw "Invalid path: actual = " + probe.path
+ + ", expected = " + expectedPath;
+ }
+ var expectedCandidatePaths = probe.allResults[0].candidatePaths;
+ if (!compareArrays(probe.candidatePaths, expectedCandidatePaths)) {
+ throw "Invalid candidatePaths: actual = " + JSON.stringify(probe.candidatePaths)
+ + ", expected = " + JSON.stringify(expectedCandidatePaths);
}
}
diff --git a/tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs b/tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs
index a65256a68..c40f22736 100644
--- a/tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs
@@ -3,10 +3,11 @@ import qbs.FileInfo
BaseApp {
inputNames: ["tool.1", "tool.2"]
inputSearchPaths: "bin"
- outputFilePaths: ["bin/tool.2"]
inputCandidateFilter: {
return function(f) {
return FileInfo.fileName(f) == "tool.2";
}
}
+ outputFilePaths: ["bin/tool.2"]
+ outputCandidatePaths: [["bin/tool.1", "bin/tool.2"]]
}
diff --git a/tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs b/tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs
index b112db44d..33656d4e6 100644
--- a/tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs
@@ -1,8 +1,9 @@
BaseApp {
inputSelectors: [
- {names : "tool", nameSuffixes: [".1", ".2"]},
+ {names : "tool", nameSuffixes: [".0", ".1", ".2"]},
{names : "super-tool", nameSuffixes: [".1"]},
]
inputSearchPaths: "bin"
outputFilePaths: ["bin/tool.1", "bin/super-tool.1"]
+ outputCandidatePaths: [["bin/tool.0", "bin/tool.1"], ["bin/super-tool.1"]]
}
diff --git a/tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs b/tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs
index 60c56e6b4..dd0b58aa2 100644
--- a/tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs
@@ -1,9 +1,10 @@
BaseApp {
inputSelectors: [
"tool",
- ["tool.1", "tool.2"],
+ ["tool.0", "tool.1", "tool.2"],
{names : ["tool.3", "tool.4"]},
]
inputSearchPaths: "bin"
outputFilePaths: ["bin/tool", "bin/tool.1", "bin/tool.3"]
+ outputCandidatePaths: [["bin/tool"], ["bin/tool.0", "bin/tool.1"], ["bin/tool.3"]]
}
diff --git a/tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs b/tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs
index 5e4fc27ca..7ae78de24 100644
--- a/tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs
@@ -5,4 +5,5 @@ BaseApp {
]
inputSearchPaths: "bin"
outputFilePaths: ["bin/tool.2", "bin/super-tool.1"]
+ outputCandidatePaths: [["bin/tool.2"], ["bin/super-tool.1"]]
}
diff --git a/tests/auto/blackbox/testdata/path-probe/mult-files.qbs b/tests/auto/blackbox/testdata/path-probe/mult-files.qbs
index 08727ac01..aa08befc8 100644
--- a/tests/auto/blackbox/testdata/path-probe/mult-files.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/mult-files.qbs
@@ -7,4 +7,5 @@ BaseApp {
]
inputSearchPaths: "bin"
outputFilePaths: ["bin/tool.1", "bin/tool.2", "bin/tool.3", "bin/tool.4"]
+ outputCandidatePaths: [["bin/tool.1"], ["bin/tool.2"], ["bin/tool.3"], ["bin/tool.4"]]
}
diff --git a/tests/auto/blackbox/testdata/path-probe/name-filter.qbs b/tests/auto/blackbox/testdata/path-probe/name-filter.qbs
index 406988fed..b2840443b 100644
--- a/tests/auto/blackbox/testdata/path-probe/name-filter.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/name-filter.qbs
@@ -7,4 +7,5 @@ BaseApp {
};
}
outputFilePaths: ["bin/tool.2"]
+ outputCandidatePaths: [["bin/tool.2"]]
}
diff --git a/tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs b/tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs
index aaa27042c..aabb0fe7b 100644
--- a/tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs
@@ -5,4 +5,5 @@ BaseApp {
"tool.2",
]
inputSearchPaths: "bin"
+ outputCandidatePaths: [["bin/tool.1"], ["bin/nonexistent"], ["bin/tool.2"]]
}
diff --git a/tests/auto/blackbox/testdata/path-probe/non-existent.qbs b/tests/auto/blackbox/testdata/path-probe/non-existent.qbs
index f0c58fa6c..aad01c31b 100644
--- a/tests/auto/blackbox/testdata/path-probe/non-existent.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/non-existent.qbs
@@ -1,4 +1,5 @@
BaseApp {
inputNames: "nonexistent"
inputSearchPaths: "bin"
+ outputCandidatePaths: [["bin/nonexistent"]]
}
diff --git a/tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs b/tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs
index 992a0bea4..98f5b141a 100644
--- a/tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs
@@ -2,4 +2,5 @@ BaseApp {
inputNames: ["tool.1", "tool.2"]
inputSearchPaths: "bin"
outputFilePaths: ["bin/tool.1"]
+ outputCandidatePaths: [["bin/tool.1"]]
}
diff --git a/tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs b/tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs
index 697665242..292df4add 100644
--- a/tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs
@@ -2,4 +2,5 @@ BaseApp {
inputSelectors: ["tool"]
inputSearchPaths: "bin"
outputFilePaths: ["bin/tool"]
+ outputCandidatePaths: [["bin/tool"]]
}
diff --git a/tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs b/tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs
index d57700baf..cf7cfe436 100644
--- a/tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs
@@ -2,4 +2,5 @@ BaseApp {
inputSelectors: "tool"
inputSearchPaths: "bin"
outputFilePaths: ["bin/tool"]
+ outputCandidatePaths: [["bin/tool"]]
}
diff --git a/tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs b/tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs
index 4442e719a..3436a49c3 100644
--- a/tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs
@@ -1,6 +1,7 @@
BaseApp {
inputNames: "tool"
inputSearchPaths: "bin"
- inputNameSuffixes: [".1", ".2"]
+ inputNameSuffixes: [".0", ".1", ".2"]
outputFilePaths: ["bin/tool.1"]
+ outputCandidatePaths: [["bin/tool.0", "bin/tool.1"]]
}
diff --git a/tests/auto/blackbox/testdata/path-probe/single-file.qbs b/tests/auto/blackbox/testdata/path-probe/single-file.qbs
index 3590e7664..e22d7ba0d 100644
--- a/tests/auto/blackbox/testdata/path-probe/single-file.qbs
+++ b/tests/auto/blackbox/testdata/path-probe/single-file.qbs
@@ -2,4 +2,5 @@ BaseApp {
inputNames: "tool"
inputSearchPaths: "bin"
outputFilePaths: ["bin/tool"]
+ outputCandidatePaths: [["bin/tool"]]
}
diff --git a/tests/auto/blackbox/testdata/probeProperties/probeProperties.qbs b/tests/auto/blackbox/testdata/probeProperties/probeProperties.qbs
index 9846eacef..ce89d11f4 100644
--- a/tests/auto/blackbox/testdata/probeProperties/probeProperties.qbs
+++ b/tests/auto/blackbox/testdata/probeProperties/probeProperties.qbs
@@ -1,29 +1,40 @@
import qbs.Probes
-CppApplication {
- Probes.PathProbe {
- id: probe1
- names: ["bin/tool"]
- platformSearchPaths: [product.sourceDirectory]
- }
+Project {
- Probes.PathProbe {
- id: probe2
- names: ["tool"]
- platformSearchPaths: [product.sourceDirectory + "/bin"]
- }
+ CppApplication {
+ Probes.PathProbe {
+ id: probe1
+ names: ["bin/tool"]
+ platformSearchPaths: [product.sourceDirectory]
+ }
- targetName: {
- console.info("probe1.fileName=" + probe1.fileName);
- console.info("probe1.path=" + probe1.path);
- console.info("probe1.filePath=" + probe1.filePath);
+ Probes.PathProbe {
+ id: probe2
+ names: ["tool"]
+ platformSearchPaths: [product.sourceDirectory + "/bin"]
+ }
- console.info("probe2.fileName=" + probe2.fileName);
- console.info("probe2.path=" + probe2.path);
- console.info("probe2.filePath=" + probe2.filePath);
+ targetName: {
+ console.info("probe1.fileName=" + probe1.fileName);
+ console.info("probe1.path=" + probe1.path);
+ console.info("probe1.filePath=" + probe1.filePath);
- return name;
+ console.info("probe2.fileName=" + probe2.fileName);
+ console.info("probe2.path=" + probe2.path);
+ console.info("probe2.filePath=" + probe2.filePath);
+
+ console.info("probe3.fileName=" + probe3.fileName);
+ console.info("probe3.path=" + probe3.path);
+ console.info("probe3.filePath=" + probe3.filePath);
+ return name;
+ }
+ }
+
+ Probes.PathProbe {
+ id: probe3
+ names: ["tool"]
+ platformSearchPaths: [project.sourceDirectory + "/bin"]
}
- files: ["main.c"]
}
diff --git a/tests/auto/blackbox/testdata/property-evaluation-context/modules/base/base.qbs b/tests/auto/blackbox/testdata/property-evaluation-context/modules/base/base.qbs
new file mode 100644
index 000000000..a97538751
--- /dev/null
+++ b/tests/auto/blackbox/testdata/property-evaluation-context/modules/base/base.qbs
@@ -0,0 +1,4 @@
+Module {
+ property string productInBase: product.name
+ property string productInTop: ""
+}
diff --git a/tests/auto/blackbox/testdata/property-evaluation-context/modules/top/top.qbs b/tests/auto/blackbox/testdata/property-evaluation-context/modules/top/top.qbs
new file mode 100644
index 000000000..fa073ff78
--- /dev/null
+++ b/tests/auto/blackbox/testdata/property-evaluation-context/modules/top/top.qbs
@@ -0,0 +1,6 @@
+Module {
+ Depends { name: "base" }
+ base.productInTop: product.name
+ property string productInTop: product.name
+ property string productInExport: ""
+}
diff --git a/tests/auto/blackbox/testdata/property-evaluation-context/property-evaluation-context.qbs b/tests/auto/blackbox/testdata/property-evaluation-context/property-evaluation-context.qbs
new file mode 100644
index 000000000..28216c150
--- /dev/null
+++ b/tests/auto/blackbox/testdata/property-evaluation-context/property-evaluation-context.qbs
@@ -0,0 +1,34 @@
+Project {
+ qbsSearchPaths: [ path ]
+ Product {
+ name: "mylib"
+ Export {
+ Depends { name: "top" }
+ top.productInExport: product.name
+ }
+ }
+
+ Product {
+ type: "rule-output"
+ name: "myapp"
+ Depends { name: "mylib" }
+
+ Rule {
+ alwaysRun: true
+ multiplex: true
+ requiresInputs: false
+ outputFileTags: "rule-output"
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.silent = true;
+ cmd.sourceCode = function() {
+ console.info("base.productInBase evaluated in: " + product.base.productInBase);
+ console.info("base.productInTop evaluated in: " + product.base.productInTop);
+ console.info("top.productInExport evaluated in: " + product.top.productInExport);
+ console.info("top.productInTop evaluated in: " + product.top.productInTop);
+ }
+ return [cmd];
+ }
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/protobuf/addressbook_cpp.qbs b/tests/auto/blackbox/testdata/protobuf/addressbook_cpp.qbs
index f09706b47..5e6ffc508 100644
--- a/tests/auto/blackbox/testdata/protobuf/addressbook_cpp.qbs
+++ b/tests/auto/blackbox/testdata/protobuf/addressbook_cpp.qbs
@@ -12,6 +12,7 @@ CppApplication {
Depends { name: "cpp" }
cpp.cxxLanguageVersion: "c++11"
+ cpp.minimumMacosVersion: "10.8"
Depends { name: "protobuf.cpp"; required: false }
property bool hasProtobuf: {
diff --git a/tests/auto/blackbox/testdata/protobuf/import.qbs b/tests/auto/blackbox/testdata/protobuf/import.qbs
index 59a094dce..ef4e80c1b 100644
--- a/tests/auto/blackbox/testdata/protobuf/import.qbs
+++ b/tests/auto/blackbox/testdata/protobuf/import.qbs
@@ -13,6 +13,7 @@ CppApplication {
protobuf.cpp.importPaths: [sourceDirectory]
cpp.cxxLanguageVersion: "c++11"
+ cpp.minimumMacosVersion: "10.8"
Depends { name: "protobuf.cpp"; required: false }
property bool hasProtobuf: {
diff --git a/tests/auto/blackbox/testdata/protobuf/needs-import-dir.qbs b/tests/auto/blackbox/testdata/protobuf/needs-import-dir.qbs
index 475c1c6c7..493632a0e 100644
--- a/tests/auto/blackbox/testdata/protobuf/needs-import-dir.qbs
+++ b/tests/auto/blackbox/testdata/protobuf/needs-import-dir.qbs
@@ -14,6 +14,7 @@ CppApplication {
protobuf.cpp.importPaths: (theImportDir ? [theImportDir] : []).concat([sourceDirectory])
cpp.cxxLanguageVersion: "c++11"
+ cpp.minimumMacosVersion: "10.8"
Depends { name: "protobuf.cpp"; required: false }
property bool hasProtobuf: {
diff --git a/tests/auto/blackbox/testdata/response-files/response-files.qbs b/tests/auto/blackbox/testdata/response-files/response-files.qbs
index efed1dc9f..168cdf66a 100644
--- a/tests/auto/blackbox/testdata/response-files/response-files.qbs
+++ b/tests/auto/blackbox/testdata/response-files/response-files.qbs
@@ -44,6 +44,9 @@ Project {
Product {
name: "lotsofobjects"
type: ["dynamiclibrary"]
+ // clang-cl does not use response file internally, thus linker complains that command is
+ // too long. This can be worked around by calling the linker directly
+ cpp.linkerMode: qbs.toolchain.contains("clang-cl") ? "manual" : original
Depends { name: "cpp" }
Rule {
multiplex: true
diff --git a/tests/auto/blackbox/testdata/sanitizer/sanitizer.cpp b/tests/auto/blackbox/testdata/sanitizer/sanitizer.cpp
new file mode 100644
index 000000000..4a7c3ee32
--- /dev/null
+++ b/tests/auto/blackbox/testdata/sanitizer/sanitizer.cpp
@@ -0,0 +1,4 @@
+int main(int argc, char *argv[])
+{
+ return 0;
+}
diff --git a/tests/auto/blackbox/testdata/sanitizer/sanitizer.qbs b/tests/auto/blackbox/testdata/sanitizer/sanitizer.qbs
new file mode 100644
index 000000000..7b5054316
--- /dev/null
+++ b/tests/auto/blackbox/testdata/sanitizer/sanitizer.qbs
@@ -0,0 +1,30 @@
+CppApplication {
+ property string sanitizer
+
+ property bool supportsSanitizer: {
+ if (qbs.toolchain.contains("clang-cl"))
+ // only these are supported
+ return sanitizer === "address" || sanitizer === "undefined";
+ if (!qbs.toolchain.contains("gcc"))
+ return false;
+ if (qbs.toolchain.contains("mingw"))
+ return false;
+ return true;
+ }
+
+ condition: {
+ if (!sanitizer)
+ return true;
+ if (!supportsSanitizer)
+ console.info("Compiler does not support sanitizer");
+ return supportsSanitizer;
+ }
+ qbs.buildVariant: "release"
+ cpp.cxxLanguageVersion: "c++11"
+ cpp.minimumMacosVersion: "10.8"
+ consoleApplication: true
+ cpp.runtimeLibrary: "static"
+ cpp.driverFlags: sanitizer ? ["-fsanitize=" + sanitizer] : []
+ cpp.debugInformation: true
+ files: "sanitizer.cpp"
+}
diff --git a/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.h b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.h
new file mode 100644
index 000000000..a82b12fbd
--- /dev/null
+++ b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.h
@@ -0,0 +1 @@
+#include "lib.h"
diff --git a/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.qbs b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.qbs
new file mode 100644
index 000000000..e931b853c
--- /dev/null
+++ b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/app.qbs
@@ -0,0 +1,4 @@
+CppApplication {
+ cpp.includePaths: project.sourceDirectory + "/lib"
+ files: "main.cpp"
+}
diff --git a/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/main.cpp b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/main.cpp
new file mode 100644
index 000000000..2e7bedac8
--- /dev/null
+++ b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/app/main.cpp
@@ -0,0 +1,3 @@
+#include "app.h"
+
+int main() { }
diff --git a/tests/auto/blackbox/testdata/scan-result-in-non-dependency/lib/lib.h b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/lib/lib.h
new file mode 100644
index 000000000..af6f627b7
--- /dev/null
+++ b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/lib/lib.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void lib1_foo(); \ No newline at end of file
diff --git a/tests/auto/blackbox/testdata/scan-result-in-non-dependency/other/other.qbs b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/other/other.qbs
new file mode 100644
index 000000000..29682da1c
--- /dev/null
+++ b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/other/other.qbs
@@ -0,0 +1,24 @@
+import qbs.TextFile
+
+Product {
+ type: "testproduct"
+ files: "../lib/lib.h"
+
+ Rule {
+ multiplex: true
+ Artifact {
+ fileTags: ["testproduct"]
+ filePath: "fubar"
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating text file";
+ cmd.sourceCode = function() {
+ var tf = new TextFile(output.filePath, TextFile.WriteOnly);
+ tf.writeLine("blubb");
+ tf.close();
+ }
+ return cmd;
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/scan-result-in-non-dependency/p.qbs b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/p.qbs
new file mode 100644
index 000000000..bcbd5ebce
--- /dev/null
+++ b/tests/auto/blackbox/testdata/scan-result-in-non-dependency/p.qbs
@@ -0,0 +1,6 @@
+Project {
+ references: [
+ "app/app.qbs",
+ "other/other.qbs",
+ ]
+}
diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.h b/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.h
new file mode 100644
index 000000000..a82b12fbd
--- /dev/null
+++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.h
@@ -0,0 +1 @@
+#include "lib.h"
diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.qbs b/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.qbs
new file mode 100644
index 000000000..984e9aca9
--- /dev/null
+++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/app/app.qbs
@@ -0,0 +1,4 @@
+CppApplication {
+ Depends { name: "lib" }
+ files: "main.cpp"
+}
diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/app/main.cpp b/tests/auto/blackbox/testdata/scan-result-in-other-product/app/main.cpp
new file mode 100644
index 000000000..2e7bedac8
--- /dev/null
+++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/app/main.cpp
@@ -0,0 +1,3 @@
+#include "app.h"
+
+int main() { }
diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.h b/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.h
new file mode 100644
index 000000000..af6f627b7
--- /dev/null
+++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void lib1_foo(); \ No newline at end of file
diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.qbs b/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.qbs
new file mode 100644
index 000000000..fe2916714
--- /dev/null
+++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/lib/lib.qbs
@@ -0,0 +1,7 @@
+Product {
+ files: "lib.h"
+ Export {
+ Depends { name: "cpp" }
+ cpp.includePaths: product.sourceDirectory
+ }
+}
diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/other/other.qbs b/tests/auto/blackbox/testdata/scan-result-in-other-product/other/other.qbs
new file mode 100644
index 000000000..29682da1c
--- /dev/null
+++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/other/other.qbs
@@ -0,0 +1,24 @@
+import qbs.TextFile
+
+Product {
+ type: "testproduct"
+ files: "../lib/lib.h"
+
+ Rule {
+ multiplex: true
+ Artifact {
+ fileTags: ["testproduct"]
+ filePath: "fubar"
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating text file";
+ cmd.sourceCode = function() {
+ var tf = new TextFile(output.filePath, TextFile.WriteOnly);
+ tf.writeLine("blubb");
+ tf.close();
+ }
+ return cmd;
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/scan-result-in-other-product/p.qbs b/tests/auto/blackbox/testdata/scan-result-in-other-product/p.qbs
new file mode 100644
index 000000000..fedf84989
--- /dev/null
+++ b/tests/auto/blackbox/testdata/scan-result-in-other-product/p.qbs
@@ -0,0 +1,7 @@
+Project {
+ references: [
+ "app/app.qbs",
+ "lib/lib.qbs",
+ "other/other.qbs",
+ ]
+}
diff --git a/tests/auto/blackbox/testdata/undefined-target-platform/undefined-target-platform.qbs b/tests/auto/blackbox/testdata/undefined-target-platform/undefined-target-platform.qbs
new file mode 100644
index 000000000..2b3724c26
--- /dev/null
+++ b/tests/auto/blackbox/testdata/undefined-target-platform/undefined-target-platform.qbs
@@ -0,0 +1,13 @@
+import qbs.File
+import qbs.FileInfo
+
+Product {
+ name: "undefined-target-platform"
+ qbs.targetPlatform: undefined
+
+ readonly property bool _validate: {
+ if (Array.isArray(qbs.targetOS) && qbs.targetOS.length === 0)
+ return true;
+ throw "Invalid qbs.targetOS value: " + qbs.targetOS;
+ }
+}
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
index 861790acd..25e36816c 100644
--- a/tests/auto/blackbox/tst_blackbox.cpp
+++ b/tests/auto/blackbox/tst_blackbox.cpp
@@ -713,6 +713,25 @@ void TestBlackbox::buildGraphVersions()
QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
}
+void TestBlackbox::buildVariantDefaults_data()
+{
+ QTest::addColumn<QString>("buildVariant");
+ QTest::newRow("default") << QString();
+ QTest::newRow("debug") << QStringLiteral("debug");
+ QTest::newRow("release") << QStringLiteral("release");
+ QTest::newRow("profiling") << QStringLiteral("profiling");
+}
+
+void TestBlackbox::buildVariantDefaults()
+{
+ QFETCH(QString, buildVariant);
+ QDir::setCurrent(testDataDir + "/build-variant-defaults");
+ QbsRunParameters params{QStringLiteral("resolve")};
+ if (!buildVariant.isEmpty())
+ params.arguments << ("modules.qbs.buildVariant:" + buildVariant);
+ QCOMPARE(runQbs(params), 0);
+}
+
void TestBlackbox::changedFiles_data()
{
QTest::addColumn<bool>("useChangedFilesForInitialBuild");
@@ -942,20 +961,11 @@ void TestBlackbox::dependenciesProperty()
QCOMPARE(product2_cpp_defines.first().toString(), QLatin1String("DIGEDAG"));
}
-void TestBlackbox::dependencyProfileMismatch()
+void TestBlackbox::dependencyScanningLoop()
{
- QDir::setCurrent(testDataDir + "/dependency-profile-mismatch");
- const SettingsPtr s = settings();
- qbs::Internal::TemporaryProfile depProfile("qbs_autotests_profileMismatch", s.get());
- depProfile.p.setValue("qbs.architecture", "x86"); // Profiles must not be empty...
- s->sync();
- QbsRunParameters params(QStringList() << ("project.mainProfile:" + profileName())
- << ("project.depProfile:" + depProfile.p.name()));
- params.expectFailure = true;
- QVERIFY2(runQbs(params) != 0, m_qbsStderr.constData());
- QVERIFY2(m_qbsStderr.contains(profileName().toLocal8Bit())
- && m_qbsStderr.contains("', which does not exist"),
- m_qbsStderr.constData());
+ QDir::setCurrent(testDataDir + "/dependency-scanning-loop");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
}
void TestBlackbox::deprecatedProperty()
@@ -1442,7 +1452,7 @@ void TestBlackbox::versionScript()
{
const SettingsPtr s = settings();
Profile buildProfile(profileName(), s.get());
- QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList();
+ QStringList toolchain = profileToolchain(buildProfile);
if (!toolchain.contains("gcc") || targetOs() != HostOsInfo::HostOsLinux)
QSKIP("version script test only applies to Linux");
QDir::setCurrent(testDataDir + "/versionscript");
@@ -1765,6 +1775,40 @@ void TestBlackbox::cxxLanguageVersion_data()
std::make_pair(QString("msvc-new"), QString("/std:"))});
}
+void TestBlackbox::conanfileProbe()
+{
+ QString executable = findExecutable({"conan"});
+ if (executable.isEmpty())
+ QSKIP("conan is not installed or not available in PATH.");
+
+ // We first build a dummy package testlib and use that as dependency
+ // in the testapp package.
+ QDir::setCurrent(testDataDir + "/conanfile-probe/testlib");
+ QStringList arguments { "create", "-o", "opt=True", "-s", "os=AIX", ".",
+ "testlib/1.2.3@qbs/testing" };
+ QProcess conan;
+ conan.start(executable, arguments);
+ QVERIFY(waitForProcessSuccess(conan));
+
+ QDir::setCurrent(testDataDir + "/conanfile-probe/testapp");
+ QCOMPARE(runQbs(QbsRunParameters("resolve", {"--force-probe-execution"})), 0);
+
+ QFile file(relativeBuildDir() + "/results.json");
+ QVERIFY(file.open(QIODevice::ReadOnly));
+ QVariantMap actualResults = QJsonDocument::fromJson(file.readAll()).toVariant().toMap();
+ const auto generatedFilesPath = actualResults.take("generatedFilesPath").toString();
+ // We want to make sure that generatedFilesPath is under the project directory,
+ // but we don't care about the actual name.
+ QVERIFY(directoryExists(relativeBuildDir() + "/genconan/"
+ + QFileInfo(generatedFilesPath).baseName()));
+
+ const QVariantMap expectedResults = {
+ { "json", "TESTLIB_ENV_VAL" },
+ { "dependencies", QVariantList{"testlib1", "testlib2"} },
+ };
+ QCOMPARE(actualResults, expectedResults);
+}
+
void TestBlackbox::cpuFeatures()
{
QDir::setCurrent(testDataDir + "/cpu-features");
@@ -1832,7 +1876,7 @@ void TestBlackbox::separateDebugInfo()
const SettingsPtr s = settings();
Profile buildProfile(profileName(), s.get());
- QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList();
+ QStringList toolchain = profileToolchain(buildProfile);
if (isDarwin) {
QVERIFY(directoryExists(relativeProductBuildDir("app1") + "/app1.app.dSYM"));
QVERIFY(regularFileExists(relativeProductBuildDir("app1")
@@ -2035,7 +2079,7 @@ void TestBlackbox::trackExternalProductChanges()
rmDirR(relativeBuildDir());
const SettingsPtr s = settings();
const Profile profile(profileName(), s.get());
- const QStringList toolchainTypes = profile.value("qbs.toolchain").toStringList();
+ const QStringList toolchainTypes = profileToolchain(profile);
if (!toolchainTypes.contains("gcc"))
QSKIP("Need GCC-like compiler to run this test");
params.environment = QProcessEnvironment::systemEnvironment();
@@ -2332,9 +2376,11 @@ void TestBlackbox::reproducibleBuild()
{
const SettingsPtr s = settings();
const Profile profile(profileName(), s.get());
- const QStringList toolchains = profile.value("qbs.toolchain").toStringList();
- if (!toolchains.contains("gcc") || toolchains.contains("clang"))
+ const QStringList toolchains = profileToolchain(profile);
+ if (!toolchains.contains("gcc"))
QSKIP("reproducible builds only supported for gcc");
+ if (toolchains.contains("clang"))
+ QSKIP("reproducible builds are not supported for clang");
QFETCH(bool, reproducible);
@@ -2495,6 +2541,36 @@ void TestBlackbox::ruleWithNonRequiredInputs()
QVERIFY2(m_qbsStdout.contains("Generating"), m_qbsStdout.constData());
}
+void TestBlackbox::sanitizer_data()
+{
+ QTest::addColumn<QString>("sanitizer");
+ QTest::newRow("none") << QString();
+ QTest::newRow("address") << QStringLiteral("address");
+ QTest::newRow("undefined") << QStringLiteral("undefined");
+ QTest::newRow("thread") << QStringLiteral("thread");
+}
+
+void TestBlackbox::sanitizer()
+{
+ QFETCH(QString, sanitizer);
+ QDir::setCurrent(testDataDir + "/sanitizer");
+ rmDirR(relativeBuildDir());
+ QbsRunParameters params("build", {"--command-echo-mode", "command-line"});
+ if (!sanitizer.isEmpty()) {
+ params.arguments.append(
+ {QStringLiteral("products.sanitizer.sanitizer:\"") + sanitizer + "\""});
+ }
+ QCOMPARE(runQbs(params), 0);
+ if (m_qbsStdout.contains(QByteArrayLiteral("Compiler does not support sanitizer")))
+ QSKIP("Compiler does not support the specified sanitizer");
+ if (!sanitizer.isEmpty()) {
+ QVERIFY2(m_qbsStdout.contains(QByteArrayLiteral("-fsanitize=") + sanitizer.toLatin1()),
+ qPrintable(m_qbsStdout));
+ } else {
+ QVERIFY2(!m_qbsStdout.contains(QByteArrayLiteral("-fsanitize=")), qPrintable(m_qbsStdout));
+ }
+}
+
void TestBlackbox::scannerItem()
{
QDir::setCurrent(testDataDir + "/scanner-item");
@@ -2513,6 +2589,47 @@ void TestBlackbox::scannerItem()
QVERIFY2(m_qbsStdout.contains("handling file2.in"), m_qbsStdout.constData());
}
+void TestBlackbox::scanResultInOtherProduct()
+{
+ QDir::setCurrent(testDataDir + "/scan-result-in-other-product");
+ QCOMPARE(runQbs(QStringList("-vv")), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("generating text file"), m_qbsStdout.constData());
+ QVERIFY2(!m_qbsStderr.contains("The file dependency might get lost during change tracking"),
+ m_qbsStderr.constData());
+ WAIT_FOR_NEW_TIMESTAMP();
+ REPLACE_IN_FILE("other/other.qbs", "blubb", "blubb2");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("generating text file"), m_qbsStdout.constData());
+ WAIT_FOR_NEW_TIMESTAMP();
+ touch("lib/lib.h");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
+ QVERIFY2(!m_qbsStdout.contains("generating text file"), m_qbsStdout.constData());
+}
+
+void TestBlackbox::scanResultInNonDependency()
+{
+ QDir::setCurrent(testDataDir + "/scan-result-in-non-dependency");
+ QCOMPARE(runQbs(QStringList("-vv")), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("generating text file"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStderr.contains("The file dependency might get lost during change tracking"),
+ m_qbsStderr.constData());
+ WAIT_FOR_NEW_TIMESTAMP();
+ REPLACE_IN_FILE("other/other.qbs", "blubb", "blubb2");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("generating text file"), m_qbsStdout.constData());
+ WAIT_FOR_NEW_TIMESTAMP();
+ touch("lib/lib.h");
+ QCOMPARE(runQbs(), 0);
+ QEXPECT_FAIL("", "QBS-1532", Continue);
+ QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
+ QVERIFY2(!m_qbsStdout.contains("generating text file"), m_qbsStdout.constData());
+}
+
void TestBlackbox::setupBuildEnvironment()
{
QDir::setCurrent(testDataDir + "/setup-build-environment");
@@ -2821,6 +2938,8 @@ void TestBlackbox::pathProbe()
QbsRunParameters buildParams("build", QStringList{"-f", projectFile});
buildParams.expectFailure = !successExpected;
QCOMPARE(runQbs(buildParams) == 0, successExpected);
+ if (!successExpected)
+ QVERIFY2(m_qbsStderr.contains("Probe failed to find files"), m_qbsStderr);
}
void TestBlackbox::pchChangeTracking()
@@ -3077,6 +3196,9 @@ void TestBlackbox::probeProperties()
QVERIFY2(m_qbsStdout.contains("probe2.fileName=tool"), m_qbsStdout.constData());
QVERIFY2(m_qbsStdout.contains("probe2.path=" + dir + "/bin"), m_qbsStdout.constData());
QVERIFY2(m_qbsStdout.contains("probe2.filePath=" + dir + "/bin/tool"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("probe3.fileName=tool"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("probe3.path=" + dir + "/bin"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("probe3.filePath=" + dir + "/bin/tool"), m_qbsStdout.constData());
}
void TestBlackbox::probesAndShadowProducts()
@@ -3099,7 +3221,7 @@ void TestBlackbox::probeInExportedModule()
<< QStringLiteral("probe-in-exported-module.qbs"))), 0);
QVERIFY2(m_qbsStdout.contains("found: true"), m_qbsStdout.constData());
QVERIFY2(m_qbsStdout.contains("prop: yes"), m_qbsStdout.constData());
- QVERIFY2(m_qbsStdout.contains("listProp: my,myother"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("listProp: myother,my"), m_qbsStdout.constData());
}
void TestBlackbox::probesAndArrayProperties()
@@ -3368,6 +3490,17 @@ void TestBlackbox::propertyChanges()
QVERIFY(m_qbsStdout.contains("Making output from other output"));
}
+void TestBlackbox::propertyEvaluationContext()
+{
+ const QString testDir = testDataDir + "/property-evaluation-context";
+ QDir::setCurrent(testDir);
+ QCOMPARE(runQbs(), 0);
+ QCOMPARE(m_qbsStdout.count("base.productInBase evaluated in: myapp"), 1);
+ QCOMPARE(m_qbsStdout.count("base.productInTop evaluated in: myapp"), 1);
+ QCOMPARE(m_qbsStdout.count("top.productInExport evaluated in: mylib"), 1);
+ QCOMPARE(m_qbsStdout.count("top.productInTop evaluated in: myapp"), 1);
+}
+
void TestBlackbox::qtBug51237()
{
const QString profileName = "profile-qtBug51237";
@@ -3452,6 +3585,42 @@ void TestBlackbox::dynamicRuleOutputs()
QVERIFY(!QFile::exists(sourceFile2));
}
+void TestBlackbox::emptyProfile()
+{
+ QDir::setCurrent(testDataDir + "/empty-profile");
+
+ const SettingsPtr s = settings();
+ const Profile buildProfile(profileName(), s.get());
+ bool isMsvc = false;
+ auto toolchainType = buildProfile.value(QStringLiteral("qbs.toolchainType")).toString();
+ QbsRunParameters params;
+ params.profile = "none";
+
+ if (toolchainType.isEmpty()) {
+ const auto toolchain = buildProfile.value(QStringLiteral("qbs.toolchain")).toStringList();
+ if (!toolchain.isEmpty())
+ toolchainType = toolchain.first();
+ }
+ if (!toolchainType.isEmpty()) {
+ params.arguments = QStringList{QStringLiteral("qbs.toolchainType:") + toolchainType};
+ isMsvc = toolchainType == "msvc" || toolchainType == "clang-cl";
+ }
+
+ if (!isMsvc) {
+ const auto tcPath =
+ QDir::toNativeSeparators(
+ buildProfile.value(QStringLiteral("cpp.toolchainInstallPath")).toString());
+ auto paths = params.environment.value(QStringLiteral("PATH"))
+ .split(HostOsInfo::pathListSeparator(), QString::SkipEmptyParts);
+ if (!tcPath.isEmpty() && !paths.contains(tcPath)) {
+ paths.prepend(tcPath);
+ params.environment.insert(
+ QStringLiteral("PATH"), paths.join(HostOsInfo::pathListSeparator()));
+ }
+ }
+ QCOMPARE(runQbs(params), 0);
+}
+
void TestBlackbox::erroneousFiles_data()
{
QTest::addColumn<QString>("errorMessage");
@@ -3544,9 +3713,11 @@ void TestBlackbox::escapedLinkerFlags()
{
const SettingsPtr s = settings();
const Profile buildProfile(profileName(), s.get());
- const QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList();
- if (!toolchain.contains("gcc") || targetOs() == HostOsInfo::HostOsMacos)
+ const QStringList toolchain = profileToolchain(buildProfile);
+ if (!toolchain.contains("gcc"))
QSKIP("escaped linker flags test only applies with gcc and GNU ld");
+ if (targetOs() == HostOsInfo::HostOsMacos)
+ QSKIP("Does not apply on macOS");
QDir::setCurrent(testDataDir + "/escaped-linker-flags");
QbsRunParameters params(QStringList("products.app.escapeLinkerFlags:false"));
QCOMPARE(runQbs(params), 0);
@@ -3836,6 +4007,40 @@ void TestBlackbox::fileTagsFilterMerging()
QVERIFY2(QFile::exists(otherOutput), qPrintable(otherOutput));
}
+void TestBlackbox::freedesktop()
+{
+ if (!HostOsInfo::isAnyUnixHost())
+ QSKIP("only applies on Unix");
+ if (HostOsInfo::isMacosHost())
+ QSKIP("Does not apply on macOS");
+ QDir::setCurrent(testDataDir + "/freedesktop");
+ QCOMPARE(runQbs(), 0);
+
+ // Check desktop file
+ QString desktopFilePath =
+ defaultInstallRoot + "/usr/local/share/applications/myapp.desktop";
+ QVERIFY(QFile::exists(desktopFilePath));
+ QFile desktopFile(desktopFilePath);
+ QVERIFY2(desktopFile.open(QIODevice::ReadOnly), qPrintable(desktopFile.errorString()));
+ QByteArrayList lines = desktopFile.readAll().split('\n');
+ // Automatically filled line:
+ QVERIFY(lines.contains("Exec=main"));
+ // Name specified in `freedesktop.name` property
+ QVERIFY(lines.contains("Name=My App"));
+ // Overridden line:
+ QVERIFY(lines.contains("Icon=myapp.png"));
+ // Untouched line:
+ QVERIFY(lines.contains("Terminal=false"));
+
+ // Check AppStream file
+ QVERIFY(QFile::exists(defaultInstallRoot +
+ "/usr/local/share/metainfo/myapp.appdata.xml"));
+
+ // Check icon file
+ QVERIFY(QFile::exists(defaultInstallRoot +
+ "/usr/local/share/icons/hicolor/scalable/apps/myapp.png"));
+}
+
void TestBlackbox::installedTransformerOutput()
{
QDir::setCurrent(testDataDir + "/installed-transformer-output");
@@ -3849,8 +4054,16 @@ void TestBlackbox::installLocations_data()
QTest::addColumn<QString>("binDir");
QTest::addColumn<QString>("dllDir");
QTest::addColumn<QString>("libDir");
- QTest::newRow("explicit values") << QString("bindir") << QString("dlldir") << QString("libdir");
- QTest::newRow("default values") << QString() << QString() << QString();
+ QTest::addColumn<QString>("pluginDir");
+ QTest::addColumn<QString>("dsymDir");
+ QTest::newRow("explicit values")
+ << QString("bindir")
+ << QString("dlldir")
+ << QString("libdir")
+ << QString("pluginDir")
+ << QString("dsymDir");
+ QTest::newRow("default values")
+ << QString() << QString() << QString() << QString() << QString();
}
void TestBlackbox::installLocations()
@@ -3859,6 +4072,8 @@ void TestBlackbox::installLocations()
QFETCH(QString, binDir);
QFETCH(QString, dllDir);
QFETCH(QString, libDir);
+ QFETCH(QString, pluginDir);
+ QFETCH(QString, dsymDir);
QbsRunParameters params("resolve");
if (!binDir.isEmpty())
params.arguments.push_back("products.theapp.installDir:" + binDir);
@@ -3866,6 +4081,13 @@ void TestBlackbox::installLocations()
params.arguments.push_back("products.thelib.installDir:" + dllDir);
if (!libDir.isEmpty())
params.arguments.push_back("products.thelib.importLibInstallDir:" + libDir);
+ if (!pluginDir.isEmpty())
+ params.arguments.push_back("products.theplugin.installDir:" + pluginDir);
+ if (!dsymDir.isEmpty()) {
+ params.arguments.push_back("products.theapp.debugInformationInstallDir:" + dsymDir);
+ params.arguments.push_back("products.thelib.debugInformationInstallDir:" + dsymDir);
+ params.arguments.push_back("products.theplugin.debugInformationInstallDir:" + dsymDir);
+ }
QCOMPARE(runQbs(params), 0);
const bool isWindows = m_qbsStdout.contains("is windows");
const bool isDarwin = m_qbsStdout.contains("is darwin");
@@ -3873,33 +4095,77 @@ void TestBlackbox::installLocations()
const bool isUnix = m_qbsStdout.contains("is unix");
QVERIFY(isWindows || isDarwin || isUnix);
QCOMPARE(runQbs(QbsRunParameters(QStringList("--clean-install-root"))), 0);
- const QString dllFileName =
- isWindows ? "thelib.dll" : isDarwin ? "thelib" : "libthelib.so";
- const QString appFileName = isWindows ? "theapp.exe" : "theapp";
- if (binDir.isEmpty())
- binDir = isDarwin ? "/Applications" : "/bin";
- if (dllDir.isEmpty())
- dllDir = isDarwin ? "/Library/Frameworks" : isWindows ? "/bin" : "/lib";
- if (libDir.isEmpty())
- libDir = "/lib";
- if (isDarwin) {
- if (isMac)
- binDir += "/theapp.app/Contents/MacOS";
- else
- binDir += "/theapp.app/";
- dllDir += "/thelib.framework";
- }
+
+ struct BinaryInfo
+ {
+ QString fileName;
+ QString installDir;
+ QString subDir;
+
+ QString absolutePath(const QString &prefix) const
+ {
+ return QDir::cleanPath(prefix + '/' + installDir + '/' + subDir + '/' + fileName);
+ }
+ };
+
+ const BinaryInfo dll = {
+ isWindows ? "thelib.dll" : isDarwin ? "thelib" : "libthelib.so",
+ dllDir.isEmpty()
+ ? (isDarwin ? "/Library/Frameworks" : (isWindows ? "/bin" : "/lib"))
+ : dllDir,
+ isDarwin ? "thelib.framework" : ""
+ };
+ const BinaryInfo dllDsym = {
+ isWindows ? "thelib.pdb" : isDarwin ? "thelib.framework.dSYM" : "libthelib.so.debug",
+ dsymDir.isEmpty() ? dll.installDir : dsymDir,
+ {}
+ };
+ const BinaryInfo plugin = {
+ isWindows ? "theplugin.dll" : isDarwin ? "theplugin" : "libtheplugin.so",
+ pluginDir.isEmpty() ? dll.installDir : pluginDir,
+ isDarwin ? (isMac ? "theplugin.bundle/Contents/MacOS" : "theplugin.bundle") : ""
+ };
+ const BinaryInfo pluginDsym = {
+ isWindows ? "theplugin.pdb" : isDarwin ? "theplugin.bundle.dSYM" : "libtheplugin.so.debug",
+ dsymDir.isEmpty() ? plugin.installDir : dsymDir,
+ {}
+ };
+ const BinaryInfo app = {
+ isWindows ? "theapp.exe" : "theapp",
+ binDir.isEmpty() ? (isDarwin ? "/Applications" : "/bin") : binDir,
+ isDarwin ? (isMac ? "theapp.app/Contents/MacOS" : "theapp.app") : ""
+ };
+ const BinaryInfo appDsym = {
+ isWindows ? "theapp.pdb" : isDarwin ? "theapp.app.dSYM" : "theapp.debug",
+ dsymDir.isEmpty() ? app.installDir : dsymDir,
+ {}
+ };
+
const QString installRoot = QDir::currentPath() + "/default/install-root";
const QString installPrefix = isWindows ? QString() : "/usr/local";
const QString fullInstallPrefix = installRoot + '/' + installPrefix + '/';
- const QString appFilePath = fullInstallPrefix + binDir + '/' + appFileName;
+ const QString appFilePath = app.absolutePath(fullInstallPrefix);
QVERIFY2(QFile::exists(appFilePath), qPrintable(appFilePath));
- const QString dllFilePath = fullInstallPrefix + dllDir + '/' + dllFileName;
+ const QString dllFilePath = dll.absolutePath(fullInstallPrefix);
QVERIFY2(QFile::exists(dllFilePath), qPrintable(dllFilePath));
if (isWindows) {
- const QString libFilePath = fullInstallPrefix + libDir + "/thelib.lib";
+ const BinaryInfo lib = {
+ "thelib.lib",
+ libDir.isEmpty() ? "/lib" : libDir,
+ ""
+ };
+ const QString libFilePath = lib.absolutePath(fullInstallPrefix);
QVERIFY2(QFile::exists(libFilePath), qPrintable(libFilePath));
}
+ const QString pluginFilePath = plugin.absolutePath(fullInstallPrefix);
+ QVERIFY2(QFile::exists(pluginFilePath), qPrintable(pluginFilePath));
+
+ const QString appDsymFilePath = appDsym.absolutePath(fullInstallPrefix);
+ QVERIFY2(QFileInfo(appDsymFilePath).exists(), qPrintable(appDsymFilePath));
+ const QString dllDsymFilePath = dllDsym.absolutePath(fullInstallPrefix);
+ QVERIFY2(QFileInfo(dllDsymFilePath).exists(), qPrintable(dllDsymFilePath));
+ const QString pluginDsymFilePath = pluginDsym.absolutePath(fullInstallPrefix);
+ QVERIFY2(QFile::exists(pluginDsymFilePath), qPrintable(pluginDsymFilePath));
}
void TestBlackbox::inputsFromDependencies()
@@ -4080,7 +4346,7 @@ void TestBlackbox::cli()
const SettingsPtr s = settings();
Profile p("qbs_autotests-cli", s.get());
- const QStringList toolchain = p.value("qbs.toolchain").toStringList();
+ const QStringList toolchain = profileToolchain(p);
if (!p.exists() || !(toolchain.contains("dotnet") || toolchain.contains("mono")))
QSKIP("No suitable Common Language Infrastructure test profile");
@@ -4311,6 +4577,15 @@ void TestBlackbox::jsExtensionsBinaryFile()
QCOMPARE(data.at(7), char(0xFF));
}
+void TestBlackbox::lastModuleCandidateBroken()
+{
+ QDir::setCurrent(testDataDir + "/last-module-candidate-broken");
+ QbsRunParameters params;
+ params.expectFailure = true;
+ QVERIFY(runQbs(params) != 0);
+ QVERIFY2(m_qbsStderr.contains("Module Foo could not be loaded"), m_qbsStderr);
+}
+
void TestBlackbox::ld()
{
QDir::setCurrent(testDataDir + "/ld");
@@ -4549,7 +4824,7 @@ void TestBlackbox::linkerLibraryDuplicates()
{
const SettingsPtr s = settings();
Profile buildProfile(profileName(), s.get());
- QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList();
+ QStringList toolchain = profileToolchain(buildProfile);
if (!toolchain.contains("gcc"))
QSKIP("linkerLibraryDuplicates test only applies to GCC toolchain");
@@ -4629,7 +4904,7 @@ void TestBlackbox::linkerScripts()
{
const SettingsPtr s = settings();
Profile buildProfile(profileName(), s.get());
- QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList();
+ QStringList toolchain = profileToolchain(buildProfile);
if (!toolchain.contains("gcc") || targetOs() != HostOsInfo::HostOsLinux)
QSKIP("linker script test only applies to Linux ");
@@ -4743,9 +5018,10 @@ void TestBlackbox::listPropertiesWithOuter()
void TestBlackbox::listPropertyOrder()
{
QDir::setCurrent(testDataDir + "/list-property-order");
- const QbsRunParameters params(QStringList() << "-qq");
+ const QbsRunParameters params(QStringList() << "-q");
QCOMPARE(runQbs(params), 0);
const QByteArray firstOutput = m_qbsStderr;
+ QVERIFY(firstOutput.contains("listProp = [\"product\",\"higher3\",\"higher2\",\"higher1\",\"lower\"]"));
for (int i = 0; i < 25; ++i) {
rmDirR(relativeBuildDir());
QCOMPARE(runQbs(params), 0);
@@ -4987,6 +5263,8 @@ void TestBlackbox::propertyPrecedence()
// Case 1: [cmdline=0,prod=0,export=0,nonleaf=0,profile=0]
QCOMPARE(runQbs(params), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
+
QVERIFY2(m_qbsStdout.contains("scalar prop: leaf\n")
&& m_qbsStdout.contains("list prop: [\"leaf\"]\n"),
m_qbsStdout.constData());
@@ -4995,6 +5273,8 @@ void TestBlackbox::propertyPrecedence()
// Case 2: [cmdline=0,prod=0,export=0,nonleaf=0,profile=1]
switchProfileContents(profile.p, s.get(), true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
+
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: profile\n")
&& m_qbsStdout.contains("list prop: [\"profile\"]\n"),
@@ -5006,6 +5286,7 @@ void TestBlackbox::propertyPrecedence()
switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: nonleaf\n")
&& m_qbsStdout.contains("list prop: [\"nonleaf\",\"leaf\"]\n"),
@@ -5014,6 +5295,7 @@ void TestBlackbox::propertyPrecedence()
// Case 4: [cmdline=0,prod=0,export=0,nonleaf=1,profile=1]
switchProfileContents(profile.p, s.get(), true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: nonleaf\n")
&& m_qbsStdout.contains("list prop: [\"nonleaf\",\"profile\"]\n"),
@@ -5026,6 +5308,7 @@ void TestBlackbox::propertyPrecedence()
switchFileContents(nonleafFile, false);
switchFileContents(depFile, true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: export\n")
&& m_qbsStdout.contains("list prop: [\"export\",\"leaf\"]\n"),
@@ -5034,15 +5317,21 @@ void TestBlackbox::propertyPrecedence()
// Case 6: [cmdline=0,prod=0,export=1,nonleaf=0,profile=1]
switchProfileContents(profile.p, s.get(), true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: export\n")
&& m_qbsStdout.contains("list prop: [\"export\",\"profile\"]\n"),
m_qbsStdout.constData());
+
// Case 7: [cmdline=0,prod=0,export=1,nonleaf=1,profile=0]
switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.contains("WARNING: Conflicting scalar values at")
+ && m_qbsStderr.contains("nonleaf.qbs:4:22")
+ && m_qbsStderr.contains("dep.qbs:6:26"),
+ m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: export\n")
&& m_qbsStdout.contains("list prop: [\"export\",\"nonleaf\",\"leaf\"]\n"),
@@ -5051,6 +5340,10 @@ void TestBlackbox::propertyPrecedence()
// Case 8: [cmdline=0,prod=0,export=1,nonleaf=1,profile=1]
switchProfileContents(profile.p, s.get(), true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.contains("WARNING: Conflicting scalar values at")
+ && m_qbsStderr.contains("nonleaf.qbs:4:22")
+ && m_qbsStderr.contains("dep.qbs:6:26"),
+ m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: export\n")
&& m_qbsStdout.contains("list prop: [\"export\",\"nonleaf\",\"profile\"]\n"),
@@ -5064,6 +5357,7 @@ void TestBlackbox::propertyPrecedence()
switchFileContents(depFile, false);
switchFileContents(productFile, true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"leaf\"]\n"),
@@ -5072,6 +5366,7 @@ void TestBlackbox::propertyPrecedence()
// Case 10: [cmdline=0,prod=1,export=0,nonleaf=0,profile=1]
switchProfileContents(profile.p, s.get(), true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"profile\"]\n"),
@@ -5081,6 +5376,7 @@ void TestBlackbox::propertyPrecedence()
switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"nonleaf\",\"leaf\"]\n"),
@@ -5089,6 +5385,7 @@ void TestBlackbox::propertyPrecedence()
// Case 12: [cmdline=0,prod=1,export=0,nonleaf=1,profile=1]
switchProfileContents(profile.p, s.get(), true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"nonleaf\",\"profile\"]\n"),
@@ -5099,6 +5396,7 @@ void TestBlackbox::propertyPrecedence()
switchFileContents(nonleafFile, false);
switchFileContents(depFile, true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"export\",\"leaf\"]\n"),
@@ -5107,6 +5405,7 @@ void TestBlackbox::propertyPrecedence()
// Case 14: [cmdline=0,prod=1,export=1,nonleaf=0,profile=1]
switchProfileContents(profile.p, s.get(), true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"export\",\"profile\"]\n"),
@@ -5116,6 +5415,7 @@ void TestBlackbox::propertyPrecedence()
switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"export\",\"nonleaf\",\"leaf\"]\n"),
@@ -5124,6 +5424,7 @@ void TestBlackbox::propertyPrecedence()
// Case 16: [cmdline=0,prod=1,export=1,nonleaf=1,profile=1]
switchProfileContents(profile.p, s.get(), true);
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"export\",\"nonleaf\",\"profile\"]\n"),
@@ -5137,6 +5438,7 @@ void TestBlackbox::propertyPrecedence()
switchFileContents(productFile, false);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5146,6 +5448,7 @@ void TestBlackbox::propertyPrecedence()
switchProfileContents(profile.p, s.get(), true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5156,6 +5459,7 @@ void TestBlackbox::propertyPrecedence()
switchFileContents(nonleafFile, true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5165,6 +5469,7 @@ void TestBlackbox::propertyPrecedence()
switchProfileContents(profile.p, s.get(), true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5176,6 +5481,7 @@ void TestBlackbox::propertyPrecedence()
switchFileContents(depFile, true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5185,6 +5491,7 @@ void TestBlackbox::propertyPrecedence()
switchProfileContents(profile.p, s.get(), true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5195,6 +5502,7 @@ void TestBlackbox::propertyPrecedence()
switchFileContents(nonleafFile, true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5204,6 +5512,7 @@ void TestBlackbox::propertyPrecedence()
switchProfileContents(profile.p, s.get(), true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5216,6 +5525,7 @@ void TestBlackbox::propertyPrecedence()
switchFileContents(productFile, true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5225,6 +5535,7 @@ void TestBlackbox::propertyPrecedence()
switchProfileContents(profile.p, s.get(), true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5235,6 +5546,7 @@ void TestBlackbox::propertyPrecedence()
switchFileContents(nonleafFile, true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5244,6 +5556,7 @@ void TestBlackbox::propertyPrecedence()
switchProfileContents(profile.p, s.get(), true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5255,6 +5568,7 @@ void TestBlackbox::propertyPrecedence()
switchFileContents(depFile, true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5264,6 +5578,7 @@ void TestBlackbox::propertyPrecedence()
switchProfileContents(profile.p, s.get(), true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5274,6 +5589,7 @@ void TestBlackbox::propertyPrecedence()
switchFileContents(nonleafFile, true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5283,6 +5599,7 @@ void TestBlackbox::propertyPrecedence()
switchProfileContents(profile.p, s.get(), true);
resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
QCOMPARE(runQbs(resolveParams), 0);
+ QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData());
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
@@ -5563,8 +5880,8 @@ void TestBlackbox::qbsSession()
// Wait for and verify hello packet.
QJsonObject receivedMessage = getNextSessionPacket(sessionProc, incomingData);
QCOMPARE(receivedMessage.value("type"), "hello");
- QCOMPARE(receivedMessage.value("api-level").toInt(), 1);
- QCOMPARE(receivedMessage.value("api-compat-level").toInt(), 1);
+ QCOMPARE(receivedMessage.value("api-level").toInt(), 2);
+ QCOMPARE(receivedMessage.value("api-compat-level").toInt(), 2);
// Resolve & verify structure
QJsonObject resolveMessage;
@@ -5622,7 +5939,7 @@ void TestBlackbox::qbsSession()
const QJsonObject group = v.toObject();
const QJsonArray sourceArtifacts
= group.value("source-artifacts").toArray();
- const auto findArtifact = [&sourceArtifacts](const QString fileName) {
+ const auto findArtifact = [&sourceArtifacts](const QString &fileName) {
for (const QJsonValue &v : sourceArtifacts) {
const QJsonObject artifact = v.toObject();
if (QFileInfo(artifact.value("file-path").toString()).fileName()
@@ -5892,34 +6209,51 @@ void TestBlackbox::qbsSession()
qDebug() << error;
}
QVERIFY(error.isEmpty());
- QJsonObject projectData = receivedMessage.value("project-data").toObject();
- QJsonArray products = projectData.value("products").toArray();
- bool file1 = false;
- bool file2 = false;
- for (const QJsonValue &v : products) {
- const QJsonObject product = v.toObject();
- const QString productName = product.value("full-display-name").toString();
- const QJsonArray groups = product.value("groups").toArray();
- for (const QJsonValue &v : groups) {
- const QJsonObject group = v.toObject();
- const QString groupName = group.value("name").toString();
- const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray();
- for (const QJsonValue &v : sourceArtifacts) {
- const QString filePath = v.toObject().value("file-path").toString();
- if (filePath.endsWith("file1.cpp")) {
- QCOMPARE(productName, QString("theLib"));
- QCOMPARE(groupName, QString("sources"));
- file1 = true;
- } else if (filePath.endsWith("file2.cpp")) {
- QCOMPARE(productName, QString("theLib"));
- QCOMPARE(groupName, QString("sources"));
- file2 = true;
+
+ receivedReply = false;
+ sendPacket(resolveMessage);
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-resolved") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ const QJsonObject projectData = receivedMessage.value("project-data").toObject();
+ QJsonArray products = projectData.value("products").toArray();
+ bool file1 = false;
+ bool file2 = false;
+ for (const QJsonValue &v : products) {
+ const QJsonObject product = v.toObject();
+ const QString productName = product.value("full-display-name").toString();
+ const QJsonArray groups = product.value("groups").toArray();
+ for (const QJsonValue &v : groups) {
+ const QJsonObject group = v.toObject();
+ const QString groupName = group.value("name").toString();
+ const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray();
+ for (const QJsonValue &v : sourceArtifacts) {
+ const QString filePath = v.toObject().value("file-path").toString();
+ if (filePath.endsWith("file1.cpp")) {
+ QCOMPARE(productName, QString("theLib"));
+ QCOMPARE(groupName, QString("sources"));
+ file1 = true;
+ } else if (filePath.endsWith("file2.cpp")) {
+ QCOMPARE(productName, QString("theLib"));
+ QCOMPARE(groupName, QString("sources"));
+ file2 = true;
+ }
+ }
}
}
+ QVERIFY(file1);
+ QVERIFY(file2);
}
}
- QVERIFY(file1);
- QVERIFY(file2);
+ QVERIFY(receivedReply);
+
receivedReply = false;
receivedProcessResult = false;
bool compiledFile1 = false;
@@ -5978,32 +6312,48 @@ void TestBlackbox::qbsSession()
if (!error.isEmpty())
qDebug() << error;
QVERIFY(error.isEmpty());
- projectData = receivedMessage.value("project-data").toObject();
- products = projectData.value("products").toArray();
- file1 = false;
- file2 = false;
- for (const QJsonValue &v : products) {
- const QJsonObject product = v.toObject();
- const QString productName = product.value("full-display-name").toString();
- const QJsonArray groups = product.value("groups").toArray();
- for (const QJsonValue &v : groups) {
- const QJsonObject group = v.toObject();
- const QString groupName = group.value("name").toString();
- const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray();
- for (const QJsonValue &v : sourceArtifacts) {
- const QString filePath = v.toObject().value("file-path").toString();
- if (filePath.endsWith("file1.cpp")) {
- file1 = true;
- } else if (filePath.endsWith("file2.cpp")) {
- QCOMPARE(productName, QString("theLib"));
- QCOMPARE(groupName, QString("sources"));
- file2 = true;
+ receivedReply = false;
+ sendPacket(resolveMessage);
+ while (!receivedReply) {
+ receivedMessage = getNextSessionPacket(sessionProc, incomingData);
+ QVERIFY(!receivedMessage.isEmpty());
+ const QString msgType = receivedMessage.value("type").toString();
+ if (msgType == "project-resolved") {
+ receivedReply = true;
+ const QJsonObject error = receivedMessage.value("error").toObject();
+ if (!error.isEmpty())
+ qDebug() << error;
+ QVERIFY(error.isEmpty());
+ const QJsonObject projectData = receivedMessage.value("project-data").toObject();
+ QJsonArray products = projectData.value("products").toArray();
+ bool file1 = false;
+ bool file2 = false;
+ for (const QJsonValue &v : products) {
+ const QJsonObject product = v.toObject();
+ const QString productName = product.value("full-display-name").toString();
+ const QJsonArray groups = product.value("groups").toArray();
+ for (const QJsonValue &v : groups) {
+ const QJsonObject group = v.toObject();
+ const QString groupName = group.value("name").toString();
+ const QJsonArray sourceArtifacts = group.value("source-artifacts").toArray();
+ for (const QJsonValue &v : sourceArtifacts) {
+ const QString filePath = v.toObject().value("file-path").toString();
+ if (filePath.endsWith("file1.cpp")) {
+ file1 = true;
+ } else if (filePath.endsWith("file2.cpp")) {
+ QCOMPARE(productName, QString("theLib"));
+ QCOMPARE(groupName, QString("sources"));
+ file2 = true;
+ }
+ }
}
}
+ QVERIFY(!file1);
+ QVERIFY(file2);
}
}
- QVERIFY(!file1);
- QVERIFY(file2);
+ QVERIFY(receivedReply);
+
receivedReply = false;
receivedProcessResult = false;
compiledFile1 = false;
@@ -7012,6 +7362,12 @@ void TestBlackbox::typescript()
QVERIFY(regularFileExists(relativeProductBuildDir("animals") + "/main.js"));
}
+void TestBlackbox::undefinedTargetPlatform()
+{
+ QDir::setCurrent(testDataDir + "/undefined-target-platform");
+ QCOMPARE(runQbs(), 0);
+}
+
void TestBlackbox::importInPropertiesCondition()
{
QDir::setCurrent(testDataDir + "/import-in-properties-condition");
@@ -7776,6 +8132,17 @@ void TestBlackbox::grpc()
QCOMPARE(runQbs(runParams), 0);
}
+void TestBlackbox::hostOsProperties()
+{
+ QDir::setCurrent(testDataDir + "/host-os-properties");
+ QCOMPARE(runQbs(QStringLiteral("run")), 0);
+ QVERIFY2(m_qbsStdout.contains(
+ ("HOST_ARCHITECTURE = " + HostOsInfo::hostOSArchitecture()).data()),
+ m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains(("HOST_PLATFORM = " + HostOsInfo::hostOSIdentifier()).data()),
+ m_qbsStdout.constData());
+}
+
void TestBlackbox::ico()
{
QDir::setCurrent(testDataDir + "/ico");
diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h
index 4e2755724..757462b80 100644
--- a/tests/auto/blackbox/tst_blackbox.h
+++ b/tests/auto/blackbox/tst_blackbox.h
@@ -60,6 +60,8 @@ private slots:
void buildDirectories();
void buildEnvChange();
void buildGraphVersions();
+ void buildVariantDefaults_data();
+ void buildVariantDefaults();
void changedFiles_data();
void changedFiles();
void changedInputsFromDependencies();
@@ -83,9 +85,10 @@ private slots:
void conflictingArtifacts();
void cxxLanguageVersion();
void cxxLanguageVersion_data();
+ void conanfileProbe();
void cpuFeatures();
void dependenciesProperty();
- void dependencyProfileMismatch();
+ void dependencyScanningLoop();
void deprecatedProperty();
void disappearedProfile();
void discardUnusedData();
@@ -96,6 +99,7 @@ private slots:
void dynamicMultiplexRule();
void dynamicProject();
void dynamicRuleOutputs();
+ void emptyProfile();
void enableExceptions();
void enableExceptions_data();
void enableRtti();
@@ -118,6 +122,7 @@ private slots:
void externalLibs();
void fileDependencies();
void fileTagsFilterMerging();
+ void freedesktop();
void generatedArtifactAsInputToDynamicRule();
void generateLinkerMapFile();
void generator();
@@ -125,6 +130,7 @@ private slots:
void groupsInModules();
void grpc_data();
void grpc();
+ void hostOsProperties();
void ico();
void importAssignment();
void importChangeTracking();
@@ -164,6 +170,7 @@ private slots:
void jsExtensionsTemporaryDir();
void jsExtensionsTextFile();
void jsExtensionsBinaryFile();
+ void lastModuleCandidateBroken();
void ld();
void linkerMode();
void linkerVariant_data();
@@ -236,6 +243,7 @@ private slots:
void propertyAssignmentOnNonPresentModule();
void propertyAssignmentInFailedModule();
void propertyChanges();
+ void propertyEvaluationContext();
void propertyPrecedence();
void properQuoting();
void propertiesInExportItems();
@@ -265,7 +273,11 @@ private slots:
void ruleCycle();
void ruleWithNoInputs();
void ruleWithNonRequiredInputs();
+ void sanitizer_data();
+ void sanitizer();
void scannerItem();
+ void scanResultInOtherProduct();
+ void scanResultInNonDependency();
void setupBuildEnvironment();
void setupRunEnvironment();
void smartRelinking();
@@ -301,6 +313,7 @@ private slots:
void trackRemoveProduct();
void transitiveOptionalDependencies();
void typescript();
+ void undefinedTargetPlatform();
void usingsAsSoleInputsNonMultiplexed();
void variantSuffix();
void variantSuffix_data();
diff --git a/tests/auto/blackbox/tst_blackboxandroid.cpp b/tests/auto/blackbox/tst_blackboxandroid.cpp
index e312c4493..eb0303a07 100644
--- a/tests/auto/blackbox/tst_blackboxandroid.cpp
+++ b/tests/auto/blackbox/tst_blackboxandroid.cpp
@@ -79,7 +79,7 @@ void TestBlackboxAndroid::android()
QFETCH(QString, projectDir);
QFETCH(QStringList, productNames);
QFETCH(QList<QByteArrayList>, expectedFilesLists);
- QFETCH(QStringList, customProperties);
+ QFETCH(QStringList, qmlAppCustomProperties);
const SettingsPtr s = settings();
Profile p(theProfileName(projectDir == "qml-app"), s.get());
@@ -110,7 +110,7 @@ void TestBlackboxAndroid::android()
auto currentExpectedFilesLists = expectedFilesLists;
const QString configArgument = "config:" + configName;
QbsRunParameters resolveParams("resolve");
- resolveParams.arguments << configArgument << customProperties;
+ resolveParams.arguments << configArgument << qmlAppCustomProperties;
resolveParams.profile = p.name();
QCOMPARE(runQbs(resolveParams), 0);
QbsRunParameters buildParams(QStringList{"--command-echo-mode", "command-line",
@@ -206,14 +206,41 @@ void TestBlackboxAndroid::android_data()
.toString() == "clang";
return QByteArray("lib/${ARCH}/") + (usesClang ? "libc++_shared.so" : oldcxxLib);
};
- const QByteArrayList archsForQt = { pQt.value("qbs.architecture").toString().toUtf8() };
- QByteArrayList ndkArchsForQt = archsForQt;
- if (ndkArchsForQt.first() == "armv7a")
- ndkArchsForQt.first() = "armeabi-v7a";
- else if (ndkArchsForQt.first() == "armv5te")
- ndkArchsForQt.first() = "armeabi";
- else if (ndkArchsForQt.first() == "arm64")
- ndkArchsForQt.first() = "arm64-v8a";
+
+ bool usingOldQt = true;
+ QStringList qmakeFilePaths = pQt.value(QStringLiteral("moduleProviders.Qt.qmakeFilePaths")).
+ toStringList();
+ if (qmakeFilePaths.size() == 1) {
+ qbs::Version version = TestBlackboxBase::qmakeVersion(qmakeFilePaths[0]);
+ if (version.isValid() && version >= qbs::Version(5, 14))
+ usingOldQt = false;
+ }
+
+ QByteArrayList archsForQt;
+ if (usingOldQt) {
+ archsForQt = { pQt.value("qbs.architecture").toString().toUtf8() };
+ if (archsStringList.empty())
+ archsStringList << QStringLiteral("armv7a"); // must match default in common.qbs
+ } else {
+ QStringList archsForQtStringList = pQt.value(QStringLiteral("qbs.architectures"))
+ .toStringList();
+ if (archsForQtStringList.empty())
+ archsForQtStringList << pQt.value("qbs.architecture").toString();
+ std::transform(archsForQtStringList.begin(),
+ archsForQtStringList.end(),
+ std::back_inserter(archsForQt),
+ [] (const QString &s) {
+ return s.toUtf8();
+ });
+ }
+
+ QByteArrayList ndkArchsForQt;
+ std::transform(archsForQt.begin(), archsForQt.end(), std::back_inserter(ndkArchsForQt),
+ [] (const QString &s) {
+ return s.toUtf8().replace("armv7a", "armeabi-v7a")
+ .replace("armv5te", "armeabi")
+ .replace("arm64", "arm64-v8a");
+ });
auto expandArchs = [] (const QByteArrayList &archs, const QByteArrayList &lst) {
const QByteArray &archPlaceHolder = "${ARCH}";
@@ -237,7 +264,7 @@ void TestBlackboxAndroid::android_data()
QTest::addColumn<QString>("projectDir");
QTest::addColumn<QStringList>("productNames");
QTest::addColumn<QList<QByteArrayList>>("expectedFilesLists");
- QTest::addColumn<QStringList>("customProperties");
+ QTest::addColumn<QStringList>("qmlAppCustomProperties");
QTest::newRow("teapot")
<< "teapot" << QStringList("TeapotNativeActivity")
<< (QList<QByteArrayList>() << commonFiles + expandArchs(archs, {
@@ -257,9 +284,12 @@ void TestBlackboxAndroid::android_data()
"lib/${ARCH}/libdependency.so"}))
<< QStringList{"products.minimalnative.multiplexByQbsProperties:[]",
"modules.qbs.architecture:" + archsStringList.first()};
- QTest::newRow("qml app")
- << "qml-app" << QStringList("qmlapp")
- << (QList<QByteArrayList>() << commonFiles + expandArchs(ndkArchsForQt, {
+ QByteArrayList qmlAppExpectedFiles;
+ QByteArrayList qmlAppMinistroExpectedFiles;
+ QByteArrayList qmlAppCustomMetaDataExpectedFiles;
+ QStringList qmlAppCustomProperties;
+ if (usingOldQt) {
+ qmlAppExpectedFiles << commonFiles + expandArchs(ndkArchsForQt, {
"resources.arsc",
"assets/--Added-by-androiddeployqt--/qml/QtQuick.2/plugins.qmltypes",
"assets/--Added-by-androiddeployqt--/qml/QtQuick.2/qmldir",
@@ -298,64 +328,157 @@ void TestBlackboxAndroid::android_data()
"lib/${ARCH}/libQt5QuickParticles.so",
"lib/${ARCH}/libQt5Quick.so",
"lib/${ARCH}/libqmlapp.so",
- "res/layout/splash.xml"}))
- << QStringList{"modules.Android.sdk.automaticSources:false",
- "modules.qbs.architecture:" + archsForQt.first()};
- QTest::newRow("qml app using Ministro")
- << "qml-app" << QStringList("qmlapp")
- << (QList<QByteArrayList>() << commonFiles + expandArchs(ndkArchsForQt, {
+ "res/layout/splash.xml"});
+ qmlAppMinistroExpectedFiles << commonFiles + expandArchs(ndkArchsForQt, {
+ "resources.arsc",
+ "assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list",
+ "lib/${ARCH}/libgdbserver.so",
+ cxxLibPath("libgnustl_shared.so", true),
+ "lib/${ARCH}/libqmlapp.so",
+ "res/layout/splash.xml"});
+ qmlAppCustomMetaDataExpectedFiles << commonFiles + expandArchs(ndkArchsForQt, {
+ "resources.arsc",
+ "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/plugins.qmltypes",
+ "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/qmldir",
+ "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/plugins.qmltypes",
+ "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/qmldir",
+ "assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list",
+ "assets/dummyasset.txt",
+ "lib/${ARCH}/libgdbserver.so",
+ cxxLibPath("libgnustl_shared.so", true),
+ "lib/${ARCH}/libplugins_bearer_libqandroidbearer.so",
+ "lib/${ARCH}/libplugins_imageformats_libqgif.so",
+ "lib/${ARCH}/libplugins_imageformats_libqicns.so",
+ "lib/${ARCH}/libplugins_imageformats_libqico.so",
+ "lib/${ARCH}/libplugins_imageformats_libqjpeg.so",
+ "lib/${ARCH}/libplugins_imageformats_libqtga.so",
+ "lib/${ARCH}/libplugins_imageformats_libqtiff.so",
+ "lib/${ARCH}/libplugins_imageformats_libqwbmp.so",
+ "lib/${ARCH}/libplugins_imageformats_libqwebp.so",
+ "lib/${ARCH}/libplugins_platforms_android_libqtforandroid.so",
+ "lib/${ARCH}/libplugins_qmltooling_libqmldbg_debugger.so",
+ "lib/${ARCH}/libplugins_qmltooling_libqmldbg_inspector.so",
+ "lib/${ARCH}/libplugins_qmltooling_libqmldbg_local.so",
+ "lib/${ARCH}/libplugins_qmltooling_libqmldbg_messages.so",
+ "lib/${ARCH}/libplugins_qmltooling_libqmldbg_native.so",
+ "lib/${ARCH}/libplugins_qmltooling_libqmldbg_nativedebugger.so",
+ "lib/${ARCH}/libplugins_qmltooling_libqmldbg_profiler.so",
+ "lib/${ARCH}/libplugins_qmltooling_libqmldbg_preview.so",
+ "lib/${ARCH}/libplugins_qmltooling_libqmldbg_quickprofiler.so",
+ "lib/${ARCH}/libplugins_qmltooling_libqmldbg_server.so",
+ "lib/${ARCH}/libplugins_qmltooling_libqmldbg_tcp.so",
+ "lib/${ARCH}/libqml_QtQuick.2_libqtquick2plugin.so",
+ "lib/${ARCH}/libqml_QtQuick_Window.2_libwindowplugin.so",
+ "lib/${ARCH}/libQt5Core.so",
+ "lib/${ARCH}/libQt5Gui.so",
+ "lib/${ARCH}/libQt5Network.so",
+ "lib/${ARCH}/libQt5Qml.so",
+ "lib/${ARCH}/libQt5QuickParticles.so",
+ "lib/${ARCH}/libQt5Quick.so",
+ "lib/${ARCH}/libqmlapp.so",
+ "res/layout/splash.xml"});
+ qmlAppCustomProperties = QStringList{"modules.Android.sdk.automaticSources:false",
+ "modules.qbs.architecture:" + archsForQt.first()};
+ } else {
+ qmlAppExpectedFiles << commonFiles + expandArchs(ndkArchsForQt, {
"resources.arsc",
- "assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list",
+ "assets/android_rcc_bundle.rcc",
"lib/${ARCH}/libgdbserver.so",
cxxLibPath("libgnustl_shared.so", true),
- "lib/${ARCH}/libqmlapp.so",
- "res/layout/splash.xml"}))
+ "lib/${ARCH}/libplugins_bearer_qandroidbearer_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qgif_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qicns_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qico_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qjpeg_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qtga_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qtiff_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qwbmp_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qwebp_${ARCH}.so",
+ "lib/${ARCH}/libplugins_platforms_qtforandroid_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_debugger_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_inspector_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_local_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_messages_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_native_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_nativedebugger_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_profiler_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_preview_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_quickprofiler_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_server_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_tcp_${ARCH}.so",
+ "lib/${ARCH}/libqml_QtQuick.2_qtquick2plugin_${ARCH}.so",
+ "lib/${ARCH}/libqml_QtQuick_Window.2_windowplugin_${ARCH}.so",
+ "lib/${ARCH}/libQt5Core_${ARCH}.so",
+ "lib/${ARCH}/libQt5Gui_${ARCH}.so",
+ "lib/${ARCH}/libQt5Network_${ARCH}.so",
+ "lib/${ARCH}/libQt5Qml_${ARCH}.so",
+ "lib/${ARCH}/libQt5QuickParticles_${ARCH}.so",
+ "lib/${ARCH}/libQt5Quick_${ARCH}.so",
+ "lib/${ARCH}/libQt5QmlModels_${ARCH}.so",
+ "lib/${ARCH}/libQt5QmlWorkerScript_${ARCH}.so",
+ "lib/${ARCH}/libqmlapp_${ARCH}.so",
+ "res/layout/splash.xml"});
+ qmlAppMinistroExpectedFiles << commonFiles + expandArchs(ndkArchsForQt, {
+ "resources.arsc",
+ "assets/android_rcc_bundle.rcc",
+ "lib/${ARCH}/libgdbserver.so",
+ cxxLibPath("libgnustl_shared.so", true),
+ "lib/${ARCH}/libqmlapp_${ARCH}.so",
+ "res/layout/splash.xml"});
+ qmlAppCustomMetaDataExpectedFiles << commonFiles + expandArchs(ndkArchsForQt, {
+ "resources.arsc",
+ "assets/android_rcc_bundle.rcc",
+ "assets/dummyasset.txt",
+ "lib/${ARCH}/libgdbserver.so",
+ cxxLibPath("libgnustl_shared.so", true),
+ "lib/${ARCH}/libplugins_bearer_qandroidbearer_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qgif_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qicns_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qico_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qjpeg_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qtga_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qtiff_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qwbmp_${ARCH}.so",
+ "lib/${ARCH}/libplugins_imageformats_qwebp_${ARCH}.so",
+ "lib/${ARCH}/libplugins_platforms_qtforandroid_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_debugger_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_inspector_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_local_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_messages_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_native_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_nativedebugger_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_profiler_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_preview_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_quickprofiler_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_server_${ARCH}.so",
+ "lib/${ARCH}/libplugins_qmltooling_qmldbg_tcp_${ARCH}.so",
+ "lib/${ARCH}/libqml_QtQuick.2_qtquick2plugin_${ARCH}.so",
+ "lib/${ARCH}/libqml_QtQuick_Window.2_windowplugin_${ARCH}.so",
+ "lib/${ARCH}/libQt5Core_${ARCH}.so",
+ "lib/${ARCH}/libQt5Gui_${ARCH}.so",
+ "lib/${ARCH}/libQt5Network_${ARCH}.so",
+ "lib/${ARCH}/libQt5Qml_${ARCH}.so",
+ "lib/${ARCH}/libQt5QuickParticles_${ARCH}.so",
+ "lib/${ARCH}/libQt5Quick_${ARCH}.so",
+ "lib/${ARCH}/libQt5QmlModels_${ARCH}.so",
+ "lib/${ARCH}/libQt5QmlWorkerScript_${ARCH}.so",
+ "lib/${ARCH}/libqmlapp_${ARCH}.so",
+ "res/layout/splash.xml"});
+ qmlAppCustomProperties = QStringList{"modules.Android.sdk.automaticSources:false"};
+ }
+ QTest::newRow("qml app")
+ << "qml-app" << QStringList("qmlapp")
+ << (QList<QByteArrayList>() << qmlAppExpectedFiles)
+ << qmlAppCustomProperties;
+ QTest::newRow("qml app using Ministro")
+ << "qml-app" << QStringList("qmlapp")
+ << (QList<QByteArrayList>() << qmlAppMinistroExpectedFiles)
<< QStringList{"modules.Qt.android_support.useMinistro:true",
"modules.Android.sdk.automaticSources:false"};
QTest::newRow("qml app with custom metadata")
<< "qml-app" << QStringList("qmlapp")
- << (QList<QByteArrayList>() << commonFiles + expandArchs(ndkArchsForQt, {
- "resources.arsc",
- "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/plugins.qmltypes",
- "assets/--Added-by-androiddeployqt--/qml/QtQuick.2/qmldir",
- "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/plugins.qmltypes",
- "assets/--Added-by-androiddeployqt--/qml/QtQuick/Window.2/qmldir",
- "assets/--Added-by-androiddeployqt--/qt_cache_pregenerated_file_list",
- "assets/dummyasset.txt",
- "lib/${ARCH}/libgdbserver.so",
- cxxLibPath("libgnustl_shared.so", true),
- "lib/${ARCH}/libplugins_bearer_libqandroidbearer.so",
- "lib/${ARCH}/libplugins_imageformats_libqgif.so",
- "lib/${ARCH}/libplugins_imageformats_libqicns.so",
- "lib/${ARCH}/libplugins_imageformats_libqico.so",
- "lib/${ARCH}/libplugins_imageformats_libqjpeg.so",
- "lib/${ARCH}/libplugins_imageformats_libqtga.so",
- "lib/${ARCH}/libplugins_imageformats_libqtiff.so",
- "lib/${ARCH}/libplugins_imageformats_libqwbmp.so",
- "lib/${ARCH}/libplugins_imageformats_libqwebp.so",
- "lib/${ARCH}/libplugins_platforms_android_libqtforandroid.so",
- "lib/${ARCH}/libplugins_qmltooling_libqmldbg_debugger.so",
- "lib/${ARCH}/libplugins_qmltooling_libqmldbg_inspector.so",
- "lib/${ARCH}/libplugins_qmltooling_libqmldbg_local.so",
- "lib/${ARCH}/libplugins_qmltooling_libqmldbg_messages.so",
- "lib/${ARCH}/libplugins_qmltooling_libqmldbg_native.so",
- "lib/${ARCH}/libplugins_qmltooling_libqmldbg_nativedebugger.so",
- "lib/${ARCH}/libplugins_qmltooling_libqmldbg_profiler.so",
- "lib/${ARCH}/libplugins_qmltooling_libqmldbg_preview.so",
- "lib/${ARCH}/libplugins_qmltooling_libqmldbg_quickprofiler.so",
- "lib/${ARCH}/libplugins_qmltooling_libqmldbg_server.so",
- "lib/${ARCH}/libplugins_qmltooling_libqmldbg_tcp.so",
- "lib/${ARCH}/libqml_QtQuick.2_libqtquick2plugin.so",
- "lib/${ARCH}/libqml_QtQuick_Window.2_libwindowplugin.so",
- "lib/${ARCH}/libQt5Core.so",
- "lib/${ARCH}/libQt5Gui.so",
- "lib/${ARCH}/libQt5Network.so",
- "lib/${ARCH}/libQt5Qml.so",
- "lib/${ARCH}/libQt5QuickParticles.so",
- "lib/${ARCH}/libQt5Quick.so",
- "lib/${ARCH}/libqmlapp.so",
- "res/layout/splash.xml"}))
- << QStringList("modules.Android.sdk.automaticSources:true");
+ << (QList<QByteArrayList>() << qmlAppCustomMetaDataExpectedFiles)
+ << QStringList("modules.Android.sdk.automaticSources:true");
QTest::newRow("no native")
<< "no-native"
<< QStringList("com.example.android.basicmediadecoder")
@@ -390,7 +513,7 @@ void TestBlackboxAndroid::android_data()
"lib/${ARCH}/liblib2.so",
cxxLibPath("libstlport_shared.so", false)}))
<< QStringList();
- QByteArrayList expectedFiles1 = (commonFiles
+ QByteArrayList expectedFiles1 = qbs::toList(qbs::toSet(commonFiles
+ expandArchs(QByteArrayList{"armeabi-v7a", "x86"}, {
"resources.arsc",
"lib/${ARCH}/libgdbserver.so",
@@ -400,7 +523,7 @@ void TestBlackboxAndroid::android_data()
"resources.arsc",
"lib/${ARCH}/libgdbserver.so",
"lib/${ARCH}/libp1lib2.so",
- cxxLibPath("libstlport_shared.so", false)})).toSet().toList();
+ cxxLibPath("libstlport_shared.so", false)})));
QByteArrayList expectedFiles2 = commonFiles + expandArchs(archs, {
"lib/${ARCH}/libgdbserver.so",
"lib/${ARCH}/libp2lib1.so",
diff --git a/tests/auto/blackbox/tst_blackboxapple.cpp b/tests/auto/blackbox/tst_blackboxapple.cpp
index cde742f3c..3623dc51b 100644
--- a/tests/auto/blackbox/tst_blackboxapple.cpp
+++ b/tests/auto/blackbox/tst_blackboxapple.cpp
@@ -60,6 +60,65 @@ static QString getEmbeddedBinaryPlist(const QString &file)
return QString::fromUtf8(p.readAllStandardOutput()).trimmed();
}
+static QVariantMap readInfoPlistFile(const QString &infoPlistPath)
+{
+ if (!QFile::exists(infoPlistPath)) {
+ qWarning() << infoPlistPath << "doesn't exist";
+ return {};
+ }
+
+ QProcess plutil;
+ plutil.start("plutil", {
+ QStringLiteral("-convert"),
+ QStringLiteral("json"),
+ infoPlistPath
+ });
+ if (!plutil.waitForStarted()) {
+ qWarning() << plutil.errorString();
+ return {};
+ }
+ if (!plutil.waitForFinished()) {
+ qWarning() << plutil.errorString();
+ return {};
+ }
+ if (plutil.exitCode() != 0) {
+ qWarning() << plutil.readAllStandardError().constData();
+ return {};
+ }
+
+ QFile infoPlist(infoPlistPath);
+ if (!infoPlist.open(QIODevice::ReadOnly)) {
+ qWarning() << infoPlist.errorString();
+ return {};
+ }
+ QJsonParseError error;
+ const auto json = QJsonDocument::fromJson(infoPlist.readAll(), &error);
+ if (error.error != QJsonParseError::NoError) {
+ qWarning() << error.errorString();
+ return {};
+ }
+ return json.object().toVariantMap();
+}
+
+static QString getInfoPlistPath(const QString &bundlePath)
+{
+ QFileInfo contents(bundlePath + "/Contents");
+ if (contents.exists() && contents.isDir())
+ return contents.filePath() + "/Info.plist"; // macOS bundle
+ return bundlePath + "/Info.plist";
+}
+
+static bool testVariantListType(const QVariant &variant, QMetaType::Type type)
+{
+ if (variant.userType() != QMetaType::QVariantList)
+ return false;
+ for (const auto &value : variant.toList()) {
+ if (value.userType() != type)
+ return false;
+ }
+ return true;
+}
+
TestBlackboxApple::TestBlackboxApple()
: TestBlackboxBase (SRCDIR "/testdata-apple", "blackbox-apple")
{
@@ -190,8 +249,11 @@ void TestBlackboxApple::appleMultiConfig()
void TestBlackboxApple::aggregateDependencyLinking()
{
- if (HostOsInfo::hostOsVersion() > qbs::Version(10, 13, 4))
- QSKIP("32-bit arch build is no longer supported on macOS versions higher than 10.13.4.");
+ // XCode 11 produces warning about deprecation of 32-bit apps, so skip the test
+ // for future XCode versions as well
+ const auto xcodeVersion = findXcodeVersion();
+ if (xcodeVersion >= qbs::Version(11))
+ QSKIP("32-bit arch build is no longer supported on macOS higher than 10.13.4.");
QDir::setCurrent(testDataDir + "/aggregateDependencyLinking");
QCOMPARE(runQbs(QStringList{"-p", "multi_arch_lib"}), 0);
@@ -623,47 +685,47 @@ void TestBlackboxApple::deploymentTarget_data()
}
QTest::newRow("macos x86_64") << "macosx" << macos << "x86_64"
<< "-triple x86_64-apple-macosx10.6"
- << "-macosx_version_min 10.6";
+ << "10.6";
if (xcodeVersion >= qbs::Version(6))
QTest::newRow("macos x86_64h") << "macosx" << macos << "x86_64h"
<< "-triple x86_64h-apple-macosx10.12"
- << "-macosx_version_min 10.12";
+ << "10.12";
QTest::newRow("ios armv7a") << "iphoneos" << ios << "armv7a"
<< "-triple thumbv7-apple-ios6.0"
- << "-iphoneos_version_min 6.0";
+ << "6.0";
QTest::newRow("ios armv7s") << "iphoneos" <<ios << "armv7s"
<< "-triple thumbv7s-apple-ios7.0"
- << "-iphoneos_version_min 7.0";
+ << "7.0";
if (xcodeVersion >= qbs::Version(5))
QTest::newRow("ios arm64") << "iphoneos" <<ios << "arm64"
<< "-triple arm64-apple-ios7.0"
- << "-iphoneos_version_min 7.0";
+ << "7.0";
QTest::newRow("ios-simulator x86") << "iphonesimulator" << ios_sim << "x86"
<< "-triple i386-apple-ios6.0"
- << "-ios_simulator_version_min 6.0";
+ << "6.0";
if (xcodeVersion >= qbs::Version(5))
QTest::newRow("ios-simulator x86_64") << "iphonesimulator" << ios_sim << "x86_64"
<< "-triple x86_64-apple-ios7.0"
- << "-ios_simulator_version_min 7.0";
+ << "7.0";
if (xcodeVersion >= qbs::Version(7)) {
if (xcodeVersion >= qbs::Version(7, 1)) {
QTest::newRow("tvos arm64") << "appletvos" << tvos << "arm64"
<< "-triple arm64-apple-tvos9.0"
- << "-tvos_version_min 9.0";
+ << "9.0";
QTest::newRow("tvos-simulator x86_64") << "appletvsimulator" << tvos_sim << "x86_64"
<< "-triple x86_64-apple-tvos9.0"
- << "-tvos_simulator_version_min 9.0";
+ << "9.0";
}
QTest::newRow("watchos armv7k") << "watchos" << watchos << "armv7k"
<< "-triple thumbv7k-apple-watchos2.0"
- << "-watchos_version_min 2.0";
+ << "2.0";
QTest::newRow("watchos-simulator x86") << "watchsimulator" << watchos_sim << "x86"
<< "-triple i386-apple-watchos2.0"
- << "-watchos_simulator_version_min 2.0";
+ << "2.0";
}
}
@@ -772,37 +834,35 @@ void TestBlackboxApple::infoPlist()
params.arguments = QStringList() << "-f" << "infoplist.qbs";
QCOMPARE(runQbs(params), 0);
- auto infoplistPath = relativeProductBuildDir("infoplist")
- + "/infoplist.app/Contents/Info.plist";
- if (!QFile::exists(infoplistPath))
- infoplistPath = relativeProductBuildDir("infoplist") + "/infoplist.app/Info.plist";
- QVERIFY(QFile::exists(infoplistPath));
- QProcess plutil;
- plutil.start("plutil", {
- QStringLiteral("-convert"),
- QStringLiteral("json"),
- infoplistPath
- });
- QVERIFY2(plutil.waitForStarted(), qPrintable(plutil.errorString()));
- QVERIFY2(plutil.waitForFinished(), qPrintable(plutil.errorString()));
- QVERIFY2(plutil.exitCode() == 0, qPrintable(plutil.readAllStandardError().constData()));
+ const auto infoPlistPath = getInfoPlistPath(
+ relativeProductBuildDir("infoplist") + "/infoplist.app");
+ QVERIFY(QFile::exists(infoPlistPath));
+ const auto content = readInfoPlistFile(infoPlistPath);
+ QVERIFY(!content.isEmpty());
- QFile infoplist(infoplistPath);
- QVERIFY(infoplist.open(QIODevice::ReadOnly));
- QJsonParseError error;
- const auto json = QJsonDocument::fromJson(infoplist.readAll(), &error);
- QCOMPARE(error.error, QJsonParseError::NoError);
- QVERIFY(json.isObject());
// common values
- QCOMPARE(json.object().value(QStringLiteral("CFBundleIdentifier")),
+ QCOMPARE(content.value(QStringLiteral("CFBundleIdentifier")),
QStringLiteral("org.example.infoplist"));
- QCOMPARE(json.object().value(QStringLiteral("CFBundleName")), QStringLiteral("infoplist"));
- QCOMPARE(json.object().value(QStringLiteral("CFBundleExecutable")),
+ QCOMPARE(content.value(QStringLiteral("CFBundleName")), QStringLiteral("infoplist"));
+ QCOMPARE(content.value(QStringLiteral("CFBundleExecutable")),
QStringLiteral("infoplist"));
- if (!json.object().contains(QStringLiteral("SDKROOT"))) { // macOS-specific values
- QCOMPARE(json.object().value("LSMinimumSystemVersion"), QStringLiteral("10.7"));
- QVERIFY(json.object().contains("NSPrincipalClass"));
+ if (!content.contains(QStringLiteral("SDKROOT"))) { // macOS-specific values
+ QCOMPARE(content.value("LSMinimumSystemVersion"), QStringLiteral("10.7"));
+ QCOMPARE(content.value("NSPrincipalClass"), QStringLiteral("NSApplication"));
+ } else {
+ // QBS-1447: UIDeviceFamily was set to a string instead of an array
+ const auto family = content.value(QStringLiteral("UIDeviceFamily"));
+ if (family.isValid()) {
+ // int gets converted to a double when exporting plist as JSON
+ QVERIFY(testVariantListType(family, QMetaType::Double));
+ }
+ const auto caps = content.value(QStringLiteral("UIRequiredDeviceCapabilities"));
+ if (caps.isValid())
+ QVERIFY(testVariantListType(caps, QMetaType::QString));
+ const auto orientations = content.value(QStringLiteral("UIRequiredDeviceCapabilities"));
+ if (orientations.isValid())
+ QVERIFY(testVariantListType(orientations, QMetaType::QString));
}
}
@@ -813,6 +873,31 @@ void TestBlackboxApple::objcArc()
QCOMPARE(runQbs(), 0);
}
+void TestBlackboxApple::overrideInfoPlist()
+{
+ QDir::setCurrent(testDataDir + "/overrideInfoPlist");
+
+ QCOMPARE(runQbs(), 0);
+
+ const auto infoPlistPath = getInfoPlistPath(
+ relativeProductBuildDir("overrideInfoPlist") + "/overrideInfoPlist.app");
+ QVERIFY(QFile::exists(infoPlistPath));
+ const auto content = readInfoPlistFile(infoPlistPath);
+ QVERIFY(!content.isEmpty());
+
+ // test we do not override custom values by default
+ QCOMPARE(content.value(QStringLiteral("DefaultValue")),
+ QStringLiteral("The default value"));
+ // test we can override custom values
+ QCOMPARE(content.value(QStringLiteral("OverriddenValue")),
+ QStringLiteral("The overridden value"));
+ // test we do not override special values set by Qbs by default
+ QCOMPARE(content.value(QStringLiteral("CFBundleExecutable")),
+ QStringLiteral("overrideInfoPlist"));
+ // test we can override special values set by Qbs
+ QCOMPARE(content.value(QStringLiteral("CFBundleName")), QStringLiteral("My Bundle"));
+}
+
void TestBlackboxApple::xcode()
{
QProcess xcodeSelect;
diff --git a/tests/auto/blackbox/tst_blackboxapple.h b/tests/auto/blackbox/tst_blackboxapple.h
index 76711ddf5..be2e5c5b5 100644
--- a/tests/auto/blackbox/tst_blackboxapple.h
+++ b/tests/auto/blackbox/tst_blackboxapple.h
@@ -63,6 +63,7 @@ private slots:
void iconsetApp();
void infoPlist();
void objcArc();
+ void overrideInfoPlist();
void xcode();
private:
diff --git a/tests/auto/blackbox/tst_blackboxbase.cpp b/tests/auto/blackbox/tst_blackboxbase.cpp
index 61b0271f6..90afaabfc 100644
--- a/tests/auto/blackbox/tst_blackboxbase.cpp
+++ b/tests/auto/blackbox/tst_blackboxbase.cpp
@@ -64,7 +64,7 @@ static bool supportsSettingsDirOption(const QString &command) {
TestBlackboxBase::TestBlackboxBase(const QString &testDataSrcDir, const QString &testName)
: testDataDir(testWorkDir(testName)),
- testSourceDir(QDir::cleanPath(testDataSrcDir)),
+ testSourceDir(testDataSourceDir(testDataSrcDir)),
qbsExecutableFilePath(initQbsExecutableFilePath()),
defaultInstallRoot(relativeBuildDir() + QLatin1Char('/') + InstallOptions::defaultInstallRoot())
{
@@ -232,3 +232,21 @@ QMap<QString, QString> TestBlackboxBase::findJdkTools(int *status)
{"jar", QDir::fromNativeSeparators(tools["jar"].toString())}
};
}
+
+qbs::Version TestBlackboxBase::qmakeVersion(const QString &qmakeFilePath)
+{
+ QStringList arguments;
+ arguments << "-query" << "QT_VERSION";
+ QProcess qmakeProcess;
+ qmakeProcess.start(qmakeFilePath, arguments);
+ if (!qmakeProcess.waitForStarted() || !qmakeProcess.waitForFinished()
+ || qmakeProcess.exitStatus() != QProcess::NormalExit) {
+ qDebug() << "qmake '" << qmakeFilePath << "' could not be run.";
+ return qbs::Version();
+ }
+ QByteArray result = qmakeProcess.readAll().simplified();
+ qbs::Version version = qbs::Version::fromString(result);
+ if (!version.isValid())
+ qDebug() << "qmake '" << qmakeFilePath << "' version is not valid.";
+ return version;
+}
diff --git a/tests/auto/blackbox/tst_blackboxbase.h b/tests/auto/blackbox/tst_blackboxbase.h
index 251f3752d..518cc80d0 100644
--- a/tests/auto/blackbox/tst_blackboxbase.h
+++ b/tests/auto/blackbox/tst_blackboxbase.h
@@ -42,14 +42,14 @@ public:
init();
}
- QbsRunParameters(const QString &cmd, const QStringList &args = QStringList())
- : command(cmd), arguments(args)
+ QbsRunParameters(QString cmd, QStringList args = QStringList())
+ : command(std::move(cmd)), arguments(std::move(args))
{
init();
}
- QbsRunParameters(const QStringList &args)
- : arguments(args)
+ QbsRunParameters(QStringList args)
+ : arguments(std::move(args))
{
init();
}
@@ -92,6 +92,7 @@ protected:
static void ccp(const QString &sourceDirPath, const QString &targetDirPath);
static QString findExecutable(const QStringList &fileNames);
QMap<QString, QString> findJdkTools(int *status);
+ static qbs::Version qmakeVersion(const QString &qmakeFilePath);
const QString testDataDir;
const QString testSourceDir;
diff --git a/tests/auto/blackbox/tst_blackboxjava.cpp b/tests/auto/blackbox/tst_blackboxjava.cpp
index f7feb0612..a815a84ff 100644
--- a/tests/auto/blackbox/tst_blackboxjava.cpp
+++ b/tests/auto/blackbox/tst_blackboxjava.cpp
@@ -119,7 +119,7 @@ void TestBlackboxJava::java()
if (process.waitForStarted()) {
QVERIFY2(process.waitForFinished(), qPrintable(process.errorString()));
const QByteArray stdOut = process.readAllStandardOutput();
- QVERIFY2(stdOut.contains("Class-Path: car_jar.jar random_stuff.jar"), stdOut.constData());
+ QVERIFY2(stdOut.contains("Class-Path: random_stuff.jar car_jar.jar"), stdOut.constData());
QVERIFY2(stdOut.contains("Main-Class: Vehicles"), stdOut.constData());
QVERIFY2(stdOut.contains("Some-Property: Some-Value"), stdOut.constData());
QVERIFY2(stdOut.contains("Additional-Property: Additional-Value"), stdOut.constData());
@@ -184,6 +184,7 @@ void TestBlackboxJava::javaDependencyTracking_data()
"/usr/lib/jvm/java-" + minorVersion + "-openjdk" + dpkgArch("-"), // Debian
"/usr/lib/jvm/java-" + minorVersion + "-openjdk", // Arch
"/usr/lib/jvm/jre-1." + minorVersion + ".0-openjdk", // Fedora
+ "/usr/lib64/jvm/java-1." + minorVersion + ".0-openjdk", // OpenSuSE
};
for (const QString &searchPath : searchPaths) {
if (QFile::exists(searchPath + "/bin/javac"))
diff --git a/tests/auto/blackbox/tst_blackboxqt.cpp b/tests/auto/blackbox/tst_blackboxqt.cpp
index 035af959c..595a173a2 100644
--- a/tests/auto/blackbox/tst_blackboxqt.cpp
+++ b/tests/auto/blackbox/tst_blackboxqt.cpp
@@ -121,7 +121,7 @@ void TestBlackboxQt::combinedMoc()
void TestBlackboxQt::createProject()
{
QDir::setCurrent(testDataDir + "/create-project");
- QVERIFY(QFile::copy(SRCDIR "/../../../examples/helloworld-qt/main.cpp",
+ QVERIFY(QFile::copy(testSourceDir + "/../../../../examples/helloworld-qt/main.cpp",
QDir::currentPath() + "/main.cpp"));
QbsRunParameters createParams("create-project");
createParams.profile.clear();
@@ -210,12 +210,48 @@ void TestBlackboxQt::lrelease()
QVERIFY(!regularFileExists(relativeProductBuildDir("lrelease-test") + "/hu.qm"));
}
+void TestBlackboxQt::metaTypes_data()
+{
+ QTest::addColumn<bool>("generate");
+ QTest::addColumn<QString>("installDir");
+ QTest::newRow("don't generate") << false << QString();
+ QTest::newRow("don't generate with install info") << false << QString("blubb");
+ QTest::newRow("generate only") << true << QString();
+ QTest::newRow("generate and install") << true << QString("blubb");
+}
+
+void TestBlackboxQt::metaTypes()
+{
+ QDir::setCurrent(testDataDir + "/metatypes");
+ QFETCH(bool, generate);
+ QFETCH(QString, installDir);
+ const QStringList args{"modules.Qt.core.generateMetaTypesFile:"
+ + QString(generate ? "true" : "false"),
+ "modules.Qt.core.metaTypesInstallDir:" + installDir,
+ "-v", "--force-probe-execution"};
+ QCOMPARE(runQbs(QbsRunParameters("resolve", args)), 0);
+ const bool canGenerate = m_qbsStdout.contains("can generate");
+ const bool cannotGenerate = m_qbsStdout.contains("cannot generate");
+ QVERIFY(canGenerate != cannotGenerate);
+ const bool expectFiles = generate && canGenerate;
+ const bool expectInstalledFiles = expectFiles && !installDir.isEmpty();
+ QCOMPARE(runQbs(QStringList("--clean-install-root")), 0);
+ const QString productDir = relativeProductBuildDir("mylib");
+ const QString outputDir = productDir + "/qt.headers";
+ QVERIFY(!regularFileExists(outputDir + "/moc_unmocableclass.cpp.json"));
+ QCOMPARE(regularFileExists(outputDir + "/moc_mocableclass1.cpp.json"), expectFiles);
+ QCOMPARE(regularFileExists(outputDir + "/mocableclass2.moc.json"), expectFiles);
+ QCOMPARE(regularFileExists(productDir + "/mylib_metatypes.json"), expectFiles);
+ QCOMPARE(regularFileExists(relativeBuildDir() + "/install-root/some-prefix/" + installDir
+ + "/mylib_metatypes.json"), expectInstalledFiles);
+}
+
void TestBlackboxQt::mixedBuildVariants()
{
QDir::setCurrent(testDataDir + "/mixed-build-variants");
const SettingsPtr s = settings();
Profile profile(profileName(), s.get());
- if (profile.value("qbs.toolchain").toStringList().contains("msvc")) {
+ if (profileToolchain(profile).contains("msvc")) {
QbsRunParameters params;
params.arguments << "qbs.buildVariant:debug";
params.expectFailure = true;
@@ -339,7 +375,7 @@ void TestBlackboxQt::qmlDebugging()
QCOMPARE(runQbs(), 0);
const SettingsPtr s = settings();
Profile profile(profileName(), s.get());
- if (!profile.value("qbs.toolchain").toStringList().contains("gcc"))
+ if (!profileToolchain(profile).contains("gcc"))
return;
QProcess nm;
nm.start("nm", QStringList(relativeExecutableFilePath("debuggable-app")));
@@ -360,6 +396,40 @@ void TestBlackboxQt::qobjectInObjectiveCpp()
QCOMPARE(runQbs(), 0);
}
+void TestBlackboxQt::qmlTypeRegistrar_data()
+{
+ QTest::addColumn<QString>("importName");
+ QTest::addColumn<QString>("installDir");
+ QTest::newRow("don't generate") << QString() << QString();
+ QTest::newRow("don't generate with install info") << QString() << QString("blubb");
+ QTest::newRow("generate only") << QString("People") << QString();
+ QTest::newRow("generate and install") << QString("People") << QString("blubb");
+}
+
+void TestBlackboxQt::qmlTypeRegistrar()
+{
+ QDir::setCurrent(testDataDir + "/qmltyperegistrar");
+ QFETCH(QString, importName);
+ QFETCH(QString, installDir);
+ rmDirR(relativeBuildDir());
+ const QStringList args{"modules.Qt.qml.importName:" + importName,
+ "modules.Qt.qml.typesInstallDir:" + installDir};
+ QCOMPARE(runQbs(QbsRunParameters("resolve", args)), 0);
+ const bool hasRegistrar = m_qbsStdout.contains("has registrar");
+ const bool doesNotHaveRegistrar = m_qbsStdout.contains("does not have registrar");
+ QVERIFY(hasRegistrar != doesNotHaveRegistrar);
+ if (doesNotHaveRegistrar)
+ QSKIP("Qt version too old");
+ QCOMPARE(runQbs(), 0);
+ const bool enabled = !importName.isEmpty();
+ QCOMPARE(m_qbsStdout.contains("running qmltyperegistrar"), enabled);
+ QCOMPARE(m_qbsStdout.contains("compiling myapp_qmltyperegistrations.cpp"), enabled);
+ const QString buildDir = relativeProductBuildDir("myapp");
+ QCOMPARE(regularFileExists(buildDir + "/myapp.qmltypes"), enabled);
+ QCOMPARE(regularFileExists(relativeBuildDir() + "/install-root/" + installDir
+ + "/myapp.qmltypes"), enabled && !installDir.isEmpty());
+}
+
void TestBlackboxQt::qtKeywords()
{
QDir::setCurrent(testDataDir + "/qt-keywords");
diff --git a/tests/auto/blackbox/tst_blackboxqt.h b/tests/auto/blackbox/tst_blackboxqt.h
index 180f9e0c0..4008b14ca 100644
--- a/tests/auto/blackbox/tst_blackboxqt.h
+++ b/tests/auto/blackbox/tst_blackboxqt.h
@@ -53,6 +53,8 @@ private slots:
void includedMocCpp();
void linkerVariant();
void lrelease();
+ void metaTypes_data();
+ void metaTypes();
void mixedBuildVariants();
void mocAndCppCombining();
void mocFlags();
@@ -63,6 +65,8 @@ private slots:
void pluginSupport();
void qmlDebugging();
void qobjectInObjectiveCpp();
+ void qmlTypeRegistrar_data();
+ void qmlTypeRegistrar();
void qtKeywords();
void quickCompiler();
void qtScxml();
diff --git a/tests/auto/blackbox/tst_clangdb.cpp b/tests/auto/blackbox/tst_clangdb.cpp
index 3a6dd2d92..65e562484 100644
--- a/tests/auto/blackbox/tst_clangdb.cpp
+++ b/tests/auto/blackbox/tst_clangdb.cpp
@@ -202,9 +202,9 @@ void TestClangDb::checkClangDetectsSourceCodeProblems()
// clang-check.exe does not understand MSVC command-line syntax
const SettingsPtr s = settings();
qbs::Profile profile(profileName(), s.get());
- if (profile.value("qbs.toolchain").toStringList().contains("msvc")) {
+ if (profileToolchain(profile).contains("msvc")) {
arguments << "-extra-arg-before=--driver-mode=cl";
- } else if (profile.value("qbs.toolchain").toStringList().contains("mingw")) {
+ } else if (profileToolchain(profile).contains("mingw")) {
arguments << "-extra-arg-before=--driver-mode=g++";
}
diff --git a/tests/auto/buildgraph/tst_buildgraph.cpp b/tests/auto/buildgraph/tst_buildgraph.cpp
index 95314ad20..20f2cc6a5 100644
--- a/tests/auto/buildgraph/tst_buildgraph.cpp
+++ b/tests/auto/buildgraph/tst_buildgraph.cpp
@@ -51,6 +51,8 @@
#include <QtTest/qtest.h>
+#include <memory>
+
using namespace qbs;
using namespace qbs::Internal;
@@ -58,7 +60,7 @@ const TopLevelProjectPtr project = TopLevelProject::create();
TestBuildGraph::TestBuildGraph(ILogSink *logSink) : m_logSink(logSink)
{
- project->buildData.reset(new ProjectBuildData);
+ project->buildData = std::make_unique<ProjectBuildData>();
}
void TestBuildGraph::initTestCase()
@@ -84,7 +86,7 @@ ResolvedProductConstPtr TestBuildGraph::productWithDirectCycle()
{
const ResolvedProductPtr product = ResolvedProduct::create();
product->project = project;
- product->buildData.reset(new ProductBuildData);
+ product->buildData = std::make_unique<ProductBuildData>();
const auto root = new Artifact;
root->product = product;
const auto child = new Artifact;
@@ -101,7 +103,7 @@ ResolvedProductConstPtr TestBuildGraph::productWithLessDirectCycle()
{
const ResolvedProductPtr product = ResolvedProduct::create();
product->project = project;
- product->buildData.reset(new ProductBuildData);
+ product->buildData = std::make_unique<ProductBuildData>();
const auto root = new Artifact;
const auto child = new Artifact;
const auto grandchild = new Artifact;
@@ -123,7 +125,7 @@ ResolvedProductConstPtr TestBuildGraph::productWithNoCycle()
{
const ResolvedProductPtr product = ResolvedProduct::create();
product->project = project;
- product->buildData.reset(new ProductBuildData);
+ product->buildData = std::make_unique<ProductBuildData>();
const auto root = new Artifact;
const auto root2 = new Artifact;
root->product = product;
diff --git a/tests/auto/language/testdata/erroneous/ambiguous-multiplex-dependency.qbs b/tests/auto/language/testdata/erroneous/ambiguous-multiplex-dependency.qbs
new file mode 100644
index 000000000..6f60b1faf
--- /dev/null
+++ b/tests/auto/language/testdata/erroneous/ambiguous-multiplex-dependency.qbs
@@ -0,0 +1,14 @@
+Project {
+ Product {
+ name: "a"
+ multiplexByQbsProperties: ["architectures", "buildVariants"]
+ qbs.architectures: ["x86", "arm"]
+ qbs.buildVariants: ["debug", "release"]
+ }
+ Product {
+ name: "b"
+ Depends { name: "a" }
+ multiplexByQbsProperties: ["architectures"]
+ qbs.architectures: ["x86", "arm"]
+ }
+}
diff --git a/tests/auto/language/testdata/erroneous/dependency-profile-mismatch-2.qbs b/tests/auto/language/testdata/erroneous/dependency-profile-mismatch-2.qbs
new file mode 100644
index 000000000..d76907a35
--- /dev/null
+++ b/tests/auto/language/testdata/erroneous/dependency-profile-mismatch-2.qbs
@@ -0,0 +1,17 @@
+Project {
+ Profile {
+ name: "profile1"
+ }
+ Profile {
+ name: "profile2"
+ }
+
+ Product {
+ name: "dep"
+ qbs.profiles: ["profile1", "profile2"]
+ }
+ Product {
+ name: "main"
+ Depends { name: "dep"; profiles: ["profile47"]; }
+ }
+}
diff --git a/tests/auto/language/testdata/erroneous/dependency-profile-mismatch.qbs b/tests/auto/language/testdata/erroneous/dependency-profile-mismatch.qbs
new file mode 100644
index 000000000..e014fa9b1
--- /dev/null
+++ b/tests/auto/language/testdata/erroneous/dependency-profile-mismatch.qbs
@@ -0,0 +1,14 @@
+Project {
+ Profile {
+ name: "profile1"
+ }
+
+ Product {
+ name: "dep"
+ qbs.profiles: ["profile1"]
+ }
+ Product {
+ name: "main"
+ Depends { name: "dep"; profiles: ["profile47"]; }
+ }
+}
diff --git a/tests/auto/language/tst_language.cpp b/tests/auto/language/tst_language.cpp
index 31aebfa3a..25e549d18 100644
--- a/tests/auto/language/tst_language.cpp
+++ b/tests/auto/language/tst_language.cpp
@@ -79,8 +79,7 @@ using namespace qbs;
using namespace qbs::Internal;
static QString testDataDir() {
- return FileInfo::resolvePath(QStringLiteral(SRCDIR),
- QStringLiteral("../../../tests/auto/language/testdata"));
+ return testDataSourceDir(SRCDIR "/testdata");
}
static QString testProject(const char *fileName) {
return testDataDir() + QLatin1Char('/') + QLatin1String(fileName);
@@ -180,7 +179,7 @@ void TestLanguage::initTestCase()
m_engine = ScriptEngine::create(m_logger, EvalContext::PropertyEvaluation, this);
loader = new Loader(m_engine, m_logger);
loader->setSearchPaths(QStringList()
- << QStringLiteral(SRCDIR "/../../../share/qbs"));
+ << (testDataDir() + "/../../../../share/qbs"));
defaultParameters.setTopLevelProfile(profileName());
defaultParameters.setConfigurationName("default");
defaultParameters.expandBuildConfiguration();
@@ -925,9 +924,20 @@ void TestLanguage::erroneousFiles_data()
<< "original-in-export-item3.qbs:6:9.*Item 'x.y' is not declared. Did you forget "
"to add a Depends item";
QTest::newRow("mismatching-multiplex-dependency")
- << "mismatching-multiplex-dependency.qbs:7:5.*Dependency from product "
- "'b \\{\"architecture\":\"mips\"\\}' to product 'a \\{\"architecture\":\"mips\"\\}'"
- " not fulfilled.";
+ << "mismatching-multiplex-dependency.qbs:9:9.*Dependency from product "
+ "'b \\{\"architecture\":\"mips\"\\}' to product 'a'"
+ " not fulfilled. There are no eligible multiplex candidates.";
+ QTest::newRow("ambiguous-multiplex-dependency")
+ << "ambiguous-multiplex-dependency.qbs:10:9.*Dependency from product 'b "
+ "\\{\"architecture\":\"x86\"\\}' to product 'a' is ambiguous. Eligible multiplex "
+ "candidates: a \\{\"architecture\":\"x86\",\"buildVariant\":\"debug\"\\}, "
+ "a \\{\"architecture\":\"x86\",\"buildVariant\":\"release\"\\}.";
+ QTest::newRow("dependency-profile-mismatch")
+ << "dependency-profile-mismatch.qbs:10:5.*Product 'main' depends on 'dep', "
+ "which does not exist for the requested profile 'profile47'.";
+ QTest::newRow("dependency-profile-mismatch-2")
+ << "dependency-profile-mismatch-2.qbs:15:9 Dependency from product 'main' to "
+ "product 'dep' not fulfilled. There are no eligible multiplex candidates.";
QTest::newRow("duplicate-multiplex-value")
<< "duplicate-multiplex-value.qbs:3:1.*Duplicate entry 'x86' in qbs.architectures.";
QTest::newRow("duplicate-multiplex-value2")
@@ -1051,7 +1061,7 @@ void TestLanguage::exports()
propertyName = QStringList() << "dummy" << "defines";
propertyValue = product->moduleProperties->property(propertyName);
QCOMPARE(propertyValue.toStringList(),
- QStringList() << "LIBA" << "LIBB" << "LIBC" << "LIBD");
+ QStringList() << "LIBD" << "LIBC" << "LIBA" << "LIBB");
propertyName = QStringList() << "dummy" << "productName";
propertyValue = product->moduleProperties->property(propertyName);
QCOMPARE(propertyValue.toString(), QString("libE"));
@@ -1730,10 +1740,10 @@ void TestLanguage::moduleProperties_data()
QTest::newRow("init") << QString() << QVariant();
QTest::newRow("merge_lists")
<< "defines"
- << QVariant(QStringList() << "THE_PRODUCT" << "QT_CORE" << "QT_GUI" << "QT_NETWORK");
+ << QVariant(QStringList() << "THE_PRODUCT" << "QT_NETWORK" << "QT_GUI" << "QT_CORE");
QTest::newRow("merge_lists_and_values")
<< "defines"
- << QVariant(QStringList() << "THE_PRODUCT" << "QT_CORE" << "QT_GUI" << "QT_NETWORK");
+ << QVariant(QStringList() << "THE_PRODUCT" << "QT_NETWORK" << "QT_GUI" << "QT_CORE");
QTest::newRow("merge_lists_with_duplicates")
<< "cxxFlags"
<< QVariant(QStringList() << "-foo" << "BAR" << "-foo" << "BAZ");
@@ -2469,7 +2479,7 @@ void TestLanguage::projectFileLookup_data()
QTest::addColumn<QString>("projectFileOutput");
QTest::addColumn<bool>("failureExpected");
- const QString baseDir = QLatin1String(SRCDIR) + "/testdata";
+ const QString baseDir = testDataDir();
const QString multiProjectsDir = baseDir + "/dirwithmultipleprojects";
const QString noProjectsDir = baseDir + "/dirwithnoprojects";
const QString oneProjectDir = baseDir + "/dirwithoneproject";
@@ -3182,6 +3192,7 @@ void TestLanguage::wildcards()
QFile projectFile(projectFilePath);
QVERIFY(projectFile.open(QIODevice::WriteOnly));
QTextStream s(&projectFile);
+ using Qt::endl;
s << "import qbs.base 1.0" << endl << endl
<< "Application {" << endl
<< " name: \"MyProduct\"" << endl;
diff --git a/tests/auto/shared.h b/tests/auto/shared.h
index 8f85f5d6c..beda8fff3 100644
--- a/tests/auto/shared.h
+++ b/tests/auto/shared.h
@@ -31,6 +31,7 @@
#include <tools/hostosinfo.h>
#include <tools/profile.h>
#include <tools/settings.h>
+#include <tools/toolchains.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qcryptographichash.h>
@@ -46,6 +47,8 @@
#include <memory>
+
+
#define REPLACE_IN_FILE(filePath, oldContent, newContent) \
do { \
QFile f((filePath)); \
@@ -83,7 +86,7 @@ using SettingsPtr = std::unique_ptr<qbs::Settings>;
inline SettingsPtr settings()
{
const QString settingsDir = QLatin1String(qgetenv("QBS_AUTOTEST_SETTINGS_DIR"));
- return SettingsPtr(new qbs::Settings(settingsDir));
+ return std::make_unique<qbs::Settings>(settingsDir);
}
inline QString profileName()
@@ -268,14 +271,22 @@ inline void copyFileAndUpdateTimestamp(const QString &source, const QString &tar
touch(target);
}
+inline QStringList profileToolchain(const qbs::Profile &profile)
+{
+ const auto toolchainType = profile.value(QStringLiteral("qbs.toolchainType")).toString();
+ if (!toolchainType.isEmpty())
+ return qbs::canonicalToolchain(toolchainType);
+ return profile.value(QStringLiteral("qbs.toolchain")).toStringList();
+}
+
inline QString objectFileName(const QString &baseName, const QString &profileName)
{
const SettingsPtr s = settings();
qbs::Profile profile(profileName, s.get());
- const auto tc = profile.value("qbs.toolchainType").toString();
- const auto tcList = profile.value("qbs.toolchain").toStringList();
- const bool isMsvc = tc == "msvc" || tcList.contains("msvc")
- || (tc.isEmpty() && tcList.isEmpty() && qbs::Internal::HostOsInfo::isWindowsHost());
+
+ const auto tcList = profileToolchain(profile);
+ const bool isMsvc = tcList.contains("msvc")
+ || (tcList.isEmpty() && qbs::Internal::HostOsInfo::isWindowsHost());
const QString suffix = isMsvc ? "obj" : "o";
return baseName + '.' + suffix;
}
@@ -285,6 +296,30 @@ inline QString inputDirHash(const QString &dir)
return QCryptographicHash::hash(dir.toLatin1(), QCryptographicHash::Sha1).toHex().left(16);
}
+inline QString testDataSourceDir(const QString &dir)
+{
+ QDir result;
+ QString testSourceRootDirFromEnv = QDir::fromNativeSeparators(qEnvironmentVariable("QBS_TEST_SOURCE_ROOT"));
+ if (testSourceRootDirFromEnv.isEmpty()) {
+ result.setPath(dir);
+ } else {
+ QDir testSourceRootDir(dir);
+ while (testSourceRootDir.dirName() != "tests")
+ testSourceRootDir = QFileInfo(testSourceRootDir, "").dir();
+
+ QString relativeDataPath = testSourceRootDir.relativeFilePath(dir);
+ QString absoluteDataPath = QDir(testSourceRootDirFromEnv).absoluteFilePath(relativeDataPath);
+ result.setPath(absoluteDataPath);
+ }
+
+ if (!result.exists())
+ qFatal("Expected data folder '%s' to be present, but it does not exist. You may set "
+ "QBS_TEST_SOURCE_ROOT to the 'tests' folder in your qbs repository to configure "
+ "a custom location.", qPrintable(result.absolutePath()));
+
+ return result.absolutePath();
+}
+
inline QString testWorkDir(const QString &testName)
{
QString dir = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv("QBS_TEST_WORK_ROOT")));
diff --git a/tests/benchmarker/benchmarker.cpp b/tests/benchmarker/benchmarker.cpp
index 5ecdbf08b..2cc442a72 100644
--- a/tests/benchmarker/benchmarker.cpp
+++ b/tests/benchmarker/benchmarker.cpp
@@ -34,16 +34,17 @@
#include <QtConcurrent/qtconcurrentrun.h>
#include <iostream>
+#include <utility>
namespace qbsBenchmarker {
-Benchmarker::Benchmarker(Activities activities, const QString &oldCommit, const QString &newCommit,
- const QString &testProject, const QString &qbsRepo)
+Benchmarker::Benchmarker(Activities activities, QString oldCommit, QString newCommit,
+ QString testProject, QString qbsRepo)
: m_activities(activities)
- , m_oldCommit(oldCommit)
- , m_newCommit(newCommit)
- , m_testProject(testProject)
- , m_qbsRepo(qbsRepo)
+ , m_oldCommit(std::move(oldCommit))
+ , m_newCommit(std::move(newCommit))
+ , m_testProject(std::move(testProject))
+ , m_qbsRepo(std::move(qbsRepo))
{
}
diff --git a/tests/benchmarker/benchmarker.h b/tests/benchmarker/benchmarker.h
index 9b6d5a157..6313e8094 100644
--- a/tests/benchmarker/benchmarker.h
+++ b/tests/benchmarker/benchmarker.h
@@ -53,8 +53,8 @@ using BenchmarkResults = QHash<Activity, BenchmarkResult>;
class Benchmarker
{
public:
- Benchmarker(Activities activities, const QString &oldCommit, const QString &newCommit,
- const QString &testProject, const QString &qbsRepo);
+ Benchmarker(Activities activities, QString oldCommit, QString newCommit,
+ QString testProject, QString qbsRepo);
~Benchmarker();
void benchmark();
diff --git a/tests/benchmarker/commandlineparser.cpp b/tests/benchmarker/commandlineparser.cpp
index 4e5052453..9b08bd60d 100644
--- a/tests/benchmarker/commandlineparser.cpp
+++ b/tests/benchmarker/commandlineparser.cpp
@@ -41,9 +41,7 @@ static QString ruleExecutionActivity() { return "rule-execution"; }
static QString nullBuildActivity() { return "null-build"; }
static QString allActivities() { return "all"; }
-CommandLineParser::CommandLineParser()
-{
-}
+CommandLineParser::CommandLineParser() = default;
void CommandLineParser::parse()
{
@@ -84,6 +82,10 @@ void CommandLineParser::parse()
}
m_oldCommit = parser.value(oldCommitOption);
m_newCommit = parser.value(newCommitOption);
+ if (m_oldCommit == m_newCommit) {
+ throw Exception(QStringLiteral("Error parsing command line: "
+ "'new commit' and 'old commit' must be different commits.\n%1").arg(parser.helpText()));
+ }
m_testProjectFilePath = parser.value(testProjectOption);
m_qbsRepoDirPath = parser.value(qbsRepoOption);
const QStringList activitiesList = parser.value(activitiesOption).split(',');
diff --git a/tests/benchmarker/exception.h b/tests/benchmarker/exception.h
index b4df36974..9fab479ea 100644
--- a/tests/benchmarker/exception.h
+++ b/tests/benchmarker/exception.h
@@ -35,8 +35,8 @@ namespace qbsBenchmarker {
class Exception : public QException {
public:
- explicit Exception(const QString &description) : m_description(description) {}
- ~Exception() throw() override { }
+ explicit Exception(QString description) : m_description(std::move(description)) {}
+ ~Exception() throw() override = default;
QString description() const { return m_description; }
diff --git a/tests/benchmarker/valgrindrunner.cpp b/tests/benchmarker/valgrindrunner.cpp
index 344a23516..174781318 100644
--- a/tests/benchmarker/valgrindrunner.cpp
+++ b/tests/benchmarker/valgrindrunner.cpp
@@ -44,10 +44,10 @@
namespace qbsBenchmarker {
-ValgrindRunner::ValgrindRunner(Activities activities, const QString &testProject,
+ValgrindRunner::ValgrindRunner(Activities activities, QString testProject,
const QString &qbsBuildDir, const QString &baseOutputDir)
: m_activities(activities)
- , m_testProject(testProject)
+ , m_testProject(std::move(testProject))
, m_qbsBinary(qbsBuildDir + "/bin/qbs")
, m_baseOutputDir(baseOutputDir)
{
diff --git a/tests/benchmarker/valgrindrunner.h b/tests/benchmarker/valgrindrunner.h
index 3ec82a6a2..378723868 100644
--- a/tests/benchmarker/valgrindrunner.h
+++ b/tests/benchmarker/valgrindrunner.h
@@ -55,7 +55,7 @@ public:
class ValgrindRunner
{
public:
- ValgrindRunner(Activities activities, const QString &testProject, const QString &qbsBuildDir,
+ ValgrindRunner(Activities activities, QString testProject, const QString &qbsBuildDir,
const QString &baseOutputDir);
void run();
diff --git a/tests/fuzzy-test/commandlineparser.cpp b/tests/fuzzy-test/commandlineparser.cpp
index 18515604b..23be7b0ad 100644
--- a/tests/fuzzy-test/commandlineparser.cpp
+++ b/tests/fuzzy-test/commandlineparser.cpp
@@ -37,9 +37,7 @@ static QString maxDurationoption() { return "--max-duration"; }
static QString jobCountOption() { return "--jobs"; }
static QString logOption() { return "--log"; }
-CommandLineParser::CommandLineParser()
-{
-}
+CommandLineParser::CommandLineParser() = default;
void CommandLineParser::parse(const QStringList &commandLine)
{
diff --git a/tests/fuzzy-test/commandlineparser.h b/tests/fuzzy-test/commandlineparser.h
index a000a515d..76b49331b 100644
--- a/tests/fuzzy-test/commandlineparser.h
+++ b/tests/fuzzy-test/commandlineparser.h
@@ -35,8 +35,8 @@
class ParseException : public std::exception
{
public:
- ParseException(const QString &error) : errorMessage(error) { }
- ~ParseException() throw() override {}
+ ParseException(QString error) : errorMessage(std::move(error)) { }
+ ~ParseException() throw() override = default;
QString errorMessage;
diff --git a/tests/fuzzy-test/fuzzytester.cpp b/tests/fuzzy-test/fuzzytester.cpp
index b836ee623..045e46718 100644
--- a/tests/fuzzy-test/fuzzytester.cpp
+++ b/tests/fuzzy-test/fuzzytester.cpp
@@ -36,6 +36,7 @@
#include <algorithm>
#include <cstdlib>
#include <ctime>
+#include <random>
static QString resolveIncrementalActivity() { return "resolve-incremental"; }
static QString buildIncrementalActivity() { return "build-incremental"; }
@@ -71,7 +72,7 @@ void FuzzyTester::runTest(const QString &profile, const QString &startCommit,
// Shuffle the initial sequence. Otherwise all invocations of the tool with the same start
// commit would try the same sequence of commits.
std::srand(std::time(nullptr));
- std::random_shuffle(allCommits.begin(), allCommits.end());
+ std::shuffle(allCommits.begin(), allCommits.end(), std::mt19937(std::random_device()()));
quint64 run = 0;
QStringList buildSequence(workingStartCommit);
diff --git a/tests/fuzzy-test/fuzzytester.h b/tests/fuzzy-test/fuzzytester.h
index 2d75bb1af..2d0279e1a 100644
--- a/tests/fuzzy-test/fuzzytester.h
+++ b/tests/fuzzy-test/fuzzytester.h
@@ -35,8 +35,8 @@
class TestError {
public:
- TestError(const QString &errorMessage) : errorMessage(errorMessage) {}
- ~TestError() throw() {}
+ TestError(QString errorMessage) : errorMessage(std::move(errorMessage)) {}
+ ~TestError() throw() = default;
QString errorMessage;