aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--README18
-rw-r--r--VERSION1
-rw-r--r--changelogs/changes-1.6.016
-rw-r--r--changelogs/changes-1.6.16
-rw-r--r--changelogs/changes-1.7.023
-rw-r--r--changelogs/changes-1.7.15
-rw-r--r--changelogs/changes-1.7.25
-rw-r--r--changelogs/changes-1.8.033
-rw-r--r--dist/dist.qbs4
-rw-r--r--doc/doc.qbs7
-rw-r--r--doc/howtos.qdoc154
-rw-r--r--doc/qbs.qdoc89
-rw-r--r--doc/reference/commands.qdoc7
-rw-r--r--doc/reference/items/convenience/androidapk.qdoc2
-rw-r--r--doc/reference/items/convenience/appleapplicationdiskimage.qdoc106
-rw-r--r--doc/reference/items/convenience/applediskimage.qdoc43
-rw-r--r--doc/reference/items/convenience/application.qdoc2
-rw-r--r--doc/reference/items/language/depends.qdoc26
-rw-r--r--doc/reference/items/language/module.qdoc37
-rw-r--r--doc/reference/items/language/parameter.qdoc53
-rw-r--r--doc/reference/items/language/parameters.qdoc67
-rw-r--r--doc/reference/items/language/probe.qdoc2
-rw-r--r--doc/reference/items/language/product.qdoc45
-rw-r--r--doc/reference/items/language/rule.qdoc13
-rw-r--r--doc/reference/modules/android-ndk-module.qdoc2
-rw-r--r--doc/reference/modules/cpp-module.qdoc52
-rw-r--r--doc/reference/modules/dmg-module.qdoc342
-rw-r--r--doc/reference/modules/qbs-module.qdoc37
-rw-r--r--doc/reference/reference.qdoc2
-rw-r--r--docker/windowsservercore/Dockerfile27
-rw-r--r--docker/windowsservercore/qtifwsilent.qs47
-rw-r--r--examples/cocoa-application/CocoaApplication.qbs43
-rw-r--r--examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/Contents.json68
-rw-r--r--examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_128x128.pngbin0 -> 5256 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_128x128@2x.pngbin0 -> 11304 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_16x16.pngbin0 -> 487 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_16x16@2x.pngbin0 -> 1374 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_256x256.pngbin0 -> 11304 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_256x256@2x.pngbin0 -> 26984 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_32x32.pngbin0 -> 1374 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_32x32@2x.pngbin0 -> 2423 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_512x512.pngbin0 -> 26984 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_512x512@2x.pngbin0 -> 63576 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/background.pngbin0 -> 86627 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/background@2x.pngbin0 -> 217596 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/dmg.iconset/icon_128x128.pngbin0 -> 5256 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/dmg.iconset/icon_128x128@2x.pngbin0 -> 11304 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/dmg.iconset/icon_16x16.pngbin0 -> 487 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/dmg.iconset/icon_16x16@2x.pngbin0 -> 1374 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/dmg.iconset/icon_256x256.pngbin0 -> 11304 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/dmg.iconset/icon_256x256@2x.pngbin0 -> 26984 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/dmg.iconset/icon_32x32.pngbin0 -> 1374 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/dmg.iconset/icon_32x32@2x.pngbin0 -> 2423 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/dmg.iconset/icon_512x512.pngbin0 -> 26984 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/dmg.iconset/icon_512x512@2x.pngbin0 -> 63576 bytes
-rw-r--r--examples/cocoa-application/CocoaApplication/en.lproj/LICENSE27
l---------examples/cocoa-application/CocoaApplication/en_US.lproj1
-rw-r--r--examples/cocoa-application/app.qbs83
-rw-r--r--examples/cocoa-application/dmg.qbs72
-rw-r--r--qbs-resources/imports/QbsAutotest.qbs5
-rw-r--r--qbs-resources/imports/QbsFunctions/functions.js18
-rw-r--r--qbs-resources/imports/QbsLibrary.qbs3
-rw-r--r--qbs-resources/imports/QbsProduct.qbs5
-rw-r--r--qbs-resources/modules/qbsversion/qbsversion.qbs24
-rw-r--r--qbs.pro1
-rw-r--r--qbs.qbs5
-rw-r--r--qbs_version.pri2
-rw-r--r--scripts/make-release-archive.sh (renamed from make-release-archive.sh)0
-rw-r--r--scripts/make-release-archives.bat75
-rw-r--r--share/qbs/imports/qbs/ModUtils/utils.js20
-rw-r--r--share/qbs/imports/qbs/PathTools/path-tools.js69
-rw-r--r--share/qbs/imports/qbs/Probes/AndroidNdkProbe.qbs38
-rw-r--r--share/qbs/imports/qbs/Probes/GccProbe.qbs20
-rw-r--r--share/qbs/imports/qbs/Probes/GccVersionProbe.qbs68
-rw-r--r--share/qbs/imports/qbs/Probes/NpmProbe.qbs24
-rw-r--r--share/qbs/imports/qbs/Probes/PathProbe.qbs3
-rw-r--r--share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs9
-rw-r--r--share/qbs/imports/qbs/Probes/XcodeProbe.qbs103
-rw-r--r--share/qbs/imports/qbs/base/AppleApplicationDiskImage.qbs110
-rw-r--r--share/qbs/imports/qbs/base/AppleDiskImage.qbs34
-rw-r--r--share/qbs/imports/qbs/base/Application.qbs13
-rw-r--r--share/qbs/imports/qbs/base/AutotestRunner.qbs2
-rw-r--r--share/qbs/imports/qbs/base/Library.qbs13
-rw-r--r--share/qbs/imports/qbs/base/LoadableModule.qbs5
-rw-r--r--share/qbs/imports/qbs/base/NativeBinary.qbs56
-rw-r--r--share/qbs/modules/Android/ndk/ndk.qbs10
-rw-r--r--share/qbs/modules/Android/sdk/sdk.qbs1
-rw-r--r--share/qbs/modules/archiver/archiver.qbs4
-rw-r--r--share/qbs/modules/bundle/BundleModule.qbs19
-rw-r--r--share/qbs/modules/bundle/MacOSX-Product-Types.xcspec3
-rw-r--r--share/qbs/modules/bundle/bundle.js20
-rw-r--r--share/qbs/modules/cpp/CppModule.qbs14
-rw-r--r--share/qbs/modules/cpp/DarwinGCC.qbs90
-rw-r--r--share/qbs/modules/cpp/GenericGCC.qbs99
-rw-r--r--share/qbs/modules/cpp/UnixGCC.qbs1
-rw-r--r--share/qbs/modules/cpp/android-gcc.qbs29
-rw-r--r--share/qbs/modules/cpp/darwin.js186
-rw-r--r--share/qbs/modules/cpp/gcc.js350
-rw-r--r--share/qbs/modules/cpp/ios-gcc.qbs5
-rw-r--r--share/qbs/modules/cpp/macos-gcc.qbs5
-rw-r--r--share/qbs/modules/cpp/msvc.js108
-rw-r--r--share/qbs/modules/cpp/windows-mingw.qbs51
-rw-r--r--share/qbs/modules/cpp/windows-msvc.qbs21
-rw-r--r--share/qbs/modules/dmg/DMGModule.qbs156
-rw-r--r--share/qbs/modules/dmg/dmg.js212
-rw-r--r--share/qbs/modules/ib/IBModule.qbs21
-rw-r--r--share/qbs/modules/ib/ib.js65
-rw-r--r--share/qbs/modules/java/JavaModule.qbs8
-rw-r--r--share/qbs/modules/java/io/qt/qbs/Artifact.java5
-rw-r--r--share/qbs/modules/java/io/qt/qbs/ArtifactListTextWriter.java60
-rw-r--r--share/qbs/modules/java/io/qt/qbs/ArtifactListWriter.java3
-rw-r--r--share/qbs/modules/java/io/qt/qbs/ArtifactListXmlWriter.java98
-rw-r--r--share/qbs/modules/java/io/qt/qbs/tools/JavaCompilerScannerTool.java19
-rw-r--r--share/qbs/modules/java/io/qt/qbs/tools/utils/ArtifactProcessor.java74
-rw-r--r--share/qbs/modules/java/io/qt/qbs/tools/utils/ArtifactScanner.java126
-rw-r--r--share/qbs/modules/java/io/qt/qbs/tools/utils/JavaCompilerOptions.java64
-rw-r--r--share/qbs/modules/java/io/qt/qbs/tools/utils/JavaCompilerScanner.java125
-rw-r--r--share/qbs/modules/java/utils.js8
-rw-r--r--share/qbs/modules/nodejs/NodeJS.qbs1
-rw-r--r--share/qbs/modules/nodejs/nodejs.js7
-rw-r--r--share/qbs/modules/qbs/common.qbs35
-rw-r--r--share/qbs/modules/xcode/xcode.js94
-rw-r--r--share/qbs/modules/xcode/xcode.qbs35
-rw-r--r--share/share.qbs27
-rw-r--r--src/3rdparty/python/.gitignore3
-rwxr-xr-xsrc/3rdparty/python/bin/dmgbuild36
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/biplist/LICENSE25
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/biplist/__init__.py870
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/biplist/qt_attribution.json13
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/LICENSE19
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/__init__.py3
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/badge.py143
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/colors.py494
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/core.py592
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/licensing.py461
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/qt_attribution.json13
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/resources.py355
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/ds_store/LICENSE19
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/ds_store/__init__.py3
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/ds_store/buddy.py473
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/ds_store/qt_attribution.json13
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/ds_store/store.py1231
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/mac_alias/LICENSE19
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/mac_alias/__init__.py27
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/mac_alias/alias.py587
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/mac_alias/bookmark.py650
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/mac_alias/osx.py823
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/mac_alias/qt_attribution.json13
-rw-r--r--src/3rdparty/python/lib/python2.7/site-packages/mac_alias/utils.py18
-rwxr-xr-xsrc/3rdparty/python/update.sh3
-rw-r--r--src/app/app.pri1
-rw-r--r--src/app/qbs-setup-android/android-setup.cpp82
-rw-r--r--src/app/qbs-setup-qt/setupqt.cpp14
-rw-r--r--src/app/qbs-setup-toolchains/xcodeprobe.cpp19
-rw-r--r--src/app/qbs/commandlinefrontend.cpp18
-rw-r--r--src/app/qbs/parser/commandlineparser.cpp142
-rw-r--r--src/app/qbs/qbs.qbs3
-rw-r--r--src/lib/corelib/api/internaljobs.cpp10
-rw-r--r--src/lib/corelib/api/jobs.cpp2
-rw-r--r--src/lib/corelib/api/project.cpp83
-rw-r--r--src/lib/corelib/api/project.h16
-rw-r--r--src/lib/corelib/api/projectdata.cpp18
-rw-r--r--src/lib/corelib/api/projectdata.h2
-rw-r--r--src/lib/corelib/api/projectdata_p.h2
-rw-r--r--src/lib/corelib/api/runenvironment.cpp13
-rw-r--r--src/lib/corelib/buildgraph/artifact.cpp8
-rw-r--r--src/lib/corelib/buildgraph/artifact.h2
-rw-r--r--src/lib/corelib/buildgraph/buildgraph.cpp72
-rw-r--r--src/lib/corelib/buildgraph/buildgraph.h3
-rw-r--r--src/lib/corelib/buildgraph/buildgraph.pri5
-rw-r--r--src/lib/corelib/buildgraph/buildgraphloader.cpp175
-rw-r--r--src/lib/corelib/buildgraph/buildgraphloader.h14
-rw-r--r--src/lib/corelib/buildgraph/cycledetector.h2
-rw-r--r--src/lib/corelib/buildgraph/depscanner.cpp8
-rw-r--r--src/lib/corelib/buildgraph/depscanner.h2
-rw-r--r--src/lib/corelib/buildgraph/executor.cpp20
-rw-r--r--src/lib/corelib/buildgraph/executorjob.cpp2
-rw-r--r--src/lib/corelib/buildgraph/forward_decls.h14
-rw-r--r--src/lib/corelib/buildgraph/inputartifactscanner.cpp12
-rw-r--r--src/lib/corelib/buildgraph/inputartifactscanner.h2
-rw-r--r--src/lib/corelib/buildgraph/processcommandexecutor.cpp9
-rw-r--r--src/lib/corelib/buildgraph/productbuilddata.h2
-rw-r--r--src/lib/corelib/buildgraph/productinstaller.cpp6
-rw-r--r--src/lib/corelib/buildgraph/projectbuilddata.cpp22
-rw-r--r--src/lib/corelib/buildgraph/projectbuilddata.h2
-rw-r--r--src/lib/corelib/buildgraph/qtmocscanner.cpp1
-rw-r--r--src/lib/corelib/buildgraph/rescuableartifactdata.h2
-rw-r--r--src/lib/corelib/buildgraph/rulecommands.cpp16
-rw-r--r--src/lib/corelib/buildgraph/rulecommands.h2
-rw-r--r--src/lib/corelib/buildgraph/rulegraph.cpp6
-rw-r--r--src/lib/corelib/buildgraph/rulenode.cpp8
-rw-r--r--src/lib/corelib/buildgraph/rulesapplicator.cpp19
-rw-r--r--src/lib/corelib/buildgraph/transformer.cpp2
-rw-r--r--src/lib/corelib/buildgraph/tst_buildgraph.cpp140
-rw-r--r--src/lib/corelib/corelib.pro1
-rw-r--r--src/lib/corelib/corelib.qbs27
-rw-r--r--src/lib/corelib/generators/clangcompilationdb/clangcompilationdb.pri5
-rw-r--r--src/lib/corelib/generators/clangcompilationdb/clangcompilationdb.qbs19
-rw-r--r--src/lib/corelib/generators/generatableprojectiterator.h2
-rw-r--r--src/lib/corelib/generators/generator.cpp11
-rw-r--r--src/lib/corelib/generators/generator.h15
-rw-r--r--src/lib/corelib/generators/generatordata.h6
-rw-r--r--src/lib/corelib/generators/generators.pri3
-rw-r--r--src/lib/corelib/generators/generators.qbs8
-rw-r--r--src/lib/corelib/jsextensions/environmentextension.cpp1
-rw-r--r--src/lib/corelib/jsextensions/fileinfoextension.cpp8
-rw-r--r--src/lib/corelib/jsextensions/moduleproperties.cpp6
-rw-r--r--src/lib/corelib/jsextensions/utilitiesextension.cpp18
-rw-r--r--src/lib/corelib/language/astpropertiesitemhandler.cpp8
-rw-r--r--src/lib/corelib/language/builtindeclarations.cpp38
-rw-r--r--src/lib/corelib/language/builtindeclarations.h2
-rw-r--r--src/lib/corelib/language/evaluator.cpp47
-rw-r--r--src/lib/corelib/language/evaluator.h17
-rwxr-xr-x[-rw-r--r--]src/lib/corelib/language/evaluatorscriptclass.cpp118
-rwxr-xr-x[-rw-r--r--]src/lib/corelib/language/evaluatorscriptclass.h11
-rw-r--r--src/lib/corelib/language/filecontext.h2
-rw-r--r--src/lib/corelib/language/forward_decls.h93
-rw-r--r--src/lib/corelib/language/identifiersearch.h3
-rw-r--r--src/lib/corelib/language/item.cpp33
-rw-r--r--src/lib/corelib/language/item.h8
-rw-r--r--src/lib/corelib/language/itempool.h3
-rw-r--r--src/lib/corelib/language/itemreader.cpp10
-rw-r--r--src/lib/corelib/language/itemreader.h9
-rw-r--r--src/lib/corelib/language/itemreaderastvisitor.cpp11
-rw-r--r--src/lib/corelib/language/itemreadervisitorstate.h3
-rw-r--r--src/lib/corelib/language/itemtype.h4
-rw-r--r--src/lib/corelib/language/language.cpp63
-rw-r--r--src/lib/corelib/language/language.h26
-rw-r--r--src/lib/corelib/language/language.pri5
-rw-r--r--src/lib/corelib/language/loader.cpp26
-rw-r--r--src/lib/corelib/language/loader.h4
-rwxr-xr-x[-rw-r--r--]src/lib/corelib/language/moduleloader.cpp985
-rw-r--r--src/lib/corelib/language/moduleloader.h79
-rw-r--r--src/lib/corelib/language/modulemerger.cpp13
-rw-r--r--src/lib/corelib/language/preparescriptobserver.cpp14
-rw-r--r--src/lib/corelib/language/preparescriptobserver.h11
-rw-r--r--src/lib/corelib/language/projectresolver.cpp192
-rw-r--r--src/lib/corelib/language/projectresolver.h26
-rw-r--r--src/lib/corelib/language/property.h3
-rw-r--r--src/lib/corelib/language/propertydeclaration.cpp5
-rw-r--r--src/lib/corelib/language/propertydeclaration.h1
-rw-r--r--src/lib/corelib/language/propertymapinternal.h8
-rw-r--r--src/lib/corelib/language/qualifiedid.h4
-rw-r--r--src/lib/corelib/language/scriptengine.cpp26
-rw-r--r--src/lib/corelib/language/scriptengine.h8
-rw-r--r--src/lib/corelib/language/tst_language.cpp2344
-rw-r--r--src/lib/corelib/language/value.cpp7
-rw-r--r--src/lib/corelib/language/value.h4
-rw-r--r--src/lib/corelib/parser/qmljsastvisitor_p.h3
-rw-r--r--src/lib/corelib/parser/qmljsengine_p.h3
-rw-r--r--src/lib/corelib/parser/qmljslexer_p.h3
-rw-r--r--src/lib/corelib/parser/qmljsparser_p.h3
-rw-r--r--src/lib/corelib/tools/architectures.cpp27
-rw-r--r--src/lib/corelib/tools/architectures.h1
-rw-r--r--src/lib/corelib/tools/buildgraphlocker.cpp9
-rw-r--r--src/lib/corelib/tools/buildgraphlocker.h5
-rw-r--r--src/lib/corelib/tools/error.cpp18
-rw-r--r--src/lib/corelib/tools/fileinfo.h2
-rw-r--r--src/lib/corelib/tools/filesaver.h4
-rw-r--r--src/lib/corelib/tools/filetime.h2
-rw-r--r--src/lib/corelib/tools/id.h4
-rw-r--r--src/lib/corelib/tools/launcherpackets.cpp1
-rw-r--r--src/lib/corelib/tools/launchersocket.cpp4
-rw-r--r--src/lib/corelib/tools/launchersocket.h4
-rw-r--r--src/lib/corelib/tools/persistence.cpp2
-rw-r--r--src/lib/corelib/tools/persistence.h26
-rw-r--r--src/lib/corelib/tools/preferences.cpp15
-rw-r--r--src/lib/corelib/tools/preferences.h2
-rw-r--r--src/lib/corelib/tools/processutils.h4
-rw-r--r--src/lib/corelib/tools/projectgeneratormanager.cpp22
-rw-r--r--src/lib/corelib/tools/projectgeneratormanager.h11
-rw-r--r--src/lib/corelib/tools/qbs_export.h11
-rw-r--r--src/lib/corelib/tools/qbspluginmanager.cpp145
-rw-r--r--src/lib/corelib/tools/qbspluginmanager.h96
-rw-r--r--src/lib/corelib/tools/scannerpluginmanager.cpp66
-rw-r--r--src/lib/corelib/tools/scannerpluginmanager.h24
-rw-r--r--src/lib/corelib/tools/scripttools.h2
-rw-r--r--src/lib/corelib/tools/set.h6
-rw-r--r--src/lib/corelib/tools/setupprojectparameters.cpp60
-rw-r--r--src/lib/corelib/tools/setupprojectparameters.h6
-rw-r--r--src/lib/corelib/tools/tools.pri8
-rw-r--r--src/lib/corelib/tools/tst_tools.cpp950
-rw-r--r--src/lib/corelib/tools/weakpointer.h38
-rw-r--r--src/lib/corelib/use_corelib.pri1
-rw-r--r--src/lib/corelib/use_installed_corelib.pri1
-rw-r--r--src/lib/library.pri1
-rw-r--r--src/lib/libs.qbs1
-rw-r--r--src/lib/qtprofilesetup/qtenvironment.h4
-rw-r--r--src/lib/qtprofilesetup/qtprofilesetup.cpp119
-rw-r--r--src/lib/qtprofilesetup/templates/QtModule.qbs3
-rw-r--r--src/lib/qtprofilesetup/templates/core.qbs32
-rw-r--r--src/lib/qtprofilesetup/templates/dbus.qbs1
-rw-r--r--src/lib/qtprofilesetup/templates/gui.qbs1
-rw-r--r--src/lib/qtprofilesetup/templates/module.qbs1
-rw-r--r--src/lib/qtprofilesetup/templates/plugin.qbs1
-rw-r--r--src/lib/qtprofilesetup/templates/qml.qbs23
-rw-r--r--src/lib/qtprofilesetup/templates/scxml.qbs1
-rw-r--r--src/plugins/generator/clangcompilationdb/clangcompilationdb.pro12
-rw-r--r--src/plugins/generator/clangcompilationdb/clangcompilationdb.qbs11
-rw-r--r--src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.cpp (renamed from src/lib/corelib/generators/clangcompilationdb/clangcompilationdbgenerator.cpp)0
-rw-r--r--src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.h (renamed from src/lib/corelib/generators/clangcompilationdb/clangcompilationdbgenerator.h)0
-rw-r--r--src/plugins/generator/clangcompilationdb/clangcompilationdbgeneratorplugin.cpp64
-rw-r--r--src/plugins/generator/generator.pro2
-rw-r--r--src/plugins/generator/visualstudio/io/msbuildprojectwriter.cpp (renamed from src/lib/corelib/generators/visualstudio/io/msbuildprojectwriter.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/io/msbuildprojectwriter.h (renamed from src/lib/corelib/generators/visualstudio/io/msbuildprojectwriter.h)0
-rw-r--r--src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.cpp (renamed from src/lib/corelib/generators/visualstudio/io/visualstudiosolutionwriter.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.h (renamed from src/lib/corelib/generators/visualstudio/io/visualstudiosolutionwriter.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/imsbuildgroup.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/imsbuildgroup.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/imsbuildgroup.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/imsbuildgroup.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/imsbuildnode.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/imsbuildnode.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/imsbuildnode.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/imsbuildnode.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/imsbuildnodevisitor.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/imsbuildnodevisitor.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/imsbuildproperty.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/imsbuildproperty.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/imsbuildproperty.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/imsbuildproperty.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildclcompile.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/items/msbuildclcompile.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildclcompile.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/items/msbuildclcompile.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildclinclude.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/items/msbuildclinclude.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildclinclude.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/items/msbuildclinclude.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/items/msbuildfileitem.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/items/msbuildfileitem.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/items/msbuildfilter.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/items/msbuildfilter.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildlink.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/items/msbuildlink.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildlink.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/items/msbuildlink.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildnone.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/items/msbuildnone.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/items/msbuildnone.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/items/msbuildnone.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildimport.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuildimport.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildimport.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuildimport.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuildimportgroup.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuildimportgroup.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuilditem.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuilditem.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuilditem.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuilditem.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuilditemdefinitiongroup.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuilditemgroup.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuilditemgroup.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuilditemmetadata.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuilditemmetadata.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuilditemmetadata.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuilditemmetadata.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildproject.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuildproject.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildproject.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuildproject.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildproperty.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuildproperty.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildproperty.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuildproperty.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuildpropertygroup.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.h (renamed from src/lib/corelib/generators/visualstudio/msbuild/msbuildpropertygroup.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuildfiltersproject.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuildfiltersproject.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuildfiltersproject.h (renamed from src/lib/corelib/generators/visualstudio/msbuildfiltersproject.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuildqbsgenerateproject.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuildqbsgenerateproject.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuildqbsgenerateproject.h (renamed from src/lib/corelib/generators/visualstudio/msbuildqbsgenerateproject.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuildqbsproductproject.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuildqbsproductproject.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuildqbsproductproject.h (renamed from src/lib/corelib/generators/visualstudio/msbuildqbsproductproject.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuildsharedsolutionpropertiesproject.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuildsharedsolutionpropertiesproject.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuildsharedsolutionpropertiesproject.h (renamed from src/lib/corelib/generators/visualstudio/msbuildsharedsolutionpropertiesproject.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuildsolutionpropertiesproject.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuildsolutionpropertiesproject.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuildsolutionpropertiesproject.h (renamed from src/lib/corelib/generators/visualstudio/msbuildsolutionpropertiesproject.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuildtargetproject.cpp (renamed from src/lib/corelib/generators/visualstudio/msbuildtargetproject.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/msbuildtargetproject.h (renamed from src/lib/corelib/generators/visualstudio/msbuildtargetproject.h)0
-rw-r--r--src/plugins/generator/visualstudio/msbuildutils.h (renamed from src/lib/corelib/generators/visualstudio/msbuildutils.h)0
-rw-r--r--src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.cpp (renamed from src/lib/corelib/generators/visualstudio/solution/ivisualstudiosolutionproject.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.h (renamed from src/lib/corelib/generators/visualstudio/solution/ivisualstudiosolutionproject.h)0
-rw-r--r--src/plugins/generator/visualstudio/solution/visualstudiosolution.cpp (renamed from src/lib/corelib/generators/visualstudio/solution/visualstudiosolution.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/solution/visualstudiosolution.h (renamed from src/lib/corelib/generators/visualstudio/solution/visualstudiosolution.h)0
-rw-r--r--src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.cpp (renamed from src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionfileproject.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.h (renamed from src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionfileproject.h)0
-rw-r--r--src/plugins/generator/visualstudio/solution/visualstudiosolutionfolderproject.cpp (renamed from src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionfolderproject.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/solution/visualstudiosolutionfolderproject.h (renamed from src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionfolderproject.h)0
-rw-r--r--src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.cpp (renamed from src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionglobalsection.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.h (renamed from src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionglobalsection.h)0
-rw-r--r--src/plugins/generator/visualstudio/visualstudio.pro (renamed from src/lib/corelib/generators/visualstudio/visualstudio.pri)7
-rw-r--r--src/plugins/generator/visualstudio/visualstudio.qbs (renamed from src/lib/corelib/generators/visualstudio/visualstudio.qbs)12
-rw-r--r--src/plugins/generator/visualstudio/visualstudiogenerator.cpp (renamed from src/lib/corelib/generators/visualstudio/visualstudiogenerator.cpp)62
-rw-r--r--src/plugins/generator/visualstudio/visualstudiogenerator.h (renamed from src/lib/corelib/generators/visualstudio/visualstudiogenerator.h)4
-rw-r--r--src/plugins/generator/visualstudio/visualstudiogeneratorplugin.cpp67
-rw-r--r--src/plugins/generator/visualstudio/visualstudioguidpool.cpp (renamed from src/lib/corelib/generators/visualstudio/visualstudioguidpool.cpp)0
-rw-r--r--src/plugins/generator/visualstudio/visualstudioguidpool.h (renamed from src/lib/corelib/generators/visualstudio/visualstudioguidpool.h)0
-rw-r--r--src/plugins/plugins.pri3
-rw-r--r--src/plugins/plugins.pro2
-rw-r--r--src/plugins/plugins.qbs2
-rw-r--r--src/plugins/qbsplugin.qbs (renamed from src/plugins/scanner/scannerplugin.qbs)10
-rw-r--r--src/plugins/scanner/cpp/cpp.qbs4
-rw-r--r--src/plugins/scanner/cpp/cpp_global.h2
-rw-r--r--src/plugins/scanner/cpp/cppscanner.cpp19
-rw-r--r--src/plugins/scanner/qt/qt.qbs4
-rw-r--r--src/plugins/scanner/qt/qtscanner.cpp20
-rw-r--r--src/plugins/scanner/scanner.h2
-rw-r--r--static.pro44
-rw-r--r--tests/auto/api/testdata/QBS-728/QBS-728.qbs2
-rw-r--r--tests/auto/api/testdata/buildgraph-info/buildgraph-info.qbs5
-rw-r--r--tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs2
-rw-r--r--tests/auto/api/testdata/infinite-loop-process/main.cpp11
-rw-r--r--tests/auto/api/testdata/multi-arch/multi-arch.qbs9
-rw-r--r--tests/auto/api/testdata/multiplexing/foo.txt1
-rw-r--r--tests/auto/api/testdata/multiplexing/multiplexing.qbs124
-rw-r--r--tests/auto/api/testdata/new-output-artifact-in-dependency/lib.cpp9
-rw-r--r--tests/auto/api/testdata/new-output-artifact-in-dependency/new-output-artifact-in-dependency.qbs1
-rw-r--r--tests/auto/api/testdata/objc/main.mm5
-rw-r--r--tests/auto/api/testdata/objc/objc.qbs2
-rw-r--r--tests/auto/api/testdata/rc/rc.qbs2
-rw-r--r--tests/auto/api/testdata/rename-product/lib.cpp6
-rw-r--r--tests/auto/api/testdata/rename-product/rename.qbs3
-rw-r--r--tests/auto/api/testdata/rename-target-artifact/lib.cpp6
-rw-r--r--tests/auto/api/testdata/rename-target-artifact/rename.qbs3
-rw-r--r--tests/auto/api/testdata/static-lib-deps/d.cpp2
-rw-r--r--tests/auto/api/testdata/static-lib-deps/d.mm8
-rw-r--r--tests/auto/api/testdata/static-lib-deps/static-lib-deps.qbs25
-rw-r--r--tests/auto/api/tst_api.cpp337
-rw-r--r--tests/auto/api/tst_api.h2
-rw-r--r--tests/auto/auto.pri5
-rw-r--r--tests/auto/auto.pro2
-rw-r--r--tests/auto/auto.qbs4
-rw-r--r--tests/auto/blackbox/blackbox-apple.pro20
-rw-r--r--tests/auto/blackbox/blackbox-apple.qbs23
-rw-r--r--tests/auto/blackbox/blackbox-clangdb.qbs25
-rw-r--r--tests/auto/blackbox/blackbox-java.qbs22
-rw-r--r--tests/auto/blackbox/blackbox-qt.pro18
-rw-r--r--tests/auto/blackbox/blackbox-qt.qbs22
-rw-r--r--tests/auto/blackbox/blackbox.qbs88
-rw-r--r--tests/auto/blackbox/find/find-android.qbs3
-rw-r--r--tests/auto/blackbox/find/find-jdk.qbs2
-rw-r--r--tests/auto/blackbox/find/find-nodejs.qbs2
-rw-r--r--tests/auto/blackbox/find/find-typescript.qbs2
-rw-r--r--tests/auto/blackbox/find/find-xcode.qbs41
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/apple-dmg.qbs88
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/de_DE.lproj/eula.txt6
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/en_GB.lproj/eula.txt6
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/en_US.lproj/eula.txt6
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/fr_FR.lproj/eula.txt6
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/hello.icnsbin0 -> 1393763 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/hello.tifbin0 -> 866742 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/ja_JP.lproj/eula.txt6
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/ko_KR.lproj/eula.rtf49
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/main.c1
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/ru_RU.lproj/eula.txt6
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/white.iconset/icon_16x16.png (renamed from tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16.png)bin649 -> 649 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/white.iconset/icon_16x16@2x.png (renamed from tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16@2x.png)bin665 -> 665 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/zh_CN.lproj/eula.odtbin0 -> 2680 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-dmg/zh_TW.lproj/eula.docxbin0 -> 12338 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-multiconfig/app.c2
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-multiconfig/apple-multiconfig.qbs136
-rw-r--r--tests/auto/blackbox/testdata-apple/apple-multiconfig/lib.c12
-rw-r--r--tests/auto/blackbox/testdata-apple/bundle-structure/bundle-structure.qbs (renamed from tests/auto/blackbox/testdata/bundle-structure/bundle-structure.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-apple/bundle-structure/dummy.c (renamed from tests/auto/blackbox/testdata/bundle-structure/dummy.c)0
-rw-r--r--tests/auto/blackbox/testdata-apple/bundle-structure/dummy.h (renamed from tests/auto/blackbox/testdata/bundle-structure/dummy.h)0
-rw-r--r--tests/auto/blackbox/testdata-apple/bundle-structure/dummy_p.h (renamed from tests/auto/blackbox/testdata/bundle-structure/dummy_p.h)0
-rw-r--r--tests/auto/blackbox/testdata-apple/bundle-structure/resource.txt (renamed from tests/auto/blackbox/testdata/bundle-structure/resource.txt)0
-rw-r--r--tests/auto/blackbox/testdata-apple/deploymentTarget/deployment.qbs (renamed from tests/auto/blackbox/testdata/deploymentTarget/deployment.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-apple/deploymentTarget/main.c (renamed from tests/auto/blackbox/testdata/deploymentTarget/main.c)0
-rw-r--r--tests/auto/blackbox/testdata-apple/embedInfoPlist/embedInfoPlist.qbs (renamed from tests/auto/blackbox/testdata/embedInfoPlist/embedInfoPlist.qbs)1
-rw-r--r--tests/auto/blackbox/testdata-apple/embedInfoPlist/main.m (renamed from tests/auto/blackbox/testdata/embedInfoPlist/main.m)0
-rw-r--r--tests/auto/blackbox/testdata-apple/frameworkStructure/BaseResource (renamed from tests/auto/blackbox/testdata/frameworkStructure/BaseResource)0
-rw-r--r--tests/auto/blackbox/testdata-apple/frameworkStructure/Widget.cpp (renamed from tests/auto/blackbox/testdata/frameworkStructure/Widget.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-apple/frameworkStructure/Widget.h (renamed from tests/auto/blackbox/testdata/frameworkStructure/Widget.h)0
-rw-r--r--tests/auto/blackbox/testdata-apple/frameworkStructure/WidgetPrivate.h (renamed from tests/auto/blackbox/testdata/frameworkStructure/WidgetPrivate.h)0
-rw-r--r--tests/auto/blackbox/testdata-apple/frameworkStructure/en.lproj/EnglishResource (renamed from tests/auto/blackbox/testdata/frameworkStructure/en.lproj/EnglishResource)0
-rw-r--r--tests/auto/blackbox/testdata-apple/frameworkStructure/frameworkStructure.qbs (renamed from tests/auto/blackbox/testdata/frameworkStructure/frameworkStructure.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/assetcatalog/EmptyStoryboard.storyboard (renamed from tests/auto/blackbox/testdata/ib/assetcatalog/EmptyStoryboard.storyboard)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/assetcatalog/MainMenu.xib4666
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/assetcatalog/Storyboard.storyboard (renamed from tests/auto/blackbox/testdata/ib/assetcatalog/Storyboard.storyboard)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/assetcatalog/assetcatalogempty.qbs (renamed from tests/auto/blackbox/testdata/ib/assetcatalog/assetcatalogempty.qbs)3
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16.png (renamed from tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16.png)bin649 -> 649 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16@2x.png (renamed from tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16@2x.png)bin665 -> 665 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/Contents.json (renamed from tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/other.imageset/Contents.json)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16.png (renamed from tests/auto/blackbox/testdata/ib/iconset/white.iconset/icon_16x16.png)bin649 -> 649 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16@2x.png (renamed from tests/auto/blackbox/testdata/ib/iconset/white.iconset/icon_16x16@2x.png)bin665 -> 665 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/assetcatalog/main.c (renamed from tests/auto/blackbox/testdata/ib/assetcatalog/main.c)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/assetcatalog1.xcassets/.keep (renamed from tests/auto/blackbox/testdata/ib/empty-asset-catalogs/assetcatalog1.xcassets/.keep)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/assetcatalog2.xcassets/.keep (renamed from tests/auto/blackbox/testdata/ib/empty-asset-catalogs/assetcatalog2.xcassets/.keep)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/main.c (renamed from tests/auto/blackbox/testdata/ib/empty-asset-catalogs/main.c)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/multiple-asset-catalogs.qbs (renamed from tests/auto/blackbox/testdata/ib/empty-asset-catalogs/multiple-asset-catalogs.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/iconset/iconset.qbs (renamed from tests/auto/blackbox/testdata/ib/iconset/iconset.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/iconset/white.iconset/icon_16x16.png (renamed from tests/auto/blackbox/testdata/ib/iconsetapp/white.iconset/icon_16x16.png)bin649 -> 649 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/iconset/white.iconset/icon_16x16@2x.png (renamed from tests/auto/blackbox/testdata/ib/iconsetapp/white.iconset/icon_16x16@2x.png)bin665 -> 665 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/iconsetapp/iconsetapp.qbs (renamed from tests/auto/blackbox/testdata/ib/iconsetapp/iconsetapp.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/iconsetapp/main.c (renamed from tests/auto/blackbox/testdata/ib/iconsetapp/main.c)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/iconsetapp/white.iconset/icon_16x16.png (renamed from tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16.png)bin649 -> 649 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/iconsetapp/white.iconset/icon_16x16@2x.png (renamed from tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16@2x.png)bin665 -> 665 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/Contents.json (renamed from tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/Contents.json)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16.png (renamed from tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16.png)bin649 -> 649 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16@2x.png (renamed from tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16@2x.png)bin665 -> 665 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/Contents.json (renamed from tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/Contents.json)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16.pngbin0 -> 649 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16@2x.pngbin0 -> 665 bytes
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/main.c (renamed from tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/main.c)0
-rw-r--r--tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/multiple-asset-catalogs.qbs (renamed from tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/multiple-asset-catalogs.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-apple/infoplist/infoplist.qbs (renamed from tests/auto/blackbox/testdata/infoplist/infoplist.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-apple/infoplist/main.c (renamed from tests/auto/blackbox/testdata/infoplist/main.c)0
-rw-r--r--tests/auto/blackbox/testdata-apple/objc-arc/arc.m (renamed from tests/auto/blackbox/testdata/objc-arc/arc.m)0
-rw-r--r--tests/auto/blackbox/testdata-apple/objc-arc/arc.mm (renamed from tests/auto/blackbox/testdata/objc-arc/arc.mm)0
-rw-r--r--tests/auto/blackbox/testdata-apple/objc-arc/main.m (renamed from tests/auto/blackbox/testdata/objc-arc/main.m)0
-rw-r--r--tests/auto/blackbox/testdata-apple/objc-arc/mrc.m (renamed from tests/auto/blackbox/testdata/objc-arc/mrc.m)0
-rw-r--r--tests/auto/blackbox/testdata-apple/objc-arc/mrc.mm (renamed from tests/auto/blackbox/testdata/objc-arc/mrc.mm)0
-rw-r--r--tests/auto/blackbox/testdata-apple/objc-arc/objc-arc.qbs (renamed from tests/auto/blackbox/testdata/objc-arc/objc-arc.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs (renamed from tests/auto/blackbox/testdata/xcode/xcode-project.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-java/android/multiple-apks-per-project/product1/product1.qbs2
-rw-r--r--tests/auto/blackbox/testdata-java/android/teapot/teapot.qbs42
-rw-r--r--tests/auto/blackbox/testdata-qt/auto-qrc/auto-qrc.qbs (renamed from tests/auto/blackbox/testdata/auto-qrc/auto-qrc.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/auto-qrc/main.cpp (renamed from tests/auto/blackbox/testdata/auto-qrc/main.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/resource1.txt (renamed from tests/auto/blackbox/testdata/auto-qrc/qrc-base/resource1.txt)0
-rw-r--r--tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/subdir/resource2.txt (renamed from tests/auto/blackbox/testdata/auto-qrc/qrc-base/subdir/resource2.txt)0
-rw-r--r--tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/subdir/resource3.txt (renamed from tests/auto/blackbox/testdata/auto-qrc/qrc-base/subdir/resource3.txt)0
-rw-r--r--tests/auto/blackbox/testdata-qt/combined-moc/combined-moc.qbs (renamed from tests/auto/blackbox/testdata/combined-moc/combined-moc.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/combined-moc/main.cpp (renamed from tests/auto/blackbox/testdata/combined-moc/main.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/combined-moc/theobject.h (renamed from tests/auto/blackbox/testdata/combined-moc/theobject.h)0
-rw-r--r--tests/auto/blackbox/testdata-qt/create-project/dummy.txt (renamed from tests/auto/blackbox/testdata/create-project/dummy.txt)0
-rw-r--r--tests/auto/blackbox/testdata-qt/dbus-adaptors/THIS.IS.A.STRANGE.FILENAME.CAR.XML (renamed from tests/auto/blackbox/testdata/dbus-adaptors/THIS.IS.A.STRANGE.FILENAME.CAR.XML)0
-rw-r--r--tests/auto/blackbox/testdata-qt/dbus-adaptors/car.cpp (renamed from tests/auto/blackbox/testdata/dbus-adaptors/car.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/dbus-adaptors/car.h (renamed from tests/auto/blackbox/testdata/dbus-adaptors/car.h)0
-rw-r--r--tests/auto/blackbox/testdata-qt/dbus-adaptors/car.qbs (renamed from tests/auto/blackbox/testdata/dbus-adaptors/car.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/dbus-adaptors/main.cpp (renamed from tests/auto/blackbox/testdata/dbus-adaptors/main.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/dbus-interfaces/car.xml (renamed from tests/auto/blackbox/testdata/dbus-interfaces/car.xml)0
-rw-r--r--tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.cpp (renamed from tests/auto/blackbox/testdata/dbus-interfaces/controller.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.h (renamed from tests/auto/blackbox/testdata/dbus-interfaces/controller.h)0
-rw-r--r--tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.qbs (renamed from tests/auto/blackbox/testdata/dbus-interfaces/controller.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.ui (renamed from tests/auto/blackbox/testdata/dbus-interfaces/controller.ui)0
-rw-r--r--tests/auto/blackbox/testdata-qt/dbus-interfaces/main.cpp (renamed from tests/auto/blackbox/testdata/dbus-interfaces/main.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/lrelease/de.ts (renamed from tests/auto/blackbox/testdata/lrelease/de.ts)0
-rw-r--r--tests/auto/blackbox/testdata-qt/lrelease/hu.ts (renamed from tests/auto/blackbox/testdata/lrelease/hu.ts)0
-rw-r--r--tests/auto/blackbox/testdata-qt/lrelease/lrelease.qbs (renamed from tests/auto/blackbox/testdata/lrelease/lrelease.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/mixed-build-variants/main.cpp (renamed from tests/auto/blackbox/testdata/mixed-build-variants/main.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/mixed-build-variants/mixed-build-variants.qbs11
-rw-r--r--tests/auto/blackbox/testdata-qt/moc-flags/blubb.h (renamed from tests/auto/blackbox/testdata/moc-flags/blubb.h)0
-rw-r--r--tests/auto/blackbox/testdata-qt/moc-flags/main.cpp (renamed from tests/auto/blackbox/testdata/moc-flags/main.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/moc-flags/moc-flags.qbs (renamed from tests/auto/blackbox/testdata/moc-flags/moc-flags.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/plugin-meta-data/app.cpp (renamed from tests/auto/blackbox/testdata/plugin-meta-data/app.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/plugin-meta-data/metadata.json (renamed from tests/auto/blackbox/testdata/plugin-meta-data/metadata.json)0
-rw-r--r--tests/auto/blackbox/testdata-qt/plugin-meta-data/plugin-meta-data.qbs (renamed from tests/auto/blackbox/testdata/plugin-meta-data/plugin-meta-data.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/plugin-meta-data/theplugin.cpp (renamed from tests/auto/blackbox/testdata/plugin-meta-data/theplugin.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/qml-debugging/main.cpp (renamed from tests/auto/blackbox/testdata/qml-debugging/main.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/qml-debugging/qml-debugging.qbs (renamed from tests/auto/blackbox/testdata/qml-debugging/qml-debugging.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/qobject-in-mm/main.mm (renamed from tests/auto/blackbox/testdata/qobject-in-mm/main.mm)0
-rw-r--r--tests/auto/blackbox/testdata-qt/qobject-in-mm/qobject-in-mm.qbs (renamed from tests/auto/blackbox/testdata/qobject-in-mm/qobject-in-mm.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/qrc/bla.cpp (renamed from tests/auto/blackbox/testdata/qrc/bla.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/qrc/bla.qrc (renamed from tests/auto/blackbox/testdata/qrc/bla.qrc)0
-rw-r--r--tests/auto/blackbox/testdata-qt/qrc/i.qbs (renamed from tests/auto/blackbox/testdata/qrc/i.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/qrc/stuff.txt (renamed from tests/auto/blackbox/testdata/qrc/stuff.txt)0
-rw-r--r--tests/auto/blackbox/testdata-qt/qt-keywords/main.cpp (renamed from tests/auto/blackbox/testdata/qt-keywords/main.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/qt-keywords/qt-keywords.qbs (renamed from tests/auto/blackbox/testdata/qt-keywords/qt-keywords.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/qtscxml/dummystatemachine.scxml (renamed from tests/auto/blackbox/testdata/qtscxml/dummystatemachine.scxml)0
-rw-r--r--tests/auto/blackbox/testdata-qt/qtscxml/main.cpp (renamed from tests/auto/blackbox/testdata/qtscxml/main.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/qtscxml/qtscxml.qbs (renamed from tests/auto/blackbox/testdata/qtscxml/qtscxml.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/static-qt-plugin-linking.qbs (renamed from tests/auto/blackbox/testdata/static-qt-plugin-linking/static-qt-plugin-linking.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/trackAddMocInclude/after/main.cpp (renamed from tests/auto/blackbox/testdata/trackAddMocInclude/after/main.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/trackAddMocInclude/before/main.cpp (renamed from tests/auto/blackbox/testdata/trackAddMocInclude/before/main.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/trackAddMocInclude/before/test.qbs (renamed from tests/auto/blackbox/testdata/trackAddMocInclude/before/test.qbs)0
-rw-r--r--tests/auto/blackbox/testdata-qt/trackQObjChange/bla.cpp (renamed from tests/auto/blackbox/testdata/trackQObjChange/bla.cpp)0
-rw-r--r--tests/auto/blackbox/testdata-qt/trackQObjChange/bla_noqobject.h (renamed from tests/auto/blackbox/testdata/trackQObjChange/bla_noqobject.h)0
-rw-r--r--tests/auto/blackbox/testdata-qt/trackQObjChange/bla_qobject.h (renamed from tests/auto/blackbox/testdata/trackQObjChange/bla_qobject.h)0
-rw-r--r--tests/auto/blackbox/testdata-qt/trackQObjChange/i.qbs (renamed from tests/auto/blackbox/testdata/trackQObjChange/i.qbs)0
-rw-r--r--tests/auto/blackbox/testdata/assembly/assembly.qbs26
-rw-r--r--tests/auto/blackbox/testdata/aux-inputs-from-deps/aux-inputs-from-deps.qbs80
-rw-r--r--tests/auto/blackbox/testdata/aux-inputs-from-deps/main.cpp3
-rw-r--r--tests/auto/blackbox/testdata/aux-inputs-from-deps/util.js8
-rw-r--r--tests/auto/blackbox/testdata/buildenv-change/buildenv-change.qbs17
-rw-r--r--tests/auto/blackbox/testdata/buildenv-change/file.c1
-rw-r--r--tests/auto/blackbox/testdata/buildenv-change/main.cpp3
-rw-r--r--tests/auto/blackbox/testdata/buildenv-change/subdir/theheader.h0
-rw-r--r--tests/auto/blackbox/testdata/buildenv-change/subdir2/theheader.h0
-rw-r--r--tests/auto/blackbox/testdata/clean/clean.qbs1
-rw-r--r--tests/auto/blackbox/testdata/clean/dep.cpp8
-rw-r--r--tests/auto/blackbox/testdata/dependency-profile-mismatch/dependency-profile-mismatch.qbs2
-rw-r--r--tests/auto/blackbox/testdata/deprecated-property/modules/themodule/m.qbs7
-rw-r--r--tests/auto/blackbox/testdata/disappeared-profile/disappeared-profile.qbs14
-rw-r--r--tests/auto/blackbox/testdata/disappeared-profile/in1.txt0
-rw-r--r--tests/auto/blackbox/testdata/disappeared-profile/in2.txt0
-rw-r--r--tests/auto/blackbox/testdata/disappeared-profile/modules-dir/modules/m/m.qbs34
-rw-r--r--tests/auto/blackbox/testdata/enableExceptions/main.cpp4
-rw-r--r--tests/auto/blackbox/testdata/enableRtti/main.cpp4
-rw-r--r--tests/auto/blackbox/testdata/error-info/error-info.qbs4
-rw-r--r--tests/auto/blackbox/testdata/export-rule/export-rule.qbs7
-rw-r--r--tests/auto/blackbox/testdata/find/find-cli.qbs2
-rw-r--r--tests/auto/blackbox/testdata/ib/assetcatalog/MainMenu.xib680
-rw-r--r--tests/auto/blackbox/testdata/install-root-from-project-file/file.txt0
-rw-r--r--tests/auto/blackbox/testdata/install-root-from-project-file/install-root-from-project-file.qbs13
-rw-r--r--tests/auto/blackbox/testdata/installpackage/installpackage.qbs6
-rw-r--r--tests/auto/blackbox/testdata/installpackage/lib.h14
-rw-r--r--tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs1
-rw-r--r--tests/auto/blackbox/testdata/jsextensions-process/main.cpp20
-rw-r--r--tests/auto/blackbox/testdata/jsextensions-process/process.qbs22
-rw-r--r--tests/auto/blackbox/testdata/jsextensions-propertylist/propertylist.qbs5
-rw-r--r--tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs1
-rw-r--r--tests/auto/blackbox/testdata/loadablemodule/exported.h8
-rw-r--r--tests/auto/blackbox/testdata/loadablemodule/loadablemodule.qbs12
-rw-r--r--tests/auto/blackbox/testdata/loadablemodule/main.cpp41
-rw-r--r--tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p1.qbs0
-rw-r--r--tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p2.qbs0
-rw-r--r--tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p3.qbs0
-rw-r--r--tests/auto/blackbox/testdata/missing-project-file/empty-dir/irrelevant.txt0
-rw-r--r--tests/auto/blackbox/testdata/missing-project-file/project-dir/file.cpp1
-rw-r--r--tests/auto/blackbox/testdata/missing-project-file/project-dir/main.cpp1
-rw-r--r--tests/auto/blackbox/testdata/missing-project-file/project-dir/missing-project-file.qbs8
-rw-r--r--tests/auto/blackbox/testdata/mixed-build-variants/mixed-build-variants.qbs6
-rw-r--r--tests/auto/blackbox/testdata/pch-change-tracking/header1.h6
-rw-r--r--tests/auto/blackbox/testdata/pch-change-tracking/header2.cpp8
-rw-r--r--tests/auto/blackbox/testdata/pch-change-tracking/header2.h3
-rw-r--r--tests/auto/blackbox/testdata/pch-change-tracking/main.cpp3
-rw-r--r--tests/auto/blackbox/testdata/pch-change-tracking/pch-change-tracking.qbs1
-rw-r--r--tests/auto/blackbox/testdata/plugin-dependency/helper.cpp12
-rw-r--r--tests/auto/blackbox/testdata/plugin-dependency/main.cpp17
-rw-r--r--tests/auto/blackbox/testdata/plugin-dependency/plugin-dependency.qbs53
-rw-r--r--tests/auto/blackbox/testdata/plugin-dependency/plugin1.cpp12
-rw-r--r--tests/auto/blackbox/testdata/plugin-dependency/plugin2.cpp12
-rw-r--r--tests/auto/blackbox/testdata/plugin-dependency/plugin3.cpp12
-rw-r--r--tests/auto/blackbox/testdata/plugin-dependency/plugin4.cpp12
-rw-r--r--tests/auto/blackbox/testdata/probes-in-nested-modules/probes-in-nested-modules.qbs15
-rw-r--r--tests/auto/blackbox/testdata/project_filepath_check/main2.cpp1
-rw-r--r--tests/auto/blackbox/testdata/project_filepath_check/project2.qbs2
-rw-r--r--tests/auto/blackbox/testdata/propertyChanges/lib.cpp8
-rw-r--r--tests/auto/blackbox/testdata/propertyChanges/propertyChanges.qbs2
-rw-r--r--tests/auto/blackbox/testdata/qbsVersion/qbs-version.qbs4
-rw-r--r--tests/auto/blackbox/testdata/rule-with-non-required-inputs/a.inp0
-rw-r--r--tests/auto/blackbox/testdata/rule-with-non-required-inputs/b.inp0
-rw-r--r--tests/auto/blackbox/testdata/rule-with-non-required-inputs/c.inp0
-rw-r--r--tests/auto/blackbox/testdata/rule-with-non-required-inputs/rule-with-non-required-inputs.qbs42
-rw-r--r--tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs30
-rw-r--r--tests/auto/blackbox/testdata/subprofile-change-tracking/subprofile-change-tracking.qbs5
-rw-r--r--tests/auto/blackbox/testdata/symbolLinkMode/indirect.cpp3
-rw-r--r--tests/auto/blackbox/testdata/symbolLinkMode/lib.cpp11
-rw-r--r--tests/auto/blackbox/testdata/symbolLinkMode/main.cpp17
-rw-r--r--tests/auto/blackbox/testdata/symbolLinkMode/symbolLinkMode.qbs105
-rw-r--r--tests/auto/blackbox/testdata/whole-archive/dynamiclib.cpp9
-rw-r--r--tests/auto/blackbox/testdata/whole-archive/main1.cpp6
-rw-r--r--tests/auto/blackbox/testdata/whole-archive/main2.cpp6
-rw-r--r--tests/auto/blackbox/testdata/whole-archive/main3.cpp6
-rw-r--r--tests/auto/blackbox/testdata/whole-archive/main4.cpp6
-rw-r--r--tests/auto/blackbox/testdata/whole-archive/unused1.cpp1
-rw-r--r--tests/auto/blackbox/testdata/whole-archive/unused2.cpp1
-rw-r--r--tests/auto/blackbox/testdata/whole-archive/unused3.cpp1
-rw-r--r--tests/auto/blackbox/testdata/whole-archive/unused4.cpp1
-rw-r--r--tests/auto/blackbox/testdata/whole-archive/used.cpp1
-rw-r--r--tests/auto/blackbox/testdata/whole-archive/whole-archive.qbs70
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp1655
-rw-r--r--tests/auto/blackbox/tst_blackbox.h40
-rw-r--r--tests/auto/blackbox/tst_blackboxapple.cpp755
-rw-r--r--tests/auto/blackbox/tst_blackboxapple.h74
-rw-r--r--tests/auto/blackbox/tst_blackboxbase.cpp28
-rw-r--r--tests/auto/blackbox/tst_blackboxbase.h11
-rw-r--r--tests/auto/blackbox/tst_blackboxjava.cpp72
-rw-r--r--tests/auto/blackbox/tst_blackboxjava.h2
-rw-r--r--tests/auto/blackbox/tst_blackboxqt.cpp311
-rw-r--r--tests/auto/blackbox/tst_blackboxqt.h64
-rw-r--r--tests/auto/blackbox/tst_clangdb.cpp8
-rw-r--r--tests/auto/buildgraph/buildgraph.pro1
-rw-r--r--tests/auto/buildgraph/buildgraph.qbs5
-rw-r--r--tests/auto/buildgraph/tst_buildgraph.cpp123
-rw-r--r--tests/auto/buildgraph/tst_buildgraph.h (renamed from src/lib/corelib/buildgraph/tst_buildgraph.h)22
-rw-r--r--tests/auto/cmdlineparser/cmdlineparser.qbs4
-rw-r--r--tests/auto/language/language.pro3
-rw-r--r--tests/auto/language/language.qbs14
-rw-r--r--tests/auto/language/testdata/conditionaldepends.qbs11
-rw-r--r--tests/auto/language/testdata/dependencyOnAllProfiles.qbs3
-rw-r--r--tests/auto/language/testdata/enum-project-props.qbs14
-rw-r--r--tests/auto/language/testdata/erroneous/invalid-parameter-rhs.qbs7
-rw-r--r--tests/auto/language/testdata/erroneous/invalid-parameter-type.qbs10
-rw-r--r--tests/auto/language/testdata/erroneous/mismatching-multiplex-dependency.qbs15
-rw-r--r--tests/auto/language/testdata/erroneous/modules/module_with_parameters/module_with_parameters.qbs6
-rw-r--r--tests/auto/language/testdata/erroneous/undeclared-parameter1.qbs7
-rw-r--r--tests/auto/language/testdata/erroneous/undeclared-parameter2.qbs7
-rw-r--r--tests/auto/language/testdata/getNativeSetting.qbs6
-rw-r--r--tests/auto/language/testdata/module-property-overrides-per-product.qbs16
-rw-r--r--tests/auto/language/testdata/modules/dummy3/dummy3.qbs4
-rw-r--r--tests/auto/language/testdata/parameter-types.qbs19
-rw-r--r--tests/auto/language/testdata/profilevaluesandoverriddenvalues.qbs4
-rw-r--r--tests/auto/language/tst_language.cpp2443
-rw-r--r--tests/auto/language/tst_language.h (renamed from src/lib/corelib/language/tst_language.h)38
-rw-r--r--tests/auto/shared.h45
-rw-r--r--tests/auto/tools/tools.pro1
-rw-r--r--tests/auto/tools/tools.qbs10
-rw-r--r--tests/auto/tools/tst_tools.cpp931
-rw-r--r--tests/auto/tools/tst_tools.h (renamed from src/lib/corelib/tools/tst_tools.h)13
-rw-r--r--tests/fuzzy-test/fuzzytester.cpp13
-rw-r--r--tests/fuzzy-test/fuzzytester.h4
671 files changed, 25528 insertions, 7748 deletions
diff --git a/.gitattributes b/.gitattributes
index fbe3f9874..71f59f087 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,3 +1,3 @@
/.gitignore export-ignore
/.gitattributes export-ignore
-/make-release-archive.sh export-ignore
+/scripts/make-release-archive.sh export-ignore
diff --git a/README b/README
index 105eff1cb..9b6c5bf9c 100644
--- a/README
+++ b/README
@@ -32,3 +32,21 @@ Installation ("make install") is not needed. It is however possible, using
make install INSTALL_ROOT=$INSTALL_DIRECTORY
+You can also build Qbs for Windows using Docker on Windows 10 systems.
+Switch your Docker environment to use Windows containers, then run the
+following to download the Windows 10 Qbs development image:
+
+ docker pull qtproject/qbswindowsservercore
+
+The Dockerfile from which this image is built is located in the docker
+directory of the qbs source tree, should you wish to build it yourself.
+
+You can then use the image to perform builds and develop Qbs. For example:
+
+ # Run a container interactively with cmd shell access,
+ # mounting the current directory inside at C:\qbs
+ docker run -i -v %CD%:C:\qbs -w C:\qbs qtproject/qbswindowsservercore
+
+ # Perform a release build with a temporary container instance,
+ # and copy the output artifacts to the working directory
+ docker run --rm -v %CD%:C:\qbs -w C:\qbs qtproject/qbswindowsservercore cmd /c scripts\make-release-archives
diff --git a/VERSION b/VERSION
new file mode 100644
index 000000000..f8e233b27
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+1.9.0
diff --git a/changelogs/changes-1.6.0 b/changelogs/changes-1.6.0
new file mode 100644
index 000000000..616be8660
--- /dev/null
+++ b/changelogs/changes-1.6.0
@@ -0,0 +1,16 @@
+* Added lex_yacc module.
+* Introduced property cpp.systemRunPaths.
+* Introduced the ability to check a module's version in a Depends item.
+* Introduced cpp.driverFlags, which allows specifying flags to be
+ passed to the compiler driver (in any mode), but never the system linker.
+* Introduced cpp.linkerMode property to allow selection of the
+ correct linker (C driver, C++ driver, or system linker) based on the
+ objects being linked.
+* Added automatic escaping of arguments passed to the
+ cpp.linkerFlags and cpp.platformLinkerFlags properties using the -Wl
+ or -Xlinker syntaxes. To revert to the old behavior,
+ Project.minimumQbsVersion can be set to a version lower than 1.6.
+* Each build configuration now requires a unique name, which
+ is specified on the command line in the same place that qbs.buildVariant
+ used to be specified. This allows building for multiple configurations
+ with the same variant.
diff --git a/changelogs/changes-1.6.1 b/changelogs/changes-1.6.1
new file mode 100644
index 000000000..20899adec
--- /dev/null
+++ b/changelogs/changes-1.6.1
@@ -0,0 +1,6 @@
+Features:
+ * Added cpp.linkerWrapper property.
+Important bug fixes:
+ * Fixed a number of bugs evaluating module properties (QBS-845, QBS-1005).
+ * Fixed x86_64 > x86 cross compiling (QBS-1028).
+ * Fixed dynamic rules with generated inputs (QBS-1029).
diff --git a/changelogs/changes-1.7.0 b/changelogs/changes-1.7.0
new file mode 100644
index 000000000..341ebcd33
--- /dev/null
+++ b/changelogs/changes-1.7.0
@@ -0,0 +1,23 @@
+Features:
+ * Added a generator for Visual Studio projects.
+ * The Group item is now nestable.
+ * Stricter type checking for properties.
+ * Added support for generating qrc files.
+ * Added full support for the QtScxml module.
+ * Introduced cpp.soVersion.
+ * Added support for building Inno Setup packages.
+ * Tentative support for Visual Studio 2017.
+ * We now assume UTF-8 encoding for project files.
+ * In Scanner items, input.fileName now contains
+ a filename rather than the full path.
+ * Warnings encountered during project resolving are now stored
+ and re-displayed when the project is loaded.
+ * Documentation was improved in several places, most
+ notably for the Rule item.
+ * Support for the deprecated Transformer item was removed.
+Important bug fixes:
+ * Long paths on Windows are handled (QBS-1068).
+ * Cyclic module dependencies are detected (QBS-1044).
+ * The libqbscore soname now includes the minor version,
+ so that it will not stay the same across ABI changes
+ (QBS-1002).
diff --git a/changelogs/changes-1.7.1 b/changelogs/changes-1.7.1
new file mode 100644
index 000000000..07262550c
--- /dev/null
+++ b/changelogs/changes-1.7.1
@@ -0,0 +1,5 @@
+Important bug fixes:
+ * Fixed race condition in qmake build (QBS-1091)
+ * Qt Creator no longer leaves empty build directories
+ behind after cancelled project loading (QTCREATORBUG-17543)
+ * Fixed an exception crossing the API boundary
diff --git a/changelogs/changes-1.7.2 b/changelogs/changes-1.7.2
new file mode 100644
index 000000000..9f4385d77
--- /dev/null
+++ b/changelogs/changes-1.7.2
@@ -0,0 +1,5 @@
+Important bug fixes:
+ * macOS: Fixed App Extension builds on older versions of Xcode/macOS
+ * Windows: Fixed handling of files on network shares
+ * Fixed syntax error in Qt module that occurred with static Qt builds
+ * Several fixes for the Visual Studio generator (QBS-1077, QBS-1100)
diff --git a/changelogs/changes-1.8.0 b/changelogs/changes-1.8.0
new file mode 100644
index 000000000..5c4cec23e
--- /dev/null
+++ b/changelogs/changes-1.8.0
@@ -0,0 +1,33 @@
+Features:
+ * General:
+ * It is no longer strictly required to provide a profile.
+ * Sub-second timestamp resolutions are now supported on Unix
+ systems.
+ * Added a convenient replacement for
+ product.moduleProperty("module", "property"), namely
+ product.module.property.
+ * The loadFile and loadExtension functions are deprecated in
+ favor of the new require function, which accepts arguments of either
+ form accepted by the deprecated functions.
+ * Added new tool qbs-create-project to set up a new qbs
+ project from an existing source tree.
+ * FileTagger items can now have conditions.
+ * Probe items can now appear directly under a Project item.
+ * Cpp module:
+ * Added support for QNX and the QCC toolchain
+ * Added the cpp.useRPathLink property to control whether
+ to use the -rpath-link linker option.
+ * Provided the means to easily combine source files for the C
+ language family in order to support "amalgamation builds".
+ * Introduced cpp.treatSystemHeadersAsDependencies.
+ * Qt modules:
+ * Introduced property Qt.core.combineMocOutput.
+ * Introduced Qt.core.enableKeywords for simple disabling of
+ the "signals", "slots" and "emit" symbols.
+Important bug fixes:
+ * Improved scalability of parallel builds on Linux by starting
+ Process commands via a dedicated launcher process.
+Behavior changes:
+ * The base directory for source files changed from the product
+ source directory to the parent directory of the file where the files are
+ listed.
diff --git a/dist/dist.qbs b/dist/dist.qbs
index a5ba27308..51b55bd4d 100644
--- a/dist/dist.qbs
+++ b/dist/dist.qbs
@@ -3,7 +3,6 @@ import qbs.FileInfo
import qbs.ModUtils
import qbs.Process
import qbs.TextFile
-import QbsFunctions
Product {
Depends { name: "qbs-config" }
@@ -14,6 +13,7 @@ Product {
Depends { name: "qbs-setup-toolchains" }
Depends { name: "qbs_app" }
Depends { name: "qbs_processlauncher" }
+ Depends { name: "qbsversion" }
Depends { name: "qbscore" }
Depends { name: "qbsqtprofilesetup" }
Depends { name: "qbs_cpp_scanner" }
@@ -50,7 +50,7 @@ Product {
condition: qbs.targetOS.contains("windows")
builtByDefault: false
type: ["archiver.archive"]
- targetName: "qbs-windows-" + qbs.architecture + "-" + QbsFunctions.qbsVersion()
+ targetName: "qbs-windows-" + qbs.architecture + "-" + qbsversion.version
destinationDirectory: project.buildDirectory
archiver.type: "zip"
diff --git a/doc/doc.qbs b/doc/doc.qbs
index c83259c42..c6ff39808 100644
--- a/doc/doc.qbs
+++ b/doc/doc.qbs
@@ -1,5 +1,4 @@
import qbs 1.0
-import QbsFunctions
Product {
name: "documentation"
@@ -7,8 +6,10 @@ Product {
type: "qch"
Depends { name: "Qt.core" }
Depends { name: "qbsbuildconfig" }
+ Depends { name: "qbsversion" }
files: [
+ "howtos.qdoc",
"qbs.qdoc",
"config/*.qdocconf",
"reference/**/*",
@@ -19,9 +20,9 @@ Product {
fileTags: "qdocconf-main"
}
- property string versionTag: QbsFunctions.qbsVersion().replace(/\.|-/g, "")
+ property string versionTag: qbsversion.version.replace(/\.|-/g, "")
Qt.core.qdocEnvironment: [
- "QBS_VERSION=" + QbsFunctions.qbsVersion(),
+ "QBS_VERSION=" + qbsversion.version,
"SRCDIR=" + path,
"QT_INSTALL_DOCS=" + Qt.core.docPath,
"QBS_VERSION_TAG=" + versionTag
diff --git a/doc/howtos.qdoc b/doc/howtos.qdoc
new file mode 100644
index 000000000..b8974c3d0
--- /dev/null
+++ b/doc/howtos.qdoc
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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
+ \previouspage custom-modules.html
+ \nextpage reference.html
+ \page howtos.html
+
+ \title How-tos
+
+ This page provides concrete instructions for common scenarios.
+
+ \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 create application bundles and frameworks on iOS, macOS, tvOS, and watchOS?}
+ \endlist
+
+ \section1 How do I build a Qt-based project?
+
+ First of all, your project files need to declare a Qt dependency.
+ See \l{Qt Modules} for how to do that.
+
+ To build the project, you need a matching \e profile. The following commands
+ set up and use a Qt-specific profile:
+ \code
+ $ qbs setup-qt /usr/bin/qmake qt
+ $ cd my_project
+ $ qbs profile:qt
+ \endcode
+ If you plan to use this profile a lot, consider making it the default one:
+ \code
+ $ qbs config defaultProfile qt
+ $ cd my_project
+ $ qbs
+ \endcode
+ See \l{Managing Qt Versions} for more details.
+ \note These instructions are only relevant for building from the command line.
+ If you use Qt Creator, profiles are set up automatically from the information in the Kit.
+
+ \section1 How do I make my app build against my library?
+
+ This is achieved by introducing a \e dependency between the two products using the
+ \l{Depends Item}{Depends item}. Here is a simple, but complete example:
+ \code
+ import qbs
+ Project {
+ CppApplication {
+ name : "the-app"
+ files : [ "main.cpp" ]
+ Depends { name: "the-lib" }
+ }
+ DynamicLibrary {
+ name: "the-lib"
+ Depends { name: "cpp" }
+ files: [
+ "lib.cpp",
+ "lib.h",
+ ]
+ Export {
+ Depends { name: "cpp" }
+ cpp.includePaths: [product.sourceDirectory]
+ }
+ }
+ }
+ \endcode
+
+ The product \c the-lib is a dynamic library. It expects other products to build against it, and
+ for that purpose, it exports an include path (via an \l{Export Item}{Export item}), so that the
+ source files in these products can include the library's header file.
+
+ The product \c the-app is an application that expresses its intent to link against \c the-lib
+ by declaring a dependency on it. Now \c main.cpp can include \c lib.h (because of the exported
+ include path) and the application binary will link against the library (because the linker
+ \l{Rule Item}{rule} in the \l{Module cpp}{cpp module} considers library dependencies as inputs).
+ \note In a non-trivial project, the two products would not be defined in the same file.
+ Instead, you would put them into files of their own and use the
+ \l{Project Item}{Project item}'s \c references property to pull them into the project.
+ The product definitions would stay exactly the same. In particular, their location
+ in the project tree is irrelevant to the relationship between them.
+
+ \section1 How do I create application bundles and frameworks on iOS, macOS, tvOS, and watchOS?
+
+ Creating an application bundle or framework is achieved by introducing a dependency on the
+ \l{Module bundle}{Bundle module} and setting the \c bundle.isBundle property to \c true.
+
+ Here is a simple example for an application:
+
+ \code
+ import qbs
+
+ Application {
+ Depends { name: "cpp" }
+ Depends { name: "bundle" }
+ bundle.isBundle: true
+ name: "the-app"
+ files: ["main.cpp"]
+ }
+ \endcode
+
+ and for a framework:
+
+ \code
+ import qbs
+
+ DynamicLibrary {
+ Depends { name: "cpp" }
+ Depends { name: "bundle" }
+ bundle.isBundle: true
+ name: "the-lib"
+ files: ["lib.cpp", "lib.h"]
+ }
+ \endcode
+
+ \QBS also supports building static frameworks - you can create one by replacing
+ \c DynamicLibrary with \c StaticLibrary in the example above.
+
+ \note When using the \c Application or \c Library templates (or derived templates like
+ \c CppApplication, \c DynamicLibrary, and \c StaticLibrary),
+ your products will build as bundles on Apple platforms by default (this behavior is subject to
+ change in a future release).
+
+ To explicitly control whether your product is built as a bundle, set the \c bundle.isBundle
+ property. Setting the \c consoleApplication property of your product will also influence whether
+ your product is built as a bundle.
+
+ Building your application against your framework is the same as linking a normal dynamic or
+ static library; see the \l{How do I make my app build against my library?} section for an
+ example.
+*/
diff --git a/doc/qbs.qdoc b/doc/qbs.qdoc
index f9e6025d1..4f16cf40a 100644
--- a/doc/qbs.qdoc
+++ b/doc/qbs.qdoc
@@ -68,8 +68,10 @@
\li \l{Running Applications}
\li \l{Installing Files}
\li \l{Using the Shell}
+ \li \l{Generators}
\li \l{Custom Modules and Items}
\endlist
+ \li \l{How-tos}
\li \l{Reference}
\endlist
*/
@@ -269,6 +271,7 @@
\li \l{Running Applications}
\li \l{Installing Files}
\li \l{Using the Shell}
+ \li \l{Generators}
\li \l{Custom Modules and Items}
\endlist
@@ -598,9 +601,10 @@
The syntax is \c{<prefix>.<prop-name>:<prop-value>}. The following command lines
demonstrate how to set different kinds of properties:
\code
- $ qbs projects.someProject.projectProperty:false # set a property of a project
- $ qbs products.someProduct.productProperty:false # set a property of a product
- $ qbs modules.cpp.treatWarningsAsErrors:true # set a module property for all products
+ $ qbs projects.someProject.projectProperty:false # set a property of a project
+ $ qbs products.someProduct.productProperty:false # set a property of a product
+ $ qbs modules.cpp.treatWarningsAsErrors:true # set a module property for all products
+ $ qbs products.someProduct.cpp.treatWarningsAsErrors:true # set a module property for one product
\endcode
Property values on the command line can also be expressed in JavaScript form, the same way
@@ -808,7 +812,7 @@
\contentspage index.html
\previouspage installing-files.html
\page shell.html
- \nextpage custom-modules.html
+ \nextpage generators.html
\title Using the Shell
@@ -826,9 +830,9 @@
/*!
\contentspage index.html
- \previouspage shell.html
+ \previouspage generators.html
\page custom-modules.html
- \nextpage reference.html
+ \nextpage howtos.html
\title Custom Modules and Items
@@ -892,3 +896,76 @@
\endcode
*/
+
+/*!
+ \contentspage index.html
+ \previouspage shell.html
+ \page generators.html
+ \nextpage custom-modules.html
+
+ \title Generators
+
+ Generators are a \QBS sub-tool and set of APIs which enable arbitrary processing to be performed
+ on the build graph. Currently they are used to implement IDE integration with popular IDEs like
+ Visual Studio.
+
+ \section1 Using Generators
+
+ To generate a project for another build system like Visual Studio, use the
+ \c qbs-generate sub-command and specify a generator using the \c{-g} option. For example:
+
+ \code
+ # For Visual Studio
+ qbs generate -g visualstudio2015
+ \endcode
+
+ \QBS will then generate a series of files in the current directory, based on the generator that
+ was chosen. For the Visual Studio generator, the resulting project files can be
+ opened in the respective IDEs and all work can be performed there.
+
+ The project files will expose as much information as possible to the IDE and will use \QBS to
+ perform the actual build. \note You cannot modify build system files and expect the changes
+ to be reflected in \QBS; you must edit your \QBS project files and re-run \c{qbs-generate} in
+ order for the changes to be reflected in your IDE.
+
+ \section1 Limitations
+
+ Due to the high flexibility of the Qbs project format and build engine, some projects may be too
+ complex to produce an equivalent project file for another build system.
+
+ This list of limitations aims to be as small as possible, but one of the most notable (at least
+ for the Visual Studio generator) is that certain properties must contain the same
+ value across all build configurations. For example, the following is not allowed:
+
+ \code
+ Product {
+ // ERROR: 'name' property cannot have different values based on the configuration
+ name: qbs.configuration === "debug"
+ ? "MyProduct_debug"
+ : "MyProduct"
+ }
+ \endcode
+
+ Note that this limitation only applies when property values are varied on the configuration
+ name. For example, the following is OK (as long as the value of xyz itself does not vary across
+ configurations):
+
+ \code
+ Product {
+ // OK
+ property bool isDebug: <some value>
+ name: isDebug ? "MyProduct_debug" : "MyProduct"
+ }
+ \endcode
+
+ The properties to which the limitation applies includes but is not limited to:
+
+ \list
+ \li \l{Product Item}{Product}.name
+ \li \l{Module bundle}{bundle}.isBundle
+ \endlist
+
+ If a simple workaround is possible in a particular case (e.g. varying Product.targetName across
+ configuration instead of Product.name), the generator will typically suggest it in the error
+ message.
+*/
diff --git a/doc/reference/commands.qdoc b/doc/reference/commands.qdoc
index 8e8229ca9..ce2330ffc 100644
--- a/doc/reference/commands.qdoc
+++ b/doc/reference/commands.qdoc
@@ -145,6 +145,13 @@
\li The binary to invoke. Explicitly setting this property overrides a path provided when
instantiating the object.
\row
+ \li \c relevantEnvironmentVariables
+ \li stringList
+ \li undefined
+ \li Names of environment variables that the invoked binary considers.
+ If one of these variables changes in the build environment, the command will be
+ re-run even if the input files are still up to date.
+ \row
\li \c responseFileThreshold
\li int
\li 32000 on Windows, -1 elsewhere
diff --git a/doc/reference/items/convenience/androidapk.qdoc b/doc/reference/items/convenience/androidapk.qdoc
index 17496bbc3..c3cce0ea1 100644
--- a/doc/reference/items/convenience/androidapk.qdoc
+++ b/doc/reference/items/convenience/androidapk.qdoc
@@ -27,7 +27,7 @@
/*!
\contentspage list-of-convenience-items.html
\page androidapk-item.html
- \nextpage application-item.html
+ \nextpage applediskimage-item.html
\ingroup list-of-convenience-items
\ingroup list-of-items
diff --git a/doc/reference/items/convenience/appleapplicationdiskimage.qdoc b/doc/reference/items/convenience/appleapplicationdiskimage.qdoc
new file mode 100644
index 000000000..7612d60bf
--- /dev/null
+++ b/doc/reference/items/convenience/appleapplicationdiskimage.qdoc
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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
+ \page appleapplicationdiskimage-item.html
+ \previouspage applediskimage-item.html
+ \nextpage application-item.html
+ \ingroup list-of-convenience-items
+ \ingroup list-of-items
+
+ \title AppleApplicationDiskImage Item
+ \brief Represents a product that is an Apple application drag 'n' drop disk image installer.
+
+ An \c AppleApplicationDiskImage item is a convenience item that has a dependency on the
+ \l{Module dmg}{DMG module} and whose type is \c{["dmg.dmg"]}, and also has rules and properties
+ specific to building drag 'n' drop disk image installers with an application bundle and symbolic
+ link to the /Applications directory.
+
+ Any artifacts of product dependencies which are tagged \c{"installable"} will be copied into the
+ disk image, provided their file paths are relative to the path specified by the \c{sourceBase}
+ property (i.e. are located in that directory). Any artifacts tagged \c{"installable"} and which
+ are not relative to \c{sourceBase} will be ignored.
+
+ Here is what the project file could look like for a simple DMG installer:
+ \code
+ import qbs
+
+ AppleApplicationDiskImage {
+ Depends { name: "myapp" }
+ name: "My App"
+ dmg.volumeName: name
+ dmg.iconSize: 128
+ dmg.windowWidth: 640
+ dmg.windowHeight: 280
+ dmg.iconPositions: [
+ {"path": "Applications", "x": 128, "y": 128},
+ {"path": "My App.app", "x": 256, "y": 128}
+ ]
+ files: ["background.tiff", "volume-icon.icns"]
+ Group {
+ files: ["*.lproj/**"] // licenses
+ fileTags: ["dmg.license.input"]
+ }
+ }
+ \endcode
+
+ For plain disk images whose contents are not a single application bundle, consider the base
+ \l{AppleDiskImage Item}{AppleDiskImage} item instead.
+
+ \section1 AppleApplicationDiskImage Properties
+ The following properties are available in addition to the ones inherited from \c AppleDiskImage.
+
+ \table
+ \header
+ \li Property
+ \li Type
+ \li Since
+ \li Default
+ \li Description
+ \row
+ \li sourceBase
+ \li \c{string}
+ \li 1.9
+ \li /Applications
+ \li The base directory from which artifacts installed into the disk image will be copied.
+ This directory is always considered to be relative to \c{qbs.installRoot}.
+ For example, if the application Example.app exists at
+ \c{qbs.installRoot}/Applications/Example.app, and \c{sourceBase} is
+ \c{/Applications}, the application will be located at /Example.app
+ relative to the disk image root, and therefore its full path when the disk image is
+ mounted would be something like /Volumes/Example-1.0/Example.app.
+ \row
+ \li symlinks
+ \li \c{stringList}
+ \li 1.9
+ \li \c{["/Applications:Applications"]}
+ \li List of symlinks to create in the disk image. This is specified as a list of strings,
+ each string containing two file paths separated by a colon. The first path is the
+ symlink target, and the second path is the name of the symlink relative to the root of
+ the disk image.
+ \endtable
+*/
diff --git a/doc/reference/items/convenience/applediskimage.qdoc b/doc/reference/items/convenience/applediskimage.qdoc
new file mode 100644
index 000000000..ffd335212
--- /dev/null
+++ b/doc/reference/items/convenience/applediskimage.qdoc
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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
+ \page applediskimage-item.html
+ \previouspage androidapk-item.html
+ \nextpage appleapplicationdiskimage-item.html
+ \ingroup list-of-convenience-items
+ \ingroup list-of-items
+
+ \title AppleDiskImage Item
+ \brief Represents a product that is an Apple disk image.
+
+ An \c AppleDiskImage item is a convenience item that has a dependency on the
+ \l{Module dmg}{DMG module} and whose type is \c{["dmg.dmg"]}.
+
+ For single-application drag 'n' drop disk image installers, you'll probably want to use the
+ \l{AppleApplicationDiskImage Item}{AppleApplicationDiskImage} item instead.
+*/
diff --git a/doc/reference/items/convenience/application.qdoc b/doc/reference/items/convenience/application.qdoc
index 1a13724b1..d254e84ee 100644
--- a/doc/reference/items/convenience/application.qdoc
+++ b/doc/reference/items/convenience/application.qdoc
@@ -27,7 +27,7 @@
/*!
\contentspage list-of-convenience-items.html
\page application-item.html
- \previouspage androidapk-item.html
+ \previouspage appleapplicationdiskimage-item.html
\nextpage applicationextension-item.html
\ingroup list-of-convenience-items
\ingroup list-of-items
diff --git a/doc/reference/items/language/depends.qdoc b/doc/reference/items/language/depends.qdoc
index 74f3befc6..66627c9e2 100644
--- a/doc/reference/items/language/depends.qdoc
+++ b/doc/reference/items/language/depends.qdoc
@@ -62,6 +62,32 @@
\endcode
+ \section1 Dependency Parameters
+
+ Sometimes it is desirable to have certain dependencies handled differently
+ than others. For example, one might want to depend on a dynamic library
+ without linking it.
+
+ This can be done by setting the parameter \c{cpp.link} to \c{true} in the
+ dynamic library dependency:
+ \code
+ Product {
+ Depends { name: "cpp" }
+ Depends { name: "some_dynamic_lib"; cpp.link: false }
+
+ // ...
+ }
+ \endcode
+
+ Dependency parameters are a special type of property that can only be set
+ within \c{Depends} and \c{Parameters} items. Dependency parameters are
+ declared in the modules they belong to.
+
+ In the example above, the \c{cpp} module declares the parameter \c{link}.
+ The \c{Depends} item for \e{some_dynamic_lib} sets \c{cpp.link} to
+ \c{false}, which tells the linker rule to ignore this particular dependency.
+
+
\section1 Depends Properties
\table
diff --git a/doc/reference/items/language/module.qdoc b/doc/reference/items/language/module.qdoc
index 8b6c5ca9b..a9e9ebd44 100644
--- a/doc/reference/items/language/module.qdoc
+++ b/doc/reference/items/language/module.qdoc
@@ -28,7 +28,7 @@
\contentspage list-of-language-items.html
\previouspage group-item.html
\page module-item.html
- \nextpage probe-item.html
+ \nextpage parameter-item.html
\ingroup list-of-language-items
\ingroup list-of-items
@@ -146,6 +146,41 @@
\endcode
+ \section1 Dependency Parameters
+
+ Modules can declare dependency parameters. Those parameters can be set
+ within \c{Depends} items. Rules of the module can read the parameters of
+ dependencies and act accordingly.
+
+ In the following example, the module \e{foo} declares the parameter
+ \c{ignore}. A dependency to \c{bar} then sets the parameter \c{foo.ignore}
+ to \c{true}. A rule in \c{foo} ignores all dependencies that have
+ \c{foo.ignore} set to true.
+
+ \code
+ Module { // Definition of module 'foo'.
+ Parameter { property bool ignore }
+ Rule {
+ ...
+ prepare: {
+ for (i in product.dependencies) {
+ var dep = product.dependencies[i];
+ if (dep.foo.ignore)
+ continue;
+ // Do something with the dependency.
+ }
+ }
+ }
+ ...
+ }
+ ----------
+ Product {
+ Depends { name: "foo" }
+ Depends { name: "bar"; foo.ignore: true }
+ }
+ \endcode
+
+
\section1 Module Properties
\table
diff --git a/doc/reference/items/language/parameter.qdoc b/doc/reference/items/language/parameter.qdoc
new file mode 100644
index 000000000..168a7ce0d
--- /dev/null
+++ b/doc/reference/items/language/parameter.qdoc
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** 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-language-items.html
+ \previouspage module-item.html
+ \page parameter-item.html
+ \nextpage parameters-item.html
+ \ingroup list-of-language-items
+ \ingroup list-of-items
+
+ \title Parameter Item
+ \brief Declares a dependency parameter.
+
+ The \c{Parameter} item declares a dependency parameter.
+ This item can only appear within \c{Module}
+ items and \c{Export} items.
+
+ The \c{Parameter} item contains exactly one property declaration.
+
+ Example:
+ \code
+ Module {
+ Parameter { property string extra }
+ }
+ \endcode
+
+ The \l{Module Item#dependency-parameters}{\c{Module} item page}
+ has more information about dependency parameters.
+*/
diff --git a/doc/reference/items/language/parameters.qdoc b/doc/reference/items/language/parameters.qdoc
new file mode 100644
index 000000000..d7143290a
--- /dev/null
+++ b/doc/reference/items/language/parameters.qdoc
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** 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-language-items.html
+ \previouspage parameter-item.html
+ \page parameters-item.html
+ \nextpage probe-item.html
+ \ingroup list-of-language-items
+ \ingroup list-of-items
+
+ \title Parameters Item
+ \brief Defines default values for dependency parameters within
+ \c{Export} items.
+
+ The \c{Parameters} item defines default values for dependency
+ parameters within \c{Export} items.
+
+ Example:
+ \code
+ DynamicLibrary {
+ name: "foo"
+ ...
+ Export {
+ ...
+ Parameters {
+ cpp.link: false
+ }
+ }
+ }
+ \endcode
+
+ Every dependency on \e{foo} has the parameter \c{cpp.link} set to
+ \c{false} by default.
+
+ This can be overridden explicitly:
+ \code
+ Depends { name: "foo"; cpp.link: true }
+ \endcode
+
+ The parameters item contains a number of property bindings where
+ each property must be a \l{Parameter Item}{properly declared}
+ \l{Module Item#dependency_parameters}{dependency parameter}.
+*/
diff --git a/doc/reference/items/language/probe.qdoc b/doc/reference/items/language/probe.qdoc
index 50fe271e1..89683086c 100644
--- a/doc/reference/items/language/probe.qdoc
+++ b/doc/reference/items/language/probe.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
\contentspage list-of-language-items.html
- \previouspage module-item.html
+ \previouspage parameters-item.html
\page probe-item.html
\nextpage product-item.html
\ingroup list-of-language-items
diff --git a/doc/reference/items/language/product.qdoc b/doc/reference/items/language/product.qdoc
index 5b960305d..3b317143c 100644
--- a/doc/reference/items/language/product.qdoc
+++ b/doc/reference/items/language/product.qdoc
@@ -107,15 +107,6 @@
To change the name of your product's target artifact, modify \c{Product.targetName}
instead.
\row
- \li profiles
- \li stringList
- \li \c{[project.profile]}
- \li The profiles for which the product should be built. For each profile listed here,
- one instance of the product will be built according to the properties set in
- the respective profile.
- This property is only relevant for projects that require products being built for
- different architectures. Otherwise it can be left at its default value.
- \row
\li type
\li stringList
\li empty list
@@ -169,6 +160,37 @@
Info.plist files in Apple application and framework bundles, for example.
\endtable
+ The following properties are relevant for product multiplexing only.
+ Unless multiplexing is desired, they can be left at their default values.
+
+ \note We do not promise backwards compatibility for multiplexing properties as they are likely
+ to change in future \QBS versions.
+
+ \table
+ \header
+ \li Property
+ \li Type
+ \li Default
+ \li Description
+ \row
+ \li aggregate
+ \li bool
+ \li \c{undefined}
+ \li If \c{true}, an aggregate product will be created that has dependencies on all
+ multiplex instances of this product.
+ \row
+ \li multiplexedType
+ \li stringList
+ \li \c{undefined}
+ \li Specifies the product type for the multiplexed product instances.
+ \row
+ \li multiplexByQbsProperties
+ \li stringList
+ \li \c{["profiles"]}
+ \li Specifies which properties of the qbs module will be used for product multiplexing.
+ Its value must be a subset of \c{["architectures", "buildVariants", "profiles"]}.
+ \endtable
+
The following properties are automatically set by \QBS and cannot be changed by the user:
\table
@@ -182,11 +204,6 @@
\li The build directory for this product. This is the directory where generated files
are placed.
\row
- \li profile
- \li string
- \li The profile for building this particular instance of the product. Derived
- automatically from the \c profiles property.
- \row
\li sourceDirectory
\li path
\li The source directory for this product. This is the directory of the file where this
diff --git a/doc/reference/items/language/rule.qdoc b/doc/reference/items/language/rule.qdoc
index eff9a95ff..64ab142c6 100644
--- a/doc/reference/items/language/rule.qdoc
+++ b/doc/reference/items/language/rule.qdoc
@@ -213,6 +213,8 @@
that produces artifacts that are compatible with \a{auxiliaryInputs}.
Unlike \a{inputs}, the property \a{auxiliaryInputs} has no effect on the content of the
\a{inputs} variable in the \a{prepare} script.
+ All rules in this product and rules of product dependencies that produce target
+ artifacts are considered.
\row
\li excludedAuxiliaryInputs
\li string list
@@ -271,7 +273,8 @@
\li string list
\li undefined
\li Each artifact that matches the file tags in \a explicitlyDependsOn
- is added to the dependencies of each output node.
+ is added to the dependencies of each output node. All artifacts in the current product
+ and target artifact of products that this product depends on are considered.
\row
\li prepare
\li script
@@ -282,6 +285,14 @@
The argument \c{input} is \c{undefined} if there's more than one input artifact for this
rule. Similarly, \c{output} is only defined if there's exactly one output artifact.
\row
+ \li requiresInputs
+ \li bool
+ \li \c true if the rule declares any inputs, \c false otherwise
+ \li Specifies whether a rule's commands should be created even if no inputs are available.
+ Enabling this property can be useful in cases where you potentially have input files,
+ but it is possible that there are none and you want to create the output file in
+ any case.
+ \row
\li alwaysRun
\li bool
\li false
diff --git a/doc/reference/modules/android-ndk-module.qdoc b/doc/reference/modules/android-ndk-module.qdoc
index e341ddb3d..006d7e5a6 100644
--- a/doc/reference/modules/android-ndk-module.qdoc
+++ b/doc/reference/modules/android-ndk-module.qdoc
@@ -48,7 +48,7 @@
Project {
DynamicLibrary {
name: "hello-jni"
- architectures: ["mips", "x86"]
+ qbs.architectures: ["mips", "x86"]
files: ["jni/hello-jni.c"]
}
diff --git a/doc/reference/modules/cpp-module.qdoc b/doc/reference/modules/cpp-module.qdoc
index a65eb659f..46c38b4cd 100644
--- a/doc/reference/modules/cpp-module.qdoc
+++ b/doc/reference/modules/cpp-module.qdoc
@@ -443,6 +443,12 @@
\li determined by qbs-setup-toolchains
\li Full path of the dsymutil binary. This is set in the build profile.
\row
+ \li lipoPath
+ \li \c{string}
+ \li 1.9
+ \li determined automatically
+ \li Full path of the lipo binary.
+ \row
\li frameworkPaths
\li \c{pathList}
\li 1.0
@@ -665,7 +671,7 @@
\li useRPathLink
\li \c{bool}
\li 1.8
- \li \c{true} on non-Darwin Unix platforms.
+ \li \c{true} on non-Darwin Unix platforms or when targeting macOS 10.4.x and older.
\li Use the \c{-rpath-link} linker option for transitive shared objects.
\row
\li visibility
@@ -724,6 +730,13 @@
\li Default
\li Description
\row
+ \li alwaysUseLipo
+ \li \{bool}
+ \li 1.9
+ \li \c{false}
+ \li Whether to always use lipo when combining Mach-O output files on Apple platforms,
+ even if there is only one CPU architecture. The should not normally need to be changed.
+ \row
\li compilerDefines
\li \c{stringList}
\li 1.0
@@ -781,6 +794,43 @@
User project files should not set this property.
\endtable
+
+ \section1 Dependency Parameters
+
+ \table
+ \header
+ \li Parameter
+ \li Type
+ \li Since
+ \li Default
+ \li Description
+ \row
+ \li \c{link}
+ \li \c{bool}
+ \li 1.9
+ \li undefined
+ \li If \c{false}, the dependency will not be linked, even if
+ it is a valid input for a linker rule. This property
+ affects library dependencies only.
+ \row
+ \li \c{linkWholeArchive}
+ \li \c{bool}
+ \li 1.9
+ \li undefined
+ \li If \c{true}, then if the dependency is a static library, all of its objects
+ will be pulled into target binary, even if their symbols do not appear to be used.
+ This parameter is mainly useful when creating a dynamic library from static libraries.
+ \row
+ \li \c{symbolLinkMode}
+ \li \c{string}
+ \li 1.9
+ \li undefined
+ \li Attribute specifying how the library or framework will be linked.
+ May contain the values: "weak", "lazy", "reexport", and "upward"; refer to the Apple
+ ld64 man page for full details. \c{undefined} uses normal linking.
+ Currently only applies when linking for Apple platforms.
+ \endtable
+
\section1 Relevant File Tags
\table
diff --git a/doc/reference/modules/dmg-module.qdoc b/doc/reference/modules/dmg-module.qdoc
new file mode 100644
index 000000000..6a11e6c4b
--- /dev/null
+++ b/doc/reference/modules/dmg-module.qdoc
@@ -0,0 +1,342 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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
+ \page dmg-module.html
+ \ingroup list-of-modules
+
+ \title Module dmg
+ \since 1.9
+ \brief Provides support for building Apple Disk Images
+
+ The \c dmg module contains properties and rules for building Apple Disk Images, which are
+ typically used to distribute applications and installers on macOS.
+
+ This module is only available on Apple platforms.
+
+ \section1 General Properties
+
+ \table
+ \header
+ \li Property
+ \li Type
+ \li Since
+ \li Default
+ \li Description
+ \row
+ \li volumeName
+ \li \c{string}
+ \li 1.9
+ \li \c{product.targetName}
+ \li The name of the disk image which displayed in Finder when the DMG is mounted.
+ \row
+ \li badgeVolumeIcon
+ \li \c{bool}
+ \li 1.9
+ \li \c{false}
+ \li Whether to render the user-supplied icon (see the \c{"icns"} file tag documentation)
+ on top of the default volume icon instead of using it directly. This generally gives
+ the disk image icon a better and more consistent appearance.
+ \row
+ \li format
+ \li \c{string}
+ \li 1.9
+ \li \c{"UDBZ"}
+ \li The format to create the disk image in.
+ Allowed values include but are not limited to \c{"UDZO"}, \c{"UDBZ"} and \c{"ULFO"}.
+ \row
+ \li compressionLevel
+ \li \c{int}
+ \li 1.9
+ \li 9 in release mode, otherwise undefined
+ \li Sets the zlib, bzip2, or lzfse compression level for UDZO, UDBZ, or ULFO disk images.
+ \row
+ \li sourceBase
+ \li \c{string}
+ \li 1.9
+ \li \c{undefined}
+ \li Specifies the base directory of the files that are going to be embedded in the DMG
+ (see the \c{"dmg.input"} file tag documentation). The source base directory is omitted
+ from the target directory path of the DMG directory.
+ The default value of this property is the directory of the current file
+ to be embedded, relative to the product's source directory.
+ \endtable
+
+ \section1 Appearance Properties
+
+ Properties in this section are used to control the contents of the .DS_Store file and its
+ embedded Alias and Bookmark records, that will be generated by \QBS in order to control the
+ appearance of the disk image when mounted in Finder.
+
+ \table
+ \header
+ \li Property
+ \li Type
+ \li Since
+ \li Default
+ \li Description
+ \row
+ \li backgroundColor
+ \li \c{string}
+ \li 1.9
+ \li \c{undefined}
+ \li Specifies the background color of the disk image as seen when mounted in Finder.
+ Refer to the \l{https://dmgbuild.readthedocs.io/en/latest/settings.html#background}
+ {dmgbuild documentation}
+ for the full list of supported color names and formats.
+ To use an image for the background instead,
+ refer to the \c{"tiff"} file tag documentation.
+ \row
+ \li iconSize
+ \li \c{int}
+ \li 1.9
+ \li \c{128}
+ \li Specifies the width and height of the file icons as seen when the disk image is mounted
+ in Finder.
+ \row
+ \li windowX
+ \li \c{int}
+ \li 1.9
+ \li \c{100}
+ \li Specifies the X position of the Finder window that displays the disk image contents
+ when it is mounted.
+ \row
+ \li windowY
+ \li \c{int}
+ \li 1.9
+ \li \c{100}
+ \li Specifies the Y position of the Finder window that displays the disk image contents
+ when it is mounted.
+ \row
+ \li windowWidth
+ \li \c{int}
+ \li 1.9
+ \li \c{640}
+ \li Specifies the width of the Finder window that displays the disk image contents
+ when it is mounted.
+ \row
+ \li windowHeight
+ \li \c{int}
+ \li 1.9
+ \li \c{480}
+ \li Specifies the height of the Finder window that displays the disk image contents
+ when it is mounted. Note that the window height includes the height of the standard
+ macOS title bar (22 points).
+ \row
+ \li iconPositions
+ \li \c{list}
+ \li 1.9
+ \li \c{undefined}
+ List of objects containing \c{path}, \c{x}, and \c{y} properties, which correspond to
+ disk image-relative file paths and visual coordinates of file icons in the disk image
+ as seen when it is mounted in Finder. For example:
+ \code
+ dmg.iconPositions: [
+ {"path": "Applications", "x": 128, "y": 128},
+ {"path": "Foo Bar.app", "x": 256, "y": 128}
+ ]
+ \endcode
+ This property is useful for specifying the positions of files where you do not have
+ direct control over the corresponding \QBS artifact, or there is no corresponding \QBS
+ artifact (for example, "Foo Bar.app" is a directory, which has no equivalent artifact in
+ the build graph). For files to which you are directly applying the \c{dmg.input} file
+ tag, you should use the \c{dmg.iconX} and \c{dmg.iconY} properties instead.
+ \row
+ \li iconX
+ \li \c{int}
+ \li 1.9
+ \li \c{windowWidth / 2}
+ \li X position of the file icon in the Finder window that displayed the disk image contents
+ when it is mounted. This property is only useful with artifacts tagged \c{dmg.input} and
+ cannot be used at the product level to affect all files.
+ If you do not have access to the artifact corresponding to the file whose position you
+ want to set, use the \c{dmg.iconPositions} property instead.
+ \row
+ \li iconY
+ \li \c{int}
+ \li 1.9
+ \li \c{windowHeight / 2}
+ \li Y position of the file icon in the Finder window that displayed the disk image contents
+ when it is mounted. This property is only useful with artifacts tagged \c{dmg.input} and
+ cannot be used at the product level to affect all files.
+ If you do not have access to the artifact corresponding to the file whose position you
+ want to set, use the \c{dmg.iconPositions} property instead.
+ \endtable
+
+ \section1 License Properties
+
+ Properties in this section are used to control the content and appearance of the license prompt
+ displayed when a user attempts to mount the resulting disk image via Finder.
+
+ \table
+ \header
+ \li Property
+ \li Type
+ \li Since
+ \li Default
+ \li Description
+ \row
+ \li defaultLicenseLocale
+ \li \c{string}
+ \li 1.9
+ \li \c{"en_US"}
+ \li Locale of the default license to display when there is no license whose locale matches
+ the system locale.
+ \row
+ \li licenseLocale
+ \li \c{string}
+ \li 1.9
+ \li determined automatically
+ \li Locale of the license file. Defaults to a value guess from the file path, specifically
+ the base name of any .lproj directory found in the file's path. If the locale could not
+ be determined from the file path and this property is not set, an error will be emitted.
+ This property is only useful with artifacts tagged \c{dmg.license.input} and
+ cannot be used at the product level to affect all files.
+ \row
+ \li licenseLanguageName
+ \li \c{string}
+ \li 1.9
+ \li \c{"English"}
+ \li Name of the language associated with the license file, localized for that language.
+ This property is only useful with artifacts tagged \c{dmg.license.input} and
+ cannot be used at the product level to affect all files.
+ \row
+ \li licenseAgreeButtonText
+ \li \c{string}
+ \li 1.9
+ \li \c{"Agree"}
+ \li Text shown on the "Agree" button associated with the license file,
+ localized for that language.
+ This property is only useful with artifacts tagged \c{dmg.license.input} and
+ cannot be used at the product level to affect all files.
+ \row
+ \li licenseDisagreeButtonText
+ \li \c{string}
+ \li 1.9
+ \li \c{"Disagree"}
+ \li Text shown on the "Disagree" button associated with the license file,
+ localized for that language.
+ This property is only useful with artifacts tagged \c{dmg.license.input} and
+ cannot be used at the product level to affect all files.
+ \row
+ \li licensePrintButtonText
+ \li \c{string}
+ \li 1.9
+ \li \c{"Print"}
+ \li Text shown on the "Print" button associated with the license file,
+ localized for that language.
+ This property is only useful with artifacts tagged \c{dmg.license.input} and
+ cannot be used at the product level to affect all files.
+ \row
+ \li licenseSaveButtonText
+ \li \c{string}
+ \li 1.9
+ \li \c{"Save"}
+ \li Text shown on the "Save" button associated with the license file,
+ localized for that language.
+ This property is only useful with artifacts tagged \c{dmg.license.input} and
+ cannot be used at the product level to affect all files.
+ \row
+ \li licenseInstructionText
+ \li \c{string}
+ \li 1.9
+ \li \c{"If you agree with the terms of this license, press \"Agree\" to install the software. If you do not agree, press \"Disagree\"."}
+ \li Instruction text associated with the license file that will be shown on the license
+ dialog, localized for that language.
+ This property is only useful with artifacts tagged \c{dmg.license.input} and
+ cannot be used at the product level to affect all files.
+ \endtable
+
+ \section1 Advanced Properties
+
+ \table
+ \header
+ \li Property
+ \li Type
+ \li Since
+ \li Default
+ \li Description
+ \row
+ \li dmgSuffix
+ \li \c{string}
+ \li 1.9
+ \li \c{".dmg"}
+ \li File extension for disk images.
+ This should not normally need to be changed.
+ \row
+ \li hdiutilPath
+ \li \c{string}
+ \li 1.9
+ \li \c{"/usr/bin/hdiutil"}
+ \li Path to the hdiutil binary used to perform disk image related operations.
+ This should not normally need to be changed.
+ \row
+ \li textutilPath
+ \li \c{string}
+ \li 1.9
+ \li \c{"/usr/bin/textutil"}
+ \li Path to the textutil binary used to convert license agreement files to rich text format.
+ This should not normally need to be changed.
+ \endtable
+
+ \section1 Relevant File Tags
+
+ \table
+ \header
+ \li Tag
+ \li Auto-tagged File Names
+ \li Since
+ \li Description
+ \row
+ \li \c{"dmg.input"}
+ \li n/a
+ \li 1.9
+ \li If the product contains files with this tag, they will be copied into the disk image.
+ See the \c{sourceBase} property to learn how to control the destination directory and
+ hierarchy of copied files within the disk image.
+ \row
+ \li \c{"dmg.license.input"}
+ \li \c{*.txt}, \c{*.rtf}, \c{*.html}, \c{*.doc}, \c{*.docx}, \c{*.odt}, \c{*.xml},
+ \c{*.webarchive}
+ \li 1.9
+ \li If the product contains files with this tag, they will be converted into rich text and
+ used for the license prompt when mounting the DMG.
+ \row
+ \li \c{"icns"}
+ \li \c{*.icns}
+ \li 1.3
+ \li If the product contains a file with this tag, it will be added as the Apple Disk Image
+ volume icon, which will show up in the Finder as an overlay on the file icon.
+ \row
+ \li \c{"tiff"}
+ \li \c{*.tif}, \c{*.tiff}
+ \li 1.9
+ \li If the product contains a file with this tag, it will be used as the background image
+ of the directory as shown in Finder when the DMG file is mounted.
+ \endtable
+*/
diff --git a/doc/reference/modules/qbs-module.qdoc b/doc/reference/modules/qbs-module.qdoc
index afca54da1..a0260b521 100644
--- a/doc/reference/modules/qbs-module.qdoc
+++ b/doc/reference/modules/qbs-module.qdoc
@@ -321,7 +321,42 @@
in that it must not be visible to the code being built. In fact, the install root is
often just a temporary location used to package the binaries, which should therefore not
assume they will be in that location at run-time. For the same reason, this property
- must not be set from within project files.
+ is usually not set from within project files.
+ \endtable
+
+ \section1 Multiplexing Properties
+
+ This section lists properties specific to product multiplexing.
+
+ \table
+ \header
+ \li Property
+ \li Type
+ \li Since
+ \li Default
+ \li Description
+ \row
+ \li architectures
+ \li \c{stringList}
+ \li 1.9
+ \li \c{["armv5te"]} on Android, same as Xcode on Apple platforms, otherwise equivalent to
+ \c{[qbs.architecture]}
+ \li Specifies the architectures the product will be built for.
+ \row
+ \li buildVariants
+ \li \c{stringList}
+ \li 1.9
+ \li equivalent to \c{[qbs.buildVariant]}
+ \li Specifies the build variants the product will be built for.
+ \row
+ \li profiles
+ \li \c{stringList}
+ \li 1.9
+ \li \c{[product.profile]}
+ \li The profiles for which the product should be built. For each profile listed here,
+ one instance of the product will be built according to the properties set in
+ the respective profile.
+ This property is the same as \c{product.profiles}, which takes precedence.
\endtable
*/
diff --git a/doc/reference/reference.qdoc b/doc/reference/reference.qdoc
index ffe2b2745..5677b6844 100644
--- a/doc/reference/reference.qdoc
+++ b/doc/reference/reference.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
\contentspage index.html
- \previouspage shell.html
+ \previouspage howtos.html
\page reference.html
\title Reference
diff --git a/docker/windowsservercore/Dockerfile b/docker/windowsservercore/Dockerfile
new file mode 100644
index 000000000..db4c8e14c
--- /dev/null
+++ b/docker/windowsservercore/Dockerfile
@@ -0,0 +1,27 @@
+FROM microsoft/windowsservercore:10.0.14393.1198
+LABEL Description="Windows Server Core development environment for Qbs with Qt 5.8, Chocolatey and various dependencies for testing Qbs modules and functionality"
+
+COPY qtifwsilent.qs C:\qtifwsilent.qs
+RUN powershell -NoProfile -ExecutionPolicy Bypass -Command \
+ $ErrorActionPreference = 'Stop'; \
+ wget 'https://download.qt.io/official_releases/qt/5.8/5.8.0/qt-opensource-windows-x86-msvc2015-5.8.0.exe' -OutFile C:\qt32.exe ; \
+ wget 'https://download.qt.io/official_releases/qt/5.8/5.8.0/qt-opensource-windows-x86-msvc2015_64-5.8.0.exe' -OutFile C:\qt64.exe ; \
+ $Env:QT_INSTALL_DIR = 'C:\\Qt_5.8.0_msvc2015' ; Start-Process C:\qt32.exe -ArgumentList '--script C:/qtifwsilent.qs' -Wait ; \
+ $Env:QT_INSTALL_DIR = 'C:\\Qt_5.8.0_msvc2015_64' ; Start-Process C:\qt64.exe -ArgumentList '--script C:/qtifwsilent.qs' -Wait ; \
+ Remove-Item C:\qt32.exe -Force ; \
+ Remove-Item C:\qt64.exe -Force ; \
+ Remove-Item C:\qtifwsilent.qs -Force
+ENV QTDIR C:\\Qt_5.8.0_msvc2015\\5.8\\msvc2015
+ENV QTDIR64 C:\\Qt_5.8.0_msvc2015_64\\5.8\\msvc2015_64
+
+RUN @powershell -NoProfile -ExecutionPolicy Bypass -Command \
+ $Env:chocolateyVersion = '0.10.5' ; \
+ $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 qbs --version 1.8.0
+RUN choco install -y unzip --version 6.0
+RUN choco install -y visualcpp-build-tools --version 14.0.25420.1
+RUN choco install -y zip --version 3.0
+
+# Disable crash dialog for release-mode runtimes
+RUN reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting" /v DontShowUI /t REG_DWORD /d 1 /f
diff --git a/docker/windowsservercore/qtifwsilent.qs b/docker/windowsservercore/qtifwsilent.qs
new file mode 100644
index 000000000..6b087ccde
--- /dev/null
+++ b/docker/windowsservercore/qtifwsilent.qs
@@ -0,0 +1,47 @@
+function Controller() {
+ installer.autoRejectMessageBoxes();
+ installer.installationFinished.connect(function() {
+ gui.clickButton(buttons.NextButton);
+ })
+}
+
+Controller.prototype.WelcomePageCallback = function() {
+ gui.clickButton(buttons.NextButton);
+}
+
+Controller.prototype.CredentialsPageCallback = function() {
+ gui.clickButton(buttons.NextButton);
+}
+
+Controller.prototype.IntroductionPageCallback = function() {
+ gui.clickButton(buttons.NextButton);
+}
+
+Controller.prototype.TargetDirectoryPageCallback = function() {
+ gui.currentPageWidget().TargetDirectoryLineEdit.setText(installer.environmentVariable("QT_INSTALL_DIR"));
+ gui.clickButton(buttons.NextButton);
+}
+
+Controller.prototype.ComponentSelectionPageCallback = function() {
+ gui.clickButton(buttons.NextButton);
+}
+
+Controller.prototype.LicenseAgreementPageCallback = function() {
+ gui.currentPageWidget().AcceptLicenseRadioButton.setChecked(true);
+ gui.clickButton(buttons.NextButton);
+}
+
+Controller.prototype.StartMenuDirectoryPageCallback = function() {
+ gui.clickButton(buttons.NextButton);
+}
+
+Controller.prototype.ReadyForInstallationPageCallback = function() {
+ gui.clickButton(buttons.NextButton);
+}
+
+Controller.prototype.FinishedPageCallback = function() {
+ var checkBoxForm = gui.currentPageWidget().LaunchQtCreatorCheckBoxForm;
+ if (checkBoxForm && checkBoxForm.launchQtCreatorCheckBox)
+ checkBoxForm.launchQtCreatorCheckBox.checked = false;
+ gui.clickButton(buttons.FinishButton);
+}
diff --git a/examples/cocoa-application/CocoaApplication.qbs b/examples/cocoa-application/CocoaApplication.qbs
index 2c26904a8..d0d2affc6 100644
--- a/examples/cocoa-application/CocoaApplication.qbs
+++ b/examples/cocoa-application/CocoaApplication.qbs
@@ -36,39 +36,18 @@
**
****************************************************************************/
-import qbs 1.0
+import qbs
+import qbs.Utilities
-CppApplication {
- Depends { condition: product.condition; name: "ib" }
- condition: qbs.targetOS.contains("macos")
- name: "Cocoa Application"
+Project {
+ references: [
+ "app.qbs"
+ ]
- cpp.useObjcPrecompiledHeader: true
-
- cpp.frameworks: ["Cocoa"]
-
- Group {
- prefix: "CocoaApplication/"
- files: [
- "AppDelegate.h",
- "AppDelegate.m",
- "CocoaApplication-Info.plist",
- "main.m"
- ]
- }
-
- Group {
- name: "Supporting Files"
- prefix: "CocoaApplication/en.lproj/"
- files: [
- "Credits.rtf",
- "InfoPlist.strings",
- "MainMenu.xib"
- ]
- }
-
- Group {
- files: ["CocoaApplication/CocoaApplication-Prefix.pch"]
- fileTags: ["objc_pch_src"]
+ SubProject {
+ filePath: "dmg.qbs"
+ Properties {
+ condition: Utilities.versionCompare(qbs.version, "1.9") >= 0
+ }
}
}
diff --git a/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/Contents.json b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 000000000..7cd4f8e12
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,68 @@
+{
+ "images" : [
+ {
+ "size" : "16x16",
+ "idiom" : "mac",
+ "filename" : "icon_16x16.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "16x16",
+ "idiom" : "mac",
+ "filename" : "icon_16x16@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "32x32",
+ "idiom" : "mac",
+ "filename" : "icon_32x32.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "32x32",
+ "idiom" : "mac",
+ "filename" : "icon_32x32@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "128x128",
+ "idiom" : "mac",
+ "filename" : "icon_128x128.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "128x128",
+ "idiom" : "mac",
+ "filename" : "icon_128x128@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "256x256",
+ "idiom" : "mac",
+ "filename" : "icon_256x256.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "256x256",
+ "idiom" : "mac",
+ "filename" : "icon_256x256@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "512x512",
+ "idiom" : "mac",
+ "filename" : "icon_512x512.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "512x512",
+ "idiom" : "mac",
+ "filename" : "icon_512x512@2x.png",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_128x128.png b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_128x128.png
new file mode 100644
index 000000000..6c556a835
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_128x128.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_128x128@2x.png
new file mode 100644
index 000000000..4442d3eb2
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_128x128@2x.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_16x16.png b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_16x16.png
new file mode 100644
index 000000000..2adcdb5f4
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_16x16.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_16x16@2x.png
new file mode 100644
index 000000000..2a7030fd7
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_16x16@2x.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_256x256.png b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_256x256.png
new file mode 100644
index 000000000..4442d3eb2
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_256x256.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_256x256@2x.png
new file mode 100644
index 000000000..069b5c050
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_256x256@2x.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_32x32.png b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_32x32.png
new file mode 100644
index 000000000..2a7030fd7
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_32x32.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_32x32@2x.png
new file mode 100644
index 000000000..c5e458164
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_32x32@2x.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_512x512.png b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_512x512.png
new file mode 100644
index 000000000..069b5c050
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_512x512.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_512x512@2x.png
new file mode 100644
index 000000000..0b810615e
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/CocoaApplication.xcassets/AppIcon.appiconset/icon_512x512@2x.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/background.png b/examples/cocoa-application/CocoaApplication/background.png
new file mode 100644
index 000000000..938dc0c04
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/background.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/background@2x.png b/examples/cocoa-application/CocoaApplication/background@2x.png
new file mode 100644
index 000000000..099e9d830
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/background@2x.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_128x128.png b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_128x128.png
new file mode 100644
index 000000000..6c556a835
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_128x128.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_128x128@2x.png b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_128x128@2x.png
new file mode 100644
index 000000000..4442d3eb2
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_128x128@2x.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_16x16.png b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_16x16.png
new file mode 100644
index 000000000..2adcdb5f4
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_16x16.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_16x16@2x.png b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_16x16@2x.png
new file mode 100644
index 000000000..2a7030fd7
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_16x16@2x.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_256x256.png b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_256x256.png
new file mode 100644
index 000000000..4442d3eb2
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_256x256.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_256x256@2x.png b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_256x256@2x.png
new file mode 100644
index 000000000..069b5c050
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_256x256@2x.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_32x32.png b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_32x32.png
new file mode 100644
index 000000000..2a7030fd7
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_32x32.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_32x32@2x.png b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_32x32@2x.png
new file mode 100644
index 000000000..c5e458164
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_32x32@2x.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_512x512.png b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_512x512.png
new file mode 100644
index 000000000..069b5c050
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_512x512.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_512x512@2x.png b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_512x512@2x.png
new file mode 100644
index 000000000..0b810615e
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/dmg.iconset/icon_512x512@2x.png
Binary files differ
diff --git a/examples/cocoa-application/CocoaApplication/en.lproj/LICENSE b/examples/cocoa-application/CocoaApplication/en.lproj/LICENSE
new file mode 100644
index 000000000..44650fe73
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/en.lproj/LICENSE
@@ -0,0 +1,27 @@
+Copyright (C) 2017 The Qt Company Ltd.
+
+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 and its Subsidiary(-ies) 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.
diff --git a/examples/cocoa-application/CocoaApplication/en_US.lproj b/examples/cocoa-application/CocoaApplication/en_US.lproj
new file mode 120000
index 000000000..545e7ac76
--- /dev/null
+++ b/examples/cocoa-application/CocoaApplication/en_US.lproj
@@ -0,0 +1 @@
+en.lproj \ No newline at end of file
diff --git a/examples/cocoa-application/app.qbs b/examples/cocoa-application/app.qbs
new file mode 100644
index 000000000..366d49263
--- /dev/null
+++ b/examples/cocoa-application/app.qbs
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of the examples of Qbs.
+**
+** 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 and its Subsidiary(-ies) 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."
+**
+****************************************************************************/
+
+import qbs
+
+CppApplication {
+ Depends { condition: product.condition; name: "ib" }
+ condition: qbs.targetOS.contains("macos")
+ name: "Cocoa Application"
+
+ cpp.useObjcPrecompiledHeader: true
+
+ cpp.frameworks: ["Cocoa"]
+
+ Group {
+ prefix: "CocoaApplication/"
+ files: [
+ "AppDelegate.h",
+ "AppDelegate.m",
+ "CocoaApplication-Info.plist",
+ "CocoaApplication.xcassets",
+ "main.m"
+ ]
+ }
+
+ Group {
+ name: "Supporting Files"
+ prefix: "CocoaApplication/en.lproj/"
+ files: [
+ "Credits.rtf",
+ "InfoPlist.strings",
+ "MainMenu.xib"
+ ]
+ }
+
+ Group {
+ files: ["CocoaApplication/CocoaApplication-Prefix.pch"]
+ fileTags: ["objc_pch_src"]
+ }
+
+ Group {
+ fileTagsFilter: ["bundle.content"]
+ qbs.install: true
+ qbs.installDir: "Applications"
+ qbs.installSourceBase: product.destinationDirectory
+ }
+
+ ib.appIconName: "AppIcon"
+}
diff --git a/examples/cocoa-application/dmg.qbs b/examples/cocoa-application/dmg.qbs
new file mode 100644
index 000000000..e8e0a923a
--- /dev/null
+++ b/examples/cocoa-application/dmg.qbs
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of the examples of Qbs.
+**
+** 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 and its Subsidiary(-ies) 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."
+**
+****************************************************************************/
+
+import qbs
+
+AppleApplicationDiskImage {
+ condition: qbs.targetOS.contains("macos")
+ name: "Cocoa Application DMG"
+ targetName: "cocoa-application-" + version
+ version: "1.0"
+
+ Depends { name: "Cocoa Application" }
+ Depends { name: "ib" }
+
+ files: [
+ "CocoaApplication/dmg.iconset",
+ "CocoaApplication/en_US.lproj/LICENSE",
+ ]
+
+ // set to false to use a solid-color background (see dmg.backgroundColor below)
+ property bool useImageBackground: true
+ Group {
+ condition: useImageBackground
+ files: ["CocoaApplication/background*"]
+ }
+
+ dmg.backgroundColor: "#41cd52"
+ dmg.badgeVolumeIcon: true
+ dmg.iconPositions: [
+ {"x": 200, "y": 200, "path": "Cocoa Application.app"},
+ {"x": 400, "y": 200, "path": "Applications"}
+ ]
+ dmg.windowX: 420
+ dmg.windowY: 250
+ dmg.windowWidth: 600
+ dmg.windowHeight: 422 // this *includes* the macOS title bar height of 22
+ dmg.iconSize: 64
+}
diff --git a/qbs-resources/imports/QbsAutotest.qbs b/qbs-resources/imports/QbsAutotest.qbs
index 66e076677..7fc959394 100644
--- a/qbs-resources/imports/QbsAutotest.qbs
+++ b/qbs-resources/imports/QbsAutotest.qbs
@@ -9,7 +9,10 @@ QtApplication {
Depends { name: "Qt.testlib" }
Depends { name: "qbscore" }
Depends { name: "qbsbuildconfig" }
- cpp.includePaths: "../../../src"
+ cpp.includePaths: [
+ "../../../src",
+ "../../../src/app/shared", // for the logger
+ ]
cpp.cxxLanguageVersion: "c++11"
destinationDirectory: "bin"
Group {
diff --git a/qbs-resources/imports/QbsFunctions/functions.js b/qbs-resources/imports/QbsFunctions/functions.js
deleted file mode 100644
index b50af378a..000000000
--- a/qbs-resources/imports/QbsFunctions/functions.js
+++ /dev/null
@@ -1,18 +0,0 @@
-function qbsVersion() { return "1.8.1"; }
-
-function versionIsAtLeast(actualVersion, expectedVersion)
-{
- var actualVersionParts = actualVersion.split('.').map(function(item) {
- return parseInt(item, 10);
- });
- var expectedVersionParts = expectedVersion.split('.').map(function(item) {
- return parseInt(item, 10);
- });
- for (var i = 0; i < expectedVersionParts.length; ++i) {
- if (actualVersionParts[i] > expectedVersionParts[i])
- return true;
- if (actualVersionParts[i] < expectedVersionParts[i])
- return false;
- }
- return i === expectedVersionParts.length || expectedVersionParts[i] === 0;
-}
diff --git a/qbs-resources/imports/QbsLibrary.qbs b/qbs-resources/imports/QbsLibrary.qbs
index 218da8941..b459b4c8c 100644
--- a/qbs-resources/imports/QbsLibrary.qbs
+++ b/qbs-resources/imports/QbsLibrary.qbs
@@ -1,10 +1,9 @@
import qbs
-import QbsFunctions
QbsProduct {
Depends { name: "cpp" }
Depends { name: "bundle" }
- version: QbsFunctions.qbsVersion()
+ version: qbsversion.version
type: Qt.core.staticBuild ? "staticlibrary" : "dynamiclibrary"
targetName: (qbs.enableDebugCode && qbs.targetOS.contains("windows")) ? (name + 'd') : name
destinationDirectory: qbs.targetOS.contains("windows") ? "bin" : qbsbuildconfig.libDirName
diff --git a/qbs-resources/imports/QbsProduct.qbs b/qbs-resources/imports/QbsProduct.qbs
index fae3336b3..a90037bc6 100644
--- a/qbs-resources/imports/QbsProduct.qbs
+++ b/qbs-resources/imports/QbsProduct.qbs
@@ -1,9 +1,9 @@
import qbs
-import QbsFunctions
Product {
Depends { name: "qbsbuildconfig" }
- Depends { name: "Qt.core" }
+ Depends { name: "qbsversion" }
+ Depends { name: "Qt.core"; versionAtLeast: minimumQtVersion }
property string minimumQtVersion: "5.6.0"
property bool install: true
cpp.defines: {
@@ -15,5 +15,4 @@ Product {
return res;
}
cpp.enableExceptions: true
- condition: QbsFunctions.versionIsAtLeast(Qt.core.version, minimumQtVersion)
}
diff --git a/qbs-resources/modules/qbsversion/qbsversion.qbs b/qbs-resources/modules/qbsversion/qbsversion.qbs
new file mode 100644
index 000000000..ff1fd18f0
--- /dev/null
+++ b/qbs-resources/modules/qbsversion/qbsversion.qbs
@@ -0,0 +1,24 @@
+import qbs
+import qbs.File
+import qbs.FileInfo
+import qbs.TextFile
+
+Module {
+ Probe {
+ id: qbsVersionProbe
+ property var lastModified: File.lastModified(versionFilePath)
+ property string versionFilePath: FileInfo.joinPaths(path, "..", "..", "..", "VERSION")
+ property string version
+ configure: {
+ var tf = new TextFile(versionFilePath, TextFile.ReadOnly);
+ try {
+ version = tf.readAll().trim();
+ found = !!version;
+ } finally {
+ tf.close();
+ }
+ }
+ }
+
+ version: qbsVersionProbe.version
+}
diff --git a/qbs.pro b/qbs.pro
index 43c668c98..5d59d8733 100644
--- a/qbs.pro
+++ b/qbs.pro
@@ -36,6 +36,7 @@ src_app.subdir = src/app
src_app.depends = setupqtprofilelib
src_libexec.subdir = src/libexec
src_plugins.subdir = src/plugins
+CONFIG(shared, static|shared): src_plugins.depends = corelib
tests.depends = corelib src_plugins
SUBDIRS += \
corelib\
diff --git a/qbs.qbs b/qbs.qbs
index e65ca2b11..3a5485cd3 100644
--- a/qbs.qbs
+++ b/qbs.qbs
@@ -25,6 +25,11 @@ Project {
}
Product {
+ name: "version"
+ files: ["VERSION"]
+ }
+
+ Product {
name: "qmake project files for qbs"
files: ["**/*.pr[io]"]
}
diff --git a/qbs_version.pri b/qbs_version.pri
index cfb08b609..97c4c799e 100644
--- a/qbs_version.pri
+++ b/qbs_version.pri
@@ -1,4 +1,4 @@
-QBS_VERSION = 1.8.1
+QBS_VERSION = $$cat($$PWD/VERSION)
QBS_VERSION_MAJ = $$section(QBS_VERSION, ., 0, 0)
QBS_VERSION_MIN = $$section(QBS_VERSION, ., 1, 1)
DEFINES += QBS_VERSION=\\\"$$QBS_VERSION\\\"
diff --git a/make-release-archive.sh b/scripts/make-release-archive.sh
index b554e78fe..b554e78fe 100644
--- a/make-release-archive.sh
+++ b/scripts/make-release-archive.sh
diff --git a/scripts/make-release-archives.bat b/scripts/make-release-archives.bat
new file mode 100644
index 000000000..d4b5301f6
--- /dev/null
+++ b/scripts/make-release-archives.bat
@@ -0,0 +1,75 @@
+@echo off
+
+REM Copyright (C) 2017 The Qt Company Ltd.
+REM Contact: https://www.qt.io/licensing/
+REM
+REM This file is part of Qbs.
+REM
+REM $QT_BEGIN_LICENSE:LGPL$
+REM Commercial License Usage
+REM Licensees holding valid commercial Qt licenses may use this file in
+REM accordance with the commercial license agreement provided with the
+REM Software or, alternatively, in accordance with the terms contained in
+REM a written agreement between you and The Qt Company. For licensing terms
+REM and conditions see https://www.qt.io/terms-conditions. For further
+REM information use the contact form at https://www.qt.io/contact-us.
+REM
+REM GNU Lesser General Public License Usage
+REM Alternatively, this file may be used under the terms of the GNU Lesser
+REM General Public License version 3 as published by the Free Software
+REM Foundation and appearing in the file LICENSE.LGPL3 included in the
+REM packaging of this file. Please review the following information to
+REM ensure the GNU Lesser General Public License version 3 requirements
+REM will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+REM
+REM GNU General Public License Usage
+REM Alternatively, this file may be used under the terms of the GNU
+REM General Public License version 2.0 or (at your option) the GNU General
+REM Public license version 3 or any later version approved by the KDE Free
+REM Qt Foundation. The licenses are as published by the Free Software
+REM Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+REM included in the packaging of this file. Please review the following
+REM information to ensure the GNU General Public License requirements will
+REM be met: https://www.gnu.org/licenses/gpl-2.0.html and
+REM https://www.gnu.org/licenses/gpl-3.0.html.
+REM
+REM $QT_END_LICENSE$
+
+setlocal enabledelayedexpansion || exit /b
+if not exist VERSION ( echo This script must be run from the qbs source directory 1>&2 && exit /b 1 )
+for /f %%j in (VERSION) do ( set "version=!version!%%j," )
+set "version=%version:~0,-1%"
+
+set builddir=%TEMP%\qbs-release-%version%
+if exist "%builddir%" ( del /s /q "%builddir%" || exit /b )
+
+qbs setup-toolchains --settings-dir "%builddir%\.settings" --detect || exit /b
+
+if exist "%QTDIR%" (
+ qbs setup-qt --settings-dir "%builddir%\.settings"^
+ "%QTDIR%\bin\qmake.exe" qt || exit /b
+) else (
+ echo QTDIR environment variable not set or does not exist: %QTDIR%
+ exit /b 1
+)
+if exist "%QTDIR64%" (
+ qbs setup-qt --settings-dir "%builddir%\.settings"^
+ "%QTDIR64%\bin\qmake.exe" qt64 || exit /b
+) else (
+ echo QTDIR64 environment variable not set or does not exist: %QTDIR64%
+ exit /b 1
+)
+
+REM Work around QBS-1142, where symlinks to UNC named paths aren't resolved
+REM properly, for example if this command is being run in a Docker container
+REM where the current directory is a symlink
+(robocopy "%CD%" "%builddir%\source" /e /njh /njs /ndl /nc /ns /xd .git) ^& IF %ERRORLEVEL% GTR 1 exit %ERRORLEVEL%
+
+qbs build --settings-dir "%builddir%\.settings"^
+ -f "%builddir%\source" -d "%builddir%\build"^
+ -p dist qbs.buildVariant:release dist.includeTopLevelDir:true^
+ release "qbs.installRoot:%builddir%\qbs-windows-x86-%version%" profile:qt^
+ release-64 "qbs.installRoot:%builddir%\qbs-windows-x86_64-%version%" profile:qt64 || exit /b
+
+copy /y "%builddir%\build\release\qbs-windows-x86-%version%.zip" dist || exit /b
+copy /y "%builddir%\build\release-64\qbs-windows-x86_64-%version%.zip" dist || exit /b
diff --git a/share/qbs/imports/qbs/ModUtils/utils.js b/share/qbs/imports/qbs/ModUtils/utils.js
index 39fee80f1..50715f126 100644
--- a/share/qbs/imports/qbs/ModUtils/utils.js
+++ b/share/qbs/imports/qbs/ModUtils/utils.js
@@ -248,13 +248,18 @@ function allFileTags(fileTaggers) {
}
/**
- * Flattens an environment dictionary (string keys to arrays or strings)
- * into a string list containing items like \c key=value1:value2:value3
+ * Flattens a dictionary (string keys to strings)
+ * into a string list containing items like \c key=value1
*/
-function flattenEnvironmentDictionary(dict, pathListSeparator) {
+function flattenDictionary(dict, separator) {
+ separator = separator || "=";
var list = [];
- for (var i in dict)
- list.push(i + "=" + dict[i]);
+ for (var i in dict) {
+ var value = i;
+ if (dict[i] !== undefined) // allow differentiation between undefined and empty string
+ value += separator + dict[i];
+ list.push(value);
+ }
return list;
}
@@ -507,8 +512,9 @@ function guessArchitecture(m) {
var architecture;
if (m) {
// based on the search algorithm from qprocessordetection.h in qtbase
- if (hasAnyOf(m, ["__arm__", "__TARGET_ARCH_ARM", "_M_ARM", "__aarch64__"])) {
- if (hasAnyOf(m, ["__aarch64__"])) {
+ var arm64Defs = ["_M_ARM64", "__aarch64__", "__ARM64__"];
+ if (hasAnyOf(m, ["__arm__", "__TARGET_ARCH_ARM", "_M_ARM"].concat(arm64Defs))) {
+ if (hasAnyOf(m, arm64Defs)) {
architecture = "arm64";
} else {
architecture = "arm";
diff --git a/share/qbs/imports/qbs/PathTools/path-tools.js b/share/qbs/imports/qbs/PathTools/path-tools.js
index 2bbec5255..68c37f568 100644
--- a/share/qbs/imports/qbs/PathTools/path-tools.js
+++ b/share/qbs/imports/qbs/PathTools/path-tools.js
@@ -30,44 +30,44 @@
var FileInfo = require("qbs.FileInfo");
-function _bundleExecutableTemporaryFilePath(product) {
- return ".tmp/" + FileInfo.fileName(bundleExecutableFilePath(product));
+function _bundleExecutableTemporaryFilePath(product, variantSuffix) {
+ return ".tmp/" + FileInfo.fileName(bundleExecutableFilePath(product, variantSuffix));
}
-function bundleExecutableFilePath(product) {
- return product.moduleProperty("bundle", "executablePath");
+function bundleExecutableFilePath(product, variantSuffix) {
+ return product.moduleProperty("bundle", "executablePath") + (variantSuffix || "");
}
-function applicationFilePath(product) {
+function applicationFilePath(product, variantSuffix) {
if (product.moduleProperty("bundle", "isBundle"))
- return _bundleExecutableTemporaryFilePath(product);
+ return _bundleExecutableTemporaryFilePath(product, variantSuffix);
return product.moduleProperty("cpp", "executablePrefix")
- + product.targetName
+ + product.targetName + (variantSuffix || "")
+ product.moduleProperty("cpp", "executableSuffix");
}
-function loadableModuleFilePath(product) {
+function loadableModuleFilePath(product, variantSuffix) {
if (product.moduleProperty("bundle", "isBundle"))
- return _bundleExecutableTemporaryFilePath(product);
+ return _bundleExecutableTemporaryFilePath(product, variantSuffix);
return product.moduleProperty("cpp", "loadableModulePrefix")
- + product.targetName
+ + product.targetName + (variantSuffix || "")
+ product.moduleProperty("cpp", "loadableModuleSuffix");
}
-function staticLibraryFilePath(product) {
+function staticLibraryFilePath(product, variantSuffix) {
if (product.moduleProperty("bundle", "isBundle"))
- return _bundleExecutableTemporaryFilePath(product);
+ return _bundleExecutableTemporaryFilePath(product, variantSuffix);
return product.moduleProperty("cpp", "staticLibraryPrefix")
- + product.targetName
+ + product.targetName + (variantSuffix || "")
+ product.moduleProperty("cpp", "staticLibrarySuffix");
}
-function dynamicLibraryFilePath(product, version, maxParts) {
+function dynamicLibraryFilePath(product, variantSuffix, version, maxParts) {
if (product.moduleProperty("bundle", "isBundle"))
- return _bundleExecutableTemporaryFilePath(product);
+ return _bundleExecutableTemporaryFilePath(product, variantSuffix);
// If no override version was given, use the product's version
// We specifically want to differentiate between undefined and i.e.
@@ -84,7 +84,9 @@ function dynamicLibraryFilePath(product, version, maxParts) {
version = version.split('.').slice(0, maxParts).join('.');
// Start with prefix + name (i.e. libqbs, qbs)
- var fileName = product.moduleProperty("cpp", "dynamicLibraryPrefix") + product.targetName;
+ var fileName = product.moduleProperty("cpp", "dynamicLibraryPrefix")
+ + product.targetName
+ + (variantSuffix || "");
// For Mach-O images, append the version number if there is one (i.e. libqbs.1.0.0)
var imageFormat = product.moduleProperty("cpp", "imageFormat");
@@ -103,6 +105,21 @@ function dynamicLibraryFilePath(product, version, maxParts) {
return fileName;
}
+function linkerOutputFilePath(fileTag, product, variantSuffix, version, maxParts) {
+ switch (fileTag) {
+ case "application":
+ return applicationFilePath(product, variantSuffix);
+ case "loadablemodule":
+ return loadableModuleFilePath(product, variantSuffix);
+ case "staticlibrary":
+ return staticLibraryFilePath(product, variantSuffix);
+ case "dynamiclibrary":
+ return dynamicLibraryFilePath(product, variantSuffix, version, maxParts);
+ default:
+ throw new Error("Unknown linker output file tag: " + fileTag);
+ }
+}
+
function importLibraryFilePath(product) {
return product.moduleProperty("cpp", "dynamicLibraryPrefix")
+ product.targetName
@@ -116,7 +133,7 @@ function debugInfoIsBundle(product) {
return !flags.contains("-f") && !flags.contains("--flat");
}
-function debugInfoFileName(product, fileTag) {
+function debugInfoFileName(product, variantSuffix, fileTag) {
var suffix = "";
// For dSYM bundles, the DWARF debug info file has no suffix
@@ -125,19 +142,19 @@ function debugInfoFileName(product, fileTag) {
suffix = product.moduleProperty("cpp", "debugInfoSuffix");
if (product.moduleProperty("bundle", "isBundle")) {
- return FileInfo.fileName(bundleExecutableFilePath(product)) + suffix;
+ return FileInfo.fileName(bundleExecutableFilePath(product, variantSuffix)) + suffix;
} else {
switch (fileTag) {
case "application":
- return applicationFilePath(product) + suffix;
+ return applicationFilePath(product, variantSuffix) + suffix;
case "dynamiclibrary":
- return dynamicLibraryFilePath(product) + suffix;
+ return dynamicLibraryFilePath(product, variantSuffix) + suffix;
case "loadablemodule":
- return loadableModuleFilePath(product) + suffix;
+ return loadableModuleFilePath(product, variantSuffix) + suffix;
case "staticlibrary":
- return staticLibraryFilePath(product) + suffix;
+ return staticLibraryFilePath(product, variantSuffix) + suffix;
default:
- return product.targetName + suffix;
+ return product.targetName + (variantSuffix || "") + suffix;
}
}
}
@@ -149,11 +166,11 @@ function debugInfoBundlePath(product, fileTag) {
if (product.moduleProperty("qbs", "targetOS").contains("darwin")
&& product.moduleProperty("bundle", "isBundle"))
return product.moduleProperty("bundle", "bundleName") + suffix;
- return debugInfoFileName(product, fileTag) + suffix;
+ return debugInfoFileName(product, undefined, fileTag) + suffix;
}
-function debugInfoFilePath(product, fileTag) {
- var name = debugInfoFileName(product, fileTag);
+function debugInfoFilePath(product, variantSuffix, fileTag) {
+ var name = debugInfoFileName(product, variantSuffix, fileTag);
if (product.moduleProperty("qbs", "targetOS").contains("darwin") && debugInfoIsBundle(product)) {
return FileInfo.joinPaths(debugInfoBundlePath(product, fileTag),
"Contents", "Resources", "DWARF", name);
diff --git a/share/qbs/imports/qbs/Probes/AndroidNdkProbe.qbs b/share/qbs/imports/qbs/Probes/AndroidNdkProbe.qbs
index 5673d2277..82a60bccd 100644
--- a/share/qbs/imports/qbs/Probes/AndroidNdkProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/AndroidNdkProbe.qbs
@@ -32,6 +32,7 @@ import qbs
import qbs.Environment
import qbs.File
import qbs.FileInfo
+import qbs.TextFile
PathProbe {
// Inputs
@@ -56,8 +57,10 @@ PathProbe {
}
// Outputs
+ property string samplesDir
property var hostArch
property stringList toolchains: []
+ property string ndkVersion
configure: {
var i, j, allPaths = (environmentPaths || []).concat(platformPaths || []);
@@ -72,11 +75,42 @@ PathProbe {
for (j in platforms) {
if (File.exists(FileInfo.joinPaths(allPaths[i], "prebuilt", platforms[j]))) {
path = allPaths[i];
+ if (File.exists(FileInfo.joinPaths(path, "samples")))
+ samplesDir = FileInfo.joinPaths(path, "samples"); // removed in r11
hostArch = platforms[j];
toolchains = File.directoryEntries(FileInfo.joinPaths(path, "toolchains"),
File.Dirs | File.NoDotAndDotDot);
- found = true;
- return;
+
+ // NDK r11 and above
+ var tf = new TextFile(path + "/source.properties", TextFile.ReadOnly);
+ try {
+ var lines = tf.readAll().trim().split(/\r?\n/g).filter(function (line) {
+ return line.length > 0;
+ });
+ for (var l = 0; l < lines.length; ++l) {
+ var m = lines[l].match(/^Pkg\.Revision\s*=\s*([0-9\.]+)$/);
+ if (m) {
+ ndkVersion = m[1];
+ found = true;
+ return;
+ }
+ }
+ } finally {
+ tf.close();
+ }
+
+ // NDK r10 and below
+ tf = new TextFile(path + "/RELEASE.txt", TextFile.ReadOnly);
+ try {
+ var m = tf.readAll().trim().match(/^r([0-9]+[a-z]?)( \(64-bit\))?$/);
+ if (m) {
+ ndkVersion = m[1];
+ found = true;
+ return;
+ }
+ } finally {
+ tf.close();
+ }
}
}
}
diff --git a/share/qbs/imports/qbs/Probes/GccProbe.qbs b/share/qbs/imports/qbs/Probes/GccProbe.qbs
index 7214ffacb..0ffe10f4d 100644
--- a/share/qbs/imports/qbs/Probes/GccProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/GccProbe.qbs
@@ -40,15 +40,12 @@ PathProbe {
property var environment
property string _nullDevice: qbs.nullDevice
- property stringList _toolchain: qbs.toolchain
property string _pathListSeparator: qbs.pathListSeparator
property string _sysroot: qbs.sysroot
// Outputs
property string architecture
- property int versionMajor
- property int versionMinor
- property int versionPatch
+ property string endianness
property stringList includePaths
property stringList libraryPaths
property stringList frameworkPaths
@@ -72,14 +69,13 @@ PathProbe {
// always complete (for example, the subarch is not included for arm architectures).
architecture = ModUtils.guessArchitecture(macros);
- if (_toolchain.contains("clang")) {
- versionMajor = parseInt(macros["__clang_major__"], 10);
- versionMinor = parseInt(macros["__clang_minor__"], 10);
- versionPatch = parseInt(macros["__clang_patchlevel__"], 10);
- } else {
- versionMajor = parseInt(macros["__GNUC__"], 10);
- versionMinor = parseInt(macros["__GNUC_MINOR__"], 10);
- versionPatch = parseInt(macros["__GNUC_PATCHLEVEL__"], 10);
+ switch (macros["__BYTE_ORDER__"]) {
+ case "__ORDER_BIG_ENDIAN__":
+ endianness = "big";
+ break;
+ case "__ORDER_LITTLE_ENDIAN__":
+ endianness = "little";
+ break;
}
}
}
diff --git a/share/qbs/imports/qbs/Probes/GccVersionProbe.qbs b/share/qbs/imports/qbs/Probes/GccVersionProbe.qbs
new file mode 100644
index 000000000..c0044f307
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/GccVersionProbe.qbs
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of the Qt Build Suite.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and 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.File
+import "../../../modules/cpp/gcc.js" as Gcc
+
+PathProbe {
+ // Inputs
+ property string compilerFilePath
+ property var environment
+
+ property string _nullDevice: qbs.nullDevice
+ property stringList _toolchain: qbs.toolchain
+
+ // Outputs
+ property int versionMajor
+ property int versionMinor
+ property int versionPatch
+
+ configure: {
+ if (!File.exists(compilerFilePath)) {
+ found = false;
+ return;
+ }
+
+ var macros = Gcc.dumpMacros(environment, compilerFilePath, undefined, _nullDevice);
+
+ if (_toolchain.contains("clang")) {
+ versionMajor = parseInt(macros["__clang_major__"], 10);
+ versionMinor = parseInt(macros["__clang_minor__"], 10);
+ versionPatch = parseInt(macros["__clang_patchlevel__"], 10);
+ found = true;
+ } else {
+ versionMajor = parseInt(macros["__GNUC__"], 10);
+ versionMinor = parseInt(macros["__GNUC_MINOR__"], 10);
+ versionPatch = parseInt(macros["__GNUC_PATCHLEVEL__"], 10);
+ found = true;
+ }
+ }
+}
diff --git a/share/qbs/imports/qbs/Probes/NpmProbe.qbs b/share/qbs/imports/qbs/Probes/NpmProbe.qbs
index d26e07eec..a13fd3615 100644
--- a/share/qbs/imports/qbs/Probes/NpmProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/NpmProbe.qbs
@@ -29,24 +29,42 @@
****************************************************************************/
import qbs
+import qbs.ModUtils
import "path-probe.js" as PathProbeConfigure
import "../../../modules/nodejs/nodejs.js" as NodeJs
NodeJsProbe {
names: ["npm"]
+ // Inputs
+ property string interpreterPath
+
// Outputs
property path npmBin
property path npmRoot
property path npmPrefix
configure: {
+ if (!interpreterPath)
+ throw '"interpreterPath" must be specified';
+
var result = PathProbeConfigure.configure(names, nameSuffixes, nameFilter, pathPrefixes,
pathSuffixes, platformPaths, environmentPaths,
platformEnvironmentPaths, pathListSeparator);
- result.npmBin = result.found ? NodeJs.findLocation(result.filePath, "bin") : undefined;
- result.npmRoot = result.found ? NodeJs.findLocation(result.filePath, "root") : undefined;
- result.npmPrefix = result.found ? NodeJs.findLocation(result.filePath, "prefix") : undefined;
+
+ var v = new ModUtils.EnvironmentVariable("PATH", pathListSeparator,
+ hostOS.contains("windows"));
+ v.prepend(interpreterPath);
+
+ 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;
found = result.found;
candidatePaths = result.candidatePaths;
diff --git a/share/qbs/imports/qbs/Probes/PathProbe.qbs b/share/qbs/imports/qbs/Probes/PathProbe.qbs
index 0e130c5fa..73ce2e049 100644
--- a/share/qbs/imports/qbs/Probes/PathProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/PathProbe.qbs
@@ -38,9 +38,10 @@ Probe {
property var nameFilter
property pathList pathPrefixes
property stringList pathSuffixes
- property pathList platformPaths: qbs.hostOS.contains("unix") ? ['/usr', '/usr/local'] : []
+ property pathList platformPaths: hostOS.contains("unix") ? ['/usr', '/usr/local'] : []
property pathList environmentPaths
property pathList platformEnvironmentPaths
+ property stringList hostOS: qbs.hostOS
property string pathListSeparator: qbs.pathListSeparator
// Output
diff --git a/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs b/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs
index 3e6a6cebe..da2116660 100644
--- a/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs
@@ -60,9 +60,14 @@ BinaryProbe {
var result = PathProbeConfigure.configure(names, nameSuffixes, nameFilter, pathPrefixes,
pathSuffixes, platformPaths, environmentPaths,
- platformEnvironmentPaths, qbs.pathListSeparator);
+ platformEnvironmentPaths, pathListSeparator);
+
+ var v = new ModUtils.EnvironmentVariable("PATH", pathListSeparator,
+ hostOS.contains("windows"));
+ v.prepend(interpreterPath);
+
result.version = result.found
- ? TypeScript.findTscVersion(result.filePath, interpreterPath)
+ ? TypeScript.findTscVersion(result.filePath, v.value)
: undefined;
if (FileInfo.fromNativeSeparators(packageManagerBinPath) !== result.path ||
!File.exists(FileInfo.fromNativeSeparators(packageManagerRootPath, "typescript"))) {
diff --git a/share/qbs/imports/qbs/Probes/XcodeProbe.qbs b/share/qbs/imports/qbs/Probes/XcodeProbe.qbs
new file mode 100644
index 000000000..ed3e1a1ea
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/XcodeProbe.qbs
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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.File
+import qbs.FileInfo
+import qbs.Process
+import qbs.PropertyList
+import "../../../modules/xcode/xcode.js" as Xcode
+
+Probe {
+ // Inputs
+ property string sdksPath
+ property string developerPath
+ property string xcodebuildPath
+ property stringList targetOS: qbs.targetOS
+ property string platformType
+ property string platformPath
+ property string devicePlatformPath
+ property string _xcodeInfoPlist: FileInfo.joinPaths(developerPath, "..", "Info.plist")
+
+ // Outputs
+ property var architectureSettings
+ property var availableSdks
+ property string xcodeVersion
+
+ configure: {
+ if (File.exists(_xcodeInfoPlist)) {
+ // Optimized case (no forking): reads CFBundleShortVersionString from
+ // Xcode.app/Contents/Info.plist
+ var propertyList = new PropertyList();
+ try {
+ propertyList.readFromFile(_xcodeInfoPlist);
+
+ var plist = propertyList.toObject();
+ if (plist)
+ xcodeVersion = plist["CFBundleShortVersionString"];
+ } finally {
+ propertyList.clear();
+ }
+ } else {
+ // Fallback case: execute xcodebuild -version if Xcode.app/Contents/Info.plist is
+ // missing; this can happen if developerPath is /, for example
+ var process;
+ try {
+ process = new Process();
+ process.exec(xcodebuildPath, ["-version"], true);
+ var lines = process.readStdOut().trim().split(/\r?\n/g).filter(function (line) {
+ return line.length > 0;
+ });
+ for (var l = 0; l < lines.length; ++l) {
+ var m = lines[l].match(/^Xcode ([0-9\.]+)$/);
+ if (m) {
+ xcodeVersion = m[1];
+ break;
+ }
+ }
+ } finally {
+ process.close();
+ }
+ }
+
+ architectureSettings = {};
+ var archSpecsPath = Xcode.archsSpecsPath(xcodeVersion, targetOS, platformType,
+ platformPath, devicePlatformPath);
+ var archSpecsReader = new Xcode.XcodeArchSpecsReader(archSpecsPath);
+ archSpecsReader.getArchitectureSettings().map(function (setting) {
+ var val = archSpecsReader.getArchitectureSettingValue(setting);
+ if (val)
+ architectureSettings[setting] = val;
+ });
+
+ availableSdks = Xcode.sdkInfoList(sdksPath);
+ found = !!xcodeVersion;
+ }
+}
diff --git a/share/qbs/imports/qbs/base/AppleApplicationDiskImage.qbs b/share/qbs/imports/qbs/base/AppleApplicationDiskImage.qbs
new file mode 100644
index 000000000..d1d4988c6
--- /dev/null
+++ b/share/qbs/imports/qbs/base/AppleApplicationDiskImage.qbs
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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.File
+import qbs.FileInfo
+import qbs.ModUtils
+
+AppleDiskImage {
+ property string sourceBase: "/Applications"
+ readonly property string absoluteSourceBase: FileInfo.joinPaths(qbs.installRoot, sourceBase)
+ property stringList symlinks: ["/Applications:Applications"]
+
+ readonly property string stageDirectory: FileInfo.joinPaths(destinationDirectory, "Volumes", dmg.volumeName)
+
+ Rule {
+ multiplex: true
+ inputs: ["qbs"]
+ outputFileTags: ["dmg.input", "dmg.input.symlink"]
+ outputArtifacts: Array.prototype.map.call(product.symlinks, function (symlink) {
+ var symlinkTarget = symlink.split(':')[0];
+ var symlinkName = symlink.split(':')[1] || symlinkTarget;
+ if (FileInfo.isAbsolutePath(symlinkName))
+ throw(symlink + " is an invalid symlink; the destination must be a relative path");
+ return {
+ filePath: FileInfo.joinPaths(product.stageDirectory, symlinkName),
+ fileTags: ["dmg.input", "dmg.input.symlink"],
+ dmg: { symlinkTarget: symlinkTarget, sourceBase: product.stageDirectory },
+ };
+ })
+ prepare: Array.prototype.map.call(outputs["dmg.input"], function (symlink) {
+ var cmd = new Command("ln", ["-sfn", symlink.dmg.symlinkTarget, symlink.filePath]);
+ cmd.workingDirectory = product.stageDirectory;
+ cmd.description = "symlinking " + symlink.fileName + " => " + symlink.dmg.symlinkTarget;
+ return cmd;
+ });
+ }
+
+ Rule {
+ multiplex: true
+ inputs: ["dmg.input.symlink"]
+ inputsFromDependencies: ["installable"]
+ outputFileTags: ["dmg.input"]
+ outputArtifacts: {
+ var absSourceBase = product.absoluteSourceBase;
+ var symlinkPaths = (inputs["dmg.input.symlink"] || []).map(function (s) { return s.filePath; });
+ return Array.prototype.map.call(inputs["installable"], function (a) {
+ var fp = ModUtils.artifactInstalledFilePath(a);
+ if (fp.startsWith(absSourceBase)) {
+ var outputFilePath = fp.replace(absSourceBase, product.stageDirectory);
+
+ // Check for symlink conflicts
+ for (var i in symlinkPaths) {
+ if (outputFilePath.startsWith(symlinkPaths[i]))
+ throw new Error("Cannot install '" + a.filePath
+ + "' to '" + outputFilePath + "' because it "
+ + "would conflict with the symlink at '"
+ + symlinkPaths[i] + "'");
+ }
+
+ return {
+ filePath: outputFilePath,
+ fileTags: ["dmg.input"],
+ dmg: { sourceBase: product.stageDirectory }
+ }
+ }
+ }).filter(function (a) { return !!a; });
+ }
+ prepare: {
+ var absSourceBase = product.absoluteSourceBase;
+ var cmds = [], dmgs = outputs["dmg.input"];
+ for (var i in dmgs) {
+ var a = dmgs[i];
+ var cmd = new JavaScriptCommand();
+ cmd.src = a.filePath.replace(product.stageDirectory, absSourceBase);
+ cmd.dst = a.filePath;
+ cmd.silent = true;
+ cmd.sourceCode = function () { File.copy(src, dst); };
+ cmds.push(cmd);
+ }
+ return cmds;
+ }
+ }
+}
diff --git a/share/qbs/imports/qbs/base/AppleDiskImage.qbs b/share/qbs/imports/qbs/base/AppleDiskImage.qbs
new file mode 100644
index 000000000..1467d822b
--- /dev/null
+++ b/share/qbs/imports/qbs/base/AppleDiskImage.qbs
@@ -0,0 +1,34 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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.
+**
+****************************************************************************/
+
+Product {
+ Depends { name: "dmg" }
+ type: ["dmg.dmg"]
+}
diff --git a/share/qbs/imports/qbs/base/Application.qbs b/share/qbs/imports/qbs/base/Application.qbs
index 781b440da..e16a93761 100644
--- a/share/qbs/imports/qbs/base/Application.qbs
+++ b/share/qbs/imports/qbs/base/Application.qbs
@@ -28,19 +28,12 @@
**
****************************************************************************/
-Product {
+import qbs
+
+NativeBinary {
type: {
if (isForAndroid && !consoleApplication)
return ["dynamiclibrary", "android.nativelibrary"];
return ["application"];
}
-
- property bool isForAndroid: qbs.targetOS.contains("android")
- property stringList architectures: isForAndroid && !qbs.architecture ? ["armv5te"] : undefined
-
- Depends { name: "bundle" }
-
- profiles: architectures
- ? architectures.map(function(arch) { return project.profile + '-' + arch; })
- : [project.profile]
}
diff --git a/share/qbs/imports/qbs/base/AutotestRunner.qbs b/share/qbs/imports/qbs/base/AutotestRunner.qbs
index 426b1ee8f..86818bfe1 100644
--- a/share/qbs/imports/qbs/base/AutotestRunner.qbs
+++ b/share/qbs/imports/qbs/base/AutotestRunner.qbs
@@ -39,7 +39,7 @@ Product {
type: ["autotest-result"]
builtByDefault: false
property stringList arguments: []
- property stringList environment: ModUtils.flattenEnvironmentDictionary(qbs.commonRunEnvironment)
+ property stringList environment: ModUtils.flattenDictionary(qbs.commonRunEnvironment)
property bool limitToSubProject: true
property stringList wrapper: []
Depends {
diff --git a/share/qbs/imports/qbs/base/Library.qbs b/share/qbs/imports/qbs/base/Library.qbs
index 65e677830..4f0b45789 100644
--- a/share/qbs/imports/qbs/base/Library.qbs
+++ b/share/qbs/imports/qbs/base/Library.qbs
@@ -28,19 +28,12 @@
**
****************************************************************************/
-Product {
+import qbs
+
+NativeBinary {
type: {
if (qbs.targetOS.contains("ios") && parseInt(cpp.minimumIosVersion, 10) < 8)
return ["staticlibrary"];
return ["dynamiclibrary"].concat(isForAndroid ? ["android.nativelibrary"] : []);
}
-
- property bool isForAndroid: qbs.targetOS.contains("android")
- property stringList architectures: isForAndroid && !qbs.architecture ? ["armv5te"] : undefined
-
- Depends { name: "bundle" }
-
- profiles: architectures
- ? architectures.map(function(arch) { return project.profile + '-' + arch; })
- : [project.profile]
}
diff --git a/share/qbs/imports/qbs/base/LoadableModule.qbs b/share/qbs/imports/qbs/base/LoadableModule.qbs
index 05234de60..607a7d8d2 100644
--- a/share/qbs/imports/qbs/base/LoadableModule.qbs
+++ b/share/qbs/imports/qbs/base/LoadableModule.qbs
@@ -30,7 +30,6 @@
import qbs
-Product {
- Depends { name: "bundle" }
- type: qbs.targetOS.contains("darwin") ? ["loadablemodule"] : ["dynamiclibrary"]
+DynamicLibrary {
+ type: isForDarwin ? ["loadablemodule"] : base
}
diff --git a/share/qbs/imports/qbs/base/NativeBinary.qbs b/share/qbs/imports/qbs/base/NativeBinary.qbs
new file mode 100644
index 000000000..8a88bd943
--- /dev/null
+++ b/share/qbs/imports/qbs/base/NativeBinary.qbs
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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
+
+Product {
+ property bool isForAndroid: qbs.targetOS.contains("android")
+ property bool isForDarwin: qbs.targetOS.contains("darwin")
+
+ Depends { name: "bundle" }
+
+ aggregate: {
+ if (!isForDarwin)
+ return false;
+ var archs = qbs.architectures;
+ if (archs && archs.length > 1)
+ return true;
+ var variants = qbs.buildVariants;
+ return variants && variants.length > 1;
+ }
+
+ multiplexByQbsProperties: {
+ if (isForDarwin)
+ return ["profiles", "architectures", "buildVariants"];
+ if (isForAndroid)
+ return ["architectures"]
+ return ["profiles"];
+ }
+}
diff --git a/share/qbs/modules/Android/ndk/ndk.qbs b/share/qbs/modules/Android/ndk/ndk.qbs
index 7ab8d58f7..788fba50d 100644
--- a/share/qbs/modules/Android/ndk/ndk.qbs
+++ b/share/qbs/modules/Android/ndk/ndk.qbs
@@ -33,6 +33,7 @@ import qbs.File
import qbs.FileInfo
import qbs.ModUtils
import qbs.Probes
+import qbs.Utilities
import "utils.js" as NdkUtils
@@ -42,6 +43,8 @@ Module {
environmentPaths: (ndkDir ? [ndkDir] : []).concat(base)
}
+ version: ndkProbe.ndkVersion
+
readonly property string abi: NdkUtils.androidAbi(qbs.architecture)
PropertyOptions {
name: "abi"
@@ -67,7 +70,12 @@ Module {
property string hostArch: ndkProbe.hostArch
property string ndkDir: ndkProbe.path
- property string platform: "android-9"
+ property string ndkSamplesDir: ndkProbe.samplesDir
+ property string platform: Utilities.versionCompare(version, "15") >= 0
+ ? "android-14"
+ : "android-9"
+
+ property bool useUnifiedHeaders: Utilities.versionCompare(version, "14") >= 0
// Internal properties.
property stringList availableToolchains: ndkProbe.toolchains
diff --git a/share/qbs/modules/Android/sdk/sdk.qbs b/share/qbs/modules/Android/sdk/sdk.qbs
index d07c2778f..bca52a203 100644
--- a/share/qbs/modules/Android/sdk/sdk.qbs
+++ b/share/qbs/modules/Android/sdk/sdk.qbs
@@ -51,6 +51,7 @@ Module {
property path sdkDir: sdkProbe.path
property path ndkDir: ndkProbe.path
+ property path ndkSamplesDir: ndkProbe.samplesDir
property string buildToolsVersion: sdkProbe.buildToolsVersion
property var buildToolsVersionParts: buildToolsVersion ? buildToolsVersion.split('.').map(function(item) { return parseInt(item, 10); }) : []
property int buildToolsVersionMajor: buildToolsVersionParts[0]
diff --git a/share/qbs/modules/archiver/archiver.qbs b/share/qbs/modules/archiver/archiver.qbs
index b63355c30..c70b57bf4 100644
--- a/share/qbs/modules/archiver/archiver.qbs
+++ b/share/qbs/modules/archiver/archiver.qbs
@@ -223,8 +223,10 @@ Module {
args = args.concat(product.moduleProperty("archiver", "flags"));
} else if (["tar", "zip", "jar"].contains(binaryName)) {
throw binaryName + ": unrecognized archive type: '" + type + "'";
- } else {
+ } else if (binaryName) {
throw "unrecognized archive tool: '" + binaryName + "'";
+ } else {
+ throw "no archive tool available to produce archive type: '" + type + "'";
}
var archiverCommand = new Command(binary, args);
diff --git a/share/qbs/modules/bundle/BundleModule.qbs b/share/qbs/modules/bundle/BundleModule.qbs
index 306e7cb07..e9f9128e2 100644
--- a/share/qbs/modules/bundle/BundleModule.qbs
+++ b/share/qbs/modules/bundle/BundleModule.qbs
@@ -84,7 +84,10 @@ Module {
specsSeparator,
additionalSettings,
!qbs.targetOS.contains("macos"));
- var settings = reader.expandedSettings(_productTypeIdentifier);
+ var settings = reader.expandedSettings(_productTypeIdentifier,
+ xcode.present
+ ? xcode._architectureSettings
+ : {});
var chain = reader.productTypeIdentifierChain(_productTypeIdentifier);
if (settings && chain) {
xcodeSettings = settings;
@@ -98,7 +101,8 @@ Module {
}
}
- additionalProductTypes: ["bundle.content"]
+ additionalProductTypes: !(product.multiplexed || product.aggregate)
+ || !product.multiplexConfigurationId ? ["bundle.content"] : []
property bool isBundle: !product.consoleApplication && qbs.targetOS.contains("darwin")
@@ -289,10 +293,6 @@ Module {
cmd.qmakeEnv = ModUtils.moduleProperty(product, "qmakeEnv");
cmd.buildEnv = product.moduleProperty("cpp", "buildEnv");
- cmd.defines = product.moduleProperty("cpp", "defines");
- cmd.platformDefines = product.moduleProperty("cpp", "platformDefines");
- cmd.compilerDefines = product.moduleProperty("cpp", "compilerDefines");
- cmd.allDefines = [].concat(cmd.defines || []).concat(cmd.platformDefines || []).concat(cmd.compilerDefines || []);
cmd.developerPath = product.moduleProperty("xcode", "developerPath");
cmd.platformInfoPlist = product.moduleProperty("xcode", "platformInfoPlist");
@@ -395,11 +395,6 @@ Module {
for (key in qmakeEnv)
env[key] = qmakeEnv[key];
- for (i = 0; i < allDefines.length; ++i) {
- var parts = allDefines[i].split('=');
- env[parts[0]] = parts[1];
- }
-
DarwinTools.expandPlistEnvironmentVariables(aggregatePlist, env, true);
// Add keys from partial Info.plists from asset catalogs, XIBs, and storyboards
@@ -652,7 +647,7 @@ Module {
var executables = outputs["bundle.symlink.executable"];
for (i in executables) {
- cmd = new Command("ln", ["-sf", FileInfo.joinPaths("Versions", "Current", product.targetName),
+ cmd = new Command("ln", ["-sfn", FileInfo.joinPaths("Versions", "Current", product.targetName),
executables[i].filePath]);
cmd.silent = true;
commands.push(cmd);
diff --git a/share/qbs/modules/bundle/MacOSX-Product-Types.xcspec b/share/qbs/modules/bundle/MacOSX-Product-Types.xcspec
index 51c778f07..450279358 100644
--- a/share/qbs/modules/bundle/MacOSX-Product-Types.xcspec
+++ b/share/qbs/modules/bundle/MacOSX-Product-Types.xcspec
@@ -423,6 +423,7 @@
"com.apple.package-type.bundle.unit-test"
],
"CanEmbedCompilerSanitizerLibraries" : "YES",
+ "IsUnitTest" : "YES",
"Type" : "ProductType",
"BasedOn" : "com.apple.product-type.bundle",
"Name" : "Unit Test Bundle",
@@ -445,6 +446,7 @@
"com.apple.package-type.bundle.unit-test"
],
"ProvisioningProfileSupported" : "YES",
+ "IsUITest" : "YES",
"Type" : "ProductType",
"BasedOn" : "com.apple.product-type.bundle.unit-test",
"Name" : "UI Testing Bundle",
@@ -459,6 +461,7 @@
"PackageTypes" : [
"com.apple.package-type.bundle.ocunit-test"
],
+ "IsUnitTest" : "YES",
"Type" : "ProductType",
"BasedOn" : "com.apple.product-type.bundle",
"Name" : "OCUnit Test Bundle",
diff --git a/share/qbs/modules/bundle/bundle.js b/share/qbs/modules/bundle/bundle.js
index 77f505452..2354d88b5 100644
--- a/share/qbs/modules/bundle/bundle.js
+++ b/share/qbs/modules/bundle/bundle.js
@@ -137,6 +137,16 @@ function packageType(productTypeIdentifier) {
}
}
+function _assign(target, source) {
+ if (source) {
+ for (var k in source) {
+ if (source.hasOwnProperty(k))
+ target[k] = source[k];
+ }
+ return target;
+ }
+}
+
var XcodeBuildSpecsReader = (function () {
function XcodeBuildSpecsReader(specsPath, separator, additionalSettings, useShallowBundles) {
this._additionalSettings = additionalSettings;
@@ -246,16 +256,18 @@ var XcodeBuildSpecsReader = (function () {
return obj[settingName];
}
};
- XcodeBuildSpecsReader.prototype.expandedSettings = function (typeIdentifier) {
+ XcodeBuildSpecsReader.prototype.expandedSettings = function (typeIdentifier, baseSettings) {
var obj = this.settings(typeIdentifier, true);
if (obj) {
for (var k in obj)
- obj[k] = this.expandedSetting(typeIdentifier, k);
+ obj[k] = this.expandedSetting(typeIdentifier, baseSettings, k);
return obj;
}
};
- XcodeBuildSpecsReader.prototype.expandedSetting = function (typeIdentifier, settingName) {
- var obj = this.settings(typeIdentifier, true);
+ XcodeBuildSpecsReader.prototype.expandedSetting = function (typeIdentifier, baseSettings,
+ settingName) {
+ var obj = baseSettings || {};
+ obj = _assign(obj, this.settings(typeIdentifier, true));
if (obj) {
for (var x in this._additionalSettings) {
var additionalSetting = this._additionalSettings[x];
diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs
index 8742e618e..1c9f9b40e 100644
--- a/share/qbs/modules/cpp/CppModule.qbs
+++ b/share/qbs/modules/cpp/CppModule.qbs
@@ -45,6 +45,7 @@ Module {
property bool treatWarningsAsErrors : false
property bool enableSuspiciousLinkerFlagWarnings: true
property string architecture: qbs.architecture
+ property string endianness
property string machineType // undocumented
property string imageFormat // undocumented
property string optimization: qbs.optimization
@@ -164,6 +165,7 @@ Module {
property string executableSuffix
property string debugInfoSuffix
property string debugInfoBundleSuffix
+ property string variantSuffix
property bool createSymlinks: true
property stringList dynamicLibraries // list of names, will be linked with -lname
property stringList staticLibraries // list of static library files
@@ -173,6 +175,7 @@ Module {
property string sonamePrefix
property bool useRPaths: true
property bool useRPathLink
+ property string rpathLinkFlag
property stringList assemblerFlags
PropertyOptions {
@@ -427,6 +430,7 @@ Module {
return !architecture || architecture === Utilities.canonicalArchitecture(architecture);
}, "'" + architecture + "' is invalid. You must use the canonical name '" +
Utilities.canonicalArchitecture(architecture) + "'");
+ validator.setRequiredProperty("endianness", endianness);
validator.setRequiredProperty("compilerVersion", compilerVersion);
validator.setRequiredProperty("compilerVersionMajor", compilerVersionMajor);
validator.setRequiredProperty("compilerVersionMinor", compilerVersionMinor);
@@ -462,4 +466,14 @@ Module {
v.set();
}
}
+
+ Parameter {
+ property bool link
+ }
+ Parameter {
+ property bool linkWholeArchive
+ }
+ Parameter {
+ property string symbolLinkMode
+ }
}
diff --git a/share/qbs/modules/cpp/DarwinGCC.qbs b/share/qbs/modules/cpp/DarwinGCC.qbs
index 22631ddc3..c1c92e740 100644
--- a/share/qbs/modules/cpp/DarwinGCC.qbs
+++ b/share/qbs/modules/cpp/DarwinGCC.qbs
@@ -30,31 +30,63 @@
import qbs
import qbs.DarwinTools
+import qbs.File
import qbs.FileInfo
import qbs.ModUtils
+import qbs.PathTools
+import qbs.Probes
import qbs.PropertyList
import qbs.TextFile
+import qbs.Utilities
+import "darwin.js" as Darwin
+import "gcc.js" as Gcc
UnixGCC {
condition: false
Depends { name: "xcode"; required: qbs.toolchain && qbs.toolchain.contains("xcode") }
+ Probes.BinaryProbe {
+ id: lipoProbe
+ names: [lipoName]
+ platformPaths: {
+ var paths = (xcode.present && xcode.devicePlatformPath)
+ ? [xcode.devicePlatformPath + "/Developer/usr/bin"]
+ : [];
+ return paths.concat([toolchainInstallPath, "/usr/bin"]);
+ }
+ }
+
+ property string lipoPathPrefix: Gcc.pathPrefix(lipoProbe.found
+ ? lipoProbe.path
+ : toolchainInstallPath, toolchainPrefix)
+
+ lipoName: "lipo"
+ lipoPath: lipoPathPrefix + lipoName
+
targetVendor: "apple"
targetSystem: "darwin"
targetAbi: "macho"
imageFormat: "macho"
compilerDefines: ["__GNUC__=4", "__APPLE__"]
- cxxStandardLibrary: qbs.toolchain.contains("clang") && cxxLanguageVersion !== "c++98"
- ? "libc++" : base
+ cxxStandardLibrary: libcxxAvailable ? "libc++" : base
loadableModulePrefix: ""
loadableModuleSuffix: ".bundle"
dynamicLibrarySuffix: ".dylib"
+ variantSuffix: {
+ // "release" corresponds to the "normal" (non-suffixed) variant
+ if (qbs.buildVariant !== "release")
+ return "_" + qbs.buildVariant;
+ return "";
+ }
+
separateDebugInformation: true
debugInfoBundleSuffix: ".dSYM"
debugInfoSuffix: ".dwarf"
- useRPathLink: false
+ useRPathLink: !minimumDarwinVersion
+ || Utilities.versionCompare(minimumDarwinVersion, "10.5") < 0
+ rpathLinkFlag: "-L"
toolchainInstallPath: xcode.present
? FileInfo.joinPaths(xcode.toolchainPath, "usr", "bin") : base
@@ -142,7 +174,7 @@ UnixGCC {
readonly property var buildEnv: {
var env = {
- "ARCHS_STANDARD": targetArch, // TODO: this will be affected by multi-arch support
+ "ARCHS_STANDARD": xcode.standardArchitectures,
"EXECUTABLE_NAME": product.targetName,
"LANG": "en_US.US-ASCII",
"PRODUCT_NAME": product.name
@@ -168,9 +200,57 @@ UnixGCC {
property string minimumDarwinVersionCompilerFlag
property string minimumDarwinVersionLinkerFlag
+ property bool libcxxAvailable: qbs.toolchain.contains("clang") && cxxLanguageVersion !== "c++98"
+
+ Rule {
+ condition: product.aggregate
+ inputsFromDependencies: ["application"]
+ multiplex: true
+
+ outputFileTags: ["bundle.input", "application", "primary", "debuginfo_app"]
+ outputArtifacts: Darwin.lipoOutputArtifacts(product, inputs, "application", "app")
+
+ prepare: Darwin.prepareLipo.apply(Darwin, arguments)
+ }
+
+ Rule {
+ condition: product.aggregate
+ inputsFromDependencies: ["loadablemodule"]
+ multiplex: true
+
+ outputFileTags: ["bundle.input", "loadablemodule", "primary", "debuginfo_loadablemodule"]
+ outputArtifacts: Darwin.lipoOutputArtifacts(product, inputs, "loadablemodule",
+ "loadablemodule")
+
+ prepare: Darwin.prepareLipo.apply(Darwin, arguments)
+ }
+
+ Rule {
+ condition: product.aggregate
+ inputsFromDependencies: ["dynamiclibrary"]
+ multiplex: true
+
+ outputFileTags: ["bundle.input", "dynamiclibrary", "dynamiclibrary_copy", "primary",
+ "debuginfo_dll"]
+ outputArtifacts: Darwin.lipoOutputArtifacts(product, inputs, "dynamiclibrary", "dll")
+
+ prepare: Darwin.prepareLipo.apply(Darwin, arguments)
+ }
+
+ Rule {
+ condition: product.aggregate
+ inputsFromDependencies: ["staticlibrary"]
+ multiplex: true
+
+ outputFileTags: ["bundle.input", "staticlibrary", "primary"]
+ outputArtifacts: Darwin.lipoOutputArtifacts(product, inputs, "staticlibrary")
+
+ prepare: Darwin.prepareLipo.apply(Darwin, arguments)
+ }
+
Rule {
condition: qbs.targetOS.contains("darwin")
- inputs: ["qbs"]
+ multiplex: true
Artifact {
filePath: product.name + "-cpp-Info.plist"
diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs
index d81fb15c8..7a065702e 100644
--- a/share/qbs/modules/cpp/GenericGCC.qbs
+++ b/share/qbs/modules/cpp/GenericGCC.qbs
@@ -49,6 +49,15 @@ CppModule {
names: [compilerName]
}
+ // Find the version as early as possible in case other things depend on it,
+ // for example the question of whether certain flags are supported and which need to be used
+ // in the GccProbe itself.
+ Probes.GccVersionProbe {
+ id: gccVersionProbe
+ compilerFilePath: compilerPath
+ environment: buildEnv
+ }
+
Probes.GccProbe {
id: gccProbe
compilerFilePath: compilerPath
@@ -57,6 +66,13 @@ CppModule {
_sysroot: sysroot
}
+ Probes.BinaryProbe {
+ id: binutilsProbe
+ condition: File.exists(archiverPath)
+ names: Gcc.toolNames([archiverName, assemblerName, linkerName, nmName,
+ objcopyName, stripName], toolchainPrefix)
+ }
+
targetLinkerFlags: Gcc.targetFlags("linker", false,
target, targetArch, machineType, qbs.targetOS)
targetAssemblerFlags: Gcc.targetFlags("assembler", assemblerHasTargetOption,
@@ -80,10 +96,11 @@ CppModule {
}
qbs.architecture: gccProbe.found ? gccProbe.architecture : original
+ endianness: gccProbe.endianness
- compilerVersionMajor: gccProbe.versionMajor
- compilerVersionMinor: gccProbe.versionMinor
- compilerVersionPatch: gccProbe.versionPatch
+ compilerVersionMajor: gccVersionProbe.versionMajor
+ compilerVersionMinor: gccVersionProbe.versionMinor
+ compilerVersionPatch: gccVersionProbe.versionPatch
compilerIncludePaths: gccProbe.includePaths
compilerFrameworkPaths: gccProbe.frameworkPaths
@@ -93,9 +110,12 @@ CppModule {
&& Utilities.versionCompare(compilerVersion, "3.1") >= 0
property bool assemblerHasTargetOption: qbs.toolchain.contains("xcode")
&& Utilities.versionCompare(compilerVersion, "7") >= 0
- property string target: [targetArch, targetVendor, targetSystem, targetAbi].join("-")
+ property string target: targetArch
+ ? [targetArch, targetVendor, targetSystem, targetAbi].join("-")
+ : undefined
property string targetArch: Utilities.canonicalTargetArchitecture(
- qbs.architecture, targetVendor, targetSystem, targetAbi)
+ qbs.architecture, endianness,
+ targetVendor, targetSystem, targetAbi)
property string targetVendor: "unknown"
property string targetSystem: "unknown"
property string targetAbi: "unknown"
@@ -103,6 +123,8 @@ CppModule {
property string toolchainPrefix
property string toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path
: undefined
+ property string binutilsPath: binutilsProbe.found ? binutilsProbe.path : toolchainInstallPath
+
assemblerName: 'as'
compilerName: cxxCompilerName
linkerName: 'ld'
@@ -111,7 +133,9 @@ CppModule {
property string objcopyName: "objcopy"
property string stripName: "strip"
property string dsymutilName: "dsymutil"
- property path sysroot: qbs.sysroot
+ property string lipoName
+ property string sysroot: qbs.sysroot
+ property string syslibroot: sysroot
property stringList sysrootFlags: sysroot ? ["--sysroot=" + sysroot] : []
property string linkerMode: "automatic"
@@ -140,17 +164,8 @@ CppModule {
+ "such as \"--no-undefined\", then you should set this property to \"strict\"."
}
- property string toolchainPathPrefix: {
- var path = ''
- if (toolchainInstallPath) {
- path += toolchainInstallPath
- if (path.substr(-1) !== '/')
- path += '/'
- }
- if (toolchainPrefix)
- path += toolchainPrefix
- return path
- }
+ property string toolchainPathPrefix: Gcc.pathPrefix(toolchainInstallPath, toolchainPrefix)
+ property string binutilsPathPrefix: Gcc.pathPrefix(binutilsPath, toolchainPrefix)
property string compilerExtension: qbs.hostOS.contains("windows") ? ".exe" : ""
property string cCompilerName: (qbs.toolchain.contains("clang") ? "clang" : "gcc")
@@ -166,17 +181,19 @@ CppModule {
"asm_cpp": toolchainPathPrefix + cCompilerName
})
- assemblerPath: toolchainPathPrefix + assemblerName
+ assemblerPath: binutilsPathPrefix + assemblerName
compilerPath: toolchainPathPrefix + compilerName
- linkerPath: toolchainPathPrefix + linkerName
- property string archiverPath: toolchainPathPrefix + archiverName
- property string nmPath: toolchainPathPrefix + nmName
+ linkerPath: binutilsPathPrefix + linkerName
+ property string archiverPath: binutilsPathPrefix + archiverName
+ property string nmPath: binutilsPathPrefix + nmName
property bool _nmHasDynamicOption: nmProbe.hasDynamicOption
- property string objcopyPath: toolchainPathPrefix + objcopyName
- property string stripPath: toolchainPathPrefix + stripName
+ property string objcopyPath: binutilsPathPrefix + objcopyName
+ property string stripPath: binutilsPathPrefix + stripName
property string dsymutilPath: toolchainPathPrefix + dsymutilName
+ property string lipoPath
property stringList dsymutilFlags
+ property bool alwaysUseLipo: false
property string includeFlag: "-I"
property string systemIncludeFlag: "-isystem"
@@ -269,6 +286,15 @@ CppModule {
"may not be supported by this compiler.");
}
+ if (gccProbe.endianness) {
+ validator.addCustomValidator("endianness", endianness, function (value) {
+ return endianness === gccProbe.endianness;
+ }, "'" + endianness + "' differs from the endianness produced by this compiler (" +
+ gccProbe.endianness + ")");
+ } else if (endianness) {
+ console.warn("Could not detect endianness ('" + endianness + "' given)");
+ }
+
var validateFlagsFunction = function (value) {
if (value) {
for (var i = 0; i < value.length; ++i) {
@@ -312,8 +338,14 @@ CppModule {
validator.validate();
}
+ // Product should be linked if it's not multiplexed or aggregated at all,
+ // or if it is multiplexed, if it's not the aggregate product
+ readonly property bool shouldLink: !(product.multiplexed || product.aggregate)
+ || product.multiplexConfigurationId
+
Rule {
id: dynamicLibraryLinker
+ condition: product.cpp.shouldLink
multiplex: true
inputs: {
var tags = ["obj", "linkerscript", "versionscript"];
@@ -354,7 +386,8 @@ CppModule {
for (var i = 0; i < maxVersionParts; ++i) {
var symlink = {
filePath: product.destinationDirectory + "/"
- + PathTools.dynamicLibraryFilePath(product, undefined, i),
+ + PathTools.dynamicLibraryFilePath(product, undefined, undefined,
+ i),
fileTags: ["dynamiclibrary_symlink"]
};
if (i > 0 && artifacts[i-1].filePath == symlink.filePath)
@@ -362,7 +395,9 @@ CppModule {
artifacts.push(symlink);
}
}
- return artifacts.concat(Gcc.debugInfoArtifacts(product, "dll"));
+ if (!product.aggregate)
+ artifacts = artifacts.concat(Gcc.debugInfoArtifacts(product, undefined, "dll"));
+ return artifacts;
}
prepare: {
@@ -372,6 +407,7 @@ CppModule {
Rule {
id: staticLibraryLinker
+ condition: product.cpp.shouldLink
multiplex: true
inputs: ["obj", "linkerscript"]
inputsFromDependencies: ["dynamiclibrary", "staticlibrary"]
@@ -411,6 +447,7 @@ CppModule {
Rule {
id: loadableModuleLinker
+ condition: product.cpp.shouldLink
multiplex: true
inputs: {
var tags = ["obj", "linkerscript"];
@@ -433,7 +470,11 @@ CppModule {
PathTools.bundleExecutableFilePath(product))
}
}
- return [app].concat(Gcc.debugInfoArtifacts(product, "loadablemodule"));
+ var artifacts = [app];
+ if (!product.aggregate)
+ artifacts = artifacts.concat(Gcc.debugInfoArtifacts(product, undefined,
+ "loadablemodule"));
+ return artifacts;
}
prepare: {
@@ -443,6 +484,7 @@ CppModule {
Rule {
id: applicationLinker
+ condition: product.cpp.shouldLink
multiplex: true
inputs: {
var tags = ["obj", "linkerscript"];
@@ -465,7 +507,10 @@ CppModule {
PathTools.bundleExecutableFilePath(product))
}
}
- return [app].concat(Gcc.debugInfoArtifacts(product, "app"));
+ var artifacts = [app];
+ if (!product.aggregate)
+ artifacts = artifacts.concat(Gcc.debugInfoArtifacts(product, undefined, "app"));
+ return artifacts;
}
prepare: {
diff --git a/share/qbs/modules/cpp/UnixGCC.qbs b/share/qbs/modules/cpp/UnixGCC.qbs
index b360d56fa..ee5171611 100644
--- a/share/qbs/modules/cpp/UnixGCC.qbs
+++ b/share/qbs/modules/cpp/UnixGCC.qbs
@@ -44,5 +44,6 @@ GenericGCC {
imageFormat: "elf"
systemRunPaths: ["/lib", "/usr/lib"]
useRPathLink: true
+ rpathLinkFlag: "-rpath-link="
}
diff --git a/share/qbs/modules/cpp/android-gcc.qbs b/share/qbs/modules/cpp/android-gcc.qbs
index 34ef322b6..5307c06a4 100644
--- a/share/qbs/modules/cpp/android-gcc.qbs
+++ b/share/qbs/modules/cpp/android-gcc.qbs
@@ -89,11 +89,13 @@ LinuxGCC {
toolchainDir, "prebuilt",
Android.ndk.hostArch, "bin")
+ property string toolchainTriple: [targetAbi === "androideabi" ? "arm" : targetArch,
+ targetSystem, targetAbi].join("-")
+
toolchainPrefix: {
if (qbs.toolchain && qbs.toolchain.contains("clang"))
return undefined;
- return [targetAbi === "androideabi" ? "arm" : targetArch,
- targetSystem, targetAbi].join("-") + "-";
+ return toolchainTriple + "-";
}
machineType: {
@@ -138,6 +140,10 @@ LinuxGCC {
}
systemIncludePaths: {
var includes = [];
+ if (Android.ndk.useUnifiedHeaders) {
+ // Might not be needed with Clang in a future NDK release
+ includes.push(FileInfo.joinPaths(sysroot, "usr", "include", toolchainTriple));
+ }
if (Android.ndk.appStl === "system") {
includes.push(FileInfo.joinPaths(cxxStlBaseDir, "system", "include"));
} else if (Android.ndk.appStl.startsWith("gabi++")) {
@@ -154,9 +160,20 @@ LinuxGCC {
}
return includes;
}
- defines: ["ANDROID"]
- sysroot: FileInfo.joinPaths(Android.ndk.ndkDir, "platforms", Android.ndk.platform,
- "arch-" + NdkUtils.abiNameToDirName(Android.ndk.abi))
+ defines: {
+ var list = ["ANDROID"];
+ if (Android.ndk.useUnifiedHeaders) {
+ // Might be superseded by an -mandroid-version or similar Clang compiler flag in future
+ list.push("__ANDROID_API__=" + Android.ndk.platformVersion);
+ }
+ return list;
+ }
+ syslibroot: FileInfo.joinPaths(Android.ndk.ndkDir, "platforms",
+ Android.ndk.platform, "arch-"
+ + NdkUtils.abiNameToDirName(Android.ndk.abi))
+ sysroot: !Android.ndk.useUnifiedHeaders
+ ? syslibroot
+ : FileInfo.joinPaths(Android.ndk.ndkDir, "sysroot")
targetArch: {
switch (qbs.architecture) {
@@ -183,6 +200,8 @@ LinuxGCC {
targetSystem: "linux"
targetAbi: "android" + (["armeabi", "armeabi-v7a"].contains(Android.ndk.abi) ? "eabi" : "")
+ endianness: "little"
+
Rule {
inputs: ["dynamiclibrary"]
outputFileTags: ["android.nativelibrary", "android.gdbserver-info", "android.stl-info"]
diff --git a/share/qbs/modules/cpp/darwin.js b/share/qbs/modules/cpp/darwin.js
new file mode 100644
index 000000000..3889de8e1
--- /dev/null
+++ b/share/qbs/modules/cpp/darwin.js
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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 File = require("qbs.File");
+var FileInfo = require("qbs.FileInfo");
+var Gcc = require("./gcc.js");
+var ModUtils = require("qbs.ModUtils");
+var PathTools = require("qbs.PathTools");
+
+function lipoOutputArtifacts(product, inputs, fileTag, debugSuffix) {
+ var buildVariants = [];
+ for (var i = 0; i < inputs[fileTag].length; ++i) {
+ var variant = inputs[fileTag][i].qbs.buildVariant;
+ var suffix = inputs[fileTag][i].cpp.variantSuffix;
+ if (!buildVariants.some(function (x) { return x.name === variant; }))
+ buildVariants.push({ name: variant, suffix: suffix });
+ }
+
+ var list = [];
+
+ if (fileTag === "dynamiclibrary") {
+ Array.prototype.push.apply(list, buildVariants.map(function (variant) {
+ return {
+ filePath: product.destinationDirectory + "/.sosymbols/"
+ + PathTools.dynamicLibraryFilePath(product, variant.suffix),
+ fileTags: ["dynamiclibrary_copy"],
+ qbs: { buildVariant: variant.name, variantSuffix: variant.suffix },
+ alwaysUpdated: false
+ };
+ }));
+ }
+
+ // Bundles should have a "normal" variant. In the case of frameworks, they cannot normally be
+ // linked to without a default variant unless a variant is specifically chosen at link time
+ // by passing the full path to the shared library executable instead of the -framework switch.
+ // Technically this doesn't affect qbs since qbs always uses full paths for internal
+ // dependencies but the "normal" variant is always the one that is linked to, since the
+ // alternative variants should only be chosen at runtime using the DYLD_IMAGE_SUFFIX variable.
+ // So for frameworks we'll create a symlink to the "default" variant as chosen by the user
+ // (we cannot do this automatically since the user must tell us which variant should be
+ // preferred, if there are multiple alternative variants). Applications are fine without a
+ // symlink but still need an explicitly chosen variant to set as the CFBundleExecutable so that
+ // Finder/LaunchServices can launch it normally but for simplicity we'll just use the symlink
+ // approach for all bundle types.
+ var defaultVariant;
+ if (!buildVariants.some(function (x) { return x.name === "release"; })) {
+ var defaultBuildVariant = product.qbs.defaultBuildVariant;
+ buildVariants.map(function (variant) {
+ if (variant.name === defaultBuildVariant)
+ defaultVariant = variant;
+ });
+ if (!defaultVariant) {
+ throw new Error("qbs.defaultBuildVariant is '" + defaultBuildVariant + "', but this " +
+ "variant is not in the qbs.buildVariants list (" +
+ product.qbs.buildVariants.join(", ") + ")");
+ }
+
+ buildVariants.push({
+ name: "release",
+ suffix: "",
+ isSymLink: true
+ });
+ }
+
+ Array.prototype.push.apply(list, buildVariants.map(function (variant) {
+ var tags = ["bundle.input"];
+ if (variant.isSymLink)
+ tags.push("bundle.variant_symlink");
+ else
+ tags.push(fileTag, "primary");
+
+ return {
+ filePath: FileInfo.joinPaths(product.destinationDirectory,
+ PathTools.linkerOutputFilePath(fileTag, product,
+ variant.suffix)),
+ fileTags: tags,
+ qbs: {
+ buildVariant: variant.name,
+ variantSuffix: variant.suffix,
+ _buildVariantFileName: variant.isSymLink && defaultVariant
+ ? FileInfo.fileName(PathTools.linkerOutputFilePath(
+ fileTag, product,
+ defaultVariant.suffix))
+ : undefined
+ },
+ bundle: {
+ _bundleFilePath: product.destinationDirectory + "/"
+ + PathTools.bundleExecutableFilePath(product, variant.suffix)
+ }
+ };
+ }));
+ if (debugSuffix)
+ Array.prototype.push.apply(list, Gcc.debugInfoArtifacts(product, buildVariants,
+ debugSuffix));
+ return list;
+}
+
+function prepareLipo(project, product, inputs, outputs, input, output) {
+ var cmd;
+ var commands = [];
+ var allInputs = [].concat.apply([], Object.keys(inputs).map(function (tag) {
+ return ["application", "dynamiclibrary", "staticlibrary", "loadablemodule"].contains(tag)
+ ? inputs[tag] : [];
+ }));
+
+ (outputs["bundle.variant_symlink"] || []).map(function (symlink) {
+ cmd = new Command("ln", ["-sfn", symlink.qbs._buildVariantFileName, symlink.filePath]);
+ cmd.silent = true;
+ commands.push(cmd);
+ });
+
+ for (var i = 0; i < outputs.primary.length; ++i) {
+ var vInputs = allInputs.filter(function (f) {
+ return f.qbs.buildVariant === outputs.primary[i].qbs.buildVariant
+ }).map(function (f) {
+ return f.filePath
+ });
+
+ if (vInputs.length > 1 || product.cpp.alwaysUseLipo) {
+ cmd = new Command(ModUtils.moduleProperty(product, "lipoPath"),
+ ["-create", "-output", outputs.primary[i].filePath].concat(vInputs));
+ cmd.description = "lipo " + outputs.primary[i].fileName;
+ cmd.highlight = "linker";
+ } else {
+ cmd = new JavaScriptCommand();
+ cmd.src = vInputs[0];
+ cmd.dst = outputs.primary[i].filePath;
+ cmd.sourceCode = function () {
+ File.copy(src, dst);
+ };
+ cmd.silent = true;
+ }
+
+ commands.push(cmd);
+ }
+
+ var debugInfo = outputs.debuginfo_app || outputs.debuginfo_dll
+ || outputs.debuginfo_loadablemodule;
+ if (debugInfo) {
+ var dsymPath = debugInfo[0].filePath;
+ if (outputs.debuginfo_bundle && outputs.debuginfo_bundle[0])
+ dsymPath = outputs.debuginfo_bundle[0].filePath;
+ var flags = ModUtils.moduleProperty(product, "dsymutilFlags") || [];
+ cmd = new Command(ModUtils.moduleProperty(product, "dsymutilPath"), flags.concat([
+ "-o", dsymPath
+ ]).concat(outputs.primary.map(function (f) { return f.filePath; })));
+ cmd.description = "generating dSYM for " + product.name;
+ commands.push(cmd);
+ }
+
+ cmd = new Command(ModUtils.moduleProperty(product, "stripPath"),
+ ["-S", outputs.primary[0].filePath]);
+ cmd.silent = true;
+ commands.push(cmd);
+ if (outputs.dynamiclibrary_copy)
+ Array.prototype.push.apply(commands, Gcc.createSymbolCheckingCommands(product, outputs));
+ return commands;
+}
+
diff --git a/share/qbs/modules/cpp/gcc.js b/share/qbs/modules/cpp/gcc.js
index 7e4071f1c..c8ee9eeaf 100644
--- a/share/qbs/modules/cpp/gcc.js
+++ b/share/qbs/modules/cpp/gcc.js
@@ -73,7 +73,7 @@ function useCompilerDriverLinker(product, inputs) {
return linker === product.cpp.compilerPath;
}
-function collectLibraryDependencies(product) {
+function collectLibraryDependencies(product, isDarwin) {
var publicDeps = {};
var objects = [];
var objectByFilePath = {};
@@ -83,12 +83,19 @@ function collectLibraryDependencies(product) {
objectByFilePath[obj.filePath] = obj;
}
- function addPublicFilePath(filePath) {
+ function addPublicFilePath(filePath, dep) {
var existing = objectByFilePath[filePath];
- if (existing)
+ var wholeArchive = dep.parameters.cpp && dep.parameters.cpp.linkWholeArchive;
+ var symbolLinkMode = dep.parameters.cpp && dep.parameters.cpp.symbolLinkMode;
+ if (existing) {
existing.direct = true;
- else
- addObject({ direct: true, filePath: filePath }, Array.prototype.unshift);
+ existing.wholeArchive = wholeArchive;
+ existing.symbolLinkMode = symbolLinkMode;
+ } else {
+ addObject({ direct: true, filePath: filePath,
+ wholeArchive: wholeArchive, symbolLinkMode: symbolLinkMode },
+ Array.prototype.unshift);
+ }
}
function addPrivateFilePath(filePath) {
@@ -102,7 +109,8 @@ function collectLibraryDependencies(product) {
if (!artifacts)
return;
var artifactFilePaths = artifacts.map(function(a) { return a.filePath; });
- artifactFilePaths.forEach(addFunction);
+ for (var i = 0; i < artifactFilePaths.length; ++i)
+ addFunction(artifactFilePaths[i], dep);
}
function addExternalLibs(obj) {
@@ -111,12 +119,27 @@ function collectLibraryDependencies(product) {
ModUtils.sanitizedModuleProperty(obj, "cpp", "dynamicLibraries"));
for (var i = 0, len = externalLibs.length; i < len; ++i)
addObject({ direct: true, filePath: externalLibs[i] }, Array.prototype.push);
+ if (isDarwin) {
+ externalLibs = [].concat(
+ ModUtils.sanitizedModuleProperty(obj, "cpp", "frameworks"));
+ for (var i = 0, len = externalLibs.length; i < len; ++i)
+ addObject({ direct: true, filePath: externalLibs[i], framework: true },
+ Array.prototype.push);
+ externalLibs = [].concat(
+ ModUtils.sanitizedModuleProperty(obj, "cpp", "weakFrameworks"));
+ for (var i = 0, len = externalLibs.length; i < len; ++i)
+ addObject({ direct: true, filePath: externalLibs[i], framework: true,
+ symbolLinkMode: "weak" }, Array.prototype.push);
+ }
}
function traverse(dep, isBelowIndirectDynamicLib) {
if (publicDeps[dep.name])
return;
+ if (dep.parameters.cpp && dep.parameters.cpp.link === false)
+ return;
+
var isStaticLibrary = typeof dep.artifacts["staticlibrary"] !== "undefined";
var isDynamicLibrary = !isStaticLibrary
&& typeof dep.artifacts["dynamiclibrary"] !== "undefined";
@@ -155,7 +178,10 @@ function collectLibraryDependencies(product) {
objects.forEach(
function (obj) {
if (obj.direct) {
- result.libraries.push(obj.filePath);
+ result.libraries.push({ filePath: obj.filePath,
+ wholeArchive: obj.wholeArchive,
+ symbolLinkMode: obj.symbolLinkMode,
+ framework: obj.framework });
} else {
var dirPath = FileInfo.path(obj.filePath);
if (!seenRPathLinkDirs.hasOwnProperty(dirPath)) {
@@ -207,16 +233,27 @@ function escapeLinkerFlags(product, inputs, linkerFlags) {
function linkerFlags(project, product, inputs, output, linkerPath) {
var libraryPaths = product.cpp.libraryPaths;
var distributionLibraryPaths = product.cpp.distributionLibraryPaths;
- var libraryDependencies = collectLibraryDependencies(product);
+ var isDarwin = product.qbs.targetOS.contains("darwin");
+ var libraryDependencies = collectLibraryDependencies(product, isDarwin);
var frameworks = product.cpp.frameworks;
var weakFrameworks = product.cpp.weakFrameworks;
var rpaths = (product.cpp.useRPaths !== false) ? product.cpp.rpaths : undefined;
var systemRunPaths = product.cpp.systemRunPaths || [];
- var isDarwin = product.qbs.targetOS.contains("darwin");
var i, args = additionalCompilerAndLinkerFlags(product);
if (output.fileTags.contains("dynamiclibrary")) {
- args.push(isDarwin ? "-dynamiclib" : "-shared");
+ if (isDarwin) {
+ args.push((function () {
+ var tags = ["c", "cpp", "objc", "objcpp", "asm_cpp"];
+ for (var i = 0; i < tags.length; ++i) {
+ if (linkerPath === product.cpp.compilerPathByLanguage[tags[i]])
+ return "-dynamiclib";
+ }
+ return "-dylib"; // for ld64
+ })());
+ } else {
+ args.push("-shared");
+ }
if (isDarwin) {
var internalVersion = product.cpp.internalVersion;
@@ -256,7 +293,7 @@ function linkerFlags(project, product, inputs, output, linkerPath) {
if (targetLinkerFlags)
args = args.concat(escapeLinkerFlags(product, inputs, targetLinkerFlags));
- var sysroot = product.cpp.sysroot;
+ var sysroot = product.cpp.syslibroot;
if (sysroot) {
if (product.qbs.toolchain.contains("qcc"))
args = args.concat(escapeLinkerFlags(product, inputs, ["--sysroot=" + sysroot]));
@@ -374,18 +411,62 @@ function linkerFlags(project, product, inputs, output, linkerPath) {
args = args.concat(['-weak_framework', weakFrameworks[i]]);
}
- args = args.concat(libraryDependencies.libraries.map(function(lib) {
- return FileInfo.isAbsolutePath(lib) || lib.startsWith('@')
- ? lib
- : '-l' + lib;
- }));
+ var wholeArchiveActive = false;
+ for (i = 0; i < libraryDependencies.libraries.length; ++i) {
+ var dep = libraryDependencies.libraries[i];
+ var lib = dep.filePath;
+ if (dep.wholeArchive && !wholeArchiveActive) {
+ var wholeArchiveFlag;
+ if (isDarwin) {
+ wholeArchiveFlag = "-force_load";
+ } else {
+ wholeArchiveFlag = "--whole-archive";
+ wholeArchiveActive = true;
+ }
+ Array.prototype.push.apply(args,
+ escapeLinkerFlags(product, inputs, [wholeArchiveFlag]));
+ }
+ if (!dep.wholeArchive && wholeArchiveActive) {
+ Array.prototype.push.apply(args,
+ escapeLinkerFlags(product, inputs, ["--no-whole-archive"]));
+ wholeArchiveActive = false;
+ }
+
+ var symbolLinkMode = dep.symbolLinkMode;
+ if (isDarwin && symbolLinkMode) {
+ if (!["lazy", "reexport", "upward", "weak"].contains(symbolLinkMode))
+ throw new Error("unknown value '" + symbolLinkMode + "' for cpp.symbolLinkMode");
+
+ var flags;
+ if (FileInfo.isAbsolutePath(lib) || lib.startsWith('@'))
+ flags = ["-" + symbolLinkMode + "_library", lib];
+ else if (dep.framework)
+ flags = ["-" + symbolLinkMode + "_framework", lib];
+ else
+ flags = ["-" + symbolLinkMode + "-l" + lib];
+
+ Array.prototype.push.apply(args, escapeLinkerFlags(product, inputs, flags));
+ } else if (FileInfo.isAbsolutePath(lib) || lib.startsWith('@')) {
+ args.push(dep.framework ? PathTools.frameworkExecutablePath(lib) : lib);
+ } else if (dep.framework) {
+ args.push("-framework", lib);
+ } else {
+ args.push('-l' + lib);
+ }
+ }
+ if (wholeArchiveActive) {
+ Array.prototype.push.apply(args,
+ escapeLinkerFlags(product, inputs, ["--no-whole-archive"]));
+ }
if (product.cpp.useRPathLink) {
+ if (!product.cpp.rpathLinkFlag)
+ throw new Error("Using rpath-link but cpp.rpathLinkFlag is not defined");
args = args.concat(escapeLinkerFlags(
product, inputs,
libraryDependencies.rpath_link.map(
function(dir) {
- return "-rpath-link=" + dir;
+ return product.cpp.rpathLinkFlag + dir;
})));
}
@@ -741,6 +822,58 @@ function prepareAssembler(project, product, inputs, outputs, input, output) {
return cmd;
}
+function nativeConfigString(product) {
+ var props = [];
+ if ((product.multiplexed || product.aggregate) && product.multiplexConfigurationId) {
+ if (product.qbs.targetOS.containsAny(["android", "darwin"]))
+ props.push(product.qbs.architecture);
+ if (product.qbs.targetOS.contains("darwin"))
+ props.push(product.qbs.buildVariant);
+ }
+ return props.length > 0 ? (" (" + props.join(", ") + ")") : "";
+}
+
+function compilerEnvVars(config, compilerInfo)
+{
+ if (config.qbs.toolchain.contains("qcc"))
+ return ["QCC_CONF_PATH"];
+
+ var list = ["CPATH", "TMPDIR"];
+ if (compilerInfo.tag === "c")
+ list.push("C_INCLUDE_PATH");
+ else if (compilerInfo.tag === "cpp")
+ list.push("CPLUS_INCLUDE_PATH");
+ else if (compilerInfo.tag === "objc")
+ list.push("OBJC_INCLUDE_PATH");
+ else if (compilerInfo.tag === "objccpp")
+ list.push("OBJCPLUS_INCLUDE_PATH");
+ if (config.qbs.targetOS.contains("macos"))
+ list.push("MACOSX_DEPLOYMENT_TARGET");
+ else if (config.qbs.targetOS.contains("ios"))
+ list.push("IPHONEOS_DEPLOYMENT_TARGET");
+ else if (config.qbs.targetOS.contains("tvos"))
+ list.push("TVOS_DEPLOYMENT_TARGET");
+ else if (config.qbs.targetOS.contains("watchos"))
+ list.push("WATCHOS_DEPLOYMENT_TARGET");
+ if (config.qbs.toolchain.contains("clang")) {
+ list.push("TEMP", "TMP");
+ } else {
+ list.push("LANG", "LC_CTYPE", "LC_MESSAGES", "LC_ALL", "GCC_COMPARE_DEBUG",
+ "GCC_EXEC_PREFIX", "COMPILER_PATH", "SOURCE_DATE_EPOCH");
+ }
+ return list;
+}
+
+function linkerEnvVars(config, inputs)
+{
+ if (config.qbs.toolchain.contains("clang") || config.qbs.toolchain.contains("qcc"))
+ return [];
+ var list = ["GNUTARGET", "LDEMULATION", "COLLECT_NO_DEMANGLE"];
+ if (useCompilerDriverLinker(config, inputs))
+ list.push("LIBRARY_PATH");
+ return list;
+}
+
function prepareCompiler(project, product, inputs, outputs, input, output) {
var compilerInfo = effectiveCompilerInfo(product.qbs.toolchain,
input, output);
@@ -761,7 +894,9 @@ function prepareCompiler(project, product, inputs, outputs, input, output) {
cmd.description = (pchOutput ? 'pre' : '') + 'compiling ' + input.fileName;
if (pchOutput)
cmd.description += ' (' + compilerInfo.tag + ')';
+ cmd.description += nativeConfigString(product);
cmd.highlight = "compiler";
+ cmd.relevantEnvironmentVariables = compilerEnvVars(input, compilerInfo);
cmd.responseFileArgumentIndex = wrapperArgsLength;
cmd.responseFileUsagePrefix = '@';
return cmd;
@@ -865,61 +1000,79 @@ function readSymbolFile(filePath)
return result;
}
-function createSymbolCheckingCommand(product, outputs)
-{
- // Update the symbols file if the list of relevant symbols has changed.
- cmd = new JavaScriptCommand();
- cmd.silent = true;
- cmd.sourceCode = function() {
- if (!outputs.dynamiclibrary_copy)
- return;
-
- var libFilePath = outputs.dynamiclibrary[0].filePath;
- var symbolFilePath = outputs.dynamiclibrary_copy[0].filePath;
-
- var newNmResult = getSymbolInfo(product, libFilePath);
- if (!newNmResult.success)
- return;
+function createSymbolCheckingCommands(product, outputs) {
+ var commands = [];
+ if (!outputs.dynamiclibrary || !outputs.dynamiclibrary_copy)
+ return commands;
+
+ if (outputs.dynamiclibrary.length !== outputs.dynamiclibrary_copy.length)
+ throw new Error("The number of outputs tagged dynamiclibrary ("
+ + outputs.dynamiclibrary.length + ") must be equal to the number of "
+ + "outputs tagged dynamiclibrary_copy ("
+ + outputs.dynamiclibrary_copy.length + ")");
+
+ for (var d = 0; d < outputs.dynamiclibrary_copy.length; ++d) {
+ // Update the symbols file if the list of relevant symbols has changed.
+ var cmd = new JavaScriptCommand();
+ cmd.silent = true;
+ cmd.d = d;
+ cmd.sourceCode = function() {
+ if (outputs.dynamiclibrary[d].qbs.buildVariant
+ !== outputs.dynamiclibrary_copy[d].qbs.buildVariant)
+ throw new Error("Build variant of output tagged dynamiclibrary ("
+ + outputs.dynamiclibrary[d].qbs.buildVariant + ") is not equal to "
+ + "build variant of output tagged dynamiclibrary_copy ("
+ + outputs.dynamiclibrary_copy[d].qbs.buildVariant + ") at index "
+ + d);
+
+ var libFilePath = outputs.dynamiclibrary[d].filePath;
+ var symbolFilePath = outputs.dynamiclibrary_copy[d].filePath;
+
+ var newNmResult = getSymbolInfo(product, libFilePath);
+ if (!newNmResult.success)
+ return;
- if (!File.exists(symbolFilePath)) {
- console.debug("Symbol file '" + symbolFilePath + "' does not yet exist.");
- createSymbolFile(symbolFilePath, newNmResult.allGlobalSymbols,
- newNmResult.definedGlobalSymbols);
- return;
- }
+ if (!File.exists(symbolFilePath)) {
+ console.debug("Symbol file '" + symbolFilePath + "' does not yet exist.");
+ createSymbolFile(symbolFilePath, newNmResult.allGlobalSymbols,
+ newNmResult.definedGlobalSymbols);
+ return;
+ }
- var oldNmResult = readSymbolFile(symbolFilePath);
- var checkMode = product.cpp.exportedSymbolsCheckMode;
- var oldSymbols;
- var newSymbols;
- if (checkMode === "strict") {
- oldSymbols = oldNmResult.allGlobalSymbols;
- newSymbols = newNmResult.allGlobalSymbols;
- } else {
- oldSymbols = oldNmResult.definedGlobalSymbols;
- newSymbols = newNmResult.definedGlobalSymbols;
- }
- if (oldSymbols.length !== newSymbols.length) {
- console.debug("List of relevant symbols differs for '" + libFilePath + "'.");
- createSymbolFile(symbolFilePath, newNmResult.allGlobalSymbols,
- newNmResult.definedGlobalSymbols);
- return;
- }
- for (var i = 0; i < oldSymbols.length; ++i) {
- var oldLine = oldSymbols[i];
- var newLine = newSymbols[i];
- var oldLineElems = oldLine.split(/\s+/);
- var newLineElems = newLine.split(/\s+/);
- if (oldLineElems[0] !== newLineElems[0] // Object name.
- || oldLineElems[1] !== newLineElems[1]) { // Object type
+ var oldNmResult = readSymbolFile(symbolFilePath);
+ var checkMode = product.cpp.exportedSymbolsCheckMode;
+ var oldSymbols;
+ var newSymbols;
+ if (checkMode === "strict") {
+ oldSymbols = oldNmResult.allGlobalSymbols;
+ newSymbols = newNmResult.allGlobalSymbols;
+ } else {
+ oldSymbols = oldNmResult.definedGlobalSymbols;
+ newSymbols = newNmResult.definedGlobalSymbols;
+ }
+ if (oldSymbols.length !== newSymbols.length) {
console.debug("List of relevant symbols differs for '" + libFilePath + "'.");
createSymbolFile(symbolFilePath, newNmResult.allGlobalSymbols,
newNmResult.definedGlobalSymbols);
return;
}
+ for (var i = 0; i < oldSymbols.length; ++i) {
+ var oldLine = oldSymbols[i];
+ var newLine = newSymbols[i];
+ var oldLineElems = oldLine.split(/\s+/);
+ var newLineElems = newLine.split(/\s+/);
+ if (oldLineElems[0] !== newLineElems[0] // Object name.
+ || oldLineElems[1] !== newLineElems[1]) { // Object type
+ console.debug("List of relevant symbols differs for '" + libFilePath + "'.");
+ createSymbolFile(symbolFilePath, newNmResult.allGlobalSymbols,
+ newNmResult.definedGlobalSymbols);
+ return;
+ }
+ }
}
+ commands.push(cmd);
}
- return cmd;
+ return commands;
}
function prepareLinker(project, product, inputs, outputs, input, output) {
@@ -959,8 +1112,9 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
}
cmd = new Command(linkerPath, args);
- cmd.description = 'linking ' + primaryOutput.fileName;
+ cmd.description = 'linking ' + primaryOutput.fileName + nativeConfigString(product);
cmd.highlight = 'linker';
+ cmd.relevantEnvironmentVariables = linkerEnvVars(product, inputs);
cmd.responseFileArgumentIndex = responseFileArgumentIndex;
cmd.responseFileUsagePrefix = useQnxResponseFileHack ? "-Wl,@" : "@";
commands.push(cmd);
@@ -969,20 +1123,22 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
|| outputs.debuginfo_loadablemodule;
if (debugInfo) {
if (product.qbs.targetOS.contains("darwin")) {
- var dsymPath = debugInfo[0].filePath;
- if (outputs.debuginfo_bundle && outputs.debuginfo_bundle[0])
- dsymPath = outputs.debuginfo_bundle[0].filePath;
- var flags = product.cpp.dsymutilFlags || [];
- cmd = new Command(product.cpp.dsymutilPath, flags.concat([
- "-o", dsymPath, primaryOutput.filePath
- ]));
- cmd.description = "generating dSYM for " + product.name;
- commands.push(cmd);
-
- cmd = new Command(product.cpp.stripPath,
- ["-S", primaryOutput.filePath]);
- cmd.silent = true;
- commands.push(cmd);
+ if (!product.aggregate) {
+ var dsymPath = debugInfo[0].filePath;
+ if (outputs.debuginfo_bundle && outputs.debuginfo_bundle[0])
+ dsymPath = outputs.debuginfo_bundle[0].filePath;
+ var flags = product.cpp.dsymutilFlags || [];
+ cmd = new Command(product.cpp.dsymutilPath, flags.concat([
+ "-o", dsymPath, primaryOutput.filePath
+ ]));
+ cmd.description = "generating dSYM for " + product.name;
+ commands.push(cmd);
+
+ cmd = new Command(product.cpp.stripPath,
+ ["-S", primaryOutput.filePath]);
+ cmd.silent = true;
+ commands.push(cmd);
+ }
} else {
var objcopy = product.cpp.objcopyPath;
@@ -1003,7 +1159,7 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
}
if (outputs.dynamiclibrary) {
- commands.push(createSymbolCheckingCommand(product, outputs));
+ Array.prototype.push.apply(commands, createSymbolCheckingCommands(product, outputs));
// Create symlinks from {libfoo, libfoo.1, libfoo.1.0} to libfoo.1.0.0
var links = outputs["dynamiclibrary_symlink"];
@@ -1056,7 +1212,7 @@ function concatLibsFromArtifacts(libs, artifacts, filePathGetter)
return concatLibs(deps, libs);
}
-function debugInfoArtifacts(product, debugInfoTagSuffix) {
+function debugInfoArtifacts(product, variants, debugInfoTagSuffix) {
var fileTag;
switch (debugInfoTagSuffix) {
case "app":
@@ -1070,12 +1226,18 @@ function debugInfoArtifacts(product, debugInfoTagSuffix) {
break;
}
+ variants = variants || [{}];
+
var artifacts = [];
if (product.cpp.separateDebugInformation) {
- artifacts.push({
- filePath: FileInfo.joinPaths(product.destinationDirectory,
- PathTools.debugInfoFilePath(product, fileTag)),
- fileTags: ["debuginfo_" + debugInfoTagSuffix]
+ variants.map(function (variant) {
+ artifacts.push({
+ filePath: FileInfo.joinPaths(product.destinationDirectory,
+ PathTools.debugInfoFilePath(product,
+ variant.suffix,
+ fileTag)),
+ fileTags: ["debuginfo_" + debugInfoTagSuffix]
+ });
});
if (PathTools.debugInfoIsBundle(product)) {
artifacts.push({
@@ -1200,3 +1362,23 @@ function targetFlags(tool, hasTargetOption, target, targetArch, machineType, tar
}
return args;
}
+
+function toolNames(rawToolNames, toolchainPrefix)
+{
+ return toolchainPrefix
+ ? rawToolNames.map(function(rawName) { return toolchainPrefix + rawName; })
+ : rawToolNames;
+}
+
+function pathPrefix(baseDir, prefix)
+{
+ var path = '';
+ if (baseDir) {
+ path += baseDir;
+ if (path.substr(-1) !== '/')
+ path += '/';
+ }
+ if (prefix)
+ path += prefix;
+ return path;
+}
diff --git a/share/qbs/modules/cpp/ios-gcc.qbs b/share/qbs/modules/cpp/ios-gcc.qbs
index 8518ca76a..12f3907b6 100644
--- a/share/qbs/modules/cpp/ios-gcc.qbs
+++ b/share/qbs/modules/cpp/ios-gcc.qbs
@@ -33,6 +33,7 @@ import qbs.DarwinTools
import qbs.File
import qbs.FileInfo
import qbs.ModUtils
+import qbs.Utilities
DarwinGCC {
condition: qbs.targetOS.contains('ios') &&
@@ -48,6 +49,10 @@ DarwinGCC {
? "-ios_simulator_version_min"
: "-iphoneos_version_min"
+ libcxxAvailable: base
+ && minimumDarwinVersion
+ && Utilities.versionCompare(minimumDarwinVersion, "5") >= 0
+
platformObjcFlags: base.concat(simulatorObjcFlags)
platformObjcxxFlags: base.concat(simulatorObjcFlags)
diff --git a/share/qbs/modules/cpp/macos-gcc.qbs b/share/qbs/modules/cpp/macos-gcc.qbs
index eb5dc3d41..bb1f79054 100644
--- a/share/qbs/modules/cpp/macos-gcc.qbs
+++ b/share/qbs/modules/cpp/macos-gcc.qbs
@@ -30,6 +30,7 @@
import qbs 1.0
import qbs.ModUtils
+import qbs.Utilities
DarwinGCC {
condition: qbs.targetOS.contains('macos') &&
@@ -40,4 +41,8 @@ DarwinGCC {
minimumDarwinVersion: minimumMacosVersion
minimumDarwinVersionCompilerFlag: "-mmacosx-version-min"
minimumDarwinVersionLinkerFlag: "-macosx_version_min"
+
+ libcxxAvailable: base
+ && minimumDarwinVersion
+ && Utilities.versionCompare(minimumDarwinVersion, "10.7") >= 0
}
diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js
index b1f9686e0..67559c07d 100644
--- a/share/qbs/modules/cpp/msvc.js
+++ b/share/qbs/modules/cpp/msvc.js
@@ -31,6 +31,7 @@
var File = require("qbs.File");
var FileInfo = require("qbs.FileInfo");
var ModUtils = require("qbs.ModUtils");
+var Utilities = require("qbs.Utilities");
var WindowsUtils = require("qbs.WindowsUtils");
function compilerVersionDefine(cpp) {
@@ -164,21 +165,20 @@ function prepareCompiler(project, product, inputs, outputs, input, output) {
args.push("/Fp" + FileInfo.toWindowsSeparators(pchOutput.filePath));
args.push("/Fo" + FileInfo.toWindowsSeparators(objOutput.filePath));
args.push(FileInfo.toWindowsSeparators(input.filePath));
- var copyCmd = new JavaScriptCommand();
- copyCmd.tag = tag;
- copyCmd.silent = true;
- copyCmd.sourceCode = function() {
- File.copy(input.filePath, outputs[tag + "_pch_copy"][0].filePath);
- };
- commands.push(copyCmd);
} else {
// use PCH
- var pchHeaderFilePath = ".obj/" + product.name + '_' + tag + '.pch_copy';
- var pchFilePath = FileInfo.toWindowsSeparators(product.buildDirectory
- + "\\.obj\\" + product.name + "_" + tag + ".pch");
- args.push("/FI" + pchHeaderFilePath);
- args.push("/Yu" + pchHeaderFilePath);
- args.push("/Fp" + pchFilePath);
+ var pchSourceArtifacts = product.artifacts[tag + "_pch_src"];
+ if (pchSourceArtifacts && pchSourceArtifacts.length > 0) {
+ var pchSourceFilePath = pchSourceArtifacts[0].filePath;
+ var pchFilePath = FileInfo.toWindowsSeparators(product.buildDirectory
+ + "\\.obj\\" + product.name + "_" + tag + ".pch");
+ args.push("/FI" + pchSourceFilePath);
+ args.push("/Yu" + pchSourceFilePath);
+ args.push("/Fp" + pchFilePath);
+ } else {
+ console.warning("products." + product.name + ".usePrecompiledHeader is true, "
+ + "but there is no " + tag + "_pch_src artifact.");
+ }
}
}
@@ -203,6 +203,7 @@ function prepareCompiler(project, product, inputs, outputs, input, output) {
cmd.responseFileUsagePrefix = '@';
// cl.exe outputs the cpp file name. We filter that out.
cmd.inputFileName = input.fileName;
+ cmd.relevantEnvironmentVariables = ["CL", "_CL_", "INCLUDE"];
cmd.stdoutFilterFunction = function(output) {
return output.split(inputFileName + "\r\n").join("");
};
@@ -214,15 +215,17 @@ function collectLibraryDependencies(product) {
var seen = {};
var result = [];
- function addFilePath(filePath) {
- result.push(filePath);
+ function addFilePath(filePath, wholeArchive) {
+ result.push({ filePath: filePath, wholeArchive: wholeArchive });
}
function addArtifactFilePaths(dep, artifacts) {
if (!artifacts)
return;
var artifactFilePaths = artifacts.map(function(a) { return a.filePath; });
- artifactFilePaths.forEach(addFilePath);
+ var wholeArchive = dep.parameters.cpp && dep.parameters.cpp.linkWholeArchive;
+ for (var i = 0; i < artifactFilePaths.length; ++i)
+ addFilePath(artifactFilePaths[i], wholeArchive);
}
function addExternalLibs(obj) {
@@ -232,7 +235,7 @@ function collectLibraryDependencies(product) {
externalLibs.forEach(function (libName) {
if (!libName.match(/\.lib$/i) && !libName.startsWith('@'))
libName += ".lib";
- addFilePath(libName);
+ addFilePath(libName, false);
});
}
@@ -240,6 +243,10 @@ function collectLibraryDependencies(product) {
if (seen.hasOwnProperty(dep.name))
return;
seen[dep.name] = true;
+
+ if (dep.parameters.cpp && dep.parameters.cpp.link === false)
+ return;
+
var staticLibraryArtifacts = dep.artifacts["staticlibrary"];
var dynamicLibraryArtifacts = staticLibraryArtifacts
? null : dep.artifacts["dynamiclibrary_import"];
@@ -257,12 +264,22 @@ function collectLibraryDependencies(product) {
return result;
}
+function linkerSupportsWholeArchive(product)
+{
+ return Utilities.versionCompare(product.cpp.compilerVersion, "19.0.25123") >= 0
+}
+
function prepareLinker(project, product, inputs, outputs, input, output) {
var i;
var linkDLL = (outputs.dynamiclibrary ? true : false)
var primaryOutput = (linkDLL ? outputs.dynamiclibrary[0] : outputs.application[0])
var debugInformation = product.cpp.debugInformation;
+ var additionalManifestInputs = Array.prototype.map.call(inputs["native.pe.manifest"],
+ function (a) {
+ return a.filePath;
+ });
var generateManifestFiles = !linkDLL && product.cpp.generateManifestFile;
+ var canEmbedManifest = (product.cpp.compilerVersionMajor >= 17); // VS 2012
var args = ['/nologo']
if (linkDLL) {
@@ -292,6 +309,9 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
case "armv7":
args.push("/MACHINE:ARM");
break;
+ case "arm64":
+ args.push("/MACHINE:ARM64");
+ break;
}
var minimumWindowsVersion = product.cpp.minimumWindowsVersion;
@@ -314,17 +334,24 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
if (subsystemSwitch)
args.push(subsystemSwitch);
- var linkerOutputNativeFilePath;
- var manifestFileName;
+ var linkerOutputNativeFilePath = FileInfo.toWindowsSeparators(primaryOutput.filePath);
+ var manifestFileNames = [];
if (generateManifestFiles) {
- linkerOutputNativeFilePath
- = FileInfo.toWindowsSeparators(
- FileInfo.path(primaryOutput.filePath) + "/intermediate."
- + primaryOutput.fileName);
- manifestFileName = linkerOutputNativeFilePath + ".manifest";
- args.push('/MANIFEST', '/MANIFESTFILE:' + manifestFileName)
- } else {
- linkerOutputNativeFilePath = FileInfo.toWindowsSeparators(primaryOutput.filePath);
+ if (canEmbedManifest) {
+ args.push("/MANIFEST:embed");
+ additionalManifestInputs.forEach(function (manifestFileName) {
+ args.push("/MANIFESTINPUT:" + manifestFileName);
+ });
+ } else {
+ linkerOutputNativeFilePath
+ = FileInfo.toWindowsSeparators(
+ FileInfo.path(primaryOutput.filePath) + "/intermediate."
+ + primaryOutput.fileName);
+
+ var manifestFileName = linkerOutputNativeFilePath + ".manifest";
+ args.push('/MANIFEST', '/MANIFESTFILE:' + manifestFileName);
+ manifestFileNames = [manifestFileName].concat(additionalManifestInputs);
+ }
}
var allInputs = inputs.obj || [];
@@ -333,8 +360,21 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
args.push(fileName)
}
- function toWindowsSeparator(filePath) { return FileInfo.toWindowsSeparators(filePath); }
- args = args.concat(collectLibraryDependencies(product).map(toWindowsSeparator));
+ var wholeArchiveSupported = linkerSupportsWholeArchive(product);
+ var wholeArchiveRequested = false;
+ var libDeps = collectLibraryDependencies(product);
+ for (i = 0; i < libDeps.length; ++i) {
+ var dep = libDeps[i];
+ args.push((wholeArchiveSupported && dep.wholeArchive ? "/WHOLEARCHIVE:" : "")
+ + FileInfo.toWindowsSeparators(dep.filePath));
+ if (dep.wholeArchive)
+ wholeArchiveRequested = true;
+ }
+ if (wholeArchiveRequested && !wholeArchiveSupported) {
+ console.warn("Product '" + product.name + "' sets cpp.linkWholeArchive on a dependency, "
+ + "but your linker does not support the /WHOLEARCHIVE option. "
+ + "Please upgrade to Visual Studio 2015 Update 2 or higher.");
+ }
if (product.cpp.entryPoint)
args.push("/ENTRY:" + product.cpp.entryPoint);
@@ -362,6 +402,7 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
var cmd = new Command(linkerPath, args)
cmd.description = 'linking ' + primaryOutput.fileName;
cmd.highlight = 'linker';
+ cmd.relevantEnvironmentVariables = ["LINK", "_LINK_", "LIB", "TMP"];
cmd.workingDirectory = FileInfo.path(primaryOutput.filePath)
cmd.responseFileUsagePrefix = '@';
cmd.stdoutFilterFunction = function(output) {
@@ -369,7 +410,7 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
};
commands.push(cmd);
- if (generateManifestFiles) {
+ if (generateManifestFiles && !canEmbedManifest) {
var outputNativeFilePath = FileInfo.toWindowsSeparators(primaryOutput.filePath);
cmd = new JavaScriptCommand();
cmd.src = linkerOutputNativeFilePath;
@@ -379,10 +420,9 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
}
cmd.silent = true
commands.push(cmd);
- args = [
- '/nologo', '/manifest', manifestFileName,
- "/outputresource:" + outputNativeFilePath + ";#" + (linkDLL ? "2" : "1")
- ]
+
+ args = ['/nologo', '/manifest'].concat(manifestFileNames);
+ args.push("/outputresource:" + outputNativeFilePath + ";#" + (linkDLL ? "2" : "1"));
cmd = new Command("mt.exe", args)
cmd.description = 'embedding manifest into ' + primaryOutput.fileName;
cmd.highlight = 'linker';
diff --git a/share/qbs/modules/cpp/windows-mingw.qbs b/share/qbs/modules/cpp/windows-mingw.qbs
index e3b04bff2..d74588c71 100644
--- a/share/qbs/modules/cpp/windows-mingw.qbs
+++ b/share/qbs/modules/cpp/windows-mingw.qbs
@@ -30,6 +30,7 @@
import qbs 1.0
import qbs.ModUtils
+import qbs.TextFile
import qbs.Utilities
import qbs.WindowsUtils
@@ -64,6 +65,56 @@ GenericGCC {
}
FileTagger {
+ patterns: ["*.manifest"]
+ fileTags: ["native.pe.manifest"]
+ }
+
+ Rule {
+ inputs: ["native.pe.manifest"]
+ multiplex: true
+
+ outputFileTags: ["rc"]
+ outputArtifacts: {
+ if (product.type.containsAny(["application", "dynamiclibrary"])) {
+ return [{
+ filePath: input.completeBaseName + ".rc",
+ fileTags: ["rc"]
+ }];
+ }
+ return [];
+ }
+
+ prepare: {
+ // TODO: Emulate manifest merging like Microsoft's mt.exe tool does
+ if (inputs.length !== 1)
+ throw("The MinGW toolchain does not support manifest merging; " +
+ "you may only specify a single manifest file to embed into your assembly.");
+
+ var cmd = new JavaScriptCommand();
+ cmd.silent = true;
+ cmd.productType = product.type;
+ cmd.inputFilePath = inputs[0].filePath;
+ cmd.outputFilePath = output.filePath;
+ cmd.sourceCode = function() {
+ var tf;
+ try {
+ tf = new TextFile(outputFilePath, TextFile.WriteOnly);
+ if (productType.contains("application"))
+ tf.write("1 "); // CREATEPROCESS_MANIFEST_RESOURCE_ID
+ else if (productType.contains("dynamiclibrary"))
+ tf.write("2 "); // ISOLATIONAWARE_MANIFEST_RESOURCE_ID
+ tf.write("24 "); // RT_MANIFEST
+ tf.writeLine(Utilities.cStringQuote(inputFilePath));
+ } finally {
+ if (tf)
+ tf.close();
+ }
+ };
+ return [cmd];
+ }
+ }
+
+ FileTagger {
patterns: ["*.rc"]
fileTags: ["rc"]
}
diff --git a/share/qbs/modules/cpp/windows-msvc.qbs b/share/qbs/modules/cpp/windows-msvc.qbs
index 24baa059b..59348bd51 100644
--- a/share/qbs/modules/cpp/windows-msvc.qbs
+++ b/share/qbs/modules/cpp/windows-msvc.qbs
@@ -81,6 +81,8 @@ CppModule {
switch (qbs.architecture) {
case "armv7":
return "armasm.exe";
+ case "arm64":
+ return "armasm64.exe";
case "ia64":
return "ias.exe";
case "x86":
@@ -98,6 +100,7 @@ CppModule {
property string toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path
: undefined
architecture: qbs.architecture
+ endianness: "little"
staticLibraryPrefix: ""
dynamicLibraryPrefix: ""
executablePrefix: ""
@@ -130,10 +133,6 @@ CppModule {
fileTags: ['c_pch']
filePath: ".obj/" + product.name + '_c.pch'
}
- Artifact {
- fileTags: ['c_pch_copy']
- filePath: ".obj/" + product.name + '_c.pch_copy'
- }
prepare: {
return MSVC.prepareCompiler.apply(MSVC, arguments);
}
@@ -152,11 +151,6 @@ CppModule {
fileTags: ['cpp_pch']
filePath: ".obj/" + product.name + '_cpp.pch'
}
- Artifact {
- fileTags: ['cpp_pch_copy']
- filePath: ".obj/" + product.name + '_cpp.pch_copy'
- }
-
prepare: {
return MSVC.prepareCompiler.apply(MSVC, arguments);
}
@@ -178,10 +172,15 @@ CppModule {
}
}
+ FileTagger {
+ patterns: ["*.manifest"]
+ fileTags: ["native.pe.manifest"]
+ }
+
Rule {
id: applicationLinker
multiplex: true
- inputs: ['obj']
+ inputs: ['obj', 'native.pe.manifest']
inputsFromDependencies: ['staticlibrary', 'dynamiclibrary_import', "debuginfo_app"]
outputFileTags: ["application", "debuginfo_app"]
@@ -211,7 +210,7 @@ CppModule {
Rule {
id: dynamicLibraryLinker
multiplex: true
- inputs: ['obj']
+ inputs: ['obj', 'native.pe.manifest']
inputsFromDependencies: ['staticlibrary', 'dynamiclibrary_import', "debuginfo_dll"]
outputFileTags: ["dynamiclibrary", "dynamiclibrary_import", "debuginfo_dll"]
diff --git a/share/qbs/modules/dmg/DMGModule.qbs b/share/qbs/modules/dmg/DMGModule.qbs
new file mode 100644
index 000000000..b45f9d548
--- /dev/null
+++ b/share/qbs/modules/dmg/DMGModule.qbs
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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.DarwinTools
+import qbs.File
+import qbs.FileInfo
+import qbs.ModUtils
+import qbs.Process
+import qbs.TextFile
+import "dmg.js" as Dmg
+
+Module {
+ Depends { name: "xcode"; required: false }
+
+ condition: qbs.hostOS.contains("darwin") && qbs.targetOS.contains("darwin")
+
+ property string volumeName: product.targetName
+ PropertyOptions {
+ name: "volumeName"
+ description: "the name of the disk image (displayed in Finder when mounted)"
+ }
+
+ property bool badgeVolumeIcon: false
+ PropertyOptions {
+ name: "badgeVolumeIcon"
+ description: "whether to render the user-supplied icon on top of the " +
+ "default volume icon instead of using it directly"
+ }
+
+ property string format: "UDBZ"
+ PropertyOptions {
+ name: "format"
+ description: "the format to create the disk image in"
+ }
+
+ property int compressionLevel: qbs.buildVariant === "release" ? 9 : undefined
+ PropertyOptions {
+ name: "compressionLevel"
+ description: "sets the zlib or bzip2 compression level for UDZO and UDBZ disk images"
+ }
+
+ property string textutilPath: "/usr/bin/textutil"
+ property string hdiutilPath: "/usr/bin/hdiutil"
+ property string dmgSuffix: ".dmg"
+
+ property string sourceBase
+
+ readonly property string pythonPath: File.canonicalFilePath(FileInfo.joinPaths(path,
+ "..", "..",
+ "python"))
+ readonly property string libexecPath: File.canonicalFilePath(FileInfo.joinPaths(path,
+ "..", "..", "..", "..",
+ "libexec", "qbs"))
+
+ property string backgroundColor
+ property int iconSize: 128
+ property int windowX: 100
+ property int windowY: 100
+ property int windowWidth: 640
+ property int windowHeight: 480
+ property var iconPositions
+
+ property int iconX: windowWidth / 2
+ property int iconY: windowHeight / 2
+
+ property string defaultLicenseLocale
+ property string licenseLocale
+ property string licenseLanguageName
+ property string licenseAgreeButtonText
+ property string licenseDisagreeButtonText
+ property string licensePrintButtonText
+ property string licenseSaveButtonText
+ property string licenseInstructionText
+
+ FileTagger {
+ patterns: [
+ "*.txt", "*.rtf", "*.html", "*.doc", "*.docx", "*.odt", "*.xml", "*.webarchive",
+ "LICENSE"
+ ]
+ fileTags: ["dmg.license.input"]
+ }
+
+ FileTagger {
+ patterns: ["*.icns"]
+ fileTags: ["icns"]
+ }
+
+ FileTagger {
+ patterns: ["*.tif", "*.tiff"]
+ fileTags: ["tiff"]
+ }
+
+ Rule {
+ inputs: ["dmg.license.input"]
+
+ outputFileTags: ["dmg.license"]
+ outputArtifacts: ([{
+ filePath: FileInfo.joinPaths(product.destinationDirectory, "licenses",
+ FileInfo.relativePath(product.sourceDirectory,
+ input.filePath) + ".rtf"),
+ fileTags: ["dmg.license"],
+ dmg: {
+ licenseLocale: input.dmg.licenseLocale,
+ licenseLanguageName: input.dmg.licenseLanguageName,
+ licenseAgreeButtonText: input.dmg.licenseAgreeButtonText,
+ licenseDisagreeButtonText: input.dmg.licenseDisagreeButtonText,
+ licensePrintButtonText: input.dmg.licensePrintButtonText,
+ licenseSaveButtonText: input.dmg.licenseSaveButtonText,
+ licenseInstructionText: input.dmg.licenseInstructionText
+ }
+ }])
+
+ prepare: Dmg.prepareLicense.apply(Dmg, arguments)
+ }
+
+ Rule {
+ multiplex: true
+ inputs: ["qbs", "dmg.input", "dmg.license", "icns", "tiff"]
+
+ Artifact {
+ fileTags: ["dmg.dmg"]
+ filePath: FileInfo.joinPaths(product.destinationDirectory,
+ product.targetName + product.dmg.dmgSuffix)
+ }
+
+ prepare: Dmg.prepareDmg.apply(Dmg, arguments)
+ }
+}
diff --git a/share/qbs/modules/dmg/dmg.js b/share/qbs/modules/dmg/dmg.js
new file mode 100644
index 000000000..82b701434
--- /dev/null
+++ b/share/qbs/modules/dmg/dmg.js
@@ -0,0 +1,212 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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 DarwinTools = require("qbs.DarwinTools");
+var FileInfo = require("qbs.FileInfo");
+var TextFile = require("qbs.TextFile");
+var Utilities = require("qbs.Utilities");
+
+function localizationFromArtifact(input) {
+ var locale = input.dmg.licenseLocale || DarwinTools.localizationKey(input.filePath);
+ if (!locale)
+ throw("Could not determine localization for license file: " + input.filePath);
+ return locale;
+}
+
+function dmgbuildSettings(product, inputs) {
+ var backgroundImages = inputs["tiff"];
+ var backgroundImage;
+ if (backgroundImages) {
+ if (backgroundImages.length > 1)
+ throw new Error("only one background image may be specified");
+ backgroundImage = backgroundImages[0].filePath;
+ }
+
+ var volumeIcons = inputs["icns"];
+ var volumeIcon;
+ if (volumeIcons) {
+ if (volumeIcons.length > 1)
+ throw new Error("only one volume icon may be specified");
+ volumeIcon = volumeIcons[0].filePath;
+ }
+
+ var licenseFileObjects = Array.prototype.map.call(inputs["dmg.license"], function (a) {
+ return {
+ "dmg": {
+ "licenseLocale": localizationFromArtifact(a),
+ "licenseLanguageName": a.dmg.licenseLanguageName,
+ "licenseAgreeButtonText": a.dmg.licenseAgreeButtonText,
+ "licenseDisagreeButtonText": a.dmg.licenseDisagreeButtonText,
+ "licensePrintButtonText": a.dmg.licensePrintButtonText,
+ "licenseSaveButtonText": a.dmg.licenseSaveButtonText,
+ "licenseInstructionText": a.dmg.licenseInstructionText,
+ },
+ "filePath": a.filePath
+ };
+ });
+
+ function reduceLicensesForKey(licenseFileObjects, key) {
+ return licenseFileObjects.reduce(function (accumulator, currentValue) {
+ var locale = currentValue.dmg.licenseLocale;
+ if (accumulator[locale])
+ throw new Error("Multiple license files for localization '" + locale + "'");
+ switch (key) {
+ case "licenses":
+ accumulator[locale] = currentValue.filePath;
+ break;
+ case "buttons":
+ var texts = [
+ currentValue.dmg.licenseLanguageName,
+ currentValue.dmg.licenseAgreeButtonText,
+ currentValue.dmg.licenseDisagreeButtonText,
+ currentValue.dmg.licensePrintButtonText,
+ currentValue.dmg.licenseSaveButtonText,
+ currentValue.dmg.licenseInstructionText
+ ];
+ accumulator[locale] = texts.every(function (a) { return !!a; }) ? texts : undefined;
+ break;
+ }
+ return accumulator;
+ }, {});
+ }
+
+ var contentsArray = Array.prototype.map.call(inputs["dmg.input"], function (a) {
+ if (a.dmg.sourceBase && !a.filePath.startsWith(a.dmg.sourceBase)) {
+ throw new Error("Cannot install '" + a.filePath + "', " +
+ "because it doesn't start with the value of " +
+ "dmg.sourceBase '" + a.dmg.sourceBase + "'.");
+ }
+
+ var isSymlink = a.fileTags.contains("dmg.input.symlink");
+ return {
+ "x": a.dmg.iconX,
+ "y": a.dmg.iconY,
+ "type": isSymlink ? "link" : "file",
+ "path": isSymlink ? a.dmg.symlinkTarget : a.filePath,
+ "name": FileInfo.relativePath(a.dmg.sourceBase || FileInfo.path(a.filePath), a.filePath)
+ };
+ });
+
+ Array.prototype.forEach.call(product.dmg.iconPositions, function (obj) {
+ var existingIndex = -1;
+ Array.prototype.forEach.call(contentsArray, function (contentsItem, i) {
+ if (contentsItem["name"] === obj["path"])
+ existingIndex = i;
+ });
+
+ if (existingIndex >= 0) {
+ contentsArray[existingIndex]["x"] = obj["x"];
+ contentsArray[existingIndex]["y"] = obj["y"];
+ } else {
+ contentsArray.push({
+ "type": "position",
+ "name": obj["path"], // name => path is not a typo
+ "path": obj["path"],
+ "x": obj["x"],
+ "y": obj["y"]
+ });
+ }
+ });
+
+ return {
+ "title": product.dmg.volumeName,
+ "icon": !product.dmg.badgeVolumeIcon ? volumeIcon : undefined,
+ "badge-icon": product.dmg.badgeVolumeIcon ? volumeIcon : undefined,
+ "background": backgroundImage,
+ "background-color": product.dmg.backgroundColor,
+ "icon-size": product.dmg.iconSize,
+ "window": {
+ "position": {
+ "x": product.dmg.windowX,
+ "y": product.dmg.windowY
+ },
+ "size": {
+ "width": product.dmg.windowWidth,
+ "height": product.dmg.windowHeight
+ }
+ },
+ "format": product.dmg.format,
+ "compression-level": product.dmg.compressionLevel,
+ "license": {
+ "default-language": product.dmg.defaultLicenseLocale,
+ "licenses": reduceLicensesForKey(licenseFileObjects, "licenses"),
+ "buttons": reduceLicensesForKey(licenseFileObjects, "buttons")
+ },
+ "contents": contentsArray
+ };
+}
+
+function prepareLicense(project, product, inputs, outputs, input, output) {
+ var cmd = new Command(product.dmg.textutilPath, [
+ "-convert", "rtf",
+ "-strip",
+ "-font", "Arial",
+ "-output", output.filePath,
+ "--", input.filePath
+ ]);
+ cmd.description = "converting " + input.fileName;
+ return [cmd];
+}
+
+function prepareDmg(project, product, inputs, outputs, input, output) {
+ var i;
+ var cmd;
+ var cmds = [];
+
+ var settingsJsonFilePath = FileInfo.joinPaths(product.destinationDirectory,
+ "settings.json");
+ cmd = new JavaScriptCommand();
+ cmd.silent = true;
+ cmd.settingsJSON = dmgbuildSettings(product, inputs);
+ cmd.settingsJsonFilePath = settingsJsonFilePath;
+ cmd.sourceCode = function () {
+ var tf;
+ try {
+ tf = new TextFile(settingsJsonFilePath, TextFile.WriteOnly);
+ tf.writeLine(JSON.stringify(settingsJSON, undefined, 4));
+ } finally {
+ if (tf)
+ tf.close();
+ }
+ }
+ cmds.push(cmd);
+
+ // Create the actual DMG via dmgbuild
+ cmd = new Command(FileInfo.joinPaths(product.dmg.libexecPath, "dmgbuild"),
+ [product.dmg.volumeName,
+ output.filePath,
+ "--no-hidpi", // qbs handles this by itself
+ "--settings", settingsJsonFilePath]);
+ cmd.environment = ["PYTHONPATH=" + product.dmg.pythonPath];
+ cmd.description = "creating " + output.fileName;
+ cmds.push(cmd);
+
+ return cmds;
+}
diff --git a/share/qbs/modules/ib/IBModule.qbs b/share/qbs/modules/ib/IBModule.qbs
index af0e166f7..14da4d11d 100644
--- a/share/qbs/modules/ib/IBModule.qbs
+++ b/share/qbs/modules/ib/IBModule.qbs
@@ -57,6 +57,11 @@ Module {
property stringList flags
+ // tiffutil specific
+ property string tiffutilName: "tiffutil"
+ property string tiffutilPath: FileInfo.joinPaths("/usr/bin", tiffutilName)
+ property bool combineHidpiImages: true
+
// iconutil specific
property string iconutilName: "iconutil"
property string iconutilPath: FileInfo.joinPaths("/usr/bin", iconutilName)
@@ -77,6 +82,7 @@ Module {
// private properties
property string outputFormat: "human-readable-text"
+ property string tiffSuffix: ".tiff"
property string appleIconSuffix: ".icns"
property string compiledAssetCatalogSuffix: ".car"
property string compiledNibSuffix: ".nib"
@@ -107,6 +113,11 @@ Module {
}
FileTagger {
+ patterns: ["*.png"]
+ fileTags: ["png"]
+ }
+
+ FileTagger {
patterns: ["*.iconset"] // bundle
fileTags: ["iconset"]
}
@@ -127,6 +138,16 @@ Module {
}
Rule {
+ multiplex: true
+ inputs: ["png"]
+
+ outputFileTags: ["tiff"]
+ outputArtifacts: Ib.tiffutilArtifacts(product, inputs)
+
+ prepare: Ib.prepareTiffutil.apply(Ib, arguments)
+ }
+
+ Rule {
inputs: ["iconset"]
outputFileTags: ["icns", "bundle.input"]
diff --git a/share/qbs/modules/ib/ib.js b/share/qbs/modules/ib/ib.js
index b6935077b..bd6697074 100644
--- a/share/qbs/modules/ib/ib.js
+++ b/share/qbs/modules/ib/ib.js
@@ -44,6 +44,71 @@ function artifactsFromInputs(inputs) {
return artifacts;
}
+function tiffutilScalesMap(inputs) {
+ return artifactsFromInputs(inputs).map(function (a) {
+ var m = a.filePath.match(/^(.+?)(@(\d+)x)?(\..+?)$/);
+ var basePath = m[1];
+ var scale = m[2] || "";
+ var nscale = m[3];
+ var extension = m[4];
+ if (scale && scale < 1)
+ throw new Error("Invalid scale '" + nscale + "' for image '" + a.filePath + "'");
+ return {
+ basePath: basePath,
+ extension: extension,
+ scale: scale
+ };
+ }).reduce(function (previous, current) {
+ previous[current["basePath"]] = (previous[current["basePath"]] || []).concat([{
+ extension: current["extension"],
+ scale: current["scale"]
+ }]);
+ return previous;
+ }, {});
+}
+
+function tiffutilOutputFilePath(product, basePath) {
+ return FileInfo.joinPaths(product.destinationDirectory,
+ "hidpi-images",
+ FileInfo.relativePath(product.sourceDirectory, basePath) +
+ product.ib.tiffSuffix);
+}
+
+function tiffutilArtifacts(product, inputs) {
+ var artifacts = [];
+ var map = tiffutilScalesMap(inputs);
+ for (var key in map) {
+ artifacts.push({
+ filePath: tiffutilOutputFilePath(product, key),
+ fileTags: ["tiff"]
+ });
+ }
+ return artifacts;
+}
+
+function prepareTiffutil(project, product, inputs, outputs, input, output) {
+ var cmds = [];
+ var map = tiffutilScalesMap(inputs);
+ for (var key in map) {
+ var args = ["-cat" + (product.ib.combineHidpiImages ? "hidpicheck" : "")];
+ var count = 0;
+ map[key].forEach(function (obj) {
+ args.push(key + obj["scale"] + obj["extension"]);
+ ++count;
+ });
+ args.push("-out", tiffutilOutputFilePath(product, key));
+ var cmd = new Command(product.ib.tiffutilPath, args);
+ cmd.description = "creating " + output.fileName;
+ cmd.count = count;
+ cmd.outputFilePath = output.filePath;
+ cmd.stderrFilterFunction = function (output) {
+ return output.replace(count + " images written to " + outputFilePath + ".", "");
+ };
+ cmds.push(cmd);
+ }
+ return cmds;
+}
+
function ibtooldArguments(product, inputs, input, outputs, overrideOutput) {
var i;
var args = [];
diff --git a/share/qbs/modules/java/JavaModule.qbs b/share/qbs/modules/java/JavaModule.qbs
index 468200023..7f0bb080c 100644
--- a/share/qbs/modules/java/JavaModule.qbs
+++ b/share/qbs/modules/java/JavaModule.qbs
@@ -89,20 +89,12 @@ Module {
description: "properties to add to the manifest file when building a JAR"
}
- // TODO: Remove in 1.9
property path manifestFile
PropertyOptions {
name: "manifestFile"
description: "Use files tagged \"java.manifest\" instead."
removalVersion: "1.9"
}
- Group {
- name: "Manifest"
- prefix: product.sourceDirectory + "/"
- files: java.manifestFile ? [java.manifestFile] : []
- fileTags: ["java.manifest"]
- }
-
property stringList manifestClassPath
PropertyOptions {
name: "manifestClassPath"
diff --git a/share/qbs/modules/java/io/qt/qbs/Artifact.java b/share/qbs/modules/java/io/qt/qbs/Artifact.java
index 50df37774..cc06d397b 100644
--- a/share/qbs/modules/java/io/qt/qbs/Artifact.java
+++ b/share/qbs/modules/java/io/qt/qbs/Artifact.java
@@ -31,6 +31,7 @@
package io.qt.qbs;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
public class Artifact {
@@ -54,11 +55,11 @@ public class Artifact {
}
public List<String> getFileTags() {
- return fileTags;
+ return Collections.unmodifiableList(fileTags);
}
public void setFileTags(List<String> fileTags) {
- this.fileTags = fileTags;
+ this.fileTags = new ArrayList<String>(fileTags);
}
public void addFileTag(String fileTag) {
diff --git a/share/qbs/modules/java/io/qt/qbs/ArtifactListTextWriter.java b/share/qbs/modules/java/io/qt/qbs/ArtifactListTextWriter.java
deleted file mode 100644
index df4e8b60d..000000000
--- a/share/qbs/modules/java/io/qt/qbs/ArtifactListTextWriter.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/****************************************************************************
- **
- ** Copyright (C) 2015 Jake Petroules.
- ** 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.
- **
- ****************************************************************************/
-
-package io.qt.qbs;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.util.List;
-
-public class ArtifactListTextWriter implements ArtifactListWriter {
- private String join(List<String> list, String separator) {
- String string = "";
- if (!list.isEmpty()) {
- string += list.get(0);
- for (int i = 1; i < list.size(); ++i) {
- string += separator + list;
- }
- }
-
- return string;
- }
-
- @Override
- public void write(List<Artifact> artifacts, OutputStream outputStream)
- throws IOException {
- PrintStream stream = new PrintStream(outputStream);
- for (Artifact artifact : artifacts) {
- stream.format("%s [%s]\n", artifact.getFilePath(),
- join(artifact.getFileTags(), ", "));
- }
- }
-}
diff --git a/share/qbs/modules/java/io/qt/qbs/ArtifactListWriter.java b/share/qbs/modules/java/io/qt/qbs/ArtifactListWriter.java
index 2eb9ba2f3..a213207b0 100644
--- a/share/qbs/modules/java/io/qt/qbs/ArtifactListWriter.java
+++ b/share/qbs/modules/java/io/qt/qbs/ArtifactListWriter.java
@@ -35,6 +35,5 @@ import java.io.OutputStream;
import java.util.List;
public interface ArtifactListWriter {
- public abstract void write(List<Artifact> artifacts,
- OutputStream outputStream) throws IOException;
+ void write(List<Artifact> artifacts, OutputStream outputStream) throws IOException;
}
diff --git a/share/qbs/modules/java/io/qt/qbs/ArtifactListXmlWriter.java b/share/qbs/modules/java/io/qt/qbs/ArtifactListXmlWriter.java
deleted file mode 100644
index 6646612aa..000000000
--- a/share/qbs/modules/java/io/qt/qbs/ArtifactListXmlWriter.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/****************************************************************************
- **
- ** Copyright (C) 2015 Jake Petroules.
- ** 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.
- **
- ****************************************************************************/
-
-package io.qt.qbs;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.util.List;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class ArtifactListXmlWriter implements ArtifactListWriter {
- @Override
- public void write(List<Artifact> artifacts, OutputStream outputStream)
- throws IOException {
- try {
- DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
- .newInstance();
- DocumentBuilder documentBuilder = documentBuilderFactory
- .newDocumentBuilder();
-
- Document document = documentBuilder.newDocument();
- Element rootElement = document.createElement("artifacts");
- document.appendChild(rootElement);
-
- for (Artifact artifact : artifacts) {
- Element artifactElement = document.createElement("artifact");
- rootElement.appendChild(artifactElement);
-
- Element filePathElement = document.createElement("filePath");
- artifactElement.appendChild(filePathElement);
- filePathElement.appendChild(document.createTextNode(artifact
- .getFilePath()));
-
- Element fileTagsElement = document.createElement("fileTags");
- artifactElement.appendChild(fileTagsElement);
-
- for (String fileTag : artifact.getFileTags()) {
- Element fileTagElement = document.createElement("fileTag");
- fileTagsElement.appendChild(fileTagElement);
- fileTagElement
- .appendChild(document.createTextNode(fileTag));
- }
- }
-
- TransformerFactory transformerFactory = TransformerFactory
- .newInstance();
- Transformer transformer = transformerFactory.newTransformer();
- DOMSource source = new DOMSource(document);
- StreamResult result = new StreamResult(outputStream);
-
- transformer.transform(source, result);
- new PrintStream(outputStream).println();
- } catch (ParserConfigurationException pce) {
- throw new IOException(pce);
- } catch (TransformerException tfe) {
- throw new IOException(tfe);
- }
- }
-}
diff --git a/share/qbs/modules/java/io/qt/qbs/tools/JavaCompilerScannerTool.java b/share/qbs/modules/java/io/qt/qbs/tools/JavaCompilerScannerTool.java
index e9770f659..10df621e7 100644
--- a/share/qbs/modules/java/io/qt/qbs/tools/JavaCompilerScannerTool.java
+++ b/share/qbs/modules/java/io/qt/qbs/tools/JavaCompilerScannerTool.java
@@ -35,27 +35,12 @@ import io.qt.qbs.tools.utils.JavaCompilerScanner;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
public class JavaCompilerScannerTool {
public static void main(String[] args) {
- JavaCompilerScanner scanner = new JavaCompilerScanner();
-
- List<String> compilerArguments = new ArrayList<String>(
- Arrays.asList(args));
- if (args.length >= 1 && args[0].equals("--output-format")) {
- compilerArguments.remove(0);
- if (args.length < 2) {
- throw new IllegalArgumentException(
- "--output-format requires an argument");
- }
-
- scanner.setOutputFormat(args[1]);
- compilerArguments.remove(0);
- }
-
try {
- int result = scanner.run(compilerArguments);
+ JavaCompilerScanner scanner = new JavaCompilerScanner();
+ int result = scanner.run(new ArrayList<String>(Arrays.asList(args)));
scanner.write(System.out);
System.exit(result);
} catch (IOException e) {
diff --git a/share/qbs/modules/java/io/qt/qbs/tools/utils/ArtifactProcessor.java b/share/qbs/modules/java/io/qt/qbs/tools/utils/ArtifactProcessor.java
deleted file mode 100644
index 30ba73801..000000000
--- a/share/qbs/modules/java/io/qt/qbs/tools/utils/ArtifactProcessor.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
- **
- ** Copyright (C) 2016 The Qt Company Ltd.
- ** Contact: http://www.qt.io/licensing
- **
- ** This file is part of the Qt Build Suite.
- **
- ** Commercial License Usage
- ** Licensees holding valid commercial Qt licenses may use this file in
- ** accordance with the commercial license agreement provided with the
- ** Software or, alternatively, in accordance with the terms contained in
- ** a written agreement between you and 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.
- **
- ****************************************************************************/
-
-package io.qt.qbs.tools.utils;
-
-import com.sun.source.util.Trees;
-
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.annotation.processing.RoundEnvironment;
-import javax.annotation.processing.SupportedAnnotationTypes;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import java.util.Set;
-
-@SupportedAnnotationTypes("*")
-public class ArtifactProcessor extends AbstractProcessor {
- private final ArtifactScanner treeScanner;
- private Trees trees;
-
- public ArtifactProcessor(final ArtifactScanner treeScanner) {
- this.treeScanner = treeScanner;
- }
-
- @Override
- public synchronized void init(ProcessingEnvironment processingEnv) {
- super.init(processingEnv);
- trees = Trees.instance(processingEnv);
- }
-
- @Override
- public boolean process(final Set<? extends TypeElement> types, final RoundEnvironment environment) {
- treeScanner.init(processingEnv);
- if (!environment.processingOver()) {
- for (final Element element : environment.getRootElements()) {
- treeScanner.scan(trees.getPath(element), trees);
- }
- }
- return true;
- }
-
- @Override
- public SourceVersion getSupportedSourceVersion() {
- return treeScanner.getSourceVersion();
- }
-}
diff --git a/share/qbs/modules/java/io/qt/qbs/tools/utils/ArtifactScanner.java b/share/qbs/modules/java/io/qt/qbs/tools/utils/ArtifactScanner.java
deleted file mode 100644
index eb8e736cc..000000000
--- a/share/qbs/modules/java/io/qt/qbs/tools/utils/ArtifactScanner.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/****************************************************************************
- **
- ** Copyright (C) 2016 The Qt Company Ltd.
- ** Contact: http://www.qt.io/licensing
- **
- ** This file is part of the Qt Build Suite.
- **
- ** Commercial License Usage
- ** Licensees holding valid commercial Qt licenses may use this file in
- ** accordance with the commercial license agreement provided with the
- ** Software or, alternatively, in accordance with the terms contained in
- ** a written agreement between you and 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.
- **
- ****************************************************************************/
-
-package io.qt.qbs.tools.utils;
-
-import com.sun.source.tree.ClassTree;
-import com.sun.source.tree.MethodTree;
-import com.sun.source.tree.VariableTree;
-import com.sun.source.util.TreePathScanner;
-import com.sun.source.util.Trees;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.*;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-public class ArtifactScanner extends TreePathScanner<Void, Trees> {
- private ProcessingEnvironment processingEnv;
- private SourceVersion sourceVersion;
- private Set<String> binaryNames = new HashSet<String>();
- private Set<String> nativeHeaderBinaryNames = new HashSet<String>();
-
- public ArtifactScanner(SourceVersion sourceVersion) {
- this.sourceVersion = sourceVersion;
- }
-
- public synchronized void init(ProcessingEnvironment processingEnv) {
- this.processingEnv = processingEnv;
- }
-
- public SourceVersion getSourceVersion() {
- return sourceVersion;
- }
-
- public Set<String> getBinaryNames() {
- return binaryNames;
- }
-
- public Set<String> getNativeHeaderBinaryNames() {
- return nativeHeaderBinaryNames;
- }
-
- private static TypeElement getEnclosingTypeElement(final Element element) {
- Element typeElement = element;
- while (!(typeElement instanceof TypeElement))
- typeElement = typeElement.getEnclosingElement();
- return (TypeElement) typeElement;
- }
-
- private static boolean isNativeHeaderFileGenerationSupported() {
- // This appears to depend on the actual JDK version, NOT the -source version given.
- return SourceVersion.latest().ordinal() >= 8;
- }
-
- @Override
- public Void visitClass(ClassTree node, Trees trees) {
- onVisitType((TypeElement)trees.getElement(getCurrentPath()));
- return super.visitClass(node, trees);
- }
-
- @Override
- public Void visitMethod(MethodTree node, Trees trees) {
- onVisitExecutable((ExecutableElement)trees.getElement(getCurrentPath()));
- return super.visitMethod(node, trees);
- }
-
- @Override
- public Void visitVariable(VariableTree node, Trees trees) {
- onVisitVariable((VariableElement)trees.getElement(getCurrentPath()));
- return super.visitVariable(node, trees);
- }
-
- public void onVisitType(TypeElement type) {
- binaryNames.add(processingEnv.getElementUtils().getBinaryName(type).toString());
- }
-
- public void onVisitExecutable(ExecutableElement element) {
- if (isNativeHeaderFileGenerationSupported() && element.getModifiers().contains(javax.lang.model.element.Modifier.NATIVE)) {
- nativeHeaderBinaryNames.add(processingEnv.getElementUtils().getBinaryName(getEnclosingTypeElement(element)).toString());
- }
- }
-
- public void onVisitVariable(VariableElement variable) {
- // Java 8: a native header is generated for a Java source file if it has either native methods,
- // or constant fields annotated with java.lang.annotation.Native (JDK-7150368).
- if (isNativeHeaderFileGenerationSupported()) {
- List<? extends AnnotationMirror> annotations = variable.getAnnotationMirrors();
- for (Iterator<? extends AnnotationMirror> it = annotations.iterator(); it.hasNext(); ) {
- // We could do variable.getAnnotation(java.lang.annotation.Native.class) != null,
- // but the helper tool must compile with older JDK versions.
- if (it.next().getAnnotationType().toString().equals("java.lang.annotation.Native"))
- nativeHeaderBinaryNames.add(processingEnv.getElementUtils().getBinaryName(getEnclosingTypeElement(variable)).toString());
- }
- }
- }
-}
diff --git a/share/qbs/modules/java/io/qt/qbs/tools/utils/JavaCompilerOptions.java b/share/qbs/modules/java/io/qt/qbs/tools/utils/JavaCompilerOptions.java
index 77bc1bf54..a6195f05f 100644
--- a/share/qbs/modules/java/io/qt/qbs/tools/utils/JavaCompilerOptions.java
+++ b/share/qbs/modules/java/io/qt/qbs/tools/utils/JavaCompilerOptions.java
@@ -32,7 +32,7 @@ package io.qt.qbs.tools.utils;
import javax.lang.model.SourceVersion;
import javax.tools.JavaCompiler;
-import javax.tools.StandardJavaFileManager;
+import javax.tools.JavaFileManager;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
@@ -42,37 +42,18 @@ public class JavaCompilerOptions {
private final List<String> recognizedOptions;
private final List<String> classNames;
private final List<File> files;
- private String classFilesDir;
- private String headerFilesDir;
- private SourceVersion sourceVersion;
- public String getClassFilesDir() {
- return classFilesDir;
- }
-
- public String getHeaderFilesDir() {
- return headerFilesDir;
- }
-
- private JavaCompilerOptions(List<String> recognizedOptions, List<String> classNames, List<File> files,
- String classFilesDir, String headerFilesDir, SourceVersion sourceVersion) {
+ private JavaCompilerOptions(List<String> recognizedOptions, List<String> classNames, List<File> files) {
this.recognizedOptions = recognizedOptions;
this.classNames = classNames;
this.files = files;
- this.classFilesDir = classFilesDir;
- this.headerFilesDir = headerFilesDir;
- this.sourceVersion = sourceVersion;
}
public static JavaCompilerOptions parse(JavaCompiler compiler,
- StandardJavaFileManager fileManager, String... arguments) {
+ JavaFileManager fileManager, String... arguments) {
List<String> recognizedOptions = new ArrayList<String>();
List<String> classNames = new ArrayList<String>();
List<File> files = new ArrayList<File>();
- String classFilesDir = null;
- String headerFilesDir = null;
- String sourceVersionString = null;
- int sourceVersion = SourceVersion.latest().ordinal();
for (int i = 0; i < arguments.length; ++i) {
int argumentCount = compiler.isSupportedOption(arguments[i]);
@@ -80,35 +61,6 @@ public class JavaCompilerOptions {
argumentCount = fileManager.isSupportedOption(arguments[i]);
if (argumentCount >= 0) {
- if (arguments[i].equals("-d") && argumentCount == 1)
- classFilesDir = arguments[i + 1];
-
- if (arguments[i].equals("-h") && argumentCount == 1)
- headerFilesDir = arguments[i + 1];
-
- if (arguments[i].equals("-source") && argumentCount == 1) {
- String a = arguments[i + 1];
- if (a.equals("1.0"))
- sourceVersion = 0;
- else if (a.equals("1.1"))
- sourceVersion = 1;
- else if (a.equals("1.2"))
- sourceVersion = 2;
- else if (a.equals("1.3"))
- sourceVersion = 3;
- else if (a.equals("1.4"))
- sourceVersion = 4;
- else if (a.equals("1.5") || a.equals("5"))
- sourceVersion = 5;
- else if (a.equals("1.6") || a.equals("6"))
- sourceVersion = 6;
- else if (a.equals("1.7") || a.equals("7"))
- sourceVersion = 7;
- else if (a.equals("1.8") || a.equals("8"))
- sourceVersion = 8;
- sourceVersionString = a;
- }
-
for (int j = 0; j < argumentCount + 1; ++j) {
if (i + j >= arguments.length) {
throw new IllegalArgumentException(arguments[i]);
@@ -129,11 +81,7 @@ public class JavaCompilerOptions {
}
}
- if (sourceVersion >= SourceVersion.values().length)
- throw new RuntimeException("invalid source release: " + sourceVersionString);
-
- return new JavaCompilerOptions(recognizedOptions, classNames, files, classFilesDir, headerFilesDir,
- SourceVersion.values()[sourceVersion]);
+ return new JavaCompilerOptions(recognizedOptions, classNames, files);
}
public List<String> getRecognizedOptions() {
@@ -147,8 +95,4 @@ public class JavaCompilerOptions {
public List<String> getClassNames() {
return Collections.unmodifiableList(classNames);
}
-
- public SourceVersion getSourceVersion() {
- return sourceVersion;
- }
}
diff --git a/share/qbs/modules/java/io/qt/qbs/tools/utils/JavaCompilerScanner.java b/share/qbs/modules/java/io/qt/qbs/tools/utils/JavaCompilerScanner.java
index 1be804ee5..ef655500a 100644
--- a/share/qbs/modules/java/io/qt/qbs/tools/utils/JavaCompilerScanner.java
+++ b/share/qbs/modules/java/io/qt/qbs/tools/utils/JavaCompilerScanner.java
@@ -33,60 +33,25 @@ package io.qt.qbs.tools.utils;
import io.qt.qbs.*;
import javax.tools.*;
-import javax.tools.JavaCompiler.CompilationTask;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
public class JavaCompilerScanner {
- private static final String humanReadableTextFormat = "human-readable-text";
- private static final String jsonFormat = "json";
- private static final String xmlFormat = "xml1";
-
- private Set<String> compilationOutputFilePaths = new HashSet<String>();
- private Set<String> parsedOutputFilePaths = new HashSet<String>();
private List<Artifact> artifacts = new ArrayList<Artifact>();
- private String outputFormat = humanReadableTextFormat;
-
- private static Map<String, ArtifactListWriter> getOutputFormatters() {
- Map<String, ArtifactListWriter> outputFormatters = new HashMap<String, ArtifactListWriter>();
- outputFormatters.put(humanReadableTextFormat,
- new ArtifactListTextWriter());
- outputFormatters.put(jsonFormat, new ArtifactListJsonWriter());
- outputFormatters.put(xmlFormat, new ArtifactListXmlWriter());
- return outputFormatters;
- }
-
- public String getOutputFormat() {
- return this.outputFormat;
- }
-
- public void setOutputFormat(String outputFormat) {
- this.outputFormat = outputFormat;
- }
+ private ArtifactListWriter writer = new ArtifactListJsonWriter();
public List<Artifact> getArtifacts() {
return this.artifacts;
}
- private void addArtifact(Artifact a) {
- for (int i = 0; i < this.artifacts.size(); ++i) {
- if (this.artifacts.get(i).getFilePath().equals(a.getFilePath())) {
- return;
- }
- }
-
- this.artifacts.add(a);
- this.parsedOutputFilePaths.add(a.getFilePath());
- }
-
public int run(List<String> compilerArguments) {
artifacts.clear();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardFileManager = compiler
.getStandardFileManager(null, null, null);
- JavaFileManager fileManager = new ForwardingJavaFileManager<StandardJavaFileManager>(
+ final JavaFileManager fileManager = new ForwardingJavaFileManager<StandardJavaFileManager>(
standardFileManager) {
@Override
public JavaFileObject getJavaFileForOutput(
@@ -95,7 +60,14 @@ public class JavaCompilerScanner {
throws IOException {
JavaFileObject o = super.getJavaFileForOutput(location,
className, kind, sibling);
- compilationOutputFilePaths.add(new File(o.toUri().getSchemeSpecificPart()).toString());
+ Artifact artifact = new Artifact(new File(o.toUri()
+ .getSchemeSpecificPart()).toString());
+ if (kind.equals(JavaFileObject.Kind.CLASS)) {
+ artifact.addFileTag("java.class");
+ } else if (kind.equals(JavaFileObject.Kind.SOURCE)) {
+ artifact.addFileTag("java.java");
+ }
+ artifacts.add(artifact);
return new NullFileObject(o);
}
@@ -105,7 +77,12 @@ public class JavaCompilerScanner {
String relativeName, FileObject sibling) throws IOException {
FileObject o = super.getFileForOutput(location, packageName,
relativeName, sibling);
- compilationOutputFilePaths.add(new File(o.toUri().getSchemeSpecificPart()).toString());
+ Artifact artifact = new Artifact(new File(o.toUri()
+ .getSchemeSpecificPart()).toString());
+ if (o.getName().endsWith(".h")) {
+ artifact.addFileTag("hpp");
+ }
+ artifacts.add(artifact);
return new NullFileObject(o);
}
};
@@ -114,81 +91,17 @@ public class JavaCompilerScanner {
.parse(compiler, standardFileManager, compilerArguments
.toArray(new String[compilerArguments.size()]));
- final ArtifactScanner scanner = new ArtifactScanner(options.getSourceVersion());
- final ArtifactProcessor processor = new ArtifactProcessor(scanner);
-
- final CompilationTask task = compiler.getTask(
+ return compiler.getTask(
null,
fileManager,
null,
options.getRecognizedOptions(),
options.getClassNames(),
standardFileManager.getJavaFileObjectsFromFiles(options
- .getFiles()));
- task.setProcessors(Arrays.asList(processor));
- task.call(); // exit code is not relevant, we have to ignore compilation errors sometimes
-
- final Set<String> binaryNames = scanner.getBinaryNames();
- final Iterator<String> it = binaryNames.iterator();
- while (it.hasNext()) {
- final String className = it.next();
- Artifact a = new Artifact(options.getClassFilesDir().replace('/', File.separatorChar)
- + File.separatorChar + className.replace('.', File.separatorChar) + ".class");
- a.addFileTag("java.class");
- addArtifact(a);
- }
-
- final Set<String> nativeHeaderBinaryNames = scanner.getNativeHeaderBinaryNames();
- final Iterator<String> it2 = nativeHeaderBinaryNames.iterator();
- while (it2.hasNext()) {
- final String className = it2.next();
- Artifact a = new Artifact(options.getHeaderFilesDir().replace('/', File.separatorChar)
- + File.separatorChar + className.replace('.', '_').replace('$', '_') + ".h");
- a.addFileTag("hpp");
- addArtifact(a);
- }
-
- // We can't simply compare both lists for equality because if compilation stopped due to an error,
- // only a partial list of artifacts may have been generated so far. If the parsed outputs contains file
- // paths it should not, qbs' --check-outputs option should catch that.
- if (!parsedOutputFilePaths.containsAll(compilationOutputFilePaths)) {
- ArrayList<String> parsedOutputFilePathsArray = new ArrayList<String>(parsedOutputFilePaths);
- Collections.sort(parsedOutputFilePathsArray);
- ArrayList<String> compilationOutputFilePathsArray = new ArrayList<String>(compilationOutputFilePaths);
- Collections.sort(compilationOutputFilePathsArray);
- compilationOutputFilePaths.removeAll(parsedOutputFilePaths);
- ArrayList<String> differenceArray = new ArrayList<String>(compilationOutputFilePaths);
- Collections.sort(differenceArray);
-
- System.err.println("The set of output files determined by source code parsing:\n\n"
- + join("\n", parsedOutputFilePathsArray) + "\n\n"
- + "is missing some files from the list that would be produced by the compiler:\n\n"
- + join("\n", compilationOutputFilePathsArray) + "\n\n"
- + "The missing files are:\n\n"
- + join("\n", differenceArray) + "\n\n"
- + "Compilation will still continue, though a build error *might* appear later;\n"
- + "please check the bug report at https://bugreports.qt.io/browse/QBS-1069\n");
- }
-
- return !parsedOutputFilePaths.isEmpty() ? 0 : 1;
+ .getFiles())).call() ? 0 : 1;
}
public void write(OutputStream outputStream) throws IOException {
- getOutputFormatters().get(outputFormat).write(artifacts, outputStream);
- }
-
- // Java 8 has String.join but the helper tool must build with Java 6.
- private static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements) {
- StringBuilder sb = new StringBuilder();
- for (Iterator<? extends CharSequence> it = elements.iterator(); it.hasNext(); ) {
- sb.append(it.next());
- sb.append(delimiter);
- }
-
- // Remove the last delimiter
- if (sb.length() > 0)
- sb.replace(sb.length() - delimiter.length(), sb.length(), "");
-
- return sb.toString();
+ writer.write(getArtifacts(), outputStream);
}
}
diff --git a/share/qbs/modules/java/utils.js b/share/qbs/modules/java/utils.js
index 2add147d5..be117d98e 100644
--- a/share/qbs/modules/java/utils.js
+++ b/share/qbs/modules/java/utils.js
@@ -103,7 +103,8 @@ function findJdkPath(hostOS, arch, environmentPaths, searchPaths) {
if (arch) {
// Hardcoding apple/macosx/macho here is fine because we know we're on macOS
args.push("--arch",
- Utilities.canonicalTargetArchitecture(arch, "apple", "macosx", "macho"));
+ Utilities.canonicalTargetArchitecture(arch, undefined,
+ "apple", "macosx", "macho"));
}
// --failfast doesn't print the default JVM if nothing matches the filter(s).
@@ -218,12 +219,8 @@ function helperFullyQualifiedNames(type) {
var names = [
"io/qt/qbs/Artifact",
"io/qt/qbs/ArtifactListJsonWriter",
- "io/qt/qbs/ArtifactListTextWriter",
"io/qt/qbs/ArtifactListWriter",
- "io/qt/qbs/ArtifactListXmlWriter",
"io/qt/qbs/tools/JavaCompilerScannerTool",
- "io/qt/qbs/tools/utils/ArtifactProcessor",
- "io/qt/qbs/tools/utils/ArtifactScanner",
"io/qt/qbs/tools/utils/JavaCompilerOptions",
"io/qt/qbs/tools/utils/JavaCompilerScanner",
"io/qt/qbs/tools/utils/JavaCompilerScanner$1",
@@ -301,7 +298,6 @@ function outputArtifacts(product, inputs) {
var javaArgs = [
"-classpath", process.workingDirectory() + (toolsJarPath ? (sep + toolsJarPath) : ""),
"io/qt/qbs/tools/JavaCompilerScannerTool",
- "--output-format", "json",
];
process.exec(ModUtils.moduleProperty(product, "interpreterFilePath"), javaArgs
.concat(javacArguments(product, inputs, helperOverrideArgs(product))), true);
diff --git a/share/qbs/modules/nodejs/NodeJS.qbs b/share/qbs/modules/nodejs/NodeJS.qbs
index 833506a9a..105a01618 100644
--- a/share/qbs/modules/nodejs/NodeJS.qbs
+++ b/share/qbs/modules/nodejs/NodeJS.qbs
@@ -48,6 +48,7 @@ Module {
Probes.NpmProbe {
id: npm
pathPrefixes: toolchainInstallPath ? [toolchainInstallPath] : []
+ interpreterPath: FileInfo.path(nodejs.filePath)
}
property path applicationFile
diff --git a/share/qbs/modules/nodejs/nodejs.js b/share/qbs/modules/nodejs/nodejs.js
index af292229c..c329b7fc7 100644
--- a/share/qbs/modules/nodejs/nodejs.js
+++ b/share/qbs/modules/nodejs/nodejs.js
@@ -30,10 +30,13 @@
var Process = require("qbs.Process");
-function findLocation(packageManagerFilePath, location) {
+function findLocation(packageManagerFilePath, location, nodejsPath) {
var p = new Process();
try {
- p.exec(packageManagerFilePath, [location, "-g"]);
+ if (nodejsPath)
+ p.setEnv("PATH", nodejsPath);
+ if (p.exec(packageManagerFilePath, [location, "-g"]) !== 0)
+ console.error(p.readStdErr().trim());
return p.readStdOut().trim();
} finally {
p.close();
diff --git a/share/qbs/modules/qbs/common.qbs b/share/qbs/modules/qbs/common.qbs
index 541e26940..3f65c8d09 100644
--- a/share/qbs/modules/qbs/common.qbs
+++ b/share/qbs/modules/qbs/common.qbs
@@ -37,7 +37,7 @@ import qbs.Utilities
Module {
readonly property string configurationName: "default"
- property string buildVariant: {
+ property string defaultBuildVariant: {
switch (configurationName.toLowerCase()) {
case "release":
return "release";
@@ -46,6 +46,8 @@ Module {
}
}
+ property string buildVariant: defaultBuildVariant
+
property bool enableDebugCode: buildVariant == "debug"
property bool debugInformation: (buildVariant == "debug")
property string optimization: (buildVariant == "debug" ? "none" : "fast")
@@ -97,7 +99,7 @@ Module {
property string architecture
property bool install: false
property path installSourceBase
- readonly property string installRoot: undefined
+ property string installRoot: project.buildDirectory + "/install-root"
property string installDir
property string installPrefix: ""
property path sysroot
@@ -209,9 +211,38 @@ Module {
return env;
}
+ // Properties that can be set for multiplexing products.
+ property stringList profiles
+ property stringList architectures: {
+ if (targetOS.contains("android"))
+ return ["armv5te"];
+ if (targetOS.contains("ios-simulator"))
+ return ["x86", "x86_64"];
+ if (targetOS.contains("ios"))
+ return ["armv7a", "arm64"];
+ if (targetOS.contains("macos"))
+ return ["x86_64"];
+ if (targetOS.contains("tvos-simulator"))
+ return ["x86_64"];
+ if (targetOS.contains("tvos"))
+ return ["arm64"];
+ if (targetOS.contains("watchos-simulator"))
+ return ["x86"];
+ if (targetOS.contains("watchos"))
+ return ["armv7k"];
+ return architecture ? [architecture] : undefined;
+ }
+
+ property stringList buildVariants: [defaultBuildVariant]
+
// internal properties
readonly property string version: [versionMajor, versionMinor, versionPatch].join(".")
readonly property int versionMajor: undefined // set internally
readonly property int versionMinor: undefined // set internally
readonly property int versionPatch: undefined // set internally
+ readonly property var multiplexMap: ({
+ profiles: "profile",
+ architectures: "architecture",
+ buildVariants: "buildVariant"
+ })
}
diff --git a/share/qbs/modules/xcode/xcode.js b/share/qbs/modules/xcode/xcode.js
index 9e1e5f490..82f7eecb3 100644
--- a/share/qbs/modules/xcode/xcode.js
+++ b/share/qbs/modules/xcode/xcode.js
@@ -28,10 +28,70 @@
**
****************************************************************************/
+var DarwinTools = require("qbs.DarwinTools");
var File = require("qbs.File");
var FileInfo = require("qbs.FileInfo");
var Process = require("qbs.Process");
var PropertyList = require("qbs.PropertyList");
+var Utilities = require("qbs.Utilities");
+
+var XcodeArchSpecsReader = (function () {
+ function XcodeArchSpecsReader(specsPath) {
+ var plist = new PropertyList();
+ try {
+ plist.readFromFile(specsPath);
+ this.specsObject = plist.toObject();
+ } finally {
+ plist.clear();
+ }
+ }
+ XcodeArchSpecsReader.prototype.getArchitectureSettings = function () {
+ if (this.specsObject) {
+ var names = [];
+ for (var i = 0; i < this.specsObject.length; ++i) {
+ var dict = this.specsObject[i];
+ var name = dict["ArchitectureSetting"];
+ if (name)
+ names.push(name);
+ }
+ return names;
+ }
+ };
+ XcodeArchSpecsReader.prototype.getArchitectureSettingValue = function (settingName) {
+ // settingName can be: ARCHS_STANDARD, ARCHS_STANDARD_32_BIT, ARCHS_STANDARD_64_BIT,
+ // ARCHS_STANDARD_32_64_BIT, ARCHS_STANDARD_INCLUDING_64_BIT, or ARCHS_UNIVERSAL_IPHONE_OS.
+ // NATIVE_ARCH_ACTUAL doesn't have a RealArchitectures property since it's determined by
+ // Xcode programmatically.
+ if (this.specsObject) {
+ for (var i = 0; i < this.specsObject.length; ++i) {
+ var dict = this.specsObject[i];
+ if (dict["ArchitectureSetting"] === settingName) {
+ var realArchs = dict["RealArchitectures"];
+ if (realArchs) {
+ var effectiveRealArchs = [];
+ for (var j = 0; j < realArchs.length; ++j) {
+ var re = /^\$\(([A-Za-z0-9_]+)\)$/;
+ var match = realArchs[j].match(re);
+ if (match) {
+ var val = this.getArchitectureSettingValue(match[1]);
+ // Don't silently omit values if missing. For example, if
+ // ARCHS_FOO=[x86_64, $(ARCHS_BAR)], return 'undefined' instead of
+ // simply [x86_64]. Not known to have any real world occurrences.
+ if (!val)
+ return undefined;
+ Array.prototype.push.apply(effectiveRealArchs, val);
+ } else {
+ effectiveRealArchs.push(realArchs[j]);
+ }
+ }
+ return effectiveRealArchs;
+ }
+ }
+ }
+ }
+ };
+ return XcodeArchSpecsReader;
+}());
function sdkInfoList(sdksPath) {
var sdkInfo = [];
@@ -129,3 +189,37 @@ function provisioningProfilePlistContents(filePath) {
plist.clear();
}
}
+
+function archsSpecsPath(version, targetOS, platformType, platformPath, devicePlatformPath) {
+ var _specsPluginBaseName;
+ if (Utilities.versionCompare(version, "7") >= 0) {
+ if (targetOS.contains("ios"))
+ _specsPluginBaseName = "iOSPlatform";
+ if (targetOS.contains("tvos"))
+ _specsPluginBaseName = "AppleTV";
+ if (targetOS.contains("watchos"))
+ _specsPluginBaseName = "Watch";
+ }
+
+ var _archSpecsDir = _specsPluginBaseName
+ ? FileInfo.joinPaths(devicePlatformPath, "Developer", "Library", "Xcode",
+ "PrivatePlugIns",
+ "IDE" + _specsPluginBaseName + "SupportCore.ideplugin", "Contents",
+ "Resources")
+ : FileInfo.joinPaths(platformPath, "Developer", "Library", "Xcode", "Specifications");
+
+ var _archSpecsFileBaseName = targetOS.contains("ios")
+ ? (targetOS.contains("ios-simulator") ? "iPhone Simulator " : "iPhoneOS")
+ : DarwinTools.applePlatformDirectoryName(targetOS, platformType) + " ";
+
+ if (_specsPluginBaseName) {
+ switch (platformType) {
+ case "device":
+ return FileInfo.joinPaths(_archSpecsDir, "Device.xcspec");
+ case "simulator":
+ return FileInfo.joinPaths(_archSpecsDir, "Simulator.xcspec");
+ }
+ }
+
+ return FileInfo.joinPaths(_archSpecsDir, _archSpecsFileBaseName + "Architectures.xcspec");
+}
diff --git a/share/qbs/modules/xcode/xcode.qbs b/share/qbs/modules/xcode/xcode.qbs
index 98b7bd9dd..60f49fe71 100644
--- a/share/qbs/modules/xcode/xcode.qbs
+++ b/share/qbs/modules/xcode/xcode.qbs
@@ -10,19 +10,23 @@ import qbs.PropertyList
import 'xcode.js' as Xcode
Module {
- Probe {
- id: xcodeProbe
- configure: {
- availableSdks = Xcode.sdkInfoList(sdksPath);
- found = true;
- }
+ id: xcodeModule
- property var availableSdks
+ Probes.XcodeProbe {
+ id: xcodeProbe
+ developerPath: xcodeModule.developerPath
+ platformType: xcodeModule.platformType
+ platformPath: xcodeModule.platformPath
+ devicePlatformPath: xcodeModule.devicePlatformPath
+ xcodebuildPath: xcodeModule.xcodebuildPath
+ sdksPath: xcodeModule.sdksPath
}
condition: qbs.targetOS.contains("darwin") &&
qbs.toolchain && qbs.toolchain.contains("xcode")
+ version: xcodeProbe.xcodeVersion
+
property path developerPath: "/Applications/Xcode.app/Contents/Developer"
property string sdk: DarwinTools.applePlatformName(qbs.targetOS, platformType)
property stringList targetDevices: DarwinTools.targetDevices(qbs.targetOS)
@@ -85,6 +89,9 @@ Module {
property string provisioningProfile
+ property string xcodebuildName: "xcodebuild"
+ property string xcodebuildPath: FileInfo.joinPaths(developerPath, "usr", "bin", xcodebuildName)
+
property string securityName: "security"
property string securityPath: securityName
@@ -98,6 +105,16 @@ Module {
DarwinTools.applePlatformDirectoryName(
qbs.targetOS, platformType)
+ ".platform")
+ readonly property path devicePlatformPath: FileInfo.joinPaths(
+ platformsPath,
+ DarwinTools.applePlatformDirectoryName(
+ qbs.targetOS, "device")
+ + ".platform")
+ readonly property path simulatorPlatformPath: FileInfo.joinPaths(
+ platformsPath,
+ DarwinTools.applePlatformDirectoryName(
+ qbs.targetOS, "simulator")
+ + ".platform")
readonly property path sdkPath: FileInfo.joinPaths(sdksPath,
DarwinTools.applePlatformDirectoryName(
qbs.targetOS, platformType, sdkVersion)
@@ -130,6 +147,10 @@ Module {
return FileInfo.joinPaths(Environment.getEnv("HOME"), "Library/MobileDevice/Provisioning Profiles");
}
+ readonly property stringList standardArchitectures: _architectureSettings["ARCHS_STANDARD"]
+
+ readonly property var _architectureSettings: xcodeProbe.architectureSettings
+
readonly property var _availableSdks: xcodeProbe.availableSdks
readonly property var _latestSdk: _availableSdks[_availableSdks.length - 1]
diff --git a/share/share.qbs b/share/share.qbs
index 8f1aa673f..7cb75b883 100644
--- a/share/share.qbs
+++ b/share/share.qbs
@@ -17,6 +17,25 @@ Product {
}
Group {
+ name: "Python executables"
+ files: ["../src/3rdparty/python/bin/dmgbuild"]
+ fileTags: ["qbs resources"]
+ qbs.install: true
+ qbs.installDir: qbsbuildconfig.libexecInstallDir
+ qbs.installSourceBase: "../src/3rdparty/python/bin"
+ }
+
+ Group {
+ name: "Python packages"
+ prefix: "../src/3rdparty/python/**/"
+ files: ["*.py"]
+ fileTags: ["qbs resources"]
+ qbs.install: true
+ qbs.installDir: qbsbuildconfig.resourcesInstallDir + "/share/qbs/python"
+ qbs.installSourceBase: "../src/3rdparty/python/lib/python2.7/site-packages"
+ }
+
+ Group {
name: "Modules and imports"
files: ["qbs/**/*"]
fileTags: ["qbs resources"]
@@ -37,9 +56,11 @@ Product {
Rule {
inputs: ["qbs resources"]
Artifact {
- filePath: FileInfo.joinPaths(project.buildDirectory,
- product.moduleProperty("qbsbuildconfig", "resourcesInstallDir"),
- "share", FileInfo.relativePath(product.sourceDirectory, input.filePath))
+ filePath: FileInfo.joinPaths(
+ project.buildDirectory,
+ input.moduleProperty("qbs", "installDir"),
+ FileInfo.relativePath(input.moduleProperty("qbs", "installSourceBase"),
+ input.filePath))
fileTags: ["copied qbs resources"]
}
prepare: {
diff --git a/src/3rdparty/python/.gitignore b/src/3rdparty/python/.gitignore
new file mode 100644
index 000000000..3a4de078a
--- /dev/null
+++ b/src/3rdparty/python/.gitignore
@@ -0,0 +1,3 @@
+*.pyc
+*.dist-info
+*.egg-info
diff --git a/src/3rdparty/python/bin/dmgbuild b/src/3rdparty/python/bin/dmgbuild
new file mode 100755
index 000000000..113ae0998
--- /dev/null
+++ b/src/3rdparty/python/bin/dmgbuild
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from __future__ import unicode_literals
+from __future__ import print_function
+
+import dmgbuild
+import sys
+import argparse
+
+parser = argparse.ArgumentParser(description='Construct a disk image file.')
+parser.add_argument('volume_name', metavar='volume-name',
+ help='The name to give to the volume (this will appear in the title bar when the user mounts the disk image).')
+parser.add_argument('filename', metavar='output.dmg',
+ help='The filename of the disk image to create.')
+parser.add_argument('-s', '--settings',
+ help='The path of the settings file.')
+parser.add_argument('-D', dest='defines', action='append', default=[],
+ help='Define a value for the settings file (e.g. -Dfoo=bar).')
+parser.add_argument('--no-hidpi', dest='lookForHiDPI', action='store_false', default=True,
+ help='Do not search for HiDPI versions of the background image (if specified)')
+
+
+args = parser.parse_args()
+
+defines = {}
+for d in args.defines:
+ k,v = d.split('=', 1)
+ k = k.strip()
+ v = v.strip()
+ if (v.startswith("'") and v.endswith("'")) \
+ or (v.startswith('"') and v.endswith('"')):
+ v = v[1:-1]
+ defines[k] = v
+
+dmgbuild.build_dmg(args.filename, args.volume_name, args.settings, defines=defines, lookForHiDPI=args.lookForHiDPI)
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/biplist/LICENSE b/src/3rdparty/python/lib/python2.7/site-packages/biplist/LICENSE
new file mode 100644
index 000000000..1c7ba6cc1
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/biplist/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2010, Andrew Wooster
+All rights reserved.
+
+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 biplist 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 HOLDER 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.
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/biplist/__init__.py b/src/3rdparty/python/lib/python2.7/site-packages/biplist/__init__.py
new file mode 100644
index 000000000..9cab05ec3
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/biplist/__init__.py
@@ -0,0 +1,870 @@
+"""biplist -- a library for reading and writing binary property list files.
+
+Binary Property List (plist) files provide a faster and smaller serialization
+format for property lists on OS X. This is a library for generating binary
+plists which can be read by OS X, iOS, or other clients.
+
+The API models the plistlib API, and will call through to plistlib when
+XML serialization or deserialization is required.
+
+To generate plists with UID values, wrap the values with the Uid object. The
+value must be an int.
+
+To generate plists with NSData/CFData values, wrap the values with the
+Data object. The value must be a string.
+
+Date values can only be datetime.datetime objects.
+
+The exceptions InvalidPlistException and NotBinaryPlistException may be
+thrown to indicate that the data cannot be serialized or deserialized as
+a binary plist.
+
+Plist generation example:
+
+ from biplist import *
+ from datetime import datetime
+ plist = {'aKey':'aValue',
+ '0':1.322,
+ 'now':datetime.now(),
+ 'list':[1,2,3],
+ 'tuple':('a','b','c')
+ }
+ try:
+ writePlist(plist, "example.plist")
+ except (InvalidPlistException, NotBinaryPlistException), e:
+ print "Something bad happened:", e
+
+Plist parsing example:
+
+ from biplist import *
+ try:
+ plist = readPlist("example.plist")
+ print plist
+ except (InvalidPlistException, NotBinaryPlistException), e:
+ print "Not a plist:", e
+"""
+
+from collections import namedtuple
+import datetime
+import io
+import math
+import plistlib
+from struct import pack, unpack, unpack_from
+from struct import error as struct_error
+import sys
+import time
+
+try:
+ unicode
+ unicodeEmpty = r''
+except NameError:
+ unicode = str
+ unicodeEmpty = ''
+try:
+ long
+except NameError:
+ long = int
+try:
+ {}.iteritems
+ iteritems = lambda x: x.iteritems()
+except AttributeError:
+ iteritems = lambda x: x.items()
+
+__all__ = [
+ 'Uid', 'Data', 'readPlist', 'writePlist', 'readPlistFromString',
+ 'writePlistToString', 'InvalidPlistException', 'NotBinaryPlistException'
+]
+
+# Apple uses Jan 1, 2001 as a base for all plist date/times.
+apple_reference_date = datetime.datetime.utcfromtimestamp(978307200)
+
+class Uid(object):
+ """Wrapper around integers for representing UID values. This
+ is used in keyed archiving."""
+ integer = 0
+ def __init__(self, integer):
+ self.integer = integer
+
+ def __repr__(self):
+ return "Uid(%d)" % self.integer
+
+ def __eq__(self, other):
+ if isinstance(self, Uid) and isinstance(other, Uid):
+ return self.integer == other.integer
+ return False
+
+ def __cmp__(self, other):
+ return self.integer - other.integer
+
+ def __lt__(self, other):
+ return self.integer < other.integer
+
+ def __hash__(self):
+ return self.integer
+
+ def __int__(self):
+ return int(self.integer)
+
+class Data(bytes):
+ """Wrapper around bytes to distinguish Data values."""
+
+class InvalidPlistException(Exception):
+ """Raised when the plist is incorrectly formatted."""
+
+class NotBinaryPlistException(Exception):
+ """Raised when a binary plist was expected but not encountered."""
+
+def readPlist(pathOrFile):
+ """Raises NotBinaryPlistException, InvalidPlistException"""
+ didOpen = False
+ result = None
+ if isinstance(pathOrFile, (bytes, unicode)):
+ pathOrFile = open(pathOrFile, 'rb')
+ didOpen = True
+ try:
+ reader = PlistReader(pathOrFile)
+ result = reader.parse()
+ except NotBinaryPlistException as e:
+ try:
+ pathOrFile.seek(0)
+ result = None
+ if hasattr(plistlib, 'loads'):
+ contents = None
+ if isinstance(pathOrFile, (bytes, unicode)):
+ with open(pathOrFile, 'rb') as f:
+ contents = f.read()
+ else:
+ contents = pathOrFile.read()
+ result = plistlib.loads(contents)
+ else:
+ result = plistlib.readPlist(pathOrFile)
+ result = wrapDataObject(result, for_binary=True)
+ except Exception as e:
+ raise InvalidPlistException(e)
+ finally:
+ if didOpen:
+ pathOrFile.close()
+ return result
+
+def wrapDataObject(o, for_binary=False):
+ if isinstance(o, Data) and not for_binary:
+ v = sys.version_info
+ if not (v[0] >= 3 and v[1] >= 4):
+ o = plistlib.Data(o)
+ elif isinstance(o, (bytes, plistlib.Data)) and for_binary:
+ if hasattr(o, 'data'):
+ o = Data(o.data)
+ elif isinstance(o, tuple):
+ o = wrapDataObject(list(o), for_binary)
+ o = tuple(o)
+ elif isinstance(o, list):
+ for i in range(len(o)):
+ o[i] = wrapDataObject(o[i], for_binary)
+ elif isinstance(o, dict):
+ for k in o:
+ o[k] = wrapDataObject(o[k], for_binary)
+ return o
+
+def writePlist(rootObject, pathOrFile, binary=True):
+ if not binary:
+ rootObject = wrapDataObject(rootObject, binary)
+ if hasattr(plistlib, "dump"):
+ if isinstance(pathOrFile, (bytes, unicode)):
+ with open(pathOrFile, 'wb') as f:
+ return plistlib.dump(rootObject, f)
+ else:
+ return plistlib.dump(rootObject, pathOrFile)
+ else:
+ return plistlib.writePlist(rootObject, pathOrFile)
+ else:
+ didOpen = False
+ if isinstance(pathOrFile, (bytes, unicode)):
+ pathOrFile = open(pathOrFile, 'wb')
+ didOpen = True
+ writer = PlistWriter(pathOrFile)
+ result = writer.writeRoot(rootObject)
+ if didOpen:
+ pathOrFile.close()
+ return result
+
+def readPlistFromString(data):
+ return readPlist(io.BytesIO(data))
+
+def writePlistToString(rootObject, binary=True):
+ if not binary:
+ rootObject = wrapDataObject(rootObject, binary)
+ if hasattr(plistlib, "dumps"):
+ return plistlib.dumps(rootObject)
+ elif hasattr(plistlib, "writePlistToBytes"):
+ return plistlib.writePlistToBytes(rootObject)
+ else:
+ return plistlib.writePlistToString(rootObject)
+ else:
+ ioObject = io.BytesIO()
+ writer = PlistWriter(ioObject)
+ writer.writeRoot(rootObject)
+ return ioObject.getvalue()
+
+def is_stream_binary_plist(stream):
+ stream.seek(0)
+ header = stream.read(7)
+ if header == b'bplist0':
+ return True
+ else:
+ return False
+
+PlistTrailer = namedtuple('PlistTrailer', 'offsetSize, objectRefSize, offsetCount, topLevelObjectNumber, offsetTableOffset')
+PlistByteCounts = namedtuple('PlistByteCounts', 'nullBytes, boolBytes, intBytes, realBytes, dateBytes, dataBytes, stringBytes, uidBytes, arrayBytes, setBytes, dictBytes')
+
+class PlistReader(object):
+ file = None
+ contents = ''
+ offsets = None
+ trailer = None
+ currentOffset = 0
+
+ def __init__(self, fileOrStream):
+ """Raises NotBinaryPlistException."""
+ self.reset()
+ self.file = fileOrStream
+
+ def parse(self):
+ return self.readRoot()
+
+ def reset(self):
+ self.trailer = None
+ self.contents = ''
+ self.offsets = []
+ self.currentOffset = 0
+
+ def readRoot(self):
+ result = None
+ self.reset()
+ # Get the header, make sure it's a valid file.
+ if not is_stream_binary_plist(self.file):
+ raise NotBinaryPlistException()
+ self.file.seek(0)
+ self.contents = self.file.read()
+ if len(self.contents) < 32:
+ raise InvalidPlistException("File is too short.")
+ trailerContents = self.contents[-32:]
+ try:
+ self.trailer = PlistTrailer._make(unpack("!xxxxxxBBQQQ", trailerContents))
+ offset_size = self.trailer.offsetSize * self.trailer.offsetCount
+ offset = self.trailer.offsetTableOffset
+ offset_contents = self.contents[offset:offset+offset_size]
+ offset_i = 0
+ while offset_i < self.trailer.offsetCount:
+ begin = self.trailer.offsetSize*offset_i
+ tmp_contents = offset_contents[begin:begin+self.trailer.offsetSize]
+ tmp_sized = self.getSizedInteger(tmp_contents, self.trailer.offsetSize)
+ self.offsets.append(tmp_sized)
+ offset_i += 1
+ self.setCurrentOffsetToObjectNumber(self.trailer.topLevelObjectNumber)
+ result = self.readObject()
+ except TypeError as e:
+ raise InvalidPlistException(e)
+ return result
+
+ def setCurrentOffsetToObjectNumber(self, objectNumber):
+ self.currentOffset = self.offsets[objectNumber]
+
+ def readObject(self):
+ result = None
+ tmp_byte = self.contents[self.currentOffset:self.currentOffset+1]
+ marker_byte = unpack("!B", tmp_byte)[0]
+ format = (marker_byte >> 4) & 0x0f
+ extra = marker_byte & 0x0f
+ self.currentOffset += 1
+
+ def proc_extra(extra):
+ if extra == 0b1111:
+ #self.currentOffset += 1
+ extra = self.readObject()
+ return extra
+
+ # bool, null, or fill byte
+ if format == 0b0000:
+ if extra == 0b0000:
+ result = None
+ elif extra == 0b1000:
+ result = False
+ elif extra == 0b1001:
+ result = True
+ elif extra == 0b1111:
+ pass # fill byte
+ else:
+ raise InvalidPlistException("Invalid object found at offset: %d" % (self.currentOffset - 1))
+ # int
+ elif format == 0b0001:
+ extra = proc_extra(extra)
+ result = self.readInteger(pow(2, extra))
+ # real
+ elif format == 0b0010:
+ extra = proc_extra(extra)
+ result = self.readReal(extra)
+ # date
+ elif format == 0b0011 and extra == 0b0011:
+ result = self.readDate()
+ # data
+ elif format == 0b0100:
+ extra = proc_extra(extra)
+ result = self.readData(extra)
+ # ascii string
+ elif format == 0b0101:
+ extra = proc_extra(extra)
+ result = self.readAsciiString(extra)
+ # Unicode string
+ elif format == 0b0110:
+ extra = proc_extra(extra)
+ result = self.readUnicode(extra)
+ # uid
+ elif format == 0b1000:
+ result = self.readUid(extra)
+ # array
+ elif format == 0b1010:
+ extra = proc_extra(extra)
+ result = self.readArray(extra)
+ # set
+ elif format == 0b1100:
+ extra = proc_extra(extra)
+ result = set(self.readArray(extra))
+ # dict
+ elif format == 0b1101:
+ extra = proc_extra(extra)
+ result = self.readDict(extra)
+ else:
+ raise InvalidPlistException("Invalid object found: {format: %s, extra: %s}" % (bin(format), bin(extra)))
+ return result
+
+ def readInteger(self, byteSize):
+ result = 0
+ original_offset = self.currentOffset
+ data = self.contents[self.currentOffset:self.currentOffset + byteSize]
+ result = self.getSizedInteger(data, byteSize, as_number=True)
+ self.currentOffset = original_offset + byteSize
+ return result
+
+ def readReal(self, length):
+ result = 0.0
+ to_read = pow(2, length)
+ data = self.contents[self.currentOffset:self.currentOffset+to_read]
+ if length == 2: # 4 bytes
+ result = unpack('>f', data)[0]
+ elif length == 3: # 8 bytes
+ result = unpack('>d', data)[0]
+ else:
+ raise InvalidPlistException("Unknown real of length %d bytes" % to_read)
+ return result
+
+ def readRefs(self, count):
+ refs = []
+ i = 0
+ while i < count:
+ fragment = self.contents[self.currentOffset:self.currentOffset+self.trailer.objectRefSize]
+ ref = self.getSizedInteger(fragment, len(fragment))
+ refs.append(ref)
+ self.currentOffset += self.trailer.objectRefSize
+ i += 1
+ return refs
+
+ def readArray(self, count):
+ result = []
+ values = self.readRefs(count)
+ i = 0
+ while i < len(values):
+ self.setCurrentOffsetToObjectNumber(values[i])
+ value = self.readObject()
+ result.append(value)
+ i += 1
+ return result
+
+ def readDict(self, count):
+ result = {}
+ keys = self.readRefs(count)
+ values = self.readRefs(count)
+ i = 0
+ while i < len(keys):
+ self.setCurrentOffsetToObjectNumber(keys[i])
+ key = self.readObject()
+ self.setCurrentOffsetToObjectNumber(values[i])
+ value = self.readObject()
+ result[key] = value
+ i += 1
+ return result
+
+ def readAsciiString(self, length):
+ result = unpack("!%ds" % length, self.contents[self.currentOffset:self.currentOffset+length])[0]
+ self.currentOffset += length
+ return str(result.decode('ascii'))
+
+ def readUnicode(self, length):
+ actual_length = length*2
+ data = self.contents[self.currentOffset:self.currentOffset+actual_length]
+ # unpack not needed?!! data = unpack(">%ds" % (actual_length), data)[0]
+ self.currentOffset += actual_length
+ return data.decode('utf_16_be')
+
+ def readDate(self):
+ result = unpack(">d", self.contents[self.currentOffset:self.currentOffset+8])[0]
+ # Use timedelta to workaround time_t size limitation on 32-bit python.
+ result = datetime.timedelta(seconds=result) + apple_reference_date
+ self.currentOffset += 8
+ return result
+
+ def readData(self, length):
+ result = self.contents[self.currentOffset:self.currentOffset+length]
+ self.currentOffset += length
+ return Data(result)
+
+ def readUid(self, length):
+ return Uid(self.readInteger(length+1))
+
+ def getSizedInteger(self, data, byteSize, as_number=False):
+ """Numbers of 8 bytes are signed integers when they refer to numbers, but unsigned otherwise."""
+ result = 0
+ # 1, 2, and 4 byte integers are unsigned
+ if byteSize == 1:
+ result = unpack('>B', data)[0]
+ elif byteSize == 2:
+ result = unpack('>H', data)[0]
+ elif byteSize == 4:
+ result = unpack('>L', data)[0]
+ elif byteSize == 8:
+ if as_number:
+ result = unpack('>q', data)[0]
+ else:
+ result = unpack('>Q', data)[0]
+ elif byteSize <= 16:
+ # Handle odd-sized or integers larger than 8 bytes
+ # Don't naively go over 16 bytes, in order to prevent infinite loops.
+ result = 0
+ if hasattr(int, 'from_bytes'):
+ result = int.from_bytes(data, 'big')
+ else:
+ for byte in data:
+ if not isinstance(byte, int): # Python3.0-3.1.x return ints, 2.x return str
+ byte = unpack_from('>B', byte)[0]
+ result = (result << 8) | byte
+ else:
+ raise InvalidPlistException("Encountered integer longer than 16 bytes.")
+ return result
+
+class HashableWrapper(object):
+ def __init__(self, value):
+ self.value = value
+ def __repr__(self):
+ return "<HashableWrapper: %s>" % [self.value]
+
+class BoolWrapper(object):
+ def __init__(self, value):
+ self.value = value
+ def __repr__(self):
+ return "<BoolWrapper: %s>" % self.value
+
+class FloatWrapper(object):
+ _instances = {}
+ def __new__(klass, value):
+ # Ensure FloatWrapper(x) for a given float x is always the same object
+ wrapper = klass._instances.get(value)
+ if wrapper is None:
+ wrapper = object.__new__(klass)
+ wrapper.value = value
+ klass._instances[value] = wrapper
+ return wrapper
+ def __repr__(self):
+ return "<FloatWrapper: %s>" % self.value
+
+class StringWrapper(object):
+ __instances = {}
+
+ encodedValue = None
+ encoding = None
+
+ def __new__(cls, value):
+ '''Ensure we only have a only one instance for any string,
+ and that we encode ascii as 1-byte-per character when possible'''
+
+ encodedValue = None
+
+ for encoding in ('ascii', 'utf_16_be'):
+ try:
+ encodedValue = value.encode(encoding)
+ except: pass
+ if encodedValue is not None:
+ if encodedValue not in cls.__instances:
+ cls.__instances[encodedValue] = super(StringWrapper, cls).__new__(cls)
+ cls.__instances[encodedValue].encodedValue = encodedValue
+ cls.__instances[encodedValue].encoding = encoding
+ return cls.__instances[encodedValue]
+
+ raise ValueError('Unable to get ascii or utf_16_be encoding for %s' % repr(value))
+
+ def __len__(self):
+ '''Return roughly the number of characters in this string (half the byte length)'''
+ if self.encoding == 'ascii':
+ return len(self.encodedValue)
+ else:
+ return len(self.encodedValue)//2
+
+ @property
+ def encodingMarker(self):
+ if self.encoding == 'ascii':
+ return 0b0101
+ else:
+ return 0b0110
+
+ def __repr__(self):
+ return '<StringWrapper (%s): %s>' % (self.encoding, self.encodedValue)
+
+class PlistWriter(object):
+ header = b'bplist00bybiplist1.0'
+ file = None
+ byteCounts = None
+ trailer = None
+ computedUniques = None
+ writtenReferences = None
+ referencePositions = None
+ wrappedTrue = None
+ wrappedFalse = None
+
+ def __init__(self, file):
+ self.reset()
+ self.file = file
+ self.wrappedTrue = BoolWrapper(True)
+ self.wrappedFalse = BoolWrapper(False)
+
+ def reset(self):
+ self.byteCounts = PlistByteCounts(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+ self.trailer = PlistTrailer(0, 0, 0, 0, 0)
+
+ # A set of all the uniques which have been computed.
+ self.computedUniques = set()
+ # A list of all the uniques which have been written.
+ self.writtenReferences = {}
+ # A dict of the positions of the written uniques.
+ self.referencePositions = {}
+
+ def positionOfObjectReference(self, obj):
+ """If the given object has been written already, return its
+ position in the offset table. Otherwise, return None."""
+ return self.writtenReferences.get(obj)
+
+ def writeRoot(self, root):
+ """
+ Strategy is:
+ - write header
+ - wrap root object so everything is hashable
+ - compute size of objects which will be written
+ - need to do this in order to know how large the object refs
+ will be in the list/dict/set reference lists
+ - write objects
+ - keep objects in writtenReferences
+ - keep positions of object references in referencePositions
+ - write object references with the length computed previously
+ - computer object reference length
+ - write object reference positions
+ - write trailer
+ """
+ output = self.header
+ wrapped_root = self.wrapRoot(root)
+ self.computeOffsets(wrapped_root, asReference=True, isRoot=True)
+ self.trailer = self.trailer._replace(**{'objectRefSize':self.intSize(len(self.computedUniques))})
+ self.writeObjectReference(wrapped_root, output)
+ output = self.writeObject(wrapped_root, output, setReferencePosition=True)
+
+ # output size at this point is an upper bound on how big the
+ # object reference offsets need to be.
+ self.trailer = self.trailer._replace(**{
+ 'offsetSize':self.intSize(len(output)),
+ 'offsetCount':len(self.computedUniques),
+ 'offsetTableOffset':len(output),
+ 'topLevelObjectNumber':0
+ })
+
+ output = self.writeOffsetTable(output)
+ output += pack('!xxxxxxBBQQQ', *self.trailer)
+ self.file.write(output)
+
+ def wrapRoot(self, root):
+ if isinstance(root, bool):
+ if root is True:
+ return self.wrappedTrue
+ else:
+ return self.wrappedFalse
+ elif isinstance(root, float):
+ return FloatWrapper(root)
+ elif isinstance(root, set):
+ n = set()
+ for value in root:
+ n.add(self.wrapRoot(value))
+ return HashableWrapper(n)
+ elif isinstance(root, dict):
+ n = {}
+ for key, value in iteritems(root):
+ n[self.wrapRoot(key)] = self.wrapRoot(value)
+ return HashableWrapper(n)
+ elif isinstance(root, list):
+ n = []
+ for value in root:
+ n.append(self.wrapRoot(value))
+ return HashableWrapper(n)
+ elif isinstance(root, tuple):
+ n = tuple([self.wrapRoot(value) for value in root])
+ return HashableWrapper(n)
+ elif isinstance(root, (str, unicode)) and not isinstance(root, Data):
+ return StringWrapper(root)
+ elif isinstance(root, bytes):
+ return Data(root)
+ else:
+ return root
+
+ def incrementByteCount(self, field, incr=1):
+ self.byteCounts = self.byteCounts._replace(**{field:self.byteCounts.__getattribute__(field) + incr})
+
+ def computeOffsets(self, obj, asReference=False, isRoot=False):
+ def check_key(key):
+ if key is None:
+ raise InvalidPlistException('Dictionary keys cannot be null in plists.')
+ elif isinstance(key, Data):
+ raise InvalidPlistException('Data cannot be dictionary keys in plists.')
+ elif not isinstance(key, StringWrapper):
+ raise InvalidPlistException('Keys must be strings.')
+
+ def proc_size(size):
+ if size > 0b1110:
+ size += self.intSize(size)
+ return size
+ # If this should be a reference, then we keep a record of it in the
+ # uniques table.
+ if asReference:
+ if obj in self.computedUniques:
+ return
+ else:
+ self.computedUniques.add(obj)
+
+ if obj is None:
+ self.incrementByteCount('nullBytes')
+ elif isinstance(obj, BoolWrapper):
+ self.incrementByteCount('boolBytes')
+ elif isinstance(obj, Uid):
+ size = self.intSize(obj.integer)
+ self.incrementByteCount('uidBytes', incr=1+size)
+ elif isinstance(obj, (int, long)):
+ size = self.intSize(obj)
+ self.incrementByteCount('intBytes', incr=1+size)
+ elif isinstance(obj, FloatWrapper):
+ size = self.realSize(obj)
+ self.incrementByteCount('realBytes', incr=1+size)
+ elif isinstance(obj, datetime.datetime):
+ self.incrementByteCount('dateBytes', incr=2)
+ elif isinstance(obj, Data):
+ size = proc_size(len(obj))
+ self.incrementByteCount('dataBytes', incr=1+size)
+ elif isinstance(obj, StringWrapper):
+ size = proc_size(len(obj))
+ self.incrementByteCount('stringBytes', incr=1+size)
+ elif isinstance(obj, HashableWrapper):
+ obj = obj.value
+ if isinstance(obj, set):
+ size = proc_size(len(obj))
+ self.incrementByteCount('setBytes', incr=1+size)
+ for value in obj:
+ self.computeOffsets(value, asReference=True)
+ elif isinstance(obj, (list, tuple)):
+ size = proc_size(len(obj))
+ self.incrementByteCount('arrayBytes', incr=1+size)
+ for value in obj:
+ asRef = True
+ self.computeOffsets(value, asReference=True)
+ elif isinstance(obj, dict):
+ size = proc_size(len(obj))
+ self.incrementByteCount('dictBytes', incr=1+size)
+ for key, value in iteritems(obj):
+ check_key(key)
+ self.computeOffsets(key, asReference=True)
+ self.computeOffsets(value, asReference=True)
+ else:
+ raise InvalidPlistException("Unknown object type: %s (%s)" % (type(obj).__name__, repr(obj)))
+
+ def writeObjectReference(self, obj, output):
+ """Tries to write an object reference, adding it to the references
+ table. Does not write the actual object bytes or set the reference
+ position. Returns a tuple of whether the object was a new reference
+ (True if it was, False if it already was in the reference table)
+ and the new output.
+ """
+ position = self.positionOfObjectReference(obj)
+ if position is None:
+ self.writtenReferences[obj] = len(self.writtenReferences)
+ output += self.binaryInt(len(self.writtenReferences) - 1, byteSize=self.trailer.objectRefSize)
+ return (True, output)
+ else:
+ output += self.binaryInt(position, byteSize=self.trailer.objectRefSize)
+ return (False, output)
+
+ def writeObject(self, obj, output, setReferencePosition=False):
+ """Serializes the given object to the output. Returns output.
+ If setReferencePosition is True, will set the position the
+ object was written.
+ """
+ def proc_variable_length(format, length):
+ result = b''
+ if length > 0b1110:
+ result += pack('!B', (format << 4) | 0b1111)
+ result = self.writeObject(length, result)
+ else:
+ result += pack('!B', (format << 4) | length)
+ return result
+
+ def timedelta_total_seconds(td):
+ # Shim for Python 2.6 compatibility, which doesn't have total_seconds.
+ # Make one argument a float to ensure the right calculation.
+ return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10.0**6) / 10.0**6
+
+ if setReferencePosition:
+ self.referencePositions[obj] = len(output)
+
+ if obj is None:
+ output += pack('!B', 0b00000000)
+ elif isinstance(obj, BoolWrapper):
+ if obj.value is False:
+ output += pack('!B', 0b00001000)
+ else:
+ output += pack('!B', 0b00001001)
+ elif isinstance(obj, Uid):
+ size = self.intSize(obj.integer)
+ output += pack('!B', (0b1000 << 4) | size - 1)
+ output += self.binaryInt(obj.integer)
+ elif isinstance(obj, (int, long)):
+ byteSize = self.intSize(obj)
+ root = math.log(byteSize, 2)
+ output += pack('!B', (0b0001 << 4) | int(root))
+ output += self.binaryInt(obj, as_number=True)
+ elif isinstance(obj, FloatWrapper):
+ # just use doubles
+ output += pack('!B', (0b0010 << 4) | 3)
+ output += self.binaryReal(obj)
+ elif isinstance(obj, datetime.datetime):
+ try:
+ timestamp = (obj - apple_reference_date).total_seconds()
+ except AttributeError:
+ timestamp = timedelta_total_seconds(obj - apple_reference_date)
+ output += pack('!B', 0b00110011)
+ output += pack('!d', float(timestamp))
+ elif isinstance(obj, Data):
+ output += proc_variable_length(0b0100, len(obj))
+ output += obj
+ elif isinstance(obj, StringWrapper):
+ output += proc_variable_length(obj.encodingMarker, len(obj))
+ output += obj.encodedValue
+ elif isinstance(obj, bytes):
+ output += proc_variable_length(0b0101, len(obj))
+ output += obj
+ elif isinstance(obj, HashableWrapper):
+ obj = obj.value
+ if isinstance(obj, (set, list, tuple)):
+ if isinstance(obj, set):
+ output += proc_variable_length(0b1100, len(obj))
+ else:
+ output += proc_variable_length(0b1010, len(obj))
+
+ objectsToWrite = []
+ for objRef in obj:
+ (isNew, output) = self.writeObjectReference(objRef, output)
+ if isNew:
+ objectsToWrite.append(objRef)
+ for objRef in objectsToWrite:
+ output = self.writeObject(objRef, output, setReferencePosition=True)
+ elif isinstance(obj, dict):
+ output += proc_variable_length(0b1101, len(obj))
+ keys = []
+ values = []
+ objectsToWrite = []
+ for key, value in iteritems(obj):
+ keys.append(key)
+ values.append(value)
+ for key in keys:
+ (isNew, output) = self.writeObjectReference(key, output)
+ if isNew:
+ objectsToWrite.append(key)
+ for value in values:
+ (isNew, output) = self.writeObjectReference(value, output)
+ if isNew:
+ objectsToWrite.append(value)
+ for objRef in objectsToWrite:
+ output = self.writeObject(objRef, output, setReferencePosition=True)
+ return output
+
+ def writeOffsetTable(self, output):
+ """Writes all of the object reference offsets."""
+ all_positions = []
+ writtenReferences = list(self.writtenReferences.items())
+ writtenReferences.sort(key=lambda x: x[1])
+ for obj,order in writtenReferences:
+ # Porting note: Elsewhere we deliberately replace empty unicdoe strings
+ # with empty binary strings, but the empty unicode string
+ # goes into writtenReferences. This isn't an issue in Py2
+ # because u'' and b'' have the same hash; but it is in
+ # Py3, where they don't.
+ if bytes != str and obj == unicodeEmpty:
+ obj = b''
+ position = self.referencePositions.get(obj)
+ if position is None:
+ raise InvalidPlistException("Error while writing offsets table. Object not found. %s" % obj)
+ output += self.binaryInt(position, self.trailer.offsetSize)
+ all_positions.append(position)
+ return output
+
+ def binaryReal(self, obj):
+ # just use doubles
+ result = pack('>d', obj.value)
+ return result
+
+ def binaryInt(self, obj, byteSize=None, as_number=False):
+ result = b''
+ if byteSize is None:
+ byteSize = self.intSize(obj)
+ if byteSize == 1:
+ result += pack('>B', obj)
+ elif byteSize == 2:
+ result += pack('>H', obj)
+ elif byteSize == 4:
+ result += pack('>L', obj)
+ elif byteSize == 8:
+ if as_number:
+ result += pack('>q', obj)
+ else:
+ result += pack('>Q', obj)
+ elif byteSize <= 16:
+ try:
+ result = pack('>Q', 0) + pack('>Q', obj)
+ except struct_error as e:
+ raise InvalidPlistException("Unable to pack integer %d: %s" % (obj, e))
+ else:
+ raise InvalidPlistException("Core Foundation can't handle integers with size greater than 16 bytes.")
+ return result
+
+ def intSize(self, obj):
+ """Returns the number of bytes necessary to store the given integer."""
+ # SIGNED
+ if obj < 0: # Signed integer, always 8 bytes
+ return 8
+ # UNSIGNED
+ elif obj <= 0xFF: # 1 byte
+ return 1
+ elif obj <= 0xFFFF: # 2 bytes
+ return 2
+ elif obj <= 0xFFFFFFFF: # 4 bytes
+ return 4
+ # SIGNED
+ # 0x7FFFFFFFFFFFFFFF is the max.
+ elif obj <= 0x7FFFFFFFFFFFFFFF: # 8 bytes signed
+ return 8
+ elif obj <= 0xffffffffffffffff: # 8 bytes unsigned
+ return 16
+ else:
+ raise InvalidPlistException("Core Foundation can't handle integers with size greater than 8 bytes.")
+
+ def realSize(self, obj):
+ return 8
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/biplist/qt_attribution.json b/src/3rdparty/python/lib/python2.7/site-packages/biplist/qt_attribution.json
new file mode 100644
index 000000000..6b0df2d21
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/biplist/qt_attribution.json
@@ -0,0 +1,13 @@
+{
+ "Id": "biplist",
+ "Name": "biplist",
+ "QDocModule": "qbs",
+ "QtUsage": "Used in the qbs dmg module for building Apple disk images.",
+ "Description": "biplist is a library for reading/writing binary plists.",
+ "Homepage": "https://bitbucket.org/wooster/biplist",
+ "Version": "1.0.1",
+ "License": "BSD 3-clause "New" or "Revised" License",
+ "LicenseId": "BSD-3-Clause",
+ "LicenseFile": "LICENSE",
+ "Copyright": "Copyright (c) 2010, Andrew Wooster"
+}
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/LICENSE b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/LICENSE
new file mode 100644
index 000000000..e91f4eb38
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2014 Alastair Houghton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/__init__.py b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/__init__.py
new file mode 100644
index 000000000..e7f985c32
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/__init__.py
@@ -0,0 +1,3 @@
+from .core import build_dmg
+
+__all__ = ['dmgbuild']
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/badge.py b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/badge.py
new file mode 100644
index 000000000..159a53708
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/badge.py
@@ -0,0 +1,143 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from Quartz import *
+import math
+
+_REMOVABLE_DISK_PATH = '/System/Library/Extensions/IOStorageFamily.kext/Contents/Resources/Removable.icns'
+
+def badge_disk_icon(badge_file, output_file):
+ # Load the Removable disk icon
+ url = CFURLCreateWithFileSystemPath(None, _REMOVABLE_DISK_PATH,
+ kCFURLPOSIXPathStyle, False)
+ backdrop = CGImageSourceCreateWithURL(url, None)
+ backdropCount = CGImageSourceGetCount(backdrop)
+
+ # Load the badge
+ url = CFURLCreateWithFileSystemPath(None, badge_file,
+ kCFURLPOSIXPathStyle, False)
+ badge = CGImageSourceCreateWithURL(url, None)
+ assert badge is not None, 'Unable to process image file: %s' % badge_file
+ badgeCount = CGImageSourceGetCount(badge)
+
+ # Set up a destination for our target
+ url = CFURLCreateWithFileSystemPath(None, output_file,
+ kCFURLPOSIXPathStyle, False)
+ target = CGImageDestinationCreateWithURL(url, 'com.apple.icns',
+ backdropCount, None)
+
+ # Get the RGB colorspace
+ rgbColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB)
+
+ # Scale
+ scale = 1.0
+
+ # Perspective transform
+ corners = ((0.2, 0.95), (0.8, 0.95), (0.85, 0.35), (0.15, 0.35))
+
+ # Translation
+ position = (0.5, 0.5)
+
+ for n in range(backdropCount):
+ props = CGImageSourceCopyPropertiesAtIndex(backdrop, n, None)
+ width = props['PixelWidth']
+ height = props['PixelHeight']
+ dpi = props['DPIWidth']
+ depth = props['Depth']
+
+ # Choose the best sized badge image
+ bestWidth = None
+ bestHeight = None
+ bestBadge = None
+ bestDepth = None
+ bestDPI = None
+ for m in range(badgeCount):
+ badgeProps = CGImageSourceCopyPropertiesAtIndex(badge, m, None)
+ badgeWidth = badgeProps['PixelWidth']
+ badgeHeight = badgeProps['PixelHeight']
+ badgeDPI = badgeProps['DPIWidth']
+ badgeDepth = badgeProps['Depth']
+
+ if bestBadge is None or (badgeWidth <= width
+ and (bestWidth > width
+ or badgeWidth > bestWidth
+ or (badgeWidth == bestWidth
+ and badgeDPI == dpi
+ and badgeDepth <= depth
+ and (bestDepth is None
+ or badgeDepth > bestDepth)))):
+ bestBadge = m
+ bestWidth = badgeWidth
+ bestHeight = badgeHeight
+ bestDPI = badgeDPI
+ bestDepth = badgeDepth
+
+ badgeImage = CGImageSourceCreateImageAtIndex(badge, bestBadge, None)
+ badgeCI = CIImage.imageWithCGImage_(badgeImage)
+
+ backgroundImage = CGImageSourceCreateImageAtIndex(backdrop, n, None)
+ backgroundCI = CIImage.imageWithCGImage_(backgroundImage)
+
+ compositor = CIFilter.filterWithName_('CISourceOverCompositing')
+ lanczos = CIFilter.filterWithName_('CILanczosScaleTransform')
+ perspective = CIFilter.filterWithName_('CIPerspectiveTransform')
+ transform = CIFilter.filterWithName_('CIAffineTransform')
+
+ lanczos.setValue_forKey_(badgeCI, kCIInputImageKey)
+ lanczos.setValue_forKey_(scale * float(width)/bestWidth, kCIInputScaleKey)
+ lanczos.setValue_forKey_(1.0, kCIInputAspectRatioKey)
+
+ topLeft = (width * scale * corners[0][0],
+ width * scale * corners[0][1])
+ topRight = (width * scale * corners[1][0],
+ width * scale * corners[1][1])
+ bottomRight = (width * scale * corners[2][0],
+ width * scale * corners[2][1])
+ bottomLeft = (width * scale * corners[3][0],
+ width * scale * corners[3][1])
+
+ out = lanczos.valueForKey_(kCIOutputImageKey)
+ if width >= 16:
+ perspective.setValue_forKey_(out, kCIInputImageKey)
+ perspective.setValue_forKey_(CIVector.vectorWithX_Y_(*topLeft),
+ 'inputTopLeft')
+ perspective.setValue_forKey_(CIVector.vectorWithX_Y_(*topRight),
+ 'inputTopRight')
+ perspective.setValue_forKey_(CIVector.vectorWithX_Y_(*bottomRight),
+ 'inputBottomRight')
+ perspective.setValue_forKey_(CIVector.vectorWithX_Y_(*bottomLeft),
+ 'inputBottomLeft')
+ out = perspective.valueForKey_(kCIOutputImageKey)
+
+ tfm = NSAffineTransform.transform()
+ tfm.translateXBy_yBy_(math.floor((position[0] - 0.5 * scale) * width),
+ math.floor((position[1] - 0.5 * scale) * height))
+
+ transform.setValue_forKey_(out, kCIInputImageKey)
+ transform.setValue_forKey_(tfm, 'inputTransform')
+ out = transform.valueForKey_(kCIOutputImageKey)
+
+ compositor.setValue_forKey_(out, kCIInputImageKey)
+ compositor.setValue_forKey_(backgroundCI, kCIInputBackgroundImageKey)
+
+ result = compositor.valueForKey_(kCIOutputImageKey)
+
+ cgContext = CGBitmapContextCreate(None,
+ width,
+ height,
+ 8,
+ 0,
+ rgbColorSpace,
+ kCGImageAlphaPremultipliedLast)
+ context = CIContext.contextWithCGContext_options_(cgContext, None)
+
+ context.drawImage_inRect_fromRect_(result,
+ ((0, 0), (width, height)),
+ ((0, 0), (width, height)))
+
+ image = CGBitmapContextCreateImage(cgContext)
+
+ CGImageDestinationAddImage(target, image, props)
+
+ CGImageDestinationFinalize(target)
+
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/colors.py b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/colors.py
new file mode 100644
index 000000000..1d252a6bd
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/colors.py
@@ -0,0 +1,494 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+import re
+import math
+
+class Color (object):
+ def to_rgb(self):
+ raise Exception('Must implement to_rgb() in subclasses')
+
+class RGB (Color):
+ def __init__(self, r, g, b):
+ self.r = r
+ self.g = g
+ self.b = b
+
+ def to_rgb(self):
+ return self
+
+class HSL (Color):
+ def __init__(self, h, s, l):
+ self.h = h
+ self.s = s
+ self.l = l
+
+ @staticmethod
+ def _hue_to_rgb(t1, t2, hue):
+ if hue < 0:
+ hue += 6
+ elif hue >= 6:
+ hue -= 6
+
+ if hue < 1:
+ return (t2 - t1) * hue + t1
+ elif hue < 3:
+ return t2
+ elif hue < 4:
+ return (t2 - t1) * (4 - hue) + t1
+ else:
+ return t1
+
+ def to_rgb(self):
+ hue = self.h / 60.0
+ if self.l <= 0.5:
+ t2 = self.l * (self.s + 1)
+ else:
+ t2 = self.l + self.s - (self.l * self.s)
+ t1 = self.l * 2 - t2
+ r = self._hue_to_rgb(t1, t2, hue + 2)
+ g = self._hue_to_rgb(t1, t2, hue)
+ b = self._hue_to_rgb(t1, t2, hue - 2)
+ return RGB(r, g, b)
+
+class HWB (Color):
+ def __init__(self, h, w, b):
+ self.h = h
+ self.w = w
+ self.b = b
+
+ @staticmethod
+ def _hue_to_rgb(hue):
+ if hue < 0:
+ hue += 6
+ elif hue >= 6:
+ hue -= 6
+
+ if hue < 1:
+ return hue
+ elif hue < 3:
+ return 1
+ elif hue < 4:
+ return (4 - hue)
+ else:
+ return 0
+
+ def to_rgb(self):
+ hue = self.h / 60.0
+ t1 = 1 - self.w - self.b
+ r = self._hue_to_rgb(hue + 2) * t1 + self.w
+ g = self._hue_to_rgb(hue) * t1 + self.w
+ b = self._hue_to_rgb(hue - 2) * t1 + self.w
+ return RGB(r, g, b)
+
+class CMYK (Color):
+ def __init__(self, c, m, y, k):
+ self.c = c
+ self.m = m
+ self.y = y
+ self.k = k
+
+ def to_rgb(self):
+ r = 1.0 - min(1.0, self.c + self.k)
+ g = 1.0 - min(1.0, self.m + self.k)
+ b = 1.0 - min(1.0, self.y + self.k)
+ return RGB(r, g, b)
+
+class Gray (Color):
+ def __init__(self, g):
+ self.g = g
+
+ def to_rgb(self):
+ return RGB(g, g, g)
+
+_x11_colors = {
+ 'aliceblue': (240, 248, 255),
+ 'antiquewhite': (250, 235, 215),
+ 'aqua': ( 0, 255, 255),
+ 'aquamarine': (127, 255, 212),
+ 'azure': (240, 255, 255),
+ 'beige': (245, 245, 220),
+ 'bisque': (255, 228, 196),
+ 'black': ( 0, 0, 0),
+ 'blanchedalmond': (255, 235, 205),
+ 'blue': ( 0, 0, 255),
+ 'blueviolet': (138, 43, 226),
+ 'brown': (165, 42, 42),
+ 'burlywood': (222, 184, 135),
+ 'cadetblue': ( 95, 158, 160),
+ 'chartreuse': (127, 255, 0),
+ 'chocolate': (210, 105, 30),
+ 'coral': (255, 127, 80),
+ 'cornflowerblue': (100, 149, 237),
+ 'cornsilk': (255, 248, 220),
+ 'crimson': (220, 20, 60),
+ 'cyan': ( 0, 255, 255),
+ 'darkblue': ( 0, 0, 139),
+ 'darkcyan': ( 0, 139, 139),
+ 'darkgoldenrod': (184, 134, 11),
+ 'darkgray': (169, 169, 169),
+ 'darkgreen': ( 0, 100, 0),
+ 'darkgrey': (169, 169, 169),
+ 'darkkhaki': (189, 183, 107),
+ 'darkmagenta': (139, 0, 139),
+ 'darkolivegreen': ( 85, 107, 47),
+ 'darkorange': (255, 140, 0),
+ 'darkorchid': (153, 50, 204),
+ 'darkred': (139, 0, 0),
+ 'darksalmon': (233, 150, 122),
+ 'darkseagreen': (143, 188, 143),
+ 'darkslateblue': ( 72, 61, 139),
+ 'darkslategray': ( 47, 79, 79),
+ 'darkslategrey': ( 47, 79, 79),
+ 'darkturquoise': ( 0, 206, 209),
+ 'darkviolet': (148, 0, 211),
+ 'deeppink': (255, 20, 147),
+ 'deepskyblue': ( 0, 191, 255),
+ 'dimgray': (105, 105, 105),
+ 'dimgrey': (105, 105, 105),
+ 'dodgerblue': ( 30, 144, 255),
+ 'firebrick': (178, 34, 34),
+ 'floralwhite': (255, 250, 240),
+ 'forestgreen': ( 34, 139, 34),
+ 'fuchsia': (255, 0, 255),
+ 'gainsboro': (220, 220, 220),
+ 'ghostwhite': (248, 248, 255),
+ 'gold': (255, 215, 0),
+ 'goldenrod': (218, 165, 32),
+ 'gray': (128, 128, 128),
+ 'grey': (128, 128, 128),
+ 'green': ( 0, 128, 0),
+ 'greenyellow': (173, 255, 47),
+ 'honeydew': (240, 255, 240),
+ 'hotpink': (255, 105, 180),
+ 'indianred': (205, 92, 92),
+ 'indigo': ( 75, 0, 130),
+ 'ivory': (255, 255, 240),
+ 'khaki': (240, 230, 140),
+ 'lavender': (230, 230, 250),
+ 'lavenderblush': (255, 240, 245),
+ 'lawngreen': (124, 252, 0),
+ 'lemonchiffon': (255, 250, 205),
+ 'lightblue': (173, 216, 230),
+ 'lightcoral': (240, 128, 128),
+ 'lightcyan': (224, 255, 255),
+ 'lightgoldenrodyellow': (250, 250, 210),
+ 'lightgray': (211, 211, 211),
+ 'lightgreen': (144, 238, 144),
+ 'lightgrey': (211, 211, 211),
+ 'lightpink': (255, 182, 193),
+ 'lightsalmon': (255, 160, 122),
+ 'lightseagreen': ( 32, 178, 170),
+ 'lightskyblue': (135, 206, 250),
+ 'lightslategray': (119, 136, 153),
+ 'lightslategrey': (119, 136, 153),
+ 'lightsteelblue': (176, 196, 222),
+ 'lightyellow': (255, 255, 224),
+ 'lime': ( 0, 255, 0),
+ 'limegreen': ( 50, 205, 50),
+ 'linen': (250, 240, 230),
+ 'magenta': (255, 0, 255),
+ 'maroon': (128, 0, 0),
+ 'mediumaquamarine': (102, 205, 170),
+ 'mediumblue': ( 0, 0, 205),
+ 'mediumorchid': (186, 85, 211),
+ 'mediumpurple': (147, 112, 219),
+ 'mediumseagreen': ( 60, 179, 113),
+ 'mediumslateblue': (123, 104, 238),
+ 'mediumspringgreen': ( 0, 250, 154),
+ 'mediumturquoise': ( 72, 209, 204),
+ 'mediumvioletred': (199, 21, 133),
+ 'midnightblue': ( 25, 25, 112),
+ 'mintcream': (245, 255, 250),
+ 'mistyrose': (255, 228, 225),
+ 'moccasin': (255, 228, 181),
+ 'navajowhite': (255, 222, 173),
+ 'navy': ( 0, 0, 128),
+ 'oldlace': (253, 245, 230),
+ 'olive': (128, 128, 0),
+ 'olivedrab': (107, 142, 35),
+ 'orange': (255, 165, 0),
+ 'orangered': (255, 69, 0),
+ 'orchid': (218, 112, 214),
+ 'palegoldenrod': (238, 232, 170),
+ 'palegreen': (152, 251, 152),
+ 'paleturquoise': (175, 238, 238),
+ 'palevioletred': (219, 112, 147),
+ 'papayawhip': (255, 239, 213),
+ 'peachpuff': (255, 218, 185),
+ 'peru': (205, 133, 63),
+ 'pink': (255, 192, 203),
+ 'plum': (221, 160, 221),
+ 'powderblue': (176, 224, 230),
+ 'purple': (128, 0, 128),
+ 'red': (255, 0, 0),
+ 'rosybrown': (188, 143, 143),
+ 'royalblue': ( 65, 105, 225),
+ 'saddlebrown': (139, 69, 19),
+ 'salmon': (250, 128, 114),
+ 'sandybrown': (244, 164, 96),
+ 'seagreen': ( 46, 139, 87),
+ 'seashell': (255, 245, 238),
+ 'sienna': (160, 82, 45),
+ 'silver': (192, 192, 192),
+ 'skyblue': (135, 206, 235),
+ 'slateblue': (106, 90, 205),
+ 'slategray': (112, 128, 144),
+ 'slategrey': (112, 128, 144),
+ 'snow': (255, 250, 250),
+ 'springgreen': ( 0, 255, 127),
+ 'steelblue': ( 70, 130, 180),
+ 'tan': (210, 180, 140),
+ 'teal': ( 0, 128, 128),
+ 'thistle': (216, 191, 216),
+ 'tomato': (255, 99, 71),
+ 'turquoise': ( 64, 224, 208),
+ 'violet': (238, 130, 238),
+ 'wheat': (245, 222, 179),
+ 'white': (255, 255, 255),
+ 'whitesmoke': (245, 245, 245),
+ 'yellow': (255, 255, 0),
+ 'yellowgreen': (154, 205, 50)
+ }
+
+_ws_re = re.compile('\s+')
+_token_re = re.compile('[A-Za-z_][A-Za-z0-9_]*')
+_hex_re = re.compile('#([0-9a-f]{3}(?:[0-9a-f]{3})?)$')
+_number_re = re.compile('[0-9]*(\.[0-9]*)')
+
+class ColorParser (object):
+ def __init__(self, s):
+ self._string = s
+ self._pos = 0
+
+ def skipws(self):
+ m = _ws_re.match(self._string, self._pos)
+ if m:
+ self._pos = m.end(0)
+
+ def expect(self, s, context=''):
+ if len(self._string) - self._pos < len(s) \
+ or self._string[self._pos:self._pos + len(s)] != s:
+ raise ValueError('bad color "%s" - expected "%s"%s'
+ % (self._string, s, context))
+ self._pos += len(s)
+
+ def expectEnd(self):
+ if self._pos != len(self._string):
+ raise ValueError('junk at end of color "%s"' % self._string)
+
+ def getToken(self):
+ m = _token_re.match(self._string, self._pos)
+ if m:
+ token = m.group(0)
+
+ self._pos = m.end(0)
+ return token
+ return None
+
+ def parseNumber(self, context=''):
+ m = _number_re.match(self._string, self._pos)
+ if m:
+ self._pos = m.end(0)
+ return float(m.group(0))
+ raise ValueError('bad color "%s" - expected a number%s'
+ % (self._string, context))
+
+ def parseColor(self):
+ self.skipws()
+
+ token = self.getToken()
+ if token:
+ if token == 'rgb':
+ return self.parseRGB()
+ elif token == 'hsl':
+ return self.parseHSL()
+ elif token == 'hwb':
+ return self.parseHWB()
+ elif token == 'cmyk':
+ return self.parseCMYK()
+ elif token == 'gray' or token == 'grey':
+ return self.parseGray()
+
+ try:
+ r, g, b = _x11_colors[token]
+ except KeyError:
+ raise ValueError('unknown color name "%s"' % token)
+
+ self.expectEnd()
+
+ return RGB(r / 255.0, g / 255.0, b / 255.0)
+
+ m = _hex_re.match(self._string, self._pos)
+ if m:
+ hrgb = m.group(1)
+
+ if len(hrgb) == 3:
+ r = int('0x' + 2 * hrgb[0], 16)
+ g = int('0x' + 2 * hrgb[1], 16)
+ b = int('0x' + 2 * hrgb[2], 16)
+ else:
+ r = int('0x' + hrgb[0:2], 16)
+ g = int('0x' + hrgb[2:4], 16)
+ b = int('0x' + hrgb[4:6], 16)
+
+ self._pos = m.end(0)
+ self.skipws()
+
+ self.expectEnd()
+
+ return RGB(r / 255.0, g / 255.0, b / 255.0)
+
+ raise ValueError('bad color syntax "%s"' % self._string)
+
+ def parseRGB(self):
+ self.expect('(', 'after "rgb"')
+ self.skipws()
+
+ r = self.parseValue()
+
+ self.skipws()
+ self.expect(',', 'in "rgb"')
+ self.skipws()
+
+ g = self.parseValue()
+
+ self.skipws()
+ self.expect(',', 'in "rgb"')
+ self.skipws()
+
+ b = self.parseValue()
+
+ self.skipws()
+ self.expect(')', 'at end of "rgb"')
+
+ self.skipws()
+ self.expectEnd()
+
+ return RGB(r, g, b)
+
+ def parseHSL(self):
+ self.expect('(', 'after "hsl"')
+ self.skipws()
+
+ h = self.parseAngle()
+
+ self.skipws()
+ self.expect(',', 'in "hsl"')
+ self.skipws()
+
+ s = self.parseValue()
+
+ self.skipws()
+ self.expect(',', 'in "hsl"')
+ self.skipws()
+
+ l = self.parseValue()
+
+ self.skipws()
+ self.expect(')', 'at end of "hsl"')
+
+ self.skipws()
+ self.expectEnd()
+
+ return HSL(h, s, l)
+
+ def parseHWB(self):
+ self.expect('(', 'after "hwb"')
+ self.skipws()
+
+ h = self.parseAngle()
+
+ self.skipws()
+ self.expect(',', 'in "hwb"')
+ self.skipws()
+
+ w = self.parseValue()
+
+ self.skipws()
+ self.expect(',', 'in "hwb"')
+ self.skipws()
+
+ b = self.parseValue()
+
+ self.skipws()
+ self.expect(')', 'at end of "hwb"')
+
+ self.skipws()
+ self.expectEnd()
+
+ return HWB(h, w, b)
+
+ def parseCMYK(self):
+ self.expect('(', 'after "cmyk"')
+ self.skipws()
+
+ c = self.parseValue()
+
+ self.skipws()
+ self.expect(',', 'in "cmyk"')
+ self.skipws()
+
+ m = self.parseValue()
+
+ self.skipws()
+ self.expect(',', 'in "cmyk"')
+ self.skipws()
+
+ y = self.parseValue()
+
+ self.skipws()
+ self.expect(',', 'in "cmyk"')
+ self.skipws()
+
+ k = self.parseValue()
+
+ self.skipws()
+ self.expect(')', 'at end of "cmyk"')
+
+ self.skipws()
+ self.expectEnd()
+
+ return CMYK(c, m, y, k)
+
+ def parseGray(self):
+ self.expect('(', 'after "gray"')
+ self.skipws()
+
+ g = self.parseValue()
+
+ self.skipws()
+ self.expect(')', 'at end of "gray')
+
+ self.skipws()
+ self.expectEnd()
+
+ return Gray(g)
+
+ def parseValue(self):
+ n = self.parseNumber()
+ self.skipws()
+ if self._string[self._pos] == '%':
+ n = n / 100.0
+ self.pos += 1
+ return n
+
+ def parseAngle(self):
+ n = self.parseNumber()
+ self.skipws()
+ tok = self.getToken()
+ if tok == 'rad':
+ n = n * 180.0 / math.pi
+ elif tok == 'grad' or tok == 'gon':
+ n = n * 0.9
+ elif tok != 'deg':
+ raise ValueError('bad angle unit "%s"' % tok)
+ return n
+
+_color_re = re.compile('\s*(#|rgb|hsl|hwb|cmyk|gray|grey|%s)'
+ % '|'.join(_x11_colors.keys()))
+def isAColor(s):
+ return _color_re.match(s)
+
+def parseColor(s):
+ return ColorParser(s).parseColor()
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/core.py b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/core.py
new file mode 100644
index 000000000..91f5e6c24
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/core.py
@@ -0,0 +1,592 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+import os
+import pkg_resources
+import re
+import shutil
+import stat
+import subprocess
+import sys
+import tempfile
+import tokenize
+import json
+
+try:
+ {}.iteritems
+ iteritems = lambda x: x.iteritems()
+ iterkeys = lambda x: x.iterkeys()
+except AttributeError:
+ iteritems = lambda x: x.items()
+ iterkeys = lambda x: x.keys()
+try:
+ unicode
+except NameError:
+ unicode = str
+
+import biplist
+from mac_alias import *
+from ds_store import *
+
+from . import colors
+from . import licensing
+
+try:
+ from . import badge
+except ImportError:
+ badge = None
+
+_hexcolor_re = re.compile(r'#[0-9a-f]{3}(?:[0-9a-f]{3})?')
+
+class DMGError(Exception):
+ pass
+
+def hdiutil(cmd, *args, **kwargs):
+ plist = kwargs.get('plist', True)
+ all_args = ['/usr/bin/hdiutil', cmd]
+ all_args.extend(args)
+ if plist:
+ all_args.append('-plist')
+ p = subprocess.Popen(all_args, stdout=subprocess.PIPE, close_fds=True)
+ output, errors = p.communicate()
+ if plist:
+ results = biplist.readPlistFromString(output)
+ else:
+ results = output
+ retcode = p.wait()
+ return retcode, results
+
+# On Python 2 we can just execfile() it, but Python 3 deprecated that
+def load_settings(filename, settings):
+ if sys.version_info[0] == 2:
+ execfile(filename, settings, settings)
+ else:
+ encoding = 'utf-8'
+ with open(filename, 'rb') as fp:
+ try:
+ encoding = tokenize.detect_encoding(fp.readline)[0]
+ except SyntaxError:
+ pass
+
+ with open(filename, 'r', encoding=encoding) as fp:
+ exec(compile(fp.read(), filename, 'exec'), settings, settings)
+
+def load_json(filename, settings):
+ """Read an appdmg .json spec. Uses the defaults for appdmg, rather than
+ the usual defaults for dmgbuild. """
+
+ with open(filename, 'r') as fp:
+ json_data = json.load(fp)
+
+ if 'title' not in json_data:
+ raise ValueError('missing \'title\' in JSON settings file')
+ if 'contents' not in json_data:
+ raise ValueError('missing \'contents\' in JSON settings file')
+
+ settings['volume_name'] = json_data['title']
+ settings['icon'] = json_data.get('icon', None)
+ settings['badge_icon'] = json_data.get('badge-icon', None)
+ bk = json_data.get('background', None)
+ if bk is None:
+ bk = json_data.get('background-color', None)
+ if bk is not None:
+ settings['background'] = bk
+ settings['icon_size'] = json_data.get('icon-size', 80)
+ wnd = json_data.get('window', { 'position': (100, 100),
+ 'size': (640, 480) })
+ pos = wnd.get('position', { 'x': 100, 'y': 100 })
+ siz = wnd.get('size', { 'width': 640, 'height': 480 })
+ settings['window_rect'] = ((pos.get('x', 100), pos.get('y', 100)),
+ (siz.get('width', 640), siz.get('height', 480)))
+ settings['format'] = json_data.get('format', 'UDZO')
+ settings['compression_level'] = json_data.get('compression-level', None)
+ settings['license'] = json_data.get('license', None)
+ files = []
+ symlinks = {}
+ icon_locations = {}
+ for fileinfo in json_data.get('contents', []):
+ if 'path' not in fileinfo:
+ raise ValueError('missing \'path\' in contents in JSON settings file')
+ if 'x' not in fileinfo:
+ raise ValueError('missing \'x\' in contents in JSON settings file')
+ if 'y' not in fileinfo:
+ raise ValueError('missing \'y\' in contents in JSON settings file')
+
+ kind = fileinfo.get('type', 'file')
+ path = fileinfo['path']
+ name = fileinfo.get('name', os.path.basename(path.rstrip('/')))
+ if kind == 'file':
+ files.append((path, name))
+ elif kind == 'link':
+ symlinks[name] = path
+ elif kind == 'position':
+ pass
+ icon_locations[name] = (fileinfo['x'], fileinfo['y'])
+
+ settings['files'] = files
+ settings['symlinks'] = symlinks
+ settings['icon_locations'] = icon_locations
+
+def build_dmg(filename, volume_name, settings_file=None, defines={}, lookForHiDPI=True):
+ settings = {
+ # Default settings
+ 'filename': filename,
+ 'volume_name': volume_name,
+ 'format': 'UDBZ',
+ 'compression_level': None,
+ 'size': None,
+ 'files': [],
+ 'symlinks': {},
+ 'icon': None,
+ 'badge_icon': None,
+ 'background': None,
+ 'show_status_bar': False,
+ 'show_tab_view': False,
+ 'show_toolbar': False,
+ 'show_pathbar': False,
+ 'show_sidebar': False,
+ 'sidebar_width': 180,
+ 'arrange_by': None,
+ 'grid_offset': (0, 0),
+ 'grid_spacing': 100.0,
+ 'scroll_position': (0.0, 0.0),
+ 'show_icon_preview': False,
+ 'show_item_info': False,
+ 'label_pos': 'bottom',
+ 'text_size': 16.0,
+ 'icon_size': 128.0,
+ 'include_icon_view_settings': 'auto',
+ 'include_list_view_settings': 'auto',
+ 'list_icon_size': 16.0,
+ 'list_text_size': 12.0,
+ 'list_scroll_position': (0, 0),
+ 'list_sort_by': 'name',
+ 'list_use_relative_dates': True,
+ 'list_calculate_all_sizes': False,
+ 'list_columns': ('name', 'date-modified', 'size', 'kind', 'date-added'),
+ 'list_column_widths': {
+ 'name': 300,
+ 'date-modified': 181,
+ 'date-created': 181,
+ 'date-added': 181,
+ 'date-last-opened': 181,
+ 'size': 97,
+ 'kind': 115,
+ 'label': 100,
+ 'version': 75,
+ 'comments': 300,
+ },
+ 'list_column_sort_directions': {
+ 'name': 'ascending',
+ 'date-modified': 'descending',
+ 'date-created': 'descending',
+ 'date-added': 'descending',
+ 'date-last-opened': 'descending',
+ 'size': 'descending',
+ 'kind': 'ascending',
+ 'label': 'ascending',
+ 'version': 'ascending',
+ 'comments': 'ascending',
+ },
+ 'window_rect': ((100, 100), (640, 280)),
+ 'default_view': 'icon-view',
+ 'icon_locations': {},
+ 'license': None,
+ 'defines': defines
+ }
+
+ # Execute the settings file
+ if settings_file:
+ # We now support JSON settings files using appdmg's format
+ if settings_file.endswith('.json'):
+ load_json(settings_file, settings)
+ else:
+ load_settings(settings_file, settings)
+
+ # Set up the finder data
+ bounds = settings['window_rect']
+
+ bwsp = {
+ b'ShowStatusBar': settings['show_status_bar'],
+ b'WindowBounds': b'{{%s, %s}, {%s, %s}}' % (bounds[0][0],
+ bounds[0][1],
+ bounds[1][0],
+ bounds[1][1]),
+ b'ContainerShowSidebar': False,
+ b'PreviewPaneVisibility': False,
+ b'SidebarWidth': settings['sidebar_width'],
+ b'ShowTabView': settings['show_tab_view'],
+ b'ShowToolbar': settings['show_toolbar'],
+ b'ShowPathbar': settings['show_pathbar'],
+ b'ShowSidebar': settings['show_sidebar']
+ }
+
+ arrange_options = {
+ 'name': 'name',
+ 'date-modified': 'dateModified',
+ 'date-created': 'dateCreated',
+ 'date-added': 'dateAdded',
+ 'date-last-opened': 'dateLastOpened',
+ 'size': 'size',
+ 'kind': 'kind',
+ 'label': 'label',
+ }
+
+ icvp = {
+ b'viewOptionsVersion': 1,
+ b'backgroundType': 0,
+ b'backgroundColorRed': 1.0,
+ b'backgroundColorGreen': 1.0,
+ b'backgroundColorBlue': 1.0,
+ b'gridOffsetX': float(settings['grid_offset'][0]),
+ b'gridOffsetY': float(settings['grid_offset'][1]),
+ b'gridSpacing': float(settings['grid_spacing']),
+ b'arrangeBy': str(arrange_options.get(settings['arrange_by'], 'none')),
+ b'showIconPreview': settings['show_icon_preview'] == True,
+ b'showItemInfo': settings['show_item_info'] == True,
+ b'labelOnBottom': settings['label_pos'] == 'bottom',
+ b'textSize': float(settings['text_size']),
+ b'iconSize': float(settings['icon_size']),
+ b'scrollPositionX': float(settings['scroll_position'][0]),
+ b'scrollPositionY': float(settings['scroll_position'][1])
+ }
+
+ background = settings['background']
+
+ columns = {
+ 'name': 'name',
+ 'date-modified': 'dateModified',
+ 'date-created': 'dateCreated',
+ 'date-added': 'dateAdded',
+ 'date-last-opened': 'dateLastOpened',
+ 'size': 'size',
+ 'kind': 'kind',
+ 'label': 'label',
+ 'version': 'version',
+ 'comments': 'comments'
+ }
+
+ default_widths = {
+ 'name': 300,
+ 'date-modified': 181,
+ 'date-created': 181,
+ 'date-added': 181,
+ 'date-last-opened': 181,
+ 'size': 97,
+ 'kind': 115,
+ 'label': 100,
+ 'version': 75,
+ 'comments': 300,
+ }
+
+ default_sort_directions = {
+ 'name': 'ascending',
+ 'date-modified': 'descending',
+ 'date-created': 'descending',
+ 'date-added': 'descending',
+ 'date-last-opened': 'descending',
+ 'size': 'descending',
+ 'kind': 'ascending',
+ 'label': 'ascending',
+ 'version': 'ascending',
+ 'comments': 'ascending',
+ }
+
+ lsvp = {
+ b'viewOptionsVersion': 1,
+ b'sortColumn': columns.get(settings['list_sort_by'], 'name'),
+ b'textSize': float(settings['list_text_size']),
+ b'iconSize': float(settings['list_icon_size']),
+ b'showIconPreview': settings['show_icon_preview'],
+ b'scrollPositionX': settings['list_scroll_position'][0],
+ b'scrollPositionY': settings['list_scroll_position'][1],
+ b'useRelativeDates': settings['list_use_relative_dates'],
+ b'calculateAllSizes': settings['list_calculate_all_sizes'],
+ }
+
+ lsvp['columns'] = {}
+ cndx = {}
+
+ for n, column in enumerate(settings['list_columns']):
+ cndx[column] = n
+ width = settings['list_column_widths'].get(column,
+ default_widths[column])
+ asc = 'ascending' == settings['list_column_sort_directions'].get(column,
+ default_sort_directions[column])
+
+ lsvp['columns'][columns[column]] = {
+ 'index': n,
+ 'width': width,
+ 'identifier': columns[column],
+ 'visible': True,
+ 'ascending': asc
+ }
+
+ n = len(settings['list_columns'])
+ for k in iterkeys(columns):
+ if cndx.get(k, None) is None:
+ cndx[k] = n
+ width = default_widths[k]
+ asc = 'ascending' == default_sort_directions[k]
+
+ lsvp['columns'][columns[column]] = {
+ 'index': n,
+ 'width': width,
+ 'identifier': columns[column],
+ 'visible': False,
+ 'ascending': asc
+ }
+
+ n += 1
+
+ default_view = settings['default_view']
+ views = {
+ 'icon-view': b'icnv',
+ 'column-view': b'clmv',
+ 'list-view': b'Nlsv',
+ 'coverflow': b'Flwv'
+ }
+
+ icvl = (b'type', views.get(default_view, 'icnv'))
+
+ include_icon_view_settings = default_view == 'icon-view' \
+ or settings['include_icon_view_settings'] not in \
+ ('auto', 'no', 0, False, None)
+ include_list_view_settings = default_view in ('list-view', 'coverflow') \
+ or settings['include_list_view_settings'] not in \
+ ('auto', 'no', 0, False, None)
+
+ filename = settings['filename']
+ volume_name = settings['volume_name']
+
+ # Construct a writeable image to start with
+ dirname, basename = os.path.split(os.path.realpath(filename))
+ if not basename.endswith('.dmg'):
+ basename += '.dmg'
+ writableFile = tempfile.NamedTemporaryFile(dir=dirname, prefix='.temp',
+ suffix=basename)
+
+ total_size = settings['size']
+ if total_size == None:
+ # Start with a size of 128MB - this way we don't need to calculate the
+ # size of the background image, volume icon, and .DS_Store file (and
+ # 128 MB should be well sufficient for even the most outlandish image
+ # sizes, like an uncompressed 5K multi-resolution TIFF)
+ total_size = 128 * 1024 * 1024
+
+ def roundup(x, n):
+ return x if x % n == 0 else x + n - x % n
+
+ for path in settings['files']:
+ if isinstance(path, tuple):
+ path = path[0]
+
+ if not os.path.islink(path) and os.path.isdir(path):
+ for dirpath, dirnames, filenames in os.walk(path):
+ for f in filenames:
+ fp = os.path.join(dirpath, f)
+ total_size += roundup(os.lstat(fp).st_size, 4096)
+ else:
+ total_size += roundup(os.lstat(path).st_size, 4096)
+
+ for name,target in iteritems(settings['symlinks']):
+ total_size += 4096
+
+ total_size = str(max(total_size / 1024, 1024)) + 'K'
+
+ ret, output = hdiutil('create',
+ '-ov',
+ '-volname', volume_name,
+ '-fs', 'HFS+',
+ '-fsargs', '-c c=64,a=16,e=16',
+ '-size', total_size,
+ writableFile.name)
+
+ if ret:
+ raise DMGError('Unable to create disk image')
+
+ ret, output = hdiutil('attach',
+ '-nobrowse',
+ '-owners', 'off',
+ '-noidme',
+ writableFile.name)
+
+ if ret:
+ raise DMGError('Unable to attach disk image')
+
+ try:
+ for info in output['system-entities']:
+ if info.get('mount-point', None):
+ device = info['dev-entry']
+ mount_point = info['mount-point']
+
+ icon = settings['icon']
+ if badge:
+ badge_icon = settings['badge_icon']
+ else:
+ badge_icon = None
+ icon_target_path = os.path.join(mount_point, '.VolumeIcon.icns')
+ if icon:
+ shutil.copyfile(icon, icon_target_path)
+ elif badge_icon:
+ badge.badge_disk_icon(badge_icon, icon_target_path)
+
+ if icon or badge_icon:
+ subprocess.call(['/usr/bin/SetFile', '-a', 'C', mount_point])
+
+ background_bmk = None
+
+ if not isinstance(background, (str, unicode)):
+ pass
+ elif colors.isAColor(background):
+ c = colors.parseColor(background).to_rgb()
+
+ icvp['backgroundType'] = 1
+ icvp['backgroundColorRed'] = float(c.r)
+ icvp['backgroundColorGreen'] = float(c.g)
+ icvp['backgroundColorBlue'] = float(c.b)
+ else:
+ if os.path.isfile(background):
+ # look to see if there are HiDPI resources available
+
+ if lookForHiDPI is True:
+ name, extension = os.path.splitext(os.path.basename(background))
+ orderedImages = [background]
+ imageDirectory = os.path.dirname(background)
+ if imageDirectory == '':
+ imageDirectory = '.'
+ for candidateName in os.listdir(imageDirectory):
+ hasScale = re.match(
+ '^(?P<name>.+)@(?P<scale>\d+)x(?P<extension>\.\w+)$',
+ candidateName)
+ if hasScale and name == hasScale.group('name') and \
+ extension == hasScale.group('extension'):
+ scale = int(hasScale.group('scale'))
+ if len(orderedImages) < scale:
+ orderedImages += [None] * (scale - len(orderedImages))
+ orderedImages[scale - 1] = os.path.join(imageDirectory, candidateName)
+
+ if len(orderedImages) > 1:
+ # compile the grouped tiff
+ backgroundFile = tempfile.NamedTemporaryFile(suffix='.tiff')
+ background = backgroundFile.name
+ output = tempfile.TemporaryFile(mode='w+')
+ try:
+ subprocess.check_call(
+ ['/usr/bin/tiffutil', '-cathidpicheck'] +
+ filter(None, orderedImages) +
+ ['-out', background], stdout=output, stderr=output)
+ except Exception as e:
+ output.seek(0)
+ raise ValueError(
+ 'unable to compile combined HiDPI file "%s" got error: %s\noutput: %s'
+ % (background, str(e), output.read()))
+
+ _, kind = os.path.splitext(background)
+ path_in_image = os.path.join(mount_point, '.background' + kind)
+ shutil.copyfile(background, path_in_image)
+ elif pkg_resources.resource_exists('dmgbuild', 'resources/' + background + '.tiff'):
+ tiffdata = pkg_resources.resource_string(
+ 'dmgbuild',
+ 'resources/' + background + '.tiff')
+ path_in_image = os.path.join(mount_point, '.background.tiff')
+
+ with open(path_in_image, 'w') as f:
+ f.write(tiffdata)
+ else:
+ raise ValueError('background file "%s" not found' % background)
+
+ alias = Alias.for_file(path_in_image)
+ background_bmk = Bookmark.for_file(path_in_image)
+
+ icvp['backgroundType'] = 2
+ icvp['backgroundImageAlias'] = biplist.Data(alias.to_bytes())
+
+ for f in settings['files']:
+ if isinstance(f, tuple):
+ f_in_image = os.path.join(mount_point, f[1])
+ f = f[0]
+ else:
+ basename = os.path.basename(f.rstrip('/'))
+ f_in_image = os.path.join(mount_point, basename)
+
+ # use system ditto command to preserve code signing, etc.
+ subprocess.call(['/usr/bin/ditto', f, f_in_image])
+
+ for name,target in iteritems(settings['symlinks']):
+ name_in_image = os.path.join(mount_point, name)
+ os.symlink(target, name_in_image)
+
+ userfn = settings.get('create_hook', None)
+ if callable(userfn):
+ userfn(mount_point, settings)
+
+ image_dsstore = os.path.join(mount_point, '.DS_Store')
+
+ with DSStore.open(image_dsstore, 'w+') as d:
+ d['.']['vSrn'] = ('long', 1)
+ d['.']['bwsp'] = bwsp
+ if include_icon_view_settings:
+ d['.']['icvp'] = icvp
+ if background_bmk:
+ d['.']['pBBk'] = background_bmk
+ if include_list_view_settings:
+ d['.']['lsvp'] = lsvp
+ d['.']['icvl'] = icvl
+
+ for k,v in iteritems(settings['icon_locations']):
+ d[k]['Iloc'] = v
+
+ # Delete .Trashes, if it gets created
+ shutil.rmtree(os.path.join(mount_point, '.Trashes'), True)
+ except:
+ # Always try to detach
+ hdiutil('detach', '-force', device, plist=False)
+ raise
+
+ ret, output = hdiutil('detach', device, plist=False)
+
+ if ret:
+ hdiutil('detach', '-force', device, plist=False)
+ raise DMGError('Unable to detach device cleanly')
+
+ # Shrink the output to the minimum possible size
+ ret, output = hdiutil('resize',
+ '-quiet',
+ '-sectors', 'min',
+ writableFile.name,
+ plist=False)
+
+ if ret:
+ raise DMGError('Unable to shrink')
+
+ key_prefix = {'UDZO': 'zlib', 'UDBZ': 'bzip2', 'ULFO': 'lzfse'}
+ compression_level = settings['compression_level']
+ if settings['format'] in key_prefix and compression_level:
+ compression_args = [
+ '-imagekey',
+ key_prefix[settings['format']] + '-level=' + str(compression_level)
+ ]
+ else:
+ compression_args = []
+
+ ret, output = hdiutil('convert', writableFile.name,
+ '-format', settings['format'],
+ '-ov',
+ '-o', filename, *compression_args)
+
+ if ret:
+ raise DMGError('Unable to convert')
+
+ if settings['license']:
+ ret, output = hdiutil('unflatten', '-quiet', filename, plist=False)
+
+ if ret:
+ raise DMGError('Unable to unflatten to add license')
+
+ licensing.add_license(filename, settings['license'])
+
+ ret, output = hdiutil('flatten', '-quiet', filename, plist=False)
+
+ if ret:
+ raise DMGError('Unable to flatten after adding license')
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/licensing.py b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/licensing.py
new file mode 100644
index 000000000..5c2679096
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/licensing.py
@@ -0,0 +1,461 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+import os
+import struct
+
+from .resources import *
+
+# ISO language and country codes to Macintosh Region codes (from Script.h)
+# <key> == CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes(NULL,
+# kTextLanguageDontCare,
+# <value>)
+region_codes = {
+ "en_US": 0,
+ "fr_FR": 1,
+ "en_GB": 2,
+ "de_DE": 3,
+ "it_IT": 4,
+ "nl_NL": 5,
+ "nl_BE": 6,
+ "sv_SE": 7,
+ "es_ES": 8,
+ "da_DK": 9,
+ "pt_PT": 10,
+ "fr_CA": 11,
+ "nb_NO": 12,
+ "he_IL": 13,
+ "ja_JP": 14,
+ "en_AU": 15,
+ "ar": 16,
+ "fi_FI": 17,
+ "fr_CH": 18,
+ "de_CH": 19,
+ "el_GR": 20,
+ "is_IS": 21,
+ "mt_MT": 22,
+ "el_CY": 23,
+ "tr_TR": 24,
+ "hi_IN": 33,
+ "ur_PK": 34,
+ "it_CH": 36,
+ "ro_RO": 39,
+ "grc": 40,
+ "lt_LT": 41,
+ "pl_PL": 42,
+ "hu_HU": 43,
+ "et_EE": 44,
+ "lv_LV": 45,
+ "se": 46,
+ "fo_FO": 47,
+ "fa_IR": 48,
+ "ru_RU": 49,
+ "ga_IE": 50,
+ "ko_KR": 51,
+ "zh_CN": 52,
+ "zh_TW": 53,
+ "th_TH": 54,
+ "cs_CZ": 56,
+ "sk_SK": 57,
+ "bn": 60,
+ "be_BY": 61,
+ "uk_UA": 62,
+ "sr_RS": 65,
+ "sl_SI": 66,
+ "mk_MK": 67,
+ "hr_HR": 68,
+ "pt_BR": 71,
+ "bg_BG": 72,
+ "ca_ES": 73,
+ "gd": 75,
+ "gv": 76,
+ "br": 77,
+ "iu_CA": 78,
+ "cy": 79,
+ "ga-Latg_IE": 81,
+ "en_CA": 82,
+ "dz_BT": 83,
+ "hy_AM": 84,
+ "ka_GE": 85,
+ "es_419": 86,
+ "to_TO": 88,
+ "fr_001": 91,
+ "de_AT": 92,
+ "gu_IN": 94,
+ "pa": 95,
+ "ur_IN": 96,
+ "vi_VN": 97,
+ "fr_BE": 98,
+ "uz_UZ": 99,
+ "en_SG": 100,
+ "nn_NO": 101,
+ "af_ZA": 102,
+ "eo": 103,
+ "mr_IN": 104,
+ "bo": 105,
+ "ne_NP": 106,
+ "kl": 107,
+ "en_IE": 108
+}
+
+# Map of region constants to script constants (from Script.h)
+# TextEncoding textEncoding;
+# GetTextEncodingFromScriptInfo(kTextScriptDontCare, kTextLanguageDontCare, <key>, &textEncoding);
+# <value> == GetTextEncodingBase(textEncoding);
+script_codes = {
+ 0: 0,
+ 1: 0,
+ 2: 0,
+ 3: 0,
+ 4: 0,
+ 5: 0,
+ 6: 0,
+ 7: 0,
+ 8: 0,
+ 9: 0,
+ 10: 0,
+ 11: 0,
+ 12: 0,
+ 13: 5,
+ 14: 1,
+ 15: 0,
+ 16: 4,
+ 17: 0,
+ 18: 0,
+ 19: 0,
+ 20: 6,
+ 21: 37,
+ 22: 0,
+ 23: 6,
+ 24: 35,
+ 25: 36,
+ 26: 0,
+ 27: 0,
+ 30: 0,
+ 31: 0,
+ 32: 0,
+ 33: 9,
+ 34: 4,
+ 35: 35,
+ 36: 0,
+ 37: 0,
+ 39: 38,
+ 40: 6,
+ 41: 29,
+ 42: 29,
+ 43: 29,
+ 44: 29,
+ 45: 29,
+ 46: 0,
+ 47: 37,
+ 48: 140,
+ 49: 7,
+ 50: 39,
+ 51: 3,
+ 52: 25,
+ 53: 2,
+ 54: 21,
+ 56: 29,
+ 57: 29,
+ 59: 29,
+ 60: 13,
+ 61: 7,
+ 62: 7,
+ 64: 6,
+ 65: 7,
+ 66: 36,
+ 67: 7,
+ 68: 36,
+ 70: 0,
+ 71: 0,
+ 72: 7,
+ 73: 0,
+ 75: 39,
+ 76: 39,
+ 77: 39,
+ 78: 236,
+ 79: 39,
+ 81: 40,
+ 82: 0,
+ 83: 26,
+ 84: 24,
+ 85: 23,
+ 86: 0,
+ 88: 0,
+ 91: 0,
+ 92: 0,
+ 94: 11,
+ 95: 10,
+ 96: 4,
+ 97: 30,
+ 98: 0,
+ 99: 7,
+ 100: 0,
+ 101: 0,
+ 102: 0,
+ 103: 0,
+ 104: 9,
+ 105: 26,
+ 106: 9,
+ 107: 0,
+ 108: 0
+}
+
+# Map of TextEncodingBase constants to Python encoder names (from TextCommon.h)
+encodings_map = {
+ 0: 'mac_roman', # kTextEncodingMacRoman
+ 1: 'shift_jis', # kTextEncodingMacJapanese
+ 2: 'big5', # kTextEncodingMacChineseTrad
+ 3: 'euc_kr', # kTextEncodingMacKorean
+ 4: 'mac_arabic', # kTextEncodingMacArabic
+ 6: 'mac_greek', # kTextEncodingMacGreek
+ 7: 'mac_cyrillic', # kTextEncodingMacCyrillic
+ 21: 'iso8859_11', # kTextEncodingMacThai
+ 25: 'euc-cn', # kTextEncodingMacChineseSimp
+ 29: 'mac_centeuro', # kTextEncodingMacCentralEurRoman
+ 35: 'mac_turkish', # kTextEncodingMacTurkish
+ 36: 'mac_croatian', # kTextEncodingMacCroatian
+ 37: 'mac_iceland', # kTextEncodingMacIcelandic
+ 38: 'mac_romanian', # kTextEncodingMacRomanian
+ 140: 'mac_farsi' # kTextEncodingMacFarsi
+}
+
+# Standard fonts
+fonts = {
+ 'New York': 2,
+ 'Geneva': 3,
+ 'Monaco': 4,
+ 'Venice': 5,
+ 'London': 6,
+ 'Athens': 7,
+ 'San Francisco': 8,
+ 'Toronto': 9,
+ 'Cairo': 11,
+ 'Los Angeles': 12,
+ 'Times': 20,
+ 'Helvetica': 21,
+ 'Courier': 22,
+ 'Symbol': 23,
+ 'Mobile': 24
+}
+
+# Buttons (these come from the SLAResources file which you can find in the SLA
+# SDK on developer.apple.com)
+default_buttons = {
+ 0: (
+ b'English',
+ b'Agree',
+ b'Disagree',
+ b'Print',
+ b'Save',
+ b'If you agree with the terms of this license, press "Agree" to '
+ b'install the software. If you do not agree, press "Disagree".'
+ ),
+
+ 3: (
+ b'Deutsch',
+ b'Akzeptieren',
+ b'Ablehnen',
+ b'Drucken',
+ b'Sichern...',
+ b'Klicken Sie in \xd2Akzeptieren\xd3, wenn Sie mit den Bestimmungen des Software-Lizenzvertrags einverstanden sind. Falls nicht, bitte \xd2Ablehnen\xd3 anklicken. Sie k\x9annen die Software nur installieren, wenn Sie \xd2Akzeptieren\xd3 angeklickt haben.'
+ ),
+
+ 8: (
+ b'Espa\x96ol',
+ b'Aceptar',
+ b'No aceptar',
+ b'Imprimir',
+ b'Guardar...',
+ b'Si est\x87 de acuerdo con los t\x8erminos de esta licencia, pulse "Aceptar" para instalar el software. En el supuesto de que no est\x8e de acuerdo con los t\x8erminos de esta licencia, pulse "No aceptar."'
+ ),
+
+ 1: (
+ b'Fran\x8dais',
+ b'Accepter',
+ b'Refuser',
+ b'Imprimer',
+ b'Enregistrer...',
+ b'Si vous acceptez les termes de la pr\x8esente licence, cliquez sur "Accepter" afin d\'installer le logiciel. Si vous n\'\x90tes pas d\'accord avec les termes de la licence, cliquez sur "Refuser".'
+ ),
+
+ 4: (
+ b'Italiano',
+ b'Accetto',
+ b'Rifiuto',
+ b'Stampa',
+ b'Registra...',
+ b'Se accetti le condizioni di questa licenza, fai clic su "Accetto" per installare il software. Altrimenti fai clic su "Rifiuto".'
+ ),
+
+ 14: (
+ b'Japanese',
+ b'\x93\xaf\x88\xd3\x82\xb5\x82\xdc\x82\xb7',
+ b'\x93\xaf\x88\xd3\x82\xb5\x82\xdc\x82\xb9\x82\xf1',
+ b'\x88\xf3\x8d\xfc\x82\xb7\x82\xe9',
+ b'\x95\xdb\x91\xb6...',
+ b'\x96{\x83\\\x83t\x83g\x83E\x83G\x83A\x8eg\x97p\x8b\x96\x91\xf8\x8c_\x96\xf1\x82\xcc\x8f\xf0\x8c\x8f\x82\xc9\x93\xaf\x88\xd3\x82\xb3\x82\xea\x82\xe9\x8f\xea\x8d\x87\x82\xc9\x82\xcd\x81A\x83\\\x83t\x83g\x83E\x83G\x83A\x82\xf0\x83C\x83\x93\x83X\x83g\x81[\x83\x8b\x82\xb7\x82\xe9\x82\xbd\x82\xdf\x82\xc9\x81u\x93\xaf\x88\xd3\x82\xb5\x82\xdc\x82\xb7\x81v\x82\xf0\x89\x9f\x82\xb5\x82\xc4\x82\xad\x82\xbe\x82\xb3\x82\xa2\x81B\x81@\x93\xaf\x88\xd3\x82\xb3\x82\xea\x82\xc8\x82\xa2\x8f\xea\x8d\x87\x82\xc9\x82\xcd\x81A\x81u\x93\xaf\x88\xd3\x82\xb5\x82\xdc\x82\xb9\x82\xf1\x81v\x82\xf0\x89\x9f\x82\xb5\x82\xc4\x82\xad\x82\xbe\x82\xb3\x82\xa2\x81B'
+ ),
+
+ 5: (
+ b'Nederlands',
+ b'Ja',
+ b'Nee',
+ b'Print',
+ b'Bewaar...',
+ b'Indien u akkoord gaat met de voorwaarden van deze licentie, kunt u op \'Ja\' klikken om de programmatuur te installeren. Indien u niet akkoord gaat, klikt u op \'Nee\'.'
+ ),
+
+ 7: (
+ b'Svensk',
+ b'Godk\x8anns',
+ b'Avb\x9ajs',
+ b'Skriv ut',
+ b'Spara...',
+ b'Om Du godk\x8anner licensvillkoren klicka p\x8c "Godk\x8anns" f\x9ar att installera programprodukten. Om Du inte godk\x8anner licensvillkoren, klicka p\x8c "Avb\x9ajs".'
+ ),
+
+ 71: (
+ b'Portugu\x90s',
+ b'Concordar',
+ b'Discordar',
+ b'Imprimir',
+ b'Salvar...',
+ b'Se est\x87 de acordo com os termos desta licen\x8da, pressione "Concordar" para instalar o software. Se n\x8bo est\x87 de acordo, pressione "Discordar".'
+ ),
+
+ 52: (
+ b'Simplified Chinese',
+ b'\xcd\xac\xd2\xe2',
+ b'\xb2\xbb\xcd\xac\xd2\xe2',
+ b'\xb4\xf2\xd3\xa1',
+ b'\xb4\xe6\xb4\xa2\xa1\xad',
+ b'\xc8\xe7\xb9\xfb\xc4\xfa\xcd\xac\xd2\xe2\xb1\xbe\xd0\xed\xbf\xc9\xd0\xad\xd2\xe9\xb5\xc4\xcc\xf5\xbf\xee\xa3\xac\xc7\xeb\xb0\xb4\xa1\xb0\xcd\xac\xd2\xe2\xa1\xb1\xc0\xb4\xb0\xb2\xd7\xb0\xb4\xcb\xc8\xed\xbc\xfe\xa1\xa3\xc8\xe7\xb9\xfb\xc4\xfa\xb2\xbb\xcd\xac\xd2\xe2\xa3\xac\xc7\xeb\xb0\xb4\xa1\xb0\xb2\xbb\xcd\xac\xd2\xe2\xa1\xb1\xa1\xa3'
+ ),
+
+ 53: (
+ b'Traditional Chinese',
+ b'\xa6P\xb7N',
+ b'\xa4\xa3\xa6P\xb7N',
+ b'\xa6C\xa6L',
+ b'\xc0x\xa6s\xa1K',
+ b'\xa6p\xaaG\xb1z\xa6P\xb7N\xa5\xbb\xb3\\\xa5i\xc3\xd2\xb8\xcc\xaa\xba\xb1\xf8\xb4\xda\xa1A\xbd\xd0\xab\xf6\xa1\xa7\xa6P\xb7N\xa1\xa8\xa5H\xa6w\xb8\xcb\xb3n\xc5\xe9\xa1C\xa6p\xaaG\xa4\xa3\xa6P\xb7N\xa1A\xbd\xd0\xab\xf6\xa1\xa7\xa4\xa3\xa6P\xb7N\xa1\xa8\xa1C'
+ ),
+
+ 9: (
+ b'Dansk',
+ b'Enig',
+ b'Uenig',
+ b'Udskriv',
+ b'Arkiver...',
+ b'Hvis du accepterer betingelserne i licensaftalen, skal du klikke p\x8c \xd2Enig\xd3 for at installere softwaren. Klik p\x8c \xd2Uenig\xd3 for at annullere installeringen.'
+ ),
+
+ 17: (
+ b'Suomi',
+ b'Hyv\x8aksyn',
+ b'En hyv\x8aksy',
+ b'Tulosta',
+ b'Tallenna\xc9',
+ b'Hyv\x8aksy lisenssisopimuksen ehdot osoittamalla \xd5Hyv\x8aksy\xd5. Jos et hyv\x8aksy sopimuksen ehtoja, osoita \xd5En hyv\x8aksy\xd5.'
+ ),
+
+ 51: (
+ b'Korean',
+ b'\xb5\xbf\xc0\xc7',
+ b'\xb5\xbf\xc0\xc7 \xbe\xc8\xc7\xd4',
+ b'\xc7\xc1\xb8\xb0\xc6\xae',
+ b'\xc0\xfa\xc0\xe5...',
+ b'\xbb\xe7\xbf\xeb \xb0\xe8\xbe\xe0\xbc\xad\xc0\xc7 \xb3\xbb\xbf\xeb\xbf\xa1 \xb5\xbf\xc0\xc7\xc7\xcf\xb8\xe9, "\xb5\xbf\xc0\xc7" \xb4\xdc\xc3\xdf\xb8\xa6 \xb4\xad\xb7\xaf \xbc\xd2\xc7\xc1\xc6\xae\xbf\xfe\xbe\xee\xb8\xa6 \xbc\xb3\xc4\xa1\xc7\xcf\xbd\xca\xbd\xc3\xbf\xc0. \xb5\xbf\xc0\xc7\xc7\xcf\xc1\xf6 \xbe\xca\xb4\xc2\xb4\xd9\xb8\xe9, "\xb5\xbf\xc0\xc7 \xbe\xc8\xc7\xd4" \xb4\xdc\xc3\xdf\xb8\xa6 \xb4\xa9\xb8\xa3\xbd\xca\xbd\xc3\xbf\xc0.'
+ ),
+
+ 12: (
+ b'Norsk',
+ b'Enig',
+ b'Ikke enig',
+ b'Skriv ut',
+ b'Arkiver...',
+ b'Hvis De er enig i bestemmelsene i denne lisensavtalen, klikker De p\x8c "Enig"-knappen for \x8c installere programvaren. Hvis De ikke er enig, klikker De p\x8c "Ikke enig".'
+ ),
+}
+
+class LPicResource (Resource):
+ def __init__(self, res_id, res_name, default_lang, lpic, res_attrs=0):
+ data = []
+ data.append(struct.pack(b'>HH', default_lang, len(lpic)))
+ for lang,rid,two_byte in lpic:
+ data.append(struct.pack(b'>HHH', lang, rid, int(two_byte)))
+ super(LPicResource, self).__init__(b'LPic', res_id, res_name,
+ b''.join(data), res_attrs)
+
+def get_encoder_name(locale):
+ if locale not in region_codes:
+ raise Exception("Cannot determine region code for locale '%s'" % locale)
+ region_code = region_codes[locale]
+
+ if region_code not in script_codes:
+ raise Exception("Cannot determine script code for locale '%s'" % locale)
+ script_code = script_codes[region_code]
+
+ if script_code not in encodings_map:
+ raise Exception("Cannot determine Python encoder name for locale '%s' - "
+ "encode the string data manually as a byte array instead" % locale)
+ return encodings_map[script_code]
+
+def maybe_encode(s, encoding):
+ if isinstance(s, bytes):
+ return s
+ return s.encode(encoding)
+
+def add_license(filename, license_info):
+ """Add a license agreement to the specified disk image file, which should
+ have been unflattened first."""
+
+ fork = ResourceFork.from_file(filename)
+
+ default_lang = license_info.get('default-language', 'en_US')
+ default_lang_id = region_codes.get(default_lang, 0)
+
+ lpic = []
+ ndx = 1
+ for language,license_data in license_info['licenses'].items():
+ if language not in region_codes:
+ raise Exception("Unknown language '" + language + "'. Valid languages are: " +
+ ", ".join(sorted(region_codes.keys())))
+ encoding_name = get_encoder_name(language)
+ lang_id = region_codes[language]
+
+ is_two_byte = lang_id in (14, 51, 52, 53) # Japanese, Korean, SimpChinese, TradChinese
+
+ if os.path.isfile(license_data):
+ with open(license_data) as f:
+ license_data = f.read()
+
+ if license_data.startswith('{\\rtf1'):
+ fork.add(Resource(b'RTF ', 5000 + ndx, language + ' SLA',
+ str(license_data)))
+ else:
+ fork.add(TextResource(5000 + ndx, language + ' SLA',
+ maybe_encode(license_data, encoding_name)))
+ fork.add(StyleResource(5000 + ndx, language + ' SLA',
+ [Style(0, 12, 9, Style.Helvetica,
+ 0, 0, (0, 0, 0))]))
+
+ buttons = license_info.get('buttons', {}).get(language, None)
+ if buttons is None:
+ buttons = default_buttons.get(lang_id, None)
+ if buttons is None:
+ buttons = default_buttons[0]
+
+ buttons = [maybe_encode(b, encoding_name) for b in buttons]
+
+ fork.add(StringListResource(5000 + ndx, language + ' Buttons',
+ buttons))
+
+ lpic.append((lang_id, ndx, is_two_byte))
+
+ ndx += 1
+
+ fork.add(LPicResource(5000, None, default_lang_id, lpic))
+
+ fork.write_to_file(filename)
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/qt_attribution.json b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/qt_attribution.json
new file mode 100644
index 000000000..9f318e6d2
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/qt_attribution.json
@@ -0,0 +1,13 @@
+{
+ "Id": "dmgbuild",
+ "Name": "dmgbuild",
+ "QDocModule": "qbs",
+ "QtUsage": "Used in the qbs dmg module for building Apple disk images.",
+ "Description": "macOS command line utility to build disk images",
+ "Homepage": "https://bitbucket.org/al45tair/dmgbuild",
+ "Version": "1.3.0~16",
+ "License": "MIT License",
+ "LicenseId": "MIT",
+ "LicenseFile": "LICENSE",
+ "Copyright": "Copyright (c) 2014 Alastair Houghton"
+}
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/resources.py b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/resources.py
new file mode 100644
index 000000000..d2f58e64a
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/dmgbuild/resources.py
@@ -0,0 +1,355 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+import struct
+
+class Resource (object):
+ def __init__(self, res_type, res_id, res_name, data=None, res_attrs=0):
+ self.res_type = str(res_type)
+ self.res_id = res_id
+ if isinstance(res_name, basestring):
+ res_name = str(res_name)
+ self.res_name = res_name
+ self.res_attrs = res_attrs
+ if data is None:
+ self.data = None
+ self.data = str(data)
+
+ self.data_offset = None
+ self.name_offset = None
+
+ def __repr__(self):
+ return 'Resource(%r, %r, %r, data=%r, res_attrs=%r)' % (self.res_type,
+ self.res_id,
+ self.res_name,
+ self.data,
+ self.res_attrs)
+
+class TMPLResource (Resource):
+ def __init__(self, res_id, res_name, tmpl, res_attrs=0):
+ data = []
+ for name,typecode in tmpl:
+ data.append(struct.pack(b'B', len(name)))
+ data.append(str(name))
+ data.append(str(typecode))
+ super(TMPLResource, self).__init__(b'TMPL', res_id, res_name,
+ b''.join(data), res_attrs)
+
+class StringListResource (Resource):
+ def __init__(self, res_id, res_name, strings, res_attrs=0):
+ data = []
+ data.append(struct.pack(b'>H', len(strings)))
+ for s in strings:
+ data.append(struct.pack(b'B', len(s)))
+ data.append(str(s))
+ super(StringListResource, self).__init__(b'STR#', res_id, res_name,
+ b''.join(data), res_attrs)
+
+class TextResource (Resource):
+ def __init__(self, res_id, res_name, string, res_attrs=0):
+ super(TextResource, self).__init__(b'TEXT', res_id, res_name,
+ str(string), res_attrs)
+
+class Style (object):
+ # Fonts
+ NewYork = 2
+ Geneva = 3
+ Monaco = 4
+ Venice = 5
+ London = 6
+ Athens = 7
+ SanFrancisco = 8
+ Toronto = 9
+ Cairo = 11
+ LosAngeles = 12
+ Times = 20
+ Helvetica = 21
+ Courier = 22
+ Symbol = 23
+ Mobile = 24
+
+ # Styles
+ Bold = 0x0100
+ Italic = 0x0200
+ Underline = 0x0400
+ Outline = 0x0800
+ Shadow = 0x1000
+ Condense = 0x2000
+ Expand = 0x4000
+
+ def __init__(self, start_character, height, ascent, font_id, face,
+ size, color):
+ self.start_character = start_character
+ self.height = height
+ self.ascent = ascent
+ self.font_id = font_id
+ self.face = face
+ self.size = size
+ self.color = color
+
+ def __repr__(self):
+ styles = []
+ if self.face & Style.Bold:
+ styles.append('Style.Bold')
+ if self.face & Style.Italic:
+ styles.append('Style.Italic')
+ if self.face & Style.Underline:
+ styles.append('Style.Underline')
+ if self.face & Style.Outline:
+ styles.append('Style.Outline')
+ if self.face & Style.Shadow:
+ styles.append('Style.Shadow')
+ if self.face & Style.Condense:
+ styles.append('Style.Condense')
+ if self.face & Style.Expand:
+ styles.append('Style.Expand')
+ if self.face & ~0x4f00:
+ styles.append('%#06x' % (self.face & ~0x4f00))
+ if styles:
+ styles = '|'.join(styles)
+ else:
+ styles = '0'
+
+ font_revmap = {
+ 2: 'Style.NewYork',
+ 3: 'Style.Geneva',
+ 4: 'Style.Monaco',
+ 5: 'Style.Venice',
+ 6: 'Style.London',
+ 7: 'Style.Athens',
+ 8: 'Style.SanFrancisco',
+ 9: 'Style.Toronto',
+ 11: 'Style.Cairo',
+ 12: 'Style.LosAngeles',
+ 20: 'Style.Times',
+ 21: 'Style.Helvetica',
+ 22: 'Style.Courier',
+ 23: 'Style.Symbol',
+ 24: 'Style.Mobile'
+ }
+
+ font = font_revmap.get(self.font_id, '%s' % self.font_id)
+
+ return 'Style(%r, %r, %r, %s, %s, %r, %r)' % (
+ self.start_character,
+ self.height,
+ self.ascent,
+ font,
+ styles,
+ self.size,
+ self.color)
+
+class StyleResource (Resource):
+ def __init__(self, res_id, res_name, styles, res_attrs=0):
+ data = []
+ data.append(struct.pack(b'>H', len(styles)))
+ for style in styles:
+ data.append(struct.pack(b'>LHHHHHHHH',
+ style.start_character,
+ style.height,
+ style.ascent,
+ style.font_id,
+ style.face,
+ style.size,
+ style.color[0],
+ style.color[1],
+ style.color[2]))
+ super(StyleResource, self).__init__(b'styl', res_id, res_name,
+ b''.join(data), res_attrs)
+
+class ResourceFork (object):
+ def __init__(self, resources=None):
+ self.types = {}
+ self.attrs = 0
+ if resources is not None:
+ for res in resources:
+ self.add(res)
+
+ @classmethod
+ def from_data(clss, data):
+ if len(data) < 16:
+ raise ValueError('Bad resource data - data too short')
+
+ # Read the header
+ data_start, map_start, data_len, map_len = struct.unpack(b'>LLLL',
+ data[0:16])
+
+ if data_start + data_len > len(data):
+ raise ValueError('Bad resource data - data out of range')
+ if map_start + map_len > len(data):
+ raise ValueError('Bad resource data - map out of range')
+ if map_len < 30:
+ raise ValueError('Bad resource data - map too short')
+
+ # Read the map header
+ fork_attrs, type_offset, name_offset, max_type_ndx \
+ = struct.unpack(b'>HHHH', data[map_start + 22:map_start + 30])
+ num_types = max_type_ndx + 1
+
+ if type_offset + 8 * num_types > map_len:
+ raise ValueError('Bad resource data - type data outside map')
+
+ if name_offset > map_len:
+ raise ValueError('Bad resource data - names outside map')
+
+ type_offset += map_start
+ name_offset += map_start
+
+ result = ResourceFork()
+
+ # Now read the type list
+ for ntype in range(0, num_types):
+ type_pos = 2 + type_offset + 8 * ntype
+ res_type, max_item_ndx, ref_offset \
+ = struct.unpack(b'>4sHH', data[type_pos:type_pos+8])
+ num_items = max_item_ndx + 1
+
+ result.types[res_type] = []
+
+ ref_list_offset = type_offset + ref_offset
+ if ref_list_offset + 12 * num_items > map_start + map_len:
+ raise ValueError('Bad resource data - ref list outside map')
+
+ for nitem in range(0, num_items):
+ ref_elt = ref_list_offset + 12 * nitem
+ res_id, res_name_offset, data_offset \
+ = struct.unpack(b'>hHL', data[ref_elt:ref_elt+8])
+
+ res_attrs = data_offset >> 24
+ data_offset &= 0xffffff
+
+ if data_offset >= data_len:
+ raise ValueError('Bad resource data - item data out of range')
+
+ data_offset += data_start
+ res_len = struct.unpack(b'>L', data[data_offset:data_offset+4])[0]
+ if data_offset + res_len >= data_start + data_len:
+ raise ValueError('Bad resource data - item data too large')
+
+ res_data = data[data_offset + 4:data_offset + res_len + 4]
+
+ if res_name_offset == 0xffff:
+ res_name = None
+ else:
+ res_name_offset += name_offset
+ if res_name_offset >= map_start + map_len:
+ raise ValueError('Bad resource data - name out of range')
+ res_name_len = struct.unpack(b'B', data[res_name_offset])[0]
+ res_name = data[res_name_offset + 1:res_name_offset + res_name_len + 1]
+
+ result.types[res_type].append(Resource(res_type, res_id,
+ res_name,
+ res_data, res_attrs))
+
+ return result
+
+ @classmethod
+ def from_file(clss, filename):
+ with open(filename + '/..namedfork/rsrc', 'rb') as f:
+ data = f.read()
+ return clss.from_data(data)
+
+ def to_data(self):
+ data = []
+ data_len = 0
+ names = []
+ names_len = 0
+ types_len = len(self.types) * 8
+ types_data = []
+ reflist_data = []
+ reflist_len = 0
+
+ for res_type, items in self.types.items():
+ types_data.append(struct.pack(b'>4sHH',
+ res_type,
+ len(items) - 1,
+ 2 + types_len + reflist_len))
+ for item in items:
+ data_offset = data_len
+
+ if item.res_name is None:
+ name_offset = 65535
+ else:
+ name_offset = names_len
+ n = str(item.res_name)
+ names.append(struct.pack(b'B', len(n)) + n)
+ names_len += 1 + len(n)
+
+ if item.data is None:
+ data_len += 4
+ else:
+ data_len += 4 + (len(item.data) + 3) & ~3
+
+ reflist_len += 12
+ reflist_data.append(struct.pack(b'>hHLL',
+ item.res_id,
+ name_offset,
+ (item.res_attrs << 24) \
+ | data_offset,
+ 0))
+
+ # Header
+ data.append(struct.pack(b'>LLLL240s', 256, 256 + data_len, data_len,
+ 30 + types_len + reflist_len + names_len,
+ b''))
+
+ # Resource data
+ for res_type, items in self.types.items():
+ for item in items:
+ if item.data is None:
+ dlen = 0
+ else:
+ dlen = len(item.data)
+ plen = (dlen + 3) & ~3
+ data.append(struct.pack(b'>L', dlen))
+ if item.data is not None:
+ data.append(item.data)
+ if plen != dlen:
+ data.append(b'\0' * (plen - dlen))
+
+ # Resource map header
+ data.append(struct.pack(b'>16sLHHHHH',
+ b'', 0, 0,
+ self.attrs, 28, 30 + types_len + reflist_len,
+ len(self.types) - 1))
+
+ # Type list
+ data.append(b''.join(types_data))
+
+ # Reference lists
+ data.append(b''.join(reflist_data))
+
+ # Name list
+ data.append(b''.join(names))
+
+ return b''.join(data)
+
+ def write_to_file(self, filename):
+ with open(filename + '/..namedfork/rsrc', 'wb') as f:
+ f.write(self.to_data())
+
+ def __len__(self):
+ return len(self.types)
+
+ def __getitem__(self, key):
+ return self.types[key]
+
+ def __iter__(self):
+ for res_type, items in self.types.items():
+ for item in items:
+ yield item
+
+ def __repr__(self):
+ output = []
+ for item in self:
+ output.append(repr(item))
+ return 'ResourceFork([%s])' % ', '.join(output)
+
+ def add(self, res):
+ if res.res_type in self.types:
+ self.types[res.res_type].append(res)
+ else:
+ self.types[res.res_type] = [res]
+
+ def remove(self, res):
+ self.types[res.res_type].remove(res)
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/ds_store/LICENSE b/src/3rdparty/python/lib/python2.7/site-packages/ds_store/LICENSE
new file mode 100644
index 000000000..e91f4eb38
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/ds_store/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2014 Alastair Houghton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/ds_store/__init__.py b/src/3rdparty/python/lib/python2.7/site-packages/ds_store/__init__.py
new file mode 100644
index 000000000..a6b812104
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/ds_store/__init__.py
@@ -0,0 +1,3 @@
+from .store import DSStore, DSStoreEntry
+
+__all__ = ['DSStore', 'DSStoreEntry']
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/ds_store/buddy.py b/src/3rdparty/python/lib/python2.7/site-packages/ds_store/buddy.py
new file mode 100644
index 000000000..a94ab6e22
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/ds_store/buddy.py
@@ -0,0 +1,473 @@
+# -*- coding: utf-8 -*-
+import os
+import bisect
+import struct
+import binascii
+
+try:
+ {}.iterkeys
+ iterkeys = lambda x: x.iterkeys()
+except AttributeError:
+ iterkeys = lambda x: x.keys()
+try:
+ unicode
+except NameError:
+ unicode = str
+
+class BuddyError(Exception):
+ pass
+
+class Block(object):
+ def __init__(self, allocator, offset, size):
+ self._allocator = allocator
+ self._offset = offset
+ self._size = size
+ self._value = bytearray(allocator.read(offset, size))
+ self._pos = 0
+ self._dirty = False
+
+ def __len__(self):
+ return self._size
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ self.close()
+
+ def close(self):
+ if self._dirty:
+ self.flush()
+
+ def flush(self):
+ if self._dirty:
+ self._dirty = False
+ self._allocator.write(self._offset, self._value)
+
+ def invalidate(self):
+ self._dirty = False
+
+ def zero_fill(self):
+ len = self._size - self._pos
+ zeroes = b'\0' * len
+ self._value[self._pos:self._size] = zeroes
+ self._dirty = True
+
+ def tell(self):
+ return self._pos
+
+ def seek(self, pos, whence=os.SEEK_SET):
+ if whence == os.SEEK_CUR:
+ pos += self._pos
+ elif whence == os.SEEK_END:
+ pos = self._size - pos
+
+ if pos < 0 or pos > self._size:
+ raise ValueError('Seek out of range in Block instance')
+
+ self._pos = pos
+
+ def read(self, size_or_format):
+ if isinstance(size_or_format, (str, unicode, bytes)):
+ size = struct.calcsize(size_or_format)
+ fmt = size_or_format
+ else:
+ size = size_or_format
+ fmt = None
+
+ if self._size - self._pos < size:
+ raise BuddyError('Unable to read %lu bytes in block' % size)
+
+ data = self._value[self._pos:self._pos + size]
+ self._pos += size
+
+ if fmt is not None:
+ if isinstance(data, bytearray):
+ return struct.unpack_from(fmt, bytes(data))
+ else:
+ return struct.unpack(fmt, data)
+ else:
+ return data
+
+ def write(self, data_or_format, *args):
+ if len(args):
+ data = struct.pack(data_or_format, *args)
+ else:
+ data = data_or_format
+
+ if self._pos + len(data) > self._size:
+ raise ValueError('Attempt to write past end of Block')
+
+ self._value[self._pos:self._pos + len(data)] = data
+ self._pos += len(data)
+
+ self._dirty = True
+
+ def insert(self, data_or_format, *args):
+ if len(args):
+ data = struct.pack(data_or_format, *args)
+ else:
+ data = data_or_format
+
+ del self._value[-len(data):]
+ self._value[self._pos:self._pos] = data
+ self._pos += len(data)
+
+ self._dirty = True
+
+ def delete(self, size):
+ if self._pos + size > self._size:
+ raise ValueError('Attempt to delete past end of Block')
+ del self._value[self._pos:self._pos + size]
+ self._value += b'\0' * size
+ self._dirty = True
+
+ def __str__(self):
+ return binascii.b2a_hex(self._value)
+
+class Allocator(object):
+ def __init__(self, the_file):
+ self._file = the_file
+ self._dirty = False
+
+ self._file.seek(0)
+
+ # Read the header
+ magic1, magic2, offset, size, offset2, self._unknown1 \
+ = self.read(-4, '>I4sIII16s')
+
+ if magic2 != b'Bud1' or magic1 != 1:
+ raise BuddyError('Not a buddy file')
+
+ if offset != offset2:
+ raise BuddyError('Root addresses differ')
+
+ self._root = Block(self, offset, size)
+
+ # Read the block offsets
+ count, self._unknown2 = self._root.read('>II')
+ self._offsets = []
+ c = (count + 255) & ~255
+ while c:
+ self._offsets += self._root.read('>256I')
+ c -= 256
+ self._offsets = self._offsets[:count]
+
+ # Read the TOC
+ self._toc = {}
+ count = self._root.read('>I')[0]
+ for n in range(count):
+ nlen = self._root.read('B')[0]
+ name = str(self._root.read(nlen))
+ value = self._root.read('>I')[0]
+ self._toc[name] = value
+
+ # Read the free lists
+ self._free = []
+ for n in range(32):
+ count = self._root.read('>I')
+ self._free.append(list(self._root.read('>%uI' % count)))
+
+ @classmethod
+ def open(cls, file_or_name, mode='r+'):
+ if isinstance(file_or_name, (str, unicode)):
+ if not 'b' in mode:
+ mode = mode[:1] + 'b' + mode[1:]
+ f = open(file_or_name, mode)
+ else:
+ f = file_or_name
+
+ if 'w' in mode:
+ # Create an empty file in this case
+ f.truncate()
+
+ # An empty root block needs 1264 bytes:
+ #
+ # 0 4 offset count
+ # 4 4 unknown
+ # 8 4 root block offset (2048)
+ # 12 255 * 4 padding (offsets are in multiples of 256)
+ # 1032 4 toc count (0)
+ # 1036 228 free list
+ # total 1264
+
+ # The free list will contain the following:
+ #
+ # 0 5 * 4 no blocks of width less than 5
+ # 20 6 * 8 1 block each of widths 5 to 10
+ # 68 4 no blocks of width 11 (allocated for the root)
+ # 72 19 * 8 1 block each of widths 12 to 30
+ # 224 4 no blocks of width 31
+ # total 228
+ #
+ # (The reason for this layout is that we allocate 2**5 bytes for
+ # the header, which splits the initial 2GB region into every size
+ # below 2**31, including *two* blocks of size 2**5, one of which
+ # we take. The root block itself then needs a block of size
+ # 2**11. Conveniently, each of these initial blocks will be
+ # located at offset 2**n where n is its width.)
+
+ # Write the header
+ header = struct.pack(b'>I4sIII16s',
+ 1, b'Bud1',
+ 2048, 1264, 2048,
+ b'\x00\x00\x10\x0c'
+ b'\x00\x00\x00\x87'
+ b'\x00\x00\x20\x0b'
+ b'\x00\x00\x00\x00')
+ f.write(header)
+ f.write(b'\0' * 2016)
+
+ # Write the root block
+ free_list = [struct.pack(b'>5I', 0, 0, 0, 0, 0)]
+ for n in range(5, 11):
+ free_list.append(struct.pack(b'>II', 1, 2**n))
+ free_list.append(struct.pack(b'>I', 0))
+ for n in range(12, 31):
+ free_list.append(struct.pack(b'>II', 1, 2**n))
+ free_list.append(struct.pack(b'>I', 0))
+
+ root = b''.join([struct.pack(b'>III', 1, 0, 2048 | 5),
+ struct.pack(b'>I', 0) * 255,
+ struct.pack(b'>I', 0)] + free_list)
+ f.write(root)
+
+ return Allocator(f)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ self.close()
+
+ def close(self):
+ self.flush()
+ self._file.close()
+
+ def flush(self):
+ if self._dirty:
+ size = self._root_block_size()
+ self.allocate(size, 0)
+ with self.get_block(0) as rblk:
+ self._write_root_block_into(rblk)
+
+ addr = self._offsets[0]
+ offset = addr & ~0x1f
+ size = 1 << (addr & 0x1f)
+
+ self._file.seek(0, os.SEEK_SET)
+ self._file.write(struct.pack(b'>I4sIII16s',
+ 1, b'Bud1',
+ offset, size, offset,
+ self._unknown1))
+
+ self._dirty = False
+
+ self._file.flush()
+
+ def read(self, offset, size_or_format):
+ """Read data at `offset', or raise an exception. `size_or_format'
+ may either be a byte count, in which case we return raw data,
+ or a format string for `struct.unpack', in which case we
+ work out the size and unpack the data before returning it."""
+ # N.B. There is a fixed offset of four bytes(!)
+ self._file.seek(offset + 4, os.SEEK_SET)
+
+ if isinstance(size_or_format, (str, unicode)):
+ size = struct.calcsize(size_or_format)
+ fmt = size_or_format
+ else:
+ size = size_or_format
+ fmt = None
+
+ ret = self._file.read(size)
+ if len(ret) < size:
+ ret += b'\0' * (size - len(ret))
+
+ if fmt is not None:
+ if isinstance(ret, bytearray):
+ ret = struct.unpack_from(fmt, bytes(ret))
+ else:
+ ret = struct.unpack(fmt, ret)
+
+ return ret
+
+ def write(self, offset, data_or_format, *args):
+ """Write data at `offset', or raise an exception. `data_or_format'
+ may either be the data to write, or a format string for `struct.pack',
+ in which case we pack the additional arguments and write the
+ resulting data."""
+ # N.B. There is a fixed offset of four bytes(!)
+ self._file.seek(offset + 4, os.SEEK_SET)
+
+ if len(args):
+ data = struct.pack(data_or_format, *args)
+ else:
+ data = data_or_format
+
+ self._file.write(data)
+
+ def get_block(self, block):
+ try:
+ addr = self._offsets[block]
+ except IndexError:
+ return None
+
+ offset = addr & ~0x1f
+ size = 1 << (addr & 0x1f)
+
+ return Block(self, offset, size)
+
+ def _root_block_size(self):
+ """Return the number of bytes required by the root block."""
+ # Offsets
+ size = 8
+ size += 4 * ((len(self._offsets) + 255) & ~255)
+
+ # TOC
+ size += 4
+ size += sum([5 + len(s) for s in self._toc])
+
+ # Free list
+ size += sum([4 + 4 * len(fl) for fl in self._free])
+
+ return size
+
+ def _write_root_block_into(self, block):
+ # Offsets
+ block.write('>II', len(self._offsets), self._unknown2)
+ block.write('>%uI' % len(self._offsets), *self._offsets)
+ extra = len(self._offsets) & 255
+ if extra:
+ block.write(b'\0\0\0\0' * (256 - extra))
+
+ # TOC
+ keys = list(self._toc.keys())
+ keys.sort()
+
+ block.write('>I', len(keys))
+ for k in keys:
+ b = k.encode('utf-8')
+ block.write('B', len(b))
+ block.write(b)
+ block.write('>I', self._toc[k])
+
+ # Free list
+ for w, f in enumerate(self._free):
+ block.write('>I', len(f))
+ if len(f):
+ block.write('>%uI' % len(f), *f)
+
+ def _buddy(self, offset, width):
+ f = self._free[width]
+ b = offset ^ (1 << width)
+
+ try:
+ ndx = f.index(b)
+ except ValueError:
+ ndx = None
+
+ return (f, b, ndx)
+
+ def _release(self, offset, width):
+ # Coalesce
+ while True:
+ f,b,ndx = self._buddy(offset, width)
+
+ if ndx is None:
+ break
+
+ offset &= b
+ width += 1
+ del f[ndx]
+
+ # Add to the list
+ bisect.insort(f, offset)
+
+ # Mark as dirty
+ self._dirty = True
+
+ def _alloc(self, width):
+ w = width
+ while not self._free[w]:
+ w += 1
+ while w > width:
+ offset = self._free[w].pop(0)
+ w -= 1
+ self._free[w] = [offset, offset ^ (1 << w)]
+ self._dirty = True
+ return self._free[width].pop(0)
+
+ def allocate(self, bytes, block=None):
+ """Allocate or reallocate a block such that it has space for at least
+ `bytes' bytes."""
+ if block is None:
+ # Find the first unused block
+ try:
+ block = self._offsets.index(0)
+ except ValueError:
+ block = len(self._offsets)
+ self._offsets.append(0)
+
+ # Compute block width
+ width = max(bytes.bit_length(), 5)
+
+ addr = self._offsets[block]
+ offset = addr & ~0x1f
+
+ if addr:
+ blkwidth = addr & 0x1f
+ if blkwidth == width:
+ return block
+ self._release(offset, width)
+ self._offsets[block] = 0
+
+ offset = self._alloc(width)
+ self._offsets[block] = offset | width
+ return block
+
+ def release(self, block):
+ addr = self._offsets[block]
+
+ if addr:
+ width = addr & 0x1f
+ offset = addr & ~0x1f
+ self._release(offset, width)
+
+ if block == len(self._offsets):
+ del self._offsets[block]
+ else:
+ self._offsets[block] = 0
+
+ def __len__(self):
+ return len(self._toc)
+
+ def __getitem__(self, key):
+ if not isinstance(key, (str, unicode)):
+ raise TypeError('Keys must be of string type')
+ return self._toc[key]
+
+ def __setitem__(self, key, value):
+ if not isinstance(key, (str, unicode)):
+ raise TypeError('Keys must be of string type')
+ self._toc[key] = value
+ self._dirty = True
+
+ def __delitem__(self, key):
+ if not isinstance(key, (str, unicode)):
+ raise TypeError('Keys must be of string type')
+ del self._toc[key]
+ self._dirty = True
+
+ def iterkeys(self):
+ return iterkeys(self._toc)
+
+ def keys(self):
+ return iterkeys(self._toc)
+
+ def __iter__(self):
+ return iterkeys(self._toc)
+
+ def __contains__(self, key):
+ return key in self._toc
+
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/ds_store/qt_attribution.json b/src/3rdparty/python/lib/python2.7/site-packages/ds_store/qt_attribution.json
new file mode 100644
index 000000000..dda98b937
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/ds_store/qt_attribution.json
@@ -0,0 +1,13 @@
+{
+ "Id": "ds_store",
+ "Name": "ds_store",
+ "QDocModule": "qbs",
+ "QtUsage": "Used in the qbs dmg module for building Apple disk images.",
+ "Description": "Manipulate Finder .DS_Store files from Python",
+ "Homepage": "https://bitbucket.org/al45tair/ds_store",
+ "Version": "1.1.0",
+ "License": "MIT License",
+ "LicenseId": "MIT",
+ "LicenseFile": "LICENSE",
+ "Copyright": "Copyright (c) 2014 Alastair Houghton"
+}
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/ds_store/store.py b/src/3rdparty/python/lib/python2.7/site-packages/ds_store/store.py
new file mode 100644
index 000000000..bf680d77a
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/ds_store/store.py
@@ -0,0 +1,1231 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+from __future__ import print_function
+from __future__ import division
+
+import binascii
+import struct
+import biplist
+import mac_alias
+
+try:
+ next
+except NameError:
+ next = lambda x: x.next()
+try:
+ unicode
+except NameError:
+ unicode = str
+
+from . import buddy
+
+class ILocCodec(object):
+ @staticmethod
+ def encode(point):
+ return struct.pack(b'>IIII', point[0], point[1],
+ 0xffffffff, 0xffff0000)
+
+ @staticmethod
+ def decode(bytesData):
+ if isinstance(bytesData, bytearray):
+ x, y = struct.unpack_from(b'>II', bytes(bytesData[:8]))
+ else:
+ x, y = struct.unpack(b'>II', bytesData[:8])
+ return (x, y)
+
+class PlistCodec(object):
+ @staticmethod
+ def encode(plist):
+ return biplist.writePlistToString(plist)
+
+ @staticmethod
+ def decode(bytes):
+ return biplist.readPlistFromString(bytes)
+
+class BookmarkCodec(object):
+ @staticmethod
+ def encode(bmk):
+ return bmk.to_bytes()
+
+ @staticmethod
+ def decode(bytes):
+ return mac_alias.Bookmark.from_bytes(bytes)
+
+# This list tells the code how to decode particular kinds of entry in the
+# .DS_Store file. This is really a convenience, and we currently only
+# support a tiny subset of the possible entry types.
+codecs = {
+ 'Iloc': ILocCodec,
+ 'bwsp': PlistCodec,
+ 'lsvp': PlistCodec,
+ 'lsvP': PlistCodec,
+ 'icvp': PlistCodec,
+ 'pBBk': BookmarkCodec
+ }
+
+class DSStoreEntry(object):
+ """Holds the data from an entry in a ``.DS_Store`` file. Note that this is
+ not meant to represent the entry itself---i.e. if you change the type
+ or value, your changes will *not* be reflected in the underlying file.
+
+ If you want to make a change, you should either use the :class:`DSStore`
+ object's :meth:`DSStore.insert` method (which will replace a key if it
+ already exists), or the mapping access mode for :class:`DSStore` (often
+ simpler anyway).
+ """
+ def __init__(self, filename, code, typecode, value=None):
+ if str != bytes and type(filename) == bytes:
+ filename = filename.decode('utf-8')
+ self.filename = filename
+ self.code = code
+ self.type = typecode
+ self.value = value
+
+ @classmethod
+ def read(cls, block):
+ """Read a ``.DS_Store`` entry from the containing Block"""
+ # First read the filename
+ nlen = block.read(b'>I')[0]
+ filename = block.read(2 * nlen).decode('utf-16be')
+
+ # Next, read the code and type
+ code, typecode = block.read(b'>4s4s')
+
+ # Finally, read the data
+ if typecode == b'bool':
+ value = block.read(b'>?')[0]
+ elif typecode == b'long' or typecode == b'shor':
+ value = block.read(b'>I')[0]
+ elif typecode == b'blob':
+ vlen = block.read(b'>I')[0]
+ value = block.read(vlen)
+
+ codec = codecs.get(code, None)
+ if codec:
+ value = codec.decode(value)
+ typecode = codec
+ elif typecode == b'ustr':
+ vlen = block.read(b'>I')[0]
+ value = block.read(2 * vlen).decode('utf-16be')
+ elif typecode == b'type':
+ value = block.read(b'>4s')[0]
+ elif typecode == b'comp' or typecode == b'dutc':
+ value = block.read(b'>Q')[0]
+ else:
+ raise ValueError('Unknown type code "%s"' % typecode)
+
+ return DSStoreEntry(filename, code, typecode, value)
+
+ def __lt__(self, other):
+ if not isinstance(other, DSStoreEntry):
+ raise TypeError('Can only compare against other DSStoreEntry objects')
+ sfl = self.filename.lower()
+ ofl = other.filename.lower()
+ return (sfl < ofl
+ or (self.filename == other.filename
+ and self.code < other.code))
+
+ def __le__(self, other):
+ if not isinstance(other, DSStoreEntry):
+ raise TypeError('Can only compare against other DSStoreEntry objects')
+ sfl = self.filename.lower()
+ ofl = other.filename.lower()
+ return (sfl < ofl
+ or (sfl == ofl
+ and self.code <= other.code))
+
+ def __eq__(self, other):
+ if not isinstance(other, DSStoreEntry):
+ raise TypeError('Can only compare against other DSStoreEntry objects')
+ sfl = self.filename.lower()
+ ofl = other.filename.lower()
+ return (sfl == ofl
+ and self.code == other.code)
+
+ def __ne__(self, other):
+ if not isinstance(other, DSStoreEntry):
+ raise TypeError('Can only compare against other DSStoreEntry objects')
+ sfl = self.filename.lower()
+ ofl = other.filename.lower()
+ return (sfl != ofl
+ or self.code != other.code)
+
+ def __gt__(self, other):
+ if not isinstance(other, DSStoreEntry):
+ raise TypeError('Can only compare against other DSStoreEntry objects')
+ sfl = self.filename.lower()
+ ofl = other.filename.lower()
+
+ selfCode = self.code
+ if str != bytes and type(selfCode) is bytes:
+ selfCode = selfCode.decode('utf-8')
+ otherCode = other.code
+ if str != bytes and type(otherCode) is bytes:
+ otherCode = otherCode.decode('utf-8')
+
+ return (sfl > ofl or (sfl == ofl and selfCode > otherCode))
+
+ def __ge__(self, other):
+ if not isinstance(other, DSStoreEntry):
+ raise TypeError('Can only compare against other DSStoreEntry objects')
+ sfl = self.filename.lower()
+ ofl = other.filename.lower()
+ return (sfl > ofl
+ or (sfl == ofl
+ and self.code >= other.code))
+
+ def __cmp__(self, other):
+ if not isinstance(other, DSStoreEntry):
+ raise TypeError('Can only compare against other DSStoreEntry objects')
+ r = cmp(self.filename.lower(), other.filename.lower())
+ if r:
+ return r
+ return cmp(self.code, other.code)
+
+ def byte_length(self):
+ """Compute the length of this entry, in bytes"""
+ utf16 = self.filename.encode('utf-16be')
+ l = 4 + len(utf16) + 8
+
+ if isinstance(self.type, (str, unicode)):
+ entry_type = self.type
+ value = self.value
+ else:
+ entry_type = 'blob'
+ value = self.type.encode(self.value)
+
+ if entry_type == 'bool':
+ l += 1
+ elif entry_type == 'long' or entry_type == 'shor':
+ l += 4
+ elif entry_type == 'blob':
+ l += 4 + len(value)
+ elif entry_type == 'ustr':
+ utf16 = value.encode('utf-16be')
+ l += 4 + len(utf16)
+ elif entry_type == 'type':
+ l += 4
+ elif entry_type == 'comp' or entry_type == 'dutc':
+ l += 8
+ else:
+ raise ValueError('Unknown type code "%s"' % entry_type)
+
+ return l
+
+ def write(self, block, insert=False):
+ """Write this entry to the specified Block"""
+ if insert:
+ w = block.insert
+ else:
+ w = block.write
+
+ if isinstance(self.type, (str, unicode)):
+ entry_type = self.type
+ value = self.value
+ else:
+ entry_type = 'blob'
+ value = self.type.encode(self.value)
+
+ utf16 = self.filename.encode('utf-16be')
+ w(b'>I', len(utf16) // 2)
+ w(utf16)
+ w(b'>4s4s', self.code.encode('utf-8'), entry_type.encode('utf-8'))
+
+ if entry_type == 'bool':
+ w(b'>?', value)
+ elif entry_type == 'long' or entry_type == 'shor':
+ w(b'>I', value)
+ elif entry_type == 'blob':
+ w(b'>I', len(value))
+ w(value)
+ elif entry_type == 'ustr':
+ utf16 = value.encode('utf-16be')
+ w(b'>I', len(utf16) // 2)
+ w(utf16)
+ elif entry_type == 'type':
+ w(b'>4s', value.encode('utf-8'))
+ elif entry_type == 'comp' or entry_type == 'dutc':
+ w(b'>Q', value)
+ else:
+ raise ValueError('Unknown type code "%s"' % entry_type)
+
+ def __repr__(self):
+ return '<%s %s>' % (self.filename, self.code)
+
+class DSStore(object):
+ """Python interface to a ``.DS_Store`` file. Works by manipulating the file
+ on the disk---so this code will work with ``.DS_Store`` files for *very*
+ large directories.
+
+ A :class:`DSStore` object can be used as if it was a mapping, e.g.::
+
+ d['foobar.dat']['Iloc']
+
+ will fetch the "Iloc" record for "foobar.dat", or raise :class:`KeyError` if
+ there is no such record. If used in this manner, the :class:`DSStore` object
+ will return (type, value) tuples, unless the type is "blob" and the module
+ knows how to decode it.
+
+ Currently, we know how to decode "Iloc", "bwsp", "lsvp", "lsvP" and "icvp"
+ blobs. "Iloc" decodes to an (x, y) tuple, while the others are all decoded
+ using ``biplist``.
+
+ Assignment also works, e.g.::
+
+ d['foobar.dat']['note'] = ('ustr', u'Hello World!')
+
+ as does deletion with ``del``::
+
+ del d['foobar.dat']['note']
+
+ This is usually going to be the most convenient interface, though
+ occasionally (for instance when creating a new ``.DS_Store`` file) you
+ may wish to drop down to using :class:`DSStoreEntry` objects directly."""
+ def __init__(self, store):
+ self._store = store
+ self._superblk = self._store['DSDB']
+ with self._get_block(self._superblk) as s:
+ self._rootnode, self._levels, self._records, \
+ self._nodes, self._page_size = s.read(b'>IIIII')
+ self._min_usage = 2 * self._page_size // 3
+ self._dirty = False
+
+ @classmethod
+ def open(cls, file_or_name, mode='r+', initial_entries=None):
+ """Open a ``.DS_Store`` file; pass either a Python file object, or a
+ filename in the ``file_or_name`` argument and a file access mode in
+ the ``mode`` argument. If you are creating a new file using the "w"
+ or "w+" modes, you may also specify a list of entries with which
+ to initialise the file."""
+ store = buddy.Allocator.open(file_or_name, mode)
+
+ if mode == 'w' or mode == 'w+':
+ superblk = store.allocate(20)
+ store['DSDB'] = superblk
+ page_size = 4096
+
+ if not initial_entries:
+ root = store.allocate(page_size)
+
+ with store.get_block(root) as rootblk:
+ rootblk.zero_fill()
+
+ with store.get_block(superblk) as s:
+ s.write(b'>IIIII', root, 0, 0, 1, page_size)
+ else:
+ # Make sure they're in sorted order
+ initial_entries = list(initial_entries)
+ initial_entries.sort()
+
+ # Construct the tree
+ current_level = initial_entries
+ next_level = []
+ levels = []
+ ptr_size = 0
+ node_count = 0
+ while True:
+ total = 8
+ nodes = []
+ node = []
+ for e in current_level:
+ new_total = total + ptr_size + e.byte_length()
+ if new_total > page_size:
+ nodes.append(node)
+ next_level.append(e)
+ total = 8
+ node = []
+ else:
+ total = new_total
+ node.append(e)
+ if node:
+ nodes.append(node)
+
+ node_count += len(nodes)
+ levels.append(nodes)
+
+ if len(nodes) == 1:
+ break
+
+ current_level = next_level
+ next_level = []
+ ptr_size = 4
+
+ # Allocate nodes
+ ptrs = [store.allocate(page_size) for n in range(node_count)]
+
+ # Generate nodes
+ pointers = []
+ prev_pointers = None
+ for level in levels:
+ ppndx = 0
+ lptrs = ptrs[-len(level):]
+ del ptrs[-len(level):]
+ for node in level:
+ ndx = lptrs.pop(0)
+ if prev_pointers is None:
+ with store.get_block(ndx) as block:
+ block.write(b'>II', 0, len(node))
+ for e in node:
+ e.write(block)
+ else:
+ next_node = prev_pointers[ppndx + len(node)]
+ node_ptrs = prev_pointers[ppndx:ppndx+len(node)]
+
+ with store.get_block(ndx) as block:
+ block.write(b'>II', next_node, len(node))
+ for ptr, e in zip(node_ptrs, node):
+ block.write(b'>I', ptr)
+ e.write(block)
+
+ pointers.append(ndx)
+ prev_pointers = pointers
+ pointers = []
+
+ root = prev_pointers[0]
+
+ with store.get_block(superblk) as s:
+ s.write(b'>IIIII', root, len(levels), len(initial_entries),
+ node_count, page_size)
+
+ return DSStore(store)
+
+ def _get_block(self, number):
+ return self._store.get_block(number)
+
+ def flush(self):
+ """Flush any dirty data back to the file."""
+ if self._dirty:
+ self._dirty = False
+
+ with self._get_block(self._superblk) as s:
+ s.write(b'>IIIII', self._rootnode, self._levels, self._records,
+ self._nodes, self._page_size)
+ self._store.flush()
+
+ def close(self):
+ """Flush dirty data and close the underlying file."""
+ self.flush()
+ self._store.close()
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ self.close()
+
+ # Internal B-Tree nodes look like this:
+ #
+ # [ next | count | (ptr0 | rec0) | (ptr1 | rec1) ... (ptrN | recN) ]
+
+ # Leaf nodes look like this:
+ #
+ # [ 0 | count | rec0 | rec1 ... recN ]
+
+ # Iterate over the tree, starting at `node'
+ def _traverse(self, node):
+ if node is None:
+ node = self._rootnode
+ with self._get_block(node) as block:
+ next_node, count = block.read(b'>II')
+ if next_node:
+ for n in range(count):
+ ptr = block.read(b'>I')[0]
+ for e in self._traverse(ptr):
+ yield e
+ e = DSStoreEntry.read(block)
+ yield e
+ for e in self._traverse(next_node):
+ yield e
+ else:
+ for n in range(count):
+ e = DSStoreEntry.read(block)
+ yield e
+
+ # Display the data in `node'
+ def _dump_node(self, node):
+ with self._get_block(node) as block:
+ next_node, count = block.read(b'>II')
+ print('next: %u\ncount: %u\n' % (next_node, count))
+ for n in range(count):
+ if next_node:
+ ptr = block.read(b'>I')[0]
+ print('%8u ' % ptr, end=' ')
+ else:
+ print(' ', end=' ')
+ e = DSStoreEntry.read(block)
+ print(e, ' (%u)' % e.byte_length())
+ print('used: %u' % block.tell())
+
+ # Display the data in the super block
+ def _dump_super(self):
+ print('root: %u\nlevels: %u\nrecords: %u\nnodes: %u\npage-size: %u' \
+ % (self._rootnode, self._levels, self._records,
+ self._nodes, self._page_size))
+
+ # Splits entries across two blocks, returning one pivot
+ #
+ # Tries to balance the block usage across the two as best it can
+ def _split2(self, blocks, entries, pointers, before, internal):
+ left_block = blocks[0]
+ right_block = blocks[1]
+
+ count = len(entries)
+
+ # Find the feasible splits
+ best_split = None
+ best_diff = None
+ total = before[count]
+
+ if 8 + total <= self._page_size:
+ # We can use a *single* node for this
+ best_split = count
+ else:
+ # Split into two nodes
+ for n in range(1, count - 1):
+ left_size = 8 + before[n]
+ right_size = 8 + total - before[n + 1]
+
+ if left_size > self._page_size:
+ break
+ if right_size > self._page_size:
+ continue
+
+ diff = abs(left_size - right_size)
+
+ if best_split is None or diff < best_diff:
+ best_split = n
+ best_diff = diff
+
+ if best_split is None:
+ return None
+
+ # Write the nodes
+ left_block.seek(0)
+ if internal:
+ next_node = pointers[best_split]
+ else:
+ next_node = 0
+ left_block.write(b'>II', next_node, best_split)
+
+ for n in range(best_split):
+ if internal:
+ left_block.write(b'>I', pointers[n])
+ entries[n].write(left_block)
+
+ left_block.zero_fill()
+
+ if best_split == count:
+ return []
+
+ right_block.seek(0)
+ if internal:
+ next_node = pointers[count]
+ else:
+ next_node = 0
+ right_block.write(b'>II', next_node, count - best_split - 1)
+
+ for n in range(best_split + 1, count):
+ if internal:
+ right_block.write(b'>I', pointers[n])
+ entries[n].write(right_block)
+
+ right_block.zero_fill()
+
+ pivot = entries[best_split]
+
+ return [pivot]
+
+ def _split(self, node, entry, right_ptr=0):
+ self._nodes += 1
+ self._dirty = True
+ new_right = self._store.allocate(self._page_size)
+ with self._get_block(node) as block, \
+ self._get_block(new_right) as right_block:
+
+ # First, measure and extract all the elements
+ entry_size = entry.byte_length()
+ entry_pos = None
+ next_node, count = block.read(b'>II')
+ if next_node:
+ entry_size += 4
+ pointers = []
+ entries = []
+ before = []
+ total = 0
+ for n in range(count):
+ pos = block.tell()
+ if next_node:
+ ptr = block.read(b'>I')[0]
+ pointers.append(ptr)
+ e = DSStoreEntry.read(block)
+ if e > entry:
+ entry_pos = n
+ entries.append(entry)
+ pointers.append(right_ptr)
+ before.append(total)
+ total += entry_size
+ entries.append(e)
+ before.append(total)
+ total += block.tell() - pos
+ before.append(total)
+ if next_node:
+ pointers.append(next_node)
+
+ pivot = self._split2([block, right_block],
+ entries, pointers, before,
+ bool(next_node))[0]
+
+ self._records += 1
+ self._nodes += 1
+ self._dirty = True
+
+ return (pivot, new_right)
+
+ # Allocate a new root node containing the element `pivot' and the pointers
+ # `left' and `right'
+ def _new_root(self, left, pivot, right):
+ new_root = self._store.allocate(self._page_size)
+ with self._get_block(new_root) as block:
+ block.write(b'>III', right, 1, left)
+ pivot.write(block)
+ self._rootnode = new_root
+ self._levels += 1
+ self._nodes += 1
+ self._dirty = True
+
+ # Insert an entry into an inner node; `path' is the path from the root
+ # to `node', not including `node' itself. `right_ptr' is the new node
+ # pointer (inserted to the RIGHT of `entry')
+ def _insert_inner(self, path, node, entry, right_ptr):
+ with self._get_block(node) as block:
+ next_node, count = block.read(b'>II')
+ insert_pos = None
+ insert_ndx = None
+ n = 0
+ while n < count:
+ pos = block.tell()
+ ptr = block.read(b'>I')[0]
+ e = DSStoreEntry.read(block)
+ if e == entry:
+ if n == count - 1:
+ right_ptr = next_node
+ next_node = ptr
+ block_seek(pos)
+ else:
+ right_ptr = block.read(b'>I')[0]
+ block.seek(pos + 4)
+ insert_pos = pos
+ insert_ndx = n
+ block.delete(e.byte_length() + 4)
+ count -= 1
+ self._records += 1
+ self._dirty = True
+ continue
+ elif insert_pos is None and e > entry:
+ insert_pos = pos
+ insert_ndx = n
+ n += 1
+ if insert_pos is None:
+ insert_pos = block.tell()
+ insert_ndx = count
+ remaining = self._page_size - block.tell()
+
+ if remaining < entry.byte_length() + 4:
+ pivot, new_right = self._split(node, entry, right_ptr)
+ if path:
+ self._insert_inner(path[:-1], path[-1], pivot, new_right)
+ else:
+ self._new_root(node, pivot, new_right)
+ else:
+ if insert_ndx == count:
+ block.seek(insert_pos)
+ block.write(b'>I', next_node)
+ entry.write(block)
+ next_node = right_ptr
+ else:
+ block.seek(insert_pos + 4)
+ entry.write(block, True)
+ block.insert('>I', right_ptr)
+ block.seek(0)
+ count += 1
+ block.write(b'>II', next_node, count)
+ self._records += 1
+ self._dirty = True
+
+ # Insert `entry' into the leaf node `node'
+ def _insert_leaf(self, path, node, entry):
+ with self._get_block(node) as block:
+ next_node, count = block.read(b'>II')
+ insert_pos = None
+ insert_ndx = None
+ n = 0
+ while n < count:
+ pos = block.tell()
+ e = DSStoreEntry.read(block)
+ if e == entry:
+ insert_pos = pos
+ insert_ndx = n
+ block.seek(pos)
+ block.delete(e.byte_length())
+ count -= 1
+ self._records += 1
+ self._dirty = True
+ continue
+ elif insert_pos is None and e > entry:
+ insert_pos = pos
+ insert_ndx = n
+ n += 1
+ if insert_pos is None:
+ insert_pos = block.tell()
+ insert_ndx = count
+ remaining = self._page_size - block.tell()
+
+ if remaining < entry.byte_length():
+ pivot, new_right = self._split(node, entry)
+ if path:
+ self._insert_inner(path[:-1], path[-1], pivot, new_right)
+ else:
+ self._new_root(node, pivot, new_right)
+ else:
+ block.seek(insert_pos)
+ entry.write(block, True)
+ block.seek(0)
+ count += 1
+ block.write(b'>II', next_node, count)
+ self._records += 1
+ self._dirty = True
+
+ def insert(self, entry):
+ """Insert ``entry`` (which should be a :class:`DSStoreEntry`)
+ into the B-Tree."""
+ path = []
+ node = self._rootnode
+ while True:
+ with self._get_block(node) as block:
+ next_node, count = block.read(b'>II')
+ if next_node:
+ for n in range(count):
+ ptr = block.read(b'>I')[0]
+ e = DSStoreEntry.read(block)
+ if entry < e:
+ next_node = ptr
+ break
+ elif entry == e:
+ # If we find an existing entry the same, replace it
+ self._insert_inner(path, node, entry, None)
+ return
+ path.append(node)
+ node = next_node
+ else:
+ self._insert_leaf(path, node, entry)
+ return
+
+ # Return usage information for the specified `node'
+ def _block_usage(self, node):
+ with self._get_block(node) as block:
+ next_node, count = block.read(b'>II')
+
+ for n in range(count):
+ if next_node:
+ ptr = block.read(b'>I')[0]
+ e = DSStoreEntry.read(block)
+
+ used = block.tell()
+
+ return (count, used)
+
+ # Splits entries across three blocks, returning two pivots
+ def _split3(self, blocks, entries, pointers, before, internal):
+ count = len(entries)
+
+ # Find the feasible splits
+ best_split = None
+ best_diff = None
+ total = before[count]
+ for n in range(1, count - 3):
+ left_size = 8 + before[n]
+ remaining = 16 + total - before[n + 1]
+
+ if left_size > self._page_size:
+ break
+ if remaining > 2 * self._page_size:
+ continue
+
+ for m in range(n + 2, count - 1):
+ mid_size = 8 + before[m] - before[n + 1]
+ right_size = 8 + total - before[m + 1]
+
+ if mid_size > self._page_size:
+ break
+ if right_size > self._page_size:
+ continue
+
+ diff = abs(left_size - mid_size) * abs(right_size - mid_size)
+
+ if best_split is None or diff < best_diff:
+ best_split = (n, m, count)
+ best_diff = diff
+
+ if best_split is None:
+ return None
+
+ # Write the nodes
+ prev_split = -1
+ for block, split in zip(blocks, best_split):
+ block.seek(0)
+ if internal:
+ next_node = pointers[split]
+ else:
+ next_node = 0
+ block.write(b'>II', next_node, split)
+
+ for n in range(prev_split + 1, split):
+ if internal:
+ block.write(b'>I', pointers[n])
+ entries[n].write(block)
+
+ block.zero_fill()
+
+ prev_split = split
+
+ return (entries[best_split[0]], entries[best_split[1]])
+
+ # Extract all of the entries from the specified list of `blocks',
+ # separating them by the specified `pivots'. Also computes the
+ # amount of space used before each entry.
+ def _extract(self, blocks, pivots):
+ pointers = []
+ entries = []
+ before = []
+ total = 0
+ ppivots = pivots + [None]
+ for b,p in zip(blocks, ppivots):
+ b.seek(0)
+ next_node, count = b.read(b'>II')
+ for n in range(count):
+ pos = b.tell()
+ if next_node:
+ ptr = b.read(b'>I')[0]
+ pointers.append(ptr)
+ e = DSStoreEntry.read(b)
+ entries.append(e)
+ before.append(total)
+ total += b.tell() - pos
+ if next_node:
+ pointers.append(next_node)
+ if p:
+ entries.append(p)
+ before.append(total)
+ total += p.byte_length()
+ if next_node:
+ total += 4
+ before.append(total)
+
+ return (entries, pointers, before)
+
+ # Rebalance the specified `node', whose path from the root is `path'.
+ def _rebalance(self, path, node):
+ # Can't rebalance the root
+ if not path:
+ return
+
+ with self._get_block(node) as block:
+ next_node, count = block.read(b'>II')
+
+ with self._get_block(path[-1]) as parent:
+ # Find the left and right siblings and respective pivots
+ parent_next, parent_count = parent.read(b'>II')
+ left_pos = None
+ left_node = None
+ left_pivot = None
+ node_pos = None
+ right_pos = None
+ right_node = None
+ right_pivot = None
+ prev_e = prev_ptr = prev_pos = None
+ for n in range(parent_count):
+ pos = parent.tell()
+ ptr = parent.read(b'>I')[0]
+ e = DSStoreEntry.read(parent)
+
+ if ptr == node:
+ node_pos = pos
+ right_pivot = e
+ left_pos = prev_pos
+ left_pivot = prev_e
+ left_node = prev_ptr
+ elif prev_ptr == node:
+ right_node = ptr
+ right_pos = pos
+ break
+
+ prev_e = e
+ prev_ptr = ptr
+ prev_pos = pos
+
+ if parent_next == node:
+ node_pos = parent.tell()
+ left_pos = prev_pos
+ left_pivot = prev_e
+ left_node = prev_ptr
+ elif right_node is None:
+ right_node = parent_next
+ right_pos = parent.tell()
+
+ parent_used = parent.tell()
+
+ if left_node and right_node:
+ with self._get_block(left_node) as left, \
+ self._get_block(right_node) as right:
+ blocks = [left, block, right]
+ pivots = [left_pivot, right_pivot]
+
+ entries, pointers, before = self._extract(blocks, pivots)
+
+ # If there's a chance that we could use two pages instead
+ # of three, go for it
+ pivots = self._split2(blocks, entries, pointers,
+ before, bool(next_node))
+ if pivots is None:
+ ptrs = [left_node, node, right_node]
+ pivots = self._split3(blocks, entries, pointers,
+ before, bool(next_node))
+ else:
+ if pivots:
+ ptrs = [left_node, node]
+ else:
+ ptrs = [left_node]
+ self._store.release(node)
+ self._nodes -= 1
+ node = left_node
+ self._store.release(right_node)
+ self._nodes -= 1
+ self._dirty = True
+
+ # Remove the pivots from the parent
+ with self._get_block(path[-1]) as parent:
+ if right_node == parent_next:
+ parent.seek(left_pos)
+ parent.delete(right_pos - left_pos)
+ parent_next = left_node
+ else:
+ parent.seek(left_pos + 4)
+ parent.delete(right_pos - left_pos)
+ parent.seek(0)
+ parent_count -= 2
+ parent.write(b'>II', parent_next, parent_count)
+ self._records -= 2
+
+ # Replace with those in pivots
+ for e,rp in zip(pivots, ptrs[1:]):
+ self._insert_inner(path[:-1], path[-1], e, rp)
+ elif left_node:
+ with self._get_block(left_node) as left:
+ blocks = [left, block]
+ pivots = [left_pivot]
+
+ entries, pointers, before = self._extract(blocks, pivots)
+
+ pivots = self._split2(blocks, entries, pointers,
+ before, bool(next_node))
+
+ # Remove the pivot from the parent
+ with self._get_block(path[-1]) as parent:
+ if node == parent_next:
+ parent.seek(left_pos)
+ parent.delete(node_pos - left_pos)
+ parent_next = left_node
+ else:
+ parent.seek(left_pos + 4)
+ parent.delete(node_pos - left_pos)
+ parent.seek(0)
+ parent_count -= 1
+ parent.write(b'>II', parent_next, parent_count)
+ self._records -= 1
+
+ # Replace the pivot
+ if pivots:
+ self._insert_inner(path[:-1], path[-1], pivots[0], node)
+ elif right_node:
+ with self._get_block(right_node) as right:
+ blocks = [block, right]
+ pivots = [right_pivot]
+
+ entries, pointers, before = self._extract(blocks, pivots)
+
+ pivots = self._split2(blocks, entries, pointers,
+ before, bool(next_node))
+
+ # Remove the pivot from the parent
+ with self._get_block(path[-1]) as parent:
+ if right_node == parent_next:
+ parent.seek(pos)
+ parent.delete(right_pos - node_pos)
+ parent_next = node
+ else:
+ parent.seek(pos + 4)
+ parent.delete(right_pos - node_pos)
+ parent.seek(0)
+ parent_count -= 1
+ parent.write(b'>II', parent_next, parent_count)
+ self._records -= 1
+
+ # Replace the pivot
+ if pivots:
+ self._insert_inner(path[:-1], path[-1], pivots[0],
+ right_node)
+
+ if not path and not parent_count:
+ self._store.release(path[-1])
+ self._nodes -= 1
+ self._dirty = True
+ self._rootnode = node
+ else:
+ count, used = self._block_usage(path[-1])
+
+ if used < self._page_size // 2:
+ self._rebalance(path[:-1], path[-1])
+
+ # Delete from the leaf node `node'. `filename_lc' has already been
+ # lower-cased.
+ def _delete_leaf(self, node, filename_lc, code):
+ found = False
+
+ with self._get_block(node) as block:
+ next_node, count = block.read(b'>II')
+
+ for n in range(count):
+ pos = block.tell()
+ e = DSStoreEntry.read(block)
+ if e.filename.lower() == filename_lc \
+ and (code is None or e.code == code):
+ block.seek(pos)
+ block.delete(e.byte_length())
+ found = True
+
+ # This does not affect the loop; THIS IS NOT A BUG
+ count -= 1
+
+ self._records -= 1
+ self._dirty = True
+
+ if found:
+ used = block.tell()
+
+ block.seek(0)
+ block.write(b'>II', next_node, count)
+
+ return used < self._page_size // 2
+ else:
+ return False
+
+ # Remove the largest entry from the subtree starting at `node' (with
+ # path from root `path'). Returns a tuple (rebalance, entry) where
+ # rebalance is either None if no rebalancing is required, or a
+ # (path, node) tuple giving the details of the node to rebalance.
+ def _take_largest(self, path, node):
+ path = list(path)
+ rebalance = None
+ while True:
+ with self._get_block(node) as block:
+ next_node, count = block.read(b'>II')
+
+ if next_node:
+ path.append(node)
+ node = next_node
+ continue
+
+ for n in range(count):
+ pos = block.tell()
+ e = DSStoreEntry.read(block)
+
+ count -= 1
+ block.seek(0)
+ block.write(b'>II', next_node, count)
+
+ if pos < self._page_size // 2:
+ rebalance = (path, node)
+ break
+
+ return rebalance, e
+
+ # Delete an entry from an inner node, `node'
+ def _delete_inner(self, path, node, filename_lc, code):
+ rebalance = False
+
+ with self._get_block(node) as block:
+ next_node, count = block.read(b'>II')
+
+ for n in range(count):
+ pos = block.tell()
+ ptr = block.read(b'>I')[0]
+ e = DSStoreEntry.read(block)
+ if e.filename.lower() == filename_lc \
+ and (code is None or e.code == code):
+ # Take the largest from the left subtree
+ rebalance, largest = self._take_largest(path, ptr)
+
+ # Delete this entry
+ if n == count - 1:
+ right_ptr = next_node
+ next_node = ptr
+ block.seek(pos)
+ else:
+ right_ptr = block.read(b'>I')[0]
+ block.seek(pos + 4)
+
+ block.delete(e.byte_length() + 4)
+
+ count -= 1
+ block.seek(0)
+ block.write(b'>II', next_node, count)
+
+ self._records -= 1
+ self._dirty = True
+
+ break
+
+ # Replace the pivot value
+ self._insert_inner(path, node, largest, right_ptr)
+
+ # Rebalance from the node we stole from
+ if rebalance:
+ self._rebalance(rebalance[0], rebalance[1])
+ return True
+ return False
+
+ def delete(self, filename, code):
+ """Delete an item, identified by ``filename`` and ``code``
+ from the B-Tree."""
+ if isinstance(filename, DSStoreEntry):
+ code = filename.code
+ filename = filename.filename
+
+ # If we're deleting *every* node for "filename", we must recurse
+ if code is None:
+ ###TODO: Fix this so we can do bulk deletes
+ raise ValueError('You must delete items individually. Sorry')
+
+ # Otherwise, we're deleting *one* specific node
+ filename_lc = filename.lower()
+ path = []
+ node = self._rootnode
+ while True:
+ with self._get_block(node) as block:
+ next_node, count = block.read(b'>II')
+ if next_node:
+ for n in range(count):
+ ptr = block.read(b'>I')[0]
+ e = DSStoreEntry.read(block)
+ e_lc = e.filename.lower()
+ if filename_lc < e_lc \
+ or (filename_lc == e_lc and code < e.code):
+ next_node = ptr
+ break
+ elif filename_lc == e_lc and code == e.code:
+ self._delete_inner(path, node, filename_lc, code)
+ return
+ path.append(node)
+ node = next_node
+ else:
+ if self._delete_leaf(node, filename_lc, code):
+ self._rebalance(path, node)
+ return
+
+ # Find implementation
+ def _find(self, node, filename_lc, code=None):
+ with self._get_block(node) as block:
+ next_node, count = block.read(b'>II')
+ if next_node:
+ for n in range(count):
+ ptr = block.read(b'>I')[0]
+ e = DSStoreEntry.read(block)
+ if filename_lc < e.filename.lower():
+ for e in self._find(ptr, filename_lc, code):
+ yield e
+ return
+ elif filename_lc == e.filename.lower():
+ if code is None or (code and code < e.code):
+ for e in self._find(ptr, filename_lc, code):
+ yield e
+ if code is None or code == e.code:
+ yield e
+ elif code < e.code:
+ return
+ for e in self._find(next_node, filename_lc, code):
+ yield e
+ else:
+ for n in range(count):
+ e = DSStoreEntry.read(block)
+ if filename_lc == e.filename.lower():
+ if code is None or code == e.code:
+ yield e
+ elif code < e.code:
+ return
+
+ def find(self, filename, code=None):
+ """Returns a generator that will iterate over matching entries in
+ the B-Tree."""
+ if isinstance(filename, DSStoreEntry):
+ code = filename.code
+ filename = filename.filename
+
+ filename_lc = filename.lower()
+
+ return self._find(self._rootnode, filename_lc, code)
+
+ def __len__(self):
+ return self._records
+
+ def __iter__(self):
+ return self._traverse(self._rootnode)
+
+ class Partial(object):
+ """This is used to implement indexing."""
+ def __init__(self, store, filename):
+ self._store = store
+ self._filename = filename
+
+ def __getitem__(self, code):
+ if code is None:
+ raise KeyError('no such key - [%s][None]' % self._filename)
+
+ try:
+ item = next(self._store.find(self._filename, code))
+ except StopIteration:
+ raise KeyError('no such key - [%s][%s]' % (self._filename,
+ code))
+
+ if not isinstance(item.type, (str, unicode)):
+ return item.value
+
+ return (item.type, item.value)
+
+ def __setitem__(self, code, value):
+ if code is None:
+ raise KeyError('bad key - [%s][None]' % self._filename)
+
+ codec = codecs.get(code, None)
+ if codec:
+ entry_type = codec
+ entry_value = value
+ else:
+ entry_type = value[0]
+ entry_value = value[1]
+
+ self._store.insert(DSStoreEntry(self._filename, code,
+ entry_type, entry_value))
+
+ def __delitem__(self, code):
+ if code is None:
+ raise KeyError('no such key - [%s][None]' % self._filename)
+
+ self._store.delete(self._filename, code)
+
+ def __iter__(self):
+ for item in self._store.find(self._filename):
+ yield item
+
+ def __getitem__(self, filename):
+ return self.Partial(self, filename)
+
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/LICENSE b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/LICENSE
new file mode 100644
index 000000000..e91f4eb38
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2014 Alastair Houghton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/__init__.py b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/__init__.py
new file mode 100644
index 000000000..7eb314107
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/__init__.py
@@ -0,0 +1,27 @@
+from .alias import *
+from .bookmark import *
+
+__all__ = [ 'ALIAS_KIND_FILE', 'ALIAS_KIND_FOLDER',
+ 'ALIAS_HFS_VOLUME_SIGNATURE',
+ 'ALIAS_FIXED_DISK', 'ALIAS_NETWORK_DISK', 'ALIAS_400KB_FLOPPY_DISK',
+ 'ALIAS_800KB_FLOPPY_DISK', 'ALIAS_1_44MB_FLOPPY_DISK',
+ 'ALIAS_EJECTABLE_DISK',
+ 'ALIAS_NO_CNID',
+ 'kBookmarkPath', 'kBookmarkCNIDPath', 'kBookmarkFileProperties',
+ 'kBookmarkFileName', 'kBookmarkFileID', 'kBookmarkFileCreationDate',
+ 'kBookmarkTOCPath', 'kBookmarkVolumePath',
+ 'kBookmarkVolumeURL', 'kBookmarkVolumeName', 'kBookmarkVolumeUUID',
+ 'kBookmarkVolumeSize', 'kBookmarkVolumeCreationDate',
+ 'kBookmarkVolumeProperties', 'kBookmarkContainingFolder',
+ 'kBookmarkUserName', 'kBookmarkUID', 'kBookmarkWasFileReference',
+ 'kBookmarkCreationOptions', 'kBookmarkURLLengths',
+ 'kBookmarkSecurityExtension',
+ 'AppleShareInfo',
+ 'VolumeInfo',
+ 'TargetInfo',
+ 'Alias',
+ 'Bookmark',
+ 'Data',
+ 'URL' ]
+
+
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/alias.py b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/alias.py
new file mode 100644
index 000000000..b35f4029b
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/alias.py
@@ -0,0 +1,587 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+from __future__ import division
+
+import struct
+import datetime
+import io
+import re
+import os
+import os.path
+import stat
+import sys
+
+if sys.platform == 'darwin':
+ from . import osx
+
+from .utils import *
+
+ALIAS_KIND_FILE = 0
+ALIAS_KIND_FOLDER = 1
+
+ALIAS_HFS_VOLUME_SIGNATURE = b'H+'
+
+ALIAS_FIXED_DISK = 0
+ALIAS_NETWORK_DISK = 1
+ALIAS_400KB_FLOPPY_DISK = 2
+ALIAS_800KB_FLOPPY_DISK = 3
+ALIAS_1_44MB_FLOPPY_DISK = 4
+ALIAS_EJECTABLE_DISK = 5
+
+ALIAS_NO_CNID = 0xffffffff
+
+class AppleShareInfo (object):
+ def __init__(self, zone=None, server=None, user=None):
+ #: The AppleShare zone
+ self.zone = zone
+ #: The AFP server
+ self.server = server
+ #: The username
+ self.user = user
+
+ def __repr__(self):
+ return 'AppleShareInfo(%r,%r,%r)' % (self.zone, self.server, self.user)
+
+class VolumeInfo (object):
+ def __init__(self, name, creation_date, fs_type, disk_type,
+ attribute_flags, fs_id, appleshare_info=None,
+ driver_name=None, posix_path=None, disk_image_alias=None,
+ dialup_info=None, network_mount_info=None):
+ #: The name of the volume on which the target resides
+ self.name = name
+
+ #: The creation date of the target's volume
+ self.creation_date = creation_date
+
+ #: The filesystem type (a two character code, e.g. ``b'H+'`` for HFS+)
+ self.fs_type = fs_type
+
+ #: The type of disk; should be one of
+ #:
+ #: * ALIAS_FIXED_DISK
+ #: * ALIAS_NETWORK_DISK
+ #: * ALIAS_400KB_FLOPPY_DISK
+ #: * ALIAS_800KB_FLOPPY_DISK
+ #: * ALIAS_1_44MB_FLOPPY_DISK
+ #: * ALIAS_EJECTABLE_DISK
+ self.disk_type = disk_type
+
+ #: Filesystem attribute flags (from HFS volume header)
+ self.attribute_flags = attribute_flags
+
+ #: Filesystem identifier
+ self.fs_id = fs_id
+
+ #: AppleShare information (for automatic remounting of network shares)
+ #: *(optional)*
+ self.appleshare_info = appleshare_info
+
+ #: Driver name (*probably* contains a disk driver name on older Macs)
+ #: *(optional)*
+ self.driver_name = driver_name
+
+ #: POSIX path of the mount point of the target's volume
+ #: *(optional)*
+ self.posix_path = posix_path
+
+ #: :class:`Alias` object pointing at the disk image on which the
+ #: target's volume resides *(optional)*
+ self.disk_image_alias = disk_image_alias
+
+ #: Dialup information (for automatic establishment of dialup connections)
+ self.dialup_info = dialup_info
+
+ #: Network mount information (for automatic remounting)
+ self.network_mount_info = network_mount_info
+
+ def __repr__(self):
+ args = ['name', 'creation_date', 'fs_type', 'disk_type',
+ 'attribute_flags', 'fs_id']
+ values = []
+ for a in args:
+ v = getattr(self, a)
+ values.append(repr(v))
+
+ kwargs = ['appleshare_info', 'driver_name', 'posix_path',
+ 'disk_image_alias', 'dialup_info', 'network_mount_info']
+ for a in kwargs:
+ v = getattr(self, a)
+ if v is not None:
+ values.append('%s=%r' % (a, v))
+ return 'VolumeInfo(%s)' % ','.join(values)
+
+class TargetInfo (object):
+ def __init__(self, kind, filename, folder_cnid, cnid, creation_date,
+ creator_code, type_code, levels_from=-1, levels_to=-1,
+ folder_name=None, cnid_path=None, carbon_path=None,
+ posix_path=None, user_home_prefix_len=None):
+ #: Either ALIAS_KIND_FILE or ALIAS_KIND_FOLDER
+ self.kind = kind
+
+ #: The filename of the target
+ self.filename = filename
+
+ #: The CNID (Catalog Node ID) of the target's containing folder;
+ #: CNIDs are similar to but different than traditional UNIX inode
+ #: numbers
+ self.folder_cnid = folder_cnid
+
+ #: The CNID (Catalog Node ID) of the target
+ self.cnid = cnid
+
+ #: The target's *creation* date.
+ self.creation_date = creation_date
+
+ #: The target's Mac creator code (a four-character binary string)
+ self.creator_code = creator_code
+
+ #: The target's Mac type code (a four-character binary string)
+ self.type_code = type_code
+
+ #: The depth of the alias? Always seems to be -1 on OS X.
+ self.levels_from = levels_from
+
+ #: The depth of the target? Always seems to be -1 on OS X.
+ self.levels_to = levels_to
+
+ #: The (POSIX) name of the target's containing folder. *(optional)*
+ self.folder_name = folder_name
+
+ #: The path from the volume root as a sequence of CNIDs. *(optional)*
+ self.cnid_path = cnid_path
+
+ #: The Carbon path of the target *(optional)*
+ self.carbon_path = carbon_path
+
+ #: The POSIX path of the target relative to the volume root. Note
+ #: that this may or may not have a leading '/' character, but it is
+ #: always relative to the containing volume. *(optional)*
+ self.posix_path = posix_path
+
+ #: If the path points into a user's home folder, the number of folders
+ #: deep that we go before we get to that home folder. *(optional)*
+ self.user_home_prefix_len = user_home_prefix_len
+
+ def __repr__(self):
+ args = ['kind', 'filename', 'folder_cnid', 'cnid', 'creation_date',
+ 'creator_code', 'type_code']
+ values = []
+ for a in args:
+ v = getattr(self, a)
+ values.append(repr(v))
+
+ if self.levels_from != -1:
+ values.append('levels_from=%r' % self.levels_from)
+ if self.levels_to != -1:
+ values.append('levels_to=%r' % self.levels_to)
+
+ kwargs = ['folder_name', 'cnid_path', 'carbon_path',
+ 'posix_path', 'user_home_prefix_len']
+ for a in kwargs:
+ v = getattr(self, a)
+ values.append('%s=%r' % (a, v))
+
+ return 'TargetInfo(%s)' % ','.join(values)
+
+TAG_CARBON_FOLDER_NAME = 0
+TAG_CNID_PATH = 1
+TAG_CARBON_PATH = 2
+TAG_APPLESHARE_ZONE = 3
+TAG_APPLESHARE_SERVER_NAME = 4
+TAG_APPLESHARE_USERNAME = 5
+TAG_DRIVER_NAME = 6
+TAG_NETWORK_MOUNT_INFO = 9
+TAG_DIALUP_INFO = 10
+TAG_UNICODE_FILENAME = 14
+TAG_UNICODE_VOLUME_NAME = 15
+TAG_HIGH_RES_VOLUME_CREATION_DATE = 16
+TAG_HIGH_RES_CREATION_DATE = 17
+TAG_POSIX_PATH = 18
+TAG_POSIX_PATH_TO_MOUNTPOINT = 19
+TAG_RECURSIVE_ALIAS_OF_DISK_IMAGE = 20
+TAG_USER_HOME_LENGTH_PREFIX = 21
+
+class Alias (object):
+ def __init__(self, appinfo=b'\0\0\0\0', version=2, volume=None,
+ target=None, extra=[]):
+ """Construct a new :class:`Alias` object with the specified
+ contents."""
+
+ #: Application specific information (four byte byte-string)
+ self.appinfo = appinfo
+
+ #: Version (we support only version 2)
+ self.version = version
+
+ #: A :class:`VolumeInfo` object describing the target's volume
+ self.volume = volume
+
+ #: A :class:`TargetInfo` object describing the target
+ self.target = target
+
+ #: A list of extra `(tag, value)` pairs
+ self.extra = list(extra)
+
+ @classmethod
+ def _from_fd(cls, b):
+ appinfo, recsize, version = struct.unpack(b'>4shh', b.read(8))
+
+ if recsize < 150:
+ raise ValueError('Incorrect alias length')
+
+ if version != 2:
+ raise ValueError('Unsupported alias version %u' % version)
+
+ kind, volname, voldate, fstype, disktype, \
+ folder_cnid, filename, cnid, crdate, creator_code, type_code, \
+ levels_from, levels_to, volattrs, volfsid, reserved = \
+ struct.unpack(b'>h28pI2shI64pII4s4shhI2s10s', b.read(142))
+
+ voldate = mac_epoch + datetime.timedelta(seconds=voldate)
+ crdate = mac_epoch + datetime.timedelta(seconds=crdate)
+
+ alias = Alias()
+ alias.appinfo = appinfo
+
+ alias.volume = VolumeInfo (volname.replace('/',':'),
+ voldate, fstype, disktype,
+ volattrs, volfsid)
+ alias.target = TargetInfo (kind, filename.replace('/',':'),
+ folder_cnid, cnid,
+ crdate, creator_code, type_code)
+ alias.target.levels_from = levels_from
+ alias.target.levels_to = levels_to
+
+ tag = struct.unpack(b'>h', b.read(2))[0]
+
+ while tag != -1:
+ length = struct.unpack(b'>h', b.read(2))[0]
+ value = b.read(length)
+ if length & 1:
+ b.read(1)
+
+ if tag == TAG_CARBON_FOLDER_NAME:
+ alias.target.folder_name = value.replace('/',':')
+ elif tag == TAG_CNID_PATH:
+ alias.target.cnid_path = struct.unpack(b'>%uI' % (length // 4),
+ value)
+ elif tag == TAG_CARBON_PATH:
+ alias.target.carbon_path = value
+ elif tag == TAG_APPLESHARE_ZONE:
+ if alias.volume.appleshare_info is None:
+ alias.volume.appleshare_info = AppleShareInfo()
+ alias.volume.appleshare_info.zone = value
+ elif tag == TAG_APPLESHARE_SERVER_NAME:
+ if alias.volume.appleshare_info is None:
+ alias.volume.appleshare_info = AppleShareInfo()
+ alias.volume.appleshare_info.server = value
+ elif tag == TAG_APPLESHARE_USERNAME:
+ if alias.volume.appleshare_info is None:
+ alias.volume.appleshare_info = AppleShareInfo()
+ alias.volume.appleshare_info.user = value
+ elif tag == TAG_DRIVER_NAME:
+ alias.volume.driver_name = value
+ elif tag == TAG_NETWORK_MOUNT_INFO:
+ alias.volume.network_mount_info = value
+ elif tag == TAG_DIALUP_INFO:
+ alias.volume.dialup_info = value
+ elif tag == TAG_UNICODE_FILENAME:
+ alias.target.filename = value[2:].decode('utf-16be')
+ elif tag == TAG_UNICODE_VOLUME_NAME:
+ alias.volume.name = value[2:].decode('utf-16be')
+ elif tag == TAG_HIGH_RES_VOLUME_CREATION_DATE:
+ seconds = struct.unpack(b'>Q', value)[0] / 65536.0
+ alias.volume.creation_date \
+ = mac_epoch + datetime.timedelta(seconds=seconds)
+ elif tag == TAG_HIGH_RES_CREATION_DATE:
+ seconds = struct.unpack(b'>Q', value)[0] / 65536.0
+ alias.target.creation_date \
+ = mac_epoch + datetime.timedelta(seconds=seconds)
+ elif tag == TAG_POSIX_PATH:
+ alias.target.posix_path = value
+ elif tag == TAG_POSIX_PATH_TO_MOUNTPOINT:
+ alias.volume.posix_path = value
+ elif tag == TAG_RECURSIVE_ALIAS_OF_DISK_IMAGE:
+ alias.volume.disk_image_alias = Alias.from_bytes(value)
+ elif tag == TAG_USER_HOME_LENGTH_PREFIX:
+ alias.target.user_home_prefix_len = struct.unpack(b'>h', value)[0]
+ else:
+ alias.extra.append((tag, value))
+
+ tag = struct.unpack(b'>h', b.read(2))[0]
+
+ return alias
+
+ @classmethod
+ def from_bytes(cls, bytes):
+ """Construct an :class:`Alias` object given binary Alias data."""
+ with io.BytesIO(bytes) as b:
+ return cls._from_fd(b)
+
+ @classmethod
+ def for_file(cls, path):
+ """Create an :class:`Alias` that points at the specified file."""
+ if sys.platform != 'darwin':
+ raise Exception('Not implemented (requires special support)')
+
+ a = Alias()
+
+ # Find the filesystem
+ st = osx.statfs(path)
+ vol_path = st.f_mntonname
+
+ # Grab its attributes
+ attrs = [osx.ATTR_CMN_CRTIME,
+ osx.ATTR_VOL_NAME,
+ 0, 0, 0]
+ volinfo = osx.getattrlist(vol_path, attrs, 0)
+
+ vol_crtime = volinfo[0]
+ vol_name = volinfo[1]
+
+ # Also grab various attributes of the file
+ attrs = [(osx.ATTR_CMN_OBJTYPE
+ | osx.ATTR_CMN_CRTIME
+ | osx.ATTR_CMN_FNDRINFO
+ | osx.ATTR_CMN_FILEID
+ | osx.ATTR_CMN_PARENTID), 0, 0, 0, 0]
+ info = osx.getattrlist(path, attrs, osx.FSOPT_NOFOLLOW)
+
+ if info[0] == osx.VDIR:
+ kind = ALIAS_KIND_FOLDER
+ else:
+ kind = ALIAS_KIND_FILE
+
+ cnid = info[3]
+ folder_cnid = info[4]
+
+ dirname, filename = os.path.split(path)
+
+ if dirname == '' or dirname == '.':
+ dirname = os.getcwd()
+
+ foldername = os.path.basename(dirname)
+
+ creation_date = info[1]
+
+ if kind == ALIAS_KIND_FILE:
+ creator_code = struct.pack(b'I', info[2].fileInfo.fileCreator)
+ type_code = struct.pack(b'I', info[2].fileInfo.fileType)
+ else:
+ creator_code = b'\0\0\0\0'
+ type_code = b'\0\0\0\0'
+
+ a.target = TargetInfo(kind, filename, folder_cnid, cnid, creation_date,
+ creator_code, type_code)
+ a.volume = VolumeInfo(vol_name, vol_crtime, b'H+',
+ ALIAS_FIXED_DISK, 0, b'\0\0')
+
+ a.target.folder_name = foldername
+ a.volume.posix_path = vol_path
+
+ rel_path = os.path.relpath(path, vol_path)
+
+ # Leave off the initial '/' if vol_path is '/' (no idea why)
+ if vol_path == '/':
+ a.target.posix_path = rel_path
+ else:
+ a.target.posix_path = '/' + rel_path
+
+ # Construct the Carbon and CNID paths
+ carbon_path = []
+ cnid_path = []
+ head, tail = os.path.split(rel_path)
+ if not tail:
+ head, tail = os.path.split(head)
+ while head or tail:
+ if head:
+ attrs = [osx.ATTR_CMN_FILEID, 0, 0, 0, 0]
+ info = osx.getattrlist(os.path.join(vol_path, head), attrs, 0)
+ cnid_path.append(info[0])
+ carbon_tail = tail.replace(':','/')
+ carbon_path.insert(0, carbon_tail)
+ head, tail = os.path.split(head)
+ carbon_path = vol_name + ':' + ':\0'.join(carbon_path)
+
+ a.target.carbon_path = carbon_path
+ a.target.cnid_path = cnid_path
+
+ return a
+
+ def _to_fd(self, b):
+ # We'll come back and fix the length when we're done
+ pos = b.tell()
+ b.write(struct.pack(b'>4shh', self.appinfo, 0, self.version))
+
+ carbon_volname = self.volume.name.replace(':','/').encode('utf-8')
+ carbon_filename = self.target.filename.replace(':','/').encode('utf-8')
+ voldate = (self.volume.creation_date - mac_epoch).total_seconds()
+ crdate = (self.target.creation_date - mac_epoch).total_seconds()
+
+ # NOTE: crdate should be in local time, but that's system dependent
+ # (so doing so is ridiculous, and nothing could rely on it).
+ b.write(struct.pack(b'>h28pI2shI64pII4s4shhI2s10s',
+ self.target.kind,
+ carbon_volname, voldate,
+ self.volume.fs_type,
+ self.volume.disk_type,
+ self.target.folder_cnid,
+ carbon_filename,
+ self.target.cnid,
+ crdate,
+ self.target.creator_code,
+ self.target.type_code,
+ self.target.levels_from,
+ self.target.levels_to,
+ self.volume.attribute_flags,
+ self.volume.fs_id,
+ b'\0'*10))
+
+ # Excuse the odd order; we're copying Finder
+ if self.target.folder_name:
+ carbon_foldername = self.target.folder_name.replace(':','/')\
+ .encode('utf-8')
+ b.write(struct.pack(b'>hh', TAG_CARBON_FOLDER_NAME,
+ len(carbon_foldername)))
+ b.write(carbon_foldername)
+ if len(carbon_foldername) & 1:
+ b.write(b'\0')
+
+ b.write(struct.pack(b'>hhQhhQ',
+ TAG_HIGH_RES_VOLUME_CREATION_DATE,
+ 8, long(voldate * 65536),
+ TAG_HIGH_RES_CREATION_DATE,
+ 8, long(crdate * 65536)))
+
+ if self.target.cnid_path:
+ cnid_path = struct.pack(b'>%uI' % len(self.target.cnid_path),
+ *self.target.cnid_path)
+ b.write(struct.pack(b'>hh', TAG_CNID_PATH,
+ len(cnid_path)))
+ b.write(cnid_path)
+
+ if self.target.carbon_path:
+ carbon_path=self.target.carbon_path.encode('utf-8')
+ b.write(struct.pack(b'>hh', TAG_CARBON_PATH,
+ len(carbon_path)))
+ b.write(carbon_path)
+ if len(carbon_path) & 1:
+ b.write(b'\0')
+
+ if self.volume.appleshare_info:
+ ai = self.volume.appleshare_info
+ if ai.zone:
+ b.write(struct.pack(b'>hh', TAG_APPLESHARE_ZONE,
+ len(ai.zone)))
+ b.write(ai.zone)
+ if len(ai.zone) & 1:
+ b.write(b'\0')
+ if ai.server:
+ b.write(struct.pack(b'>hh', TAG_APPLESHARE_SERVER_NAME,
+ len(ai.server)))
+ b.write(ai.server)
+ if len(ai.server) & 1:
+ b.write(b'\0')
+ if ai.username:
+ b.write(struct.pack(b'>hh', TAG_APPLESHARE_USERNAME,
+ len(ai.username)))
+ b.write(ai.username)
+ if len(ai.username) & 1:
+ b.write(b'\0')
+
+ if self.volume.driver_name:
+ driver_name = self.volume.driver_name.encode('utf-8')
+ b.write(struct.pack(b'>hh', TAG_DRIVER_NAME,
+ len(driver_name)))
+ b.write(driver_name)
+ if len(driver_name) & 1:
+ b.write(b'\0')
+
+ if self.volume.network_mount_info:
+ b.write(struct.pack(b'>hh', TAG_NETWORK_MOUNT_INFO,
+ len(self.volume.network_mount_info)))
+ b.write(self.volume.network_mount_info)
+ if len(self.volume.network_mount_info) & 1:
+ b.write(b'\0')
+
+ if self.volume.dialup_info:
+ b.write(struct.pack(b'>hh', TAG_DIALUP_INFO,
+ len(self.volume.network_mount_info)))
+ b.write(self.volume.network_mount_info)
+ if len(self.volume.network_mount_info) & 1:
+ b.write(b'\0')
+
+ utf16 = self.target.filename.replace(':','/').encode('utf-16-be')
+ b.write(struct.pack(b'>hhh', TAG_UNICODE_FILENAME,
+ len(utf16) + 2,
+ len(utf16) // 2))
+ b.write(utf16)
+
+ utf16 = self.volume.name.replace(':','/').encode('utf-16-be')
+ b.write(struct.pack(b'>hhh', TAG_UNICODE_VOLUME_NAME,
+ len(utf16) + 2,
+ len(utf16) // 2))
+ b.write(utf16)
+
+ if self.target.posix_path:
+ posix_path = self.target.posix_path.encode('utf-8')
+ b.write(struct.pack(b'>hh', TAG_POSIX_PATH,
+ len(posix_path)))
+ b.write(posix_path)
+ if len(posix_path) & 1:
+ b.write(b'\0')
+
+ if self.volume.posix_path:
+ posix_path = self.volume.posix_path.encode('utf-8')
+ b.write(struct.pack(b'>hh', TAG_POSIX_PATH_TO_MOUNTPOINT,
+ len(posix_path)))
+ b.write(posix_path)
+ if len(posix_path) & 1:
+ b.write(b'\0')
+
+ if self.volume.disk_image_alias:
+ d = self.volume.disk_image_alias.to_bytes()
+ b.write(struct.pack(b'>hh', TAG_RECURSIVE_ALIAS_OF_DISK_IMAGE,
+ len(d)))
+ b.write(d)
+ if len(d) & 1:
+ b.write(b'\0')
+
+ if self.target.user_home_prefix_len is not None:
+ b.write(struct.pack(b'>hhh', TAG_USER_HOME_LENGTH_PREFIX,
+ 2, self.target.user_home_prefix_len))
+
+ for t,v in self.extra:
+ b.write(struct.pack(b'>hh', t, len(v)))
+ b.write(v)
+ if len(v) & 1:
+ b.write(b'\0')
+
+ b.write(struct.pack(b'>hh', -1, 0))
+
+ blen = b.tell() - pos
+ b.seek(pos + 4, os.SEEK_SET)
+ b.write(struct.pack(b'>h', blen))
+
+ def to_bytes(self):
+ """Returns the binary representation for this :class:`Alias`."""
+ with io.BytesIO() as b:
+ self._to_fd(b)
+ return b.getvalue()
+
+ def __str__(self):
+ return '<Alias target=%s>' % self.target.filename
+
+ def __repr__(self):
+ values = []
+ if self.appinfo != b'\0\0\0\0':
+ values.append('appinfo=%r' % self.appinfo)
+ if self.version != 2:
+ values.append('version=%r' % self.version)
+ if self.volume is not None:
+ values.append('volume=%r' % self.volume)
+ if self.target is not None:
+ values.append('target=%r' % self.target)
+ if self.extra:
+ values.append('extra=%r' % self.extra)
+ return 'Alias(%s)' % ','.join(values)
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/bookmark.py b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/bookmark.py
new file mode 100644
index 000000000..41b9acf35
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/bookmark.py
@@ -0,0 +1,650 @@
+# -*- coding: utf-8 -*-
+#
+# This file implements the Apple "bookmark" format, which is the replacement
+# for the old-fashioned alias format. The details of this format were
+# reverse engineered; some things are still not entirely clear.
+#
+from __future__ import unicode_literals
+
+import struct
+import uuid
+import datetime
+import os
+import sys
+import pprint
+
+from urlparse import urljoin
+
+if sys.platform == 'darwin':
+ from . import osx
+
+from .utils import *
+
+BMK_DATA_TYPE_MASK = 0xffffff00
+BMK_DATA_SUBTYPE_MASK = 0x000000ff
+
+BMK_STRING = 0x0100
+BMK_DATA = 0x0200
+BMK_NUMBER = 0x0300
+BMK_DATE = 0x0400
+BMK_BOOLEAN = 0x0500
+BMK_ARRAY = 0x0600
+BMK_DICT = 0x0700
+BMK_UUID = 0x0800
+BMK_URL = 0x0900
+BMK_NULL = 0x0a00
+
+BMK_ST_ZERO = 0x0000
+BMK_ST_ONE = 0x0001
+
+BMK_BOOLEAN_ST_FALSE = 0x0000
+BMK_BOOLEAN_ST_TRUE = 0x0001
+
+# Subtypes for BMK_NUMBER are really CFNumberType values
+kCFNumberSInt8Type = 1
+kCFNumberSInt16Type = 2
+kCFNumberSInt32Type = 3
+kCFNumberSInt64Type = 4
+kCFNumberFloat32Type = 5
+kCFNumberFloat64Type = 6
+kCFNumberCharType = 7
+kCFNumberShortType = 8
+kCFNumberIntType = 9
+kCFNumberLongType = 10
+kCFNumberLongLongType = 11
+kCFNumberFloatType = 12
+kCFNumberDoubleType = 13
+kCFNumberCFIndexType = 14
+kCFNumberNSIntegerType = 15
+kCFNumberCGFloatType = 16
+
+# Resource property flags (from CFURLPriv.h)
+kCFURLResourceIsRegularFile = 0x00000001
+kCFURLResourceIsDirectory = 0x00000002
+kCFURLResourceIsSymbolicLink = 0x00000004
+kCFURLResourceIsVolume = 0x00000008
+kCFURLResourceIsPackage = 0x00000010
+kCFURLResourceIsSystemImmutable = 0x00000020
+kCFURLResourceIsUserImmutable = 0x00000040
+kCFURLResourceIsHidden = 0x00000080
+kCFURLResourceHasHiddenExtension = 0x00000100
+kCFURLResourceIsApplication = 0x00000200
+kCFURLResourceIsCompressed = 0x00000400
+kCFURLResourceIsSystemCompressed = 0x00000400
+kCFURLCanSetHiddenExtension = 0x00000800
+kCFURLResourceIsReadable = 0x00001000
+kCFURLResourceIsWriteable = 0x00002000
+kCFURLResourceIsExecutable = 0x00004000
+kCFURLIsAliasFile = 0x00008000
+kCFURLIsMountTrigger = 0x00010000
+
+# Volume property flags (from CFURLPriv.h)
+kCFURLVolumeIsLocal = 0x1 #
+kCFURLVolumeIsAutomount = 0x2 #
+kCFURLVolumeDontBrowse = 0x4 #
+kCFURLVolumeIsReadOnly = 0x8 #
+kCFURLVolumeIsQuarantined = 0x10
+kCFURLVolumeIsEjectable = 0x20 #
+kCFURLVolumeIsRemovable = 0x40 #
+kCFURLVolumeIsInternal = 0x80 #
+kCFURLVolumeIsExternal = 0x100 #
+kCFURLVolumeIsDiskImage = 0x200 #
+kCFURLVolumeIsFileVault = 0x400
+kCFURLVolumeIsLocaliDiskMirror = 0x800
+kCFURLVolumeIsiPod = 0x1000 #
+kCFURLVolumeIsiDisk = 0x2000
+kCFURLVolumeIsCD = 0x4000
+kCFURLVolumeIsDVD = 0x8000
+kCFURLVolumeIsDeviceFileSystem = 0x10000
+kCFURLVolumeSupportsPersistentIDs = 0x100000000
+kCFURLVolumeSupportsSearchFS = 0x200000000
+kCFURLVolumeSupportsExchange = 0x400000000
+# reserved 0x800000000
+kCFURLVolumeSupportsSymbolicLinks = 0x1000000000
+kCFURLVolumeSupportsDenyModes = 0x2000000000
+kCFURLVolumeSupportsCopyFile = 0x4000000000
+kCFURLVolumeSupportsReadDirAttr = 0x8000000000
+kCFURLVolumeSupportsJournaling = 0x10000000000
+kCFURLVolumeSupportsRename = 0x20000000000
+kCFURLVolumeSupportsFastStatFS = 0x40000000000
+kCFURLVolumeSupportsCaseSensitiveNames = 0x80000000000
+kCFURLVolumeSupportsCasePreservedNames = 0x100000000000
+kCFURLVolumeSupportsFLock = 0x200000000000
+kCFURLVolumeHasNoRootDirectoryTimes = 0x400000000000
+kCFURLVolumeSupportsExtendedSecurity = 0x800000000000
+kCFURLVolumeSupports2TBFileSize = 0x1000000000000
+kCFURLVolumeSupportsHardLinks = 0x2000000000000
+kCFURLVolumeSupportsMandatoryByteRangeLocks = 0x4000000000000
+kCFURLVolumeSupportsPathFromID = 0x8000000000000
+# reserved 0x10000000000000
+kCFURLVolumeIsJournaling = 0x20000000000000
+kCFURLVolumeSupportsSparseFiles = 0x40000000000000
+kCFURLVolumeSupportsZeroRuns = 0x80000000000000
+kCFURLVolumeSupportsVolumeSizes = 0x100000000000000
+kCFURLVolumeSupportsRemoteEvents = 0x200000000000000
+kCFURLVolumeSupportsHiddenFiles = 0x400000000000000
+kCFURLVolumeSupportsDecmpFSCompression = 0x800000000000000
+kCFURLVolumeHas64BitObjectIDs = 0x1000000000000000
+kCFURLVolumePropertyFlagsAll = 0xffffffffffffffff
+
+BMK_URL_ST_ABSOLUTE = 0x0001
+BMK_URL_ST_RELATIVE = 0x0002
+
+# Bookmark keys
+# = 0x1003
+kBookmarkPath = 0x1004 # Array of path components
+kBookmarkCNIDPath = 0x1005 # Array of CNIDs
+kBookmarkFileProperties = 0x1010 # (CFURL rp flags,
+ # CFURL rp flags asked for,
+ # 8 bytes NULL)
+kBookmarkFileName = 0x1020
+kBookmarkFileID = 0x1030
+kBookmarkFileCreationDate = 0x1040
+# = 0x1054 # ?
+# = 0x1055 # ?
+# = 0x1056 # ?
+# = 0x1101 # ?
+# = 0x1102 # ?
+kBookmarkTOCPath = 0x2000 # A list of (TOC id, ?) pairs
+kBookmarkVolumePath = 0x2002
+kBookmarkVolumeURL = 0x2005
+kBookmarkVolumeName = 0x2010
+kBookmarkVolumeUUID = 0x2011 # Stored (perversely) as a string
+kBookmarkVolumeSize = 0x2012
+kBookmarkVolumeCreationDate = 0x2013
+kBookmarkVolumeProperties = 0x2020 # (CFURL vp flags,
+ # CFURL vp flags asked for,
+ # 8 bytes NULL)
+kBookmarkVolumeIsRoot = 0x2030 # True if volume is FS root
+kBookmarkVolumeBookmark = 0x2040 # Embedded bookmark for disk image (TOC id)
+kBookmarkVolumeMountPoint = 0x2050 # A URL
+# = 0x2070
+kBookmarkContainingFolder = 0xc001 # Index of containing folder in path
+kBookmarkUserName = 0xc011 # User that created bookmark
+kBookmarkUID = 0xc012 # UID that created bookmark
+kBookmarkWasFileReference = 0xd001 # True if the URL was a file reference
+kBookmarkCreationOptions = 0xd010
+kBookmarkURLLengths = 0xe003 # See below
+# = 0xf017 # Localized name?
+# = 0xf022
+kBookmarkSecurityExtension = 0xf080
+# = 0xf081
+
+# kBookmarkURLLengths is an array that is set if the URL encoded by the
+# bookmark had a base URL; in that case, each entry is the length of the
+# base URL in question. Thus a URL
+#
+# file:///foo/bar/baz blam/blat.html
+#
+# will result in [3, 2], while the URL
+#
+# file:///foo bar/baz blam blat.html
+#
+# would result in [1, 2, 1, 1]
+
+
+class Data (object):
+ def __init__(self, bytedata=None):
+ #: The bytes, stored as a byte string
+ self.bytes = bytes(bytedata)
+
+ def __repr__(self):
+ return 'Data(%r)' % self.bytes
+
+class URL (object):
+ def __init__(self, base, rel=None):
+ if rel is not None:
+ #: The base URL, if any (a :class:`URL`)
+ self.base = base
+ #: The rest of the URL (a string)
+ self.relative = rel
+ else:
+ self.base = None
+ self.relative = base
+
+ @property
+ def absolute(self):
+ """Return an absolute URL."""
+ if self.base is None:
+ return self.relative
+ else:
+ base_abs = self.base.absolute
+ return urljoin(self.base.absolute, self.relative)
+
+ def __repr__(self):
+ return 'URL(%r)' % self.absolute
+
+class Bookmark (object):
+ def __init__(self, tocs=None):
+ if tocs is None:
+ #: The TOCs for this Bookmark
+ self.tocs = []
+ else:
+ self.tocs = tocs
+
+ @classmethod
+ def _get_item(cls, data, hdrsize, offset):
+ offset += hdrsize
+ if offset > len(data) - 8:
+ raise ValueError('Offset out of range')
+
+ length,typecode = struct.unpack(b'<II', data[offset:offset+8])
+
+ if len(data) - offset < 8 + length:
+ raise ValueError('Data item truncated')
+
+ databytes = data[offset+8:offset+8+length]
+
+ dsubtype = typecode & BMK_DATA_SUBTYPE_MASK
+ dtype = typecode & BMK_DATA_TYPE_MASK
+
+ if dtype == BMK_STRING:
+ return databytes.decode('utf-8')
+ elif dtype == BMK_DATA:
+ return Data(databytes)
+ elif dtype == BMK_NUMBER:
+ if dsubtype == kCFNumberSInt8Type:
+ return ord(databytes[0])
+ elif dsubtype == kCFNumberSInt16Type:
+ return struct.unpack(b'<h', databytes)[0]
+ elif dsubtype == kCFNumberSInt32Type:
+ return struct.unpack(b'<i', databytes)[0]
+ elif dsubtype == kCFNumberSInt64Type:
+ return struct.unpack(b'<q', databytes)[0]
+ elif dsubtype == kCFNumberFloat32Type:
+ return struct.unpack(b'<f', databytes)[0]
+ elif dsubtype == kCFNumberFloat64Type:
+ return struct.unpack(b'<d', databytes)[0]
+ elif dtype == BMK_DATE:
+ # Yes, dates really are stored as *BIG-endian* doubles; everything
+ # else is little-endian
+ secs = datetime.timedelta(seconds=struct.unpack(b'>d', databytes)[0])
+ return osx_epoch + secs
+ elif dtype == BMK_BOOLEAN:
+ if dsubtype == BMK_BOOLEAN_ST_TRUE:
+ return True
+ elif dsubtype == BMK_BOOLEAN_ST_FALSE:
+ return False
+ elif dtype == BMK_UUID:
+ return uuid.UUID(bytes=databytes)
+ elif dtype == BMK_URL:
+ if dsubtype == BMK_URL_ST_ABSOLUTE:
+ return URL(databytes.decode('utf-8'))
+ elif dsubtype == BMK_URL_ST_RELATIVE:
+ baseoff,reloff = struct.unpack(b'<II', databytes)
+ base = cls._get_item(data, hdrsize, baseoff)
+ rel = cls._get_item(data, hdrsize, reloff)
+ return URL(base, rel)
+ elif dtype == BMK_ARRAY:
+ result = []
+ for aoff in xrange(offset+8,offset+8+length,4):
+ eltoff, = struct.unpack(b'<I', data[aoff:aoff+4])
+ result.append(cls._get_item(data, hdrsize, eltoff))
+ return result
+ elif dtype == BMK_DICT:
+ result = {}
+ for eoff in xrange(offset+8,offset+8+length,8):
+ keyoff,valoff = struct.unpack(b'<II', data[eoff:eoff+8])
+ key = cls._get_item(data, hdrsize, keyoff)
+ val = cls._get_item(data, hdrsize, valoff)
+ result[key] = val
+ return result
+ elif dtype == BMK_NULL:
+ return None
+
+ print 'Unknown data type %08x' % typecode
+ return (typecode, databytes)
+
+ @classmethod
+ def from_bytes(cls, data):
+ """Create a :class:`Bookmark` given byte data."""
+
+ if isinstance(data, bytearray):
+ data = bytes(data)
+
+ if len(data) < 16:
+ raise ValueError('Not a bookmark file (too short)')
+
+ magic,size,dummy,hdrsize = struct.unpack(b'<4sIII', data[0:16])
+
+ if magic != 'book':
+ raise ValueError('Not a bookmark file (bad magic)')
+
+ if hdrsize < 16:
+ raise ValueError('Not a bookmark file (header size too short)')
+
+ if hdrsize > size:
+ raise ValueError('Not a bookmark file (header size too large)')
+
+ if size != len(data):
+ raise ValueError('Not a bookmark file (truncated)')
+
+ tocoffset, = struct.unpack(b'<I', data[hdrsize:hdrsize+4])
+
+ tocs = []
+
+ while tocoffset != 0:
+ tocbase = hdrsize + tocoffset
+ if tocoffset > size - hdrsize \
+ or size - tocbase < 20:
+ raise ValueError('TOC offset out of range')
+
+ tocsize,tocmagic,tocid,nexttoc,toccount \
+ = struct.unpack(b'<IIIII',
+ data[tocbase:tocbase+20])
+
+ if tocmagic != 0xfffffffe:
+ break
+
+ tocsize += 8
+
+ if size - tocbase < tocsize:
+ raise ValueError('TOC truncated')
+
+ if tocsize < 12 * toccount:
+ raise ValueError('TOC entries overrun TOC size')
+
+ toc = {}
+ for n in xrange(0,toccount):
+ ebase = tocbase + 20 + 12 * n
+ eid,eoffset,edummy = struct.unpack(b'<III',
+ data[ebase:ebase+12])
+
+ if eid & 0x80000000:
+ eid = cls._get_item(data, hdrsize, eid & 0x7fffffff)
+
+ toc[eid] = cls._get_item(data, hdrsize, eoffset)
+
+ tocs.append((tocid, toc))
+
+ tocoffset = nexttoc
+
+ return cls(tocs)
+
+ def __getitem__(self, key):
+ for tid,toc in self.tocs:
+ if key in toc:
+ return toc[key]
+ raise KeyError('Key not found')
+
+ def __setitem__(self, key, value):
+ if len(self.tocs) == 0:
+ self.tocs = [(1, {})]
+ self.tocs[0][1][key] = value
+
+ def get(self, key, default=None):
+ """Lookup the value for a given key, returning a default if not
+ present."""
+ for tid,toc in self.tocs:
+ if key in toc:
+ return toc[key]
+ return default
+
+ @classmethod
+ def _encode_item(cls, item, offset):
+ if item is True:
+ result = struct.pack(b'<II', 0, BMK_BOOLEAN | BMK_BOOLEAN_ST_TRUE)
+ elif item is False:
+ result = struct.pack(b'<II', 0, BMK_BOOLEAN | BMK_BOOLEAN_ST_FALSE)
+ elif isinstance(item, unicode):
+ encoded = item.encode('utf-8')
+ result = (struct.pack(b'<II', len(encoded), BMK_STRING | BMK_ST_ONE)
+ + encoded)
+ elif isinstance(item, bytes):
+ result = (struct.pack(b'<II', len(item), BMK_STRING | BMK_ST_ONE)
+ + item)
+ elif isinstance(item, Data):
+ result = (struct.pack(b'<II', len(item.bytes),
+ BMK_DATA | BMK_ST_ONE)
+ + bytes(item.bytes))
+ elif isinstance(item, bytearray):
+ result = (struct.pack(b'<II', len(item),
+ BMK_DATA | BMK_ST_ONE)
+ + bytes(item))
+ elif isinstance(item, int) or isinstance(item, long):
+ if item > -0x80000000 and item < 0x7fffffff:
+ result = struct.pack(b'<IIi', 4,
+ BMK_NUMBER | kCFNumberSInt32Type, item)
+ else:
+ result = struct.pack(b'<IIq', 8,
+ BMK_NUMBER | kCFNumberSInt64Type, item)
+ elif isinstance(item, float):
+ result = struct.pack(b'<IId', 8,
+ BMK_NUMBER | kCFNumberFloat64Type, item)
+ elif isinstance(item, datetime.datetime):
+ secs = item - osx_epoch
+ result = struct.pack(b'<II', 8, BMK_DATE | BMK_ST_ZERO) \
+ + struct.pack(b'>d', float(secs.total_seconds()))
+ elif isinstance(item, uuid.UUID):
+ result = struct.pack(b'<II', 16, BMK_UUID | BMK_ST_ONE) \
+ + item.bytes
+ elif isinstance(item, URL):
+ if item.base:
+ baseoff = offset + 16
+ reloff, baseenc = cls._encode_item(item.base, baseoff)
+ xoffset, relenc = cls._encode_item(item.relative, reloff)
+ result = b''.join([
+ struct.pack(b'<IIII', 8, BMK_URL | BMK_URL_ST_RELATIVE,
+ baseoff, reloff),
+ baseenc,
+ relenc])
+ else:
+ encoded = item.relative.encode('utf-8')
+ result = struct.pack(b'<II', len(encoded),
+ BMK_URL | BMK_URL_ST_ABSOLUTE) + encoded
+ elif isinstance(item, list):
+ ioffset = offset + 8 + len(item) * 4
+ result = [struct.pack(b'<II', len(item) * 4, BMK_ARRAY | BMK_ST_ONE)]
+ enc = []
+ for elt in item:
+ result.append(struct.pack(b'<I', ioffset))
+ ioffset, ienc = cls._encode_item(elt, ioffset)
+ enc.append(ienc)
+ result = b''.join(result + enc)
+ elif isinstance(item, dict):
+ ioffset = offset + 8 + len(item) * 8
+ result = [struct.pack(b'<II', len(item) * 8, BMK_DICT | BMK_ST_ONE)]
+ enc = []
+ for k,v in item.iteritems():
+ result.append(struct.pack(b'<I', ioffset))
+ ioffset, ienc = cls._encode_item(k, ioffset)
+ enc.append(ienc)
+ result.append(struct.pack(b'<I', ioffset))
+ ioffset, ienc = cls._encode_item(v, ioffset)
+ enc.append(ienc)
+ result = b''.join(result + enc)
+ elif item is None:
+ result = struct.pack(b'<II', 0, BMK_NULL | BMK_ST_ONE)
+ else:
+ raise ValueError('Unknown item type when encoding: %s' % item)
+
+ offset += len(result)
+
+ # Pad to a multiple of 4 bytes
+ if offset & 3:
+ extra = 4 - (offset & 3)
+ result += b'\0' * extra
+ offset += extra
+
+ return (offset, result)
+
+ def to_bytes(self):
+ """Convert this :class:`Bookmark` to a byte representation."""
+
+ result = []
+ tocs = []
+ offset = 4 # For the offset to the first TOC
+
+ # Generate the data and build the TOCs
+ for tid,toc in self.tocs:
+ entries = []
+
+ for k,v in toc.iteritems():
+ if isinstance(k, basestring):
+ noffset = offset
+ voffset, enc = self._encode_item(k, offset)
+ result.append(enc)
+ offset, enc = self._encode_item(v, voffset)
+ result.append(enc)
+ entries.append((noffset | 0x80000000, voffset))
+ else:
+ entries.append((k, offset))
+ offset, enc = self._encode_item(v, offset)
+ result.append(enc)
+
+ # TOC entries must be sorted - CoreServicesInternal does a
+ # binary search to find data
+ entries.sort()
+
+ tocs.append((tid, b''.join([struct.pack(b'<III',k,o,0)
+ for k,o in entries])))
+
+ first_toc_offset = offset
+
+ # Now generate the TOC headers
+ for ndx,toc in enumerate(tocs):
+ tid, data = toc
+ if ndx == len(tocs) - 1:
+ next_offset = 0
+ else:
+ next_offset = offset + 20 + len(data)
+
+ result.append(struct.pack(b'<IIIII', len(data) - 8,
+ 0xfffffffe,
+ tid,
+ next_offset,
+ len(data) / 12))
+ result.append(data)
+
+ offset += 20 + len(data)
+
+ # Finally, add the header (and the first TOC offset, which isn't part
+ # of the header, but goes just after it)
+ header = struct.pack(b'<4sIIIQQQQI', b'book',
+ offset + 48,
+ 0x10040000,
+ 48,
+ 0, 0, 0, 0, first_toc_offset)
+
+ result.insert(0, header)
+
+ return b''.join(result)
+
+ @classmethod
+ def for_file(cls, path):
+ """Construct a :class:`Bookmark` for a given file."""
+
+ # Find the filesystem
+ st = osx.statfs(path)
+ vol_path = st.f_mntonname
+
+ # Grab its attributes
+ attrs = [osx.ATTR_CMN_CRTIME,
+ osx.ATTR_VOL_SIZE
+ | osx.ATTR_VOL_NAME
+ | osx.ATTR_VOL_UUID,
+ 0, 0, 0]
+ volinfo = osx.getattrlist(vol_path, attrs, 0)
+
+ vol_crtime = volinfo[0]
+ vol_size = volinfo[1]
+ vol_name = volinfo[2]
+ vol_uuid = volinfo[3]
+
+ # Also grab various attributes of the file
+ attrs = [(osx.ATTR_CMN_OBJTYPE
+ | osx.ATTR_CMN_CRTIME
+ | osx.ATTR_CMN_FILEID), 0, 0, 0, 0]
+ info = osx.getattrlist(path, attrs, osx.FSOPT_NOFOLLOW)
+
+ cnid = info[2]
+ crtime = info[1]
+
+ if info[0] == osx.VREG:
+ flags = kCFURLResourceIsRegularFile
+ elif info[0] == osx.VDIR:
+ flags = kCFURLResourceIsDirectory
+ elif info[0] == osx.VLNK:
+ flags = kCFURLResourceIsSymbolicLink
+ else:
+ flags = kCFURLResourceIsRegularFile
+
+ dirname, filename = os.path.split(path)
+
+ relcount = 0
+ if not os.path.isabs(dirname):
+ curdir = os.getcwd()
+ head, tail = os.path.split(curdir)
+ relcount = 0
+ while head and tail:
+ relcount += 1
+ head, tail = os.path.split(head)
+ dirname = os.path.join(curdir, dirname)
+
+ foldername = os.path.basename(dirname)
+
+ rel_path = os.path.relpath(path, vol_path)
+
+ # Build the path arrays
+ name_path = []
+ cnid_path = []
+ head, tail = os.path.split(rel_path)
+ if not tail:
+ head, tail = os.path.split(head)
+ while head or tail:
+ if head:
+ attrs = [osx.ATTR_CMN_FILEID, 0, 0, 0, 0]
+ info = osx.getattrlist(os.path.join(vol_path, head), attrs, 0)
+ cnid_path.insert(0, info[0])
+ head, tail = os.path.split(head)
+ name_path.insert(0, tail)
+ else:
+ head, tail = os.path.split(head)
+ name_path.append(filename)
+ cnid_path.append(cnid)
+
+ url_lengths = [relcount, len(name_path) - relcount]
+
+ fileprops = Data(struct.pack(b'<QQQ', flags, 0x0f, 0))
+ volprops = Data(struct.pack(b'<QQQ', 0x81 | kCFURLVolumeSupportsPersistentIDs,
+ 0x13ef | kCFURLVolumeSupportsPersistentIDs, 0))
+
+ toc = {
+ kBookmarkPath: name_path,
+ kBookmarkCNIDPath: cnid_path,
+ kBookmarkFileCreationDate: crtime,
+ kBookmarkFileProperties: fileprops,
+ kBookmarkContainingFolder: len(name_path) - 2,
+ kBookmarkVolumePath: vol_path,
+ kBookmarkVolumeIsRoot: vol_path == '/',
+ kBookmarkVolumeURL: URL('file://' + vol_path),
+ kBookmarkVolumeName: vol_name,
+ kBookmarkVolumeSize: vol_size,
+ kBookmarkVolumeCreationDate: vol_crtime,
+ kBookmarkVolumeUUID: str(vol_uuid).upper(),
+ kBookmarkVolumeProperties: volprops,
+ kBookmarkCreationOptions: 512,
+ kBookmarkWasFileReference: True,
+ kBookmarkUserName: 'unknown',
+ kBookmarkUID: 99,
+ }
+
+ if relcount:
+ toc[kBookmarkURLLengths] = url_lengths
+
+ return Bookmark([(1, toc)])
+
+ def __repr__(self):
+ result = ['Bookmark([']
+ for tid,toc in self.tocs:
+ result.append('(0x%x, {\n' % tid)
+ for k,v in toc.iteritems():
+ if isinstance(k, basestring):
+ kf = repr(k)
+ else:
+ kf = '0x%04x' % k
+ result.append(' %s: %r\n' % (kf, v))
+ result.append('}),\n')
+ result.append('])')
+
+ return ''.join(result)
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/osx.py b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/osx.py
new file mode 100644
index 000000000..bdd5d09e9
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/osx.py
@@ -0,0 +1,823 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from ctypes import *
+import struct
+import os
+import datetime
+import uuid
+
+from .utils import *
+
+libc = cdll.LoadLibrary('/usr/lib/libc.dylib')
+
+# Constants
+FSOPT_NOFOLLOW = 0x00000001
+FSOPT_NOINMEMUPDATE = 0x00000002
+FSOPT_REPORT_FULLSIZE = 0x00000004
+FSOPT_PACK_INVAL_ATTRS = 0x00000008
+
+VOL_CAPABILITIES_FORMAT = 0
+VOL_CAPABILITIES_INTERFACES = 1
+
+VOL_CAP_FMT_PERSISTENTOBJECTIDS = 0x00000001
+VOL_CAP_FMT_SYMBOLICLINKS = 0x00000002
+VOL_CAP_FMT_HARDLINKS = 0x00000004
+VOL_CAP_FMT_JOURNAL = 0x00000008
+VOL_CAP_FMT_JOURNAL_ACTIVE = 0x00000010
+VOL_CAP_FMT_NO_ROOT_TIMES = 0x00000020
+VOL_CAP_FMT_SPARSE_FILES = 0x00000040
+VOL_CAP_FMT_ZERO_RUNS = 0x00000080
+VOL_CAP_FMT_CASE_SENSITIVE = 0x00000100
+VOL_CAP_FMT_CASE_PRESERVING = 0x00000200
+VOL_CAP_FMT_FAST_STATFS = 0x00000400
+VOL_CAP_FMT_2TB_FILESIZE = 0x00000800
+VOL_CAP_FMT_OPENDENYMODES = 0x00001000
+VOL_CAP_FMT_HIDDEN_FILES = 0x00002000
+VOL_CAP_FMT_PATH_FROM_ID = 0x00004000
+VOL_CAP_FMT_NO_VOLUME_SIZES = 0x00008000
+VOL_CAP_FMT_DECMPFS_COMPRESSION = 0x00010000
+VOL_CAP_FMT_64BIT_OBJECT_IDS = 0x00020000
+
+VOL_CAP_INT_SEARCHFS = 0x00000001
+VOL_CAP_INT_ATTRLIST = 0x00000002
+VOL_CAP_INT_NFSEXPORT = 0x00000004
+VOL_CAP_INT_READDIRATTR = 0x00000008
+VOL_CAP_INT_EXCHANGEDATA = 0x00000010
+VOL_CAP_INT_COPYFILE = 0x00000020
+VOL_CAP_INT_ALLOCATE = 0x00000040
+VOL_CAP_INT_VOL_RENAME = 0x00000080
+VOL_CAP_INT_ADVLOCK = 0x00000100
+VOL_CAP_INT_FLOCK = 0x00000200
+VOL_CAP_INT_EXTENDED_SECURITY = 0x00000400
+VOL_CAP_INT_USERACCESS = 0x00000800
+VOL_CAP_INT_MANLOCK = 0x00001000
+VOL_CAP_INT_NAMEDSTREAMS = 0x00002000
+VOL_CAP_INT_EXTENDED_ATTR = 0x00004000
+
+ATTR_CMN_NAME = 0x00000001
+ATTR_CMN_DEVID = 0x00000002
+ATTR_CMN_FSID = 0x00000004
+ATTR_CMN_OBJTYPE = 0x00000008
+ATTR_CMN_OBJTAG = 0x00000010
+ATTR_CMN_OBJID = 0x00000020
+ATTR_CMN_OBJPERMANENTID = 0x00000040
+ATTR_CMN_PAROBJID = 0x00000080
+ATTR_CMN_SCRIPT = 0x00000100
+ATTR_CMN_CRTIME = 0x00000200
+ATTR_CMN_MODTIME = 0x00000400
+ATTR_CMN_CHGTIME = 0x00000800
+ATTR_CMN_ACCTIME = 0x00001000
+ATTR_CMN_BKUPTIME = 0x00002000
+ATTR_CMN_FNDRINFO = 0x00004000
+ATTR_CMN_OWNERID = 0x00008000
+ATTR_CMN_GRPID = 0x00010000
+ATTR_CMN_ACCESSMASK = 0x00020000
+ATTR_CMN_FLAGS = 0x00040000
+ATTR_CMN_USERACCESS = 0x00200000
+ATTR_CMN_EXTENDED_SECURITY = 0x00400000
+ATTR_CMN_UUID = 0x00800000
+ATTR_CMN_GRPUUID = 0x01000000
+ATTR_CMN_FILEID = 0x02000000
+ATTR_CMN_PARENTID = 0x04000000
+ATTR_CMN_FULLPATH = 0x08000000
+ATTR_CMN_ADDEDTIME = 0x10000000
+ATTR_CMN_RETURNED_ATTRS = 0x80000000
+ATTR_CMN_ALL_ATTRS = 0x9fe7ffff
+
+ATTR_VOL_FSTYPE = 0x00000001
+ATTR_VOL_SIGNATURE = 0x00000002
+ATTR_VOL_SIZE = 0x00000004
+ATTR_VOL_SPACEFREE = 0x00000008
+ATTR_VOL_SPACEAVAIL = 0x00000010
+ATTR_VOL_MINALLOCATION = 0x00000020
+ATTR_VOL_ALLOCATIONCLUMP = 0x00000040
+ATTR_VOL_IOBLOCKSIZE = 0x00000080
+ATTR_VOL_OBJCOUNT = 0x00000100
+ATTR_VOL_FILECOUNT = 0x00000200
+ATTR_VOL_DIRCOUNT = 0x00000400
+ATTR_VOL_MAXOBJCOUNT = 0x00000800
+ATTR_VOL_MOUNTPOINT = 0x00001000
+ATTR_VOL_NAME = 0x00002000
+ATTR_VOL_MOUNTFLAGS = 0x00004000
+ATTR_VOL_MOUNTEDDEVICE = 0x00008000
+ATTR_VOL_ENCODINGSUSED = 0x00010000
+ATTR_VOL_CAPABILITIES = 0x00020000
+ATTR_VOL_UUID = 0x00040000
+ATTR_VOL_ATTRIBUTES = 0x40000000
+ATTR_VOL_INFO = 0x80000000
+ATTR_VOL_ALL_ATTRS = 0xc007ffff
+
+ATTR_DIR_LINKCOUNT = 0x00000001
+ATTR_DIR_ENTRYCOUNT = 0x00000002
+ATTR_DIR_MOUNTSTATUS = 0x00000004
+DIR_MNTSTATUS_MNTPOINT = 0x00000001
+DIR_MNTSTATUS_TRIGGER = 0x00000002
+ATTR_DIR_ALL_ATTRS = 0x00000007
+
+ATTR_FILE_LINKCOUNT = 0x00000001
+ATTR_FILE_TOTALSIZE = 0x00000002
+ATTR_FILE_ALLOCSIZE = 0x00000004
+ATTR_FILE_IOBLOCKSIZE = 0x00000008
+ATTR_FILE_DEVTYPE = 0x00000020
+ATTR_FILE_DATALENGTH = 0x00000200
+ATTR_FILE_DATAALLOCSIZE = 0x00000400
+ATTR_FILE_RSRCLENGTH = 0x00001000
+ATTR_FILE_RSRCALLOCSIZE = 0x00002000
+
+ATTR_FILE_ALL_ATTRS = 0x0000362f
+
+ATTR_FORK_TOTALSIZE = 0x00000001
+ATTR_FORK_ALLOCSIZE = 0x00000002
+ATTR_FORK_ALL_ATTRS = 0x00000003
+
+# These can't be used
+ATTR_FILE_FORKCOUNT = 0x00000080
+ATTR_FILE_FORKLIST = 0x00000100
+ATTR_CMN_NAMEDATTRCOUNT = 0x00080000
+ATTR_CMN_NAMEDATTRLIST = 0x00100000
+ATTR_FILE_DATAEXTENTS = 0x00000800
+ATTR_FILE_RSRCEXTENTS = 0x00004000
+ATTR_FILE_CLUMPSIZE = 0x00000010
+ATTR_FILE_FILETYPE = 0x00000040
+
+class attrlist(Structure):
+ _fields_ = [('bitmapcount', c_ushort),
+ ('reserved', c_ushort),
+ ('commonattr', c_uint),
+ ('volattr', c_uint),
+ ('dirattr', c_uint),
+ ('fileattr', c_uint),
+ ('forkattr', c_uint)]
+
+class attribute_set_t(Structure):
+ _fields_ = [('commonattr', c_uint),
+ ('volattr', c_uint),
+ ('dirattr', c_uint),
+ ('fileattr', c_uint),
+ ('forkattr', c_uint)]
+
+class fsobj_id_t(Structure):
+ _fields_ = [('fid_objno', c_uint),
+ ('fid_generation', c_uint)]
+
+class timespec(Structure):
+ _fields_ = [('tv_sec', c_long),
+ ('tv_nsec', c_long)]
+
+class attrreference_t(Structure):
+ _fields_ = [('attr_dataoffset', c_int),
+ ('attr_length', c_uint)]
+
+class fsid_t(Structure):
+ _fields_ = [('val', c_uint * 2)]
+
+class guid_t(Structure):
+ _fields_ = [('g_guid', c_byte*16)]
+
+class kauth_ace(Structure):
+ _fields_ = [('ace_applicable', guid_t),
+ ('ace_flags', c_uint)]
+
+class kauth_acl(Structure):
+ _fields_ = [('acl_entrycount', c_uint),
+ ('acl_flags', c_uint),
+ ('acl_ace', kauth_ace * 128)]
+
+class kauth_filesec(Structure):
+ _fields_ = [('fsec_magic', c_uint),
+ ('fsec_owner', guid_t),
+ ('fsec_group', guid_t),
+ ('fsec_acl', kauth_acl)]
+
+class diskextent(Structure):
+ _fields_ = [('startblock', c_uint),
+ ('blockcount', c_uint)]
+
+OSType = c_uint
+UInt16 = c_ushort
+SInt16 = c_short
+SInt32 = c_int
+
+class Point(Structure):
+ _fields_ = [('x', SInt16),
+ ('y', SInt16)]
+class Rect(Structure):
+ _fields_ = [('x', SInt16),
+ ('y', SInt16),
+ ('w', SInt16),
+ ('h', SInt16)]
+class FileInfo(Structure):
+ _fields_ = [('fileType', OSType),
+ ('fileCreator', OSType),
+ ('finderFlags', UInt16),
+ ('location', Point),
+ ('reservedField', UInt16),
+ ('reserved1', SInt16 * 4),
+ ('extendedFinderFlags', UInt16),
+ ('reserved2', SInt16),
+ ('putAwayFolderID', SInt32)]
+class FolderInfo(Structure):
+ _fields_ = [('windowBounds', Rect),
+ ('finderFlags', UInt16),
+ ('location', Point),
+ ('reservedField', UInt16),
+ ('scrollPosition', Point),
+ ('reserved1', SInt32),
+ ('extendedFinderFlags', UInt16),
+ ('reserved2', SInt16),
+ ('putAwayFolderID', SInt32)]
+class FinderInfo(Union):
+ _fields_ = [('fileInfo', FileInfo),
+ ('folderInfo', FolderInfo)]
+
+extentrecord = diskextent * 8
+
+vol_capabilities_set_t = c_uint * 4
+
+class vol_capabilities_attr_t(Structure):
+ _fields_ = [('capabilities', vol_capabilities_set_t),
+ ('valid', vol_capabilities_set_t)]
+
+class vol_attributes_attr_t(Structure):
+ _fields_ = [('validattr', attribute_set_t),
+ ('nativeattr', attribute_set_t)]
+
+dev_t = c_uint
+
+fsobj_type_t = c_uint
+
+VNON = 0
+VREG = 1
+VDIR = 2
+VBLK = 3
+VCHR = 4
+VLNK = 5
+VSOCK = 6
+VFIFO = 7
+VBAD = 8
+VSTR = 9
+VCPLX = 10
+
+fsobj_tag_t = c_uint
+
+VT_NON = 0
+VT_UFS = 1
+VT_NFS = 2
+VT_MFS = 3
+VT_MSDOSFS = 4
+VT_LFS = 5
+VT_LOFS = 6
+VT_FDESC = 7
+VT_PORTAL = 8
+VT_NULL = 9
+VT_UMAP = 10
+VT_KERNFS = 11
+VT_PROCFS = 12
+VT_AFS = 13
+VT_ISOFS = 14
+VT_UNION = 15
+VT_HFS = 16
+VT_ZFS = 17
+VT_DEVFS = 18
+VT_WEBDAV = 19
+VT_UDF = 20
+VT_AFP = 21
+VT_CDDA = 22
+VT_CIFS = 23
+VT_OTHER = 24
+
+fsfile_type_t = c_uint
+fsvolid_t = c_uint
+text_encoding_t = c_uint
+uid_t = c_uint
+gid_t = c_uint
+int32_t = c_int
+uint32_t = c_uint
+int64_t = c_longlong
+uint64_t = c_ulonglong
+off_t = c_long
+size_t = c_ulong
+uuid_t = c_byte*16
+
+NAME_MAX = 255
+PATH_MAX = 1024
+
+class struct_statfs(Structure):
+ _fields_ = [('f_bsize', uint32_t),
+ ('f_iosize', int32_t),
+ ('f_blocks', uint64_t),
+ ('f_bfree', uint64_t),
+ ('f_bavail', uint64_t),
+ ('f_files', uint64_t),
+ ('f_ffree', uint64_t),
+ ('f_fsid', fsid_t),
+ ('f_owner', uid_t),
+ ('f_type', uint32_t),
+ ('f_flags', uint32_t),
+ ('f_fssubtype', uint32_t),
+ ('f_fstypename', c_char * 16),
+ ('f_mntonname', c_char * PATH_MAX),
+ ('f_mntfromname', c_char * PATH_MAX),
+ ('f_reserved', uint32_t * 8)]
+
+# Calculate the maximum number of bytes required for the attribute buffer
+_attr_info = (
+ # Common attributes
+ (0, ATTR_CMN_RETURNED_ATTRS, sizeof(attribute_set_t)),
+ (0, ATTR_CMN_NAME, sizeof(attrreference_t) + NAME_MAX * 3 + 1),
+ (0, ATTR_CMN_DEVID, sizeof(dev_t)),
+ (0, ATTR_CMN_FSID, sizeof(fsid_t)),
+ (0, ATTR_CMN_OBJTYPE, sizeof(fsobj_type_t)),
+ (0, ATTR_CMN_OBJTAG, sizeof(fsobj_tag_t)),
+ (0, ATTR_CMN_OBJPERMANENTID, sizeof(fsobj_id_t)),
+ (0, ATTR_CMN_PAROBJID, sizeof(fsobj_id_t)),
+ (0, ATTR_CMN_SCRIPT, sizeof(text_encoding_t)),
+ (0, ATTR_CMN_CRTIME, sizeof(timespec)),
+ (0, ATTR_CMN_MODTIME, sizeof(timespec)),
+ (0, ATTR_CMN_CHGTIME, sizeof(timespec)),
+ (0, ATTR_CMN_ACCTIME, sizeof(timespec)),
+ (0, ATTR_CMN_BKUPTIME, sizeof(timespec)),
+ (0, ATTR_CMN_FNDRINFO, sizeof(FinderInfo)),
+ (0, ATTR_CMN_OWNERID, sizeof(uid_t)),
+ (0, ATTR_CMN_GRPID, sizeof(gid_t)),
+ (0, ATTR_CMN_ACCESSMASK, sizeof(uint32_t)),
+ (0, ATTR_CMN_NAMEDATTRCOUNT, None),
+ (0, ATTR_CMN_NAMEDATTRLIST, None),
+ (0, ATTR_CMN_FLAGS, sizeof(uint32_t)),
+ (0, ATTR_CMN_USERACCESS, sizeof(uint32_t)),
+ (0, ATTR_CMN_EXTENDED_SECURITY, sizeof(attrreference_t) + sizeof(kauth_filesec)),
+ (0, ATTR_CMN_UUID, sizeof(guid_t)),
+ (0, ATTR_CMN_GRPUUID, sizeof(guid_t)),
+ (0, ATTR_CMN_FILEID, sizeof(uint64_t)),
+ (0, ATTR_CMN_PARENTID, sizeof(uint64_t)),
+ (0, ATTR_CMN_FULLPATH, sizeof(attrreference_t) + PATH_MAX),
+ (0, ATTR_CMN_ADDEDTIME, sizeof(timespec)),
+
+ # Volume attributes
+ (1, ATTR_VOL_FSTYPE, sizeof(uint32_t)),
+ (1, ATTR_VOL_SIGNATURE, sizeof(uint32_t)),
+ (1, ATTR_VOL_SIZE, sizeof(off_t)),
+ (1, ATTR_VOL_SPACEFREE, sizeof(off_t)),
+ (1, ATTR_VOL_SPACEAVAIL, sizeof(off_t)),
+ (1, ATTR_VOL_MINALLOCATION, sizeof(off_t)),
+ (1, ATTR_VOL_ALLOCATIONCLUMP, sizeof(off_t)),
+ (1, ATTR_VOL_IOBLOCKSIZE, sizeof(uint32_t)),
+ (1, ATTR_VOL_OBJCOUNT, sizeof(uint32_t)),
+ (1, ATTR_VOL_FILECOUNT, sizeof(uint32_t)),
+ (1, ATTR_VOL_DIRCOUNT, sizeof(uint32_t)),
+ (1, ATTR_VOL_MAXOBJCOUNT, sizeof(uint32_t)),
+ (1, ATTR_VOL_MOUNTPOINT, sizeof(attrreference_t) + PATH_MAX),
+ (1, ATTR_VOL_NAME, sizeof(attrreference_t) + NAME_MAX + 1),
+ (1, ATTR_VOL_MOUNTFLAGS, sizeof(uint32_t)),
+ (1, ATTR_VOL_MOUNTEDDEVICE, sizeof(attrreference_t) + PATH_MAX),
+ (1, ATTR_VOL_ENCODINGSUSED, sizeof(c_ulonglong)),
+ (1, ATTR_VOL_CAPABILITIES, sizeof(vol_capabilities_attr_t)),
+ (1, ATTR_VOL_UUID, sizeof(uuid_t)),
+ (1, ATTR_VOL_ATTRIBUTES, sizeof(vol_attributes_attr_t)),
+
+ # Directory attributes
+ (2, ATTR_DIR_LINKCOUNT, sizeof(uint32_t)),
+ (2, ATTR_DIR_ENTRYCOUNT, sizeof(uint32_t)),
+ (2, ATTR_DIR_MOUNTSTATUS, sizeof(uint32_t)),
+
+ # File attributes
+ (3, ATTR_FILE_LINKCOUNT, sizeof(uint32_t)),
+ (3, ATTR_FILE_TOTALSIZE, sizeof(off_t)),
+ (3, ATTR_FILE_ALLOCSIZE, sizeof(off_t)),
+ (3, ATTR_FILE_IOBLOCKSIZE, sizeof(uint32_t)),
+ (3, ATTR_FILE_CLUMPSIZE, sizeof(uint32_t)),
+ (3, ATTR_FILE_DEVTYPE, sizeof(uint32_t)),
+ (3, ATTR_FILE_FILETYPE, sizeof(uint32_t)),
+ (3, ATTR_FILE_FORKCOUNT, sizeof(uint32_t)),
+ (3, ATTR_FILE_FORKLIST, None),
+ (3, ATTR_FILE_DATALENGTH, sizeof(off_t)),
+ (3, ATTR_FILE_DATAALLOCSIZE, sizeof(off_t)),
+ (3, ATTR_FILE_DATAEXTENTS, sizeof(extentrecord)),
+ (3, ATTR_FILE_RSRCLENGTH, sizeof(off_t)),
+ (3, ATTR_FILE_RSRCALLOCSIZE, sizeof(off_t)),
+ (3, ATTR_FILE_RSRCEXTENTS, sizeof(extentrecord)),
+
+ # Fork attributes
+ (4, ATTR_FORK_TOTALSIZE, sizeof(off_t)),
+ (4, ATTR_FORK_ALLOCSIZE, sizeof(off_t))
+ )
+
+def _attrbuf_size(attrs):
+ size = 4
+ for entry in _attr_info:
+ if attrs[entry[0]] & entry[1]:
+ if entry[2] is None:
+ raise ValueError('Unsupported attribute (%u, %x)'
+ % (entry[0], entry[1]))
+ size += entry[2]
+ return size
+
+_getattrlist = libc.getattrlist
+_getattrlist.argtypes = [c_char_p, POINTER(attrlist), c_void_p, c_ulong, c_ulong]
+_getattrlist.restype = c_int
+
+_fgetattrlist = libc.fgetattrlist
+_fgetattrlist.argtypes = [c_int, POINTER(attrlist), c_void_p, c_ulong, c_ulong]
+_fgetattrlist.restype = c_int
+
+_statfs = libc['statfs$INODE64']
+_statfs.argtypes = [c_char_p, POINTER(struct_statfs)]
+_statfs.restype = c_int
+
+_fstatfs = libc['fstatfs$INODE64']
+_fstatfs.argtypes = [c_int, POINTER(struct_statfs)]
+_fstatfs.restype = c_int
+
+def _datetime_from_timespec(ts):
+ td = datetime.timedelta(seconds=ts.tv_sec + 1.0e-9 * ts.tv_nsec)
+ return unix_epoch + td
+
+def _decode_utf8_nul(sz):
+ nul = sz.find('\0')
+ if nul > -1:
+ sz = sz[:nul]
+ return sz.decode('utf-8')
+
+def _decode_attrlist_result(buf, attrs, options):
+ result = []
+
+ assert len(buf) >= 4
+ total_size = uint32_t.from_buffer(buf, 0).value
+ assert total_size <= len(buf)
+
+ offset = 4
+
+ # Common attributes
+ if attrs[0] & ATTR_CMN_RETURNED_ATTRS:
+ a = attribute_set_t.from_buffer(buf, offset)
+ result.append(a)
+ offset += sizeof (attribute_set_t)
+ if not (options & FSOPT_PACK_INVAL_ATTRS):
+ attrs = [a.commonattr, a.volattr, a.dirattr, a.fileattr, a.forkattr]
+ if attrs[0] & ATTR_CMN_NAME:
+ a = attrreference_t.from_buffer(buf, offset)
+ ofs = offset + a.attr_dataoffset
+ name = _decode_utf8_nul(buf[ofs:ofs+a.attr_length])
+ offset += sizeof (attrreference_t)
+ result.append(name)
+ if attrs[0] & ATTR_CMN_DEVID:
+ a = dev_t.from_buffer(buf, offset)
+ offset += sizeof(dev_t)
+ result.append(a.value)
+ if attrs[0] & ATTR_CMN_FSID:
+ a = fsid_t.from_buffer(buf, offset)
+ offset += sizeof(fsid_t)
+ result.append(a)
+ if attrs[0] & ATTR_CMN_OBJTYPE:
+ a = fsobj_type_t.from_buffer(buf, offset)
+ offset += sizeof(fsobj_type_t)
+ result.append(a.value)
+ if attrs[0] & ATTR_CMN_OBJTAG:
+ a = fsobj_tag_t.from_buffer(buf, offset)
+ offset += sizeof(fsobj_tag_t)
+ result.append(a.value)
+ if attrs[0] & ATTR_CMN_OBJID:
+ a = fsobj_id_t.from_buffer(buf, offset)
+ offset += sizeof(fsobj_id_t)
+ result.append(a)
+ if attrs[0] & ATTR_CMN_OBJPERMANENTID:
+ a = fsobj_id_t.from_buffer(buf, offset)
+ offset += sizeof(fsobj_id_t)
+ result.append(a)
+ if attrs[0] & ATTR_CMN_PAROBJID:
+ a = fsobj_id_t.from_buffer(buf, offset)
+ offset += sizeof(fsobj_id_t)
+ result.append(a)
+ if attrs[0] & ATTR_CMN_SCRIPT:
+ a = text_encoding_t.from_buffer(buf, offset)
+ offset += sizeof(text_encoding_t)
+ result.append(a.value)
+ if attrs[0] & ATTR_CMN_CRTIME:
+ a = timespec.from_buffer(buf, offset)
+ offset += sizeof(timespec)
+ result.append(_datetime_from_timespec(a))
+ if attrs[0] & ATTR_CMN_MODTIME:
+ a = timespec.from_buffer(buf, offset)
+ offset += sizeof(timespec)
+ result.append(_datetime_from_timespec(a))
+ if attrs[0] & ATTR_CMN_CHGTIME:
+ a = timespec.from_buffer(buf, offset)
+ offset += sizeof(timespec)
+ result.append(_datetime_from_timespec(a))
+ if attrs[0] & ATTR_CMN_ACCTIME:
+ a = timespec.from_buffer(buf, offset)
+ offset += sizeof(timespec)
+ result.append(_datetime_from_timespec(a))
+ if attrs[0] & ATTR_CMN_BKUPTIME:
+ a = timespec.from_buffer(buf, offset)
+ offset += sizeof(timespec)
+ result.append(_datetime_from_timespec(a))
+ if attrs[0] & ATTR_CMN_FNDRINFO:
+ a = FinderInfo.from_buffer(buf, offset)
+ offset += sizeof(FinderInfo)
+ result.append(a)
+ if attrs[0] & ATTR_CMN_OWNERID:
+ a = uid_t.from_buffer(buf, offset)
+ offset += sizeof(uid_t)
+ result.append(a.value)
+ if attrs[0] & ATTR_CMN_GRPID:
+ a = gid_t.from_buffer(buf, offset)
+ offset += sizeof(gid_t)
+ result.append(a.value)
+ if attrs[0] & ATTR_CMN_ACCESSMASK:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[0] & ATTR_CMN_FLAGS:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[0] & ATTR_CMN_USERACCESS:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[0] & ATTR_CMN_EXTENDED_SECURITY:
+ a = attrreference_t.from_buffer(buf, offset)
+ ofs = offset + a.attr_dataoffset
+ offset += sizeof(attrreference_t)
+ ec = uint32_t.from_buffer(buf, ofs + 36).value
+ class kauth_acl(Structure):
+ _fields_ = [('acl_entrycount', c_uint),
+ ('acl_flags', c_uint),
+ ('acl_ace', kauth_ace * ec)]
+ class kauth_filesec(Structure):
+ _fields_ = [('fsec_magic', c_uint),
+ ('fsec_owner', guid_t),
+ ('fsec_group', guid_t),
+ ('fsec_acl', kauth_acl)]
+ a = kauth_filesec.from_buffer(buf, ofs)
+ result.append(a)
+ if attrs[0] & ATTR_CMN_UUID:
+ result.append(uuid.UUID(bytes=buf[offset:offset+16]))
+ offset += sizeof(guid_t)
+ if attrs[0] & ATTR_CMN_GRPUUID:
+ result.append(uuid.UUID(bytes=buf[offset:offset+16]))
+ offset += sizeof(guid_t)
+ if attrs[0] & ATTR_CMN_FILEID:
+ a = uint64_t.from_buffer(buf, offset)
+ offset += sizeof(uint64_t)
+ result.append(a.value)
+ if attrs[0] & ATTR_CMN_PARENTID:
+ a = uint64_t.from_buffer(buf, offset)
+ offset += sizeof(uint64_t)
+ result.append(a.value)
+ if attrs[0] & ATTR_CMN_FULLPATH:
+ a = attrreference_t.from_buffer(buf, offset)
+ ofs = offset + a.attr_dataoffset
+ path = _decode_utf8_nul(buf[ofs:ofs+a.attr_length])
+ offset += sizeof (attrreference_t)
+ result.append(path)
+ if attrs[0] & ATTR_CMN_ADDEDTIME:
+ a = timespec.from_buffer(buf, offset)
+ offset += sizeof(timespec)
+ result.append(_datetime_from_timespec(a))
+
+ # Volume attributes
+ if attrs[1] & ATTR_VOL_FSTYPE:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_SIGNATURE:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_SIZE:
+ a = off_t.from_buffer(buf, offset)
+ offset += sizeof(off_t)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_SPACEFREE:
+ a = off_t.from_buffer(buf, offset)
+ offset += sizeof(off_t)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_SPACEAVAIL:
+ a = off_t.from_buffer(buf, offset)
+ offset += sizeof(off_t)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_MINALLOCATION:
+ a = off_t.from_buffer(buf, offset)
+ offset += sizeof(off_t)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_ALLOCATIONCLUMP:
+ a = off_t.from_buffer(buf, offset)
+ offset += sizeof(off_t)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_IOBLOCKSIZE:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_OBJCOUNT:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_FILECOUNT:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_DIRCOUNT:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_MAXOBJCOUNT:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_MOUNTPOINT:
+ a = attrreference_t.from_buffer(buf, offset)
+ ofs = offset + a.attr_dataoffset
+ path = _decode_utf8_nul(buf[ofs:ofs+a.attr_length])
+ offset += sizeof (attrreference_t)
+ result.append(path)
+ if attrs[1] & ATTR_VOL_NAME:
+ a = attrreference_t.from_buffer(buf, offset)
+ ofs = offset + a.attr_dataoffset
+ name = _decode_utf8_nul(buf[ofs:ofs+a.attr_length])
+ offset += sizeof (attrreference_t)
+ result.append(name)
+ if attrs[1] & ATTR_VOL_MOUNTFLAGS:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_MOUNTEDDEVICE:
+ a = attrreference_t.from_buffer(buf, offset)
+ ofs = offset + a.attr_dataoffset
+ path = _decode_utf8_nul(buf[ofs:ofs+a.attr_length])
+ offset += sizeof (attrreference_t)
+ result.append(path)
+ if attrs[1] & ATTR_VOL_ENCODINGSUSED:
+ a = c_ulonglong.from_buffer(buf, offset)
+ offset += sizeof(c_ulonglong)
+ result.append(a.value)
+ if attrs[1] & ATTR_VOL_CAPABILITIES:
+ a = vol_capabilities_attr_t.from_buffer(buf, offset)
+ offset += sizeof(vol_capabilities_attr_t)
+ result.append(a)
+ if attrs[1] & ATTR_VOL_UUID:
+ result.append(uuid.UUID(bytes=buf[offset:offset+16]))
+ offset += sizeof(uuid_t)
+ if attrs[1] & ATTR_VOL_ATTRIBUTES:
+ a = vol_attributes_attr_t.from_buffer(buf, offset)
+ offset += sizeof(vol_attributes_attr_t)
+ result.append(a)
+
+ # Directory attributes
+ if attrs[2] & ATTR_DIR_LINKCOUNT:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[2] & ATTR_DIR_ENTRYCOUNT:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[2] & ATTR_DIR_MOUNTSTATUS:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+
+ # File attributes
+ if attrs[3] & ATTR_FILE_LINKCOUNT:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[3] & ATTR_FILE_TOTALSIZE:
+ a = off_t.from_buffer(buf, offset)
+ offset += sizeof(off_t)
+ result.append(a.value)
+ if attrs[3] & ATTR_FILE_ALLOCSIZE:
+ a = off_t.from_buffer(buf, offset)
+ offset += sizeof(off_t)
+ result.append(a.value)
+ if attrs[3] & ATTR_FILE_IOBLOCKSIZE:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[3] & ATTR_FILE_CLUMPSIZE:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[3] & ATTR_FILE_DEVTYPE:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[3] & ATTR_FILE_FILETYPE:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[3] & ATTR_FILE_FORKCOUNT:
+ a = uint32_t.from_buffer(buf, offset)
+ offset += sizeof(uint32_t)
+ result.append(a.value)
+ if attrs[3] & ATTR_FILE_DATALENGTH:
+ a = off_t.from_buffer(buf, offset)
+ offset += sizeof(off_t)
+ result.append(a.value)
+ if attrs[3] & ATTR_FILE_DATAALLOCSIZE:
+ a = off_t.from_buffer(buf, offset)
+ offset += sizeof(off_t)
+ result.append(a.value)
+ if attrs[3] & ATTR_FILE_DATAEXTENTS:
+ a = extentrecord.from_buffer(buf, offset)
+ offset += sizeof(extentrecord)
+ result.append(a.value)
+ if attrs[3] & ATTR_FILE_RSRCLENGTH:
+ a = off_t.from_buffer(buf, offset)
+ offset += sizeof(off_t)
+ result.append(a.value)
+ if attrs[3] & ATTR_FILE_RSRCALLOCSIZE:
+ a = off_t.from_buffer(buf, offset)
+ offset += sizeof(off_t)
+ result.append(a.value)
+ if attrs[3] & ATTR_FILE_RSRCEXTENTS:
+ a = extentrecord.from_buffer(buf, offset)
+ offset += sizeof(extentrecord)
+ result.append(a.value)
+
+ # Fork attributes
+ if attrs[4] & ATTR_FORK_TOTALSIZE:
+ a = off_t.from_buffer(buf, offset)
+ offset += sizeof(off_t)
+ result.append(a.value)
+ if attrs[4] & ATTR_FORK_ALLOCSIZE:
+ a = off_t.from_buffer(buf, offset)
+ offset += sizeof(off_t)
+ result.append(a.value)
+
+ return result
+
+# Sadly, ctypes.get_errno() seems not to work
+__error = libc.__error
+__error.restype = POINTER(c_int)
+
+def _get_errno():
+ return __error().contents.value
+
+def getattrlist(path, attrs, options):
+ attrs = list(attrs)
+ if attrs[1]:
+ attrs[1] |= ATTR_VOL_INFO
+ alist = attrlist(bitmapcount=5,
+ commonattr=attrs[0],
+ volattr=attrs[1],
+ dirattr=attrs[2],
+ fileattr=attrs[3],
+ forkattr=attrs[4])
+
+ bufsize = _attrbuf_size(attrs)
+ buf = create_string_buffer(bufsize)
+
+ ret = _getattrlist(path, byref(alist), buf, bufsize,
+ options | FSOPT_REPORT_FULLSIZE)
+
+ if ret < 0:
+ err = _get_errno()
+ raise OSError(err, os.strerror(err), path)
+
+ return _decode_attrlist_result(buf, attrs, options)
+
+def fgetattrlist(fd, attrs, options):
+ if hasattr(fd, 'fileno'):
+ fd = fd.fileno()
+ attrs = list(attrs)
+ if attrs[1]:
+ attrs[1] |= ATTR_VOL_INFO
+ alist = attrlist(bitmapcount=5,
+ commonattr=attrs[0],
+ volattr=attrs[1],
+ dirattr=attrs[2],
+ fileattr=attrs[3],
+ forkattr=attrs[4])
+
+ bufsize = _attrbuf_size(attrs)
+ buf = create_string_buffer(bufsize)
+
+ ret = _fgetattrlist(fd, byref(alist), buf, bufsize,
+ options | FSOPT_REPORT_FULLSIZE)
+
+ if ret < 0:
+ err = _get_errno()
+ raise OSError(err, os.strerror(err))
+
+ return _decode_attrlist_result(buf, attrs, options)
+
+def statfs(path):
+ result = struct_statfs()
+ ret = _statfs(path, byref(result))
+ if ret < 0:
+ err = _get_errno()
+ raise OSError(err, os.strerror(err), path)
+ return result
+
+def fstatfs(fd):
+ if hasattr(fd, 'fileno'):
+ fd = fd.fileno()
+ result = struct_statfs()
+ ret = _fstatfs(fd, byref(result))
+ if ret < 0:
+ err = _get_errno()
+ raise OSError(err, os.strerror(err))
+ return result
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/qt_attribution.json b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/qt_attribution.json
new file mode 100644
index 000000000..562440cd6
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/qt_attribution.json
@@ -0,0 +1,13 @@
+{
+ "Id": "mac_alias",
+ "Name": "mac_alias",
+ "QDocModule": "qbs",
+ "QtUsage": "Used in the qbs dmg module for building Apple disk images.",
+ "Description": "Generate/parse Mac OS Alias records from Python",
+ "Homepage": "https://bitbucket.org/al45tair/mac_alias",
+ "Version": "2.0.1",
+ "License": "MIT License",
+ "LicenseId": "MIT",
+ "LicenseFile": "LICENSE",
+ "Copyright": "Copyright (c) 2014 Alastair Houghton"
+}
diff --git a/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/utils.py b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/utils.py
new file mode 100644
index 000000000..6a7d0a121
--- /dev/null
+++ b/src/3rdparty/python/lib/python2.7/site-packages/mac_alias/utils.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+import datetime
+
+ZERO = datetime.timedelta(0)
+class UTC (datetime.tzinfo):
+ def utcoffset(self, dt):
+ return ZERO
+ def dst(self, dt):
+ return ZERO
+ def tzname(self, dt):
+ return 'UTC'
+
+utc = UTC()
+mac_epoch = datetime.datetime(1904,1,1,0,0,0,0,utc)
+unix_epoch = datetime.datetime(1970,1,1,0,0,0,0,utc)
+osx_epoch = datetime.datetime(2001,1,1,0,0,0,0,utc)
diff --git a/src/3rdparty/python/update.sh b/src/3rdparty/python/update.sh
new file mode 100755
index 000000000..2eb3138c9
--- /dev/null
+++ b/src/3rdparty/python/update.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+pip install -U --isolated --prefix=$PWD --no-binary :all: --no-compile --no-deps biplist dmgbuild ds_store mac_alias
+rm lib/python2.7/site-packages/dmgbuild/resources/*.tiff
diff --git a/src/app/app.pri b/src/app/app.pri
index 5904c9dd5..49bbd905b 100644
--- a/src/app/app.pri
+++ b/src/app/app.pri
@@ -2,6 +2,7 @@ include(../install_prefix.pri)
QT = core
TEMPLATE = app
+DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_PROCESS_COMBINED_ARGUMENT_START
!isEmpty(QBS_APPS_DESTDIR):DESTDIR = $${QBS_APPS_DESTDIR}
else:DESTDIR = ../../../bin
diff --git a/src/app/qbs-setup-android/android-setup.cpp b/src/app/qbs-setup-android/android-setup.cpp
index c5ff47254..99866be9a 100644
--- a/src/app/qbs-setup-android/android-setup.cpp
+++ b/src/app/qbs-setup-android/android-setup.cpp
@@ -43,6 +43,7 @@
#include <tools/error.h>
#include <tools/hostosinfo.h>
#include <tools/profile.h>
+#include <tools/settings.h>
#include <tools/version.h>
#include <QtCore/qcoreapplication.h>
@@ -53,6 +54,8 @@
#include <QtCore/qprocess.h>
#include <QtCore/qstring.h>
+#include <algorithm>
+
using namespace qbs;
using qbs::Internal::Tr;
@@ -156,6 +159,29 @@ static QtInfoPerArch getQtAndroidInfo(const QString &qtSdkDir)
return archs;
}
+static QString maximumPlatform(const QString &platform1, const QString &platform2)
+{
+ if (platform1.isEmpty())
+ return platform2;
+ if (platform2.isEmpty())
+ return platform1;
+ static const QString prefix = qls("android-");
+ const QString numberString1 = platform1.mid(prefix.count());
+ const QString numberString2 = platform2.mid(prefix.count());
+ bool ok;
+ const int value1 = numberString1.toInt(&ok);
+ if (!ok) {
+ qWarning("Ignoring malformed Android platform string '%s'.", qPrintable(platform1));
+ return platform2;
+ }
+ const int value2 = numberString2.toInt(&ok);
+ if (!ok) {
+ qWarning("Ignoring malformed Android platform string '%s'.", qPrintable(platform2));
+ return platform1;
+ }
+ return prefix + QString::number(std::max(value1, value2));
+}
+
static void setupNdk(qbs::Settings *settings, const QString &profileName, const QString &ndkDirPath,
const QString &qtSdkDirPath)
{
@@ -170,37 +196,41 @@ static void setupNdk(qbs::Settings *settings, const QString &profileName, const
mainProfile.setValue(qls("Android.sdk.ndkDir"), QDir::cleanPath(ndkDirPath));
}
mainProfile.setValue(qls("qbs.toolchain"), QStringList() << qls("gcc"));
+ const QStringList archs = expectedArchs();
const QtInfoPerArch infoPerArch = getQtAndroidInfo(qtSdkDirPath);
- foreach (const QString &arch, expectedArchs()) {
- const QString subProName = subProfileName(profileName, arch);
+ mainProfile.setValue(qls("qbs.architectures"), infoPerArch.isEmpty()
+ ? archs : QStringList(infoPerArch.keys()));
+ QStringList searchPaths;
+ QString platform;
+ for (const QString &arch : archs) {
const QtAndroidInfo qtAndroidInfo = infoPerArch.value(arch);
- if (qtAndroidInfo.isValid()) {
- const QString setupQtPath = qApp->applicationDirPath() + qls("/qbs-setup-qt");
- QProcess setupQt;
- setupQt.start(setupQtPath, QStringList() << qtAndroidInfo.qmakePath << subProName);
- if (!setupQt.waitForStarted()) {
- throw ErrorInfo(Tr::tr("Setting up Qt profile failed: '%1' "
- "could not be started.").arg(setupQtPath));
- }
- if (!setupQt.waitForFinished()) {
- throw ErrorInfo(Tr::tr("Setting up Qt profile failed: Error running '%1' (%2)")
- .arg(setupQtPath, setupQt.errorString()));
- }
- if (setupQt.exitCode() != 0) {
- throw ErrorInfo(Tr::tr("Setting up Qt profile failed: '%1' returned with "
- "exit code %2.").arg(setupQtPath).arg(setupQt.exitCode()));
- }
+ if (!qtAndroidInfo.isValid())
+ continue;
+ const QString subProName = subProfileName(profileName, arch);
+ const QString setupQtPath = qApp->applicationDirPath() + qls("/qbs-setup-qt");
+ QProcess setupQt;
+ setupQt.start(setupQtPath, QStringList({ qtAndroidInfo.qmakePath, subProName }));
+ if (!setupQt.waitForStarted()) {
+ throw ErrorInfo(Tr::tr("Setting up Qt profile failed: '%1' "
+ "could not be started.").arg(setupQtPath));
+ }
+ if (!setupQt.waitForFinished()) {
+ throw ErrorInfo(Tr::tr("Setting up Qt profile failed: Error running '%1' (%2)")
+ .arg(setupQtPath, setupQt.errorString()));
}
- Profile p(subProName, settings);
- if (qtAndroidInfo.isValid()) {
- if (!qtAndroidInfo.platform.isEmpty())
- p.setValue(qls("Android.ndk.platform"), qtAndroidInfo.platform);
- } else {
- p.removeProfile();
+ if (setupQt.exitCode() != 0) {
+ throw ErrorInfo(Tr::tr("Setting up Qt profile failed: '%1' returned with "
+ "exit code %2.").arg(setupQtPath).arg(setupQt.exitCode()));
}
- p.setBaseProfile(mainProfile.name());
- p.setValue(qls("qbs.architecture"), arch);
+ settings->sync();
+ qbs::Internal::TemporaryProfile p(subProName, settings);
+ searchPaths << p.p.value(qls("preferences.qbsSearchPaths")).toStringList();
+ platform = maximumPlatform(platform, qtAndroidInfo.platform);
}
+ if (!searchPaths.isEmpty())
+ mainProfile.setValue(qls("preferences.qbsSearchPaths"), searchPaths);
+ if (!platform.isEmpty())
+ mainProfile.setValue(qls("Android.ndk.platform"), platform);
}
void setupAndroid(Settings *settings, const QString &profileName, const QString &sdkDirPath,
diff --git a/src/app/qbs-setup-qt/setupqt.cpp b/src/app/qbs-setup-qt/setupqt.cpp
index 481042f8e..55db5415b 100644
--- a/src/app/qbs-setup-qt/setupqt.cpp
+++ b/src/app/qbs-setup-qt/setupqt.cpp
@@ -356,15 +356,11 @@ static bool isToolchainProfile(const Profile &profile)
static bool isQtProfile(const Profile &profile)
{
- bool hasQtKey = false;
- foreach (const QString &key, profile.allKeys(Profile::KeySelectionRecursive)) {
- if (key.startsWith(QLatin1String("Qt."))) {
- hasQtKey = true;
- break;
- }
- }
-
- return hasQtKey;
+ const QStringList searchPaths
+ = profile.value(QStringLiteral("preferences.qbsSearchPaths")).toStringList();
+ return std::any_of(searchPaths.cbegin(), searchPaths.cend(), [] (const QString &path) {
+ return QFileInfo(path + QStringLiteral("/modules/Qt")).isDir();
+ });
}
template <typename T> bool areProfilePropertiesIncompatible(const T &set1, const T &set2)
diff --git a/src/app/qbs-setup-toolchains/xcodeprobe.cpp b/src/app/qbs-setup-toolchains/xcodeprobe.cpp
index 0b38750cf..18b072e30 100644
--- a/src/app/qbs-setup-toolchains/xcodeprobe.cpp
+++ b/src/app/qbs-setup-toolchains/xcodeprobe.cpp
@@ -53,7 +53,8 @@
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
#include <QtCore/qsettings.h>
-#include <QtCore/qregularexpression.h>
+
+#include <regex>
using namespace qbs;
using Internal::Tr;
@@ -61,8 +62,8 @@ using Internal::Tr;
namespace {
static const QString defaultDeveloperPath =
QStringLiteral("/Applications/Xcode.app/Contents/Developer");
-static const QRegularExpression defaultDeveloperPathRegex(
- QStringLiteral("^/Applications/Xcode([a-zA-Z0-9 _-]+)\\.app/Contents/Developer$"));
+static const std::regex defaultDeveloperPathRegex(
+ "^/Applications/Xcode([a-zA-Z0-9 _-]+)\\.app/Contents/Developer$");
class XcodeProbe
{
@@ -215,13 +216,15 @@ void XcodeProbe::detectAll()
int i = 1;
detectDeveloperPaths();
for (const QString &developerPath : developerPaths) {
- QRegularExpressionMatch match(defaultDeveloperPathRegex.match(developerPath));
QString profileName = QLatin1String("xcode");
if (developerPath != defaultDeveloperPath) {
- profileName += match.hasMatch()
- ? match.capturedTexts().value(1).toLower().replace(QLatin1Char(' '),
- QLatin1Char('-'))
- : QString::number(i++);
+ const auto devPath = developerPath.toStdString();
+ std::smatch match;
+ if (std::regex_match(devPath, match, defaultDeveloperPathRegex))
+ profileName += QString::fromStdString(match[1]).toLower().replace(QLatin1Char(' '),
+ QLatin1Char('-'));
+ else
+ profileName += QString::number(i++);
}
setupDefaultToolchains(developerPath, profileName);
}
diff --git a/src/app/qbs/commandlinefrontend.cpp b/src/app/qbs/commandlinefrontend.cpp
index 8cc374a35..bd35e3bcb 100644
--- a/src/app/qbs/commandlinefrontend.cpp
+++ b/src/app/qbs/commandlinefrontend.cpp
@@ -139,13 +139,15 @@ void CommandLineFrontend::start()
if (m_parser.showProgress())
m_observer = new ConsoleProgressObserver;
SetupProjectParameters params;
+ params.setEnvironment(QProcessEnvironment::systemEnvironment());
params.setProjectFilePath(m_parser.projectFilePath());
- params.setIgnoreDifferentProjectFilePath(m_parser.force());
params.setDryRun(m_parser.dryRun());
params.setForceProbeExecution(m_parser.forceProbesExecution());
params.setWaitLockBuildGraph(m_parser.waitLockBuildGraph());
params.setLogElapsedTime(m_parser.logTime());
params.setSettingsDirectory(m_settings->baseDirectory());
+ params.setOverrideBuildGraphData(m_parser.command() == ResolveCommandType);
+ params.setPropertyCheckingMode(ErrorHandlingMode::Strict);
if (!m_parser.buildBeforeInstalling() || m_parser.command() == DumpNodesTreeCommandType)
params.setRestoreBehavior(SetupProjectParameters::RestoreOnly);
foreach (const QVariantMap &buildConfig, m_parser.buildConfigurations()) {
@@ -159,14 +161,7 @@ void CommandLineFrontend::start()
userConfig.insert(installRootKey, installRoot);
}
const QString configurationName = userConfig.take(configurationKey).toString();
- QString profileName = userConfig.take(profileKey).toString();
- if (profileName.isEmpty())
- profileName = m_settings->defaultProfile();
- if (profileName.isEmpty()) {
- qbsDebug() << Tr::tr("No profile specified and no default profile exists. "
- "Using default property values.");
- profileName = Profile::fallbackName();
- }
+ const QString profileName = userConfig.take(profileKey).toString();
const Preferences prefs(m_settings);
params.setSearchPaths(prefs.searchPaths(QDir::cleanPath(QCoreApplication::applicationDirPath()
+ QLatin1String("/" QBS_RELATIVE_SEARCH_PATH))));
@@ -492,7 +487,7 @@ void CommandLineFrontend::build()
void CommandLineFrontend::generate()
{
const QString generatorName = m_parser.generateOptions().generatorName();
- QSharedPointer<ProjectGenerator> generator(ProjectGeneratorManager::findGenerator(generatorName));
+ auto generator = ProjectGeneratorManager::findGenerator(generatorName);
if (!generator) {
const QString generatorNames = ProjectGeneratorManager::loadedGeneratorNames()
.join(QLatin1String("\n\t"));
@@ -509,7 +504,8 @@ void CommandLineFrontend::generate()
generator->generate(m_projects,
m_parser.buildConfigurations(),
m_parser.installOptions(QString()),
- m_parser.settingsDir());
+ m_parser.settingsDir(),
+ ConsoleLogger::instance(m_settings));
}
int CommandLineFrontend::runTarget()
diff --git a/src/app/qbs/parser/commandlineparser.cpp b/src/app/qbs/parser/commandlineparser.cpp
index ff42d1bab..8ff4a83ed 100644
--- a/src/app/qbs/parser/commandlineparser.cpp
+++ b/src/app/qbs/parser/commandlineparser.cpp
@@ -86,6 +86,7 @@ public:
void setupProgress();
void setupLogLevel();
void setupBuildOptions();
+ void setupBuildConfigurations();
bool checkForExistingBuildConfiguration(const QList<QVariantMap> &buildConfigs,
const QString &configurationName);
bool withNonDefaultProducts() const;
@@ -101,6 +102,7 @@ public:
QString projectFilePath;
QString projectBuildDirectory;
BuildOptions buildOptions;
+ QList<QVariantMap> buildConfigurations;
CommandLineOptionPool optionPool;
CommandPool commandPool;
bool showProgress;
@@ -290,61 +292,7 @@ static QString getBuildConfigurationName(const QVariantMap &buildConfig)
QList<QVariantMap> CommandLineParser::buildConfigurations() const
{
- // first: configuration name, second: properties.
- // Empty configuration name used for global properties.
- typedef std::pair<QString, QVariantMap> PropertyListItem;
- QList<PropertyListItem> propertiesPerConfiguration;
-
- const QString configurationNameKey = QLatin1String("qbs.configurationName");
- QString currentConfigurationName;
- QVariantMap currentProperties;
- foreach (const QString &arg, d->command->additionalArguments()) {
- const int sepPos = arg.indexOf(QLatin1Char(':'));
- if (sepPos == -1) { // New build configuration found.
- propertiesPerConfiguration << std::make_pair(currentConfigurationName,
- currentProperties);
- currentConfigurationName = arg;
- currentProperties.clear();
- continue;
- }
- const QString property = d->propertyName(arg.left(sepPos));
- if (property.isEmpty()) {
- qbsWarning() << Tr::tr("Ignoring empty property.");
- } else if (property == configurationNameKey) {
- qbsWarning() << Tr::tr("Refusing to overwrite special property '%1'.")
- .arg(configurationNameKey);
- } else {
- const QString rawString = arg.mid(sepPos + 1);
- currentProperties.insert(property, representationToSettingsValue(rawString));
- }
- }
- propertiesPerConfiguration << std::make_pair(currentConfigurationName, currentProperties);
-
- if (propertiesPerConfiguration.count() == 1) // No configuration name specified on command line.
- propertiesPerConfiguration << PropertyListItem(QStringLiteral("default"), QVariantMap());
-
- const QVariantMap globalProperties = propertiesPerConfiguration.takeFirst().second;
- QList<QVariantMap> buildConfigs;
- foreach (const PropertyListItem &item, propertiesPerConfiguration) {
- QVariantMap properties = item.second;
- for (QVariantMap::ConstIterator globalPropIt = globalProperties.constBegin();
- globalPropIt != globalProperties.constEnd(); ++globalPropIt) {
- if (!properties.contains(globalPropIt.key()))
- properties.insert(globalPropIt.key(), globalPropIt.value());
- }
-
- const QString configurationName = item.first;
- if (d->checkForExistingBuildConfiguration(buildConfigs, configurationName)) {
- qbsWarning() << Tr::tr("Ignoring redundant request to build for configuration '%1'.")
- .arg(configurationName);
- continue;
- }
-
- properties.insert(configurationNameKey, configurationName);
- buildConfigs << properties;
- }
-
- return buildConfigs;
+ return d->buildConfigurations;
}
bool CommandLineParser::parseCommandLine(const QStringList &args)
@@ -395,8 +343,9 @@ void CommandLineParser::CommandLineParserPrivate::doParse()
if (command->type() == BuildCommandType && optionPool.versionOption()->enabled())
return;
- setupProjectFile();
setupBuildDirectory();
+ setupBuildConfigurations();
+ setupProjectFile();
setupProgress();
setupLogLevel();
setupBuildOptions();
@@ -480,6 +429,28 @@ void CommandLineParser::CommandLineParserPrivate::setupProjectFile()
{
projectFilePath = optionPool.fileOption()->projectFilePath();
if (projectFilePath.isEmpty()) {
+ bool allBuildGraphsExist = true;
+ foreach (const QVariantMap &buildConfig, buildConfigurations) {
+ const QString configName = buildConfig.value(QLatin1String("qbs.configurationName"))
+ .toString();
+ const QString profile = buildConfig.value(QLatin1String("qbs.profile")).toString();
+ QString buildDir = projectBuildDirectory;
+ Settings settings(settingsDir());
+ if (buildDir.isEmpty()) {
+ buildDir = Preferences(&settings, profile).defaultBuildDirectory();
+ if (buildDir.isEmpty())
+ buildDir = QDir::currentPath();
+ }
+ if (!QFile::exists(buildDir + QLatin1Char('/') + configName + QLatin1Char('/')
+ + configName + QLatin1String(".bg"))) {
+ allBuildGraphsExist = false;
+ break;
+ }
+ }
+ if (allBuildGraphsExist) {
+ qbsDebug() << "No project file given; using the one from the build graph.";
+ return;
+ }
qbsDebug() << "No project file given; looking in current directory.";
projectFilePath = QDir::currentPath();
}
@@ -545,6 +516,65 @@ void CommandLineParser::CommandLineParserPrivate::setupBuildOptions()
buildOptions.setRemoveExistingInstallation(optionPool.removeFirstoption()->enabled());
}
+void CommandLineParser::CommandLineParserPrivate::setupBuildConfigurations()
+{
+ // first: configuration name, second: properties.
+ // Empty configuration name used for global properties.
+ typedef std::pair<QString, QVariantMap> PropertyListItem;
+ QList<PropertyListItem> propertiesPerConfiguration;
+
+ const QString configurationNameKey = QLatin1String("qbs.configurationName");
+ QString currentConfigurationName;
+ QVariantMap currentProperties;
+ foreach (const QString &arg, command->additionalArguments()) {
+ const int sepPos = arg.indexOf(QLatin1Char(':'));
+ if (sepPos == -1) { // New build configuration found.
+ propertiesPerConfiguration << std::make_pair(currentConfigurationName,
+ currentProperties);
+ currentConfigurationName = arg;
+ currentProperties.clear();
+ continue;
+ }
+ const QString property = propertyName(arg.left(sepPos));
+ if (property.isEmpty()) {
+ qbsWarning() << Tr::tr("Ignoring empty property.");
+ } else if (property == configurationNameKey) {
+ qbsWarning() << Tr::tr("Refusing to overwrite special property '%1'.")
+ .arg(configurationNameKey);
+ } else {
+ const QString rawString = arg.mid(sepPos + 1);
+ currentProperties.insert(property, representationToSettingsValue(rawString));
+ }
+ }
+ propertiesPerConfiguration << std::make_pair(currentConfigurationName, currentProperties);
+
+ if (propertiesPerConfiguration.count() == 1) // No configuration name specified on command line.
+ propertiesPerConfiguration << PropertyListItem(QStringLiteral("default"), QVariantMap());
+
+ const QVariantMap globalProperties = propertiesPerConfiguration.takeFirst().second;
+ QList<QVariantMap> buildConfigs;
+ foreach (const PropertyListItem &item, propertiesPerConfiguration) {
+ QVariantMap properties = item.second;
+ for (QVariantMap::ConstIterator globalPropIt = globalProperties.constBegin();
+ globalPropIt != globalProperties.constEnd(); ++globalPropIt) {
+ if (!properties.contains(globalPropIt.key()))
+ properties.insert(globalPropIt.key(), globalPropIt.value());
+ }
+
+ const QString configurationName = item.first;
+ if (checkForExistingBuildConfiguration(buildConfigs, configurationName)) {
+ qbsWarning() << Tr::tr("Ignoring redundant request to build for configuration '%1'.")
+ .arg(configurationName);
+ continue;
+ }
+
+ properties.insert(configurationNameKey, configurationName);
+ buildConfigs << properties;
+ }
+
+ buildConfigurations = buildConfigs;
+}
+
void CommandLineParser::CommandLineParserPrivate::setupProgress()
{
const ShowProgressOption * const option = optionPool.showProgressOption();
diff --git a/src/app/qbs/qbs.qbs b/src/app/qbs/qbs.qbs
index da02da68f..ae4c0ab72 100644
--- a/src/app/qbs/qbs.qbs
+++ b/src/app/qbs/qbs.qbs
@@ -1,5 +1,4 @@
import qbs 1.0
-import QbsFunctions
QbsApp {
name: "qbs_app"
@@ -7,7 +6,7 @@ QbsApp {
targetName: "qbs"
// TODO: Use Utilities.cStringQuote
cpp.defines: base.concat([
- 'QBS_VERSION="' + QbsFunctions.qbsVersion() + '"',
+ 'QBS_VERSION="' + qbsversion.version + '"',
'QBS_RELATIVE_LIBEXEC_PATH="' + qbsbuildconfig.relativeLibexecPath + '"',
'QBS_RELATIVE_SEARCH_PATH="' + qbsbuildconfig.relativeSearchPath + '"',
'QBS_RELATIVE_PLUGINS_PATH="' + qbsbuildconfig.relativePluginsPath + '"',
diff --git a/src/lib/corelib/api/internaljobs.cpp b/src/lib/corelib/api/internaljobs.cpp
index 3094477b5..f6978ffc8 100644
--- a/src/lib/corelib/api/internaljobs.cpp
+++ b/src/lib/corelib/api/internaljobs.cpp
@@ -248,7 +248,7 @@ void InternalSetupProjectJob::start()
const QString buildDir
= TopLevelProject::deriveBuildDirectory(m_parameters.buildRoot(), projectId);
if (m_existingProject && m_existingProject->buildDirectory != buildDir)
- m_existingProject.clear();
+ m_existingProject.reset();
if (!m_existingProject) {
bgLocker = new BuildGraphLocker(ProjectBuildData::deriveBuildGraphFilePath(buildDir,
projectId),
@@ -261,7 +261,7 @@ void InternalSetupProjectJob::start()
m_newProject->bgLocker = bgLocker;
deleteLocker = false;
} catch (const ErrorInfo &error) {
- m_newProject.clear();
+ m_newProject.reset();
setError(error);
// Delete the build graph locker if and only if we allocated it here.
@@ -303,7 +303,7 @@ void InternalSetupProjectJob::execute()
storeBuildGraph(m_newProject);
// The evalutation context cannot be re-used for building, which runs in a different thread.
- m_newProject->buildData->evaluationContext.clear();
+ m_newProject->buildData->evaluationContext.reset();
}
void InternalSetupProjectJob::resolveProjectFromScratch(ScriptEngine *engine)
@@ -323,7 +323,7 @@ void InternalSetupProjectJob::resolveBuildDataFromScratch(const RulesEvaluationC
BuildGraphLoadResult InternalSetupProjectJob::restoreProject(const RulesEvaluationContextPtr &evalContext)
{
- BuildGraphLoader bgLoader(m_parameters.adjustedEnvironment(), logger());
+ BuildGraphLoader bgLoader(logger());
const BuildGraphLoadResult loadResult
= bgLoader.load(m_existingProject, m_parameters, evalContext);
return loadResult;
@@ -386,7 +386,7 @@ void InternalBuildJob::build(const TopLevelProjectPtr &project,
void InternalBuildJob::handleFinished()
{
setError(m_executor->error());
- project()->buildData->evaluationContext.clear();
+ project()->buildData->evaluationContext.reset();
storeBuildGraph();
m_executor->deleteLater();
}
diff --git a/src/lib/corelib/api/jobs.cpp b/src/lib/corelib/api/jobs.cpp
index b1b5b7e5f..76c1484cf 100644
--- a/src/lib/corelib/api/jobs.cpp
+++ b/src/lib/corelib/api/jobs.cpp
@@ -268,7 +268,7 @@ void SetupProjectJob::finish()
// already transferred.
if (m_existingProject.isValid()
&& (!error().hasError() || !m_existingProject.d->internalProject->buildData)) {
- m_existingProject.d->internalProject.clear();
+ m_existingProject.d->internalProject.reset();
}
}
diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp
index fe9baa9b9..88f2c689e 100644
--- a/src/lib/corelib/api/project.cpp
+++ b/src/lib/corelib/api/project.cpp
@@ -51,6 +51,7 @@
#include "runenvironment.h"
#include <buildgraph/artifact.h>
#include <buildgraph/buildgraph.h>
+#include <buildgraph/buildgraphloader.h>
#include <buildgraph/emptydirectoriesremover.h>
#include <buildgraph/nodetreedumper.h>
#include <buildgraph/productbuilddata.h>
@@ -71,7 +72,7 @@
#include <tools/installoptions.h>
#include <tools/preferences.h>
#include <tools/processresult.h>
-#include <tools/scannerpluginmanager.h>
+#include <tools/qbspluginmanager.h>
#include <tools/scripttools.h>
#include <tools/setupprojectparameters.h>
#include <tools/qbsassert.h>
@@ -82,11 +83,8 @@
#include <QtCore/qshareddata.h>
#include <mutex>
-
-#ifdef QBS_STATIC_LIB
-extern "C" ScannerPlugin *cppScanners[];
-extern "C" ScannerPlugin *qtScanners[];
-#endif
+#include <utility>
+#include <vector>
namespace qbs {
namespace Internal {
@@ -111,11 +109,9 @@ static void loadPlugins(const QStringList &_pluginPaths, const Logger &logger)
pluginPaths << pluginPath;
}
}
- ScannerPluginManager::instance()->loadPlugins(pluginPaths, logger);
-#ifdef QBS_STATIC_LIB
- ScannerPluginManager::instance()->loadPlugins(cppScanners);
- ScannerPluginManager::instance()->loadPlugins(qtScanners);
-#endif
+ auto pluginManager = QbsPluginManager::instance();
+ pluginManager->loadStaticPlugins();
+ pluginManager->loadPlugins(pluginPaths, logger);
qRegisterMetaType<ErrorInfo>("qbs::ErrorInfo");
qRegisterMetaType<ProcessResult>("qbs::ProcessResult");
@@ -206,14 +202,19 @@ QList<ResolvedProductPtr> ProjectPrivate::allEnabledInternalProducts(bool includ
return enabledInternalProducts(internalProject, includingNonDefault);
}
+static bool matches(const ProductData &product, const ResolvedProductConstPtr &rproduct)
+{
+ return product.name() == rproduct->name
+ && product.profile() == rproduct->profile
+ && product.multiplexConfigurationId() == rproduct->multiplexConfigurationId;
+}
+
static ResolvedProductPtr internalProductForProject(const ResolvedProjectConstPtr &project,
const ProductData &product)
{
for (const ResolvedProductPtr &resolvedProduct : qAsConst(project->products)) {
- if (product.name() == resolvedProduct->name
- && product.profile() == resolvedProduct->profile) {
+ if (matches(product, resolvedProduct))
return resolvedProduct;
- }
}
for (const ResolvedProjectConstPtr &subProject : qAsConst(project->subProjects)) {
const ResolvedProductPtr &p = internalProductForProject(subProject, product);
@@ -231,8 +232,11 @@ ResolvedProductPtr ProjectPrivate::internalProduct(const ProductData &product) c
ProductData ProjectPrivate::findProductData(const ProductData &product) const
{
for (const ProductData &p : m_projectData.allProducts()) {
- if (p.name() == product.name() && p.profile() == product.profile())
+ if (p.name() == product.name()
+ && p.profile() == product.profile()
+ && p.multiplexConfigurationId() == product.multiplexConfigurationId()) {
return p;
+ }
}
return ProductData();
}
@@ -728,14 +732,14 @@ RuleCommandList ProjectPrivate::ruleCommands(const ProductData &product,
case AbstractCommand::JavaScriptCommandType: {
externalCommand.d->type = RuleCommand::JavaScriptCommandType;
const JavaScriptCommandPtr &jsCmd
- = internalCommand.staticCast<JavaScriptCommand>();
+ = std::static_pointer_cast<JavaScriptCommand>(internalCommand);
externalCommand.d->sourceCode = jsCmd->sourceCode();
break;
}
case AbstractCommand::ProcessCommandType: {
externalCommand.d->type = RuleCommand::ProcessCommandType;
const ProcessCommandPtr &procCmd
- = internalCommand.staticCast<ProcessCommand>();
+ = std::static_pointer_cast<ProcessCommand>(internalCommand);
externalCommand.d->executable = procCmd->program();
externalCommand.d->arguments = procCmd->arguments();
externalCommand.d->workingDir = procCmd->workingDir();
@@ -759,6 +763,11 @@ static bool productIsRunnable(const ResolvedProductConstPtr &product)
return product->fileTags.contains("application");
}
+static bool productIsMultiplexed(const ResolvedProductConstPtr &product)
+{
+ return product->productProperties.value(QStringLiteral("multiplexed")).toBool();
+}
+
void ProjectPrivate::retrieveProjectData(ProjectData &projectData,
const ResolvedProjectConstPtr &internalProject)
{
@@ -773,10 +782,12 @@ void ProjectPrivate::retrieveProjectData(ProjectData &projectData,
product.d->version = resolvedProduct->productProperties
.value(QLatin1String("version")).toString();
product.d->profile = resolvedProduct->profile;
+ product.d->multiplexConfigurationId = resolvedProduct->multiplexConfigurationId;
product.d->location = resolvedProduct->location;
product.d->buildDirectory = resolvedProduct->buildDirectory();
product.d->isEnabled = resolvedProduct->enabled;
product.d->isRunnable = productIsRunnable(resolvedProduct);
+ product.d->isMultiplexed = productIsMultiplexed(resolvedProduct);
product.d->properties = resolvedProduct->productProperties;
product.d->moduleProperties.d->m_map = resolvedProduct->moduleProperties;
for (const GroupPtr &resolvedGroup : qAsConst(resolvedProduct->groups))
@@ -1124,6 +1135,44 @@ ErrorInfo Project::dumpNodesTree(QIODevice &outDevice, const QList<ProductData>
return ErrorInfo();
}
+Project::BuildGraphInfo Project::getBuildGraphInfo(const QString &bgFilePath,
+ const QStringList &requestedProperties)
+{
+ BuildGraphInfo info;
+ try {
+ const Internal::TopLevelProjectConstPtr project = BuildGraphLoader::loadProject(bgFilePath);
+ info.bgFilePath = bgFilePath;
+ info.overriddenProperties = project->overriddenValues;
+ info.profileData = project->profileConfigs;
+ std::vector<std::pair<QString, QString>> props;
+ 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));
+ }
+ for (const ResolvedProductConstPtr &product : project->allProducts()) {
+ if (props.empty())
+ break;
+ if (product->profile != project->profile())
+ continue;
+ for (auto it = props.begin(); it != props.end();) {
+ const QVariant value
+ = product->moduleProperties->moduleProperty(it->first, it->second);
+ if (value.isValid()) {
+ info.requestedProperties.insert(it->first + QLatin1Char('.') + it->second,
+ value);
+ it = props.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+ } catch (const ErrorInfo &e) {
+ info.error = e;
+ }
+ return info;
+}
+
#ifdef QBS_ENABLE_PROJECT_FILE_UPDATES
/*!
* \brief Adds a new empty group to the given product.
diff --git a/src/lib/corelib/api/project.h b/src/lib/corelib/api/project.h
index 5456da335..034db2625 100644
--- a/src/lib/corelib/api/project.h
+++ b/src/lib/corelib/api/project.h
@@ -41,6 +41,7 @@
#include "rulecommand.h"
#include "../language/forward_decls.h"
+#include "../tools/error.h"
#include "../tools/qbs_export.h"
#include <QtCore/qshareddata.h>
@@ -62,7 +63,6 @@ class BuildJob;
class BuildOptions;
class CleanJob;
class CleanOptions;
-class ErrorInfo;
class GroupData;
class ILogSink;
class InstallJob;
@@ -139,6 +139,20 @@ public:
ErrorInfo dumpNodesTree(QIODevice &outDevice, const QList<ProductData> &products);
+
+ class BuildGraphInfo
+ {
+ public:
+ QString bgFilePath;
+ QVariantMap overriddenProperties;
+ QVariantMap profileData;
+ QVariantMap requestedProperties;
+ ErrorInfo error;
+ };
+ static BuildGraphInfo getBuildGraphInfo(const QString &bgFilePath,
+ const QStringList &requestedProperties);
+
+
#ifdef QBS_ENABLE_PROJECT_FILE_UPDATES
ErrorInfo addGroup(const ProductData &product, const QString &groupName);
ErrorInfo addFiles(const ProductData &product, const GroupData &group,
diff --git a/src/lib/corelib/api/projectdata.cpp b/src/lib/corelib/api/projectdata.cpp
index 475861e5b..987bd24a4 100644
--- a/src/lib/corelib/api/projectdata.cpp
+++ b/src/lib/corelib/api/projectdata.cpp
@@ -474,6 +474,11 @@ QString ProductData::profile() const
return d->profile;
}
+QString ProductData::multiplexConfigurationId() const
+{
+ return d->multiplexConfigurationId;
+}
+
/*!
* \brief The location at which the product is defined in the source file.
*/
@@ -599,6 +604,12 @@ bool ProductData::isRunnable() const
return d->isRunnable;
}
+bool ProductData::isMultiplexed() const
+{
+ QBS_ASSERT(isValid(), return false);
+ return d->isMultiplexed;
+}
+
bool operator==(const ProductData &lhs, const ProductData &rhs)
{
if (!lhs.isValid() && !rhs.isValid())
@@ -611,12 +622,14 @@ bool operator==(const ProductData &lhs, const ProductData &rhs)
&& lhs.version() == rhs.version()
&& lhs.dependencies() == rhs.dependencies()
&& lhs.profile() == rhs.profile()
+ && lhs.multiplexConfigurationId() == rhs.multiplexConfigurationId()
&& lhs.location() == rhs.location()
&& lhs.groups() == rhs.groups()
&& lhs.generatedArtifacts() == rhs.generatedArtifacts()
&& lhs.properties() == rhs.properties()
&& lhs.moduleProperties() == rhs.moduleProperties()
- && lhs.isEnabled() == rhs.isEnabled();
+ && lhs.isEnabled() == rhs.isEnabled()
+ && lhs.isMultiplexed() == rhs.isMultiplexed();
}
bool operator!=(const ProductData &lhs, const ProductData &rhs)
@@ -631,7 +644,8 @@ bool operator<(const ProductData &lhs, const ProductData &rhs)
return true;
if (nameCmp > 0)
return false;
- return lhs.profile() < rhs.profile();
+ return lhs.profile() < rhs.profile()
+ && lhs.multiplexConfigurationId() < lhs.multiplexConfigurationId();
}
/*!
diff --git a/src/lib/corelib/api/projectdata.h b/src/lib/corelib/api/projectdata.h
index 12bc756ae..9f9dafcc7 100644
--- a/src/lib/corelib/api/projectdata.h
+++ b/src/lib/corelib/api/projectdata.h
@@ -189,6 +189,7 @@ public:
QString targetName() const;
QString version() const;
QString profile() const;
+ QString multiplexConfigurationId() const;
CodeLocation location() const;
QString buildDirectory() const;
QList<ArtifactData> generatedArtifacts() const;
@@ -200,6 +201,7 @@ public:
PropertyMap moduleProperties() const;
bool isEnabled() const;
bool isRunnable() const;
+ bool isMultiplexed() const;
private:
QExplicitlySharedDataPointer<Internal::ProductDataPrivate> d;
diff --git a/src/lib/corelib/api/projectdata_p.h b/src/lib/corelib/api/projectdata_p.h
index 9eee68db2..58ae2ffea 100644
--- a/src/lib/corelib/api/projectdata_p.h
+++ b/src/lib/corelib/api/projectdata_p.h
@@ -110,6 +110,7 @@ public:
QString targetName;
QString version;
QString profile;
+ QString multiplexConfigurationId;
CodeLocation location;
QString buildDirectory;
QList<GroupData> groups;
@@ -118,6 +119,7 @@ public:
QList<ArtifactData> generatedArtifacts;
bool isEnabled;
bool isRunnable;
+ bool isMultiplexed;
bool isValid;
};
diff --git a/src/lib/corelib/api/runenvironment.cpp b/src/lib/corelib/api/runenvironment.cpp
index 96484815b..a2caea987 100644
--- a/src/lib/corelib/api/runenvironment.cpp
+++ b/src/lib/corelib/api/runenvironment.cpp
@@ -265,11 +265,14 @@ int RunEnvironment::doRunTarget(const QString &targetBin, const QStringList &arg
}
if (completeSuffix == QLatin1String("js")) {
- // The Node.js binary is called nodejs on Debian/Ubuntu-family operating systems due to a
- // conflict with another package containing a binary named node
- targetExecutable = findExecutable(QStringList()
- << QLatin1String("nodejs")
- << QLatin1String("node"));
+ targetExecutable = d->resolvedProduct->moduleProperties->moduleProperty(
+ QLatin1String("nodejs"), QLatin1String("interpreterFilePath")).toString();
+ if (targetExecutable.isEmpty())
+ // The Node.js binary is called nodejs on Debian/Ubuntu-family operating systems due to
+ // conflict with another package containing a binary named node
+ targetExecutable = findExecutable(QStringList()
+ << QLatin1String("nodejs")
+ << QLatin1String("node"));
targetArguments.prepend(targetBin);
}
diff --git a/src/lib/corelib/buildgraph/artifact.cpp b/src/lib/corelib/buildgraph/artifact.cpp
index e7c45e6c6..4562c4e9c 100644
--- a/src/lib/corelib/buildgraph/artifact.cpp
+++ b/src/lib/corelib/buildgraph/artifact.cpp
@@ -71,26 +71,26 @@ void Artifact::accept(BuildGraphVisitor *visitor)
QString Artifact::toString() const
{
return QLatin1String("ARTIFACT ") + filePath() + QLatin1String(" [")
- + (!product.isNull() ? product->name : QLatin1String("<null>")) + QLatin1Char(']');
+ + (!product.expired() ? product->name : QLatin1String("<null>")) + QLatin1Char(']');
}
void Artifact::addFileTag(const FileTag &t)
{
m_fileTags += t;
- if (!product.isNull() && product->buildData)
+ if (!product.expired() && product->buildData)
product->buildData->artifactsByFileTag[t] += this;
}
void Artifact::removeFileTag(const FileTag &t)
{
m_fileTags -= t;
- if (!product.isNull() && product->buildData)
+ if (!product.expired() && product->buildData)
removeArtifactFromSetByFileTag(this, t, product->buildData->artifactsByFileTag);
}
void Artifact::setFileTags(const FileTags &newFileTags)
{
- if (product.isNull() || !product->buildData) {
+ if (product.expired() || !product->buildData) {
m_fileTags = newFileTags;
return;
}
diff --git a/src/lib/corelib/buildgraph/artifact.h b/src/lib/corelib/buildgraph/artifact.h
index 466169d46..ea0b6a6dc 100644
--- a/src/lib/corelib/buildgraph/artifact.h
+++ b/src/lib/corelib/buildgraph/artifact.h
@@ -64,7 +64,7 @@ using ArtifactSet = Set<Artifact *>;
*
*
*/
-class Artifact : public FileResourceBase, public BuildGraphNode
+class QBS_AUTOTEST_EXPORT Artifact : public FileResourceBase, public BuildGraphNode
{
public:
Artifact();
diff --git a/src/lib/corelib/buildgraph/buildgraph.cpp b/src/lib/corelib/buildgraph/buildgraph.cpp
index 2fd0bc28a..a12ef3410 100644
--- a/src/lib/corelib/buildgraph/buildgraph.cpp
+++ b/src/lib/corelib/buildgraph/buildgraph.cpp
@@ -93,19 +93,21 @@ public:
{
}
- void init(QScriptValue &productScriptValue, const ResolvedProductConstPtr &product)
+ void init(QScriptValue &productScriptValue, const ResolvedProductConstPtr &product,
+ PrepareScriptObserver *observer)
{
- QScriptValue depfunc = m_engine->newFunction(&js_productDependencies, product.data());
- setProduct(depfunc, product.data());
+ QScriptValue depfunc = m_engine->newFunction(&js_productDependencies, product.get());
+ setObserver(depfunc, observer);
productScriptValue.setProperty(QLatin1String("dependencies"), depfunc,
QScriptValue::ReadOnly | QScriptValue::Undeletable
| QScriptValue::PropertyGetter);
}
private:
- static QScriptValue js_productDependencies(QScriptContext *, ScriptEngine *engine,
+ static QScriptValue js_productDependencies(QScriptContext *ctx, ScriptEngine *engine,
const ResolvedProduct * const product)
{
+ const QString parametersKey = QStringLiteral("parameters");
QScriptValue result = engine->newArray();
quint32 idx = 0;
QList<ResolvedProductPtr> productDeps = product->dependencies.toList();
@@ -113,15 +115,30 @@ private:
[](const ResolvedProductPtr &p1, const ResolvedProductPtr &p2) {
return p1->name < p2->name;
});
+ PrepareScriptObserver *observer = getObserver(ctx->callee());
for (const ResolvedProductPtr &dependency : qAsConst(productDeps)) {
QScriptValue obj = engine->newObject();
setupProductScriptValue(static_cast<ScriptEngine *>(engine), obj, dependency, 0);
+
+ const QVariantMap &params = product->dependencyParameters.value(dependency);
+ obj.setProperty(parametersKey, params.isEmpty()
+ ? engine->newObject() : toScriptValue(engine, observer, params,
+ dependency->name));
+
result.setProperty(idx++, obj);
}
for (const ResolvedModuleConstPtr &dependency : qAsConst(product->modules)) {
+ if (dependency->isProduct)
+ continue;
QScriptValue obj = engine->newObject();
setupModuleScriptValue(static_cast<ScriptEngine *>(engine), obj,
product->moduleProperties->value(), dependency->name);
+
+ const QVariantMap &params = product->moduleParameters.value(dependency);
+ obj.setProperty(parametersKey, params.isEmpty()
+ ? engine->newObject() : toScriptValue(engine, observer, params,
+ dependency->name));
+
result.setProperty(idx++, obj);
}
return result;
@@ -163,14 +180,42 @@ private:
moduleScriptValue.setProperty(QStringLiteral("artifacts"), engine->newObject());
}
- static void setProduct(QScriptValue scriptValue, const ResolvedProduct *product)
+ static void setObserver(QScriptValue scriptValue, PrepareScriptObserver *observer)
+ {
+ attachPointerTo(scriptValue, observer);
+ }
+
+ static PrepareScriptObserver *getObserver(const QScriptValue &scriptValue)
{
- attachPointerTo(scriptValue, product);
+ return attachedPointer<PrepareScriptObserver>(scriptValue);
}
- static const ResolvedProduct *getProduct(const QScriptValue &scriptValue)
+ static QScriptValue toScriptValue(QScriptEngine *qScriptEngine, PrepareScriptObserver *observer,
+ const QVariantMap &v, const QString &depName)
{
- return attachedPointer<const ResolvedProduct>(scriptValue);
+ return toScriptValue(static_cast<ScriptEngine *>(qScriptEngine), observer, v, depName);
+ }
+
+ static QScriptValue toScriptValue(ScriptEngine *engine, PrepareScriptObserver *observer,
+ const QVariantMap &v, const QString &depName,
+ const QualifiedId &moduleName = QualifiedId())
+ {
+ QScriptValue obj = engine->newObject();
+ bool objIdAddedToObserver = false;
+ for (auto it = v.begin(); it != v.end(); ++it) {
+ if (it.value().type() == QVariant::Map) {
+ obj.setProperty(it.key(), toScriptValue(engine, observer, it.value().toMap(),
+ depName, QualifiedId(moduleName) << it.key()));
+ } else {
+ if (observer && !objIdAddedToObserver) {
+ objIdAddedToObserver = true;
+ observer->addParameterObjectId(obj.objectId(), depName, moduleName);
+ }
+ engine->setObservedProperty(obj, it.key(), engine->toScriptValue(it.value()),
+ observer);
+ }
+ }
+ return obj;
}
ScriptEngine *m_engine;
@@ -223,12 +268,12 @@ static void setupProductScriptValue(ScriptEngine *engine, QScriptValue &productS
{
ModuleProperties::init(productScriptValue, product);
- QScriptValue artifactsFunc = engine->newFunction(&js_productArtifacts, product.data());
+ QScriptValue artifactsFunc = engine->newFunction(&js_productArtifacts, product.get());
productScriptValue.setProperty(QStringLiteral("artifacts"), artifactsFunc,
QScriptValue::ReadOnly | QScriptValue::Undeletable
| QScriptValue::PropertyGetter);
- DependenciesFunction(engine).init(productScriptValue, product);
+ DependenciesFunction(engine).init(productScriptValue, product, observer);
if (observer)
observer->setProductObjectId(productScriptValue.objectId());
const QVariantMap &propMap = product->productProperties;
@@ -249,7 +294,8 @@ void setupScriptEngineForProduct(ScriptEngine *engine, const ResolvedProductCons
const ResolvedModuleConstPtr &module, QScriptValue targetObject,
PrepareScriptObserver *observer)
{
- QScriptValue projectScriptValue = setupProjectScriptValue(engine, product->project, observer);
+ QScriptValue projectScriptValue = setupProjectScriptValue(engine, product->project.lock(),
+ observer);
targetObject.setProperty(QLatin1String("project"), projectScriptValue);
if (observer)
observer->setProjectObjectId(projectScriptValue.objectId());
@@ -510,10 +556,10 @@ static void doSanityChecksForProduct(const ResolvedProductConstPtr &product,
QBS_CHECK(parent->children.contains(node));
for (BuildGraphNode * const child : qAsConst(node->children)) {
QBS_CHECK(child->parents.contains(node));
- QBS_CHECK(!child->product.isNull());
+ QBS_CHECK(!child->product.expired());
QBS_CHECK(!child->product->buildData.isNull());
QBS_CHECK(child->product->buildData->nodes.contains(child));
- QBS_CHECK(allProducts.contains(child->product));
+ QBS_CHECK(allProducts.contains(child->product.lock()));
}
Artifact * const artifact = dynamic_cast<Artifact *>(node);
diff --git a/src/lib/corelib/buildgraph/buildgraph.h b/src/lib/corelib/buildgraph/buildgraph.h
index 1d127af30..0620cebb2 100644
--- a/src/lib/corelib/buildgraph/buildgraph.h
+++ b/src/lib/corelib/buildgraph/buildgraph.h
@@ -41,6 +41,7 @@
#include "forward_decls.h"
#include <language/forward_decls.h>
+#include <tools/qbs_export.h>
#include <QtCore/qstringlist.h>
@@ -73,7 +74,7 @@ void dumpProductBuildData(const ResolvedProductConstPtr &product);
bool findPath(BuildGraphNode *u, BuildGraphNode *v, QList<BuildGraphNode*> &path);
-void connect(BuildGraphNode *p, BuildGraphNode *c);
+void QBS_AUTOTEST_EXPORT connect(BuildGraphNode *p, BuildGraphNode *c);
void loggedConnect(BuildGraphNode *u, BuildGraphNode *v, const Logger &logger);
bool safeConnect(Artifact *u, Artifact *v, const Logger &logger);
void removeGeneratedArtifactFromDisk(Artifact *artifact, const Logger &logger);
diff --git a/src/lib/corelib/buildgraph/buildgraph.pri b/src/lib/corelib/buildgraph/buildgraph.pri
index fabba661e..4229ad414 100644
--- a/src/lib/corelib/buildgraph/buildgraph.pri
+++ b/src/lib/corelib/buildgraph/buildgraph.pri
@@ -70,11 +70,6 @@ HEADERS += \
$$PWD/timestampsupdater.h \
$$PWD/transformer.h
-qbs_enable_unit_tests {
- HEADERS += $$PWD/tst_buildgraph.h
- SOURCES += $$PWD/tst_buildgraph.cpp
-}
-
!qbs_no_dev_install {
buildgraph_headers.files = $$PWD/forward_decls.h
buildgraph_headers.path = $${QBS_INSTALL_PREFIX}/include/qbs/buildgraph
diff --git a/src/lib/corelib/buildgraph/buildgraphloader.cpp b/src/lib/corelib/buildgraph/buildgraphloader.cpp
index 796565fe0..6b094164a 100644
--- a/src/lib/corelib/buildgraph/buildgraphloader.cpp
+++ b/src/lib/corelib/buildgraph/buildgraphloader.cpp
@@ -51,8 +51,10 @@
#include <language/language.h>
#include <language/loader.h>
#include <language/propertymapinternal.h>
+#include <language/qualifiedid.h>
#include <language/resolvedfilecontext.h>
#include <logging/translator.h>
+#include <tools/buildgraphlocker.h>
#include <tools/fileinfo.h>
#include <tools/persistence.h>
#include <tools/profiling.h>
@@ -67,8 +69,8 @@
namespace qbs {
namespace Internal {
-BuildGraphLoader::BuildGraphLoader(const QProcessEnvironment &env, const Logger &logger) :
- m_logger(logger), m_environment(env)
+BuildGraphLoader::BuildGraphLoader(const Logger &logger) :
+ m_logger(logger)
{
}
@@ -106,7 +108,8 @@ BuildGraphLoadResult BuildGraphLoader::load(const TopLevelProjectPtr &existingPr
if (existingProject) {
QBS_CHECK(existingProject->buildData);
existingProject->buildData->evaluationContext = evalContext;
- checkBuildGraphCompatibility(existingProject);
+ if (!checkBuildGraphCompatibility(existingProject))
+ return m_result;
m_result.loadedProject = existingProject;
} else {
loadBuildGraphFromDisk();
@@ -136,6 +139,21 @@ BuildGraphLoadResult BuildGraphLoader::load(const TopLevelProjectPtr &existingPr
return m_result;
}
+TopLevelProjectConstPtr BuildGraphLoader::loadProject(const QString &bgFilePath)
+{
+ class LogSink : public ILogSink {
+ void doPrintMessage(LoggerLevel, const QString &, const QString &) override { }
+ } dummySink;
+ Logger dummyLogger(&dummySink);
+ BuildGraphLocker bgLocker(bgFilePath, dummyLogger, false, nullptr);
+ PersistentPool pool(dummyLogger);
+ pool.load(bgFilePath);
+ const TopLevelProjectPtr project = TopLevelProject::create();
+ project->load(pool);
+ project->setBuildConfiguration(pool.headData().projectConfig);
+ return project;
+}
+
void BuildGraphLoader::loadBuildGraphFromDisk()
{
const QString projectId = TopLevelProject::deriveId(m_parameters.finalBuildConfigurationTree());
@@ -149,8 +167,10 @@ void BuildGraphLoader::loadBuildGraphFromDisk()
try {
pool.load(buildGraphFilePath);
} catch (const ErrorInfo &loadError) {
- if (m_parameters.restoreBehavior() == SetupProjectParameters::RestoreOnly)
+ if (m_parameters.restoreBehavior() == SetupProjectParameters::RestoreOnly
+ || m_parameters.projectFilePath().isEmpty()) {
throw;
+ }
m_logger.qbsInfo() << loadError.toString();
return;
}
@@ -164,7 +184,8 @@ void BuildGraphLoader::loadBuildGraphFromDisk()
project->buildData->evaluationContext = m_evalContext;
project->setBuildConfiguration(pool.headData().projectConfig);
project->buildDirectory = buildDir;
- checkBuildGraphCompatibility(project);
+ if (!checkBuildGraphCompatibility(project))
+ return;
restoreBackPointers(project);
project->location = CodeLocation(m_parameters.projectFilePath(), project->location.line(),
project->location.column());
@@ -173,23 +194,24 @@ void BuildGraphLoader::loadBuildGraphFromDisk()
doSanityChecks(project, m_logger);
}
-void BuildGraphLoader::checkBuildGraphCompatibility(const TopLevelProjectConstPtr &project)
+bool BuildGraphLoader::checkBuildGraphCompatibility(const TopLevelProjectConstPtr &project)
{
- if (QFileInfo(project->location.filePath()) != QFileInfo(m_parameters.projectFilePath())) {
- QString errorMessage = Tr::tr("Stored build graph at '%1' is for project file '%2', but "
- "input file is '%3'. ")
- .arg(QDir::toNativeSeparators(project->buildGraphFilePath()),
- QDir::toNativeSeparators(project->location.filePath()),
- QDir::toNativeSeparators(m_parameters.projectFilePath()));
- if (!m_parameters.ignoreDifferentProjectFilePath()) {
- errorMessage += Tr::tr("Aborting.");
- throw ErrorInfo(errorMessage);
- }
-
- // Okay, let's assume it's the same project anyway (the source dir might have moved).
- errorMessage += Tr::tr("Ignoring.");
- m_logger.qbsWarning() << errorMessage;
+ if (m_parameters.projectFilePath().isEmpty())
+ m_parameters.setProjectFilePath(project->location.filePath());
+ if (QFileInfo(project->location.filePath()) == QFileInfo(m_parameters.projectFilePath()))
+ return true;
+ QString message = Tr::tr("Stored build graph at '%1' is for project file '%2', but "
+ "input file is '%3'.")
+ .arg(QDir::toNativeSeparators(project->buildGraphFilePath()),
+ QDir::toNativeSeparators(project->location.filePath()),
+ QDir::toNativeSeparators(m_parameters.projectFilePath()));
+ if (m_parameters.overrideBuildGraphData()) {
+ m_logger.qbsInfo() << message;
+ return false;
}
+ message.append(QLatin1Char('\n')).append(Tr::tr("Use the 'resolve' command to enforce "
+ "using a different project file."));
+ throw ErrorInfo(message);
}
static bool checkProductForChangedDependency(QList<ResolvedProductPtr> &changedProducts,
@@ -230,7 +252,7 @@ void BuildGraphLoader::trackProjectChanges()
QList<ResolvedProductPtr> allRestoredProducts = restoredProject->allProducts();
QList<ResolvedProductPtr> changedProducts;
bool reResolvingNecessary = false;
- if (!isConfigCompatible())
+ if (!checkConfigCompatibility())
reResolvingNecessary = true;
if (hasProductFileChanged(allRestoredProducts, restoredProject->lastResolveTime,
buildSystemFiles, changedProducts)) {
@@ -258,6 +280,8 @@ void BuildGraphLoader::trackProjectChanges()
}
restoredProject->buildData->isDirty = true;
+ if (!m_parameters.overrideBuildGraphData())
+ m_parameters.setEnvironment(restoredProject->environment);
Loader ldr(m_evalContext->engine(), m_logger);
ldr.setSearchPaths(m_parameters.searchPaths());
ldr.setProgressObserver(m_evalContext->observer());
@@ -266,6 +290,8 @@ void BuildGraphLoader::trackProjectChanges()
for (const auto &restoredProduct : qAsConst(allRestoredProducts))
restoredProbes.insert(restoredProduct->uniqueName(), restoredProduct->probes);
ldr.setOldProductProbes(restoredProbes);
+ if (!m_parameters.overrideBuildGraphData())
+ ldr.setStoredProfiles(restoredProject->profileConfigs);
m_result.newlyResolvedProject = ldr.loadProject(m_parameters);
QMap<QString, ResolvedProductPtr> freshProductsByName;
@@ -274,13 +300,13 @@ void BuildGraphLoader::trackProjectChanges()
for (const ResolvedProductPtr &cp : qAsConst(allNewlyResolvedProducts))
freshProductsByName.insert(cp->uniqueName(), cp);
+ m_envChange = restoredProject->environment != m_result.newlyResolvedProject->environment;
checkAllProductsForChanges(allRestoredProducts, freshProductsByName, changedProducts);
- QSharedPointer<ProjectBuildData> oldBuildData;
+ std::shared_ptr<ProjectBuildData> oldBuildData;
ChildListHash childLists;
if (!changedProducts.isEmpty()) {
- oldBuildData = QSharedPointer<ProjectBuildData>(
- new ProjectBuildData(restoredProject->buildData.data()));
+ oldBuildData = std::make_shared<ProjectBuildData>(restoredProject->buildData.data());
for (const ResolvedProductConstPtr &product : qAsConst(allRestoredProducts)) {
if (!product->buildData)
continue;
@@ -357,13 +383,13 @@ void BuildGraphLoader::trackProjectChanges()
childLists, rescuableArtifactData.value(changedProduct->uniqueName()));
}
- EmptyDirectoriesRemover(m_result.newlyResolvedProject.data(), m_logger)
+ EmptyDirectoriesRemover(m_result.newlyResolvedProject.get(), m_logger)
.removeEmptyParentDirectories(m_artifactsRemovedFromDisk);
for (FileResourceBase * const f : qAsConst(m_objectsToDelete)) {
Artifact * const a = dynamic_cast<Artifact *>(f);
if (a)
- a->product.clear(); // To help with the sanity checks.
+ a->product.reset(); // To help with the sanity checks.
}
doSanityChecks(m_result.newlyResolvedProject, m_logger);
}
@@ -388,8 +414,10 @@ bool BuildGraphLoader::probeExecutionForced(
bool BuildGraphLoader::hasEnvironmentChanged(const TopLevelProjectConstPtr &restoredProject) const
{
+ if (!m_parameters.overrideBuildGraphData())
+ return false;
QProcessEnvironment oldEnv = restoredProject->environment;
- QProcessEnvironment newEnv = m_environment;
+ QProcessEnvironment newEnv = m_parameters.adjustedEnvironment();
// HACK. Valgrind screws up our null-build benchmarker otherwise.
// TODO: Think about a (module-provided) whitelist.
@@ -399,7 +427,7 @@ bool BuildGraphLoader::hasEnvironmentChanged(const TopLevelProjectConstPtr &rest
if (oldEnv != newEnv) {
m_logger.qbsDebug() << "Set of environment variables changed. Must re-resolve project.";
m_logger.qbsTrace() << "old: " << restoredProject->environment.toStringList() << "\nnew:"
- << m_environment.toStringList();
+ << m_parameters.adjustedEnvironment().toStringList();
return true;
}
return false;
@@ -641,7 +669,7 @@ bool BuildGraphLoader::checkForPropertyChanges(const ResolvedProductPtr &restore
return false;
// This check must come first, as it can prevent build data rescuing.
- if (checkTransformersForPropertyChanges(restoredProduct, newlyResolvedProduct))
+ if (checkTransformersForChanges(restoredProduct, newlyResolvedProduct))
return true;
if (restoredProduct->fileTags != newlyResolvedProduct->fileTags) {
@@ -659,7 +687,7 @@ bool BuildGraphLoader::checkForPropertyChanges(const ResolvedProductPtr &restore
return false;
}
-bool BuildGraphLoader::checkTransformersForPropertyChanges(const ResolvedProductPtr &restoredProduct,
+bool BuildGraphLoader::checkTransformersForChanges(const ResolvedProductPtr &restoredProduct,
const ResolvedProductPtr &newlyResolvedProduct)
{
bool transformerChanges = false;
@@ -668,11 +696,12 @@ bool BuildGraphLoader::checkTransformersForPropertyChanges(const ResolvedProduct
const TransformerPtr transformer = artifact->transformer;
if (!transformer || !seenTransformers.insert(transformer).second)
continue;
- if (checkForPropertyChanges(transformer, newlyResolvedProduct))
+ if (checkForPropertyChanges(transformer, newlyResolvedProduct)
+ || checkForEnvChanges(transformer))
transformerChanges = true;
}
if (transformerChanges) {
- m_logger.qbsDebug() << "Property changes in product '"
+ m_logger.qbsDebug() << "Property or environment changes in product '"
<< newlyResolvedProduct->uniqueName() << "'.";
}
return transformerChanges;
@@ -719,15 +748,35 @@ static SourceArtifactConstPtr findSourceArtifact(const ResolvedProductConstPtr &
return artifact;
}
-static QVariantMap propertyMapByKind(const ResolvedProductConstPtr &product, Property::Kind kind)
+template<typename T> static QVariantMap getParameterValue(
+ const QHash<T, QVariantMap> &parameters,
+ const QString &depName)
+{
+ for (auto it = parameters.cbegin(); it != parameters.cend(); ++it) {
+ if (it.key()->name == depName)
+ return it.value();
+ }
+ return QVariantMap();
+}
+
+static QVariantMap propertyMapByKind(const ResolvedProductConstPtr &product,
+ const Property &property)
{
- switch (kind) {
+ switch (property.kind) {
case Property::PropertyInModule:
return product->moduleProperties->value();
case Property::PropertyInProduct:
return product->productProperties;
case Property::PropertyInProject:
return product->project->projectProperties();
+ case Property::PropertyInParameters: {
+ const int sepIndex = property.moduleName.indexOf(QLatin1Char(':'));
+ const QString depName = property.moduleName.left(sepIndex);
+ QVariantMap v = getParameterValue(product->dependencyParameters, depName);
+ if (!v.isEmpty())
+ return v;
+ return getParameterValue(product->moduleParameters, depName);
+ }
default:
QBS_CHECK(false);
}
@@ -747,7 +796,7 @@ bool BuildGraphLoader::checkForPropertyChanges(const TransformerPtr &restoredTra
{
// This check must come first, as it can prevent build data rescuing.
for (const Property &property : qAsConst(restoredTrafo->propertiesRequestedInCommands)) {
- if (checkForPropertyChange(property, propertyMapByKind(freshProduct, property.kind))) {
+ if (checkForPropertyChange(property, propertyMapByKind(freshProduct, property))) {
invalidateTransformer(restoredTrafo);
return true;
}
@@ -769,7 +818,7 @@ bool BuildGraphLoader::checkForPropertyChanges(const TransformerPtr &restoredTra
}
for (const Property &property : qAsConst(restoredTrafo->propertiesRequestedInPrepareScript)) {
- if (checkForPropertyChange(property, propertyMapByKind(freshProduct, property.kind)))
+ if (checkForPropertyChange(property, propertyMapByKind(freshProduct, property)))
return true;
}
@@ -788,6 +837,25 @@ bool BuildGraphLoader::checkForPropertyChanges(const TransformerPtr &restoredTra
return false;
}
+bool BuildGraphLoader::checkForEnvChanges(const TransformerPtr &restoredTrafo)
+{
+ if (!m_envChange)
+ return false;
+ // TODO: Also check results of getEnv() from commands here; we currently do not track them
+ for (const AbstractCommandPtr &c : qAsConst(restoredTrafo->commands)) {
+ if (c->type() != AbstractCommand::ProcessCommandType)
+ continue;
+ for (const QString &var : std::static_pointer_cast<ProcessCommand>(c)->relevantEnvVars()) {
+ if (restoredTrafo->product()->topLevelProject()->environment.value(var)
+ != m_result.newlyResolvedProject->environment.value(var)) {
+ invalidateTransformer(restoredTrafo);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
bool BuildGraphLoader::checkForPropertyChange(const Property &restoredProperty,
const QVariantMap &newProperties)
{
@@ -801,6 +869,15 @@ bool BuildGraphLoader::checkForPropertyChange(const Property &restoredProperty,
v = moduleProperty(newProperties, restoredProperty.moduleName,
restoredProperty.propertyName);
break;
+ case Property::PropertyInParameters: {
+ const int sepIndex = restoredProperty.moduleName.indexOf(QLatin1Char(':'));
+ QualifiedId moduleName
+ = QualifiedId::fromString(restoredProperty.moduleName.mid(sepIndex + 1));
+ QVariantMap map = newProperties;
+ while (!moduleName.isEmpty())
+ map = map.value(moduleName.takeFirst()).toMap();
+ v = map.value(restoredProperty.propertyName);
+ }
}
if (restoredProperty.value != v) {
m_logger.qbsDebug() << "Value for property '" << restoredProperty.moduleName << "."
@@ -833,9 +910,31 @@ void BuildGraphLoader::replaceFileDependencyWithArtifact(const ResolvedProductPt
m_objectsToDelete << filedep;
}
-bool BuildGraphLoader::isConfigCompatible()
+bool BuildGraphLoader::checkConfigCompatibility()
{
const TopLevelProjectConstPtr restoredProject = m_result.loadedProject;
+ if (!m_parameters.overrideBuildGraphData()) {
+ if (!m_parameters.overriddenValues().isEmpty()
+ && m_parameters.overriddenValues() != restoredProject->overriddenValues) {
+ throw ErrorInfo(Tr::tr("Property values set on the command line differ from the "
+ "ones used for the previous build. Use the 'resolve' command if "
+ "you really want to rebuild with the new properties."));
+ }
+ m_parameters.setOverriddenValues(restoredProject->overriddenValues);
+ if (!m_parameters.topLevelProfile().isEmpty()
+ && m_parameters.topLevelProfile() != restoredProject->profile()) {
+ throw ErrorInfo(Tr::tr("The current profile is '%1', but profile '%2' was used "
+ "when last building for configuration '%3'. Use the "
+ "'resolve' command if you really want to rebuild with a "
+ "different profile.")
+ .arg(m_parameters.topLevelProfile(), restoredProject->profile(),
+ m_parameters.configurationName()));
+ }
+ m_parameters.setTopLevelProfile(restoredProject->profile());
+ m_parameters.expandBuildConfiguration();
+ }
+ if (!m_parameters.overrideBuildGraphData())
+ return true;
if (m_parameters.finalBuildConfigurationTree() != restoredProject->buildConfiguration())
return false;
for (QVariantMap::ConstIterator it = restoredProject->profileConfigs.constBegin();
@@ -843,7 +942,7 @@ bool BuildGraphLoader::isConfigCompatible()
const QVariantMap buildConfig = SetupProjectParameters::expandedBuildConfiguration(
m_parameters.settingsDirectory(), it.key(), m_parameters.configurationName());
const QVariantMap newConfig = SetupProjectParameters::finalBuildConfigurationTree(
- buildConfig, m_parameters.overriddenValues(), m_parameters.buildRoot());
+ buildConfig, m_parameters.overriddenValues());
if (newConfig != it.value())
return false;
}
diff --git a/src/lib/corelib/buildgraph/buildgraphloader.h b/src/lib/corelib/buildgraph/buildgraphloader.h
index c64b05c16..c2b2f1f55 100644
--- a/src/lib/corelib/buildgraph/buildgraphloader.h
+++ b/src/lib/corelib/buildgraph/buildgraphloader.h
@@ -70,16 +70,18 @@ public:
class BuildGraphLoader
{
public:
- BuildGraphLoader(const QProcessEnvironment &env, const Logger &logger);
+ BuildGraphLoader(const Logger &logger);
~BuildGraphLoader();
BuildGraphLoadResult load(const TopLevelProjectPtr &existingProject,
const SetupProjectParameters &parameters,
const RulesEvaluationContextPtr &evalContext);
+ static TopLevelProjectConstPtr loadProject(const QString &bgFilePath);
+
private:
void loadBuildGraphFromDisk();
- void checkBuildGraphCompatibility(const TopLevelProjectConstPtr &project);
+ bool checkBuildGraphCompatibility(const TopLevelProjectConstPtr &project);
void trackProjectChanges();
bool probeExecutionForced(const TopLevelProjectConstPtr &restoredProject,
const QList<ResolvedProductPtr> &restoredProducts) const;
@@ -103,17 +105,18 @@ private:
const ResolvedProductPtr &newlyResolvedProduct);
bool checkForPropertyChanges(const ResolvedProductPtr &restoredProduct,
const ResolvedProductPtr &newlyResolvedProduct);
- bool checkTransformersForPropertyChanges(const ResolvedProductPtr &restoredProduct,
+ bool checkTransformersForChanges(const ResolvedProductPtr &restoredProduct,
const ResolvedProductPtr &newlyResolvedProduct);
void onProductRemoved(const ResolvedProductPtr &product, ProjectBuildData *projectBuildData,
bool removeArtifactsFromDisk = true);
bool checkForPropertyChanges(const TransformerPtr &restoredTrafo,
const ResolvedProductPtr &freshProduct);
+ bool checkForEnvChanges(const TransformerPtr &restoredTrafo);
bool checkForPropertyChange(const Property &restoredProperty,
const QVariantMap &newProperties);
void replaceFileDependencyWithArtifact(const ResolvedProductPtr &fileDepProduct,
FileDependency *filedep, Artifact *artifact);
- bool isConfigCompatible();
+ bool checkConfigCompatibility();
bool isPrepareScriptUpToDate(const ScriptFunctionConstPtr &script,
const FileTime &referenceTime);
@@ -134,13 +137,14 @@ private:
SetupProjectParameters m_parameters;
BuildGraphLoadResult m_result;
Logger m_logger;
- QProcessEnvironment m_environment;
QStringList m_artifactsRemovedFromDisk;
qint64 m_wildcardExpansionEffort;
qint64 m_propertyComparisonEffort;
// These must only be deleted at the end so we can still peek into the old look-up table.
QList<FileResourceBase *> m_objectsToDelete;
+
+ bool m_envChange = false;
};
} // namespace Internal
diff --git a/src/lib/corelib/buildgraph/cycledetector.h b/src/lib/corelib/buildgraph/cycledetector.h
index a3275e0d5..d280f6ecd 100644
--- a/src/lib/corelib/buildgraph/cycledetector.h
+++ b/src/lib/corelib/buildgraph/cycledetector.h
@@ -49,7 +49,7 @@ namespace Internal {
class BuildGraphNode;
-class CycleDetector : private BuildGraphVisitor
+class QBS_AUTOTEST_EXPORT CycleDetector : private BuildGraphVisitor
{
public:
CycleDetector(const Logger &logger);
diff --git a/src/lib/corelib/buildgraph/depscanner.cpp b/src/lib/corelib/buildgraph/depscanner.cpp
index fddacfc5d..2ca4c3e5f 100644
--- a/src/lib/corelib/buildgraph/depscanner.cpp
+++ b/src/lib/corelib/buildgraph/depscanner.cpp
@@ -189,7 +189,7 @@ bool UserDependencyScanner::recursive() const
const void *UserDependencyScanner::key() const
{
- return m_scanner.data();
+ return m_scanner.get();
}
QString UserDependencyScanner::createId() const
@@ -226,9 +226,9 @@ QStringList UserDependencyScanner::evaluate(Artifact *artifact, const ScriptFunc
{
ScriptEngineActiveFlagGuard guard(m_engine);
- if (artifact->product.data() != m_product) {
- m_product = artifact->product.data();
- setupScriptEngineForProduct(m_engine, artifact->product,
+ if (artifact->product.get() != m_product) {
+ m_product = artifact->product.get();
+ setupScriptEngineForProduct(m_engine, artifact->product.lock(),
m_scanner->module, m_global, &m_observer);
}
diff --git a/src/lib/corelib/buildgraph/depscanner.h b/src/lib/corelib/buildgraph/depscanner.h
index 08b779536..6ab577839 100644
--- a/src/lib/corelib/buildgraph/depscanner.h
+++ b/src/lib/corelib/buildgraph/depscanner.h
@@ -117,7 +117,7 @@ private:
ScriptEngine *m_engine;
PrepareScriptObserver m_observer;
QScriptValue m_global;
- void *m_product;
+ ResolvedProduct *m_product;
};
} // namespace Internal
diff --git a/src/lib/corelib/buildgraph/executor.cpp b/src/lib/corelib/buildgraph/executor.cpp
index 29b963778..7b98eb909 100644
--- a/src/lib/corelib/buildgraph/executor.cpp
+++ b/src/lib/corelib/buildgraph/executor.cpp
@@ -231,9 +231,9 @@ void Executor::doBuild()
= m_project->buildData->lookupFiles(fileToConsider);
for (const FileResourceBase * const file : files) {
const Artifact * const artifact = dynamic_cast<const Artifact *>(file);
- if (artifact && m_productsToBuild.contains(artifact->product)) {
+ if (artifact && m_productsToBuild.contains(artifact->product.lock())) {
m_tagsOfFilesToConsider.unite(artifact->fileTags());
- m_productsOfFilesToConsider << artifact->product;
+ m_productsOfFilesToConsider << artifact->product.lock();
}
}
}
@@ -717,7 +717,7 @@ void Executor::doSanityChecks()
QBS_CHECK(!m_productsToBuild.isEmpty());
for (const ResolvedProductConstPtr &product : qAsConst(m_productsToBuild)) {
QBS_CHECK(product->buildData);
- QBS_CHECK(product->topLevelProject() == m_project);
+ QBS_CHECK(product->topLevelProject() == m_project.get());
}
}
@@ -760,7 +760,7 @@ void Executor::rescueOldBuildData(Artifact *artifact, bool *childrenAdded = 0)
if (artifact->artifactType != Artifact::Generated)
return;
- ResolvedProduct * const product = artifact->product.data();
+ ResolvedProduct * const product = artifact->product.get();
AllRescuableArtifactData::Iterator it
= product->buildData->rescuableArtifactData.find(artifact->filePath());
if (it == product->buildData->rescuableArtifactData.end())
@@ -951,7 +951,7 @@ void Executor::runTransformer(const TransformerPtr &transformer)
for (Artifact * const artifact : qAsConst(transformer->outputs))
artifact->buildState = BuildGraphNode::Building;
m_processingJobs.insert(job, transformer);
- job->run(transformer.data());
+ job->run(transformer.get());
}
void Executor::finishTransformer(const TransformerPtr &transformer)
@@ -1044,7 +1044,7 @@ void Executor::checkForUnbuiltProducts()
bool Executor::checkNodeProduct(BuildGraphNode *node)
{
- if (!m_partialBuild || m_productsToBuild.contains(node->product))
+ if (!m_partialBuild || m_productsToBuild.contains(node->product.lock()))
return true;
// TODO: Turn this into a warning once we have a reliable C++ scanner.
@@ -1073,7 +1073,7 @@ void Executor::finish()
m_cancelationTimer->stop();
}
- EmptyDirectoriesRemover(m_project.data(), m_logger)
+ EmptyDirectoriesRemover(m_project.get(), m_logger)
.removeEmptyParentDirectories(m_artifactsRemovedFromDisk);
if (m_buildOptions.logElapsedTime()) {
@@ -1160,10 +1160,10 @@ void Executor::setupForBuildingSelectedFiles(const BuildGraphNode *node)
return;
if (m_buildOptions.filesToConsider().isEmpty())
return;
- if (!m_productsOfFilesToConsider.contains(node->product))
+ if (!m_productsOfFilesToConsider.contains(node->product.lock()))
return;
const RuleNode * const ruleNode = static_cast<const RuleNode *>(node);
- const Rule * const rule = ruleNode->rule().data();
+ const Rule * const rule = ruleNode->rule().get();
if (rule->inputs.intersects(m_tagsOfFilesToConsider)) {
FileTags otherInputs = rule->auxiliaryInputs;
otherInputs.unite(rule->explicitlyDependsOn).subtract(rule->excludedAuxiliaryInputs);
@@ -1200,7 +1200,7 @@ void Executor::prepareReachableNodes_impl(BuildGraphNode *node)
void Executor::prepareProducts()
{
- ProductPrioritySetter prioritySetter(m_project.data());
+ ProductPrioritySetter prioritySetter(m_project.get());
prioritySetter.apply();
for (const ResolvedProductPtr &product : qAsConst(m_productsToBuild))
product->setupBuildEnvironment(m_evalContext->engine(), m_project->environment);
diff --git a/src/lib/corelib/buildgraph/executorjob.cpp b/src/lib/corelib/buildgraph/executorjob.cpp
index 56c9a8ac3..628426adf 100644
--- a/src/lib/corelib/buildgraph/executorjob.cpp
+++ b/src/lib/corelib/buildgraph/executorjob.cpp
@@ -139,7 +139,7 @@ void ExecutorJob::runNextCommand()
qFatal("Missing implementation for command type %d", command->type());
}
- m_currentCommandExecutor->start(m_transformer, command.data());
+ m_currentCommandExecutor->start(m_transformer, command.get());
}
void ExecutorJob::onCommandFinished(const ErrorInfo &err)
diff --git a/src/lib/corelib/buildgraph/forward_decls.h b/src/lib/corelib/buildgraph/forward_decls.h
index c24944fe3..fe35cd89a 100644
--- a/src/lib/corelib/buildgraph/forward_decls.h
+++ b/src/lib/corelib/buildgraph/forward_decls.h
@@ -39,7 +39,7 @@
#ifndef QBS_BG_FORWARD_DECLS_H
#define QBS_BG_FORWARD_DECLS_H
-#include <QtCore/qsharedpointer.h>
+#include <memory>
namespace qbs {
namespace Internal {
@@ -51,20 +51,20 @@ class ProductBuildData;
class Node;
class Transformer;
-typedef QSharedPointer<Transformer> TransformerPtr;
-typedef QSharedPointer<const Transformer> TransformerConstPtr;
+typedef std::shared_ptr<Transformer> TransformerPtr;
+typedef std::shared_ptr<const Transformer> TransformerConstPtr;
class RulesEvaluationContext;
-typedef QSharedPointer<RulesEvaluationContext> RulesEvaluationContextPtr;
+typedef std::shared_ptr<RulesEvaluationContext> RulesEvaluationContextPtr;
class AbstractCommand;
-typedef QSharedPointer<AbstractCommand> AbstractCommandPtr;
+typedef std::shared_ptr<AbstractCommand> AbstractCommandPtr;
class ProcessCommand;
-typedef QSharedPointer<ProcessCommand> ProcessCommandPtr;
+typedef std::shared_ptr<ProcessCommand> ProcessCommandPtr;
class JavaScriptCommand;
-typedef QSharedPointer<JavaScriptCommand> JavaScriptCommandPtr;
+typedef std::shared_ptr<JavaScriptCommand> JavaScriptCommandPtr;
template<typename T> class Set;
using ArtifactSet = Set<Artifact *>;
diff --git a/src/lib/corelib/buildgraph/inputartifactscanner.cpp b/src/lib/corelib/buildgraph/inputartifactscanner.cpp
index 203edb0da..6b545dd24 100644
--- a/src/lib/corelib/buildgraph/inputartifactscanner.cpp
+++ b/src/lib/corelib/buildgraph/inputartifactscanner.cpp
@@ -72,7 +72,7 @@ static void resolveDepencency(const RawScannedDependency &dependency,
if (!dependency.isClean())
absDirPath = QDir::cleanPath(absDirPath);
- ResolvedProject *project = product->project.data();
+ ResolvedProject *project = product->project.get();
FileDependency *fileDependencyArtifact = 0;
Artifact *dependencyInProduct = 0;
Artifact *dependencyInOtherProduct = 0;
@@ -179,7 +179,7 @@ void InputArtifactScanner::scanForFileDependencies(Artifact *inputArtifact)
Set<DependencyScanner *> InputArtifactScanner::scannersForArtifact(const Artifact *artifact) const
{
Set<DependencyScanner *> scanners;
- ResolvedProduct *product = artifact->product.data();
+ ResolvedProduct *product = artifact->product.get();
ScriptEngine *engine = product->topLevelProject()->buildData->evaluationContext->engine();
QHash<FileTag, InputArtifactScannerContext::DependencyScannerCacheItem> &scannerCache
= m_context->scannersCache[product];
@@ -200,7 +200,7 @@ Set<DependencyScanner *> InputArtifactScanner::scannersForArtifact(const Artifac
}
}
for (const DependencyScannerPtr &scanner : qAsConst(cache.scanners))
- scanners += scanner.data();
+ scanners += scanner.get();
}
return scanners;
}
@@ -262,13 +262,13 @@ void InputArtifactScanner::resolveScanResultDependencies(const Artifact *inputAr
cachedResolvedDependencyItem.valid = true;
if (FileInfo::isAbsolute(dependencyFilePath)) {
- resolveDepencency(dependency, inputArtifact->product.data(), &resolvedDependency);
+ resolveDepencency(dependency, inputArtifact->product.get(), &resolvedDependency);
goto resolved;
}
// try include paths
for (const QString &includePath : cache.searchPaths) {
- resolveDepencency(dependency, inputArtifact->product.data(),
+ resolveDepencency(dependency, inputArtifact->product.get(),
&resolvedDependency, includePath);
if (resolvedDependency.isValid())
goto resolved;
@@ -298,7 +298,7 @@ resolved:
void InputArtifactScanner::handleDependency(ResolvedDependency &dependency)
{
- const ResolvedProductPtr product = m_artifact->product;
+ const ResolvedProductPtr product = m_artifact->product.lock();
QBS_CHECK(m_artifact->artifactType == Artifact::Generated);
QBS_CHECK(product);
diff --git a/src/lib/corelib/buildgraph/inputartifactscanner.h b/src/lib/corelib/buildgraph/inputartifactscanner.h
index 6d82f97ec..54e2db0ad 100644
--- a/src/lib/corelib/buildgraph/inputartifactscanner.h
+++ b/src/lib/corelib/buildgraph/inputartifactscanner.h
@@ -60,7 +60,7 @@ class RawScanResults;
class PropertyMapInternal;
class DependencyScanner;
-typedef QSharedPointer<DependencyScanner> DependencyScannerPtr;
+typedef std::shared_ptr<DependencyScanner> DependencyScannerPtr;
class ResolvedDependency
{
diff --git a/src/lib/corelib/buildgraph/processcommandexecutor.cpp b/src/lib/corelib/buildgraph/processcommandexecutor.cpp
index 6fecb73a4..4b435e71f 100644
--- a/src/lib/corelib/buildgraph/processcommandexecutor.cpp
+++ b/src/lib/corelib/buildgraph/processcommandexecutor.cpp
@@ -336,11 +336,14 @@ void ProcessCommandExecutor::onProcessFinished()
static QString environmentVariableString(const QString &key, const QString &value)
{
QString str;
- if (HostOsInfo::isAnyUnixHost())
- str += QStringLiteral("export ");
if (HostOsInfo::isWindowsHost())
str += QStringLiteral("set ");
- return str + shellQuote(key + QLatin1Char('=') + value) + QLatin1Char('\n');
+ str += shellQuote(key + QLatin1Char('=') + value);
+ if (HostOsInfo::isWindowsHost())
+ str += QLatin1Char('\n');
+ else
+ str += QLatin1Char(' ');
+ return str;
}
void ProcessCommandExecutor::doReportCommandDescription()
diff --git a/src/lib/corelib/buildgraph/productbuilddata.h b/src/lib/corelib/buildgraph/productbuilddata.h
index 1bac76593..6027de282 100644
--- a/src/lib/corelib/buildgraph/productbuilddata.h
+++ b/src/lib/corelib/buildgraph/productbuilddata.h
@@ -53,7 +53,7 @@ namespace Internal {
class Logger;
-class ProductBuildData : public PersistentObject
+class QBS_AUTOTEST_EXPORT ProductBuildData : public PersistentObject
{
public:
~ProductBuildData();
diff --git a/src/lib/corelib/buildgraph/productinstaller.cpp b/src/lib/corelib/buildgraph/productinstaller.cpp
index 935bdd0b1..1688dcc76 100644
--- a/src/lib/corelib/buildgraph/productinstaller.cpp
+++ b/src/lib/corelib/buildgraph/productinstaller.cpp
@@ -84,7 +84,7 @@ ProductInstaller::ProductInstaller(const TopLevelProjectPtr &project,
if (m_options.removeExistingInstallation())
throw ErrorInfo(Tr::tr("Refusing to remove sysroot."));
}
- initInstallRoot(project.data(), m_options);
+ initInstallRoot(project.get(), m_options);
}
void ProductInstaller::install()
@@ -125,6 +125,8 @@ QString ProductInstaller::targetFilePath(const TopLevelProject *project,
= properties->qbsPropertyValue(QLatin1String("installSourceBase")).toString();
initInstallRoot(project, options);
QString targetDir = options.installRoot();
+ if (targetDir.isEmpty())
+ targetDir = properties->qbsPropertyValue(QLatin1String("installRoot")).toString();
targetDir.append(QLatin1Char('/')).append(installPrefix)
.append(QLatin1Char('/')).append(relativeInstallDir);
targetDir = QDir::cleanPath(targetDir);
@@ -190,7 +192,7 @@ void ProductInstaller::copyFile(const Artifact *artifact)
.arg(m_products.first()->project->topLevelProject()->id()));
}
- const QString targetFilePath = this->targetFilePath(m_project.data(),
+ const QString targetFilePath = this->targetFilePath(m_project.get(),
artifact->product->sourceDirectory, artifact->filePath(),
artifact->properties, m_options);
const QString targetDir = FileInfo::path(targetFilePath);
diff --git a/src/lib/corelib/buildgraph/projectbuilddata.cpp b/src/lib/corelib/buildgraph/projectbuilddata.cpp
index bb120b9f2..25b2651a9 100644
--- a/src/lib/corelib/buildgraph/projectbuilddata.cpp
+++ b/src/lib/corelib/buildgraph/projectbuilddata.cpp
@@ -96,6 +96,7 @@ QString ProjectBuildData::deriveBuildGraphFilePath(const QString &buildDir, cons
static QString productNameForErrorMessage(const ResolvedProduct *product)
{
return product->profile == product->topLevelProject()->profile()
+ && product->multiplexConfigurationId.isEmpty()
? product->name : product->uniqueName();
}
@@ -112,10 +113,10 @@ void ProjectBuildData::insertIntoLookupTable(FileResourceBase *fileres)
error.append(Tr::tr("Conflicting artifacts for file path '%1'.")
.arg(artifact->filePath()));
error.append(Tr::tr("The first artifact comes from product '%1'.")
- .arg(productNameForErrorMessage(otherArtifact->product.data())),
+ .arg(productNameForErrorMessage(otherArtifact->product.get())),
otherArtifact->product->location);
error.append(Tr::tr("The second artifact comes from product '%1'.")
- .arg(productNameForErrorMessage(artifact->product.data())),
+ .arg(productNameForErrorMessage(artifact->product.get())),
artifact->product->location);
throw error;
}
@@ -357,7 +358,7 @@ private:
void visit(const RuleConstPtr &parentRule, const RuleConstPtr &rule)
{
- if (!m_rulesOnPath.insert(rule.data()).second) {
+ if (!m_rulesOnPath.insert(rule.get()).second) {
QString pathstr;
for (const Rule *r : qAsConst(m_rulePath)) {
pathstr += QLatin1Char('\n') + r->toString() + QLatin1Char('\t')
@@ -365,7 +366,7 @@ private:
}
throw ErrorInfo(Tr::tr("Cycle detected in rule dependencies: %1").arg(pathstr));
}
- m_rulePath.append(rule.data());
+ m_rulePath.append(rule.get());
RuleNode *node = m_nodePerRule.value(rule);
if (!node) {
node = new RuleNode;
@@ -391,15 +392,22 @@ private:
void endVisit(const RuleConstPtr &rule)
{
- m_rulesOnPath.remove(rule.data());
+ m_rulesOnPath.remove(rule.get());
m_rulePath.removeLast();
}
};
static bool areRulesCompatible(const RuleNode *ruleNode, const RuleNode *dependencyRule)
{
- return ruleNode->rule()->inputsFromDependencies.intersects(
- dependencyRule->rule()->collectedOutputFileTags());
+ const FileTags outTags = dependencyRule->rule()->collectedOutputFileTags();
+ if (ruleNode->rule()->inputsFromDependencies.intersects(outTags))
+ return true;
+ if (!dependencyRule->product->fileTags.intersects(outTags))
+ return false;
+ if (ruleNode->rule()->explicitlyDependsOn.intersects(outTags))
+ return true;
+ return ruleNode->rule()->auxiliaryInputs.intersects(outTags)
+ && !ruleNode->rule()->excludedAuxiliaryInputs.intersects(outTags);
}
void BuildDataResolver::resolveProductBuildData(const ResolvedProductPtr &product)
diff --git a/src/lib/corelib/buildgraph/projectbuilddata.h b/src/lib/corelib/buildgraph/projectbuilddata.h
index ebcdf53fc..12c943880 100644
--- a/src/lib/corelib/buildgraph/projectbuilddata.h
+++ b/src/lib/corelib/buildgraph/projectbuilddata.h
@@ -59,7 +59,7 @@ class FileDependency;
class FileResourceBase;
class ScriptEngine;
-class ProjectBuildData : public PersistentObject
+class QBS_AUTOTEST_EXPORT ProjectBuildData : public PersistentObject
{
public:
ProjectBuildData(const ProjectBuildData *other = 0);
diff --git a/src/lib/corelib/buildgraph/qtmocscanner.cpp b/src/lib/corelib/buildgraph/qtmocscanner.cpp
index ccb959a0f..bc3df54f5 100644
--- a/src/lib/corelib/buildgraph/qtmocscanner.cpp
+++ b/src/lib/corelib/buildgraph/qtmocscanner.cpp
@@ -46,6 +46,7 @@
#include "rawscanresults.h"
#include <language/scriptengine.h>
#include <logging/translator.h>
+#include <plugins/scanner/scanner.h>
#include <tools/fileinfo.h>
#include <tools/scannerpluginmanager.h>
#include <tools/scripttools.h>
diff --git a/src/lib/corelib/buildgraph/rescuableartifactdata.h b/src/lib/corelib/buildgraph/rescuableartifactdata.h
index 1a6b33cdc..0058885a1 100644
--- a/src/lib/corelib/buildgraph/rescuableartifactdata.h
+++ b/src/lib/corelib/buildgraph/rescuableartifactdata.h
@@ -54,7 +54,7 @@ namespace qbs {
namespace Internal {
class PersistentPool;
-class RescuableArtifactData
+class QBS_AUTOTEST_EXPORT RescuableArtifactData
{
public:
~RescuableArtifactData();
diff --git a/src/lib/corelib/buildgraph/rulecommands.cpp b/src/lib/corelib/buildgraph/rulecommands.cpp
index 73f5fcfc3..6419d4e58 100644
--- a/src/lib/corelib/buildgraph/rulecommands.cpp
+++ b/src/lib/corelib/buildgraph/rulecommands.cpp
@@ -40,6 +40,7 @@
#include "rulecommands.h"
#include <logging/translator.h>
#include <tools/error.h>
+#include <tools/fileinfo.h>
#include <tools/hostosinfo.h>
#include <tools/persistence.h>
#include <tools/qbsassert.h>
@@ -235,6 +236,7 @@ bool ProcessCommand::equals(const AbstractCommand *otherAbstractCommand) const
&& m_responseFileUsagePrefix == other->m_responseFileUsagePrefix
&& m_stdoutFilePath == other->m_stdoutFilePath
&& m_stderrFilePath == other->m_stderrFilePath
+ && m_relevantEnvVars == other->m_relevantEnvVars
&& m_environment == other->m_environment;
}
@@ -259,6 +261,8 @@ void ProcessCommand::fillFromScriptValue(const QScriptValue *scriptValue, const
+ QLatin1String(")()");
else
m_stderrFilterFunction = stderrFilterFunction.toString();
+ m_relevantEnvVars = scriptValue->property(QLatin1String("relevantEnvironmentVariables"))
+ .toVariant().toStringList();
m_responseFileThreshold = scriptValue->property(QLatin1String("responseFileThreshold"))
.toInt32();
m_responseFileArgumentIndex = scriptValue->property(QLatin1String("responseFileArgumentIndex"))
@@ -287,6 +291,14 @@ void ProcessCommand::fillFromScriptValue(const QScriptValue *scriptValue, const
applyCommandProperties(scriptValue);
}
+QStringList ProcessCommand::relevantEnvVars() const
+{
+ QStringList vars = m_relevantEnvVars;
+ if (!FileInfo::isAbsolute(program()))
+ vars << QLatin1String("PATH");
+ return vars;
+}
+
void ProcessCommand::load(PersistentPool &pool)
{
AbstractCommand::load(pool);
@@ -300,6 +312,7 @@ void ProcessCommand::load(PersistentPool &pool)
pool.load(m_maxExitCode);
pool.load(m_responseFileThreshold);
pool.load(m_responseFileArgumentIndex);
+ pool.load(m_relevantEnvVars);
pool.load(m_stdoutFilePath);
pool.load(m_stderrFilePath);
}
@@ -317,6 +330,7 @@ void ProcessCommand::store(PersistentPool &pool) const
pool.store(m_maxExitCode);
pool.store(m_responseFileThreshold);
pool.store(m_responseFileArgumentIndex);
+ pool.store(m_relevantEnvVars);
pool.store(m_stdoutFilePath);
pool.store(m_stderrFilePath);
}
@@ -442,7 +456,7 @@ bool commandListsAreEqual(const QList<AbstractCommandPtr> &l1, const QList<Abstr
if (l1.count() != l2.count())
return false;
for (int i = 0; i < l1.count(); ++i)
- if (!l1.at(i)->equals(l2.at(i).data()))
+ if (!l1.at(i)->equals(l2.at(i).get()))
return false;
return true;
}
diff --git a/src/lib/corelib/buildgraph/rulecommands.h b/src/lib/corelib/buildgraph/rulecommands.h
index 8e8f68804..4e0d88056 100644
--- a/src/lib/corelib/buildgraph/rulecommands.h
+++ b/src/lib/corelib/buildgraph/rulecommands.h
@@ -122,6 +122,7 @@ public:
int responseFileArgumentIndex() const { return m_responseFileArgumentIndex; }
QString responseFileUsagePrefix() const { return m_responseFileUsagePrefix; }
QProcessEnvironment environment() const { return m_environment; }
+ QStringList relevantEnvVars() const;
QString stdoutFilePath() const { return m_stdoutFilePath; }
QString stderrFilePath() const { return m_stderrFilePath; }
@@ -143,6 +144,7 @@ private:
int m_responseFileArgumentIndex;
QString m_responseFileUsagePrefix;
QProcessEnvironment m_environment;
+ QStringList m_relevantEnvVars;
QString m_stdoutFilePath;
QString m_stderrFilePath;
};
diff --git a/src/lib/corelib/buildgraph/rulegraph.cpp b/src/lib/corelib/buildgraph/rulegraph.cpp
index 50b520e19..8bd42c9f9 100644
--- a/src/lib/corelib/buildgraph/rulegraph.cpp
+++ b/src/lib/corelib/buildgraph/rulegraph.cpp
@@ -56,7 +56,7 @@ void RuleGraph::build(const Set<RulePtr> &rules, const FileTags &productFileTags
m_rules.reserve(rules.size());
for (const RulePtr &rule : rules) {
for (const FileTag &fileTag : rule->collectedOutputFileTags())
- m_outputFileTagToRule[fileTag].append(rule.data());
+ m_outputFileTagToRule[fileTag].append(rule.get());
insert(rule);
}
@@ -68,11 +68,11 @@ void RuleGraph::build(const Set<RulePtr> &rules, const FileTags &productFileTags
inFileTags += rule->auxiliaryInputs;
inFileTags += rule->explicitlyDependsOn;
for (const FileTag &fileTag : qAsConst(inFileTags)) {
- inputFileTagToRule[fileTag].append(rule.data());
+ inputFileTagToRule[fileTag].append(rule.get());
for (const Rule * const producingRule : m_outputFileTagToRule.value(fileTag)) {
if (!producingRule->collectedOutputFileTags().intersects(
rule->excludedAuxiliaryInputs)) {
- connect(rule.data(), producingRule);
+ connect(rule.get(), producingRule);
}
}
}
diff --git a/src/lib/corelib/buildgraph/rulenode.cpp b/src/lib/corelib/buildgraph/rulenode.cpp
index a9c547490..d4558787d 100644
--- a/src/lib/corelib/buildgraph/rulenode.cpp
+++ b/src/lib/corelib/buildgraph/rulenode.cpp
@@ -73,7 +73,7 @@ void RuleNode::accept(BuildGraphVisitor *visitor)
QString RuleNode::toString() const
{
return QLatin1String("RULE ") + m_rule->toString() + QLatin1String(" [")
- + (!product.isNull() ? product->name : QLatin1String("<null>")) + QLatin1Char(']');
+ + (!product.expired() ? product->name : QLatin1String("<null>")) + QLatin1Char(']');
}
void RuleNode::apply(const Logger &logger, const ArtifactSet &changedInputs,
@@ -83,7 +83,7 @@ void RuleNode::apply(const Logger &logger, const ArtifactSet &changedInputs,
const ArtifactSet addedInputs = allCompatibleInputs - m_oldInputArtifacts;
const ArtifactSet removedInputs = m_oldInputArtifacts - allCompatibleInputs;
result->upToDate = changedInputs.isEmpty() && addedInputs.isEmpty() && removedInputs.isEmpty()
- && m_rule->requiresInputs();
+ && m_rule->declaresInputs() && m_rule->requiresInputs;
if (logger.traceEnabled()) {
logger.qbsTrace()
@@ -133,8 +133,8 @@ void RuleNode::apply(const Logger &logger, const ArtifactSet &changedInputs,
}
RulesApplicator::handleRemovedRuleOutputs(inputs, outputArtifactsToRemove, logger);
}
- if (!inputs.isEmpty() || !m_rule->requiresInputs()) {
- RulesApplicator applicator(product, logger);
+ if (!inputs.isEmpty() || !m_rule->declaresInputs() || !m_rule->requiresInputs) {
+ RulesApplicator applicator(product.lock(), logger);
applicator.applyRule(m_rule, inputs);
result->createdNodes = applicator.createdArtifacts();
result->invalidatedNodes = applicator.invalidatedArtifacts();
diff --git a/src/lib/corelib/buildgraph/rulesapplicator.cpp b/src/lib/corelib/buildgraph/rulesapplicator.cpp
index 271c9c325..297d01189 100644
--- a/src/lib/corelib/buildgraph/rulesapplicator.cpp
+++ b/src/lib/corelib/buildgraph/rulesapplicator.cpp
@@ -84,12 +84,12 @@ RulesApplicator::~RulesApplicator()
void RulesApplicator::applyRule(const RuleConstPtr &rule, const ArtifactSet &inputArtifacts)
{
- if (inputArtifacts.isEmpty() && rule->requiresInputs())
+ if (inputArtifacts.isEmpty() && rule->declaresInputs() && rule->requiresInputs)
return;
m_createdArtifacts.clear();
m_invalidatedArtifacts.clear();
- RulesEvaluationContext::Scope s(evalContext().data());
+ RulesEvaluationContext::Scope s(evalContext().get());
m_rule = rule;
m_completeInputSet = inputArtifacts;
@@ -197,7 +197,7 @@ void RulesApplicator::doApply(const ArtifactSet &inputArtifacts, QScriptValue &p
if (!outputArtifact)
continue;
outputArtifacts << outputArtifact;
- ruleArtifactArtifactMap << std::make_pair(ruleArtifact.data(), outputArtifact);
+ ruleArtifactArtifactMap << std::make_pair(ruleArtifact.get(), outputArtifact);
}
}
@@ -206,9 +206,16 @@ void RulesApplicator::doApply(const ArtifactSet &inputArtifacts, QScriptValue &p
for (Artifact * const outputArtifact : qAsConst(outputArtifacts)) {
// connect artifacts that match the file tags in explicitlyDependsOn
- for (const FileTag &fileTag : qAsConst(m_rule->explicitlyDependsOn))
+ for (const FileTag &fileTag : qAsConst(m_rule->explicitlyDependsOn)) {
for (Artifact *dependency : m_product->lookupArtifactsByFileTag(fileTag))
loggedConnect(outputArtifact, dependency, m_logger);
+ for (const ResolvedProductConstPtr &depProduct : qAsConst(m_product->dependencies)) {
+ for (Artifact * const ta : depProduct->targetArtifacts()) {
+ if (ta->fileTags().contains(fileTag))
+ loggedConnect(outputArtifact, ta, m_logger);
+ }
+ }
+ }
outputArtifact->product->unregisterArtifactWithChangedInputs(outputArtifact);
}
@@ -302,7 +309,7 @@ Artifact *RulesApplicator::createOutputArtifact(const QString &filePath, const F
Artifact *outputArtifact = lookupArtifact(m_product, outputPath);
if (outputArtifact) {
- const Transformer * const transformer = outputArtifact->transformer.data();
+ const Transformer * const transformer = outputArtifact->transformer.get();
if (transformer && transformer->rule != m_rule) {
QString e = Tr::tr("Conflicting rules for producing %1 %2 \n")
.arg(outputArtifact->filePath(),
@@ -339,7 +346,7 @@ Artifact *RulesApplicator::createOutputArtifact(const QString &filePath, const F
(*inputArtifacts.cbegin())->filePath()));
throw error;
}
- if (m_rule->requiresInputs())
+ if (m_rule->declaresInputs())
outputArtifact->clearTimestamp();
m_invalidatedArtifacts += outputArtifact;
} else {
diff --git a/src/lib/corelib/buildgraph/transformer.cpp b/src/lib/corelib/buildgraph/transformer.cpp
index a9b51f151..147c61aff 100644
--- a/src/lib/corelib/buildgraph/transformer.cpp
+++ b/src/lib/corelib/buildgraph/transformer.cpp
@@ -159,7 +159,7 @@ ResolvedProductPtr Transformer::product() const
{
if (outputs.isEmpty())
return ResolvedProductPtr();
- return (*outputs.cbegin())->product;
+ return (*outputs.cbegin())->product.lock();
}
void Transformer::setupInputs(QScriptValue targetScriptValue, const ArtifactSet &inputs,
diff --git a/src/lib/corelib/buildgraph/tst_buildgraph.cpp b/src/lib/corelib/buildgraph/tst_buildgraph.cpp
deleted file mode 100644
index 9cc502cf4..000000000
--- a/src/lib/corelib/buildgraph/tst_buildgraph.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qbs.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "tst_buildgraph.h"
-
-#include <buildgraph/artifact.h>
-#include <buildgraph/buildgraph.h>
-#include <buildgraph/cycledetector.h>
-#include <buildgraph/productbuilddata.h>
-#include <buildgraph/projectbuilddata.h>
-#include <language/language.h>
-#include <logging/logger.h>
-#include <tools/error.h>
-
-#include <QtTest/qtest.h>
-
-namespace qbs {
-namespace Internal {
-
-const TopLevelProjectPtr project = TopLevelProject::create();
-
-TestBuildGraph::TestBuildGraph(ILogSink *logSink) : m_logSink(logSink)
-{
- project->buildData.reset(new ProjectBuildData);
-}
-
-void TestBuildGraph::initTestCase()
-{
-}
-
-void TestBuildGraph::cleanupTestCase()
-{
-}
-
-
-bool TestBuildGraph::cycleDetected(const ResolvedProductConstPtr &product)
-{
- try {
- CycleDetector(Logger(m_logSink)).visitProduct(product);
- return false;
- } catch (const ErrorInfo &) {
- return true;
- }
-}
-
-ResolvedProductConstPtr TestBuildGraph::productWithDirectCycle()
-{
- const ResolvedProductPtr product = ResolvedProduct::create();
- product->project = project;
- product->buildData.reset(new ProductBuildData);
- Artifact * const root = new Artifact;
- root->product = product;
- Artifact * const child = new Artifact;
- child->product = product;
- product->buildData->roots.insert(root);
- product->buildData->nodes << root << child;
- qbs::Internal::connect(root, child);
- qbs::Internal::connect(child, root);
- return product;
-}
-
-ResolvedProductConstPtr TestBuildGraph::productWithLessDirectCycle()
-{
- const ResolvedProductPtr product = ResolvedProduct::create();
- product->project = project;
- product->buildData.reset(new ProductBuildData);
- Artifact * const root = new Artifact;
- Artifact * const child = new Artifact;
- Artifact * const grandchild = new Artifact;
- root->product = product;
- child->product = product;
- grandchild->product = product;
- product->buildData->roots << root;
- product->buildData->nodes << root << child << grandchild;
- qbs::Internal::connect(root, child);
- qbs::Internal::connect(child, grandchild);
- qbs::Internal::connect(grandchild, root);
- return product;
-}
-
-// root appears as a child, but in a different tree
-ResolvedProductConstPtr TestBuildGraph::productWithNoCycle()
-{
- const ResolvedProductPtr product = ResolvedProduct::create();
- product->project = project;
- product->buildData.reset(new ProductBuildData);
- Artifact * const root = new Artifact;
- Artifact * const root2 = new Artifact;
- root->product = product;
- root2->product = product;
- product->buildData->roots << root << root2;
- product->buildData->nodes << root << root2;
- qbs::Internal::connect(root2, root);
- return product;
-}
-
-void TestBuildGraph::testCycle()
-{
- QVERIFY(cycleDetected(productWithDirectCycle()));
- QVERIFY(cycleDetected(productWithLessDirectCycle()));
- QVERIFY(!cycleDetected(productWithNoCycle()));
-}
-
-} // namespace Internal
-} // namespace qbs
diff --git a/src/lib/corelib/corelib.pro b/src/lib/corelib/corelib.pro
index 97093e319..8e53891fd 100644
--- a/src/lib/corelib/corelib.pro
+++ b/src/lib/corelib/corelib.pro
@@ -8,7 +8,6 @@ isEmpty(QBS_RELATIVE_LIBEXEC_PATH) {
DEFINES += QBS_RELATIVE_LIBEXEC_PATH=\\\"$${QBS_RELATIVE_LIBEXEC_PATH}\\\"
QT += core-private network script
-qbs_enable_unit_tests:QT += testlib
qbs_enable_project_file_updates: QT += gui
INCLUDEPATH += $$PWD
diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs
index 1b137925c..6f470902a 100644
--- a/src/lib/corelib/corelib.qbs
+++ b/src/lib/corelib/corelib.qbs
@@ -1,15 +1,10 @@
import qbs 1.0
-import QbsFunctions
QbsLibrary {
- Depends { name: "clangcompilationdbgenerator" }
- Depends { name: "visualstudiogenerator" }
Depends { name: "cpp" }
Depends { name: "Qt"; submodules: ["core-private", "network", "script", "xml"] }
Depends { condition: qbsbuildconfig.enableProjectFileUpdates; name: "Qt.gui" }
- Depends { condition: qbsbuildconfig.enableUnitTests; name: "Qt.testlib" }
- Depends { condition: Qt.core.staticBuild; name: "qbs_cpp_scanner" }
- Depends { condition: Qt.core.staticBuild; name: "qbs_qt_scanner" }
+ Depends { condition: Qt.core.staticBuild; productTypes: ["qbsplugin"] }
name: "qbscore"
cpp.includePaths: base.concat([
".",
@@ -17,13 +12,14 @@ QbsLibrary {
])
property stringList projectFileUpdateDefines:
qbsbuildconfig.enableProjectFileUpdates ? ["QBS_ENABLE_PROJECT_FILE_UPDATES"] : []
+ property stringList enableUnitTestsDefines:
+ qbsbuildconfig.enableUnitTests ? ["QBS_ENABLE_UNIT_TESTS"] : []
// TODO: Use Utilities.cStringQuote
cpp.defines: base.concat([
'QBS_RELATIVE_LIBEXEC_PATH="' + qbsbuildconfig.relativeLibexecPath + '"',
"QBS_VERSION=\"" + version + "\"",
"QT_CREATOR", "QML_BUILD_STATIC_LIB", // needed for QmlJS
- "SRCDIR=\"" + path + "\""
- ]).concat(projectFileUpdateDefines)
+ ]).concat(projectFileUpdateDefines).concat(enableUnitTestsDefines)
Properties {
condition: qbs.targetOS.contains("windows")
@@ -387,6 +383,8 @@ QbsLibrary {
"projectgeneratormanager.cpp",
"qbsassert.cpp",
"qbsassert.h",
+ "qbspluginmanager.cpp",
+ "qbspluginmanager.h",
"qbsprocess.cpp",
"qbsprocess.h",
"qttools.cpp",
@@ -457,19 +455,6 @@ QbsLibrary {
qbs.install: qbsbuildconfig.installApiHeaders
qbs.installDir: headerInstallPrefix
}
- Group {
- condition: qbsbuildconfig.enableUnitTests
- name: "tests"
- cpp.defines: outer.filter(function(def) { return def !== "QT_NO_CAST_FROM_ASCII"; })
- files: [
- "buildgraph/tst_buildgraph.cpp",
- "buildgraph/tst_buildgraph.h",
- "language/tst_language.cpp",
- "language/tst_language.h",
- "tools/tst_tools.h",
- "tools/tst_tools.cpp"
- ]
- }
Export {
Depends { name: "cpp" }
cpp.defines: product.projectFileUpdateDefines
diff --git a/src/lib/corelib/generators/clangcompilationdb/clangcompilationdb.pri b/src/lib/corelib/generators/clangcompilationdb/clangcompilationdb.pri
deleted file mode 100644
index 61dc8f19e..000000000
--- a/src/lib/corelib/generators/clangcompilationdb/clangcompilationdb.pri
+++ /dev/null
@@ -1,5 +0,0 @@
-HEADERS += \
- $$PWD/clangcompilationdbgenerator.h
-
-SOURCES += \
- $$PWD/clangcompilationdbgenerator.cpp
diff --git a/src/lib/corelib/generators/clangcompilationdb/clangcompilationdb.qbs b/src/lib/corelib/generators/clangcompilationdb/clangcompilationdb.qbs
deleted file mode 100644
index c8f626190..000000000
--- a/src/lib/corelib/generators/clangcompilationdb/clangcompilationdb.qbs
+++ /dev/null
@@ -1,19 +0,0 @@
-import qbs
-
-QbsLibrary {
- type: ["staticlibrary"]
- name: "clangcompilationdbgenerator"
- install: false
-
- cpp.includePaths: base.concat([
- "../..",
- ])
-
- Depends { name: "cpp" }
- Depends { name: "Qt.core" }
-
- files: [
- "clangcompilationdbgenerator.cpp",
- "clangcompilationdbgenerator.h"
- ]
-}
diff --git a/src/lib/corelib/generators/generatableprojectiterator.h b/src/lib/corelib/generators/generatableprojectiterator.h
index 295ed6d17..793627512 100644
--- a/src/lib/corelib/generators/generatableprojectiterator.h
+++ b/src/lib/corelib/generators/generatableprojectiterator.h
@@ -45,7 +45,7 @@
namespace qbs {
-class GeneratableProjectIterator {
+class QBS_EXPORT GeneratableProjectIterator {
GeneratableProject project;
public:
diff --git a/src/lib/corelib/generators/generator.cpp b/src/lib/corelib/generators/generator.cpp
index b58ae1ea2..87cd701d9 100644
--- a/src/lib/corelib/generators/generator.cpp
+++ b/src/lib/corelib/generators/generator.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "generator.h"
+#include <logging/logger.h>
#include <tools/error.h>
#include <tools/hostosinfo.h>
#include <tools/installoptions.h>
@@ -52,6 +53,7 @@ public:
QList<QVariantMap> buildConfigurations;
InstallOptions installOptions;
QString qbsSettingsDir;
+ Internal::Logger logger = Internal::Logger(nullptr);
};
ProjectGenerator::ProjectGenerator()
@@ -79,7 +81,8 @@ static QString _configurationName(const QVariantMap &buildConfiguration)
void ProjectGenerator::generate(const QList<Project> &projects,
const QList<QVariantMap> &buildConfigurations,
const InstallOptions &installOptions,
- const QString &qbsSettingsDir)
+ const QString &qbsSettingsDir,
+ const Internal::Logger &logger)
{
d->projects = projects;
std::sort(d->projects.begin(), d->projects.end(),
@@ -91,6 +94,7 @@ void ProjectGenerator::generate(const QList<Project> &projects,
return _configurationName(a) < _configurationName(b); });
d->installOptions = installOptions;
d->qbsSettingsDir = qbsSettingsDir;
+ d->logger = logger;
generate();
}
@@ -233,4 +237,9 @@ QString ProjectGenerator::qbsSettingsDir() const
return d->qbsSettingsDir;
}
+const Internal::Logger &ProjectGenerator::logger() const
+{
+ return d->logger;
+}
+
} // namespace qbs
diff --git a/src/lib/corelib/generators/generator.h b/src/lib/corelib/generators/generator.h
index 9155f2c09..8c7bfde8b 100644
--- a/src/lib/corelib/generators/generator.h
+++ b/src/lib/corelib/generators/generator.h
@@ -71,7 +71,8 @@ public:
void generate(const QList<Project> &projects,
const QList<QVariantMap> &buildConfigurations,
const InstallOptions &installOptions,
- const QString &qbsSettingsDir);
+ const QString &qbsSettingsDir,
+ const Internal::Logger &logger);
const GeneratableProject project() const;
QFileInfo qbsExecutableFilePath() const;
@@ -87,20 +88,12 @@ private:
protected:
ProjectGenerator();
+ const Internal::Logger &logger() const;
+
private:
ProjectGeneratorPrivate *d;
};
} // namespace qbs
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef qbs::ProjectGenerator **(*getGenerators_f)();
-
-#ifdef __cplusplus
-}
-#endif
-
#endif // GENERATORPLUGIN_H
diff --git a/src/lib/corelib/generators/generatordata.h b/src/lib/corelib/generators/generatordata.h
index 1d4685433..47f4acb93 100644
--- a/src/lib/corelib/generators/generatordata.h
+++ b/src/lib/corelib/generators/generatordata.h
@@ -52,14 +52,14 @@ typedef QMap<QString, Project> GeneratableProjectMap;
typedef QMap<QString, ProjectData> GeneratableProjectDataMap;
typedef QMap<QString, ProductData> GeneratableProductDataMap;
-struct GeneratableProductData {
+struct QBS_EXPORT GeneratableProductData {
GeneratableProductDataMap data;
QString name() const;
CodeLocation location() const;
QStringList dependencies() const;
};
-struct GeneratableProjectData {
+struct QBS_EXPORT GeneratableProjectData {
struct Id {
private:
friend struct GeneratableProjectData;
@@ -78,7 +78,7 @@ struct GeneratableProjectData {
Id uniqueName() const;
};
-struct GeneratableProject : public GeneratableProjectData {
+struct QBS_EXPORT GeneratableProject : public GeneratableProjectData {
GeneratableProjectMap projects;
QMap<QString, QVariantMap> buildConfigurations;
QMap<QString, QStringList> commandLines;
diff --git a/src/lib/corelib/generators/generators.pri b/src/lib/corelib/generators/generators.pri
index 935419c1f..d90ad4274 100644
--- a/src/lib/corelib/generators/generators.pri
+++ b/src/lib/corelib/generators/generators.pri
@@ -8,6 +8,3 @@ HEADERS += \
$$PWD/generator.h \
$$PWD/generatordata.h \
$$PWD/igeneratableprojectvisitor.h
-
-include(clangcompilationdb/clangcompilationdb.pri)
-include(visualstudio/visualstudio.pri)
diff --git a/src/lib/corelib/generators/generators.qbs b/src/lib/corelib/generators/generators.qbs
deleted file mode 100644
index b6f40ec8c..000000000
--- a/src/lib/corelib/generators/generators.qbs
+++ /dev/null
@@ -1,8 +0,0 @@
-import qbs
-
-Project {
- references: [
- "clangcompilationdb/clangcompilationdb.qbs",
- "visualstudio/visualstudio.qbs",
- ]
-}
diff --git a/src/lib/corelib/jsextensions/environmentextension.cpp b/src/lib/corelib/jsextensions/environmentextension.cpp
index fcb0411fd..06e5e0765 100644
--- a/src/lib/corelib/jsextensions/environmentextension.cpp
+++ b/src/lib/corelib/jsextensions/environmentextension.cpp
@@ -43,7 +43,6 @@
#include <logging/translator.h>
#include <QtCore/qdir.h>
-#include <QtCore/qregularexpression.h>
#include <QtScript/qscriptable.h>
#include <QtScript/qscriptengine.h>
diff --git a/src/lib/corelib/jsextensions/fileinfoextension.cpp b/src/lib/corelib/jsextensions/fileinfoextension.cpp
index 25392becf..74362dc4d 100644
--- a/src/lib/corelib/jsextensions/fileinfoextension.cpp
+++ b/src/lib/corelib/jsextensions/fileinfoextension.cpp
@@ -45,11 +45,12 @@
#include <QtCore/qdir.h>
#include <QtCore/qfileinfo.h>
-#include <QtCore/qregularexpression.h>
#include <QtScript/qscriptable.h>
#include <QtScript/qscriptengine.h>
+#include <regex>
+
namespace qbs {
namespace Internal {
@@ -258,8 +259,9 @@ QScriptValue FileInfoExtension::js_joinPaths(QScriptContext *context, QScriptEng
paths.append(arg);
}
}
- return paths.join(QLatin1Char('/')).replace(QRegularExpression(QLatin1String("/{2,}")),
- QLatin1String("/"));
+ return engine->toScriptValue(QString::fromStdString(
+ std::regex_replace(paths.join(QLatin1Char('/')).toStdString(),
+ std::regex("/{2,}"), "/")));
}
} // namespace Internal
diff --git a/src/lib/corelib/jsextensions/moduleproperties.cpp b/src/lib/corelib/jsextensions/moduleproperties.cpp
index df93c52af..c9b17c855 100644
--- a/src/lib/corelib/jsextensions/moduleproperties.cpp
+++ b/src/lib/corelib/jsextensions/moduleproperties.cpp
@@ -134,7 +134,7 @@ static QString artifactType() { return QLatin1String("artifact"); }
void ModuleProperties::init(QScriptValue productObject,
const ResolvedProductConstPtr &product)
{
- init(productObject, product.data(), productType());
+ init(productObject, product.get(), productType());
setupModules(productObject, product, nullptr);
}
@@ -152,7 +152,7 @@ void ModuleProperties::init(QScriptValue artifactObject, const Artifact *artifac
};
QScriptEngine * const engine = artifactObject.engine();
artifactObject.setProperty(QStringLiteral("product"), engine->toScriptValue(productProperties));
- setupModules(artifactObject, artifact->product, artifact);
+ setupModules(artifactObject, artifact->product.lock(), artifact);
}
void ModuleProperties::init(QScriptValue objectWithProperties, const void *ptr,
@@ -178,7 +178,7 @@ void ModuleProperties::setupModules(QScriptValue &object, const ResolvedProductC
QScriptValue data = engine->newObject();
data.setProperty(ModuleNameKey, module->name);
QVariant v;
- v.setValue<quintptr>(reinterpret_cast<quintptr>(product.data()));
+ v.setValue<quintptr>(reinterpret_cast<quintptr>(product.get()));
data.setProperty(ProductPtrKey, engine->newVariant(v));
v.setValue<quintptr>(reinterpret_cast<quintptr>(artifact));
data.setProperty(ArtifactPtrKey, engine->newVariant(v));
diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp
index c2dc06ab1..a8e5e7c1e 100644
--- a/src/lib/corelib/jsextensions/utilitiesextension.cpp
+++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp
@@ -57,7 +57,6 @@
#include <QtCore/qcryptographichash.h>
#include <QtCore/qdir.h>
-#include <QtCore/qregularexpression.h>
#include <QtScript/qscriptable.h>
#include <QtScript/qscriptengine.h>
@@ -141,15 +140,20 @@ QScriptValue UtilitiesExtension::js_canonicalTargetArchitecture(QScriptContext *
if (arch.isUndefined() || arch.isNull())
return arch;
- const QScriptValue vendor = context->argument(1);
- const QScriptValue system = context->argument(2);
- const QScriptValue abi = context->argument(3);
+ QScriptValue endianness = context->argument(1);
+ if (endianness.isUndefined() || endianness.isNull())
+ endianness = QString();
+ const QScriptValue vendor = context->argument(2);
+ const QScriptValue system = context->argument(3);
+ const QScriptValue abi = context->argument(4);
- if (!arch.isString() || !vendor.isString() || !system.isString() || !abi.isString())
+ if (!arch.isString() || !endianness.isString()
+ || !vendor.isString() || !system.isString() || !abi.isString())
return context->throwError(QScriptContext::SyntaxError,
- QStringLiteral("canonicalTargetArchitecture expects 1 to 4 arguments of type string"));
+ QStringLiteral("canonicalTargetArchitecture expects 1 to 5 arguments of type string"));
- return engine->toScriptValue(canonicalTargetArchitecture(arch.toString(), vendor.toString(),
+ return engine->toScriptValue(canonicalTargetArchitecture(arch.toString(), endianness.toString(),
+ vendor.toString(),
system.toString(), abi.toString()));
}
diff --git a/src/lib/corelib/language/astpropertiesitemhandler.cpp b/src/lib/corelib/language/astpropertiesitemhandler.cpp
index 51d9eb43c..4b0d36f3e 100644
--- a/src/lib/corelib/language/astpropertiesitemhandler.cpp
+++ b/src/lib/corelib/language/astpropertiesitemhandler.cpp
@@ -105,7 +105,7 @@ private:
continue;
}
if (it.value()->type() == Value::ItemValueType) {
- Item * const innerVal = it.value().staticCast<ItemValue>()->item();
+ Item * const innerVal = std::static_pointer_cast<ItemValue>(it.value())->item();
ItemValuePtr outerVal = outer->itemProperty(it.key());
if (!outerVal) {
outerVal = ItemValue::create(Item::create(outer->pool(), innerVal->type()),
@@ -119,8 +119,8 @@ private:
throw ErrorInfo(Tr::tr("Incompatible value type in unconditional value at %1.")
.arg(outerVal->location().toString()));
}
- doApply(it.key(), outer, outerVal.staticCast<JSSourceValue>(),
- it.value().staticCast<JSSourceValue>());
+ doApply(it.key(), outer, std::static_pointer_cast<JSSourceValue>(outerVal),
+ std::static_pointer_cast<JSSourceValue>(it.value()));
} else {
QBS_CHECK(!"Unexpected value type in conditional value.");
}
@@ -171,7 +171,7 @@ static QString getPropertyString(const Item *propertiesItem, const QString &name
}
}
- const JSSourceValuePtr srcval = value.staticCast<JSSourceValue>();
+ const JSSourceValuePtr srcval = std::static_pointer_cast<JSSourceValue>(value);
return srcval->sourceCodeForEvaluation();
}
diff --git a/src/lib/corelib/language/builtindeclarations.cpp b/src/lib/corelib/language/builtindeclarations.cpp
index 63586bbce..bb9b79ada 100644
--- a/src/lib/corelib/language/builtindeclarations.cpp
+++ b/src/lib/corelib/language/builtindeclarations.cpp
@@ -67,6 +67,8 @@ BuiltinDeclarations::BuiltinDeclarations()
{ QLatin1String("FileTagger"), ItemType::FileTagger },
{ QLatin1String("Group"), ItemType::Group },
{ QLatin1String("Module"), ItemType::Module },
+ { QLatin1String("Parameter"), ItemType::Parameter },
+ { QLatin1String("Parameters"), ItemType::Parameters },
{ QLatin1String("Probe"), ItemType::Probe },
{ QLatin1String("Product"), ItemType::Product },
{ QLatin1String("Project"), ItemType::Project },
@@ -215,12 +217,18 @@ void BuiltinDeclarations::addDependsItem()
PropertyDeclaration limitDecl(QLatin1String("limitToSubProject"), PropertyDeclaration::Boolean);
limitDecl.setInitialValueSource(QLatin1String("false"));
item << limitDecl;
+ item << PropertyDeclaration(QLatin1String("multiplexConfigurationId"),
+ PropertyDeclaration::String, PropertyDeclaration::ReadOnlyFlag);
insert(item);
}
void BuiltinDeclarations::addExportItem()
{
- addModuleLikeItem(ItemType::Export);
+ ItemDeclaration item = moduleLikeItem(ItemType::Export);
+ auto allowedChildTypes = item.allowedChildTypes();
+ allowedChildTypes.insert(ItemType::Parameters);
+ item.setAllowedChildTypes(allowedChildTypes);
+ insert(item);
}
void BuiltinDeclarations::addFileTaggerItem()
@@ -260,10 +268,10 @@ void BuiltinDeclarations::addGroupItem()
void BuiltinDeclarations::addModuleItem()
{
- addModuleLikeItem(ItemType::Module);
+ insert(moduleLikeItem(ItemType::Module));
}
-void BuiltinDeclarations::addModuleLikeItem(ItemType type)
+ItemDeclaration BuiltinDeclarations::moduleLikeItem(ItemType type)
{
ItemDeclaration item(type);
item.setAllowedChildTypes(ItemDeclaration::TypeNames()
@@ -271,6 +279,7 @@ void BuiltinDeclarations::addModuleLikeItem(ItemType type)
<< ItemType::Depends
<< ItemType::FileTagger
<< ItemType::Rule
+ << ItemType::Parameter
<< ItemType::Probe
<< ItemType::PropertyOptions
<< ItemType::Scanner);
@@ -291,7 +300,7 @@ void BuiltinDeclarations::addModuleLikeItem(ItemType type)
PropertyDeclaration presentDecl(QLatin1String("present"), PropertyDeclaration::Boolean);
presentDecl.setInitialValueSource(QLatin1String("true"));
item << presentDecl;
- insert(item);
+ return item;
}
void BuiltinDeclarations::addProbeItem()
@@ -326,9 +335,12 @@ void BuiltinDeclarations::addProductItem()
decl.setInitialValueSource(QLatin1String("true"));
item << decl;
decl = PropertyDeclaration(QLatin1String("profiles"), PropertyDeclaration::StringList);
- decl.setInitialValueSource(QLatin1String("[project.profile]"));
+ decl.setDeprecationInfo(DeprecationInfo(Version::fromString(QLatin1String("1.9.0")),
+ Tr::tr("Use qbs.profiles instead.")));
+ item << decl;
+ decl = PropertyDeclaration(QLatin1String("profile"), PropertyDeclaration::String); // Internal
+ decl.setInitialValueSource(QLatin1String("project.profile"));
item << decl;
- item << PropertyDeclaration(QLatin1String("profile"), PropertyDeclaration::String); // Internal
decl = PropertyDeclaration(QLatin1String("targetName"), PropertyDeclaration::String);
decl.setInitialValueSource(QLatin1String("new String(name)"
".replace(/[/\\\\?%*:|\"<>]/g, '_').valueOf()"));
@@ -346,6 +358,17 @@ void BuiltinDeclarations::addProductItem()
item << PropertyDeclaration(QLatin1String("qbsSearchPaths"),
PropertyDeclaration::StringList);
item << PropertyDeclaration(QLatin1String("version"), PropertyDeclaration::String);
+
+ decl = PropertyDeclaration(QLatin1String("multiplexByQbsProperties"),
+ PropertyDeclaration::StringList);
+ decl.setInitialValueSource(QLatin1String("[\"profiles\"]"));
+ item << decl;
+ item << PropertyDeclaration(QLatin1String("multiplexedType"), PropertyDeclaration::StringList);
+ item << PropertyDeclaration(QLatin1String("aggregate"), PropertyDeclaration::Boolean);
+ item << PropertyDeclaration(QLatin1String("multiplexed"), PropertyDeclaration::Boolean,
+ PropertyDeclaration::ReadOnlyFlag);
+ item << PropertyDeclaration(QLatin1String("multiplexConfigurationId"),
+ PropertyDeclaration::String, PropertyDeclaration::ReadOnlyFlag);
insert(item);
}
@@ -398,6 +421,9 @@ void BuiltinDeclarations::addRuleItem()
PropertyDeclaration decl(QLatin1String("multiplex"), PropertyDeclaration::Boolean);
decl.setInitialValueSource(QLatin1String("false"));
item << decl;
+ PropertyDeclaration requiresInputsDecl(QLatin1String("requiresInputs"),
+ PropertyDeclaration::Boolean);
+ item << requiresInputsDecl;
item << PropertyDeclaration(QLatin1String("name"), PropertyDeclaration::String);
item << PropertyDeclaration(QLatin1String("inputs"), PropertyDeclaration::StringList);
item << PropertyDeclaration(QLatin1String("outputFileTags"), PropertyDeclaration::StringList);
diff --git a/src/lib/corelib/language/builtindeclarations.h b/src/lib/corelib/language/builtindeclarations.h
index d85f4101a..745a5766f 100644
--- a/src/lib/corelib/language/builtindeclarations.h
+++ b/src/lib/corelib/language/builtindeclarations.h
@@ -76,7 +76,7 @@ private:
void addFileTaggerItem();
void addGroupItem();
void addModuleItem();
- void addModuleLikeItem(ItemType type);
+ static ItemDeclaration moduleLikeItem(ItemType type);
void addProbeItem();
void addProductItem();
void addProjectItem();
diff --git a/src/lib/corelib/language/evaluator.cpp b/src/lib/corelib/language/evaluator.cpp
index 389a00455..78bca0c13 100644
--- a/src/lib/corelib/language/evaluator.cpp
+++ b/src/lib/corelib/language/evaluator.cpp
@@ -58,9 +58,9 @@
namespace qbs {
namespace Internal {
-Evaluator::Evaluator(ScriptEngine *scriptEngine, const Logger &logger)
+Evaluator::Evaluator(ScriptEngine *scriptEngine)
: m_scriptEngine(scriptEngine)
- , m_scriptClass(new EvaluatorScriptClass(scriptEngine, logger))
+ , m_scriptClass(new EvaluatorScriptClass(scriptEngine, scriptEngine->logger()))
{
}
@@ -144,7 +144,7 @@ QScriptValue Evaluator::scriptValue(const Item *item)
EvaluationData *edata = new EvaluationData;
edata->evaluator = this;
edata->item = item;
- edata->item->setPropertyObserver(this);
+ edata->item->setObserver(this);
scriptValue = m_scriptEngine->newObject(m_scriptClass);
attachPointerTo(scriptValue, edata);
@@ -205,31 +205,26 @@ bool Evaluator::evaluateProperty(QScriptValue *result, const Item *item, const Q
return true;
}
-QScriptValue Evaluator::fileScope(const FileContextConstPtr &file)
+Evaluator::FileContextScopes Evaluator::fileContextScopes(const FileContextConstPtr &file)
{
- QScriptValue &result = m_fileScopeMap[file];
- if (result.isObject()) {
- // already initialized
- return result;
+ FileContextScopes &result = m_fileContextScopesMap[file];
+ if (!result.fileScope.isObject()) {
+ if (file->idScope())
+ result.fileScope = scriptValue(file->idScope());
+ else
+ result.fileScope = m_scriptEngine->newObject();
+ result.fileScope.setProperty(QLatin1String("filePath"), file->filePath());
+ result.fileScope.setProperty(QLatin1String("path"), file->dirPath());
+ }
+ if (!result.importScope.isObject()) {
+ try {
+ result.importScope = m_scriptEngine->newObject();
+ m_scriptEngine->import(file, result.importScope);
+ JsExtensions::setupExtensions(file->jsExtensions(), result.importScope);
+ } catch (const ErrorInfo &e) {
+ result.importScope = m_scriptEngine->currentContext()->throwError(e.toString());
+ }
}
-
- if (file->idScope())
- result = scriptValue(file->idScope());
- else
- result = m_scriptEngine->newObject();
- result.setProperty(QLatin1String("filePath"), file->filePath());
- result.setProperty(QLatin1String("path"), file->dirPath());
- return result;
-}
-
-QScriptValue Evaluator::importScope(const FileContextConstPtr &file)
-{
- QScriptValue &result = m_importScopeMap[file];
- if (result.isObject())
- return result;
- result = m_scriptEngine->newObject();
- m_scriptEngine->import(file, result);
- JsExtensions::setupExtensions(file->jsExtensions(), result);
return result;
}
diff --git a/src/lib/corelib/language/evaluator.h b/src/lib/corelib/language/evaluator.h
index b074c9f9e..c86f0375d 100644
--- a/src/lib/corelib/language/evaluator.h
+++ b/src/lib/corelib/language/evaluator.h
@@ -55,12 +55,12 @@ class FileTags;
class Logger;
class ScriptEngine;
-class Evaluator : private ItemObserver
+class QBS_AUTOTEST_EXPORT Evaluator : private ItemObserver
{
friend class SVConverter;
public:
- Evaluator(ScriptEngine *scriptEngine, const Logger &logger);
+ Evaluator(ScriptEngine *scriptEngine);
virtual ~Evaluator();
ScriptEngine *engine() const { return m_scriptEngine; }
@@ -75,8 +75,14 @@ public:
QStringList stringListValue(const Item *item, const QString &name, bool *propertyWasSet = 0);
QScriptValue scriptValue(const Item *item);
- QScriptValue fileScope(const FileContextConstPtr &file);
- QScriptValue importScope(const FileContextConstPtr &file);
+
+ struct FileContextScopes
+ {
+ QScriptValue fileScope;
+ QScriptValue importScope;
+ };
+
+ FileContextScopes fileContextScopes(const FileContextConstPtr &file);
void setCachingEnabled(bool enabled);
@@ -93,8 +99,7 @@ private:
ScriptEngine *m_scriptEngine;
EvaluatorScriptClass *m_scriptClass;
mutable QHash<const Item *, QScriptValue> m_scriptValueMap;
- mutable QHash<FileContextConstPtr, QScriptValue> m_fileScopeMap;
- mutable QHash<FileContextConstPtr, QScriptValue> m_importScopeMap;
+ mutable QHash<FileContextConstPtr, FileContextScopes> m_fileContextScopesMap;
};
class EvalCacheEnabler
diff --git a/src/lib/corelib/language/evaluatorscriptclass.cpp b/src/lib/corelib/language/evaluatorscriptclass.cpp
index 1054c61a9..ba7df02b5 100644..100755
--- a/src/lib/corelib/language/evaluatorscriptclass.cpp
+++ b/src/lib/corelib/language/evaluatorscriptclass.cpp
@@ -47,17 +47,15 @@
#include "propertydeclaration.h"
#include "value.h"
#include <logging/translator.h>
-#include <tools/architectures.h>
#include <tools/fileinfo.h>
-#include <tools/hostosinfo.h>
#include <tools/qbsassert.h>
#include <tools/scripttools.h>
-#include <tools/shellutils.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qdebug.h>
#include <QtCore/qsettings.h>
+#include <QtScript/qscriptclasspropertyiterator.h>
#include <QtScript/qscriptstring.h>
#include <QtScript/qscriptvalue.h>
@@ -101,15 +99,6 @@ public:
}
private:
- QScriptValue importScope(Evaluator *evaluator, const FileContextConstPtr &file)
- {
- try {
- return evaluator->importScope(file);
- } catch (const ErrorInfo &e) {
- return evaluator->engine()->currentContext()->throwError(e.toString());
- }
- }
-
void setupConvenienceProperty(const QString &conveniencePropertyName, QScriptValue *extraScope,
const QScriptValue &scriptValue)
{
@@ -162,6 +151,8 @@ private:
for (int i = 0; i < value->alternatives().count(); ++i) {
const JSSourceValue::Alternative *alternative = 0;
alternative = &value->alternatives().at(i);
+ const Evaluator::FileContextScopes fileCtxScopes
+ = data->evaluator->fileContextScopes(value->file());
if (!conditionScopeItem) {
// We have to differentiate between module instances and normal items here.
//
@@ -194,14 +185,14 @@ private:
? data->item->scope() : data->item;
conditionScope = data->evaluator->scriptValue(conditionScopeItem);
QBS_ASSERT(conditionScope.isObject(), return);
- conditionFileScope = data->evaluator->fileScope(value->file());
+ conditionFileScope = fileCtxScopes.fileScope;
}
scriptContext->pushScope(conditionFileScope);
pushItemScopes(conditionScopeItem);
if (alternative->value->definingItem())
pushItemScopes(alternative->value->definingItem());
scriptContext->pushScope(conditionScope);
- const QScriptValue theImportScope = importScope(data->evaluator, value->file());
+ const QScriptValue &theImportScope = fileCtxScopes.importScope;
if (theImportScope.isError()) {
scriptContext->popScope();
scriptContext->popScope();
@@ -232,12 +223,12 @@ private:
if (value->sourceUsesBase())
outerValue->setSourceUsesBaseFlag();
outerValue->setLocation(value->line(), value->column());
- outerItem = Item::create(data->item->pool(), ItemType::ModuleInstance);
+ outerItem = Item::create(data->item->pool(), ItemType::Outer);
outerItem->setProperty(propertyName->toString(), outerValue);
}
if (overrides.toBool())
value->setIsExclusiveListValue();
- value = alternative->value.data();
+ value = alternative->value.get();
break;
}
}
@@ -275,7 +266,9 @@ private:
setupConvenienceProperty(QLatin1String("original"), &extraScope, originalValue);
}
- pushScope(data->evaluator->fileScope(value->file()));
+ const Evaluator::FileContextScopes fileCtxScopes
+ = data->evaluator->fileContextScopes(value->file());
+ pushScope(fileCtxScopes.fileScope);
pushItemScopes(data->item);
if (itemOfProperty->type() != ItemType::ModuleInstance) {
// Own properties of module instances must not have the instance itself in the scope.
@@ -284,7 +277,7 @@ private:
if (value->definingItem())
pushItemScopes(value->definingItem());
pushScope(extraScope);
- const QScriptValue theImportScope = importScope(data->evaluator, value->file());
+ const QScriptValue &theImportScope = fileCtxScopes.importScope;
if (theImportScope.isError()) {
*result = theImportScope;
} else {
@@ -362,7 +355,7 @@ QScriptClass::QueryFlags EvaluatorScriptClass::queryItemProperty(const Evaluatio
{
for (const Item *item = data->item; item; item = item->prototype()) {
m_queryResult.value = item->ownProperty(name);
- if (!m_queryResult.value.isNull()) {
+ if (m_queryResult.value) {
m_queryResult.data = data;
m_queryResult.itemOfProperty = item;
return HandlesReadAccess;
@@ -401,7 +394,7 @@ void EvaluatorScriptClass::collectValuesFromNextChain(const EvaluationData *data
QScriptValueList lst;
Set<Value *> oldNextChain = m_currentNextChain;
for (ValuePtr next = value; next; next = next->next())
- m_currentNextChain.insert(next.data());
+ m_currentNextChain.insert(next.get());
for (ValuePtr next = value; next; next = next->next()) {
QScriptValue v = data->evaluator->property(next->definingItem(), propertyName);
@@ -414,7 +407,7 @@ void EvaluatorScriptClass::collectValuesFromNextChain(const EvaluationData *data
continue;
lst << v;
if (next->type() == Value::JSSourceValueType
- && next.staticCast<JSSourceValue>()->isExclusiveListValue()) {
+ && std::static_pointer_cast<JSSourceValue>(next)->isExclusiveListValue()) {
lst = lst.mid(lst.length() - 2);
break;
}
@@ -540,25 +533,23 @@ class PropertyStackManager
{
public:
PropertyStackManager(const Item *itemOfProperty, const QScriptString &name, const Value *value,
- QStack<QualifiedId> &requestedProperties,
+ std::stack<QualifiedId> &requestedProperties,
PropertyDependencies &propertyDependencies)
: m_requestedProperties(requestedProperties)
{
if (value->type() == Value::JSSourceValueType
&& (itemOfProperty->type() == ItemType::ModuleInstance
- || itemOfProperty->type() == ItemType::Module)) {
+ || itemOfProperty->type() == ItemType::Module
+ || itemOfProperty->type() == ItemType::Export)) {
const VariantValueConstPtr varValue
= itemOfProperty->variantProperty(QLatin1String("name"));
- // QBS_CHECK(varValue);
- // TODO: Check why the base module sometimes has no name. Code suggests it has to have one.
- if (varValue) {
- m_stackUpdate = true;
- const QualifiedId fullPropName
- = QualifiedId::fromString(varValue->value().toString()) << name.toString();
- if (!requestedProperties.isEmpty())
- propertyDependencies[fullPropName].insert(requestedProperties.top());
- m_requestedProperties.push(fullPropName);
- }
+ QBS_ASSERT(varValue, return);
+ m_stackUpdate = true;
+ const QualifiedId fullPropName
+ = QualifiedId::fromString(varValue->value().toString()) << name.toString();
+ if (!requestedProperties.empty())
+ propertyDependencies[fullPropName].insert(requestedProperties.top());
+ m_requestedProperties.push(fullPropName);
}
}
@@ -569,7 +560,7 @@ public:
}
private:
- QStack<QualifiedId> &m_requestedProperties;
+ std::stack<QualifiedId> &m_requestedProperties;
bool m_stackUpdate = false;
};
@@ -599,7 +590,7 @@ QScriptValue EvaluatorScriptClass::property(const QScriptValue &object, const QS
if (debugProperties)
qDebug() << "[SC] property " << name;
- PropertyStackManager propStackmanager(itemOfProperty, name, value.data(),
+ PropertyStackManager propStackmanager(itemOfProperty, name, value.get(),
m_requestedProperties, m_propertyDependencies);
QScriptValue result;
@@ -612,7 +603,7 @@ QScriptValue EvaluatorScriptClass::property(const QScriptValue &object, const QS
}
}
- if (value->next() && !m_currentNextChain.contains(value.data())) {
+ if (value->next() && !m_currentNextChain.contains(value.get())) {
collectValuesFromNextChain(data, &result, name.toString(), value);
} else {
QScriptValue parentObject;
@@ -623,7 +614,7 @@ QScriptValue EvaluatorScriptClass::property(const QScriptValue &object, const QS
converter.start();
const PropertyDeclaration decl = data->item->propertyDeclaration(name.toString());
- convertToPropertyType(data->item, decl, value.data(), result);
+ convertToPropertyType(data->item, decl, value.get(), result);
}
if (debugProperties)
@@ -633,6 +624,59 @@ QScriptValue EvaluatorScriptClass::property(const QScriptValue &object, const QS
return result;
}
+class EvaluatorScriptClassPropertyIterator : public QScriptClassPropertyIterator
+{
+public:
+ EvaluatorScriptClassPropertyIterator(const QScriptValue &object, EvaluationData *data)
+ : QScriptClassPropertyIterator(object), m_it(data->item->properties())
+ {
+ }
+
+ bool hasNext() const override
+ {
+ return m_it.hasNext();
+ }
+
+ void next() override
+ {
+ m_it.next();
+ }
+
+ bool hasPrevious() const override
+ {
+ return m_it.hasPrevious();
+ }
+
+ void previous() override
+ {
+ m_it.previous();
+ }
+
+ void toFront() override
+ {
+ m_it.toFront();
+ }
+
+ void toBack() override
+ {
+ m_it.toBack();
+ }
+
+ QScriptString name() const override
+ {
+ return object().engine()->toStringHandle(m_it.key());
+ }
+
+private:
+ QMapIterator<QString, ValuePtr> m_it;
+};
+
+QScriptClassPropertyIterator *EvaluatorScriptClass::newIterator(const QScriptValue &object)
+{
+ EvaluationData *const data = attachedPointer<EvaluationData>(object);
+ return data ? new EvaluatorScriptClassPropertyIterator(object, data) : nullptr;
+}
+
void EvaluatorScriptClass::setValueCacheEnabled(bool enabled)
{
m_valueCacheEnabled = enabled;
diff --git a/src/lib/corelib/language/evaluatorscriptclass.h b/src/lib/corelib/language/evaluatorscriptclass.h
index c6c16cf44..865d9e971 100644..100755
--- a/src/lib/corelib/language/evaluatorscriptclass.h
+++ b/src/lib/corelib/language/evaluatorscriptclass.h
@@ -46,10 +46,10 @@
#include <logging/logger.h>
#include <tools/set.h>
-#include <QtCore/qstack.h>
-
#include <QtScript/qscriptclass.h>
+#include <stack>
+
QT_BEGIN_NAMESPACE
class QScriptContext;
QT_END_NAMESPACE
@@ -67,9 +67,10 @@ public:
QueryFlags queryProperty(const QScriptValue &object,
const QScriptString &name,
- QueryFlags flags, uint *id);
+ QueryFlags flags, uint *id) override;
QScriptValue property(const QScriptValue &object,
- const QScriptString &name, uint id);
+ const QScriptString &name, uint id) override;
+ QScriptClassPropertyIterator *newIterator(const QScriptValue &object) override;
void setValueCacheEnabled(bool enabled);
@@ -113,7 +114,7 @@ private:
bool m_valueCacheEnabled;
Set<Value *> m_currentNextChain;
PropertyDependencies m_propertyDependencies;
- QStack<QualifiedId> m_requestedProperties;
+ std::stack<QualifiedId> m_requestedProperties;
};
} // namespace Internal
diff --git a/src/lib/corelib/language/filecontext.h b/src/lib/corelib/language/filecontext.h
index 7a0511632..001e64066 100644
--- a/src/lib/corelib/language/filecontext.h
+++ b/src/lib/corelib/language/filecontext.h
@@ -53,7 +53,7 @@ class ItemPool;
class FileContext : public FileContextBase
{
public:
- static FileContextPtr create();
+ static FileContextPtr QBS_AUTOTEST_EXPORT create();
void setContent(const QString &content) { m_content = content; }
const QString &content() const { return m_content; }
diff --git a/src/lib/corelib/language/forward_decls.h b/src/lib/corelib/language/forward_decls.h
index 6b09449c2..4ce9d57eb 100644
--- a/src/lib/corelib/language/forward_decls.h
+++ b/src/lib/corelib/language/forward_decls.h
@@ -39,94 +39,101 @@
#ifndef QBS_LANG_FORWARD_DECLS_H
#define QBS_LANG_FORWARD_DECLS_H
-#include <QtCore/qsharedpointer.h>
+#include <memory>
+
+#include <QtCore/qhash.h>
namespace qbs {
namespace Internal {
class Value;
-typedef QSharedPointer<Value> ValuePtr;
-typedef QSharedPointer<const Value> ValueConstPtr;
+typedef std::shared_ptr<Value> ValuePtr;
+typedef std::shared_ptr<const Value> ValueConstPtr;
class ItemValue;
-typedef QSharedPointer<ItemValue> ItemValuePtr;
-typedef QSharedPointer<const ItemValue> ItemValueConstPtr;
+typedef std::shared_ptr<ItemValue> ItemValuePtr;
+typedef std::shared_ptr<const ItemValue> ItemValueConstPtr;
class JSSourceValue;
-typedef QSharedPointer<JSSourceValue> JSSourceValuePtr;
-typedef QSharedPointer<const JSSourceValue> JSSourceValueConstPtr;
+typedef std::shared_ptr<JSSourceValue> JSSourceValuePtr;
+typedef std::shared_ptr<const JSSourceValue> JSSourceValueConstPtr;
class VariantValue;
-typedef QSharedPointer<VariantValue> VariantValuePtr;
-typedef QSharedPointer<const VariantValue> VariantValueConstPtr;
+typedef std::shared_ptr<VariantValue> VariantValuePtr;
+typedef std::shared_ptr<const VariantValue> VariantValueConstPtr;
class FileContext;
-typedef QSharedPointer<FileContext> FileContextPtr;
-typedef QSharedPointer<const FileContext> FileContextConstPtr;
+typedef std::shared_ptr<FileContext> FileContextPtr;
+typedef std::shared_ptr<const FileContext> FileContextConstPtr;
class FileContextBase;
-typedef QSharedPointer<FileContextBase> FileContextBasePtr;
-typedef QSharedPointer<const FileContextBase> FileContextBaseConstPtr;
+typedef std::shared_ptr<FileContextBase> FileContextBasePtr;
+typedef std::shared_ptr<const FileContextBase> FileContextBaseConstPtr;
class Probe;
-typedef QSharedPointer<Probe> ProbePtr;
-typedef QSharedPointer<const Probe> ProbeConstPtr;
+typedef std::shared_ptr<Probe> ProbePtr;
+typedef std::shared_ptr<const Probe> ProbeConstPtr;
class PropertyMapInternal;
-typedef QSharedPointer<PropertyMapInternal> PropertyMapPtr;
-typedef QSharedPointer<const PropertyMapInternal> PropertyMapConstPtr;
+typedef std::shared_ptr<PropertyMapInternal> PropertyMapPtr;
+typedef std::shared_ptr<const PropertyMapInternal> PropertyMapConstPtr;
class FileTagger;
-typedef QSharedPointer<FileTagger> FileTaggerPtr;
-typedef QSharedPointer<const FileTagger> FileTaggerConstPtr;
+typedef std::shared_ptr<FileTagger> FileTaggerPtr;
+typedef std::shared_ptr<const FileTagger> FileTaggerConstPtr;
class ResolvedProduct;
-typedef QSharedPointer<ResolvedProduct> ResolvedProductPtr;
-typedef QSharedPointer<const ResolvedProduct> ResolvedProductConstPtr;
+typedef std::shared_ptr<ResolvedProduct> ResolvedProductPtr;
+typedef std::shared_ptr<const ResolvedProduct> ResolvedProductConstPtr;
class ResolvedProject;
-typedef QSharedPointer<ResolvedProject> ResolvedProjectPtr;
-typedef QSharedPointer<const ResolvedProject> ResolvedProjectConstPtr;
+typedef std::shared_ptr<ResolvedProject> ResolvedProjectPtr;
+typedef std::shared_ptr<const ResolvedProject> ResolvedProjectConstPtr;
class TopLevelProject;
-typedef QSharedPointer<TopLevelProject> TopLevelProjectPtr;
-typedef QSharedPointer<const TopLevelProject> TopLevelProjectConstPtr;
+typedef std::shared_ptr<TopLevelProject> TopLevelProjectPtr;
+typedef std::shared_ptr<const TopLevelProject> TopLevelProjectConstPtr;
class ResolvedFileContext;
-typedef QSharedPointer<ResolvedFileContext> ResolvedFileContextPtr;
-typedef QSharedPointer<const ResolvedFileContext> ResolvedFileContextConstPtr;
+typedef std::shared_ptr<ResolvedFileContext> ResolvedFileContextPtr;
+typedef std::shared_ptr<const ResolvedFileContext> ResolvedFileContextConstPtr;
class Rule;
-typedef QSharedPointer<Rule> RulePtr;
-typedef QSharedPointer<const Rule> RuleConstPtr;
+typedef std::shared_ptr<Rule> RulePtr;
+typedef std::shared_ptr<const Rule> RuleConstPtr;
class ResolvedScanner;
-typedef QSharedPointer<ResolvedScanner> ResolvedScannerPtr;
-typedef QSharedPointer<const ResolvedScanner> ResolvedScannerConstPtr;
+typedef std::shared_ptr<ResolvedScanner> ResolvedScannerPtr;
+typedef std::shared_ptr<const ResolvedScanner> ResolvedScannerConstPtr;
class SourceArtifactInternal;
-typedef QSharedPointer<SourceArtifactInternal> SourceArtifactPtr;
-typedef QSharedPointer<const SourceArtifactInternal> SourceArtifactConstPtr;
+typedef std::shared_ptr<SourceArtifactInternal> SourceArtifactPtr;
+typedef std::shared_ptr<const SourceArtifactInternal> SourceArtifactConstPtr;
class ScriptFunction;
-typedef QSharedPointer<ScriptFunction> ScriptFunctionPtr;
-typedef QSharedPointer<const ScriptFunction> ScriptFunctionConstPtr;
+typedef std::shared_ptr<ScriptFunction> ScriptFunctionPtr;
+typedef std::shared_ptr<const ScriptFunction> ScriptFunctionConstPtr;
class RuleArtifact;
-typedef QSharedPointer<RuleArtifact> RuleArtifactPtr;
-typedef QSharedPointer<const RuleArtifact> RuleArtifactConstPtr;
+typedef std::shared_ptr<RuleArtifact> RuleArtifactPtr;
+typedef std::shared_ptr<const RuleArtifact> RuleArtifactConstPtr;
class ResolvedModule;
-typedef QSharedPointer<ResolvedModule> ResolvedModulePtr;
-typedef QSharedPointer<const ResolvedModule> ResolvedModuleConstPtr;
+typedef std::shared_ptr<ResolvedModule> ResolvedModulePtr;
+typedef std::shared_ptr<const ResolvedModule> ResolvedModuleConstPtr;
class ResolvedGroup;
-typedef QSharedPointer<ResolvedGroup> GroupPtr;
-typedef QSharedPointer<const ResolvedGroup> GroupConstPtr;
+typedef std::shared_ptr<ResolvedGroup> GroupPtr;
+typedef std::shared_ptr<const ResolvedGroup> GroupConstPtr;
class ArtifactProperties;
-typedef QSharedPointer<ArtifactProperties> ArtifactPropertiesPtr;
-typedef QSharedPointer<const ArtifactProperties> ArtifactPropertiesConstPtr;
+typedef std::shared_ptr<ArtifactProperties> ArtifactPropertiesPtr;
+typedef std::shared_ptr<const ArtifactProperties> ArtifactPropertiesConstPtr;
+
+template <typename T> inline static uint qHash(const std::shared_ptr<T> &p, uint seed = 0)
+{
+ return ::qHash(p.get(), seed);
+}
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/identifiersearch.h b/src/lib/corelib/language/identifiersearch.h
index 999366314..e466c576a 100644
--- a/src/lib/corelib/language/identifiersearch.h
+++ b/src/lib/corelib/language/identifiersearch.h
@@ -42,13 +42,14 @@
#include <parser/qmljsastfwd_p.h>
#include <parser/qmljsastvisitor_p.h>
+#include <tools/qbs_export.h>
#include <QtCore/qmap.h>
#include <QtCore/qstring.h>
namespace qbs {
namespace Internal {
-class IdentifierSearch : private QbsQmlJS::AST::Visitor
+class QBS_AUTOTEST_EXPORT IdentifierSearch : private QbsQmlJS::AST::Visitor
{
public:
IdentifierSearch();
diff --git a/src/lib/corelib/language/item.cpp b/src/lib/corelib/language/item.cpp
index 3e6da3231..e02fa08c3 100644
--- a/src/lib/corelib/language/item.cpp
+++ b/src/lib/corelib/language/item.cpp
@@ -59,7 +59,7 @@ namespace Internal {
Item::Item(ItemPool *pool, ItemType type)
: m_pool(pool)
- , m_propertyObserver(0)
+ , m_observer(0)
, m_prototype(0)
, m_scope(0)
, m_outerItem(0)
@@ -106,7 +106,9 @@ QString Item::typeName() const
switch (type()) {
case ItemType::IdScope: return QLatin1String("[IdScope]");
case ItemType::ModuleInstance: return QLatin1String("[ModuleInstance]");
+ case ItemType::ModuleParameters: return QLatin1String("[ModuleParametersInstance]");
case ItemType::ModulePrefix: return QLatin1String("[ModulePrefix]");
+ case ItemType::Outer: return QLatin1String("[Outer]");
case ItemType::Scope: return QLatin1String("[Scope]");
default: return BuiltinDeclarations::instance().nameForType(type());
}
@@ -150,7 +152,7 @@ ItemValuePtr Item::itemProperty(const QString &name, const Item *itemTemplate)
ItemValuePtr result;
ValuePtr v = property(name);
if (v && v->type() == Value::ItemValueType) {
- result = v.staticCast<ItemValue>();
+ result = std::static_pointer_cast<ItemValue>(v);
} else if (itemTemplate) {
result = ItemValue::create(Item::create(m_pool, itemTemplate->type()));
setProperty(name, result);
@@ -163,7 +165,7 @@ JSSourceValuePtr Item::sourceProperty(const QString &name) const
ValuePtr v = property(name);
if (!v || v->type() != Value::JSSourceValueType)
return JSSourceValuePtr();
- return v.staticCast<JSSourceValue>();
+ return std::static_pointer_cast<JSSourceValue>(v);
}
VariantValuePtr Item::variantProperty(const QString &name) const
@@ -171,7 +173,7 @@ VariantValuePtr Item::variantProperty(const QString &name) const
ValuePtr v = property(name);
if (!v || v->type() != Value::VariantValueType)
return VariantValuePtr();
- return v.staticCast<VariantValue>();
+ return std::static_pointer_cast<VariantValue>(v);
}
PropertyDeclaration Item::propertyDeclaration(const QString &name) const
@@ -187,17 +189,17 @@ void Item::addModule(const Item::Module &module)
m_modules.insert(it, module);
}
-void Item::setPropertyObserver(ItemObserver *observer) const
+void Item::setObserver(ItemObserver *observer) const
{
- QBS_ASSERT(!observer || !m_propertyObserver, return); // warn if accidentally overwritten
- m_propertyObserver = observer;
+ QBS_ASSERT(!observer || !m_observer, return); // warn if accidentally overwritten
+ m_observer = observer;
}
void Item::setProperty(const QString &name, const ValuePtr &value)
{
m_properties.insert(name, value);
- if (m_propertyObserver)
- m_propertyObserver->onItemPropertyChanged(this);
+ if (m_observer)
+ m_observer->onItemPropertyChanged(this);
}
void Item::dump() const
@@ -273,19 +275,19 @@ void Item::dump(int indentation) const
for (auto it = m_properties.constBegin(); it != m_properties.constEnd(); ++it) {
const QByteArray nextIndent(indentation + 4, ' ');
qDebug("%skey: %s, value type: %s", nextIndent.constData(), qPrintable(it.key()),
- valueType(it.value().data()));
+ valueType(it.value().get()));
switch (it.value()->type()) {
case Value::JSSourceValueType:
qDebug("%svalue: %s", nextIndent.constData(),
- qPrintable(it.value().staticCast<JSSourceValue>()->sourceCodeForEvaluation()));
+ qPrintable(std::static_pointer_cast<JSSourceValue>(it.value())->sourceCodeForEvaluation()));
break;
case Value::ItemValueType:
qDebug("%svalue:", nextIndent.constData());
- it.value().staticCast<ItemValue>()->item()->dump(indentation + 8);
+ std::static_pointer_cast<ItemValue>(it.value())->item()->dump(indentation + 8);
break;
case Value::VariantValueType:
qDebug("%svalue: %s", nextIndent.constData(),
- qPrintable(it.value().staticCast<VariantValue>()->value().toString()));
+ qPrintable(std::static_pointer_cast<VariantValue>(it.value())->value().toString()));
break;
}
}
@@ -336,5 +338,10 @@ void Item::setPropertyDeclaration(const QString &name, const PropertyDeclaration
m_propertyDeclarations.insert(name, declaration);
}
+void Item::setPropertyDeclarations(const Item::PropertyDeclarationMap &decls)
+{
+ m_propertyDeclarations = decls;
+}
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/item.h b/src/lib/corelib/language/item.h
index 59140a5c5..3df4c5903 100644
--- a/src/lib/corelib/language/item.h
+++ b/src/lib/corelib/language/item.h
@@ -60,7 +60,7 @@ class ItemObserver;
class ItemPool;
class Logger;
-class Item : public QbsQmlJS::Managed
+class QBS_AUTOTEST_EXPORT Item : public QbsQmlJS::Managed
{
friend class ASTPropertiesItemHandler;
friend class ItemPool;
@@ -79,6 +79,7 @@ public:
Item *item;
bool isProduct;
bool required;
+ QVariantMap parameters;
VersionRange versionRange;
};
typedef std::vector<Module> Modules;
@@ -117,11 +118,12 @@ public:
ItemValuePtr itemProperty(const QString &name, const Item *itemTemplate = nullptr);
JSSourceValuePtr sourceProperty(const QString &name) const;
VariantValuePtr variantProperty(const QString &name) const;
- void setPropertyObserver(ItemObserver *observer) const;
+ void setObserver(ItemObserver *observer) const;
void setProperty(const QString &name, const ValuePtr &value);
void setProperties(const PropertyMap &props) { m_properties = props; }
void removeProperty(const QString &name);
void setPropertyDeclaration(const QString &name, const PropertyDeclaration &declaration);
+ void setPropertyDeclarations(const PropertyDeclarationMap &decls);
void setLocation(const CodeLocation &location) { m_location = location; }
void setPrototype(Item *prototype) { m_prototype = prototype; }
void setFile(const FileContextPtr &file) { m_file = file; }
@@ -139,7 +141,7 @@ private:
void dump(int indentation) const;
ItemPool *m_pool;
- mutable ItemObserver *m_propertyObserver;
+ mutable ItemObserver *m_observer;
QString m_id;
CodeLocation m_location;
Item *m_prototype;
diff --git a/src/lib/corelib/language/itempool.h b/src/lib/corelib/language/itempool.h
index 7ab62d6c1..a4837a057 100644
--- a/src/lib/corelib/language/itempool.h
+++ b/src/lib/corelib/language/itempool.h
@@ -41,6 +41,7 @@
#define QBS_ITEMPOOL_H
#include <parser/qmljsmemorypool_p.h>
+#include <tools/qbs_export.h>
#include <QtCore/qlist.h>
@@ -50,7 +51,7 @@ namespace Internal {
class Item;
enum class ItemType;
-class ItemPool
+class QBS_AUTOTEST_EXPORT ItemPool
{
Q_DISABLE_COPY(ItemPool)
public:
diff --git a/src/lib/corelib/language/itemreader.cpp b/src/lib/corelib/language/itemreader.cpp
index 097adfc1c..564fe1323 100644
--- a/src/lib/corelib/language/itemreader.cpp
+++ b/src/lib/corelib/language/itemreader.cpp
@@ -62,15 +62,15 @@ void ItemReader::setSearchPaths(const QStringList &searchPaths)
void ItemReader::pushExtraSearchPaths(const QStringList &extraSearchPaths)
{
- m_extraSearchPaths.push(extraSearchPaths);
+ m_extraSearchPaths.push_back(extraSearchPaths);
}
void ItemReader::popExtraSearchPaths()
{
- m_extraSearchPaths.pop();
+ m_extraSearchPaths.pop_back();
}
-QStack<QStringList> ItemReader::extraSearchPathsStack() const
+std::vector<QStringList> ItemReader::extraSearchPathsStack() const
{
return m_extraSearchPaths;
}
@@ -78,8 +78,8 @@ QStack<QStringList> ItemReader::extraSearchPathsStack() const
QStringList ItemReader::searchPaths() const
{
QStringList paths;
- for (int i = m_extraSearchPaths.count(); --i >= 0;)
- paths += m_extraSearchPaths.at(i);
+ for (auto it = m_extraSearchPaths.crbegin(), end = m_extraSearchPaths.crend(); it != end; ++it)
+ paths += *it;
paths += m_searchPaths;
return paths;
}
diff --git a/src/lib/corelib/language/itemreader.h b/src/lib/corelib/language/itemreader.h
index 785dac3c7..293fea996 100644
--- a/src/lib/corelib/language/itemreader.h
+++ b/src/lib/corelib/language/itemreader.h
@@ -44,9 +44,10 @@
#include <logging/logger.h>
#include <tools/set.h>
-#include <QtCore/qstack.h>
#include <QtCore/qstringlist.h>
+#include <stack>
+
namespace qbs {
namespace Internal {
@@ -73,8 +74,8 @@ public:
void setSearchPaths(const QStringList &searchPaths);
void pushExtraSearchPaths(const QStringList &extraSearchPaths);
void popExtraSearchPaths();
- QStack<QStringList> extraSearchPathsStack() const;
- void setExtraSearchPathsStack(const QStack<QStringList> &s) { m_extraSearchPaths = s; }
+ std::vector<QStringList> extraSearchPathsStack() const;
+ void setExtraSearchPathsStack(const std::vector<QStringList> &s) { m_extraSearchPaths = s; }
void clearExtraSearchPathsStack() { m_extraSearchPaths.clear(); }
QStringList searchPaths() const;
@@ -88,7 +89,7 @@ public:
private:
ItemPool *m_pool = nullptr;
QStringList m_searchPaths;
- QStack<QStringList> m_extraSearchPaths;
+ std::vector<QStringList> m_extraSearchPaths;
ItemReaderVisitorState * const m_visitorState;
qint64 m_elapsedTime = -1;
};
diff --git a/src/lib/corelib/language/itemreaderastvisitor.cpp b/src/lib/corelib/language/itemreaderastvisitor.cpp
index f748119d2..4bc629c5e 100644
--- a/src/lib/corelib/language/itemreaderastvisitor.cpp
+++ b/src/lib/corelib/language/itemreaderastvisitor.cpp
@@ -268,6 +268,7 @@ Item *ItemReaderASTVisitor::targetItemForBinding(const QStringList &bindingName,
if (!v) {
const ItemType itemType = i < c - 1 ? ItemType::ModulePrefix : ItemType::ModuleInstance;
Item *newItem = Item::create(m_itemPool, itemType);
+ newItem->setLocation(value->location());
v = ItemValue::create(newItem);
targetItem->setProperty(bindingName.at(i), v);
}
@@ -275,7 +276,7 @@ Item *ItemReaderASTVisitor::targetItemForBinding(const QStringList &bindingName,
QString msg = Tr::tr("Binding to non-item property.");
throw ErrorInfo(msg, value->location());
}
- targetItem = v.staticCast<ItemValue>()->item();
+ targetItem = std::static_pointer_cast<ItemValue>(v)->item();
}
return targetItem;
}
@@ -310,17 +311,17 @@ void ItemReaderASTVisitor::inheritItem(Item *dst, const Item *src)
continue;
switch (v->type()) {
case Value::JSSourceValueType: {
- JSSourceValuePtr sv = v.staticCast<JSSourceValue>();
+ JSSourceValuePtr sv = std::static_pointer_cast<JSSourceValue>(v);
QBS_CHECK(!sv->baseValue());
- const JSSourceValuePtr baseValue = it.value().staticCast<JSSourceValue>();
+ const JSSourceValuePtr baseValue = std::static_pointer_cast<JSSourceValue>(it.value());
sv->setBaseValue(baseValue);
for (const JSSourceValue::Alternative &alt : qAsConst(sv->m_alternatives))
alt.value->setBaseValue(baseValue);
break;
}
case Value::ItemValueType:
- inheritItem(v.staticCast<ItemValue>()->item(),
- it.value().staticCast<const ItemValue>()->item());
+ inheritItem(std::static_pointer_cast<ItemValue>(v)->item(),
+ std::static_pointer_cast<const ItemValue>(it.value())->item());
break;
default:
QBS_CHECK(!"unexpected value type");
diff --git a/src/lib/corelib/language/itemreadervisitorstate.h b/src/lib/corelib/language/itemreadervisitorstate.h
index 3340f5d2a..a72d5fe3a 100644
--- a/src/lib/corelib/language/itemreadervisitorstate.h
+++ b/src/lib/corelib/language/itemreadervisitorstate.h
@@ -42,9 +42,10 @@
#include <logging/logger.h>
#include <tools/set.h>
-#include <QtCore/qstack.h>
#include <QtCore/qstringlist.h>
+#include <stack>
+
namespace qbs {
namespace Internal {
class Item;
diff --git a/src/lib/corelib/language/itemtype.h b/src/lib/corelib/language/itemtype.h
index a4aa8c768..4901cbbe4 100644
--- a/src/lib/corelib/language/itemtype.h
+++ b/src/lib/corelib/language/itemtype.h
@@ -54,6 +54,8 @@ enum class ItemType {
FileTagger,
Group,
Module,
+ Parameter,
+ Parameters,
Probe,
Product,
Project,
@@ -69,7 +71,9 @@ enum class ItemType {
// Internal items created mainly by the module loader.
IdScope,
ModuleInstance,
+ ModuleParameters,
ModulePrefix,
+ Outer,
Scope,
Unknown
diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp
index fb920ccad..c5aa34ae1 100644
--- a/src/lib/corelib/language/language.cpp
+++ b/src/lib/corelib/language/language.cpp
@@ -337,7 +337,7 @@ bool operator==(const ScriptFunction &a, const ScriptFunction &b)
return a.sourceCode == b.sourceCode
&& a.location == b.location
&& a.argumentNames == b.argumentNames
- && equals(a.fileContext.data(), b.fileContext.data());
+ && equals(a.fileContext.get(), b.fileContext.get());
}
void ResolvedModule::load(PersistentPool &pool)
@@ -346,6 +346,7 @@ void ResolvedModule::load(PersistentPool &pool)
pool.load(moduleDependencies);
pool.load(setupBuildEnvironmentScript);
pool.load(setupRunEnvironmentScript);
+ pool.load(isProduct);
}
void ResolvedModule::store(PersistentPool &pool) const
@@ -354,14 +355,16 @@ void ResolvedModule::store(PersistentPool &pool) const
pool.store(moduleDependencies);
pool.store(setupBuildEnvironmentScript);
pool.store(setupRunEnvironmentScript);
+ pool.store(isProduct);
}
bool operator==(const ResolvedModule &m1, const ResolvedModule &m2)
{
return m1.name == m2.name
+ && m1.isProduct == m2.isProduct
&& m1.moduleDependencies.toSet() == m2.moduleDependencies.toSet()
- && equals(m1.setupBuildEnvironmentScript.data(), m2.setupBuildEnvironmentScript.data())
- && equals(m1.setupRunEnvironmentScript.data(), m2.setupRunEnvironmentScript.data());
+ && equals(m1.setupBuildEnvironmentScript.get(), m2.setupBuildEnvironmentScript.get())
+ && equals(m1.setupRunEnvironmentScript.get(), m2.setupRunEnvironmentScript.get());
}
QString Rule::toString() const
@@ -400,7 +403,7 @@ bool Rule::isDynamic() const
return outputArtifactsScript->isValid();
}
-bool Rule::requiresInputs() const
+bool Rule::declaresInputs() const
{
return !inputs.isEmpty() || !inputsFromDependencies.isEmpty();
}
@@ -418,6 +421,7 @@ void Rule::load(PersistentPool &pool)
pool.load(inputsFromDependencies);
pool.load(explicitlyDependsOn);
pool.load(multiplex);
+ pool.load(requiresInputs);
pool.load(alwaysRun);
pool.load(artifacts);
}
@@ -435,6 +439,7 @@ void Rule::store(PersistentPool &pool) const
pool.store(inputsFromDependencies);
pool.store(explicitlyDependsOn);
pool.store(multiplex);
+ pool.store(requiresInputs);
pool.store(alwaysRun);
pool.store(artifacts);
}
@@ -502,6 +507,7 @@ void ResolvedProduct::load(PersistentPool &pool)
pool.load(fileTags);
pool.load(name);
pool.load(profile);
+ pool.load(multiplexConfigurationId);
pool.load(targetName);
pool.load(sourceDirectory);
pool.load(destinationDirectory);
@@ -511,8 +517,10 @@ void ResolvedProduct::load(PersistentPool &pool)
pool.load(moduleProperties);
pool.load(rules);
pool.load(dependencies);
+ pool.load(dependencyParameters);
pool.load(fileTaggers);
pool.load(modules);
+ pool.load(moduleParameters);
pool.load(scanners);
pool.load(groups);
pool.load(artifactProperties);
@@ -526,6 +534,7 @@ void ResolvedProduct::store(PersistentPool &pool) const
pool.store(fileTags);
pool.store(name);
pool.store(profile);
+ pool.store(multiplexConfigurationId);
pool.store(targetName);
pool.store(sourceDirectory);
pool.store(destinationDirectory);
@@ -535,8 +544,10 @@ void ResolvedProduct::store(PersistentPool &pool) const
pool.store(moduleProperties);
pool.store(rules);
pool.store(dependencies);
+ pool.store(dependencyParameters);
pool.store(fileTaggers);
pool.store(modules);
+ pool.store(moduleParameters);
pool.store(scanners);
pool.store(groups);
pool.store(artifactProperties);
@@ -594,7 +605,7 @@ static QProcessEnvironment getProcessEnvironment(ScriptEngine *engine, EnvType e
{
QMap<QString, const ResolvedModule *> moduleMap;
for (const ResolvedModuleConstPtr &module : modules)
- moduleMap.insert(module->name, module.data());
+ moduleMap.insert(module->name, module.get());
QHash<const ResolvedModule*, QList<const ResolvedModule*> > moduleParents;
QHash<const ResolvedModule*, QList<const ResolvedModule*> > moduleChildren;
@@ -602,16 +613,16 @@ static QProcessEnvironment getProcessEnvironment(ScriptEngine *engine, EnvType e
for (const QString &moduleName : qAsConst(module->moduleDependencies)) {
const ResolvedModule * const depmod = moduleMap.value(moduleName);
QBS_ASSERT(depmod, return env);
- moduleParents[depmod].append(module.data());
- moduleChildren[module.data()].append(depmod);
+ moduleParents[depmod].append(module.get());
+ moduleChildren[module.get()].append(depmod);
}
}
QList<const ResolvedModule *> rootModules;
for (const ResolvedModuleConstPtr &module : modules) {
- if (moduleParents.value(module.data()).isEmpty()) {
+ if (moduleParents.value(module.get()).isEmpty()) {
QBS_ASSERT(module, return env);
- rootModules.append(module.data());
+ rootModules.append(module.get());
}
}
@@ -758,15 +769,17 @@ TopLevelProject *ResolvedProduct::topLevelProject() const
return project->topLevelProject();
}
-QString ResolvedProduct::uniqueName(const QString &name, const QString &profile)
+QString ResolvedProduct::uniqueName(const QString &name, const QString &multiplexConfigurationId)
{
- QBS_CHECK(!profile.isEmpty());
- return name + QLatin1Char('.') + profile;
+ QString result = name;
+ if (!multiplexConfigurationId.isEmpty())
+ result.append(QLatin1Char('.')).append(multiplexConfigurationId);
+ return result;
}
QString ResolvedProduct::uniqueName() const
{
- return uniqueName(name, profile);
+ return uniqueName(name, multiplexConfigurationId);
}
static QStringList findGeneratedFiles(const Artifact *base, bool recursive, const FileTags &tags)
@@ -795,9 +808,10 @@ QStringList ResolvedProduct::generatedFiles(const QString &baseFile, bool recurs
return QStringList();
}
-QString ResolvedProduct::deriveBuildDirectoryName(const QString &name, const QString &profile)
+QString ResolvedProduct::deriveBuildDirectoryName(const QString &name,
+ const QString &multiplexConfigurationId)
{
- QString dirName = uniqueName(name, profile);
+ QString dirName = uniqueName(name, multiplexConfigurationId);
const QByteArray hash = QCryptographicHash::hash(dirName.toUtf8(), QCryptographicHash::Sha1);
return HostOsInfo::rfc1034Identifier(dirName)
.append(QLatin1Char('.'))
@@ -811,9 +825,9 @@ QString ResolvedProduct::buildDirectory() const
bool ResolvedProduct::isInParentProject(const ResolvedProductConstPtr &other) const
{
- for (const ResolvedProject *otherParent = other->project.data(); otherParent;
- otherParent = otherParent->parentProject.data()) {
- if (otherParent == project.data())
+ for (const ResolvedProject *otherParent = other->project.get(); otherParent;
+ otherParent = otherParent->parentProject.get()) {
+ if (otherParent == project.get())
return true;
}
return false;
@@ -858,7 +872,7 @@ TopLevelProject *ResolvedProject::topLevelProject()
m_topLevelProject = tlp;
return m_topLevelProject;
}
- QBS_CHECK(!parentProject.isNull());
+ QBS_CHECK(!parentProject.expired());
m_topLevelProject = parentProject->topLevelProject();
return m_topLevelProject;
}
@@ -985,6 +999,7 @@ void TopLevelProject::load(PersistentPool &pool)
pool.load(environment);
pool.load(probes);
pool.load(profileConfigs);
+ pool.load(overriddenValues);
pool.load(buildSystemFiles);
pool.load(lastResolveTime);
pool.load(warningsEncountered);
@@ -1005,6 +1020,7 @@ void TopLevelProject::store(PersistentPool &pool) const
pool.store(environment);
pool.store(probes);
pool.store(profileConfigs);
+ pool.store(overriddenValues);
pool.store(buildSystemFiles);
pool.store(lastResolveTime);
pool.store(warningsEncountered);
@@ -1153,7 +1169,7 @@ template<typename T> bool listsAreEqual(const QList<T> &l1, const QList<T> &l2)
const T value2 = map2.value(key);
if (!value2)
return false;
- if (!equals(map1.value(key).data(), value2.data()))
+ if (!equals(map1.value(key).get(), value2.get()))
return false;
}
return true;
@@ -1196,13 +1212,13 @@ bool operator==(const Rule &r1, const Rule &r2)
if (r1.artifacts.count() != r2.artifacts.count())
return false;
for (int i = 0; i < r1.artifacts.count(); ++i) {
- if (!equals(r1.artifacts.at(i).data(), r2.artifacts.at(i).data()))
+ if (!equals(r1.artifacts.at(i).get(), r2.artifacts.at(i).get()))
return false;
}
return r1.module->name == r2.module->name
- && equals(r1.prepareScript.data(), r2.prepareScript.data())
- && equals(r1.outputArtifactsScript.data(), r2.outputArtifactsScript.data())
+ && equals(r1.prepareScript.get(), r2.prepareScript.get())
+ && equals(r1.outputArtifactsScript.get(), r2.outputArtifactsScript.get())
&& r1.inputs == r2.inputs
&& r1.outputFileTags == r2.outputFileTags
&& r1.auxiliaryInputs == r2.auxiliaryInputs
@@ -1210,6 +1226,7 @@ bool operator==(const Rule &r1, const Rule &r2)
&& r1.inputsFromDependencies == r2.inputsFromDependencies
&& r1.explicitlyDependsOn == r2.explicitlyDependsOn
&& r1.multiplex == r2.multiplex
+ && r1.requiresInputs == r2.requiresInputs
&& r1.alwaysRun == r2.alwaysRun;
}
diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h
index 2943996c8..d65a12536 100644
--- a/src/lib/corelib/language/language.h
+++ b/src/lib/corelib/language/language.h
@@ -223,8 +223,8 @@ bool sourceArtifactSetsAreEqual(const QList<SourceArtifactPtr> &l1,
class SourceWildCards : public PersistentObject
{
public:
- typedef QSharedPointer<SourceWildCards> Ptr;
- typedef QSharedPointer<const SourceWildCards> ConstPtr;
+ typedef std::shared_ptr<SourceWildCards> Ptr;
+ typedef std::shared_ptr<const SourceWildCards> ConstPtr;
static Ptr create() { return Ptr(new SourceWildCards); }
@@ -252,7 +252,7 @@ private:
void store(PersistentPool &pool) const;
};
-class ResolvedGroup : public PersistentObject
+class QBS_AUTOTEST_EXPORT ResolvedGroup : public PersistentObject
{
public:
static GroupPtr create() { return GroupPtr(new ResolvedGroup); }
@@ -313,6 +313,7 @@ public:
QStringList moduleDependencies;
ScriptFunctionPtr setupBuildEnvironmentScript;
ScriptFunctionPtr setupRunEnvironmentScript;
+ bool isProduct;
private:
ResolvedModule() {}
@@ -348,6 +349,7 @@ public:
FileTags inputsFromDependencies;
FileTags explicitlyDependsOn;
bool multiplex;
+ bool requiresInputs;
QList<RuleArtifactPtr> artifacts; // unused, if outputFileTags/outputArtifactsScript is non-empty
bool alwaysRun;
@@ -359,7 +361,7 @@ public:
FileTags staticOutputFileTags() const;
FileTags collectedOutputFileTags() const;
bool isDynamic() const;
- bool requiresInputs() const;
+ bool declaresInputs() const;
private:
Rule() : multiplex(false), alwaysRun(false), ruleGraphId(-1) {}
@@ -393,7 +395,7 @@ private:
class TopLevelProject;
class ScriptEngine;
-class ResolvedProduct : public PersistentObject
+class QBS_AUTOTEST_EXPORT ResolvedProduct : public PersistentObject
{
public:
static ResolvedProductPtr create() { return ResolvedProductPtr(new ResolvedProduct); }
@@ -405,6 +407,7 @@ public:
QString name;
QString targetName;
QString profile;
+ QString multiplexConfigurationId;
QString sourceDirectory;
QString destinationDirectory;
CodeLocation location;
@@ -413,8 +416,10 @@ public:
PropertyMapPtr moduleProperties;
Set<RulePtr> rules;
Set<ResolvedProductPtr> dependencies;
+ QHash<ResolvedProductConstPtr, QVariantMap> dependencyParameters;
QList<FileTaggerConstPtr> fileTaggers;
QList<ResolvedModuleConstPtr> modules;
+ QHash<ResolvedModuleConstPtr, QVariantMap> moduleParameters;
QList<ResolvedScannerConstPtr> scanners;
QList<GroupPtr> groups;
QList<ProbeConstPtr> probes;
@@ -442,12 +447,14 @@ public:
TopLevelProject *topLevelProject() const;
- static QString uniqueName(const QString &name, const QString &profile);
+ static QString uniqueName(const QString &name,
+ const QString &multiplexConfigurationId);
QString uniqueName() const;
QStringList generatedFiles(const QString &baseFile, bool recursive, const FileTags &tags) const;
- static QString deriveBuildDirectoryName(const QString &name, const QString &profile);
+ static QString deriveBuildDirectoryName(const QString &name,
+ const QString &multiplexConfigurationId);
QString buildDirectory() const;
bool isInParentProject(const ResolvedProductConstPtr &other) const;
@@ -466,7 +473,7 @@ private:
mutable std::mutex m_executablePathCacheLock;
};
-class ResolvedProject : public PersistentObject
+class QBS_AUTOTEST_EXPORT ResolvedProject : public PersistentObject
{
public:
static ResolvedProjectPtr create() { return ResolvedProjectPtr(new ResolvedProject); }
@@ -497,7 +504,7 @@ private:
TopLevelProject *m_topLevelProject;
};
-class TopLevelProject : public ResolvedProject
+class QBS_AUTOTEST_EXPORT TopLevelProject : public ResolvedProject
{
friend class BuildGraphLoader;
public:
@@ -535,6 +542,7 @@ public:
QString id() const { return m_id; }
QString profile() const;
QVariantMap profileConfigs;
+ QVariantMap overriddenValues;
QString buildGraphFilePath() const;
void store(Logger logger) const;
diff --git a/src/lib/corelib/language/language.pri b/src/lib/corelib/language/language.pri
index c3bcbb674..d1961df9e 100644
--- a/src/lib/corelib/language/language.pri
+++ b/src/lib/corelib/language/language.pri
@@ -73,11 +73,6 @@ SOURCES += \
$$PWD/scriptimporter.cpp \
$$PWD/value.cpp
-qbs_enable_unit_tests {
- HEADERS += $$PWD/tst_language.h
- SOURCES += $$PWD/tst_language.cpp
-}
-
!qbs_no_dev_install {
language_headers.files = $$PWD/forward_decls.h
language_headers.path = $${QBS_INSTALL_PREFIX}/include/qbs/language
diff --git a/src/lib/corelib/language/loader.cpp b/src/lib/corelib/language/loader.cpp
index f98d82fec..821def454 100644
--- a/src/lib/corelib/language/loader.cpp
+++ b/src/lib/corelib/language/loader.cpp
@@ -47,8 +47,10 @@
#include <logging/translator.h>
#include <tools/fileinfo.h>
+#include <tools/profile.h>
#include <tools/progressobserver.h>
#include <tools/qbsassert.h>
+#include <tools/settings.h>
#include <tools/setupprojectparameters.h>
#include <QtCore/qdir.h>
@@ -96,10 +98,27 @@ void Loader::setOldProductProbes(const QHash<QString, QList<ProbeConstPtr>> &old
m_oldProductProbes = oldProbes;
}
-TopLevelProjectPtr Loader::loadProject(const SetupProjectParameters &parameters)
+void Loader::setStoredProfiles(const QVariantMap &profiles)
{
- QBS_CHECK(QFileInfo(parameters.projectFilePath()).isAbsolute());
+ m_storedProfiles = profiles;
+}
+TopLevelProjectPtr Loader::loadProject(const SetupProjectParameters &_parameters)
+{
+ QBS_CHECK(QFileInfo(_parameters.projectFilePath()).isAbsolute());
+
+ SetupProjectParameters parameters = _parameters;
+ if (parameters.topLevelProfile().isEmpty()) {
+ Settings settings(parameters.settingsDirectory());
+ QString profileName = settings.defaultProfile();
+ if (profileName.isEmpty()) {
+ m_logger.qbsDebug() << Tr::tr("No profile specified and no default profile exists. "
+ "Using default property values.");
+ profileName = Profile::fallbackName();
+ }
+ parameters.setTopLevelProfile(profileName);
+ parameters.expandBuildConfiguration();
+ }
m_engine->setEnvironment(parameters.adjustedEnvironment());
m_engine->clearExceptions();
m_engine->clearImportsCache();
@@ -127,12 +146,13 @@ TopLevelProjectPtr Loader::loadProject(const SetupProjectParameters &parameters)
}
const FileTime resolveTime = FileTime::currentTime();
- Evaluator evaluator(m_engine, m_logger);
+ Evaluator evaluator(m_engine);
ModuleLoader moduleLoader(&evaluator, m_logger);
moduleLoader.setProgressObserver(m_progressObserver);
moduleLoader.setSearchPaths(m_searchPaths);
moduleLoader.setOldProjectProbes(m_oldProjectProbes);
moduleLoader.setOldProductProbes(m_oldProductProbes);
+ moduleLoader.setStoredProfiles(m_storedProfiles);
const ModuleLoaderResult loadResult = moduleLoader.load(parameters);
ProjectResolver resolver(&evaluator, loadResult, parameters, m_logger);
resolver.setProgressObserver(m_progressObserver);
diff --git a/src/lib/corelib/language/loader.h b/src/lib/corelib/language/loader.h
index 82183c453..b94fb7553 100644
--- a/src/lib/corelib/language/loader.h
+++ b/src/lib/corelib/language/loader.h
@@ -52,7 +52,7 @@ class Logger;
class ProgressObserver;
class ScriptEngine;
-class Loader
+class QBS_AUTOTEST_EXPORT Loader
{
public:
Loader(ScriptEngine *engine, const Logger &logger);
@@ -61,6 +61,7 @@ public:
void setSearchPaths(const QStringList &searchPaths);
void setOldProjectProbes(const QList<ProbeConstPtr> &oldProbes);
void setOldProductProbes(const QHash<QString, QList<ProbeConstPtr>> &oldProbes);
+ void setStoredProfiles(const QVariantMap &profiles);
TopLevelProjectPtr loadProject(const SetupProjectParameters &parameters);
private:
@@ -70,6 +71,7 @@ private:
QStringList m_searchPaths;
QList<ProbeConstPtr> m_oldProjectProbes;
QHash<QString, QList<ProbeConstPtr>> m_oldProductProbes;
+ QVariantMap m_storedProfiles;
};
} // namespace Internal
diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp
index 1f3e1c247..40417bad6 100644..100755
--- a/src/lib/corelib/language/moduleloader.cpp
+++ b/src/lib/corelib/language/moduleloader.cpp
@@ -51,7 +51,6 @@
#include "value.h"
#include <language/language.h>
-#include <language/scriptengine.h>
#include <logging/logger.h>
#include <logging/translator.h>
#include <tools/error.h>
@@ -69,6 +68,9 @@
#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
#include <QtCore/qdiriterator.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonobject.h>
+#include <QtScript/qscriptvalueiterator.h>
#include <algorithm>
#include <utility>
@@ -130,12 +132,12 @@ public:
void apply()
{
- QHash<QString, ProductContext *> productsMap;
+ QHash<QString, std::vector<ProductContext *>> productsMap;
QList<ProductContext *> allProducts;
for (ProjectContext * const projectContext : qAsConst(m_tlp.projects)) {
for (auto &product : projectContext->products) {
allProducts.push_back(&product);
- productsMap.insert(product.name, &product);
+ productsMap[product.name].push_back(&product);
}
}
Set<ProductContext *> allDependencies;
@@ -145,10 +147,45 @@ public:
if (!dep.productTypes.isEmpty())
continue;
QBS_CHECK(!dep.name.isEmpty());
- ProductContext * const depProduct = productsMap.value(dep.name);
- QBS_CHECK(depProduct);
- productDependencies.push_back(depProduct);
- allDependencies << depProduct;
+ const auto &deps = productsMap.value(dep.name);
+ if (dep.profile == QLatin1String("*")) {
+ QBS_CHECK(!deps.empty());
+ for (ProductContext *depProduct : deps) {
+ if (depProduct == productContext)
+ continue;
+ productDependencies.push_back(depProduct);
+ allDependencies << depProduct;
+ }
+ } else {
+ auto it = std::find_if(deps.begin(), deps.end(), [&dep] (ProductContext *p) {
+ return p->multiplexConfigurationId == dep.multiplexConfigurationId;
+ });
+ if (it == deps.end()) {
+ QBS_CHECK(!productContext->multiplexConfigurationId.isEmpty());
+ ErrorInfo e(Tr::tr("Dependency from product '%1' to product '%2' not "
+ "fulfilled.")
+ .arg(productContext->name, dep.name),
+ productContext->item->location());
+ const QString configJsonString = MultiplexInfo::configurationStringFromId(
+ productContext->multiplexConfigurationId);
+ const QVariantMap config = QJsonDocument::fromJson(
+ configJsonString.toUtf8()).object().toVariantMap();
+ QString userConfigString;
+ for (auto it = config.cbegin(); it != config.cend(); ++it) {
+ if (!userConfigString.isEmpty())
+ userConfigString += QLatin1Char('\n');
+ userConfigString.append(QLatin1String("\tqbs.") + it.key())
+ .append(QLatin1String(": "))
+ .append(it.value().toStringList().join(QLatin1Char(',')));
+ }
+ e.append(Tr::tr("No product '%1' found with a matching multiplex "
+ "configuration:\n%2").arg(dep.name, userConfigString));
+ throw e;
+
+ }
+ productDependencies.push_back(*it);
+ allDependencies << *it;
+ }
}
}
const Set<ProductContext *> rootProducts
@@ -267,6 +304,11 @@ void ModuleLoader::setOldProductProbes(const QHash<QString, QList<ProbeConstPtr>
m_oldProductProbes = oldProbes;
}
+void ModuleLoader::setStoredProfiles(const QVariantMap &profiles)
+{
+ m_storedProfiles = profiles;
+}
+
ModuleLoaderResult ModuleLoader::load(const SetupProjectParameters &parameters)
{
TimedActivityLogger moduleLoaderTimer(m_logger, Tr::tr("ModuleLoader"),
@@ -274,8 +316,8 @@ ModuleLoaderResult ModuleLoader::load(const SetupProjectParameters &parameters)
if (m_logger.traceEnabled())
m_logger.qbsTrace() << "[MODLDR] load" << parameters.projectFilePath();
m_parameters = parameters;
- m_productModuleCache.clear();
m_modulePrototypeItemCache.clear();
+ m_parameterDeclarations.clear();
m_disabledItems.clear();
m_reader->clearExtraSearchPathsStack();
m_reader->setEnableTiming(parameters.logElapsedTime());
@@ -299,14 +341,14 @@ ModuleLoaderResult ModuleLoader::load(const SetupProjectParameters &parameters)
e.append(QLatin1Char('\t') + Tr::tr("projects.<project-name>.<property-name>:value"));
e.append(QLatin1Char('\t') + Tr::tr("products.<product-name>.<property-name>:value"));
e.append(QLatin1Char('\t') + Tr::tr("modules.<module-name>.<property-name>:value"));
- // TODO: Uncomment in master.
-// e.append(QLatin1Char('\t') + Tr::tr("products.<product-name>.<module-name>."
-// "<property-name>:value"));
+ e.append(QLatin1Char('\t') + Tr::tr("products.<product-name>.<module-name>."
+ "<property-name>:value"));
handlePropertyError(e, m_parameters, m_logger);
}
ModuleLoaderResult result;
- m_pool = result.itemPool.data();
+ result.profileConfigs = m_storedProfiles;
+ m_pool = result.itemPool.get();
m_reader->setPool(m_pool);
const QStringList topLevelSearchPaths = parameters.finalBuildConfigurationTree()
@@ -429,7 +471,7 @@ private:
const DeprecationInfo &di = decl.deprecationInfo();
QString message;
bool warningOnly;
- if (di.removalVersion() <= Version::qbsVersion()) {
+ if (decl.isExpired()) {
message = Tr::tr("The property '%1' can no longer be used. "
"It was removed in Qbs %2.")
.arg(decl.name(), di.removalVersion().toString());
@@ -453,8 +495,15 @@ private:
}
m_parentItem = oldParentItem;
for (Item * const child : item->children()) {
- if (child->type () != ItemType::Export)
+ switch (child->type()) {
+ case ItemType::Export:
+ case ItemType::Depends:
+ case ItemType::Parameter:
+ case ItemType::Parameters:
+ break;
+ default:
handleItem(child);
+ }
}
// Properties that don't refer to an existing module with a matching Depends item
@@ -612,43 +661,136 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult,
break;
}
}
+ adjustDependenciesForMultiplexing(projectContext);
m_reader->popExtraSearchPaths();
}
+QString ModuleLoader::MultiplexInfo::configurationStringFromId(const QString &idString)
+{
+ return QString::fromUtf8(QByteArray::fromBase64(idString.toUtf8()));
+}
+
+QString ModuleLoader::MultiplexInfo::toIdString(size_t row) const
+{
+ const auto &mprow = table.at(row);
+ QVariantMap multiplexConfiguration;
+ for (size_t column = 0; column < mprow.size(); ++column) {
+ const QString &propertyName = properties.at(column);
+ const VariantValuePtr &mpvalue = mprow.at(column);
+ multiplexConfiguration.insert(propertyName, mpvalue->value());
+ }
+ return QString::fromUtf8(QJsonDocument::fromVariant(multiplexConfiguration)
+ .toJson(QJsonDocument::Compact)
+ .toBase64());
+}
+
+void qbs::Internal::ModuleLoader::ModuleLoader::dump(const ModuleLoader::MultiplexInfo &mpi)
+{
+ QStringList header;
+ for (const auto &str : mpi.properties)
+ header << str;
+ qDebug() << header;
+
+ for (const auto &row : mpi.table) {
+ QVariantList values;
+ for (const auto &elem : row) {
+ values << elem->value();
+ }
+ qDebug() << values;
+ }
+}
+
+ModuleLoader::MultiplexTable ModuleLoader::combine(const MultiplexTable &table,
+ const MultiplexRow &values)
+{
+ MultiplexTable result;
+ if (table.empty()) {
+ result.resize(values.size());
+ for (size_t i = 0; i < values.size(); ++i) {
+ MultiplexRow row;
+ row.resize(1);
+ row[0] = values.at(i);
+ result[i] = row;
+ }
+ } else {
+ for (const auto &row : table) {
+ for (const auto &value : values) {
+ MultiplexRow newRow = row;
+ newRow.push_back(value);
+ result.push_back(newRow);
+ }
+ }
+ }
+ return result;
+}
+
+ModuleLoader::MultiplexInfo ModuleLoader::extractMultiplexInfo(Item *productItem,
+ Item *qbsModuleItem)
+{
+ const QString mpmKey = QLatin1String("multiplexMap");
+ const QString mbqpKey = QLatin1String("multiplexByQbsProperties");
+ const QString mptypeKey = QLatin1String("multiplexedType");
+ const QString aggregateKey = QLatin1String("aggregate");
+
+ const QScriptValue multiplexMap = m_evaluator->value(qbsModuleItem, mpmKey);
+ QStringList multiplexByQbsProperties = m_evaluator->stringListValue(productItem, mbqpKey);
+
+ MultiplexInfo multiplexInfo;
+ multiplexInfo.aggregate = m_evaluator->boolValue(productItem, aggregateKey);
+
+ const QString multiplexedType = m_evaluator->stringValue(productItem, mptypeKey);
+ if (!multiplexedType.isEmpty())
+ multiplexInfo.multiplexedType = VariantValue::create(multiplexedType);
+
+ for (const QString &key : multiplexByQbsProperties) {
+ const QString mappedKey = multiplexMap.property(key).toString();
+ if (mappedKey.isEmpty())
+ throw ErrorInfo(Tr::tr("There is no entry for '%1' in 'qbs.multiplexMap'.").arg(key));
+
+ const QScriptValue arr = m_evaluator->value(qbsModuleItem, key);
+ if (arr.isUndefined())
+ continue;
+ if (!arr.isArray())
+ throw ErrorInfo(Tr::tr("Property '%1' must be an array.").arg(key));
+
+ const quint32 arrlen = arr.property(QLatin1String("length")).toUInt32();
+ if (arrlen == 0)
+ continue;
+
+ MultiplexRow mprow;
+ mprow.resize(arrlen);
+ for (quint32 i = 0; i < arrlen; ++i)
+ mprow[i] = VariantValue::create(arr.property(i).toVariant());
+ multiplexInfo.table = combine(multiplexInfo.table, mprow);
+ multiplexInfo.properties.push_back(mappedKey);
+ }
+ return multiplexInfo;
+}
+
QList<Item *> ModuleLoader::multiplexProductItem(ProductContext *dummyContext, Item *productItem)
{
// Temporarily attach the qbs module here, in case we need to access one of its properties
- // to evaluate the profiles property.
+ // to evaluate properties needed for multiplexing.
const QString qbsKey = QLatin1String("qbs");
ValuePtr qbsValue = productItem->property(qbsKey); // Retrieve now to restore later.
if (qbsValue)
qbsValue = qbsValue->clone();
- productItem->addModule(loadBaseModule(dummyContext, productItem));
+ const Item::Module qbsModule = loadBaseModule(dummyContext, productItem);
+ productItem->addModule(qbsModule);
- // Overriding the product item properties must be done here already, because otherwise
- // the "profiles" property would not be overridable.
- QString productName = m_evaluator->stringValue(productItem, QLatin1String("name"));
+ // Overriding the product item properties must be done here already, because multiplexing
+ // properties might depend on product properties.
+ const QString nameKey = QLatin1String("name");
+ QString productName = m_evaluator->stringValue(productItem, nameKey);
if (productName.isEmpty()) {
productName = FileInfo::completeBaseName(productItem->file()->filePath());
- productItem->setProperty(QLatin1String("name"), VariantValue::create(productName));
+ productItem->setProperty(nameKey, VariantValue::create(productName));
}
overrideItemProperties(productItem, QLatin1String("products.") + productName,
m_parameters.overriddenValuesTree());
- const QString profilesKey = QLatin1String("profiles");
- const ValueConstPtr profilesValue = productItem->property(profilesKey);
- QBS_CHECK(profilesValue); // Default value set in BuiltinDeclarations.
- const QStringList profileNames = m_evaluator->stringListValue(productItem, profilesKey);
- if (profileNames.isEmpty()) {
- throw ErrorInfo(Tr::tr("The 'profiles' property cannot be an empty list."),
- profilesValue->location());
- }
- for (const QString &profileName : profileNames) {
- if (profileNames.count(profileName) > 1) {
- throw ErrorInfo(Tr::tr("The profile '%1' appears in the 'profiles' list twice, "
- "which is not allowed.").arg(profileName), profilesValue->location());
- }
- }
+ const MultiplexInfo &multiplexInfo = extractMultiplexInfo(productItem, qbsModule.item);
+ //dump(multiplexInfo);
// "Unload" the qbs module again.
if (qbsValue)
@@ -657,25 +799,137 @@ QList<Item *> ModuleLoader::multiplexProductItem(ProductContext *dummyContext, I
productItem->removeProperty(qbsKey);
productItem->removeModules();
- QList<Item *> additionalProductItems;
+ if (multiplexInfo.table.size() > 1) {
+ const QString multiplexedKey = QStringLiteral("multiplexed");
+ const VariantValuePtr trueValue = VariantValue::create(true);
+ productItem->setProperty(multiplexedKey, trueValue);
+ }
+
const QString profileKey = QLatin1String("profile");
- productItem->setProperty(profileKey, VariantValue::create(profileNames.first()));
- Settings settings(m_parameters.settingsDirectory());
- for (int i = 0; i < profileNames.count(); ++i) {
- Profile profile(profileNames.at(i), &settings);
- if (profile.name() != Profile::fallbackName() && !profile.exists()) {
- throw ErrorInfo(Tr::tr("The profile '%1' does not exist.").arg(profile.name()),
- productItem->location()); // TODO: profilesValue->location() is invalid, why?
- }
- if (i == 0)
- continue; // We use the original item for the first profile.
- Item * const cloned = productItem->clone();
- cloned->setProperty(profileKey, VariantValue::create(profileNames.at(i)));
- additionalProductItems << cloned;
+ const QString multiplexConfigurationIdKey = QStringLiteral("multiplexConfigurationId");
+ VariantValuePtr productNameValue = VariantValue::create(productName);
+
+ Item *aggregator = multiplexInfo.aggregate ? productItem->clone() : nullptr;
+ QList<Item *> additionalProductItems;
+ std::vector<VariantValuePtr> multiplexConfigurationIdValues;
+ for (size_t row = 0; row < multiplexInfo.table.size(); ++row) {
+ Item *item = productItem;
+ const auto &mprow = multiplexInfo.table.at(row);
+ QBS_CHECK(mprow.size() == multiplexInfo.properties.size());
+ if (row > 0) {
+ item = productItem->clone();
+ additionalProductItems.append(item);
+ }
+ if (multiplexInfo.table.size() > 1 || aggregator) {
+ const QString multiplexConfigurationId = multiplexInfo.toIdString(row);
+ const VariantValuePtr multiplexConfigurationIdValue
+ = VariantValue::create(multiplexConfigurationId);
+ multiplexConfigurationIdValues.push_back(multiplexConfigurationIdValue);
+ item->setProperty(multiplexConfigurationIdKey, multiplexConfigurationIdValue);
+ }
+ if (multiplexInfo.multiplexedType)
+ item->setProperty(QStringLiteral("type"), multiplexInfo.multiplexedType);
+ for (size_t column = 0; column < mprow.size(); ++column) {
+ Item *qbsItem = moduleInstanceItem(item, qbsKey);
+ const QString &propertyName = multiplexInfo.properties.at(column);
+ const VariantValuePtr &mpvalue = mprow.at(column);
+ qbsItem->setProperty(propertyName, mpvalue);
+
+ // Backward compatibility
+ if (propertyName == profileKey)
+ item->setProperty(profileKey, mpvalue);
+ }
}
+
+ if (aggregator) {
+ additionalProductItems << aggregator;
+
+ // Add dependencies to all multiplexed instances.
+ for (const auto &v : multiplexConfigurationIdValues) {
+ Item *dependsItem = Item::create(aggregator->pool(), ItemType::Depends);
+ dependsItem->setProperty(nameKey, productNameValue);
+ dependsItem->setProperty(multiplexConfigurationIdKey, v);
+ dependsItem->setProperty(QStringLiteral("profiles"),
+ VariantValue::create(QStringLiteral("*")));
+ Item::addChild(aggregator, dependsItem);
+ }
+ }
+
return additionalProductItems;
}
+void ModuleLoader::adjustDependenciesForMultiplexing(const ProjectContext &projectContext)
+{
+ for (const ProductContext &product : projectContext.products)
+ m_productsByName.insert({ product.name, &product });
+
+ const QString multiplexConfigurationIdKey = QStringLiteral("multiplexConfigurationId");
+ for (const ProductContext &product : projectContext.products) {
+ std::vector<Item *> additionalDependsItems;
+ for (Item *dependsItem : product.item->children()) {
+ if (dependsItem->type() != ItemType::Depends)
+ continue;
+ const QString name = m_evaluator->stringValue(dependsItem, QStringLiteral("name"));
+ const bool productIsMultiplexed = !product.multiplexConfigurationId.isEmpty();
+ if (name == product.name) {
+ QBS_CHECK(!productIsMultiplexed); // This product must be an aggregator.
+ continue;
+ }
+ const auto productRange = m_productsByName.equal_range(name);
+ std::vector<const ProductContext *> dependencies;
+ bool hasNonMultiplexedDependency = false;
+ for (auto it = productRange.first; it != productRange.second; ++it) {
+ if (!it->second->multiplexConfigurationId.isEmpty()) {
+ dependencies.push_back(it->second);
+ if (productIsMultiplexed)
+ break;
+ } else {
+ hasNonMultiplexedDependency = true;
+ break;
+ }
+ }
+
+ // These are the allowed cases:
+ // (1) Normal dependency with no multiplexing whatsoever.
+ // (2) Both product and dependency are multiplexed.
+ // (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.
+
+ // (1) and (3a)
+ if (!productIsMultiplexed && hasNonMultiplexedDependency)
+ continue;
+
+ for (std::size_t i = 0; i < dependencies.size(); ++i) {
+ const QString depMultiplexId = dependencies.at(i)->multiplexConfigurationId;
+ if (i == 0) {
+ if (productIsMultiplexed) { // (2)
+ dependsItem->setProperty(multiplexConfigurationIdKey,
+ product.item->property(multiplexConfigurationIdKey));
+ break;
+ }
+ // (3b)
+ dependsItem->setProperty(multiplexConfigurationIdKey,
+ VariantValue::create(depMultiplexId));
+ } else {
+ // (3b)
+ Item * const newDependsItem = dependsItem->clone();
+ newDependsItem->setProperty(multiplexConfigurationIdKey,
+ VariantValue::create(depMultiplexId));
+ dependsItem->setProperty(QStringLiteral("profiles"),
+ VariantValue::create(QStringLiteral("*")));
+ additionalDependsItems.push_back(newDependsItem);
+ }
+ }
+ }
+ for (Item * const newDependsItem : additionalDependsItems)
+ Item::addChild(product.item, newDependsItem);
+ }
+}
+
void ModuleLoader::prepareProduct(ProjectContext *projectContext, Item *productItem)
{
checkCancelation();
@@ -688,6 +942,8 @@ void ModuleLoader::prepareProduct(ProjectContext *projectContext, Item *productI
bool profilePropertySet;
productContext.profileName = m_evaluator->stringValue(productItem, QLatin1String("profile"),
QString(), &profilePropertySet);
+ productContext.multiplexConfigurationId
+ = m_evaluator->stringValue(productItem, QLatin1String("multiplexConfigurationId"));
QBS_CHECK(profilePropertySet);
const auto it = projectContext->result->profileConfigs.constFind(productContext.profileName);
if (it == projectContext->result->profileConfigs.constEnd()) {
@@ -695,7 +951,7 @@ void ModuleLoader::prepareProduct(ProjectContext *projectContext, Item *productI
m_parameters.settingsDirectory(), productContext.profileName,
m_parameters.configurationName());
productContext.moduleProperties = SetupProjectParameters::finalBuildConfigurationTree(
- buildConfig, m_parameters.overriddenValues(), m_parameters.buildRoot());
+ buildConfig, m_parameters.overriddenValues());
projectContext->result->profileConfigs.insert(productContext.profileName,
productContext.moduleProperties);
} else {
@@ -727,8 +983,9 @@ void ModuleLoader::setupProductDependencies(ProductContext *productContext)
QStringList extraSearchPaths = readExtraSearchPaths(item);
Settings settings(m_parameters.settingsDirectory());
- const QStringList prefsSearchPaths
- = Preferences(&settings, productContext->profileName).searchPaths();
+ const QVariantMap profileContents = productContext->project->result->profileConfigs
+ .value(productContext->profileName).toMap();
+ const QStringList prefsSearchPaths = Preferences(&settings, profileContents).searchPaths();
for (const QString &p : prefsSearchPaths) {
if (!m_moduleSearchPaths.contains(p) && FileInfo(p).exists())
extraSearchPaths << p;
@@ -856,11 +1113,13 @@ void ModuleLoader::handleProduct(ModuleLoader::ProductContext *productContext)
}
if (!checkItemCondition(item)) {
- Item * const productModule = m_productModuleCache.value(productContext->name);
+ Item * const productModule = productContext->project->topLevelProject
+ ->productModules.value(productContext->name).exportItem;
if (productModule && productModule->isPresentModule())
createNonPresentModule(productContext->name, QLatin1String("disabled"), productModule);
}
+ checkDependencyParameterDeclarations(productContext);
copyGroupsFromModulesToProduct(*productContext);
ModuleDependencies reverseModuleDeps;
@@ -868,12 +1127,91 @@ void ModuleLoader::handleProduct(ModuleLoader::ProductContext *productContext)
if (child->type() == ItemType::Group) {
if (reverseModuleDeps.isEmpty())
reverseModuleDeps = setupReverseModuleDependencies(item);
- handleGroup(child, reverseModuleDeps);
+ handleGroup(productContext, child, reverseModuleDeps);
}
}
productContext->project->result->productInfos.insert(item, productContext->info);
}
+static Item *rootPrototype(Item *item)
+{
+ Item *modulePrototype = item;
+ while (modulePrototype->prototype())
+ modulePrototype = modulePrototype->prototype();
+ return modulePrototype;
+}
+
+class DependencyParameterDeclarationCheck
+{
+public:
+ DependencyParameterDeclarationCheck(const QString &productName, const Item *productItem,
+ const QHash<const Item *, Item::PropertyDeclarationMap> &decls)
+ : m_productName(productName), m_productItem(productItem), m_parameterDeclarations(decls)
+ {
+ }
+
+ void operator()(const QVariantMap &parameters) const
+ {
+ check(parameters, QualifiedId());
+ }
+
+private:
+ void check(const QVariantMap &parameters, const QualifiedId &moduleName) const
+ {
+ for (auto it = parameters.begin(); it != parameters.end(); ++it) {
+ if (it.value().type() == QVariant::Map) {
+ check(it.value().toMap(), QualifiedId(moduleName) << it.key());
+ } else {
+ const auto &deps = m_productItem->modules();
+ auto m = std::find_if(deps.begin(), deps.end(),
+ [&moduleName] (const Item::Module &module) {
+ return module.name == moduleName;
+ });
+
+ if (m == deps.end()) {
+ const QualifiedId fullName = QualifiedId(moduleName) << it.key();
+ throw ErrorInfo(Tr::tr("Cannot set parameter '%1', "
+ "because '%2' does not have a dependency on '%3'.")
+ .arg(fullName.toString(), m_productName, moduleName.toString()),
+ m_productItem->location());
+ }
+
+ auto decls = m_parameterDeclarations.value(rootPrototype(m->item));
+
+ if (!decls.contains(it.key())) {
+ const QualifiedId fullName = QualifiedId(moduleName) << it.key();
+ throw ErrorInfo(Tr::tr("Parameter '%1' is not declared.")
+ .arg(fullName.toString()), m_productItem->location());
+ }
+ }
+ }
+ }
+
+ bool moduleExists(const QualifiedId &name) const
+ {
+ const auto &deps = m_productItem->modules();
+ auto it = std::find_if(deps.begin(), deps.end(),
+ [&name] (const Item::Module &module) {
+ return module.name == name;
+ });
+ return deps.end() != it;
+ }
+
+ const QString &m_productName;
+ const Item *m_productItem;
+ const QHash<const Item *, Item::PropertyDeclarationMap> &m_parameterDeclarations;
+};
+
+void ModuleLoader::checkDependencyParameterDeclarations(const ProductContext *productContext) const
+{
+ DependencyParameterDeclarationCheck dpdc(productContext->name, productContext->item,
+ m_parameterDeclarations);
+ for (const Item::Module &dep : productContext->item->modules()) {
+ if (!dep.parameters.isEmpty())
+ dpdc(dep.parameters);
+ }
+}
+
void ModuleLoader::handleModuleSetupError(ModuleLoader::ProductContext *productContext,
const Item::Module &module, const ErrorInfo &error)
{
@@ -887,7 +1225,8 @@ void ModuleLoader::handleModuleSetupError(ModuleLoader::ProductContext *productC
void ModuleLoader::initProductProperties(const ProductContext &product)
{
- QString buildDir = ResolvedProduct::deriveBuildDirectoryName(product.name, product.profileName);
+ QString buildDir = ResolvedProduct::deriveBuildDirectoryName(product.name,
+ product.multiplexConfigurationId);
buildDir = FileInfo::resolvePath(product.project->topLevelProject->buildDirectory, buildDir);
product.item->setProperty(QLatin1String("buildDirectory"), VariantValue::create(buildDir));
const QString sourceDir = QFileInfo(product.item->file()->filePath()).absolutePath();
@@ -990,14 +1329,15 @@ QList<Item *> ModuleLoader::loadReferencedFile(const QString &relativePath,
return loadedItems;
}
-void ModuleLoader::handleGroup(Item *groupItem, const ModuleDependencies &reverseDepencencies)
+void ModuleLoader::handleGroup(ProductContext *productContext, Item *groupItem,
+ const ModuleDependencies &reverseDepencencies)
{
checkCancelation();
- propagateModulesFromParent(groupItem, reverseDepencencies);
+ propagateModulesFromParent(productContext, groupItem, reverseDepencencies);
checkItemCondition(groupItem);
for (Item * const child : groupItem->children()) {
if (child->type() == ItemType::Group)
- handleGroup(child, reverseDepencencies);
+ handleGroup(productContext, child, reverseDepencencies);
}
}
@@ -1025,10 +1365,6 @@ void ModuleLoader::handlePropertyOptions(Item *optionsItem)
throw ErrorInfo(Tr::tr("PropertyOptions item needs a name property"),
optionsItem->location());
}
- if (!optionsItem->parent()->hasProperty(name)) {
- throw ErrorInfo(Tr::tr("PropertyOptions item refers to non-existing property '%1'")
- .arg(name), optionsItem->location());
- }
const QString description = m_evaluator->stringValue(optionsItem, QLatin1String("description"));
const auto removalVersion = Version::fromString(m_evaluator->stringValue(optionsItem,
QLatin1String("removalVersion")));
@@ -1042,13 +1378,28 @@ void ModuleLoader::handlePropertyOptions(Item *optionsItem)
DeprecationInfo di(removalVersion, description);
decl.setDeprecationInfo(di);
}
+ const ValuePtr property = optionsItem->parent()->property(name);
+ if (!property && !decl.isExpired()) {
+ throw ErrorInfo(Tr::tr("PropertyOptions item refers to non-existing property '%1'")
+ .arg(name), optionsItem->location());
+ }
+ // TODO: Uncomment in 1.10
+// if (property && decl.isExpired()) {
+// ErrorInfo e(Tr::tr("Property '%1' was scheduled for removal in version %2, but "
+// "is still present.")
+// .arg(name).arg(removalVersion.toString()),
+// property->location());
+// e.append(Tr::tr("Removal version for '%1' specified here.").arg(name),
+// optionsItem->location());
+// m_logger.printWarning(e);
+// }
optionsItem->parent()->setPropertyDeclaration(name, decl);
}
static void mergeProperty(Item *dst, const QString &name, const ValuePtr &value)
{
if (value->type() == Value::ItemValueType) {
- Item *valueItem = value.staticCast<ItemValue>()->item();
+ Item *valueItem = std::static_pointer_cast<ItemValue>(value)->item();
Item *subItem = dst->itemProperty(name, valueItem)->item();
for (QMap<QString, ValuePtr>::const_iterator it = valueItem->properties().constBegin();
it != valueItem->properties().constEnd(); ++it)
@@ -1059,8 +1410,9 @@ static void mergeProperty(Item *dst, const QString &name, const ValuePtr &value)
const ValuePtr baseValue = dst->property(name);
if (baseValue) {
QBS_CHECK(baseValue->type() == Value::JSSourceValueType);
- const JSSourceValuePtr jsBaseValue = baseValue->clone().staticCast<JSSourceValue>();
- JSSourceValue *jsValue = static_cast<JSSourceValue *>(value.data());
+ const JSSourceValuePtr jsBaseValue = std::static_pointer_cast<JSSourceValue>(
+ baseValue->clone());
+ JSSourceValue *jsValue = static_cast<JSSourceValue *>(value.get());
jsValue->setBaseValue(jsBaseValue);
}
}
@@ -1153,6 +1505,34 @@ void ModuleLoader::printProfilingInfo()
.arg(elapsedTimeString(m_elapsedTimeProbes));
}
+static void mergeParameters(QVariantMap &dst, const QVariantMap &src)
+{
+ for (auto it = src.begin(); it != src.end(); ++it) {
+ if (it.value().type() == QVariant::Map) {
+ QVariant &vdst = dst[it.key()];
+ QVariantMap mdst = vdst.toMap();
+ mergeParameters(mdst, it.value().toMap());
+ vdst = mdst;
+ } else {
+ dst[it.key()] = it.value();
+ }
+ }
+}
+
+static void adjustParametersItemTypes(Item *item)
+{
+ if (item->type() == ItemType::ModuleInstance) {
+ item->setType(ItemType::ModuleParameters);
+ return;
+ }
+
+ for (auto value : item->properties()) {
+ if (value->type() != Value::ItemValueType)
+ continue;
+ adjustParametersItemTypes(std::static_pointer_cast<ItemValue>(value)->item());
+ }
+}
+
void ModuleLoader::mergeExportItems(const ProductContext &productContext)
{
std::vector<Item *> exportItems;
@@ -1174,17 +1554,30 @@ void ModuleLoader::mergeExportItems(const ProductContext &productContext)
productContext.item->setChildren(children);
Item *merged = Item::create(productContext.item->pool(), ItemType::Export);
+ const QString nameKey = QStringLiteral("name");
+ const ValuePtr nameValue = VariantValue::create(productContext.name);
+ merged->setProperty(nameKey, nameValue);
Set<FileContextConstPtr> filesWithExportItem;
+ ProductModuleInfo &pmi
+ = productContext.project->topLevelProject->productModules[productContext.name];
for (Item * const exportItem : qAsConst(exportItems)) {
checkCancelation();
if (Q_UNLIKELY(filesWithExportItem.contains(exportItem->file())))
throw ErrorInfo(Tr::tr("Multiple Export items in one product are prohibited."),
exportItem->location());
+ exportItem->setProperty(nameKey, nameValue);
if (!checkExportItemCondition(exportItem, productContext))
continue;
filesWithExportItem += exportItem->file();
- for (Item * const child : exportItem->children())
- Item::addChild(merged, child);
+ for (Item * const child : exportItem->children()) {
+ if (child->type() == ItemType::Parameters) {
+ adjustParametersItemTypes(child);
+ mergeParameters(pmi.defaultParameters,
+ m_evaluator->scriptValue(child).toVariant().toMap());
+ } else {
+ Item::addChild(merged, child);
+ }
+ }
const Item::PropertyDeclarationMap &decls = exportItem->propertyDeclarations();
for (auto it = decls.constBegin(); it != decls.constEnd(); ++it) {
const PropertyDeclaration &newDecl = it.value();
@@ -1207,35 +1600,9 @@ void ModuleLoader::mergeExportItems(const ProductContext &productContext)
? productContext.item->location() : exportItems.back()->location());
Item::addChild(productContext.item, merged);
merged->setupForBuiltinType(m_logger);
- ProductModuleInfo &pmi
- = productContext.project->topLevelProject->productModules[productContext.name];
pmi.exportItem = merged;
}
-bool ModuleLoader::isSomeModulePropertySet(const Item *item)
-{
- for (auto it = item->properties().cbegin(); it != item->properties().cend(); ++it) {
- switch (it.value()->type()) {
- case Value::JSSourceValueType:
- if (item->type() == ItemType::ModuleInstance) {
- if (m_logger.traceEnabled()) {
- m_logger.qbsTrace() << "[LDR] scope adaptation for group module items "
- "necessary because of property " << it.key();
- }
- return true;
- }
- break;
- case Value::ItemValueType:
- if (isSomeModulePropertySet(it.value().staticCast<ItemValue>()->item()))
- return true;
- break;
- default:
- break;
- }
- }
- return false;
-}
-
Item *ModuleLoader::loadItemFromFile(const QString &filePath)
{
Item * const item = m_reader->readFile(filePath);
@@ -1243,7 +1610,7 @@ Item *ModuleLoader::loadItemFromFile(const QString &filePath)
return item;
}
-void ModuleLoader::propagateModulesFromParent(Item *groupItem,
+void ModuleLoader::propagateModulesFromParent(ProductContext *productContext, Item *groupItem,
const ModuleDependencies &reverseDepencencies)
{
QBS_CHECK(groupItem->type() == ItemType::Group);
@@ -1288,8 +1655,11 @@ void ModuleLoader::propagateModulesFromParent(Item *groupItem,
module.item->setModules(adaptedModules);
}
- if (!isSomeModulePropertySet(groupItem))
+ const QualifiedIdSet &propsSetInGroup = gatherModulePropertiesSetInGroup(groupItem);
+ if (propsSetInGroup.isEmpty())
return;
+ productContext->info.modulePropertiesSetInGroups
+ .insert(std::make_pair(groupItem, propsSetInGroup));
// Step 3: Adapt defining items in values. This is potentially necessary if module properties
// get assigned on the group level.
@@ -1309,6 +1679,14 @@ void ModuleLoader::propagateModulesFromParent(Item *groupItem,
}
}
+static Item *createReplacementForDefiningItem(const Item *definingItem, ItemType type)
+{
+ Item *replacement = Item::create(definingItem->pool(), type);
+ replacement->setLocation(definingItem->location());
+ definingItem->copyProperty(QStringLiteral("name"), replacement);
+ return replacement;
+}
+
void ModuleLoader::adjustDefiningItemsInGroupModuleInstances(const Item::Module &module,
const Item::Modules &dependentModules)
{
@@ -1325,9 +1703,7 @@ void ModuleLoader::adjustDefiningItemsInGroupModuleInstances(const Item::Module
QHash<Item *, Item *> definingItemReplacements;
- Item *modulePrototype = module.item->prototype();
- while (modulePrototype->prototype())
- modulePrototype = modulePrototype->prototype();
+ Item *modulePrototype = rootPrototype(module.item->prototype());
QBS_CHECK(modulePrototype->type() == ItemType::Module
|| modulePrototype->type() == ItemType::Export);
@@ -1390,8 +1766,8 @@ void ModuleLoader::adjustDefiningItemsInGroupModuleInstances(const Item::Module
// (plus potential values from the prototype and other module instances,
// which are different Value objects in the "next chain").
if (!replacement) {
- replacement = Item::create(v->definingItem()->pool(),
- v->definingItem()->type());
+ replacement = createReplacementForDefiningItem(v->definingItem(),
+ v->definingItem()->type());
Item * const scope = Item::create(v->definingItem()->pool(), ItemType::Scope);
scope->setProperties(module.item->scope()->properties());
Item * const scopeScope
@@ -1419,8 +1795,8 @@ void ModuleLoader::adjustDefiningItemsInGroupModuleInstances(const Item::Module
QBS_CHECK(!v->next());
Item *& replacement = definingItemReplacements[v->definingItem()];
if (!replacement) {
- replacement = Item::create(v->definingItem()->pool(),
- ItemType::Module);
+ replacement = createReplacementForDefiningItem(v->definingItem(),
+ ItemType::Module);
replacement->setScope(module.item);
}
QBS_CHECK(!replacement->hasOwnProperty(caseA));
@@ -1433,7 +1809,7 @@ void ModuleLoader::adjustDefiningItemsInGroupModuleInstances(const Item::Module
<< ", new defining item is" << replacement
<< " with scope" << replacement->scope()
<< ", value source code is "
- << v.staticCast<JSSourceValue>()->sourceCode().toString();
+ << std::static_pointer_cast<JSSourceValue>(v)->sourceCode().toString();
}
replacement->setPropertyDeclaration(propName, decl);
replacement->setProperty(propName, v);
@@ -1455,8 +1831,8 @@ void ModuleLoader::adjustDefiningItemsInGroupModuleInstances(const Item::Module
found = true;
Item *& replacement = definingItemReplacements[v->definingItem()];
if (!replacement) {
- replacement = Item::create(v->definingItem()->pool(),
- v->definingItem()->type());
+ replacement = createReplacementForDefiningItem(v->definingItem(),
+ v->definingItem()->type());
replacement->setProperties(v->definingItem()->properties());
for (const auto &decl : v->definingItem()->propertyDeclarations())
replacement->setPropertyDeclaration(decl.name(), decl);
@@ -1486,31 +1862,59 @@ void ModuleLoader::resolveDependencies(DependsContext *dependsContext, Item *ite
const Item::Module baseModule = loadBaseModule(dependsContext->product, item);
// Resolve all Depends items.
ItemModuleList loadedModules;
+ QList<Item *> dependsItemPerLoadedModule;
ProductDependencyResults productDependencies;
- for (Item * const child : item->children())
- if (child->type() == ItemType::Depends)
- resolveDependsItem(dependsContext, item, child, &loadedModules, &productDependencies);
+ const auto &itemChildren = item->children();
+ for (Item * const child : itemChildren) {
+ if (child->type() != ItemType::Depends)
+ continue;
+
+ int lastModulesCount = loadedModules.count();
+ resolveDependsItem(dependsContext, item, child, &loadedModules, &productDependencies);
+ for (int i = lastModulesCount; i < loadedModules.count(); ++i)
+ dependsItemPerLoadedModule.append(child);
+ }
+ QBS_CHECK(loadedModules.count() == dependsItemPerLoadedModule.count());
+
+ Item *lastDependsItem = nullptr;
+ for (Item * const dependsItem : dependsItemPerLoadedModule) {
+ if (dependsItem == lastDependsItem)
+ continue;
+ adjustParametersItemTypes(dependsItem);
+ forwardParameterDeclarations(dependsItem, loadedModules);
+ lastDependsItem = dependsItem;
+ }
item->addModule(baseModule);
- for (const Item::Module &module : qAsConst(loadedModules))
+ for (int i = 0; i < loadedModules.size(); ++i) {
+ Item::Module &module = loadedModules[i];
+ mergeParameters(module.parameters, extractParameters(dependsItemPerLoadedModule.at(i)));
item->addModule(module);
+ const QString moduleName = module.name.toString();
+ std::for_each(productDependencies.begin(), productDependencies.end(),
+ [&module, &moduleName] (ModuleLoaderResult::ProductInfo::Dependency &dep) {
+ if (dep.name == moduleName)
+ dep.parameters = module.parameters;
+ });
+ }
+
dependsContext->productDependencies->append(productDependencies);
}
class RequiredChainManager
{
public:
- RequiredChainManager(QStack<bool> &requiredChain, bool required)
+ RequiredChainManager(std::vector<bool> &requiredChain, bool required)
: m_requiredChain(requiredChain)
{
- m_requiredChain.push(required);
+ m_requiredChain.push_back(required);
}
- ~RequiredChainManager() { m_requiredChain.pop(); }
+ ~RequiredChainManager() { m_requiredChain.pop_back(); }
private:
- QStack<bool> &m_requiredChain;
+ std::vector<bool> &m_requiredChain;
};
void ModuleLoader::resolveDependsItem(DependsContext *dependsContext, Item *parentItem,
@@ -1580,11 +1984,8 @@ void ModuleLoader::resolveDependsItem(DependsContext *dependsContext, Item *pare
Item::Module result;
for (const QualifiedId &moduleName : qAsConst(moduleNames)) {
- bool isRequired = m_evaluator->boolValue(dependsItem, QLatin1String("required"));
- for (int i = m_requiredChain.count() - 1; i >= 0 && isRequired; --i) {
- if (!m_requiredChain.at(i))
- isRequired = false;
- }
+ const bool isRequired = m_evaluator->boolValue(dependsItem, QLatin1String("required"))
+ && !contains(m_requiredChain, false);
const Version minVersion = Version::fromString(
m_evaluator->stringValue(dependsItem, QLatin1String("versionAtLeast")));
const Version maxVersion = Version::fromString(
@@ -1604,12 +2005,19 @@ void ModuleLoader::resolveDependsItem(DependsContext *dependsContext, Item *pare
RequiredChainManager requiredChainManager(m_requiredChain, isRequired);
+ QVariantMap defaultParameters;
Item *moduleItem = loadModule(dependsContext->product, parentItem, dependsItem->location(),
- dependsItem->id(), moduleName, isRequired, &result.isProduct);
+ dependsItem->id(), moduleName, isRequired, &result.isProduct,
+ &defaultParameters);
if (!moduleItem) {
- throw ErrorInfo(Tr::tr("Dependency '%1' not found for product '%2'.")
- .arg(moduleName.toString(), dependsContext->product->name),
- dependsItem->location());
+ ErrorInfo e(Tr::tr("Dependency '%1' not found for product '%2'.")
+ .arg(moduleName.toString(), dependsContext->product->name),
+ dependsItem->location());
+ if (moduleName.count() == 2 && moduleName.first() == QLatin1String("Qt")) {
+ e.append(Tr::tr("Please create a Qt profile using the qbs-setup-qt tool "
+ "if you haven't already done so."));
+ }
+ throw e;
}
if (result.isProduct && parentItem->type() == ItemType::Module) {
throw ErrorInfo(Tr::tr("Invalid dependency on product '%1': Modules cannot depend on "
@@ -1622,25 +2030,24 @@ void ModuleLoader::resolveDependsItem(DependsContext *dependsContext, Item *pare
result.name = moduleName;
result.item = moduleItem;
result.required = isRequired;
+ result.parameters = defaultParameters;
result.versionRange = versionRange;
moduleResults->append(result);
if (result.isProduct) {
if (m_logger.traceEnabled())
m_logger.qbsTrace() << "product dependency loaded: " << moduleName.toString();
const QString profilesKey = QLatin1String("profiles");
- const QStringList profiles = m_evaluator->stringListValue(dependsItem, profilesKey);
- if (profiles.isEmpty()) {
- ModuleLoaderResult::ProductInfo::Dependency dependency;
- dependency.name = moduleName.toString();
- dependency.profile = QLatin1String("*");
- dependency.isRequired = isRequired;
- productResults->append(dependency);
- continue;
- }
- for (const QString &profile : profiles) {
+ QStringList profiles = m_evaluator->stringListValue(dependsItem, profilesKey);
+ if (profiles.isEmpty())
+ profiles.append(QLatin1String("*"));
+ const QString multiplexConfigurationId
+ = m_evaluator->stringValue(dependsItem,
+ QStringLiteral("multiplexConfigurationId"));
+ for (const QString &profile : qAsConst(profiles)) {
ModuleLoaderResult::ProductInfo::Dependency dependency;
dependency.name = moduleName.toString();
dependency.profile = profile;
+ dependency.multiplexConfigurationId = multiplexConfigurationId;
dependency.isRequired = isRequired;
productResults->append(dependency);
}
@@ -1648,6 +2055,102 @@ void ModuleLoader::resolveDependsItem(DependsContext *dependsContext, Item *pare
}
}
+void ModuleLoader::forwardParameterDeclarations(const Item *dependsItem,
+ const ItemModuleList &modules)
+{
+ for (auto it = dependsItem->properties().begin(); it != dependsItem->properties().end(); ++it) {
+ if (it.value()->type() != Value::ItemValueType)
+ continue;
+ forwardParameterDeclarations(it.key(),
+ std::static_pointer_cast<ItemValue>(it.value())->item(),
+ modules);
+ }
+}
+
+void ModuleLoader::forwardParameterDeclarations(const QualifiedId &moduleName, Item *item,
+ const ItemModuleList &modules)
+{
+ auto it = std::find_if(modules.begin(), modules.end(), [&moduleName] (const Item::Module &m) {
+ return m.name == moduleName;
+ });
+ if (it != modules.end()) {
+ item->setPropertyDeclarations(m_parameterDeclarations.value(rootPrototype(it->item)));
+ } else {
+ for (auto it = item->properties().begin(); it != item->properties().end(); ++it) {
+ if (it.value()->type() != Value::ItemValueType)
+ continue;
+ forwardParameterDeclarations(QualifiedId(moduleName) << it.key(),
+ std::static_pointer_cast<ItemValue>(it.value())->item(),
+ modules);
+ }
+ }
+}
+
+void ModuleLoader::resolveParameterDeclarations(const Item *module)
+{
+ Item::PropertyDeclarationMap decls;
+ const auto &moduleChildren = module->children();
+ for (Item *param : moduleChildren) {
+ if (param->type() != ItemType::Parameter)
+ continue;
+ const auto paramDecls = param->propertyDeclarations();
+ for (auto it = paramDecls.begin(); it != paramDecls.end(); ++it)
+ decls.insert(it.key(), it.value());
+ }
+ m_parameterDeclarations.insert(module, decls);
+}
+
+static bool isItemValue(const ValuePtr &v)
+{
+ return v->type() == Value::ItemValueType;
+}
+
+static Item::PropertyMap filterItemProperties(const Item::PropertyMap &properties)
+{
+ Item::PropertyMap result;
+ auto itEnd = properties.end();
+ for (auto it = properties.begin(); it != itEnd; ++it) {
+ if (isItemValue(it.value()))
+ result.insert(it.key(), it.value());
+ }
+ return result;
+}
+
+static QVariantMap safeToVariant(const QScriptValue &v)
+{
+ QVariantMap result;
+ QScriptValueIterator it(v);
+ while (it.hasNext()) {
+ it.next();
+ QScriptValue u = it.value();
+ if (u.isError())
+ throw ErrorInfo(u.toString());
+ result[it.name()] = (u.isObject() && !u.isArray() && !u.isRegExp())
+ ? safeToVariant(u) : it.value().toVariant();
+ }
+ return result;
+}
+
+QVariantMap ModuleLoader::extractParameters(Item *dependsItem) const
+{
+ QVariantMap result;
+ const Item::PropertyMap &itemProperties = filterItemProperties(dependsItem->properties());
+ if (itemProperties.isEmpty())
+ return result;
+
+ auto origProperties = dependsItem->properties();
+ dependsItem->setProperties(itemProperties);
+ QScriptValue sv = m_evaluator->scriptValue(dependsItem);
+ try {
+ result = safeToVariant(sv);
+ } catch (ErrorInfo ei) {
+ ei.prepend(Tr::tr("Error in dependency parameter."), dependsItem->location());
+ throw ei;
+ }
+ dependsItem->setProperties(origProperties);
+ return result;
+}
+
Q_NORETURN static void throwModuleNamePrefixError(const QualifiedId &shortName,
const QualifiedId &longName, const CodeLocation &codeLocation)
{
@@ -1664,7 +2167,7 @@ Item *ModuleLoader::moduleInstanceItem(Item *containerItem, const QualifiedId &m
const QString &moduleNameSegment = moduleName.at(i);
const ValuePtr v = instance->ownProperty(moduleName.at(i));
if (v && v->type() == Value::ItemValueType) {
- instance = v.staticCast<ItemValue>()->item();
+ instance = std::static_pointer_cast<ItemValue>(v)->item();
} else {
const ItemType itemType = i < moduleName.count() - 1 ? ItemType::ModulePrefix
: ItemType::ModuleInstance;
@@ -1684,35 +2187,28 @@ Item *ModuleLoader::moduleInstanceItem(Item *containerItem, const QualifiedId &m
return instance;
}
-Item *ModuleLoader::loadProductModule(ModuleLoader::ProductContext *productContext,
- const QString &moduleName)
+ModuleLoader::ProductModuleInfo ModuleLoader::loadProductModule(
+ ModuleLoader::ProductContext *productContext, const QString &moduleName)
{
if (m_logger.traceEnabled())
m_logger.qbsTrace() << "[MODLDR] loadProductModule name: " << moduleName;
- Item *module = m_productModuleCache.value(moduleName);
- if (module) {
- if (m_logger.traceEnabled())
- m_logger.qbsTrace() << "[MODLDR] loadProductModule cache hit.";
- return module;
- }
ProductModuleInfo &pmi = productContext->project->topLevelProject->productModules[moduleName];
- module = pmi.exportItem;
- if (module) {
+ if (pmi.exportItem && !pmi.dependenciesResolved) {
if (m_logger.traceEnabled())
- m_logger.qbsTrace() << "[MODLDR] loadProductModule cache miss.";
+ m_logger.qbsTrace() << "[MODLDR] loadProductModule resolving dependencies.";
DependsContext dependsContext;
dependsContext.product = productContext;
dependsContext.productDependencies = &pmi.productDependencies;
- resolveDependencies(&dependsContext, module);
- m_productModuleCache.insert(moduleName, module);
+ resolveDependencies(&dependsContext, pmi.exportItem);
+ pmi.dependenciesResolved = true;
}
- return module;
+ return pmi;
}
class ModuleLoader::DependsChainManager
{
public:
- DependsChainManager(QStack<DependsChainEntry> &dependsChain, const QualifiedId &module,
+ DependsChainManager(std::vector<DependsChainEntry> &dependsChain, const QualifiedId &module,
const CodeLocation &dependsLocation)
: m_dependsChain(dependsChain)
{
@@ -1728,19 +2224,19 @@ public:
error.append(module.toString(), dependsLocation);
throw error;
}
- m_dependsChain.push(std::make_pair(module, dependsLocation));
+ m_dependsChain.push_back(std::make_pair(module, dependsLocation));
}
- ~DependsChainManager() { m_dependsChain.pop(); }
+ ~DependsChainManager() { m_dependsChain.pop_back(); }
private:
- QStack<DependsChainEntry> &m_dependsChain;
+ std::vector<DependsChainEntry> &m_dependsChain;
};
Item *ModuleLoader::loadModule(ProductContext *productContext, Item *item,
const CodeLocation &dependsItemLocation,
const QString &moduleId, const QualifiedId &moduleName, bool isRequired,
- bool *isProductDependency)
+ bool *isProductDependency, QVariantMap *defaultParameters)
{
if (m_logger.traceEnabled())
m_logger.qbsTrace() << "[MODLDR] loadModule name: " << moduleName << ", id: " << moduleId;
@@ -1762,8 +2258,12 @@ Item *ModuleLoader::loadModule(ProductContext *productContext, Item *item,
QBS_CHECK(moduleInstance->type() == ItemType::ModuleInstance);
*isProductDependency = true;
- Item *modulePrototype = loadProductModule(productContext, moduleName.toString());
- if (!modulePrototype) {
+ const ProductModuleInfo &pmi = loadProductModule(productContext, moduleName.toString());
+ Item *modulePrototype = pmi.exportItem;
+ if (modulePrototype) {
+ if (defaultParameters)
+ *defaultParameters = pmi.defaultParameters;
+ } else {
*isProductDependency = false;
QStringList moduleSearchPaths;
for (const QString &searchPath : m_reader->searchPaths())
@@ -1881,7 +2381,9 @@ Item *ModuleLoader::loadModuleFile(ProductContext *productContext, const QString
if (m_logger.traceEnabled())
m_logger.qbsTrace() << "[MODLDR] trying to load " << fullModuleName << " from " << filePath;
- const ModuleItemCache::key_type cacheKey(filePath, productContext->profileName);
+ const QString keyUniquifier = productContext->multiplexConfigurationId.isEmpty() ?
+ productContext->profileName : productContext->uniqueName();
+ const ModuleItemCache::key_type cacheKey(filePath, keyUniquifier);
const ItemCacheValue cacheValue = m_modulePrototypeItemCache.value(cacheKey);
if (cacheValue.module) {
m_logger.qbsTrace() << "[LDR] loadModuleFile cache hit for " << filePath;
@@ -1899,6 +2401,9 @@ Item *ModuleLoader::loadModuleFile(ProductContext *productContext, const QString
return 0;
}
+ // Set the name before evaluating any properties. EvaluatorScriptClass reads the module name.
+ module->setProperty(QLatin1String("name"), VariantValue::create(fullModuleName));
+
if (!isBaseModule) {
DependsContext dependsContext;
dependsContext.product = productContext;
@@ -1933,10 +2438,12 @@ Item *ModuleLoader::loadModuleFile(ProductContext *productContext, const QString
return 0;
}
+ if (!isBaseModule)
+ resolveParameterDeclarations(module);
+
for (const ErrorInfo &error : qAsConst(unknownProfilePropertyErrors))
handlePropertyError(error, m_parameters, m_logger);
- module->setProperty(QLatin1String("name"), VariantValue::create(fullModuleName));
m_modulePrototypeItemCache.insert(cacheKey, ItemCacheValue(module, true));
return module;
}
@@ -1947,7 +2454,16 @@ Item::Module ModuleLoader::loadBaseModule(ProductContext *productContext, Item *
Item::Module baseModuleDesc;
baseModuleDesc.name = baseModuleName;
baseModuleDesc.item = loadModule(productContext, item, CodeLocation(), QString(),
- baseModuleName, true, &baseModuleDesc.isProduct);
+ baseModuleName, true, &baseModuleDesc.isProduct, nullptr);
+ if (productContext->item) {
+ const Item * const qbsInstanceItem
+ = moduleInstanceItem(productContext->item, baseModuleName);
+ const Item::PropertyMap &props = qbsInstanceItem->properties();
+ for (auto it = props.cbegin(); it != props.cend(); ++it) {
+ if (it.value()->type() == Value::VariantValueType)
+ baseModuleDesc.item->setProperty(it.key(), it.value());
+ }
+ }
QBS_CHECK(!baseModuleDesc.isProduct);
if (Q_UNLIKELY(!baseModuleDesc.item))
throw ErrorInfo(Tr::tr("Cannot load base qbs module."));
@@ -2209,22 +2725,12 @@ void ModuleLoader::instantiateModule(ProductContext *productContext, Item *expor
moduleInstance->property(pd.name())->location());
}
- // override module properties given on the command line
- const QVariantMap userModuleProperties = m_parameters.overriddenValuesTree()
- .value(QLatin1String("modules.") + fullName).toMap();
- for (QVariantMap::const_iterator vmit = userModuleProperties.begin();
- vmit != userModuleProperties.end(); ++vmit) {
- if (Q_UNLIKELY(!moduleInstance->hasProperty(vmit.key()))) {
- const ErrorInfo error(Tr::tr("Unknown property: %1.%2")
- .arg(moduleName.toString(), vmit.key()));
- handlePropertyError(error, m_parameters, m_logger);
- continue;
- }
- const PropertyDeclaration decl = moduleInstance->propertyDeclaration(vmit.key());
- moduleInstance->setProperty(vmit.key(),
- VariantValue::create(convertToPropertyType(vmit.value(), decl.type(), moduleName,
- vmit.key())));
- }
+ const QString generalverrideKey = QLatin1String("modules.") + fullName;
+ overrideItemProperties(moduleInstance, generalverrideKey, m_parameters.overriddenValuesTree());
+ const QString perProductOverrideKey = QLatin1String("products.") + productContext->name
+ + QLatin1Char('.') + fullName;
+ overrideItemProperties(moduleInstance, perProductOverrideKey,
+ m_parameters.overriddenValuesTree());
}
void ModuleLoader::createChildInstances(Item *instance, Item *prototype,
@@ -2278,8 +2784,10 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It
ScriptEngine * const engine = m_evaluator->engine();
QScriptValue scope = engine->newObject();
engine->currentContext()->pushScope(m_evaluator->scriptValue(parent));
- engine->currentContext()->pushScope(m_evaluator->fileScope(configureScript->file()));
- engine->currentContext()->pushScope(m_evaluator->importScope(configureScript->file()));
+ const Evaluator::FileContextScopes fileCtxScopes
+ = m_evaluator->fileContextScopes(configureScript->file());
+ engine->currentContext()->pushScope(fileCtxScopes.fileScope);
+ engine->currentContext()->pushScope(fileCtxScopes.importScope);
engine->currentContext()->pushScope(scope);
for (const ProbeProperty &b : qAsConst(probeBindings))
scope.setProperty(b.first, b.second);
@@ -2289,8 +2797,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It
if (parent->type() == ItemType::Project) {
resolvedProbe = findOldProjectProbe(probeId, condition, initialProperties, sourceCode);
} else {
- const QString &uniqueProductName
- = ResolvedProduct::uniqueName(productContext->name, productContext->profileName);
+ const QString &uniqueProductName = productContext->uniqueName();
resolvedProbe
= findOldProductProbe(uniqueProductName, condition, initialProperties, sourceCode);
}
@@ -2380,7 +2887,8 @@ void ModuleLoader::copyProperties(const Item *sourceProject, Item *targetProject
|| it.key() == QLatin1String("sourceDirectory")
|| it.key() == QLatin1String("minimumQbsVersion")) {
const JSSourceValueConstPtr &v
- = targetProject->property(it.key()).dynamicCast<const JSSourceValue>();
+ = std::dynamic_pointer_cast<const JSSourceValue>(
+ targetProject->property(it.key()));
QBS_ASSERT(v, continue);
if (v->sourceCode() == QLatin1String("undefined"))
sourceProject->copyProperty(it.key(), targetProject);
@@ -2426,10 +2934,26 @@ void ModuleLoader::setScopeForDescendants(Item *item, Item *scope)
{
for (Item * const child : item->children()) {
child->setScope(scope);
+ if (child->type() == ItemType::Depends)
+ forwardScopeToItemValues(child, scope);
setScopeForDescendants(child, scope);
}
}
+void ModuleLoader::forwardScopeToItemValues(Item *item, Item *scope)
+{
+ const auto &itemProperties = item->properties();
+ for (const ValuePtr &v : itemProperties) {
+ if (v->type() != Value::ItemValueType)
+ continue;
+ Item *k = std::static_pointer_cast<ItemValue>(v)->item();
+ if (k->type() == ItemType::ModulePrefix)
+ forwardScopeToItemValues(k, scope);
+ else
+ k->setScope(scope);
+ }
+}
+
void ModuleLoader::overrideItemProperties(Item *item, const QString &buildConfigKey,
const QVariantMap &buildConfig)
{
@@ -2439,7 +2963,7 @@ void ModuleLoader::overrideItemProperties(Item *item, const QString &buildConfig
const QVariantMap overridden = buildConfigValue.toMap();
for (QVariantMap::const_iterator it = overridden.constBegin(); it != overridden.constEnd();
++it) {
- const PropertyDeclaration decl = item->propertyDeclarations().value(it.key());
+ const PropertyDeclaration decl = item->propertyDeclaration(it.key());
if (!decl.isValid()) {
ErrorInfo error(Tr::tr("Unknown property: %1.%2").arg(buildConfigKey, it.key()));
handlePropertyError(error, m_parameters, m_logger);
@@ -2475,18 +2999,65 @@ static std::vector<Item::Module> allModules(Item *item)
return lst;
}
+void ModuleLoader::addProductModuleDependencies(ProductContext *productContext,
+ const Item::Module &module)
+{
+ auto deps = productContext->project->topLevelProject->productModules.value(
+ module.name.toString()).productDependencies;
+ const QString multiplexConfigurationIdKey = QStringLiteral("multiplexConfigurationId");
+ QList<ModuleLoaderResult::ProductInfo::Dependency> additionalDependencies;
+ const bool productIsMultiplexed = !productContext->multiplexConfigurationId.isEmpty();
+ for (auto &dep : deps) {
+ const auto productRange = m_productsByName.equal_range(dep.name);
+ std::vector<const ProductContext *> dependencies;
+ bool hasNonMultiplexedDependency = false;
+ for (auto it = productRange.first; it != productRange.second; ++it) {
+ if (!it->second->multiplexConfigurationId.isEmpty()) {
+ dependencies.push_back(it->second);
+ if (productIsMultiplexed)
+ break;
+ } else {
+ hasNonMultiplexedDependency = true;
+ break;
+ }
+ }
+
+ if (!productIsMultiplexed && hasNonMultiplexedDependency)
+ continue;
+
+ for (std::size_t i = 0; i < dependencies.size(); ++i) {
+ if (i == 0) {
+ if (productIsMultiplexed) {
+ dep.multiplexConfigurationId = std::static_pointer_cast<VariantValue>(
+ productContext->item->property(
+ multiplexConfigurationIdKey))->value().toString();
+ break;
+ } else {
+ dep.multiplexConfigurationId = dependencies.at(i)->multiplexConfigurationId;
+ }
+ } else {
+ ModuleLoaderResult::ProductInfo::Dependency newDependency = dep;
+ newDependency.multiplexConfigurationId
+ = dependencies.at(i)->multiplexConfigurationId;
+ newDependency.profile = QLatin1String("*");
+ additionalDependencies << newDependency;
+ }
+ }
+ }
+ productContext->info.usedProducts.append(deps);
+ productContext->info.usedProducts.append(additionalDependencies);
+}
+
void ModuleLoader::addTransitiveDependencies(ProductContext *ctx)
{
if (m_logger.traceEnabled())
m_logger.qbsTrace() << "[MODLDR] addTransitiveDependencies";
+
std::vector<Item::Module> transitiveDeps = allModules(ctx->item);
std::sort(transitiveDeps.begin(), transitiveDeps.end());
for (const Item::Module &m : ctx->item->modules()) {
- if (m.isProduct) {
- ctx->info.usedProducts.append(
- ctx->project->topLevelProject->productModules.value(
- m.name.toString()).productDependencies);
- }
+ if (m.isProduct)
+ addProductModuleDependencies(ctx, m);
auto it = std::lower_bound(transitiveDeps.begin(), transitiveDeps.end(), m);
QBS_CHECK(it != transitiveDeps.end() && it->name == m.name);
@@ -2495,13 +3066,11 @@ void ModuleLoader::addTransitiveDependencies(ProductContext *ctx)
for (const Item::Module &module : qAsConst(transitiveDeps)) {
if (module.isProduct) {
ctx->item->addModule(module);
- ctx->info.usedProducts.append(
- ctx->project->topLevelProject->productModules.value(
- module.name.toString()).productDependencies);
+ addProductModuleDependencies(ctx, module);
} else {
Item::Module dep;
dep.item = loadModule(ctx, ctx->item, ctx->item->location(), QString(), module.name,
- module.required, &dep.isProduct);
+ module.required, &dep.isProduct, &dep.parameters);
if (!dep.item) {
throw ErrorInfo(Tr::tr("Module '%1' not found when setting up transitive "
"dependencies for product '%2'.").arg(module.name.toString(),
@@ -2525,6 +3094,7 @@ Item *ModuleLoader::createNonPresentModule(const QString &name, const QString &r
if (!module) {
module = Item::create(m_pool, ItemType::ModuleInstance);
module->setFile(FileContext::create());
+ module->setProperty(QStringLiteral("name"), VariantValue::create(name));
}
module->setProperty(QLatin1String("present"), VariantValue::create(false));
return module;
@@ -2540,6 +3110,40 @@ void ModuleLoader::handleProductError(const ErrorInfo &error,
m_disabledItems << productContext->item;
}
+static void gatherAssignedProperties(ItemValue *iv, const QualifiedId &prefix,
+ QualifiedIdSet &properties)
+{
+ const Item::PropertyMap &props = iv->item()->properties();
+ for (auto it = props.cbegin(); it != props.cend(); ++it) {
+ switch (it.value()->type()) {
+ case Value::JSSourceValueType:
+ properties << (QualifiedId(prefix) << it.key());
+ break;
+ case Value::ItemValueType:
+ if (iv->item()->type() == ItemType::ModulePrefix) {
+ gatherAssignedProperties(std::static_pointer_cast<ItemValue>(it.value()).get(),
+ QualifiedId(prefix) << it.key(), properties);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+QualifiedIdSet ModuleLoader::gatherModulePropertiesSetInGroup(const Item *group)
+{
+ QualifiedIdSet propsSetInGroup;
+ const Item::PropertyMap &props = group->properties();
+ for (auto it = props.cbegin(); it != props.cend(); ++it) {
+ if (it.value()->type() == Value::ItemValueType) {
+ gatherAssignedProperties(std::static_pointer_cast<ItemValue>(it.value()).get(),
+ QualifiedId(it.key()), propsSetInGroup);
+ }
+ }
+ return propsSetInGroup;
+}
+
void ModuleLoader::copyGroupsFromModuleToProduct(const ProductContext &productContext,
const Item *modulePrototype)
{
@@ -2568,7 +3172,12 @@ void ModuleLoader::copyGroupsFromModulesToProduct(const ProductContext &productC
QString ModuleLoaderResult::ProductInfo::Dependency::uniqueName() const
{
- return ResolvedProduct::uniqueName(name, profile);
+ return ResolvedProduct::uniqueName(name, multiplexConfigurationId);
+}
+
+QString ModuleLoader::ProductContext::uniqueName() const
+{
+ return ResolvedProduct::uniqueName(name, multiplexConfigurationId);
}
} // namespace Internal
diff --git a/src/lib/corelib/language/moduleloader.h b/src/lib/corelib/language/moduleloader.h
index 1359b454e..0e9445f1c 100644
--- a/src/lib/corelib/language/moduleloader.h
+++ b/src/lib/corelib/language/moduleloader.h
@@ -50,14 +50,13 @@
#include <tools/version.h>
#include <QtCore/qmap.h>
-#include <QtCore/qstack.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qvariant.h>
-QT_BEGIN_NAMESPACE
-class QScriptContext;
-class QScriptEngine;
-QT_END_NAMESPACE
+#include <map>
+#include <stack>
+#include <unordered_map>
+#include <vector>
namespace qbs {
@@ -70,7 +69,8 @@ class Item;
class ItemReader;
class ProgressObserver;
class QualifiedId;
-class ScriptEngine;
+
+using ModulePropertiesPerGroup = std::unordered_map<const Item *, QualifiedIdSet>;
struct ModuleLoaderResult
{
@@ -85,6 +85,8 @@ struct ModuleLoaderResult
FileTags productTypes;
QString name;
QString profile; // "*" <=> Match all profiles.
+ QString multiplexConfigurationId;
+ QVariantMap parameters;
bool limitToSubProject = false;
bool isRequired = true;
@@ -93,10 +95,11 @@ struct ModuleLoaderResult
QList<ProbeConstPtr> probes;
QList<Dependency> usedProducts;
+ ModulePropertiesPerGroup modulePropertiesSetInGroups;
ErrorInfo delayedError;
};
- QSharedPointer<ItemPool> itemPool;
+ std::shared_ptr<ItemPool> itemPool;
Item *root;
QHash<Item *, ProductInfo> productInfos;
QList<ProbeConstPtr> projectProbes;
@@ -120,6 +123,7 @@ public:
void setSearchPaths(const QStringList &searchPaths);
void setOldProjectProbes(const QList<ProbeConstPtr> &oldProbes);
void setOldProductProbes(const QHash<QString, QList<ProbeConstPtr>> &oldProbes);
+ void setStoredProfiles(const QVariantMap &profiles);
Evaluator *evaluator() const { return m_evaluator; }
ModuleLoaderResult load(const SetupProjectParameters &parameters);
@@ -155,7 +159,10 @@ private:
ModuleLoaderResult::ProductInfo info;
QString name;
QString profileName;
+ QString multiplexConfigurationId;
QVariantMap moduleProperties;
+
+ QString uniqueName() const;
};
class TopLevelProjectContext;
@@ -166,15 +173,15 @@ private:
TopLevelProjectContext *topLevelProject;
ModuleLoaderResult *result;
std::vector<ProductContext> products;
- QStack<QStringList> searchPathsStack;
+ std::vector<QStringList> searchPathsStack;
};
struct ProductModuleInfo
{
- ProductModuleInfo() : exportItem() {}
-
- Item *exportItem;
+ Item *exportItem = nullptr;
+ bool dependenciesResolved = false;
QList<ModuleLoaderResult::ProductInfo::Dependency> productDependencies;
+ QVariantMap defaultParameters;
};
class TopLevelProjectContext
@@ -204,10 +211,31 @@ private:
void handleProject(ModuleLoaderResult *loadResult,
TopLevelProjectContext *topLevelProjectContext, Item *projectItem,
const Set<QString> &referencedFilePaths);
+
+ typedef std::vector<VariantValuePtr> MultiplexRow;
+ typedef std::vector<MultiplexRow> MultiplexTable;
+
+ struct MultiplexInfo
+ {
+ std::vector<QString> properties;
+ MultiplexTable table;
+ bool aggregate = false;
+ VariantValuePtr multiplexedType;
+
+ static QString configurationStringFromId(const QString &idString);
+ QString toIdString(size_t row) const;
+ };
+
+ void dump(const MultiplexInfo &mpi);
+ static MultiplexTable combine(const MultiplexTable &table, const MultiplexRow &values);
+ MultiplexInfo extractMultiplexInfo(Item *productItem, Item *qbsModuleItem);
QList<Item *> multiplexProductItem(ProductContext *dummyContext, Item *productItem);
+ void adjustDependenciesForMultiplexing(const ProjectContext &projectContext);
+
void prepareProduct(ProjectContext *projectContext, Item *productItem);
void setupProductDependencies(ProductContext *productContext);
void handleProduct(ProductContext *productContext);
+ void checkDependencyParameterDeclarations(const ProductContext *productContext) const;
void handleModuleSetupError(ProductContext *productContext, const Item::Module &module,
const ErrorInfo &error);
void initProductProperties(const ProductContext &product);
@@ -224,8 +252,10 @@ private:
void setupReverseModuleDependencies(const Item::Module &module, ModuleDependencies &deps,
QualifiedIdSet &seenModules);
ModuleDependencies setupReverseModuleDependencies(const Item *product);
- void handleGroup(Item *groupItem, const ModuleDependencies &reverseDepencencies);
- void propagateModulesFromParent(Item *groupItem, const ModuleDependencies &reverseDepencencies);
+ void handleGroup(ProductContext *productContext, Item *groupItem,
+ const ModuleDependencies &reverseDepencencies);
+ void propagateModulesFromParent(ProductContext *productContext, Item *groupItem,
+ const ModuleDependencies &reverseDepencencies);
void adjustDefiningItemsInGroupModuleInstances(const Item::Module &module,
const Item::Modules &dependentModules);
@@ -234,11 +264,17 @@ private:
class ItemModuleList;
void resolveDependsItem(DependsContext *dependsContext, Item *parentItem, Item *dependsItem,
ItemModuleList *moduleResults, ProductDependencyResults *productResults);
+ void forwardParameterDeclarations(const Item *dependsItem, const ItemModuleList &modules);
+ void forwardParameterDeclarations(const QualifiedId &moduleName, Item *item,
+ const ItemModuleList &modules);
+ void resolveParameterDeclarations(const Item *module);
+ QVariantMap extractParameters(Item *dependsItem) const;
Item *moduleInstanceItem(Item *containerItem, const QualifiedId &moduleName);
- Item *loadProductModule(ProductContext *productContext, const QString &moduleName);
+ ProductModuleInfo loadProductModule(ProductContext *productContext, const QString &moduleName);
Item *loadModule(ProductContext *productContext, Item *item,
const CodeLocation &dependsItemLocation, const QString &moduleId,
- const QualifiedId &moduleName, bool isRequired, bool *isModuleDependency);
+ const QualifiedId &moduleName, bool isRequired, bool *isProductDependency,
+ QVariantMap *defaultParameters);
Item *searchAndLoadModuleFile(ProductContext *productContext,
const CodeLocation &dependsItemLocation, const QualifiedId &moduleName,
const QStringList &extraSearchPaths, bool isRequired, bool *cacheHit);
@@ -261,8 +297,10 @@ private:
static QString findExistingModulePath(const QString &searchPath,
const QualifiedId &moduleName);
static void setScopeForDescendants(Item *item, Item *scope);
+ static void forwardScopeToItemValues(Item *item, Item *scope);
void overrideItemProperties(Item *item, const QString &buildConfigKey,
const QVariantMap &buildConfig);
+ void addProductModuleDependencies(ProductContext *ctx, const Item::Module &module);
void addTransitiveDependencies(ProductContext *ctx);
Item *createNonPresentModule(const QString &name, const QString &reason, Item *module);
void copyGroupsFromModuleToProduct(const ProductContext &productContext,
@@ -280,7 +318,7 @@ private:
void printProfilingInfo();
void handleProductError(const ErrorInfo &error, ProductContext *productContext);
- bool isSomeModulePropertySet(const Item *item);
+ QualifiedIdSet gatherModulePropertiesSetInGroup(const Item *group);
Item *loadItemFromFile(const QString &filePath);
ItemPool *m_pool;
@@ -290,19 +328,20 @@ private:
Evaluator *m_evaluator;
QStringList m_moduleSearchPaths;
QMap<QString, QStringList> m_moduleDirListCache;
- QHash<QString, Item *> m_productModuleCache;
ModuleItemCache m_modulePrototypeItemCache;
- QHash<Item *, Set<QString>> m_validItemPropertyNamesPerItem;
+ QHash<const Item *, Item::PropertyDeclarationMap> m_parameterDeclarations;
Set<Item *> m_disabledItems;
- QStack<bool> m_requiredChain;
+ std::vector<bool> m_requiredChain;
using DependsChainEntry = std::pair<QualifiedId, CodeLocation>;
class DependsChainManager;
- QStack<DependsChainEntry> m_dependsChain;
+ std::vector<DependsChainEntry> m_dependsChain;
QHash<QString, QList<ProbeConstPtr>> m_oldProjectProbes;
QHash<QString, QList<ProbeConstPtr>> m_oldProductProbes;
QHash<CodeLocation, QList<ProbeConstPtr>> m_currentProbes;
+ QVariantMap m_storedProfiles;
+ std::multimap<QString, const ProductContext *> m_productsByName;
SetupProjectParameters m_parameters;
Version m_qbsVersion;
Item *m_tempScopeItem = nullptr;
diff --git a/src/lib/corelib/language/modulemerger.cpp b/src/lib/corelib/language/modulemerger.cpp
index 578c0dc12..ea79d6562 100644
--- a/src/lib/corelib/language/modulemerger.cpp
+++ b/src/lib/corelib/language/modulemerger.cpp
@@ -68,7 +68,7 @@ void ModuleMerger::replaceItemInValues(QualifiedId moduleName, Item *containerIt
for (auto it = properties.begin(); it != properties.end(); ++it) {
if (it.key() != moduleNamePrefix)
continue;
- Value * const val = it.value().data();
+ Value * const val = it.value().get();
QBS_CHECK(val);
QBS_CHECK(val->type() == Value::ItemValueType);
ItemValue * const itemVal = static_cast<ItemValue *>(val);
@@ -189,10 +189,10 @@ void ModuleMerger::mergeOutProps(Item::PropertyMap *dst, const Item::PropertyMap
continue;
}
// possible conflict
- JSSourceValuePtr dstVal = v.dynamicCast<JSSourceValue>();
+ JSSourceValuePtr dstVal = std::dynamic_pointer_cast<JSSourceValue>(v);
if (!dstVal)
continue;
- JSSourceValuePtr srcVal = it.value().dynamicCast<JSSourceValue>();
+ JSSourceValuePtr srcVal = std::dynamic_pointer_cast<JSSourceValue>(it.value());
if (!srcVal)
continue;
@@ -223,8 +223,11 @@ void ModuleMerger::insertProperties(Item::PropertyMap *dst, Item *srcItem, Prope
for (Item::PropertyMap::const_iterator it = srcItem->properties().constBegin();
it != srcItem->properties().constEnd(); ++it) {
const ValuePtr &srcVal = it.value();
- if (srcVal->type() != Value::JSSourceValueType)
+ if (srcVal->type() == Value::ItemValueType
+ || it.key() == QLatin1String("_qbs_sourceDir")) {
continue;
+ }
+
const PropertyDeclaration srcDecl = srcItem->propertyDeclaration(it.key());
if (!srcDecl.isValid() || srcDecl.isScalar() != (type == ScalarProperties))
continue;
@@ -254,6 +257,8 @@ void ModuleMerger::appendPrototypeValueToNextChain(Item *moduleProto, const QStr
if (!m_clonedModulePrototype) {
m_clonedModulePrototype = Item::create(moduleProto->pool(), ItemType::Module);
m_clonedModulePrototype->setScope(m_mergedModule.item);
+ m_clonedModulePrototype->setLocation(moduleProto->location());
+ moduleProto->copyProperty(QStringLiteral("name"), m_clonedModulePrototype);
}
const ValuePtr &protoValue = moduleProto->property(propertyName);
QBS_CHECK(protoValue);
diff --git a/src/lib/corelib/language/preparescriptobserver.cpp b/src/lib/corelib/language/preparescriptobserver.cpp
index 5e643e84e..a8f0c3765 100644
--- a/src/lib/corelib/language/preparescriptobserver.cpp
+++ b/src/lib/corelib/language/preparescriptobserver.cpp
@@ -42,6 +42,8 @@
#include "property.h"
#include "scriptengine.h"
+#include <tools/stlutils.h>
+
#include <QtScript/qscriptvalue.h>
namespace qbs {
@@ -57,14 +59,20 @@ PrepareScriptObserver::PrepareScriptObserver(ScriptEngine *engine)
void PrepareScriptObserver::onPropertyRead(const QScriptValue &object, const QString &name,
const QScriptValue &value)
{
- if (object.objectId() == m_productObjectId) {
+ const auto objectId = object.objectId();
+ if (objectId == m_productObjectId) {
m_engine->addPropertyRequestedInScript(
Property(QString(), name, value.toVariant(), Property::PropertyInProduct));
- } else if (object.objectId() == m_projectObjectId) {
+ } else if (objectId == m_projectObjectId) {
m_engine->addPropertyRequestedInScript(
Property(QString(), name, value.toVariant(), Property::PropertyInProject));
+ } else {
+ const auto it = m_parameterObjects.find(objectId);
+ if (it != m_parameterObjects.cend()) {
+ m_engine->addPropertyRequestedInScript(
+ Property(it->second, name, value.toVariant(), Property::PropertyInParameters));
+ }
}
-
}
diff --git a/src/lib/corelib/language/preparescriptobserver.h b/src/lib/corelib/language/preparescriptobserver.h
index b10c22036..366d37b5d 100644
--- a/src/lib/corelib/language/preparescriptobserver.h
+++ b/src/lib/corelib/language/preparescriptobserver.h
@@ -39,8 +39,13 @@
#ifndef QBS_PREPARESCRIPTOBSERVER_H
#define QBS_PREPARESCRIPTOBSERVER_H
+#include "qualifiedid.h"
#include "scriptpropertyobserver.h"
+#include <QString>
+
+#include <unordered_map>
+
namespace qbs {
namespace Internal {
class ScriptEngine;
@@ -52,6 +57,11 @@ public:
void setProductObjectId(qint64 productId) { m_productObjectId = productId; }
void setProjectObjectId(qint64 projectId) { m_projectObjectId = projectId; }
+ void addParameterObjectId(qint64 id, const QString &depName, const QualifiedId &moduleName)
+ {
+ m_parameterObjects.insert(std::make_pair(id, depName + QLatin1Char(':')
+ + moduleName.toString()));
+ }
private:
void onPropertyRead(const QScriptValue &object, const QString &name, const QScriptValue &value);
@@ -59,6 +69,7 @@ private:
ScriptEngine * const m_engine;
qint64 m_productObjectId;
qint64 m_projectObjectId;
+ std::unordered_map<qint64, QString> m_parameterObjects;
};
} // namespace Internal
diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp
index 7dec4c978..0b81f6f4e 100644
--- a/src/lib/corelib/language/projectresolver.cpp
+++ b/src/lib/corelib/language/projectresolver.cpp
@@ -61,9 +61,9 @@
#include <tools/setupprojectparameters.h>
#include <QtCore/qdir.h>
-#include <QtCore/qqueue.h>
#include <algorithm>
+#include <queue>
namespace qbs {
namespace Internal {
@@ -190,7 +190,8 @@ QString ProjectResolver::verbatimValue(const ValueConstPtr &value, bool *propert
{
QString result;
if (value && value->type() == Value::JSSourceValueType) {
- const JSSourceValueConstPtr sourceValue = value.staticCast<const JSSourceValue>();
+ const JSSourceValueConstPtr sourceValue = std::static_pointer_cast<const JSSourceValue>(
+ value);
result = sourceCodeForEvaluation(sourceValue);
if (propertyWasSet)
*propertyWasSet = (result != QLatin1String("undefined"));
@@ -249,6 +250,7 @@ TopLevelProjectPtr ProjectResolver::resolveTopLevelProject()
projectContext.project = project;
resolveProject(m_loadResult.root, &projectContext);
project->setBuildConfiguration(m_setupParams.finalBuildConfigurationTree());
+ project->overriddenValues = m_setupParams.overriddenValues();
project->usedEnvironment = m_engine->usedEnvironment();
project->canonicalFilePathResults = m_engine->canonicalFilePathResults();
project->fileExistsResults = m_engine->fileExistsResults();
@@ -364,6 +366,8 @@ void ProjectResolver::resolveProduct(Item *item, ProjectContext *projectContext)
productContext.buildDirectory = m_evaluator->stringValue(item, QLatin1String("buildDirectory"));
product->profile = m_evaluator->stringValue(item, QLatin1String("profile"));
QBS_CHECK(!product->profile.isEmpty());
+ product->multiplexConfigurationId
+ = m_evaluator->stringValue(item, QLatin1String("multiplexConfigurationId"));
m_logger.qbsTrace() << "[PR] resolveProduct " << product->uniqueName();
m_productsByName.insert(product->uniqueName(), product);
product->enabled = m_evaluator->boolValue(item, QLatin1String("condition"));
@@ -454,17 +458,18 @@ void ProjectResolver::resolveModules(const Item *item, ProjectContext *projectCo
{
// Breadth first search needed here, because the product might set properties on the cpp module,
// whose children must be evaluated in that context then.
- QQueue<Item::Module> modules;
+ std::queue<Item::Module> modules;
for (const Item::Module &m : item->modules())
- modules.enqueue(m);
+ modules.push(m);
Set<QualifiedId> seen;
- while (!modules.isEmpty()) {
- const Item::Module m = modules.takeFirst();
+ while (!modules.empty()) {
+ const Item::Module m = modules.front();
+ modules.pop();
if (!seen.insert(m.name).second)
continue;
- resolveModule(m.name, m.item, m.isProduct, projectContext);
+ resolveModule(m.name, m.item, m.isProduct, m.parameters, projectContext);
for (const Item::Module &childModule : m.item->modules())
- modules.enqueue(childModule);
+ modules.push(childModule);
}
std::sort(m_productContext->product->modules.begin(), m_productContext->product->modules.end(),
[](const ResolvedModuleConstPtr &m1, const ResolvedModuleConstPtr &m2) {
@@ -473,7 +478,7 @@ void ProjectResolver::resolveModules(const Item *item, ProjectContext *projectCo
}
void ProjectResolver::resolveModule(const QualifiedId &moduleName, Item *item, bool isProduct,
- ProjectContext *projectContext)
+ const QVariantMap &parameters, ProjectContext *projectContext)
{
checkCancelation();
if (!m_evaluator->boolValue(item, QLatin1String("present")))
@@ -486,6 +491,7 @@ void ProjectResolver::resolveModule(const QualifiedId &moduleName, Item *item, b
const ResolvedModulePtr &module = moduleContext.module;
module->name = moduleName.toString();
+ module->isProduct = isProduct;
module->setupBuildEnvironmentScript = scriptFunctionValue(item,
QLatin1String("setupBuildEnvironment"));
module->setupRunEnvironmentScript = scriptFunctionValue(item,
@@ -499,8 +505,9 @@ void ProjectResolver::resolveModule(const QualifiedId &moduleName, Item *item, b
module->moduleDependencies += m.name.toString();
}
- if (!isProduct)
- m_productContext->product->modules += module;
+ m_productContext->product->modules += module;
+ if (!parameters.isEmpty())
+ m_productContext->product->moduleParameters[module] = parameters;
static const ItemFuncMap mapping {
{ ItemType::Group, &ProjectResolver::ignoreItem },
@@ -509,6 +516,7 @@ void ProjectResolver::resolveModule(const QualifiedId &moduleName, Item *item, b
{ ItemType::Scanner, &ProjectResolver::resolveScanner },
{ ItemType::PropertyOptions, &ProjectResolver::ignoreItem },
{ ItemType::Depends, &ProjectResolver::ignoreItem },
+ { ItemType::Parameter, &ProjectResolver::ignoreItem },
{ ItemType::Probe, &ProjectResolver::ignoreItem }
};
for (Item *child : item->children())
@@ -567,42 +575,20 @@ static QualifiedIdSet propertiesToEvaluate(const QList<QualifiedId> &initialProp
return allProperties;
}
-static void gatherAssignedProperties(ItemValue *iv, const QualifiedId &prefix,
- QList<QualifiedId> &properties)
-{
- const Item::PropertyMap &props = iv->item()->properties();
- for (auto it = props.cbegin(); it != props.cend(); ++it) {
- switch (it.value()->type()) {
- case Value::JSSourceValueType:
- properties << (QualifiedId(prefix) << it.key());
- break;
- case Value::ItemValueType:
- gatherAssignedProperties(it.value().staticCast<ItemValue>().data(),
- QualifiedId(prefix) << it.key(), properties);
- break;
- default:
- break;
- }
- }
-}
-
QVariantMap ProjectResolver::resolveAdditionalModuleProperties(const Item *group,
const QVariantMap &currentValues)
{
- // Step 1: Gather the properties directly set in the group
- QList<QualifiedId> propsSetInGroup;
- for (auto it = group->properties().cbegin(); it != group->properties().cend(); ++it) {
- if (it.value()->type() == Value::ItemValueType) {
- gatherAssignedProperties(it.value().staticCast<ItemValue>().data(),
- QualifiedId(it.key()), propsSetInGroup);
- }
- }
- if (propsSetInGroup.isEmpty())
+ // Step 1: Retrieve the properties directly set in the group
+ const ModulePropertiesPerGroup &mp = m_loadResult.productInfos.value(m_productContext->item)
+ .modulePropertiesSetInGroups;
+ const auto it = mp.find(group);
+ if (it == mp.end())
return QVariantMap();
+ const QualifiedIdSet &propsSetInGroup = it->second;
// Step 2: Gather all properties that depend on these properties.
const QualifiedIdSet &propsToEval
- = propertiesToEvaluate(propsSetInGroup, m_evaluator->propertyDependencies());
+ = propertiesToEvaluate(propsSetInGroup.toList(), m_evaluator->propertyDependencies());
// Step 3: Evaluate all these properties and replace their values in the map
QVariantMap modulesMap = currentValues.value(QLatin1String("modules")).toMap();
@@ -850,6 +836,11 @@ void ProjectResolver::resolveRule(Item *item, ProjectContext *projectContext)
rule->inputs = m_evaluator->fileTagsValue(item, QLatin1String("inputs"));
rule->inputsFromDependencies
= m_evaluator->fileTagsValue(item, QLatin1String("inputsFromDependencies"));
+ bool requiresInputsSet = false;
+ rule->requiresInputs = m_evaluator->boolValue(item, QLatin1String("requiresInputs"), true,
+ &requiresInputsSet);
+ if (!requiresInputsSet)
+ rule->requiresInputs = rule->declaresInputs();
rule->auxiliaryInputs
= m_evaluator->fileTagsValue(item, QLatin1String("auxiliaryInputs"));
rule->excludedAuxiliaryInputs
@@ -857,12 +848,19 @@ void ProjectResolver::resolveRule(Item *item, ProjectContext *projectContext)
rule->explicitlyDependsOn
= m_evaluator->fileTagsValue(item, QLatin1String("explicitlyDependsOn"));
rule->module = m_moduleContext ? m_moduleContext->module : projectContext->dummyModule;
- if (!rule->multiplex && !rule->requiresInputs()) {
- const QString message = Tr::tr("Rule has no inputs, but is not a multiplex rule.");
- ErrorInfo error(message, item->location());
- if (m_setupParams.productErrorMode() == ErrorHandlingMode::Strict)
- throw error;
- m_logger.printWarning(error);
+ if (!rule->multiplex && !rule->declaresInputs()) {
+ handleError(ErrorInfo(Tr::tr("Rule has no inputs, but is not a multiplex rule."),
+ item->location()));
+ return;
+ }
+ if (!rule->multiplex && !rule->requiresInputs) {
+ handleError(ErrorInfo(Tr::tr("Rule.requiresInputs is false for non-multiplex rule.")
+ , item->location()));
+ return;
+ }
+ if (!rule->declaresInputs() && rule->requiresInputs) {
+ handleError(ErrorInfo(Tr::tr("Rule.requiresInputs is true, but the rule "
+ "does not declare any input tags."), item->location()));
return;
}
if (m_productContext)
@@ -891,7 +889,8 @@ void ProjectResolver::resolveRuleArtifact(const RulePtr &rule, Item *item)
{
if (it.value()->type() != Value::ItemValueType)
continue;
- resolveRuleArtifactBinding(artifact, it.value().staticCast<ItemValue>()->item(),
+ resolveRuleArtifactBinding(artifact,
+ std::static_pointer_cast<ItemValue>(it.value())->item(),
QStringList(it.key()), &seenBindings);
}
}
@@ -908,13 +907,13 @@ void ProjectResolver::resolveRuleArtifactBinding(const RuleArtifactPtr &ruleArti
const QStringList name = QStringList(namePrefix) << it.key();
if (it.value()->type() == Value::ItemValueType) {
resolveRuleArtifactBinding(ruleArtifact,
- it.value().staticCast<ItemValue>()->item(), name,
+ std::static_pointer_cast<ItemValue>(it.value())->item(), name,
seenBindings);
} else if (it.value()->type() == Value::JSSourceValueType) {
const auto insertResult = seenBindings->insert(name);
if (!insertResult.second)
continue;
- JSSourceValuePtr sourceValue = it.value().staticCast<JSSourceValue>();
+ JSSourceValuePtr sourceValue = std::static_pointer_cast<JSSourceValue>(it.value());
RuleArtifact::Binding rab;
rab.name = name;
rab.code = sourceCodeForEvaluation(sourceValue);
@@ -966,11 +965,22 @@ void ProjectResolver::resolveScanner(Item *item, ProjectResolver::ProjectContext
m_productContext->product->scanners += scanner;
}
-QList<ResolvedProductPtr> ProjectResolver::getProductDependencies(const ResolvedProductConstPtr &product,
- const ModuleLoaderResult::ProductInfo &productInfo, bool &disabledDependency)
+static ModuleLoaderResult::ProductInfo::Dependency extractDependency(
+ const ResolvedProductConstPtr &product)
{
+ ModuleLoaderResult::ProductInfo::Dependency dependency;
+ dependency.name = product->name;
+ dependency.profile = product->profile;
+ dependency.multiplexConfigurationId = product->multiplexConfigurationId;
+ return dependency;
+}
+
+ProjectResolver::ProductDependencyInfos ProjectResolver::getProductDependencies(
+ const ResolvedProductConstPtr &product, const ModuleLoaderResult::ProductInfo &productInfo)
+{
+ ProductDependencyInfos result;
+ result.dependencies.reserve(productInfo.usedProducts.size());
QList<ModuleLoaderResult::ProductInfo::Dependency> dependencies = productInfo.usedProducts;
- QList<ResolvedProductPtr> usedProducts;
for (int i = dependencies.count() - 1; i >= 0; --i) {
const ModuleLoaderResult::ProductInfo::Dependency &dependency = dependencies.at(i);
QBS_CHECK(dependency.name.isEmpty() != dependency.productTypes.isEmpty());
@@ -982,11 +992,8 @@ QList<ResolvedProductPtr> ProjectResolver::getProductDependencies(const Resolved
|| (dependency.limitToSubProject && !product->isInParentProject(p))) {
continue;
}
- usedProducts << p;
- ModuleLoaderResult::ProductInfo::Dependency newDependency;
- newDependency.name = p->name;
- newDependency.profile = p->profile;
- dependencies << newDependency;
+ result.dependencies.emplace_back(p, dependency.parameters);
+ dependencies << extractDependency(p);
}
}
dependencies.removeAt(i);
@@ -996,19 +1003,29 @@ QList<ResolvedProductPtr> ProjectResolver::getProductDependencies(const Resolved
|| (dependency.limitToSubProject && !product->isInParentProject(p))) {
continue;
}
- usedProducts << p;
- ModuleLoaderResult::ProductInfo::Dependency newDependency;
- newDependency.name = p->name;
- newDependency.profile = p->profile;
- dependencies << newDependency;
+ result.dependencies.emplace_back(p, dependency.parameters);
+ dependencies << extractDependency(p);
}
dependencies.removeAt(i);
} else {
- const ResolvedProductPtr &usedProduct
- = m_productsByName.value(dependency.uniqueName());
+ ResolvedProductPtr usedProduct;
+ if (!dependency.multiplexConfigurationId.isEmpty()) {
+ usedProduct = m_productsByName.value(dependency.uniqueName());
+ } else {
+ for (const ResolvedProductPtr &p : qAsConst(m_productsByName)) {
+ if (p->name == dependency.name && p->profile == dependency.profile) {
+ usedProduct = p;
+ break;
+ }
+ }
+ }
if (!usedProduct) {
- throw ErrorInfo(Tr::tr("Product '%1' depends on '%2', which does not exist.")
- .arg(product->name, dependency.uniqueName()), product->location);
+ const ResolvedProductConstPtr p = m_productsByName.value(dependency.uniqueName());
+ ErrorInfo e(Tr::tr("Product '%1' depends on '%2', which does not exist.")
+ .arg(product->name, dependency.uniqueName()), product->location);
+ if (p)
+ e.append(Tr::tr("Requested profile was '%1'.").arg(dependency.profile));
+ throw e;
}
if (!usedProduct->enabled) {
if (!dependency.isRequired)
@@ -1020,12 +1037,12 @@ QList<ResolvedProductPtr> ProjectResolver::getProductDependencies(const Resolved
usedProduct->location);
if (m_setupParams.productErrorMode() == ErrorHandlingMode::Strict)
throw e;
- disabledDependency = true;
+ result.hasDisabledDependency = true;
}
- usedProducts << usedProduct;
+ result.dependencies.emplace_back(usedProduct, dependency.parameters);
}
}
- return usedProducts;
+ return result;
}
void ProjectResolver::matchArtifactProperties(const ResolvedProductPtr &product,
@@ -1054,24 +1071,31 @@ void ProjectResolver::printProfilingInfo()
.arg(elapsedTimeString(m_elapsedTimeGroups));
}
+void ProjectResolver::handleError(const ErrorInfo &error)
+{
+ if (m_setupParams.productErrorMode() == ErrorHandlingMode::Strict)
+ throw error;
+ m_logger.printWarning(error);
+}
+
static bool hasDependencyCycle(Set<ResolvedProduct *> *checked,
Set<ResolvedProduct *> *branch,
const ResolvedProductPtr &product,
ErrorInfo *error)
{
- if (branch->contains(product.data()))
+ if (branch->contains(product.get()))
return true;
- if (checked->contains(product.data()))
+ if (checked->contains(product.get()))
return false;
- checked->insert(product.data());
- branch->insert(product.data());
+ checked->insert(product.get());
+ branch->insert(product.get());
for (const ResolvedProductPtr &dep : qAsConst(product->dependencies)) {
if (hasDependencyCycle(checked, branch, dep, error)) {
error->prepend(dep->name, dep->location);
return true;
}
}
- branch->remove(product.data());
+ branch->remove(product.get());
return false;
}
@@ -1082,9 +1106,9 @@ void gatherDependencies(ResolvedProduct *product, DependencyMap &dependencies)
return;
Set<ResolvedProduct *> &productDeps = dependencies[product];
for (const ResolvedProductPtr &dep : qAsConst(product->dependencies)) {
- productDeps << dep.data();
- gatherDependencies(dep.data(), dependencies);
- productDeps += dependencies.value(dep.data());
+ productDeps << dep.get();
+ gatherDependencies(dep.get(), dependencies);
+ productDeps += dependencies.value(dep.get());
}
}
@@ -1094,7 +1118,7 @@ static DependencyMap allDependencies(const QList<ResolvedProductPtr> &products)
{
DependencyMap dependencies;
for (const ResolvedProductPtr &product : products)
- gatherDependencies(product.data(), dependencies);
+ gatherDependencies(product.get(), dependencies);
return dependencies;
}
@@ -1109,9 +1133,13 @@ void ProjectResolver::resolveProductDependencies(const ProjectContext &projectCo
Item *productItem = m_productItemMap.value(rproduct);
const ModuleLoaderResult::ProductInfo &productInfo
= m_loadResult.productInfos.value(productItem);
- for (const ResolvedProductPtr &usedProduct :
- getProductDependencies(rproduct, productInfo, disabledDependency)) {
- rproduct->dependencies.insert(usedProduct);
+ const ProductDependencyInfos &depInfos = getProductDependencies(rproduct, productInfo);
+ if (depInfos.hasDisabledDependency)
+ disabledDependency = true;
+ for (const auto &dep : depInfos.dependencies) {
+ rproduct->dependencies.insert(dep.product);
+ if (!dep.parameters.isEmpty())
+ rproduct->dependencyParameters.insert(dep.product, dep.parameters);
}
}
@@ -1250,7 +1278,7 @@ QVariantMap ProjectResolver::evaluateProperties(const Item *item, const Item *pr
{
if (result.contains(it.key()))
break;
- VariantValuePtr vvp = it.value().staticCast<VariantValue>();
+ VariantValuePtr vvp = std::static_pointer_cast<VariantValue>(it.value());
QVariant v = vvp->value();
if (v.isNull() && !item->propertyDeclaration(it.key()).isScalar()) // QTBUG-51237
diff --git a/src/lib/corelib/language/projectresolver.h b/src/lib/corelib/language/projectresolver.h
index cd5d5fe6b..f25db0651 100644
--- a/src/lib/corelib/language/projectresolver.h
+++ b/src/lib/corelib/language/projectresolver.h
@@ -97,7 +97,7 @@ private:
void resolveProduct(Item *item, ProjectContext *projectContext);
void resolveModules(const Item *item, ProjectContext *projectContext);
void resolveModule(const QualifiedId &moduleName, Item *item, bool isProduct,
- ProjectContext *projectContext);
+ const QVariantMap &parameters, ProjectContext *projectContext);
QVariantMap resolveAdditionalModuleProperties(const Item *group,
const QVariantMap &currentValues);
void resolveGroup(Item *item, ProjectContext *projectContext);
@@ -119,14 +119,34 @@ private:
QString convertPathProperty(const QString &path, const QString &dirPath) const;
QStringList convertPathListProperty(const QStringList &paths, const QString &dirPath) const;
ProjectContext createProjectContext(ProjectContext *parentProjectContext) const;
- QList<ResolvedProductPtr> getProductDependencies(const ResolvedProductConstPtr &product,
- const ModuleLoaderResult::ProductInfo &productInfo, bool &disabledDependency);
+
+ struct ProductDependencyInfo
+ {
+ ProductDependencyInfo(const ResolvedProductPtr &product,
+ const QVariantMap &parameters = QVariantMap())
+ : product(product), parameters(parameters)
+ {
+ }
+
+ ResolvedProductPtr product;
+ QVariantMap parameters;
+ };
+
+ struct ProductDependencyInfos
+ {
+ std::vector<ProductDependencyInfo> dependencies;
+ bool hasDisabledDependency = false;
+ };
+
+ ProductDependencyInfos getProductDependencies(const ResolvedProductConstPtr &product,
+ const ModuleLoaderResult::ProductInfo &productInfo);
QString sourceCodeAsFunction(const JSSourceValueConstPtr &value,
const PropertyDeclaration &decl) const;
QString sourceCodeForEvaluation(const JSSourceValueConstPtr &value) const;
static void matchArtifactProperties(const ResolvedProductPtr &product,
const QList<SourceArtifactPtr> &artifacts);
void printProfilingInfo();
+ void handleError(const ErrorInfo &error);
Evaluator *m_evaluator;
Logger &m_logger;
diff --git a/src/lib/corelib/language/property.h b/src/lib/corelib/language/property.h
index 666545eaf..159d977d2 100644
--- a/src/lib/corelib/language/property.h
+++ b/src/lib/corelib/language/property.h
@@ -55,7 +55,8 @@ public:
{
PropertyInModule,
PropertyInProduct,
- PropertyInProject
+ PropertyInProject,
+ PropertyInParameters
};
Property()
diff --git a/src/lib/corelib/language/propertydeclaration.cpp b/src/lib/corelib/language/propertydeclaration.cpp
index 032c53ce6..775ce3209 100644
--- a/src/lib/corelib/language/propertydeclaration.cpp
+++ b/src/lib/corelib/language/propertydeclaration.cpp
@@ -204,6 +204,11 @@ bool PropertyDeclaration::isDeprecated() const
return d->deprecationInfo.isValid();
}
+bool PropertyDeclaration::isExpired() const
+{
+ return isDeprecated() && deprecationInfo().removalVersion() <= Version::qbsVersion();
+}
+
const DeprecationInfo &PropertyDeclaration::deprecationInfo() const
{
return d->deprecationInfo;
diff --git a/src/lib/corelib/language/propertydeclaration.h b/src/lib/corelib/language/propertydeclaration.h
index 6eaeb2259..d86ad99ea 100644
--- a/src/lib/corelib/language/propertydeclaration.h
+++ b/src/lib/corelib/language/propertydeclaration.h
@@ -107,6 +107,7 @@ public:
void setFunctionArgumentNames(const QStringList &lst);
bool isDeprecated() const;
+ bool isExpired() const;
const DeprecationInfo &deprecationInfo() const;
void setDeprecationInfo(const DeprecationInfo &deprecationInfo);
diff --git a/src/lib/corelib/language/propertymapinternal.h b/src/lib/corelib/language/propertymapinternal.h
index 9874f5546..69890fef3 100644
--- a/src/lib/corelib/language/propertymapinternal.h
+++ b/src/lib/corelib/language/propertymapinternal.h
@@ -42,12 +42,13 @@
#include "forward_decls.h"
#include <tools/persistentobject.h>
+#include <tools/qbs_export.h>
#include <QtCore/qvariant.h>
namespace qbs {
namespace Internal {
-class PropertyMapInternal : public PersistentObject
+class QBS_AUTOTEST_EXPORT PropertyMapInternal : public PersistentObject
{
public:
static PropertyMapPtr create() { return PropertyMapPtr(new PropertyMapInternal); }
@@ -76,8 +77,9 @@ inline bool operator==(const PropertyMapInternal &lhs, const PropertyMapInternal
return lhs.m_value == rhs.m_value;
}
-QVariant moduleProperty(const QVariantMap &properties, const QString &moduleName,
- const QString &key);
+QVariant QBS_AUTOTEST_EXPORT moduleProperty(const QVariantMap &properties,
+ const QString &moduleName,
+ const QString &key);
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/qualifiedid.h b/src/lib/corelib/language/qualifiedid.h
index 007133be8..1415f668e 100644
--- a/src/lib/corelib/language/qualifiedid.h
+++ b/src/lib/corelib/language/qualifiedid.h
@@ -49,7 +49,7 @@
namespace qbs {
namespace Internal {
-class QualifiedId : public QStringList
+class QBS_AUTOTEST_EXPORT QualifiedId : public QStringList
{
public:
QualifiedId();
@@ -60,7 +60,7 @@ public:
QString toString() const;
};
-bool operator<(const QualifiedId &a, const QualifiedId &b);
+bool QBS_AUTOTEST_EXPORT operator<(const QualifiedId &a, const QualifiedId &b);
inline uint qHash(const QualifiedId &qid) { return qHash(qid.toString()); }
using QualifiedIdSet = Set<QualifiedId>;
diff --git a/src/lib/corelib/language/scriptengine.cpp b/src/lib/corelib/language/scriptengine.cpp
index ea33255c0..a248f0d0a 100644
--- a/src/lib/corelib/language/scriptengine.cpp
+++ b/src/lib/corelib/language/scriptengine.cpp
@@ -352,12 +352,11 @@ QScriptValue ScriptEngine::js_loadExtension(QScriptContext *context, QScriptEngi
"an extension name."));
}
- // TODO: Enable in 1.9
- // ScriptEngine *engine = static_cast<ScriptEngine *>(qtengine);
- // ErrorInfo deprWarning(Tr::tr("The loadExtension() function is deprecated and will be "
- // "removed in a future version of Qbs. Use require() "
- // "instead."), context->backtrace());
- // engine->logger().printWarning(deprWarning);
+ ScriptEngine *engine = static_cast<ScriptEngine *>(qtengine);
+ ErrorInfo deprWarning(Tr::tr("The loadExtension() function is deprecated and will be "
+ "removed in a future version of Qbs. Use require() "
+ "instead."), context->backtrace());
+ engine->logger().printWarning(deprWarning);
return js_require(context, qtengine);
}
@@ -369,12 +368,11 @@ QScriptValue ScriptEngine::js_loadFile(QScriptContext *context, QScriptEngine *q
ScriptEngine::tr("The loadFile function requires a file path."));
}
- // TODO: Enable in 1.9
- // ScriptEngine *engine = static_cast<ScriptEngine *>(qtengine);
- // ErrorInfo deprWarning(Tr::tr("The loadFile() function is deprecated and will be "
- // "removed in a future version of Qbs. Use require() "
- // "instead."), context->backtrace());
- // engine->logger().printWarning(deprWarning);
+ ScriptEngine *engine = static_cast<ScriptEngine *>(qtengine);
+ ErrorInfo deprWarning(Tr::tr("The loadFile() function is deprecated and will be "
+ "removed in a future version of Qbs. Use require() "
+ "instead."), context->backtrace());
+ engine->logger().printWarning(deprWarning);
return js_require(context, qtengine);
}
@@ -391,7 +389,7 @@ QScriptValue ScriptEngine::js_require(QScriptContext *context, QScriptEngine *qt
// First try to load a named module if the argument doesn't look like a file path
if (!moduleName.contains(QLatin1Char('/'))) {
- if (engine->m_extensionSearchPathsStack.isEmpty())
+ if (engine->m_extensionSearchPathsStack.empty())
return context->throwError(
ScriptEngine::tr("require: internal error. No search paths."));
@@ -436,7 +434,7 @@ QScriptValue ScriptEngine::js_require(QScriptContext *context, QScriptEngine *qt
// file located in the current directory search path; try that next
}
- if (engine->m_currentDirPathStack.isEmpty()) {
+ if (engine->m_currentDirPathStack.empty()) {
return context->throwError(
ScriptEngine::tr("require: internal error. No current directory."));
}
diff --git a/src/lib/corelib/language/scriptengine.h b/src/lib/corelib/language/scriptengine.h
index 44e15d0e6..da0b6028c 100644
--- a/src/lib/corelib/language/scriptengine.h
+++ b/src/lib/corelib/language/scriptengine.h
@@ -51,11 +51,11 @@
#include <QtCore/qhash.h>
#include <QtCore/qlist.h>
#include <QtCore/qprocess.h>
-#include <QtCore/qstack.h>
#include <QtCore/qstring.h>
#include <QtScript/qscriptengine.h>
+#include <stack>
#include <vector>
namespace qbs {
@@ -76,7 +76,7 @@ public:
};
using DubiousContextList = std::vector<DubiousContext>;
-class ScriptEngine : public QScriptEngine
+class QBS_AUTOTEST_EXPORT ScriptEngine : public QScriptEngine
{
Q_OBJECT
public:
@@ -237,8 +237,8 @@ private:
QHash<QString, bool> m_fileExistsResult;
QHash<std::pair<QString, quint32>, QStringList> m_directoryEntriesResult;
QHash<QString, FileTime> m_fileLastModifiedResult;
- QStack<QString> m_currentDirPathStack;
- QStack<QStringList> m_extensionSearchPathsStack;
+ std::stack<QString> m_currentDirPathStack;
+ std::stack<QStringList> m_extensionSearchPathsStack;
QScriptValue m_loadFileFunction;
QScriptValue m_loadExtensionFunction;
QScriptValue m_requireFunction;
diff --git a/src/lib/corelib/language/tst_language.cpp b/src/lib/corelib/language/tst_language.cpp
deleted file mode 100644
index f0ebc9702..000000000
--- a/src/lib/corelib/language/tst_language.cpp
+++ /dev/null
@@ -1,2344 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qbs.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#undef QT_NO_CAST_FROM_ASCII // I am qmake, and I approve this hack.
-
-#include "tst_language.h"
-
-#include "../../../../tests/auto/shared.h"
-
-#include <language/evaluator.h>
-#include <language/filecontext.h>
-#include <language/identifiersearch.h>
-#include <language/item.h>
-#include <language/itempool.h>
-#include <language/language.h>
-#include <language/propertymapinternal.h>
-#include <language/scriptengine.h>
-#include <language/value.h>
-#include <parser/qmljslexer_p.h>
-#include <parser/qmljsparser_p.h>
-#include <tools/scripttools.h>
-#include <tools/error.h>
-#include <tools/fileinfo.h>
-#include <tools/hostosinfo.h>
-#include <tools/jsliterals.h>
-#include <tools/profile.h>
-#include <tools/settings.h>
-
-#include <QtCore/qprocess.h>
-
-#include <algorithm>
-#include <utility>
-#include <vector>
-
-Q_DECLARE_METATYPE(QList<bool>)
-
-namespace qbs {
-namespace Internal {
-static QString testDataDir() {
- return FileInfo::resolvePath(QLatin1String(SRCDIR),
- QLatin1String("../../../tests/auto/language/testdata"));
-}
-static QString testProject(const char *fileName) {
- return testDataDir() + QLatin1Char('/') + QLatin1String(fileName);
-}
-
-TestLanguage::TestLanguage(ILogSink *logSink)
- : m_logSink(logSink)
- , m_wildcardsTestDirPath(QDir::tempPath() + QLatin1String("/_wildcards_test_dir_"))
-{
- qsrand(QTime::currentTime().msec());
- qRegisterMetaType<QList<bool> >("QList<bool>");
- defaultParameters.setBuildRoot("/some/build/directory");
- defaultParameters.setPropertyCheckingMode(ErrorHandlingMode::Strict);
-}
-
-TestLanguage::~TestLanguage()
-{
-}
-
-QHash<QString, ResolvedProductPtr> TestLanguage::productsFromProject(ResolvedProjectPtr project)
-{
- QHash<QString, ResolvedProductPtr> result;
- foreach (const ResolvedProductPtr &product, project->allProducts())
- result.insert(product->name, product);
- return result;
-}
-
-ResolvedModuleConstPtr TestLanguage::findModuleByName(ResolvedProductPtr product, const QString &name)
-{
- foreach (const ResolvedModuleConstPtr &module, product->modules)
- if (module->name == name)
- return module;
- return ResolvedModuleConstPtr();
-}
-
-QVariant TestLanguage::productPropertyValue(ResolvedProductPtr product, QString propertyName)
-{
- QStringList propertyNameComponents = propertyName.split(QLatin1Char('.'));
- if (propertyNameComponents.count() > 1) {
- propertyNameComponents.prepend(QLatin1String("modules"));
- return product->moduleProperties->property(propertyNameComponents);
- }
- return getConfigProperty(product->productProperties, propertyNameComponents);
-}
-
-void TestLanguage::handleInitCleanupDataTags(const char *projectFileName, bool *handled)
-{
- const QByteArray dataTag = QTest::currentDataTag();
- if (dataTag == "init") {
- *handled = true;
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject(projectFileName));
- project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
- } else if (dataTag == "cleanup") {
- *handled = true;
- project.clear();
- } else {
- *handled = false;
- }
-}
-
-#define HANDLE_INIT_CLEANUP_DATATAGS(fn) {\
- bool handled;\
- handleInitCleanupDataTags(fn, &handled);\
- if (handled)\
- return;\
- QVERIFY(project);\
-}
-
-void TestLanguage::initTestCase()
-{
- m_logger = Logger(m_logSink);
- m_engine = new ScriptEngine(m_logger, EvalContext::PropertyEvaluation, this);
- loader = new Loader(m_engine, m_logger);
- loader->setSearchPaths(QStringList()
- << QLatin1String(SRCDIR "/../../../share/qbs"));
- defaultParameters.setTopLevelProfile(profileName());
- defaultParameters.setConfigurationName("default");
- defaultParameters.expandBuildConfiguration();
- QVERIFY(QFileInfo(m_wildcardsTestDirPath).isAbsolute());
-}
-
-void TestLanguage::cleanupTestCase()
-{
- delete loader;
-}
-
-void TestLanguage::baseProperty()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("baseproperty.qbs"));
- project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value("product1");
- QVERIFY(product);
- QVariantMap cfg = product->productProperties;
- QCOMPARE(cfg.value("narf").toStringList(), QStringList() << "boo");
- QCOMPARE(cfg.value("zort").toStringList(), QStringList() << "bar" << "boo");
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::baseValidation()
-{
- qbs::SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("base-validate/base-validate.qbs"));
- try {
- project = loader->loadProject(params);
- QVERIFY2(false, "exception expected");
- } catch (const qbs::ErrorInfo &e) {
- QVERIFY2(e.toString().contains("Parent succeeded, child failed."),
- qPrintable(e.toString()));
- }
-}
-
-void TestLanguage::buildConfigStringListSyntax()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters parameters = defaultParameters;
- QVariantMap overriddenValues;
- overriddenValues.insert("project.someStrings", "foo,bar,baz");
- parameters.setOverriddenValues(overriddenValues);
- parameters.setProjectFilePath(testProject("buildconfigstringlistsyntax.qbs"));
- project = loader->loadProject(parameters);
- QVERIFY(project);
- QCOMPARE(project->projectProperties().value("someStrings").toStringList(),
- QStringList() << "foo" << "bar" << "baz");
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::builtinFunctionInSearchPathsProperty()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters parameters = defaultParameters;
- parameters.setProjectFilePath(testProject("builtinFunctionInSearchPathsProperty.qbs"));
- QVERIFY(loader->loadProject(parameters));
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::chainedProbes()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters parameters = defaultParameters;
- parameters.setProjectFilePath(testProject("chained-probes/chained-probes.qbs"));
- const TopLevelProjectConstPtr project = loader->loadProject(parameters);
- QVERIFY(project);
- QCOMPARE(project->products.count(), 1);
- const QString prop2Val = project->products.first()->moduleProperties
- ->moduleProperty("m", "prop2").toString();
- QCOMPARE(prop2Val, QLatin1String("probe1Valprobe2Val"));
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-
-}
-
-void TestLanguage::versionCompare()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters parameters = defaultParameters;
- parameters.setProjectFilePath(testProject("versionCompare.qbs"));
- QVERIFY(loader->loadProject(parameters));
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::canonicalArchitecture()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("canonicalArchitecture.qbs"));
- project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value(QLatin1String("x86"));
- QVERIFY(product);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::rfc1034Identifier()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("rfc1034identifier.qbs"));
- project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value(QLatin1String("this-has-special-characters-"
- "uh-oh-Undersc0r3s-Are.Bad"));
- QVERIFY(product);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::conditionalDepends()
-{
- bool exceptionCaught = false;
- ResolvedProductPtr product;
- ResolvedModuleConstPtr dependency;
- try {
- defaultParameters.setProjectFilePath(testProject("conditionaldepends.qbs"));
- project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
-
- product = products.value("conditionaldepends_derived");
- QVERIFY(product);
- dependency = findModuleByName(product, "dummy");
- QVERIFY(dependency);
-
- product = products.value("conditionaldepends_derived_false");
- QVERIFY(product);
- dependency = findModuleByName(product, "dummy");
- QCOMPARE(dependency, ResolvedModuleConstPtr());
-
- product = products.value("product_props_true");
- QVERIFY(product);
- dependency = findModuleByName(product, "dummy");
- QVERIFY(dependency);
-
- product = products.value("product_props_false");
- QVERIFY(product);
- dependency = findModuleByName(product, "dummy");
- QCOMPARE(dependency, ResolvedModuleConstPtr());
-
- product = products.value("project_props_true");
- QVERIFY(product);
- dependency = findModuleByName(product, "dummy");
- QVERIFY(dependency);
-
- product = products.value("project_props_false");
- QVERIFY(product);
- dependency = findModuleByName(product, "dummy");
- QCOMPARE(dependency, ResolvedModuleConstPtr());
-
- product = products.value("module_props_true");
- QVERIFY(product);
- dependency = findModuleByName(product, "dummy2");
- QVERIFY(dependency);
- dependency = findModuleByName(product, "dummy");
- QVERIFY(dependency);
-
- product = products.value("module_props_false");
- QVERIFY(product);
- dependency = findModuleByName(product, "dummy2");
- QVERIFY(dependency);
- dependency = findModuleByName(product, "dummy");
- QCOMPARE(dependency, ResolvedModuleConstPtr());
-
- product = products.value("contradictory_conditions1");
- QVERIFY(product);
- dependency = findModuleByName(product, "dummy");
- QVERIFY(dependency);
-
- product = products.value("contradictory_conditions2");
- QVERIFY(product);
- dependency = findModuleByName(product, "dummy");
- QVERIFY(dependency);
-
- product = products.value("unknown_dependency_condition_false");
- QVERIFY(product);
- dependency = findModuleByName(product, "doesonlyexistifhellfreezesover");
- QVERIFY(!dependency);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::delayedError()
-{
- QFETCH(bool, productEnabled);
- try {
- QFETCH(QString, projectFileName);
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject(projectFileName.toLatin1()));
- QVariantMap overriddenValues;
- overriddenValues.insert("project.enableProduct", productEnabled);
- params.setOverriddenValues(overriddenValues);
- project = loader->loadProject(params);
- QCOMPARE(productEnabled, false);
- QVERIFY(project);
- QCOMPARE(project->products.count(), 1);
- const ResolvedProductConstPtr theProduct = productsFromProject(project).value("theProduct");
- QVERIFY(theProduct);
- QCOMPARE(theProduct->enabled, false);
- } catch (const ErrorInfo &e) {
- if (!productEnabled)
- qDebug() << e.toString();
- QCOMPARE(productEnabled, true);
- }
-}
-
-void TestLanguage::delayedError_data()
-{
- QTest::addColumn<QString>("projectFileName");
- QTest::addColumn<bool>("productEnabled");
- QTest::newRow("product enabled, module validation error")
- << "delayed-error/validation.qbs" << true;
- QTest::newRow("product disabled, module validation error")
- << "delayed-error/validation.qbs" << false;
- QTest::newRow("product enabled, module not found")
- << "delayed-error/nonexisting.qbs" << true;
- QTest::newRow("product disabled, module not found")
- << "delayed-error/nonexisting.qbs" << false;
-}
-
-void qbs::Internal::TestLanguage::dependencyOnAllProfiles()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("dependencyOnAllProfiles.qbs"));
- Settings settings((QString()));
- TemporaryProfile p1("p1", &settings);
- p1.p.setValue("qbs.architecture", "arch1");
- TemporaryProfile p2("p2", &settings);
- p2.p.setValue("qbs.architecture", "arch2");
- QVariantMap overriddenValues;
- overriddenValues.insert("project.profile1", "p1");
- overriddenValues.insert("project.profile2", "p2");
- params.setOverriddenValues(overriddenValues);
- project = loader->loadProject(params);
- QVERIFY(project);
- QCOMPARE(project->products.count(), 3);
- const ResolvedProductConstPtr mainProduct = productsFromProject(project).value("main");
- QVERIFY(mainProduct);
- QCOMPARE(mainProduct->dependencies.count(), 2);
- foreach (const ResolvedProductConstPtr &p, mainProduct->dependencies) {
- QCOMPARE(p->name, QLatin1String("dep"));
- QVERIFY(p->profile == "p1" || p->profile == "p2");
- }
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::derivedSubProject()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("derived-sub-project/project.qbs"));
- const TopLevelProjectPtr project = loader->loadProject(params);
- QVERIFY(project);
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 1);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::defaultValue()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("defaultvalue/egon.qbs"));
- QFETCH(QString, prop1Value);
- QVariantMap overridden;
- if (!prop1Value.isEmpty())
- overridden.insert("modules.lower.prop1", prop1Value);
- params.setOverriddenValues(overridden);
- TopLevelProjectPtr project = loader->loadProject(params);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 2);
- const ResolvedProductPtr product = products.value("egon");
- QVERIFY(product);
- QStringList propertyName = QStringList() << "modules" << "lower" << "prop2";
- QVariant propertyValue = product->moduleProperties->property(propertyName);
- QFETCH(QVariant, expectedProp2Value);
- QCOMPARE(propertyValue, expectedProp2Value);
- propertyName = QStringList() << "modules" << "lower" << "listProp";
- propertyValue = product->moduleProperties->property(propertyName);
- QFETCH(QVariant, expectedListPropValue);
- QCOMPARE(propertyValue.toStringList(), expectedListPropValue.toStringList());
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::defaultValue_data()
-{
- QTest::addColumn<QString>("prop1Value");
- QTest::addColumn<QVariant>("expectedProp2Value");
- QTest::addColumn<QVariant>("expectedListPropValue");
- QTest::newRow("controlling property with random value") << "random" << QVariant("withoutBlubb")
- << QVariant(QStringList({"other"}));
- QTest::newRow("controlling property with blubb value") << "blubb" << QVariant("withBlubb")
- << QVariant(QStringList({"blubb", "other"}));
- QTest::newRow("controlling property with egon value") << "egon" << QVariant("withEgon")
- << QVariant(QStringList({"egon", "other"}));
- QTest::newRow("controlling property not overwritten") << "" << QVariant("withBlubb")
- << QVariant(QStringList({"blubb", "other"}));
-}
-
-void TestLanguage::environmentVariable()
-{
- bool exceptionCaught = false;
- try {
- // Create new environment:
- const QString varName = QLatin1String("PRODUCT_NAME");
- const QString productName = QLatin1String("MyApp") + QString::number(qrand());
- QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
- env.insert(varName, productName);
-
- QProcessEnvironment origEnv = defaultParameters.environment(); // store orig environment
-
- defaultParameters.setEnvironment(env);
- defaultParameters.setProjectFilePath(testProject("environmentvariable.qbs"));
- project = loader->loadProject(defaultParameters);
-
- defaultParameters.setEnvironment(origEnv); // reset environment
-
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value(productName);
- QVERIFY(product);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::erroneousFiles_data()
-{
- QTest::addColumn<QString>("errorMessage");
- QTest::newRow("unknown_module")
- << "Dependency 'neitherModuleNorProduct' not found";
- QTest::newRow("multiple_exports")
- << "Multiple Export items in one product are prohibited.";
- QTest::newRow("multiple_properties_in_subproject")
- << "Multiple instances of item 'Properties' found where at most one "
- "is allowed.";
- QTest::newRow("importloop1")
- << "Loop detected when importing";
- QTest::newRow("nonexistentouter")
- << "Can't find variable: outer";
- QTest::newRow("invalid_file")
- << "does not exist";
- QTest::newRow("invalid_property_type")
- << "Unknown type 'nonsense' in property declaration.";
- QTest::newRow("reserved_name_in_import")
- << "Cannot reuse the name of built-in extension 'TextFile'.";
- QTest::newRow("throw_in_property_binding")
- << "something is wrong";
- QTest::newRow("dependency_cycle")
- << "Cyclic dependencies detected.";
- QTest::newRow("dependency_cycle2")
- << "Cyclic dependencies detected.";
- QTest::newRow("dependency_cycle3")
- << "Cyclic dependencies detected.";
- QTest::newRow("dependency_cycle4")
- << "Cyclic dependencies detected.";
- QTest::newRow("references_cycle")
- << "Cycle detected while referencing file 'references_cycle.qbs'.";
- QTest::newRow("subproject_cycle")
- << "Cycle detected while loading subproject file 'subproject_cycle.qbs'.";
- QTest::newRow("invalid_stringlist_element")
- << "Element at index 1 of list property 'files' does not have string type.";
- QTest::newRow("undefined_stringlist_element")
- << "Element at index 1 of list property 'files' is undefined. String expected.";
- QTest::newRow("undeclared_item")
- << "Item 'cpp' is not declared.";
- QTest::newRow("undeclared_property_wrapper")
- << "Property 'doesntexist' is not declared.";
- QTest::newRow("undeclared_property_in_export_item")
- << "Property 'blubb' is not declared.";
- QTest::newRow("undeclared_property_in_export_item2")
- << "Item 'something' is not declared.";
- QTest::newRow("undeclared_property_in_export_item3")
- << "Property 'blubb' is not declared.";
- QTest::newRow("unknown_item_type")
- << "Unexpected item type 'Narf'";
- QTest::newRow("invalid_child_item_type")
- << "Items of type 'Project' cannot contain items of type 'Depends'.";
- QTest::newRow("conflicting_fileTagsFilter")
- << "Conflicting fileTagsFilter in Group items";
- QTest::newRow("duplicate_sources")
- << "Duplicate source file '.*main.cpp'"
- ".*duplicate_sources.qbs:4:12.*duplicate_sources.qbs:6:16.";
- QTest::newRow("duplicate_sources_wildcards")
- << "Duplicate source file '.*duplicate_sources_wildcards.qbs'"
- ".*duplicate_sources_wildcards.qbs:4:12"
- ".*duplicate_sources_wildcards.qbs:6:16.";
- QTest::newRow("oldQbsVersion")
- << "The project requires at least qbs version \\d+\\.\\d+.\\d+, "
- "but this is qbs version " QBS_VERSION ".";
- QTest::newRow("wrongQbsVersionFormat")
- << "The value '.*' of Project.minimumQbsVersion is not a valid version string.";
- QTest::newRow("properties-item-with-invalid-condition")
- << "TypeError: Result of expression 'cpp.nonexistingproperty'";
- QTest::newRow("misused-inherited-property") << "Binding to non-item property";
- QTest::newRow("undeclared_property_in_Properties_item") << "Item 'blubb' is not declared";
- QTest::newRow("same-module-prefix1") << "The name of module 'prefix1' is equal to the first "
- "component of the name of module 'prefix1.suffix'";
- QTest::newRow("same-module-prefix2") << "The name of module 'prefix2' is equal to the first "
- "component of the name of module 'prefix2.suffix'";
- QTest::newRow("conflicting-properties-in-export-items")
- << "Export item in inherited item redeclares property 'theProp' with different type.";
- QTest::newRow("invalid-property-option")
- << "PropertyOptions item refers to non-existing property 's0meProp'";
- QTest::newRow("missing-colon")
- << "Invalid item 'cpp.dynamicLibraries'. Did you mean to set a module property?";
- QTest::newRow("wrong-toplevel-item")
- << "wrong-toplevel-item.qbs:3:1.*The top-level item must be of type 'Project' or "
- "'Product', but it is of type 'Artifact'.";
- QTest::newRow("module-depends-on-product")
- << "module-with-product-dependency.qbs:4:5.*Modules cannot depend on products.";
- QTest::newRow("overwrite-inherited-readonly-property")
- << "overwrite-inherited-readonly-property.qbs"
- ":4:21.*Cannot set read-only property 'readOnlyString'.";
- QTest::newRow("overwrite-readonly-module-property")
- << "overwrite-readonly-module-property.qbs"
- ":5:30.*Cannot set read-only property 'readOnlyString'.";
-}
-
-void TestLanguage::erroneousFiles()
-{
- QFETCH(QString, errorMessage);
- QString fileName = QString::fromLocal8Bit(QTest::currentDataTag()) + QLatin1String(".qbs");
- try {
- defaultParameters.setProjectFilePath(testProject("/erroneous/") + fileName);
- loader->loadProject(defaultParameters);
- } catch (const ErrorInfo &e) {
- if (!e.toString().contains(QRegExp(errorMessage))) {
- qDebug() << "Message: " << e.toString();
- qDebug() << "Expected: " << errorMessage;
- QFAIL("Unexpected error message.");
- }
- return;
- }
- QEXPECT_FAIL("undeclared_property_in_Properties_item", "Too expensive to check", Continue);
- QVERIFY(!"No error thrown on invalid input.");
-}
-
-void TestLanguage::exports()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("exports.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 17);
- ResolvedProductPtr product;
- product = products.value("myapp");
- QVERIFY(product);
- QStringList propertyName = QStringList() << "modules" << "dummy" << "defines";
- QVariant propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYAPP" << "USE_MYLIB"
- << "USE_MYLIB2");
- propertyName = QStringList() << "modules" << "dummy" << "includePaths";
- QVariantList propertyValues = product->moduleProperties->property(propertyName).toList();
- QCOMPARE(propertyValues.count(), 3);
- QVERIFY(propertyValues.at(0).toString().endsWith("/app"));
- QVERIFY(propertyValues.at(1).toString().endsWith("/subdir/lib"));
- QVERIFY(propertyValues.at(2).toString().endsWith("/subdir2/lib"));
-
- QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(),
- QString("myapp"));
-
- product = products.value("mylib");
- QVERIFY(product);
- propertyName = QStringList() << "modules" << "dummy" << "defines";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYLIB");
-
- product = products.value("mylib2");
- QVERIFY(product);
- propertyName = QStringList() << "modules" << "dummy" << "defines";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYLIB2");
-
- product = products.value("A");
- QVERIFY(product);
- QVERIFY(product->dependencies.contains(products.value("B")));
- QVERIFY(product->dependencies.contains(products.value("C")));
- QVERIFY(product->dependencies.contains(products.value("D")));
- product = products.value("B");
- QVERIFY(product);
- QVERIFY(product->dependencies.isEmpty());
- product = products.value("C");
- QVERIFY(product);
- QVERIFY(product->dependencies.isEmpty());
- product = products.value("D");
- QVERIFY(product);
- QVERIFY(product->dependencies.isEmpty());
-
- product = products.value("myapp2");
- QVERIFY(product);
- propertyName = QStringList() << "modules" << "dummy" << "cFlags";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(), QStringList()
- << "BASE_PRODUCTWITHINHERITEDEXPORTITEM"
- << "PRODUCT_PRODUCTWITHINHERITEDEXPORTITEM");
- propertyName = QStringList() << "modules" << "dummy" << "cxxFlags";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(), QStringList() << "-bar");
- propertyName = QStringList() << "modules" << "dummy" << "defines";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(), QStringList() << "ABC");
- QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(),
- QString("myapp2"));
- QCOMPARE(product->moduleProperties->moduleProperty("dummy",
- "upperCaseProductName").toString(), QString("MYAPP2"));
-
- // Check whether we're returning incorrect cached values.
- product = products.value("myapp3");
- QVERIFY(product);
- QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(),
- QString("myapp3"));
- QCOMPARE(product->moduleProperties->moduleProperty("dummy",
- "upperCaseProductName").toString(), QString("MYAPP3"));
-
- // Verify we refer to the right "project" variable.
- product = products.value("sub p2");
- QVERIFY(product);
- QCOMPARE(product->moduleProperties->moduleProperty("dummy", "someString").toString(),
- QString("sub1"));
-
- product = products.value("libE");
- QVERIFY(product);
- propertyName = QStringList() << "modules" << "dummy" << "defines";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toStringList(),
- QStringList() << "LIBA" << "LIBB" << "LIBC" << "LIBD");
- propertyName = QStringList() << "modules" << "dummy" << "productName";
- propertyValue = product->moduleProperties->property(propertyName);
- QCOMPARE(propertyValue.toString(), QString("libE"));
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::fileContextProperties()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("filecontextproperties.qbs"));
- project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value("product1");
- QVERIFY(product);
- QVariantMap cfg = product->productProperties;
- QCOMPARE(cfg.value("narf").toString(), defaultParameters.projectFilePath());
- QString dirPath = QFileInfo(defaultParameters.projectFilePath()).absolutePath();
- QCOMPARE(cfg.value("zort").toString(), dirPath);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::getNativeSetting()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("getNativeSetting.qbs"));
- project = loader->loadProject(defaultParameters);
-
- QString expectedProductName;
- if (HostOsInfo::isMacosHost())
- expectedProductName = QLatin1String("Mac OS X");
- else if (HostOsInfo::isWindowsHost())
- expectedProductName = QLatin1String("Windows");
- else
- expectedProductName = QLatin1String("Unix");
-
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value(expectedProductName);
- QVERIFY(product);
- ResolvedProductPtr product2 = products.value(QLatin1String("fallback"));
- QVERIFY(product2);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::groupConditions_data()
-{
- QTest::addColumn<int>("groupCount");
- QTest::addColumn<QList<bool> >("groupEnabled");
- QTest::newRow("init") << 0 << QList<bool>();
- QTest::newRow("no_condition_no_group")
- << 1 << (QList<bool>() << true);
- QTest::newRow("no_condition")
- << 2 << (QList<bool>() << true << true);
- QTest::newRow("true_condition")
- << 2 << (QList<bool>() << true << true);
- QTest::newRow("false_condition")
- << 2 << (QList<bool>() << true << false);
- QTest::newRow("true_condition_from_product")
- << 2 << (QList<bool>() << true << true);
- QTest::newRow("true_condition_from_project")
- << 2 << (QList<bool>() << true << true);
- QTest::newRow("condition_accessing_module_property")
- << 2 << (QList<bool>() << true << false);
- QTest::newRow("cleanup") << 0 << QList<bool>();
-}
-
-void TestLanguage::groupConditions()
-{
- HANDLE_INIT_CLEANUP_DATATAGS("groupconditions.qbs");
- QFETCH(int, groupCount);
- QFETCH(QList<bool>, groupEnabled);
- QCOMPARE(groupCount, groupEnabled.count());
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
- ResolvedProductPtr product = products.value(productName);
- QVERIFY(product);
- QCOMPARE(product->name, productName);
- QCOMPARE(product->groups.count(), groupCount);
- for (int i = 0; i < groupCount; ++i) {
- if (product->groups.at(i)->enabled != groupEnabled.at(i)) {
- QFAIL(qPrintable(
- QString("groups.at(%1)->enabled != %2").arg(i).arg(groupEnabled.at(i))));
- }
- }
-}
-
-void TestLanguage::groupName()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("groupname.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 2);
-
- ResolvedProductPtr product = products.value("MyProduct");
- QVERIFY(product);
- QCOMPARE(product->groups.count(), 2);
- GroupConstPtr group = product->groups.at(0);
- QVERIFY(group);
- QCOMPARE(group->name, QString("MyProduct"));
- group = product->groups.at(1);
- QVERIFY(group);
- QCOMPARE(group->name, QString("MyProduct.MyGroup"));
-
- product = products.value("My2ndProduct");
- QVERIFY(product);
- QCOMPARE(product->groups.count(), 3);
- group = product->groups.at(0);
- QVERIFY(group);
- QCOMPARE(group->name, QString("My2ndProduct"));
- group = product->groups.at(1);
- QVERIFY(group);
- QCOMPARE(group->name, QString("My2ndProduct.MyGroup"));
- group = product->groups.at(2);
- QVERIFY(group);
- QCOMPARE(group->name, QString("Group 2"));
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::homeDirectory()
-{
- try {
- defaultParameters.setProjectFilePath(testProject("homeDirectory.qbs"));
- ResolvedProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 1);
-
- ResolvedProductPtr product = products.value("home");
- QVERIFY(product);
-
- QDir dir = QDir::home();
- QCOMPARE(product->productProperties.value("home").toString(), dir.path());
- QCOMPARE(product->productProperties.value("homeSlash").toString(), dir.path());
-
- dir.cdUp();
- QCOMPARE(product->productProperties.value("homeUp").toString(), dir.path());
-
- dir = QDir::home();
- QCOMPARE(product->productProperties.value("homeFile").toString(),
- dir.filePath("a"));
-
- QCOMPARE(product->productProperties.value("bogus1").toString(),
- FileInfo::resolvePath(product->sourceDirectory, QLatin1String("a~b")));
- QCOMPARE(product->productProperties.value("bogus2").toString(),
- FileInfo::resolvePath(product->sourceDirectory, QLatin1String("a/~/bb")));
- QCOMPARE(product->productProperties.value("user").toString(),
- FileInfo::resolvePath(product->sourceDirectory, QLatin1String("~foo/bar")));
- }
- catch (const ErrorInfo &e) {
- qDebug() << e.toString();
- }
-}
-
-void TestLanguage::identifierSearch_data()
-{
- QTest::addColumn<bool>("expectedHasNarf");
- QTest::addColumn<bool>("expectedHasZort");
- QTest::addColumn<QString>("sourceCode");
- QTest::newRow("no narf, no zort") << false << false << QString(
- "Product {\n"
- " name: {\n"
- " var foo = 'bar';\n"
- " console.info(foo);\n"
- " return foo;\n"
- " }\n"
- "}\n");
- QTest::newRow("narf, no zort") << true << false << QString(
- "Product {\n"
- " name: {\n"
- " var foo = 'zort';\n"
- " console.info(narf + foo);\n"
- " return foo;\n"
- " }\n"
- "}\n");
- QTest::newRow("no narf, zort") << false << true << QString(
- "Product {\n"
- " name: {\n"
- " var foo = 'narf';\n"
- " console.info(zort + foo);\n"
- " return foo;\n"
- " }\n"
- "}\n");
- QTest::newRow("narf, zort") << true << true << QString(
- "Product {\n"
- " name: {\n"
- " var foo = narf;\n"
- " foo = foo + zort;\n"
- " return foo;\n"
- " }\n"
- "}\n");
- QTest::newRow("2 narfs, 1 zort") << true << true << QString(
- "Product {\n"
- " name: {\n"
- " var foo = narf;\n"
- " foo = narf + foo + zort;\n"
- " return foo;\n"
- " }\n"
- "}\n");
-}
-
-void TestLanguage::identifierSearch()
-{
- QFETCH(bool, expectedHasNarf);
- QFETCH(bool, expectedHasZort);
- QFETCH(QString, sourceCode);
-
- bool hasNarf = !expectedHasNarf;
- bool hasZort = !expectedHasZort;
- IdentifierSearch isearch;
- isearch.add("narf", &hasNarf);
- isearch.add("zort", &hasZort);
-
- QbsQmlJS::Engine engine;
- QbsQmlJS::Lexer lexer(&engine);
- lexer.setCode(sourceCode, 1);
- QbsQmlJS::Parser parser(&engine);
- QVERIFY(parser.parse());
- QVERIFY(parser.ast());
- isearch.start(parser.ast());
- QCOMPARE(hasNarf, expectedHasNarf);
- QCOMPARE(hasZort, expectedHasZort);
-}
-
-void TestLanguage::idUsage()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("idusage.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 4);
- QVERIFY(products.contains("product1_1"));
- QVERIFY(products.contains("product2_2"));
- QVERIFY(products.contains("product3_3"));
- ResolvedProductPtr product4 = products.value("product4_4");
- QVERIFY(product4);
- QEXPECT_FAIL("", "QBS-1016", Continue);
- QCOMPARE(product4->productProperties.value("productName").toString(), product4->name);
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QVERIFY(!exceptionCaught);
-}
-
-void TestLanguage::idUniqueness()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("id-uniqueness.qbs"));
- loader->loadProject(defaultParameters);
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- const QList<ErrorItem> items = e.items();
- QCOMPARE(items.count(), 3);
- QCOMPARE(items.at(0).toString(), QString::fromUtf8("The id 'baseProduct' is not unique."));
- QVERIFY(items.at(1).toString().contains("id-uniqueness.qbs:6:5 First occurrence is here."));
- QVERIFY(items.at(2).toString().contains("id-uniqueness.qbs:9:5 Next occurrence is here."));
- }
- QVERIFY(exceptionCaught);
-}
-
-void TestLanguage::importCollection()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("import-collection/project.qbs"));
- const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- const ResolvedProductConstPtr product = products.value("da product");
- QCOMPARE(product->productProperties.value("targetName").toString(),
- QLatin1String("C1f1C1f2C2f1C2f2"));
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QVERIFY(!exceptionCaught);
-}
-
-void TestLanguage::invalidBindingInDisabledItem()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("invalidBindingInDisabledItem.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 2);
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QVERIFY(!exceptionCaught);
-}
-
-class JSSourceValueCreator
-{
- FileContextPtr m_fileContext;
- QList<QString *> m_strings;
-public:
- JSSourceValueCreator(const FileContextPtr &fileContext)
- : m_fileContext(fileContext)
- {
- }
-
- ~JSSourceValueCreator()
- {
- qDeleteAll(m_strings);
- }
-
- JSSourceValuePtr create(const QString &sourceCode)
- {
- JSSourceValuePtr value = JSSourceValue::create();
- value->setFile(m_fileContext);
- QString *str = new QString(sourceCode);
- m_strings += str;
- value->setSourceCode(QStringRef(str));
- return value;
- }
-};
-
-void TestLanguage::itemPrototype()
-{
- FileContextPtr fileContext = FileContext::create();
- fileContext->setFilePath("/dev/null");
- JSSourceValueCreator sourceValueCreator(fileContext);
- ItemPool pool;
- Item *proto = Item::create(&pool, ItemType::Product);
- proto->setProperty("x", sourceValueCreator.create("1"));
- proto->setProperty("y", sourceValueCreator.create("1"));
- Item *item = Item::create(&pool, ItemType::Product);
- item->setPrototype(proto);
- item->setProperty("y", sourceValueCreator.create("x + 1"));
- item->setProperty("z", sourceValueCreator.create("2"));
-
- Evaluator evaluator(m_engine, m_logger);
- QCOMPARE(evaluator.property(proto, "x").toVariant().toInt(), 1);
- QCOMPARE(evaluator.property(proto, "y").toVariant().toInt(), 1);
- QVERIFY(!evaluator.property(proto, "z").isValid());
- QCOMPARE(evaluator.property(item, "x").toVariant().toInt(), 1);
- QCOMPARE(evaluator.property(item, "y").toVariant().toInt(), 2);
- QCOMPARE(evaluator.property(item, "z").toVariant().toInt(), 2);
-}
-
-void TestLanguage::itemScope()
-{
- FileContextPtr fileContext = FileContext::create();
- fileContext->setFilePath("/dev/null");
- JSSourceValueCreator sourceValueCreator(fileContext);
- ItemPool pool;
- Item *scope1 = Item::create(&pool, ItemType::Scope);
- scope1->setProperty("x", sourceValueCreator.create("1"));
- Item *scope2 = Item::create(&pool, ItemType::Scope);
- scope2->setScope(scope1);
- scope2->setProperty("y", sourceValueCreator.create("x + 1"));
- Item *item = Item::create(&pool, ItemType::Scope);
- item->setScope(scope2);
- item->setProperty("z", sourceValueCreator.create("x + y"));
-
- Evaluator evaluator(m_engine, m_logger);
- QCOMPARE(evaluator.property(scope1, "x").toVariant().toInt(), 1);
- QCOMPARE(evaluator.property(scope2, "y").toVariant().toInt(), 2);
- QVERIFY(!evaluator.property(scope2, "x").isValid());
- QCOMPARE(evaluator.property(item, "z").toVariant().toInt(), 3);
-}
-
-void TestLanguage::jsExtensions()
-{
- QFile file(testProject("jsextensions.js"));
- QVERIFY(file.open(QFile::ReadOnly));
- QTextStream ts(&file);
- QString code = ts.readAll();
- QVERIFY(!code.isEmpty());
- QScriptValue evaluated = m_engine->evaluate(code, file.fileName(), 1);
- if (m_engine->hasErrorOrException(evaluated)) {
- qDebug() << m_engine->uncaughtExceptionBacktrace();
- QFAIL(qPrintable(m_engine->lastErrorString(evaluated)));
- }
-}
-
-void TestLanguage::jsImportUsedInMultipleScopes_data()
-{
- QTest::addColumn<QString>("buildVariant");
- QTest::addColumn<QString>("expectedProductName");
- QTest::newRow("debug") << QString("debug") << QString("MyProduct_debug");
- QTest::newRow("release") << QString("release") << QString("MyProduct");
-}
-
-void TestLanguage::jsImportUsedInMultipleScopes()
-{
- QFETCH(QString, buildVariant);
- QFETCH(QString, expectedProductName);
-
- bool exceptionCaught = false;
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("jsimportsinmultiplescopes.qbs"));
- params.setOverriddenValues({std::make_pair(QLatin1String("qbs.buildVariant"),
- buildVariant)});
- params.expandBuildConfiguration();
- TopLevelProjectPtr project = loader->loadProject(params);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 1);
- ResolvedProductPtr product = products.values().first();
- QVERIFY(product);
- QCOMPARE(product->name, expectedProductName);
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QVERIFY(!exceptionCaught);
-}
-
-void TestLanguage::moduleProperties_data()
-{
- QTest::addColumn<QString>("propertyName");
- QTest::addColumn<QVariant>("expectedValue");
- QTest::newRow("init") << QString() << QVariant();
- QTest::newRow("merge_lists")
- << "defines"
- << QVariant(QStringList() << "THE_PRODUCT" << "QT_CORE" << "QT_GUI" << "QT_NETWORK");
- QTest::newRow("merge_lists_and_values")
- << "defines"
- << QVariant(QStringList() << "THE_PRODUCT" << "QT_CORE" << "QT_GUI" << "QT_NETWORK");
- QTest::newRow("merge_lists_with_duplicates")
- << "cxxFlags"
- << QVariant(QStringList() << "-foo" << "BAR" << "-foo" << "BAZ");
- QTest::newRow("merge_lists_with_prototype_values")
- << "rpaths"
- << QVariant(QStringList() << "/opt/qt/lib" << "$ORIGIN");
- QTest::newRow("list_property_that_references_product")
- << "listProp"
- << QVariant(QStringList() << "x" << "123");
- QTest::newRow("list_property_depending_on_overridden_property")
- << "listProp2"
- << QVariant(QStringList() << "PRODUCT_STUFF" << "DEFAULT_STUFF" << "EXTRA_STUFF");
- QTest::newRow("overridden_list_property")
- << "listProp"
- << QVariant(QStringList() << "PRODUCT_STUFF");
- QTest::newRow("shadowed-list-property")
- << "defines"
- << QVariant(QStringList() << "MyProject" << "shadowed-list-property");
- QTest::newRow("shadowed-scalar-property")
- << "someString"
- << QVariant(QString("MyProject_shadowed-scalar-property"));
- QTest::newRow("cleanup") << QString() << QVariant();
-}
-
-void TestLanguage::moduleProperties()
-{
- HANDLE_INIT_CLEANUP_DATATAGS("moduleproperties.qbs");
- QFETCH(QString, propertyName);
- QFETCH(QVariant, expectedValue);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
- ResolvedProductPtr product = products.value(productName);
- QVERIFY(product);
- const QVariant value = product->moduleProperties->moduleProperty("dummy", propertyName);
- QCOMPARE(value, expectedValue);
-}
-
-void TestLanguage::modulePropertiesInGroups()
-{
- defaultParameters.setProjectFilePath(testProject("modulepropertiesingroups.qbs"));
- bool exceptionCaught = false;
- try {
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- const ResolvedProductPtr product = products.value("grouptest");
- QVERIFY(product);
- GroupConstPtr g1;
- GroupConstPtr g11;
- GroupConstPtr g12;
- GroupConstPtr g2;
- GroupConstPtr g21;
- GroupConstPtr g211;
- foreach (const GroupConstPtr &g, product->groups) {
- if (g->name == "g1")
- g1= g;
- else if (g->name == "g2")
- g2 = g;
- else if (g->name == "g1.1")
- g11 = g;
- else if (g->name == "g1.2")
- g12 = g;
- else if (g->name == "g2.1")
- g21 = g;
- else if (g->name == "g2.1.1")
- g211 = g;
- }
- QVERIFY(g1);
- QVERIFY(g2);
- QVERIFY(g11);
- QVERIFY(g12);
- QVERIFY(g21);
- QVERIFY(g211);
-
- const QVariantMap productProps = product->moduleProperties->value();
- const auto &productGmod1List1 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(productGmod1List1, QStringList() << "gmod1_list1_proto" << "gmod1_string_proto");
- const auto &productGmod1List2 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QCOMPARE(productGmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
- << "gmod1_list2_proto");
- const auto &productGmod1List3 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list3")
- .toStringList();
- QCOMPARE(productGmod1List3, QStringList() << "product" << "gmod1_string_proto");
- const int productP0 = moduleProperty(productProps, "gmod.gmod1", "p0").toInt();
- QCOMPARE(productP0, 1);
- const int productDepProp = moduleProperty(productProps, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(productDepProp, 0);
- const auto &productGmod2String = moduleProperty(productProps, "gmod2", "gmod2_string")
- .toString();
- QCOMPARE(productGmod2String, QString("gmod1_string_proto"));
- const auto &productGmod2List = moduleProperty(productProps, "gmod2", "gmod2_list")
- .toStringList();
- QCOMPARE(productGmod2List, QStringList() << "gmod1_string_proto" << "commonName_in_gmod1"
- << "gmod4_string_proto_gmod3_string_proto" << "gmod3_string_proto"
- << "gmod2_list_proto");
-
- const QVariantMap g1Props = g1->properties->value();
- const auto &g1Gmod1List1 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(g1Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1");
- const auto &g1Gmod1List2 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QCOMPARE(g1Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
- << "gmod1_list2_proto" << "g1");
- const auto &g1Gmod1List3 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list3")
- .toStringList();
- QCOMPARE(g1Gmod1List3, QStringList() << "product" << "g1");
- const int g1P0 = moduleProperty(g1Props, "gmod.gmod1", "p0").toInt();
- QCOMPARE(g1P0, 3);
- const int g1DepProp = moduleProperty(g1Props, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(g1DepProp, 1);
- const auto &g1Gmod2String = moduleProperty(g1Props, "gmod2", "gmod2_string").toString();
- QCOMPARE(g1Gmod2String, QString("g1"));
- const auto &g1Gmod2List = moduleProperty(g1Props, "gmod2", "gmod2_list")
- .toStringList();
- QCOMPARE(g1Gmod2List, QStringList() << "g1" << "commonName_in_gmod1" << "g1_gmod4_g1_gmod3"
- << "g1_gmod3" << "gmod2_list_proto");
-
- const QVariantMap g11Props = g11->properties->value();
- const auto &g11Gmod1List1 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(g11Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1.1");
- const auto &g11Gmod1List2 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QCOMPARE(g11Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
- << "gmod1_list2_proto" << "g1" << "g1.1");
- const auto &g11Gmod1List3 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list3")
- .toStringList();
- QCOMPARE(g11Gmod1List3, QStringList() << "product" << "g1.1");
- const int g11P0 = moduleProperty(g11Props, "gmod.gmod1", "p0").toInt();
- QCOMPARE(g11P0, 5);
- const int g11DepProp = moduleProperty(g11Props, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(g11DepProp, 2);
- const auto &g11Gmod2String = moduleProperty(g11Props, "gmod2", "gmod2_string").toString();
- QCOMPARE(g11Gmod2String, QString("g1.1"));
- const auto &g11Gmod2List = moduleProperty(g11Props, "gmod2", "gmod2_list")
- .toStringList();
- QCOMPARE(g11Gmod2List, QStringList() << "g1.1" << "commonName_in_gmod1"
- << "g1.1_gmod4_g1.1_gmod3" << "g1.1_gmod3" << "gmod2_list_proto");
-
- const QVariantMap g12Props = g12->properties->value();
- const auto &g12Gmod1List1 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(g12Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1.2");
- const auto &g12Gmod1List2 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QCOMPARE(g12Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
- << "gmod1_list2_proto" << "g1" << "g1.2");
- const auto &g12Gmod1List3 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list3")
- .toStringList();
- QCOMPARE(g12Gmod1List3, QStringList() << "product" << "g1.2");
- const int g12P0 = moduleProperty(g12Props, "gmod.gmod1", "p0").toInt();
- QCOMPARE(g12P0, 9);
- const int g12DepProp = moduleProperty(g12Props, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(g12DepProp, 1);
- const auto &g12Gmod2String = moduleProperty(g12Props, "gmod2", "gmod2_string").toString();
- QCOMPARE(g12Gmod2String, QString("g1.2"));
- const auto &g12Gmod2List = moduleProperty(g12Props, "gmod2", "gmod2_list")
- .toStringList();
- QCOMPARE(g12Gmod2List, QStringList() << "g1.2" << "commonName_in_gmod1"
- << "g1_gmod4_g1.2_gmod3" << "g1.2_gmod3" << "gmod2_list_proto");
-
- const QVariantMap g2Props = g2->properties->value();
- const auto &g2Gmod1List1 = moduleProperty(g2Props, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(g2Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2");
- const auto &g2Gmod1List2 = moduleProperty(g2Props, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QCOMPARE(g2Gmod1List2, QStringList() << "grouptest" << "g2" << "gmod1_list2_proto");
- const int g2P0 = moduleProperty(g2Props, "gmod.gmod1", "p0").toInt();
- QCOMPARE(g2P0, 6);
- const int g2DepProp = moduleProperty(g2Props, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(g2DepProp, 2);
- const auto &g2Gmod2String = moduleProperty(g2Props, "gmod2", "gmod2_string").toString();
- QCOMPARE(g2Gmod2String, QString("g2"));
- const auto &g2Gmod2List = moduleProperty(g2Props, "gmod2", "gmod2_list")
- .toStringList();
- QCOMPARE(g2Gmod2List, QStringList() << "g2" << "commonName_in_gmod1" << "g2_gmod4_g2_gmod3"
- << "g2_gmod3" << "gmod2_list_proto");
-
- const QVariantMap g21Props = g21->properties->value();
- const auto &g21Gmod1List1 = moduleProperty(g21Props, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(g21Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2");
- const auto &g21Gmod1List2 = moduleProperty(g21Props, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QEXPECT_FAIL(0, "no re-eval when no module props set", Continue);
- QCOMPARE(g21Gmod1List2, QStringList() << "grouptest" << "g2.1" << "gmod1_list2_proto");
- const int g21P0 = moduleProperty(g21Props, "gmod.gmod1", "p0").toInt();
- QCOMPARE(g21P0, 6);
- const int g21DepProp = moduleProperty(g21Props, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(g21DepProp, 2);
- const auto &g21Gmod2String = moduleProperty(g21Props, "gmod2", "gmod2_string").toString();
- QCOMPARE(g21Gmod2String, QString("g2"));
- const auto &g21Gmod2List = moduleProperty(g21Props, "gmod2", "gmod2_list")
- .toStringList();
- QEXPECT_FAIL(0, "no re-eval when no module props set", Continue);
- QCOMPARE(g21Gmod2List, QStringList() << "g2" << "commonName_in_gmod1"
- << "g2.1_gmod4_g2.1_gmod3" << "g2.1_gmod3" << "gmod2_list_proto");
-
- const QVariantMap g211Props = g211->properties->value();
- const auto &g211Gmod1List1 = moduleProperty(g211Props, "gmod.gmod1", "gmod1_list1")
- .toStringList();
- QCOMPARE(g211Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2");
- const auto &g211Gmod1List2 = moduleProperty(g211Props, "gmod.gmod1", "gmod1_list2")
- .toStringList();
- QCOMPARE(g211Gmod1List2, QStringList() << "g2.1.1");
- const int g211P0 = moduleProperty(g211Props, "gmod.gmod1", "p0").toInt();
- QCOMPARE(g211P0, 17);
- const int g211DepProp = moduleProperty(g211Props, "gmod.gmod1", "depProp").toInt();
- QCOMPARE(g211DepProp, 2);
- const auto &g211Gmod2String
- = moduleProperty(g211Props, "gmod2", "gmod2_string").toString();
- QCOMPARE(g211Gmod2String, QString("g2.1.1"));
- const auto &g211Gmod2List = moduleProperty(g211Props, "gmod2", "gmod2_list")
- .toStringList();
- QCOMPARE(g211Gmod2List, QStringList() << "g2.1.1" << "commonName_in_gmod1"
- << "g2.1.1_gmod4_g2.1.1_gmod3" << "g2.1.1_gmod3" << "gmod2_list_proto");
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::moduleScope()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("modulescope.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 1);
- ResolvedProductPtr product = products.value("product1");
- QVERIFY(product);
-
- auto intModuleValue = [product] (const QString &name) -> int
- {
- return product->moduleProperties->moduleProperty("scopemod", name).toInt();
- };
-
- QCOMPARE(intModuleValue("a"), 2); // overridden in module instance
- QCOMPARE(intModuleValue("b"), 1); // genuine
- QCOMPARE(intModuleValue("c"), 3); // genuine, dependent on overridden value
- QCOMPARE(intModuleValue("d"), 2); // genuine, dependent on genuine value
- QCOMPARE(intModuleValue("e"), 1); // genuine
- QCOMPARE(intModuleValue("f"), 2); // overridden
- QCOMPARE(intModuleValue("g"), 156); // overridden, dependent on product properties
- QCOMPARE(intModuleValue("h"), 158); // overridden, base dependent on product properties
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-
-}
-
-void TestLanguage::modules_data()
-{
- QTest::addColumn<QStringList>("expectedModulesInProduct");
- QTest::addColumn<QString>("expectedProductProperty");
- QTest::newRow("init") << QStringList();
- QTest::newRow("no_modules")
- << (QStringList() << "qbs")
- << QString();
- QTest::newRow("qt_core")
- << (QStringList() << "qbs" << "dummy" << "dummyqt.core")
- << QString("1.2.3");
- QTest::newRow("qt_gui")
- << (QStringList() << "qbs" << "dummy" << "dummyqt.core" << "dummyqt.gui")
- << QString("guiProperty");
- QTest::newRow("qt_gui_network")
- << (QStringList() << "qbs" << "dummy" << "dummyqt.core" << "dummyqt.gui"
- << "dummyqt.network")
- << QString("guiProperty,networkProperty");
- QTest::newRow("deep_module_name")
- << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy")
- << QString("abysmal");
- QTest::newRow("deep_module_name_submodule_syntax1")
- << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy")
- << QString("abysmal");
- QTest::newRow("deep_module_name_submodule_syntax2")
- << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy")
- << QString("abysmal");
- QTest::newRow("dummy_twice")
- << (QStringList() << "qbs" << "dummy")
- << QString();
- QTest::newRow("cleanup") << QStringList();
-}
-
-void TestLanguage::modules()
-{
- HANDLE_INIT_CLEANUP_DATATAGS("modules.qbs");
- QFETCH(QStringList, expectedModulesInProduct);
- QFETCH(QString, expectedProductProperty);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
- ResolvedProductPtr product = products.value(productName);
- QVERIFY(product);
- QCOMPARE(product->name, productName);
- QStringList modulesInProduct;
- foreach (ResolvedModuleConstPtr m, product->modules)
- modulesInProduct += m->name;
- modulesInProduct.sort();
- expectedModulesInProduct.sort();
- QCOMPARE(modulesInProduct, expectedModulesInProduct);
- QCOMPARE(product->productProperties.value("foo").toString(), expectedProductProperty);
-}
-
-void TestLanguage::nonRequiredProducts()
-{
- bool exceptionCaught = false;
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("non-required-products.qbs"));
- QFETCH(bool, subProjectEnabled);
- QFETCH(bool, dependeeEnabled);
- QVariantMap overriddenValues;
- if (!subProjectEnabled)
- overriddenValues.insert("projects.subproject.condition", false);
- else if (!dependeeEnabled)
- overriddenValues.insert("products.dependee.condition", false);
- params.setOverriddenValues(overriddenValues);
- const TopLevelProjectPtr project = loader->loadProject(params);
- QVERIFY(project);
- const auto products = productsFromProject(project);
- QCOMPARE(products.count(), 4 + !!subProjectEnabled);
- const ResolvedProductConstPtr dependee = products.value("dependee");
- QCOMPARE(subProjectEnabled, !dependee.isNull());
- if (dependee)
- QCOMPARE(dependeeEnabled, dependee->enabled);
- const ResolvedProductConstPtr depender = products.value("depender");
- QVERIFY(depender);
- const QStringList defines = depender->moduleProperties->moduleProperty("dummy", "defines")
- .toStringList();
- QCOMPARE(subProjectEnabled && dependeeEnabled, defines.contains("WITH_DEPENDEE"));
-
- for (const auto &name : std::vector<const char *>({ "p3", "p2", "p1"})) {
- const ResolvedProductConstPtr &product = products.value(name);
- QVERIFY2(product, name);
- QVERIFY2(!product->enabled, name);
- }
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::nonRequiredProducts_data()
-{
- QTest::addColumn<bool>("subProjectEnabled");
- QTest::addColumn<bool>("dependeeEnabled");
- QTest::newRow("dependee enabled") << true << true;
- QTest::newRow("dependee disabled") << true << false;
- QTest::newRow("sub project disabled") << false << true;
-}
-
-void TestLanguage::outerInGroup()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("outerInGroup.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 1);
- ResolvedProductPtr product = products.value("OuterInGroup");
- QVERIFY(product);
- QCOMPARE(product->groups.count(), 2);
- GroupPtr group = product->groups.at(0);
- QVERIFY(group);
- QCOMPARE(group->name, product->name);
- QCOMPARE(group->files.count(), 1);
- SourceArtifactConstPtr artifact = group->files.first();
- QVariant installDir = artifact->properties->qbsPropertyValue("installDir");
- QCOMPARE(installDir.toString(), QString("/somewhere"));
- group = product->groups.at(1);
- QVERIFY(group);
- QCOMPARE(group->name, QString("Special Group"));
- QCOMPARE(group->files.count(), 1);
- artifact = group->files.first();
- installDir = artifact->properties->qbsPropertyValue("installDir");
- QCOMPARE(installDir.toString(), QString("/somewhere/else"));
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::pathProperties()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("pathproperties.qbs"));
- project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value("product1");
- QVERIFY(product);
- QString projectFileDir = QFileInfo(defaultParameters.projectFilePath()).absolutePath();
- const QVariantMap productProps = product->productProperties;
- QCOMPARE(productProps.value("projectFileDir").toString(), projectFileDir);
- QStringList filesInProjectFileDir = QStringList()
- << FileInfo::resolvePath(projectFileDir, "aboutdialog.h")
- << FileInfo::resolvePath(projectFileDir, "aboutdialog.cpp");
- QCOMPARE(productProps.value("filesInProjectFileDir").toStringList(), filesInProjectFileDir);
- QStringList includePaths = product->moduleProperties->property(
- QStringList() << "modules" << "dummy" << "includePaths").toStringList();
- QCOMPARE(includePaths, QStringList() << projectFileDir);
- QCOMPARE(productProps.value("base_fileInProductDir").toString(),
- FileInfo::resolvePath(projectFileDir, QLatin1String("foo")));
- QCOMPARE(productProps.value("base_fileInBaseProductDir").toString(),
- FileInfo::resolvePath(projectFileDir, QLatin1String("subdir/bar")));
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::profileValuesAndOverriddenValues()
-{
- bool exceptionCaught = false;
- try {
- Settings settings((QString()));
- TemporaryProfile tp(QLatin1String("tst_lang_profile"), &settings);
- Profile profile = tp.p;
- profile.setValue("dummy.defines", "IN_PROFILE");
- profile.setValue("dummy.cFlags", "IN_PROFILE");
- profile.setValue("dummy.cxxFlags", "IN_PROFILE");
- profile.setValue("qbs.architecture", "x86");
- SetupProjectParameters parameters = defaultParameters;
- parameters.setTopLevelProfile(profile.name());
- QVariantMap overriddenValues;
- overriddenValues.insert("modules.dummy.cFlags", "OVERRIDDEN");
- parameters.setOverriddenValues(overriddenValues);
- parameters.setProjectFilePath(testProject("profilevaluesandoverriddenvalues.qbs"));
- parameters.expandBuildConfiguration();
- project = loader->loadProject(parameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product = products.value("product1");
- QVERIFY(product);
- QVariantList values;
- values = product->moduleProperties->moduleProperty("dummy", "cxxFlags").toList();
- QCOMPARE(values.length(), 1);
- QCOMPARE(values.first().toString(), QString("IN_PROFILE"));
- values = product->moduleProperties->moduleProperty("dummy", "defines").toList();
- QCOMPARE(values, QVariantList() << QLatin1String("IN_FILE") << QLatin1String("IN_PROFILE"));
- values = product->moduleProperties->moduleProperty("dummy", "cFlags").toList();
- QCOMPARE(values.length(), 1);
- QCOMPARE(values.first().toString(), QString("OVERRIDDEN"));
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::productConditions()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("productconditions.qbs"));
- TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 6);
- ResolvedProductPtr product;
- product = products.value("product_no_condition");
- QVERIFY(product);
- QVERIFY(product->enabled);
-
- product = products.value("product_true_condition");
- QVERIFY(product);
- QVERIFY(product->enabled);
-
- product = products.value("product_condition_dependent_of_module");
- QVERIFY(product);
- QVERIFY(product->enabled);
-
- product = products.value("product_false_condition");
- QVERIFY(product);
- QVERIFY(!product->enabled);
-
- product = products.value("product_probe_condition_false");
- QVERIFY(product);
- QVERIFY(!product->enabled);
-
- product = products.value("product_probe_condition_true");
- QVERIFY(product);
- QVERIFY(product->enabled);
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::productDirectories()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("productdirectories.qbs"));
- ResolvedProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 1);
- ResolvedProductPtr product;
- product = products.value("MyApp");
- QVERIFY(product);
- const QVariantMap config = product->productProperties;
- QCOMPARE(config.value(QLatin1String("buildDirectory")).toString(),
- product->buildDirectory());
- QCOMPARE(config.value(QLatin1String("sourceDirectory")).toString(), testDataDir());
- }
- catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::propertiesBlocks_data()
-{
- QTest::addColumn<QString>("propertyName");
- QTest::addColumn<QStringList>("expectedValues");
- QTest::addColumn<QString>("expectedStringValue");
-
- QTest::newRow("init") << QString() << QStringList() << QString();
- QTest::newRow("property_overwrite")
- << QString("dummy.defines")
- << QStringList("OVERWRITTEN")
- << QString();
- QTest::newRow("property_set_indirect")
- << QString("dummy.cFlags")
- << QStringList("VAL")
- << QString();
- QTest::newRow("property_overwrite_no_outer")
- << QString("dummy.defines")
- << QStringList("OVERWRITTEN")
- << QString();
- QTest::newRow("property_append_to_outer")
- << QString("dummy.defines")
- << (QStringList() << QString("ONE") << QString("TWO"))
- << QString();
-
- QTest::newRow("multiple_exclusive_properties")
- << QString("dummy.defines")
- << QStringList("OVERWRITTEN")
- << QString();
- QTest::newRow("multiple_exclusive_properties_no_outer")
- << QString("dummy.defines")
- << QStringList("OVERWRITTEN")
- << QString();
- QTest::newRow("multiple_exclusive_properties_append_to_outer")
- << QString("dummy.defines")
- << (QStringList() << QString("ONE") << QString("TWO"))
- << QString();
-
- QTest::newRow("condition_refers_to_product_property")
- << QString("dummy.defines")
- << QStringList("OVERWRITTEN")
- << QString("OVERWRITTEN");
- QTest::newRow("condition_refers_to_project_property")
- << QString("dummy.defines")
- << QStringList("OVERWRITTEN")
- << QString("OVERWRITTEN");
-
- QTest::newRow("ambiguous_properties")
- << QString("dummy.defines")
- << (QStringList() << QString("ONE") << QString("TWO"))
- << QString();
- QTest::newRow("inheritance_overwrite_in_subitem")
- << QString("dummy.defines")
- << (QStringList() << QString("OVERWRITTEN_IN_SUBITEM"))
- << QString();
- QTest::newRow("inheritance_retain_base1")
- << QString("dummy.defines")
- << (QStringList() << QString("BASE") << QString("SUB"))
- << QString();
- QTest::newRow("inheritance_retain_base2")
- << QString("dummy.defines")
- << (QStringList() << QString("BASE") << QString("SUB"))
- << QString();
- QTest::newRow("inheritance_retain_base3")
- << QString("dummy.defines")
- << (QStringList() << QString("BASE") << QString("SUB"))
- << QString();
- QTest::newRow("inheritance_retain_base4")
- << QString("dummy.defines")
- << (QStringList() << QString("BASE"))
- << QString();
- QTest::newRow("inheritance_condition_in_subitem1")
- << QString("dummy.defines")
- << (QStringList() << QString("SOMETHING") << QString("SUB"))
- << QString();
- QTest::newRow("inheritance_condition_in_subitem2")
- << QString("dummy.defines")
- << (QStringList() << QString("SOMETHING"))
- << QString();
- QTest::newRow("condition_references_id")
- << QString("dummy.defines")
- << (QStringList() << QString("OVERWRITTEN"))
- << QString();
- QTest::newRow("using_derived_Properties_item") << "dummy.defines"
- << (QStringList() << "string from MyProperties") << QString();
- QTest::newRow("conditional-depends")
- << QString("dummy.defines")
- << QStringList()
- << QString();
- QTest::newRow("cleanup") << QString() << QStringList() << QString();
-}
-
-void TestLanguage::propertiesBlocks()
-{
- HANDLE_INIT_CLEANUP_DATATAGS("propertiesblocks.qbs");
- QFETCH(QString, propertyName);
- QFETCH(QStringList, expectedValues);
- QFETCH(QString, expectedStringValue);
- QVERIFY(project);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
- ResolvedProductPtr product = products.value(productName);
- QVERIFY(product);
- QCOMPARE(product->name, productName);
- QVariant v = productPropertyValue(product, propertyName);
- QCOMPARE(v.toStringList(), expectedValues);
- if (!expectedStringValue.isEmpty()) {
- v = productPropertyValue(product, "someString");
- QCOMPARE(v.toString(), expectedStringValue);
- }
-}
-
-void TestLanguage::propertiesBlockInGroup()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(testProject("properties-block-in-group.qbs"));
- const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- QCOMPARE(project->allProducts().count(), 1);
- const ResolvedProductConstPtr product = project->allProducts().first();
- const auto groupIt = std::find_if(product->groups.constBegin(), product->groups.constEnd(),
- [](const GroupConstPtr &g) { return g->name == "the group"; });
- QVERIFY(groupIt != product->groups.constEnd());
- const QVariantMap propertyMap = (*groupIt)->properties->value();
- const QVariantList value = moduleProperty(propertyMap, "dummy", "defines").toList();
- QStringList stringListValue;
- std::transform(value.constBegin(), value.constEnd(), std::back_inserter(stringListValue),
- [](const QVariant &v) { return v.toString(); });
- QCOMPARE(stringListValue, QStringList() << "BASEDEF" << "FEATURE_ENABLED");
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::propertiesItemInModule()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(
- testProject("properties-item-in-module.qbs"));
- const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 2);
- for (const ResolvedProductConstPtr &p : products) {
- QCOMPARE(p->moduleProperties->moduleProperty("dummy", "productName").toString(),
- p->name);
- }
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::qbsPropertiesInProjectCondition()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(
- testProject("qbs-properties-in-project-condition.qbs"));
- const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 0);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::relaxedErrorMode()
-{
- QFETCH(bool, strictMode);
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("relaxed-error-mode/relaxed-error-mode.qbs"));
- params.setProductErrorMode(strictMode ? ErrorHandlingMode::Strict
- : ErrorHandlingMode::Relaxed);
- const TopLevelProjectPtr project = loader->loadProject(params);
- QVERIFY(!strictMode);
- const auto productMap = productsFromProject(project);
- const ResolvedProductConstPtr brokenProduct = productMap.value("broken");
- QVERIFY(!brokenProduct->enabled);
- QVERIFY(brokenProduct->location.isValid());
- QCOMPARE(brokenProduct->allFiles().count(), 0);
- const ResolvedProductConstPtr dependerRequired = productMap.value("depender required");
- QVERIFY(!dependerRequired->enabled);
- QVERIFY(dependerRequired->location.isValid());
- QCOMPARE(dependerRequired->allFiles().count(), 1);
- const ResolvedProductConstPtr dependerNonRequired
- = productMap.value("depender nonrequired");
- QVERIFY(dependerNonRequired->enabled);
- QCOMPARE(dependerNonRequired->allFiles().count(), 1);
- const ResolvedProductConstPtr recursiveDepender = productMap.value("recursive depender");
- QVERIFY(!recursiveDepender->enabled);
- QVERIFY(recursiveDepender->location.isValid());
- QCOMPARE(recursiveDepender->allFiles().count(), 1);
- const ResolvedProductConstPtr missingFile = productMap.value("missing file");
- QVERIFY(missingFile->enabled);
- QCOMPARE(missingFile->groups.count(), 1);
- QVERIFY(missingFile->groups.first()->enabled);
- QCOMPARE(missingFile->groups.first()->allFiles().count(), 2);
- const ResolvedProductConstPtr fine = productMap.value("fine");
- QVERIFY(fine->enabled);
- QCOMPARE(fine->allFiles().count(), 1);
- } catch (const ErrorInfo &e) {
- QVERIFY2(strictMode, qPrintable(e.toString()));
- }
-}
-
-void TestLanguage::relaxedErrorMode_data()
-{
- QTest::addColumn<bool>("strictMode");
-
- QTest::newRow("strict mode") << true;
- QTest::newRow("relaxed mode") << false;
-}
-
-void TestLanguage::requiredAndNonRequiredDependencies()
-{
- QFETCH(QString, projectFile);
- QFETCH(bool, exceptionExpected);
- try {
- SetupProjectParameters params = defaultParameters;
- const QString projectFilePath = "required-and-nonrequired-dependencies/" + projectFile;
- params.setProjectFilePath(testProject(projectFilePath.toLocal8Bit()));
- const TopLevelProjectConstPtr project = loader->loadProject(params);
- QVERIFY(project);
- QVERIFY(!exceptionExpected);
- } catch (const ErrorInfo &e) {
- QVERIFY(exceptionExpected);
- QVERIFY2(e.toString().contains("validation error!"), qPrintable(e.toString()));
- }
-}
-
-void TestLanguage::requiredAndNonRequiredDependencies_data()
-{
- QTest::addColumn<QString>("projectFile");
- QTest::addColumn<bool>("exceptionExpected");
-
- QTest::newRow("same file") << "direct-dependencies.qbs" << true;
- QTest::newRow("dependency via module") << "dependency-via-module.qbs" << true;
- QTest::newRow("dependency via export") << "dependency-via-export.qbs" << true;
- QTest::newRow("more indirection") << "complicated.qbs" << true;
- QTest::newRow("required chain (module)") << "required-chain-module.qbs" << false;
- QTest::newRow("required chain (export)") << "required-chain-export.qbs" << false;
- QTest::newRow("required chain (export indirect)") << "required-chain-export-indirect.qbs"
- << false;
-}
-
-void TestLanguage::throwingProbe()
-{
- QFETCH(bool, enableProbe);
- try {
- SetupProjectParameters params = defaultParameters;
- params.setProjectFilePath(testProject("throwing-probe.qbs"));
- QVariantMap properties;
- properties.insert(QLatin1String("products.theProduct.enableProbe"), enableProbe);
- params.setOverriddenValues(properties);
- const TopLevelProjectPtr project = loader->loadProject(params);
- QVERIFY(project);
- QVERIFY(!enableProbe);
- } catch (const ErrorInfo &e) {
- QVERIFY2(enableProbe, qPrintable(e.toString()));
- }
-}
-
-void TestLanguage::throwingProbe_data()
-{
- QTest::addColumn<bool>("enableProbe");
-
- QTest::newRow("enabled probe") << true;
- QTest::newRow("disabled probe") << false;
-}
-
-void TestLanguage::qualifiedId()
-{
- QString str = "foo.bar.baz";
- QualifiedId id = QualifiedId::fromString(str);
- QCOMPARE(id.count(), 3);
- QCOMPARE(id.toString(), str);
-
- id = QualifiedId("blubb.di.blubb"); // c'tor does not split
- QCOMPARE(id.count(), 1);
-
- QList<QualifiedId> ids;
- ids << QualifiedId::fromString("a")
- << QualifiedId::fromString("a.a")
- << QualifiedId::fromString("b")
- << QualifiedId::fromString("c.a")
- << QualifiedId::fromString("c.b.a")
- << QualifiedId::fromString("c.c");
- QList<QualifiedId> sorted = ids;
- std::sort(sorted.begin(), sorted.end());
- QCOMPARE(ids, sorted);
-}
-
-void TestLanguage::recursiveProductDependencies()
-{
- bool exceptionCaught = false;
- try {
- defaultParameters.setProjectFilePath(
- testProject("recursive-dependencies/recursive-dependencies.qbs"));
- const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- QCOMPARE(products.count(), 4);
- const ResolvedProductConstPtr p1 = products.value("p1");
- QVERIFY(p1);
- const ResolvedProductConstPtr p2 = products.value("p2");
- QVERIFY(p2);
- const ResolvedProductPtr p3 = products.value("p3");
- QVERIFY(p3);
- const ResolvedProductPtr p4 = products.value("p4");
- QVERIFY(p4);
- QVERIFY(p1->dependencies == Set<ResolvedProductPtr>() << p3 << p4);
- QVERIFY(p2->dependencies == Set<ResolvedProductPtr>() << p3 << p4);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-void TestLanguage::fileTags_data()
-{
- QTest::addColumn<int>("numberOfGroups");
- QTest::addColumn<QStringList>("expectedFileTags");
-
- QTest::newRow("init") << 0 << QStringList();
- QTest::newRow("filetagger_project_scope") << 1 << (QStringList() << "cpp");
- QTest::newRow("filetagger_product_scope") << 1 << (QStringList() << "asm");
- QTest::newRow("filetagger_static_pattern") << 1 << (QStringList() << "yellow");
- QTest::newRow("unknown_file_tag") << 1 << (QStringList() << "unknown-file-tag");
- QTest::newRow("set_file_tag_via_group") << 2 << (QStringList() << "c++");
- QTest::newRow("override_file_tag_via_group") << 2 << (QStringList() << "c++");
- QTest::newRow("add_file_tag_via_group") << 2 << (QStringList() << "cpp" << "zzz");
- QTest::newRow("cleanup") << 0 << QStringList();
-}
-
-void TestLanguage::fileTags()
-{
- HANDLE_INIT_CLEANUP_DATATAGS("filetags.qbs");
- QFETCH(int, numberOfGroups);
- QFETCH(QStringList, expectedFileTags);
- QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- ResolvedProductPtr product;
- const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
- QVERIFY(product = products.value(productName));
- QCOMPARE(product->groups.count(), numberOfGroups);
- GroupPtr group = product->groups.last();
- QVERIFY(group);
- QCOMPARE(group->files.count(), 1);
- SourceArtifactConstPtr sourceFile = group->files.first();
- QStringList fileTags = sourceFile->fileTags.toStringList();
- fileTags.sort();
- QCOMPARE(fileTags, expectedFileTags);
-}
-
-void TestLanguage::wildcards_data()
-{
- QTest::addColumn<bool>("useGroup");
- QTest::addColumn<QStringList>("filesToCreate");
- QTest::addColumn<QString>("projectFileSubDir");
- QTest::addColumn<QString>("prefix");
- QTest::addColumn<QStringList>("patterns");
- QTest::addColumn<QStringList>("excludePatterns");
- QTest::addColumn<QStringList>("expected");
-
- const bool useGroup = true;
- for (int i = 0; i <= 1; ++i) {
- const bool useGroup = i;
- const QByteArray dataTagSuffix = useGroup ? " group" : " nogroup";
- QTest::newRow(QByteArray("simple 1") + dataTagSuffix)
- << useGroup
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "*.h")
- << QStringList()
- << (QStringList() << "foo.h" << "bar.h");
- QTest::newRow(QByteArray("simple 2") + dataTagSuffix)
- << useGroup
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "foo.*")
- << QStringList()
- << (QStringList() << "foo.h" << "foo.cpp");
- QTest::newRow(QByteArray("simple 3") + dataTagSuffix)
- << useGroup
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "*.h" << "*.cpp")
- << QStringList()
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp");
- QTest::newRow(QByteArray("exclude 1") + dataTagSuffix)
- << useGroup
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "*.h" << "*.cpp")
- << (QStringList() << "bar*")
- << (QStringList() << "foo.h" << "foo.cpp");
- QTest::newRow(QByteArray("exclude 2") + dataTagSuffix)
- << useGroup
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "*")
- << (QStringList() << "*.qbs")
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp");
- QTest::newRow(QByteArray("non-recursive") + dataTagSuffix)
- << useGroup
- << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "a/*")
- << QStringList()
- << (QStringList() << "a/foo.h" << "a/foo.cpp");
- QTest::newRow(QByteArray("absolute paths") + dataTagSuffix)
- << useGroup
- << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
- << QString()
- << QString()
- << (QStringList() << m_wildcardsTestDirPath + "/?oo.*")
- << QStringList()
- << (QStringList() << "foo.h" << "foo.cpp");
- QTest::newRow(QByteArray("relative paths with dotdot") + dataTagSuffix)
- << useGroup
- << (QStringList() << "bar.h" << "bar.cpp")
- << QString("TheLaughingLlama")
- << QString()
- << (QStringList() << "../bar.*")
- << QStringList()
- << (QStringList() << "bar.h" << "bar.cpp");
- }
- QTest::newRow(QByteArray("recursive 1"))
- << useGroup
- << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "a/**")
- << QStringList()
- << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp");
- QTest::newRow(QByteArray("recursive 2"))
- << useGroup
- << (QStringList()
- << "d/1.h" << "b/d/1.h" << "b/c/d/1.h"
- << "d/e/1.h" << "b/d/e/1.h" << "b/c/d/e/1.h"
- << "a/d/1.h" << "a/b/d/1.h" << "a/b/c/d/1.h"
- << "a/d/e/1.h" << "a/b/d/e/1.h" << "a/b/c/d/e/1.h"
- << "a/d/1.cpp" << "a/b/d/1.cpp" << "a/b/c/d/1.h"
- << "a/d/e/1.cpp" << "a/b/d/e/1.cpp" << "a/b/c/d/e/1.cpp")
- << QString()
- << QString()
- << (QStringList() << "a/**/d/*.h")
- << QStringList()
- << (QStringList() << "a/d/1.h" << "a/b/d/1.h" << "a/b/c/d/1.h");
- QTest::newRow(QByteArray("recursive 3"))
- << useGroup
- << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp")
- << QString()
- << QString()
- << (QStringList() << "a/**/**/**")
- << QStringList()
- << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp");
- QTest::newRow(QByteArray("prefix"))
- << useGroup
- << (QStringList() << "subdir/foo.h" << "subdir/foo.cpp" << "subdir/bar.h"
- << "subdir/bar.cpp")
- << QString()
- << QString("subdir/")
- << (QStringList() << "*.h")
- << QStringList()
- << (QStringList() << "subdir/foo.h" << "subdir/bar.h");
- QTest::newRow(QByteArray("non-existing absolute path"))
- << useGroup
- << QStringList()
- << QString()
- << QString("/dir")
- << (QStringList() << "*.whatever")
- << QStringList()
- << QStringList();
-}
-
-void TestLanguage::wildcards()
-{
- QFETCH(bool, useGroup);
- QFETCH(QStringList, filesToCreate);
- QFETCH(QString, projectFileSubDir);
- QFETCH(QString, prefix);
- QFETCH(QStringList, patterns);
- QFETCH(QStringList, excludePatterns);
- QFETCH(QStringList, expected);
-
- // create test directory
- QDir::setCurrent(QDir::tempPath());
- {
- QString errorMessage;
- if (QFile::exists(m_wildcardsTestDirPath)) {
- if (!removeDirectoryWithContents(m_wildcardsTestDirPath, &errorMessage)) {
- qDebug() << errorMessage;
- QVERIFY2(false, "removeDirectoryWithContents failed");
- }
- }
- QVERIFY(QDir().mkdir(m_wildcardsTestDirPath));
- }
-
- // create project file
- const QString groupName = "Keks";
- QString dataTag = QString::fromLocal8Bit(QTest::currentDataTag());
- dataTag.replace(' ', '_');
- if (!projectFileSubDir.isEmpty()) {
- if (!projectFileSubDir.startsWith('/'))
- projectFileSubDir.prepend('/');
- if (projectFileSubDir.endsWith('/'))
- projectFileSubDir.chop(1);
- QVERIFY(QDir().mkpath(m_wildcardsTestDirPath + projectFileSubDir));
- }
- const QString projectFilePath = m_wildcardsTestDirPath + projectFileSubDir + "/test_" + dataTag
- + ".qbs";
- {
- QFile projectFile(projectFilePath);
- QVERIFY(projectFile.open(QIODevice::WriteOnly));
- QTextStream s(&projectFile);
- s << "import qbs.base 1.0" << endl << endl
- << "Application {" << endl
- << " name: \"MyProduct\"" << endl;
- if (useGroup) {
- s << " Group {" << endl
- << " name: " << toJSLiteral(groupName) << endl;
- }
- if (!prefix.isEmpty())
- s << " prefix: " << toJSLiteral(prefix) << endl;
- if (!patterns.isEmpty())
- s << " files: " << toJSLiteral(patterns) << endl;
- if (!excludePatterns.isEmpty())
- s << " excludeFiles: " << toJSLiteral(excludePatterns) << endl;
- if (useGroup)
- s << " }" << endl;
- s << "}" << endl << endl;
- }
-
- // create files
- foreach (QString filePath, filesToCreate) {
- filePath.prepend(m_wildcardsTestDirPath + '/');
- QFileInfo fi(filePath);
- if (!QDir(fi.path()).exists())
- QVERIFY(QDir().mkpath(fi.path()));
- QFile file(filePath);
- QVERIFY(file.open(QIODevice::WriteOnly));
- }
-
- // read the project
- bool exceptionCaught = false;
- ResolvedProductPtr product;
- try {
- defaultParameters.setProjectFilePath(projectFilePath);
- project = loader->loadProject(defaultParameters);
- QVERIFY(project);
- const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
- product = products.value("MyProduct");
- QVERIFY(product);
- GroupPtr group;
- if (useGroup) {
- QCOMPARE(product->groups.count(), HostOsInfo::isMacosHost() ? 3 : 2);
- foreach (const GroupPtr &rg, product->groups) {
- if (rg->name == groupName) {
- group = rg;
- break;
- }
- }
- } else {
- QCOMPARE(product->groups.count(), HostOsInfo::isMacosHost() ? 2 : 1);
- group = product->groups.first();
- }
- QVERIFY(group);
- QCOMPARE(group->files.count(), 0);
- SourceWildCards::Ptr wildcards = group->wildcards;
- QVERIFY(wildcards);
- QStringList actualFilePaths;
- foreach (const SourceArtifactConstPtr &artifact, wildcards->files) {
- QString str = artifact->absoluteFilePath;
- int idx = str.indexOf(m_wildcardsTestDirPath);
- if (idx != -1)
- str.remove(0, idx + m_wildcardsTestDirPath.count() + 1);
- actualFilePaths << str;
- }
- actualFilePaths.sort();
- expected.sort();
- QCOMPARE(actualFilePaths, expected);
- } catch (const ErrorInfo &e) {
- exceptionCaught = true;
- qDebug() << e.toString();
- }
- QCOMPARE(exceptionCaught, false);
-}
-
-} // namespace Internal
-} // namespace qbs
diff --git a/src/lib/corelib/language/value.cpp b/src/lib/corelib/language/value.cpp
index f1ddd770a..1b73ccf17 100644
--- a/src/lib/corelib/language/value.cpp
+++ b/src/lib/corelib/language/value.cpp
@@ -82,7 +82,7 @@ ValuePtr Value::next() const
void Value::setNext(const ValuePtr &next)
{
- QBS_ASSERT(next.data() != this, return);
+ QBS_ASSERT(next.get() != this, return);
m_next = next;
}
@@ -101,8 +101,9 @@ JSSourceValue::JSSourceValue(const JSSourceValue &other) : Value(other)
m_column = other.m_column;
m_file = other.m_file;
m_flags = other.m_flags;
- m_baseValue = other.m_baseValue ? other.m_baseValue->clone().staticCast<JSSourceValue>()
- : JSSourceValuePtr();
+ m_baseValue = other.m_baseValue
+ ? std::static_pointer_cast<JSSourceValue>(other.m_baseValue->clone())
+ : JSSourceValuePtr();
for (const Alternative &otherAlt : qAsConst(other.m_alternatives))
m_alternatives << otherAlt.clone();
}
diff --git a/src/lib/corelib/language/value.h b/src/lib/corelib/language/value.h
index c38095697..6b0c98dc9 100644
--- a/src/lib/corelib/language/value.h
+++ b/src/lib/corelib/language/value.h
@@ -109,7 +109,7 @@ class JSSourceValue : public Value
Q_DECLARE_FLAGS(Flags, Flag)
public:
- static JSSourceValuePtr create(bool createdByPropertiesBlock = false);
+ static JSSourceValuePtr QBS_AUTOTEST_EXPORT create(bool createdByPropertiesBlock = false);
~JSSourceValue();
void apply(ValueHandler *handler) { handler->handle(this); }
@@ -147,7 +147,7 @@ public:
Alternative clone() const
{
return Alternative(condition, overrideListProperties,
- value->clone().staticCast<JSSourceValue>());
+ std::static_pointer_cast<JSSourceValue>(value->clone()));
}
QString condition;
diff --git a/src/lib/corelib/parser/qmljsastvisitor_p.h b/src/lib/corelib/parser/qmljsastvisitor_p.h
index f0eff5ce7..aa4471c6b 100644
--- a/src/lib/corelib/parser/qmljsastvisitor_p.h
+++ b/src/lib/corelib/parser/qmljsastvisitor_p.h
@@ -53,11 +53,12 @@
#include "qmljsastfwd_p.h"
#include "qmljsglobal_p.h"
+#include <tools/qbs_export.h>
namespace QbsQmlJS {
namespace AST {
-class QML_PARSER_EXPORT Visitor
+class QML_PARSER_EXPORT QBS_AUTOTEST_EXPORT Visitor
{
public:
Visitor();
diff --git a/src/lib/corelib/parser/qmljsengine_p.h b/src/lib/corelib/parser/qmljsengine_p.h
index be88b917b..2fdd60b30 100644
--- a/src/lib/corelib/parser/qmljsengine_p.h
+++ b/src/lib/corelib/parser/qmljsengine_p.h
@@ -54,6 +54,7 @@
#include "qmljsglobal_p.h"
#include "qmljsastfwd_p.h"
#include "qmljsmemorypool_p.h"
+#include <tools/qbs_export.h>
#include <QtCore/qstring.h>
@@ -87,7 +88,7 @@ public:
QString message;
};
-class QML_PARSER_EXPORT Engine
+class QML_PARSER_EXPORT QBS_AUTOTEST_EXPORT Engine
{
Lexer *_lexer;
Directives *_directives;
diff --git a/src/lib/corelib/parser/qmljslexer_p.h b/src/lib/corelib/parser/qmljslexer_p.h
index 7a77ddabe..e0d61b226 100644
--- a/src/lib/corelib/parser/qmljslexer_p.h
+++ b/src/lib/corelib/parser/qmljslexer_p.h
@@ -53,6 +53,7 @@
#include "qmljsglobal_p.h"
#include "qmljsgrammar_p.h"
+#include <tools/qbs_export.h>
#include <QtCore/qstring.h>
namespace QbsQmlJS {
@@ -81,7 +82,7 @@ public:
}
};
-class QML_PARSER_EXPORT Lexer: public QmlJSGrammar
+class QML_PARSER_EXPORT QBS_AUTOTEST_EXPORT Lexer: public QmlJSGrammar
{
public:
enum {
diff --git a/src/lib/corelib/parser/qmljsparser_p.h b/src/lib/corelib/parser/qmljsparser_p.h
index 93c096367..38fc1f5ce 100644
--- a/src/lib/corelib/parser/qmljsparser_p.h
+++ b/src/lib/corelib/parser/qmljsparser_p.h
@@ -61,6 +61,7 @@
#include "qmljsgrammar_p.h"
#include "qmljsast_p.h"
#include "qmljsengine_p.h"
+#include <tools/qbs_export.h>
#include <QtCore/qlist.h>
#include <QtCore/qstring.h>
@@ -69,7 +70,7 @@ namespace QbsQmlJS {
class Engine;
-class QML_PARSER_EXPORT Parser: protected QmlJSGrammar
+class QML_PARSER_EXPORT QBS_AUTOTEST_EXPORT Parser: protected QmlJSGrammar
{
public:
union Value {
diff --git a/src/lib/corelib/tools/architectures.cpp b/src/lib/corelib/tools/architectures.cpp
index ce9a0f28f..2dbb73832 100644
--- a/src/lib/corelib/tools/architectures.cpp
+++ b/src/lib/corelib/tools/architectures.cpp
@@ -46,6 +46,7 @@
namespace qbs {
QString canonicalTargetArchitecture(const QString &architecture,
+ const QString &endianness,
const QString &vendor,
const QString &system,
const QString &abi)
@@ -77,6 +78,19 @@ QString canonicalTargetArchitecture(const QString &architecture,
return QStringLiteral("i386");
}
+ if (arch == QStringLiteral("mips") || arch == QStringLiteral("mips64")) {
+ if (endianness == QStringLiteral("big"))
+ return arch + QStringLiteral("eb");
+ if (endianness == QStringLiteral("little"))
+ return arch + QStringLiteral("el");
+ }
+
+ if (arch == QStringLiteral("ppc"))
+ return QStringLiteral("powerpc");
+
+ if (arch == QStringLiteral("ppc64") && endianness == QStringLiteral("little"))
+ return arch + QStringLiteral("le");
+
return arch;
}
@@ -115,11 +129,18 @@ QString canonicalArchitecture(const QString &architecture)
<< QLatin1String("powerpc"));
archMap.insert(QLatin1String("ppc64"), QStringList()
- << QLatin1String("powerpc64"));
-
- archMap.insert(QLatin1String("ppc64le"), QStringList()
+ << QLatin1String("ppc64le")
+ << QLatin1String("powerpc64")
<< QLatin1String("powerpc64le"));
+ archMap.insert(QLatin1String("mips"), QStringList()
+ << QLatin1String("mipseb")
+ << QLatin1String("mipsel"));
+
+ archMap.insert(QLatin1String("mips64"), QStringList()
+ << QLatin1String("mips64eb")
+ << QLatin1String("mips64el"));
+
QMapIterator<QString, QStringList> i(archMap);
while (i.hasNext()) {
i.next();
diff --git a/src/lib/corelib/tools/architectures.h b/src/lib/corelib/tools/architectures.h
index ef4ebb537..8b5d2a65d 100644
--- a/src/lib/corelib/tools/architectures.h
+++ b/src/lib/corelib/tools/architectures.h
@@ -44,6 +44,7 @@
namespace qbs {
QBS_EXPORT QString canonicalTargetArchitecture(const QString &architecture,
+ const QString &endianness,
const QString &vendor,
const QString &system,
const QString &abi);
diff --git a/src/lib/corelib/tools/buildgraphlocker.cpp b/src/lib/corelib/tools/buildgraphlocker.cpp
index eec88bcfe..82b4f0201 100644
--- a/src/lib/corelib/tools/buildgraphlocker.cpp
+++ b/src/lib/corelib/tools/buildgraphlocker.cpp
@@ -84,7 +84,7 @@ BuildGraphLocker::BuildGraphLocker(const QString &buildGraphFilePath, const Logg
m_lockFile.setStaleLockTime(0);
int attemptsToGetInfo = 0;
do {
- if (observer->canceled())
+ if (observer && observer->canceled())
break;
tryCreateBuildDirectory(buildDir, buildGraphFilePath);
if (m_lockFile.tryLock(250))
@@ -135,7 +135,7 @@ void BuildGraphLocker::rememberCreatedDirectories(const QString &buildDir)
{
QString parentDir = buildDir;
while (!QFileInfo::exists(parentDir)) {
- m_createdParentDirs.enqueue(parentDir);
+ m_createdParentDirs.push(parentDir);
parentDir = QDir::cleanPath(parentDir + QLatin1String("/.."));
}
}
@@ -143,8 +143,9 @@ void BuildGraphLocker::rememberCreatedDirectories(const QString &buildDir)
void BuildGraphLocker::removeEmptyCreatedDirectories()
{
QDir root = QDir::root();
- while (!m_createdParentDirs.isEmpty()) {
- const QString parentDir = m_createdParentDirs.dequeue();
+ while (!m_createdParentDirs.empty()) {
+ const QString parentDir = m_createdParentDirs.front();
+ m_createdParentDirs.pop();
QDirIterator it(parentDir, QDir::AllEntries | QDir::NoDotAndDotDot | QDir::System,
QDirIterator::Subdirectories);
if (it.hasNext())
diff --git a/src/lib/corelib/tools/buildgraphlocker.h b/src/lib/corelib/tools/buildgraphlocker.h
index 390ccfa98..b73ff7237 100644
--- a/src/lib/corelib/tools/buildgraphlocker.h
+++ b/src/lib/corelib/tools/buildgraphlocker.h
@@ -43,9 +43,10 @@
#include <logging/logger.h>
#include <QtCore/qlockfile.h>
-#include <QtCore/qqueue.h>
#include <QtCore/qstring.h>
+#include <queue>
+
namespace qbs {
namespace Internal {
@@ -64,7 +65,7 @@ private:
QLockFile m_lockFile;
Logger m_logger;
- QQueue<QString> m_createdParentDirs;
+ std::queue<QString> m_createdParentDirs;
};
} // namespace Internal
diff --git a/src/lib/corelib/tools/error.cpp b/src/lib/corelib/tools/error.cpp
index 6ebee2879..719b985f1 100644
--- a/src/lib/corelib/tools/error.cpp
+++ b/src/lib/corelib/tools/error.cpp
@@ -42,12 +42,12 @@
#include "persistence.h"
#include "qttools.h"
-#include <QtCore/qregularexpression.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qstringlist.h>
#include <algorithm>
#include <functional>
+#include <regex>
namespace qbs {
@@ -181,13 +181,15 @@ ErrorInfo::ErrorInfo(const QString &description, const QStringList &backtrace)
{
append(description);
for (const QString &traceLine : backtrace) {
- QRegularExpression regexp(
- QStringLiteral("^(?<message>.+) at (?<file>.+):(?<line>\\-?[0-9]+)$"));
- QRegularExpressionMatch match = regexp.match(traceLine);
- if (match.hasMatch()) {
- const CodeLocation location(match.captured(QStringLiteral("file")),
- match.captured(QStringLiteral("line")).toInt());
- appendBacktrace(match.captured(QStringLiteral("message")), location);
+ static const std::regex regexp("^(.+) at (.+):(\\-?[0-9]+)$");
+ std::smatch match;
+ const std::string tl = traceLine.toStdString();
+ if (std::regex_match(tl, match, regexp)) {
+ const QString message = QString::fromStdString(match[1]),
+ file = QString::fromStdString(match[2]),
+ line = QString::fromStdString(match[3]);
+ const CodeLocation location(file, line.toInt());
+ appendBacktrace(message, location);
}
}
}
diff --git a/src/lib/corelib/tools/fileinfo.h b/src/lib/corelib/tools/fileinfo.h
index 1655e37d9..71d178265 100644
--- a/src/lib/corelib/tools/fileinfo.h
+++ b/src/lib/corelib/tools/fileinfo.h
@@ -55,7 +55,7 @@ QT_FORWARD_DECLARE_CLASS(QFileInfo)
namespace qbs {
namespace Internal {
-class FileInfo
+class QBS_AUTOTEST_EXPORT FileInfo
{
public:
FileInfo(const QString &fileName);
diff --git a/src/lib/corelib/tools/filesaver.h b/src/lib/corelib/tools/filesaver.h
index 38228ed0c..07ba5ac25 100644
--- a/src/lib/corelib/tools/filesaver.h
+++ b/src/lib/corelib/tools/filesaver.h
@@ -40,6 +40,8 @@
#ifndef FILESAVER_H
#define FILESAVER_H
+#include "qbs_export.h"
+
#include <QtCore/qbuffer.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qscopedpointer.h>
@@ -51,7 +53,7 @@ namespace Internal {
/*!
* QSaveFile wrapper which doesn't update the target file if the contents are unchanged.
*/
-class FileSaver {
+class QBS_EXPORT FileSaver {
public:
FileSaver(const QString &filePath, bool overwriteIfUnchanged = false);
diff --git a/src/lib/corelib/tools/filetime.h b/src/lib/corelib/tools/filetime.h
index 30687833f..c9b98e9c0 100644
--- a/src/lib/corelib/tools/filetime.h
+++ b/src/lib/corelib/tools/filetime.h
@@ -60,7 +60,7 @@
namespace qbs {
namespace Internal {
-class FileTime
+class QBS_AUTOTEST_EXPORT FileTime
{
public:
#if defined(Q_OS_UNIX)
diff --git a/src/lib/corelib/tools/id.h b/src/lib/corelib/tools/id.h
index 334acc686..aedecd66e 100644
--- a/src/lib/corelib/tools/id.h
+++ b/src/lib/corelib/tools/id.h
@@ -40,6 +40,8 @@
#ifndef QBS_TOOLS_ID_H
#define QBS_TOOLS_ID_H
+#include "qbs_export.h"
+
#include <QtCore/qmetatype.h>
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
@@ -47,7 +49,7 @@
namespace qbs {
namespace Internal {
-class Id
+class QBS_AUTOTEST_EXPORT Id
{
public:
enum { IdsPerPlugin = 10000, ReservedPlugins = 1000 };
diff --git a/src/lib/corelib/tools/launcherpackets.cpp b/src/lib/corelib/tools/launcherpackets.cpp
index 9d000a5cc..aaa931a49 100644
--- a/src/lib/corelib/tools/launcherpackets.cpp
+++ b/src/lib/corelib/tools/launcherpackets.cpp
@@ -41,7 +41,6 @@
#include <QtCore/qbytearray.h>
#include <QtCore/qcoreapplication.h>
-#include <QtCore/qendian.h>
namespace qbs {
namespace Internal {
diff --git a/src/lib/corelib/tools/launchersocket.cpp b/src/lib/corelib/tools/launchersocket.cpp
index d72ce278b..948fbca4f 100644
--- a/src/lib/corelib/tools/launchersocket.cpp
+++ b/src/lib/corelib/tools/launchersocket.cpp
@@ -61,8 +61,8 @@ void LauncherSocket::sendData(const QByteArray &data)
if (!isReady())
return;
std::lock_guard<std::mutex> locker(m_requestsMutex);
- m_requests << data;
- if (m_requests.count() == 1)
+ m_requests.push_back(data);
+ if (m_requests.size() == 1)
QTimer::singleShot(0, this, &LauncherSocket::handleRequests);
}
diff --git a/src/lib/corelib/tools/launchersocket.h b/src/lib/corelib/tools/launchersocket.h
index 3b4dc985e..a9a1af800 100644
--- a/src/lib/corelib/tools/launchersocket.h
+++ b/src/lib/corelib/tools/launchersocket.h
@@ -42,10 +42,10 @@
#include "launcherpackets.h"
-#include <QtCore/qbytearraylist.h>
#include <QtCore/qobject.h>
#include <mutex>
+#include <vector>
QT_BEGIN_NAMESPACE
class QLocalSocket;
@@ -83,7 +83,7 @@ private:
QLocalSocket *m_socket = nullptr;
PacketParser m_packetParser;
- QByteArrayList m_requests;
+ std::vector<QByteArray> m_requests;
std::mutex m_requestsMutex;
};
diff --git a/src/lib/corelib/tools/persistence.cpp b/src/lib/corelib/tools/persistence.cpp
index 0d7b1a3a8..538ac6b6a 100644
--- a/src/lib/corelib/tools/persistence.cpp
+++ b/src/lib/corelib/tools/persistence.cpp
@@ -50,7 +50,7 @@
namespace qbs {
namespace Internal {
-static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-99";
+static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-102";
PersistentPool::PersistentPool(Logger &logger) : m_logger(logger)
{
diff --git a/src/lib/corelib/tools/persistence.h b/src/lib/corelib/tools/persistence.h
index c94c1b963..5ae37eab6 100644
--- a/src/lib/corelib/tools/persistence.h
+++ b/src/lib/corelib/tools/persistence.h
@@ -46,10 +46,10 @@
#include <QtCore/qdatastream.h>
#include <QtCore/qflags.h>
#include <QtCore/qprocess.h>
-#include <QtCore/qsharedpointer.h>
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
+#include <memory>
#include <type_traits>
#include <vector>
@@ -99,7 +99,7 @@ private:
typedef int PersistentObjectId;
template <typename T> T *idLoad();
- template <class T> QSharedPointer<T> idLoadS();
+ template <class T> std::shared_ptr<T> idLoadS();
void storePersistentObject(const PersistentObject *object);
@@ -113,7 +113,7 @@ private:
QDataStream m_stream;
HeadData m_headData;
std::vector<PersistentObject *> m_loadedRaw;
- std::vector<QSharedPointer<PersistentObject> > m_loaded;
+ std::vector<std::shared_ptr<PersistentObject> > m_loaded;
QHash<const PersistentObject *, int> m_storageIndices;
PersistentObjectId m_lastStoredObjectId;
@@ -148,23 +148,23 @@ template <typename T> inline T *PersistentPool::idLoad()
return t;
}
-template <class T> inline QSharedPointer<T> PersistentPool::idLoadS()
+template <class T> inline std::shared_ptr<T> PersistentPool::idLoadS()
{
PersistentObjectId id;
m_stream >> id;
if (id < 0)
- return QSharedPointer<T>();
+ return std::shared_ptr<T>();
if (id < static_cast<PersistentObjectId>(m_loaded.size())) {
- QSharedPointer<PersistentObject> obj = m_loaded.at(id);
- return obj.dynamicCast<T>();
+ std::shared_ptr<PersistentObject> obj = m_loaded.at(id);
+ return std::dynamic_pointer_cast<T>(obj);
}
m_loaded.resize(id + 1);
- const QSharedPointer<T> t = T::create();
+ const std::shared_ptr<T> t = T::create();
m_loaded[id] = t;
- PersistentObject * const po = t.data();
+ PersistentObject * const po = t.get();
po->load(*this);
return t;
}
@@ -199,14 +199,14 @@ template<typename T> struct IsPersistentObject
};
template<typename T>
-struct PersistentPool::Helper<QSharedPointer<T>,
+struct PersistentPool::Helper<std::shared_ptr<T>,
typename std::enable_if<IsPersistentObject<T>::value>::type>
{
- static void store(const QSharedPointer<T> &value, PersistentPool *pool)
+ static void store(const std::shared_ptr<T> &value, PersistentPool *pool)
{
- pool->store(value.data());
+ pool->store(value.get());
}
- static void load(QSharedPointer<T> &value, PersistentPool *pool)
+ static void load(std::shared_ptr<T> &value, PersistentPool *pool)
{
value = pool->idLoadS<typename std::remove_const<T>::type>();
}
diff --git a/src/lib/corelib/tools/preferences.cpp b/src/lib/corelib/tools/preferences.cpp
index a21dbdaf4..2516cd960 100644
--- a/src/lib/corelib/tools/preferences.cpp
+++ b/src/lib/corelib/tools/preferences.cpp
@@ -56,6 +56,11 @@ Preferences::Preferences(Settings *settings, const QString &profileName)
{
}
+Preferences::Preferences(Settings *settings, const QVariantMap &profileContents)
+ : m_settings(settings), m_profileContents(profileContents)
+{
+}
+
/*!
* \brief Returns true <=> colored output should be used for printing messages.
@@ -120,7 +125,8 @@ QStringList Preferences::pluginPaths(const QString &baseDir) const
QVariant Preferences::getPreference(const QString &key, const QVariant &defaultValue) const
{
- const QString fullKey = QLatin1String("preferences.") + key;
+ static const QString keyPrefix = QLatin1String("preferences");
+ const QString fullKey = keyPrefix + QLatin1Char('.') + key;
if (!m_profile.isEmpty()) {
QVariant value = Profile(m_profile, m_settings).value(fullKey);
if (value.isValid()) {
@@ -130,6 +136,13 @@ QVariant Preferences::getPreference(const QString &key, const QVariant &defaultV
}
}
+ QVariant value = m_profileContents.value(keyPrefix).toMap().value(key);
+ if (value.isValid()) {
+ if (key == QLatin1String("qbsSearchPaths")) // Merge with top-level value
+ value = value.toStringList() + m_settings->value(fullKey).toStringList();
+ return value;
+ }
+
return m_settings->value(fullKey, defaultValue);
}
diff --git a/src/lib/corelib/tools/preferences.h b/src/lib/corelib/tools/preferences.h
index 042a15a9e..98468b78c 100644
--- a/src/lib/corelib/tools/preferences.h
+++ b/src/lib/corelib/tools/preferences.h
@@ -53,6 +53,7 @@ class QBS_EXPORT Preferences
{
public:
explicit Preferences(Settings *settings, const QString &profileName = QString());
+ Preferences(Settings *settings, const QVariantMap &profileContents);
bool useColoredOutput() const;
int jobs() const;
@@ -68,6 +69,7 @@ private:
Settings *m_settings;
QString m_profile;
+ QVariantMap m_profileContents;
};
} // namespace qbs
diff --git a/src/lib/corelib/tools/processutils.h b/src/lib/corelib/tools/processutils.h
index 5a210289d..14ab13812 100644
--- a/src/lib/corelib/tools/processutils.h
+++ b/src/lib/corelib/tools/processutils.h
@@ -40,13 +40,15 @@
#ifndef QBS_PROCESSUTILS_H
#define QBS_PROCESSUTILS_H
+#include <tools/qbs_export.h>
+
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
namespace qbs {
namespace Internal {
-QString processNameByPid(qint64 pid);
+QString QBS_AUTOTEST_EXPORT processNameByPid(qint64 pid);
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/tools/projectgeneratormanager.cpp b/src/lib/corelib/tools/projectgeneratormanager.cpp
index a417be5e2..3991adfb9 100644
--- a/src/lib/corelib/tools/projectgeneratormanager.cpp
+++ b/src/lib/corelib/tools/projectgeneratormanager.cpp
@@ -47,10 +47,6 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdiriterator.h>
-#include <QtCore/qlibrary.h>
-
-#include "generators/clangcompilationdb/clangcompilationdbgenerator.h"
-#include "generators/visualstudio/visualstudiogenerator.h"
namespace qbs {
@@ -58,10 +54,6 @@ using namespace Internal;
ProjectGeneratorManager::~ProjectGeneratorManager()
{
- for (QLibrary * const lib : qAsConst(m_libs)) {
- lib->unload();
- delete lib;
- }
}
ProjectGeneratorManager *ProjectGeneratorManager::instance()
@@ -72,12 +64,6 @@ ProjectGeneratorManager *ProjectGeneratorManager::instance()
ProjectGeneratorManager::ProjectGeneratorManager()
{
- std::vector<QSharedPointer<ProjectGenerator> > generators;
- generators.push_back(QSharedPointer<ClangCompilationDatabaseGenerator>::create());
- const auto vsGenerators = qbs::VisualStudioGenerator::createGeneratorList();
- std::copy(vsGenerators.cbegin(), vsGenerators.cend(), std::back_inserter(generators));
- for (QSharedPointer<ProjectGenerator> generator : qAsConst(generators))
- m_generators[generator->generatorName()] = generator;
}
QStringList ProjectGeneratorManager::loadedGeneratorNames()
@@ -85,9 +71,15 @@ QStringList ProjectGeneratorManager::loadedGeneratorNames()
return instance()->m_generators.keys();
}
-QSharedPointer<ProjectGenerator> ProjectGeneratorManager::findGenerator(const QString &generatorName)
+std::shared_ptr<ProjectGenerator> ProjectGeneratorManager::findGenerator(const QString &generatorName)
{
return instance()->m_generators.value(generatorName);
}
+void ProjectGeneratorManager::registerGenerator(const std::shared_ptr<ProjectGenerator> &generator)
+{
+ if (!findGenerator(generator->generatorName()))
+ instance()->m_generators.insert(generator->generatorName(), generator);
+}
+
} // namespace qbs
diff --git a/src/lib/corelib/tools/projectgeneratormanager.h b/src/lib/corelib/tools/projectgeneratormanager.h
index 611ee3d2b..d9f997fa7 100644
--- a/src/lib/corelib/tools/projectgeneratormanager.h
+++ b/src/lib/corelib/tools/projectgeneratormanager.h
@@ -45,14 +45,9 @@
#include <generators/generator.h>
#include <QtCore/qmap.h>
-#include <QtCore/qsharedpointer.h>
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
-QT_BEGIN_NAMESPACE
-class QLibrary;
-QT_END_NAMESPACE
-
namespace qbs {
class ProjectGenerator;
namespace Internal {
@@ -65,14 +60,14 @@ public:
~ProjectGeneratorManager();
static ProjectGeneratorManager *instance();
static QStringList loadedGeneratorNames();
- static QSharedPointer<ProjectGenerator> findGenerator(const QString &generatorName);
+ static std::shared_ptr<ProjectGenerator> findGenerator(const QString &generatorName);
+ static void registerGenerator(const std::shared_ptr<ProjectGenerator> &generator);
private:
ProjectGeneratorManager();
private:
- QList<QLibrary *> m_libs;
- QMap<QString, QSharedPointer<ProjectGenerator> > m_generators;
+ QMap<QString, std::shared_ptr<ProjectGenerator> > m_generators;
};
} // namespace qbs
diff --git a/src/lib/corelib/tools/qbs_export.h b/src/lib/corelib/tools/qbs_export.h
index 5bb28f98d..a92150c63 100644
--- a/src/lib/corelib/tools/qbs_export.h
+++ b/src/lib/corelib/tools/qbs_export.h
@@ -43,11 +43,22 @@
#ifdef QBS_STATIC_LIB
# define QBS_EXPORT
+# define QBS_AUTOTEST_EXPORT
#else
# ifdef QBS_LIBRARY
# define QBS_EXPORT Q_DECL_EXPORT
+# ifdef QBS_ENABLE_UNIT_TESTS
+# define QBS_AUTOTEST_EXPORT Q_DECL_EXPORT
+# else
+# define QBS_AUTOTEST_EXPORT
+# endif
# else
# define QBS_EXPORT Q_DECL_IMPORT
+# ifdef QBS_ENABLE_UNIT_TESTS
+# define QBS_AUTOTEST_EXPORT Q_DECL_IMPORT
+# else
+# define QBS_AUTOTEST_EXPORT
+# endif
# endif
#endif
diff --git a/src/lib/corelib/tools/qbspluginmanager.cpp b/src/lib/corelib/tools/qbspluginmanager.cpp
new file mode 100644
index 000000000..9635f2bac
--- /dev/null
+++ b/src/lib/corelib/tools/qbspluginmanager.cpp
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbspluginmanager.h"
+
+#include <logging/logger.h>
+#include <logging/translator.h>
+#include <tools/hostosinfo.h>
+#include <tools/qbsassert.h>
+#include <tools/qttools.h>
+
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qlibrary.h>
+
+#include <mutex>
+
+namespace qbs {
+namespace Internal {
+
+QbsPluginManager::QbsPluginManager()
+{
+}
+
+QbsPluginManager::~QbsPluginManager()
+{
+ unloadStaticPlugins();
+
+ for (QLibrary * const lib : qAsConst(m_libs)) {
+ QbsPluginUnloadFunction unload = reinterpret_cast<QbsPluginUnloadFunction>(
+ lib->resolve("QbsPluginUnload"));
+ if (unload)
+ unload();
+ lib->unload();
+ delete lib;
+ }
+}
+
+QbsPluginManager *QbsPluginManager::instance()
+{
+ static QbsPluginManager instance;
+ return &instance;
+}
+
+void QbsPluginManager::registerStaticPlugin(QbsPluginLoadFunction load,
+ QbsPluginUnloadFunction unload)
+{
+ auto begin = m_staticPlugins.cbegin(), end = m_staticPlugins.cend();
+ if (std::find_if(begin, end, [&load](const QbsPlugin &p) { return p.load == load; }) == end)
+ m_staticPlugins.push_back(QbsPlugin { load, unload, false });
+}
+
+void QbsPluginManager::loadStaticPlugins()
+{
+ for (const auto &plugin : m_staticPlugins) {
+ if (!plugin.loaded && plugin.load)
+ plugin.load();
+ }
+}
+
+void QbsPluginManager::unloadStaticPlugins()
+{
+ for (auto &plugin : m_staticPlugins) {
+ if (plugin.loaded && plugin.unload)
+ plugin.unload();
+ }
+
+ m_staticPlugins.clear();
+}
+
+void QbsPluginManager::loadPlugins(const QStringList &pluginPaths, const Logger &logger)
+{
+ QStringList filters;
+
+ if (HostOsInfo::isWindowsHost())
+ filters << QLatin1String("*.dll");
+ else if (HostOsInfo::isMacosHost())
+ filters << QLatin1String("*.dylib");
+ else
+ filters << QLatin1String("*.so");
+
+ for (const QString &pluginPath : pluginPaths) {
+ logger.qbsTrace() << QString::fromLatin1("plugin manager: loading plugins from '%1'.")
+ .arg(QDir::toNativeSeparators(pluginPath));
+ QDirIterator it(pluginPath, filters, QDir::Files);
+ while (it.hasNext()) {
+ const QString fileName = it.next();
+ QScopedPointer<QLibrary> lib(new QLibrary(fileName));
+ if (!lib->load()) {
+ logger.qbsWarning() << Tr::tr("plugin manager: Cannot load plugin '%1': %2")
+ .arg(QDir::toNativeSeparators(fileName), lib->errorString());
+ continue;
+ }
+
+ QbsPluginLoadFunction load = reinterpret_cast<QbsPluginLoadFunction>(
+ lib->resolve("QbsPluginLoad"));
+ if (load) {
+ load();
+ logger.qbsTrace() << QString::fromLatin1("pluginmanager: plugin '%1' loaded.")
+ .arg(QDir::toNativeSeparators(fileName));
+ m_libs.push_back(lib.take());
+ } else {
+ logger.qbsWarning() << Tr::tr("plugin manager: not a qbs plugin");
+ }
+ }
+ }
+}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/lib/corelib/tools/qbspluginmanager.h b/src/lib/corelib/tools/qbspluginmanager.h
new file mode 100644
index 000000000..96d5082e3
--- /dev/null
+++ b/src/lib/corelib/tools/qbspluginmanager.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBS_PLUGINS_H
+#define QBS_PLUGINS_H
+
+#include <language/filetags.h>
+
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+class QLibrary;
+QT_END_NAMESPACE
+
+namespace qbs {
+namespace Internal {
+class Logger;
+
+typedef void (*QbsPluginLoadFunction)();
+typedef void (*QbsPluginUnloadFunction)();
+
+class QBS_EXPORT QbsPluginManager
+{
+public:
+ ~QbsPluginManager();
+ static QbsPluginManager *instance();
+ void registerStaticPlugin(QbsPluginLoadFunction, QbsPluginUnloadFunction);
+ void loadStaticPlugins();
+ void unloadStaticPlugins();
+ void loadPlugins(const QStringList &paths, const Logger &logger);
+
+protected:
+ QbsPluginManager();
+
+private:
+ struct QbsPlugin {
+ QbsPluginLoadFunction load;
+ QbsPluginUnloadFunction unload;
+ bool loaded;
+ };
+ std::vector<QbsPlugin> m_staticPlugins;
+ std::vector<QLibrary *> m_libs;
+};
+
+} // namespace Internal
+} // namespace qbs
+
+#ifdef QBS_STATIC_LIB
+#define QBS_REGISTER_STATIC_PLUGIN(exportmacro, name, load, unload) \
+ static auto qbs_static_plugin_register##name = [] { \
+ qbs::Internal::QbsPluginManager::instance()->registerStaticPlugin(load, unload); \
+ return true; \
+ }();
+#else
+#define QBS_REGISTER_STATIC_PLUGIN(exportmacro, name, load, unload) \
+ exportmacro void QbsPluginLoad() { load(); } \
+ exportmacro void QbsPluginUnload() { unload(); }
+#endif
+
+#endif
diff --git a/src/lib/corelib/tools/scannerpluginmanager.cpp b/src/lib/corelib/tools/scannerpluginmanager.cpp
index c6ce3327b..cc929cad4 100644
--- a/src/lib/corelib/tools/scannerpluginmanager.cpp
+++ b/src/lib/corelib/tools/scannerpluginmanager.cpp
@@ -39,26 +39,11 @@
#include "scannerpluginmanager.h"
-#include <logging/logger.h>
-#include <logging/translator.h>
-#include <tools/hostosinfo.h>
-#include <tools/qttools.h>
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdiriterator.h>
-#include <QtCore/qlibrary.h>
+#include <plugins/scanner/scanner.h>
namespace qbs {
namespace Internal {
-ScannerPluginManager::~ScannerPluginManager()
-{
- for (QLibrary * const lib : qAsConst(m_libs)) {
- lib->unload();
- delete lib;
- }
-}
-
ScannerPluginManager *ScannerPluginManager::instance()
{
static ScannerPluginManager scannerPlugin;
@@ -74,7 +59,7 @@ QList<ScannerPlugin *> ScannerPluginManager::scannersForFileTag(const FileTag &f
return instance()->m_scannerPlugins.value(fileTag);
}
-void ScannerPluginManager::loadPlugins(ScannerPlugin **plugins)
+void ScannerPluginManager::registerPlugins(ScannerPlugin **plugins)
{
for (int i = 0; plugins[i] != 0; ++i) {
const FileTags &fileTags = FileTags::fromStringList(
@@ -84,52 +69,5 @@ void ScannerPluginManager::loadPlugins(ScannerPlugin **plugins)
}
}
-void ScannerPluginManager::loadPlugins(const QStringList &pluginPaths, const Logger &logger)
-{
- QStringList filters;
-
- if (HostOsInfo::isWindowsHost())
- filters << QLatin1String("*.dll");
- else if (HostOsInfo::isMacosHost())
- filters << QLatin1String("*.dylib");
- else
- filters << QLatin1String("*.so");
-
- for (const QString &pluginPath : pluginPaths) {
- logger.qbsTrace() << QString::fromLatin1("pluginmanager: loading plugins from '%1'.")
- .arg(QDir::toNativeSeparators(pluginPath));
- QDirIterator it(pluginPath, filters, QDir::Files);
- while (it.hasNext()) {
- const QString fileName = it.next();
- QScopedPointer<QLibrary> lib(new QLibrary(fileName));
- if (!lib->load()) {
- logger.qbsWarning() << Tr::tr("Pluginmanager: Cannot load plugin '%1': %2")
- .arg(QDir::toNativeSeparators(fileName), lib->errorString());
- continue;
- }
-
- getScanners_f getScanners = reinterpret_cast<getScanners_f>(lib->resolve("getScanners"));
- if (!getScanners) {
- logger.qbsWarning() << Tr::tr("Pluginmanager: Cannot resolve "
- "symbol in '%1'.").arg(QDir::toNativeSeparators(fileName));
- continue;
- }
-
- ScannerPlugin **plugins = getScanners();
- if (plugins == 0) {
- logger.qbsWarning() << Tr::tr("pluginmanager: no scanners "
- "returned from '%1'.").arg(QDir::toNativeSeparators(fileName));
- continue;
- }
-
- logger.qbsTrace() << QString::fromLatin1("pluginmanager: scanner plugin '%1' loaded.")
- .arg(QDir::toNativeSeparators(fileName));
-
- loadPlugins(plugins);
- m_libs.append(lib.take());
- }
- }
-}
-
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/tools/scannerpluginmanager.h b/src/lib/corelib/tools/scannerpluginmanager.h
index a5e1ef88c..380d38a76 100644
--- a/src/lib/corelib/tools/scannerpluginmanager.h
+++ b/src/lib/corelib/tools/scannerpluginmanager.h
@@ -37,41 +37,33 @@
**
****************************************************************************/
-#ifndef QBS_PLUGINS_H
-#define QBS_PLUGINS_H
+#ifndef QBS_PLUGINS_SCANNER_H
+#define QBS_PLUGINS_SCANNER_H
+
+#include "qbs_export.h"
#include <language/filetags.h>
-#include <plugins/scanner/scanner.h>
#include <QtCore/qhash.h>
-#include <QtCore/qstring.h>
-QT_BEGIN_NAMESPACE
-class QLibrary;
-QT_END_NAMESPACE
+class ScannerPlugin;
namespace qbs {
namespace Internal {
-class Logger;
-class ScannerPluginManager
+class QBS_EXPORT ScannerPluginManager
{
public:
- ~ScannerPluginManager();
static ScannerPluginManager *instance();
static QList<ScannerPlugin *> scannersForFileTag(const FileTag &fileTag);
- void loadPlugins(ScannerPlugin **plugins);
- void loadPlugins(const QStringList &paths, const Logger &logger);
+ void registerPlugins(ScannerPlugin **plugins);
private:
ScannerPluginManager();
-
-private:
- QList<QLibrary *> m_libs;
QHash<FileTag, QList<ScannerPlugin*> > m_scannerPlugins;
};
} // namespace Internal
} // namespace qbs
-#endif
+#endif // QBS_PLUGINS_SCANNER_H
diff --git a/src/lib/corelib/tools/scripttools.h b/src/lib/corelib/tools/scripttools.h
index 56731c730..8346aea66 100644
--- a/src/lib/corelib/tools/scripttools.h
+++ b/src/lib/corelib/tools/scripttools.h
@@ -63,7 +63,7 @@ QScriptValue toScriptValue(QScriptEngine *scriptEngine, const C &container)
}
void setConfigProperty(QVariantMap &cfg, const QStringList &name, const QVariant &value);
-QVariant getConfigProperty(const QVariantMap &cfg, const QStringList &name);
+QVariant QBS_AUTOTEST_EXPORT getConfigProperty(const QVariantMap &cfg, const QStringList &name);
template <class T>
void attachPointerTo(QScriptValue &scriptValue, T *ptr)
diff --git a/src/lib/corelib/tools/set.h b/src/lib/corelib/tools/set.h
index 1fd180b21..5a24a1685 100644
--- a/src/lib/corelib/tools/set.h
+++ b/src/lib/corelib/tools/set.h
@@ -42,13 +42,13 @@
#include <tools/persistence.h>
-#include <QtCore/qsharedpointer.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qvector.h>
#include <algorithm>
#include <functional>
#include <iterator>
+#include <memory>
#include <set>
#include <type_traits>
@@ -62,7 +62,7 @@ template<typename T> Set<T> operator-(const Set<T> &set1, const Set<T> &set2);
namespace helper {
template<typename T> struct SortAfterLoad { static const bool required = false; };
template<typename T> struct SortAfterLoad<T *> { static const bool required = true; };
-template<typename T> struct SortAfterLoad<QSharedPointer<T>> { static const bool required = true; };
+template<typename T> struct SortAfterLoad<std::shared_ptr<T>> { static const bool required = true; };
}
template<typename T> class Set
@@ -424,6 +424,8 @@ template<typename T> Set<T> operator&(const Set<T> &set1, const Set<T> &set2)
return result;
}
+template<> inline QString Set<QString>::toString(const QString &value) const { return value; }
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/tools/setupprojectparameters.cpp b/src/lib/corelib/tools/setupprojectparameters.cpp
index db7b11118..5decbec08 100644
--- a/src/lib/corelib/tools/setupprojectparameters.cpp
+++ b/src/lib/corelib/tools/setupprojectparameters.cpp
@@ -60,7 +60,7 @@ class SetupProjectParametersPrivate : public QSharedData
{
public:
SetupProjectParametersPrivate()
- : ignoreDifferentProjectFilePath(false)
+ : overrideBuildGraphData(false)
, dryRun(false)
, logElapsedTime(false)
, forceProbeExecution(false)
@@ -68,7 +68,6 @@ public:
, restoreBehavior(SetupProjectParameters::RestoreAndTrackChanges)
, propertyCheckingMode(ErrorHandlingMode::Relaxed)
, productErrorMode(ErrorHandlingMode::Strict)
- , environment(QProcessEnvironment::systemEnvironment())
{
}
@@ -85,7 +84,7 @@ public:
mutable QVariantMap buildConfigurationTree;
mutable QVariantMap overriddenValuesTree;
mutable QVariantMap finalBuildConfigTree;
- bool ignoreDifferentProjectFilePath;
+ bool overrideBuildGraphData;
bool dryRun;
bool logElapsedTime;
bool forceProbeExecution;
@@ -407,7 +406,7 @@ ErrorInfo SetupProjectParameters::expandBuildConfiguration()
}
QVariantMap SetupProjectParameters::finalBuildConfigurationTree(const QVariantMap &buildConfig,
- const QVariantMap &overriddenValues, const QString &buildRoot)
+ const QVariantMap &overriddenValues)
{
QVariantMap flatBuildConfig = buildConfig;
for (QVariantMap::ConstIterator it = overriddenValues.constBegin();
@@ -415,15 +414,6 @@ QVariantMap SetupProjectParameters::finalBuildConfigurationTree(const QVariantMa
flatBuildConfig.insert(it.key(), it.value());
}
- const QString installRootKey = QLatin1String("qbs.installRoot");
- QString installRoot = flatBuildConfig.value(installRootKey).toString();
- if (installRoot.isEmpty()) {
- installRoot = buildRoot + QLatin1Char('/')
- + flatBuildConfig.value(QLatin1String("qbs.configurationName")).toString()
- + QLatin1Char('/') + InstallOptions::defaultInstallRoot();
- flatBuildConfig.insert(installRootKey, installRoot);
- }
-
QVariantMap buildConfigTree;
provideValuesTree(flatBuildConfig, &buildConfigTree);
return buildConfigTree;
@@ -436,31 +426,11 @@ QVariantMap SetupProjectParameters::finalBuildConfigurationTree() const
{
if (d->finalBuildConfigTree.isEmpty()) {
d->finalBuildConfigTree = finalBuildConfigurationTree(buildConfiguration(),
- overriddenValues(), buildRoot());
+ overriddenValues());
}
return d->finalBuildConfigTree;
}
-/*!
- * \variable SetupProjectParameters::ignoreDifferentProjectFilePath
- * \brief Returns true iff the saved build graph should be used even if its path to the
- * project file is different from \c SetupProjectParameters::projectFilePath()
- */
-bool SetupProjectParameters::ignoreDifferentProjectFilePath() const
-{
- return d->ignoreDifferentProjectFilePath;
-}
-
-/*!
- * \brief Controls whether the path to the main project file may be different from the one
- * stored in a possible build graph file.
- * The default is false.
- */
-void SetupProjectParameters::setIgnoreDifferentProjectFilePath(bool doIgnore)
-{
- d->ignoreDifferentProjectFilePath = doIgnore;
-}
-
/*!
* \brief if true, qbs will not store the build graph of the resolved project.
*/
@@ -594,6 +564,28 @@ void SetupProjectParameters::setRestoreBehavior(SetupProjectParameters::RestoreB
}
/*!
+ * Returns true if and only if environment, project file path and overridden property values
+ * should be taken from this object even if a build graph already exists.
+ * If this function returns \c false and a build graph exists, then it is an error to provide a
+ * project file path or overridden property values that differ from the respective values
+ * in the build graph.
+ */
+bool SetupProjectParameters::overrideBuildGraphData() const
+{
+ return d->overrideBuildGraphData;
+}
+
+/*!
+ * If \c doOverride is true, then environment, project file path and overridden property values
+ * are taken from this object rather than from the build graph.
+ * The default is \c false.
+ */
+void SetupProjectParameters::setOverrideBuildGraphData(bool doOverride)
+{
+ d->overrideBuildGraphData = doOverride;
+}
+
+/*!
* \enum ErrorHandlingMode
* This enum type specifies how \QBS should behave if errors occur during project resolving.
* \value ErrorHandlingMode::Strict Project resolving will stop with an error message.
diff --git a/src/lib/corelib/tools/setupprojectparameters.h b/src/lib/corelib/tools/setupprojectparameters.h
index e3f562482..21dc99e0b 100644
--- a/src/lib/corelib/tools/setupprojectparameters.h
+++ b/src/lib/corelib/tools/setupprojectparameters.h
@@ -100,11 +100,11 @@ public:
QVariantMap buildConfigurationTree() const;
static QVariantMap finalBuildConfigurationTree(const QVariantMap &buildConfig,
- const QVariantMap &overriddenValues, const QString &buildRoot);
+ const QVariantMap &overriddenValues);
QVariantMap finalBuildConfigurationTree() const;
- bool ignoreDifferentProjectFilePath() const;
- void setIgnoreDifferentProjectFilePath(bool doIgnore);
+ bool overrideBuildGraphData() const;
+ void setOverrideBuildGraphData(bool doOverride);
bool dryRun() const;
void setDryRun(bool dryRun);
diff --git a/src/lib/corelib/tools/tools.pri b/src/lib/corelib/tools/tools.pri
index 0fa91147b..301d00d05 100644
--- a/src/lib/corelib/tools/tools.pri
+++ b/src/lib/corelib/tools/tools.pri
@@ -34,6 +34,7 @@ HEADERS += \
$$PWD/processutils.h \
$$PWD/progressobserver.h \
$$PWD/projectgeneratormanager.h \
+ $$PWD/qbspluginmanager.h \
$$PWD/qbsprocess.h \
$$PWD/shellutils.h \
$$PWD/stlutils.h \
@@ -82,6 +83,7 @@ SOURCES += \
$$PWD/profiling.cpp \
$$PWD/progressobserver.cpp \
$$PWD/projectgeneratormanager.cpp \
+ $$PWD/qbspluginmanager.cpp \
$$PWD/qbsprocess.cpp \
$$PWD/shellutils.cpp \
$$PWD/buildoptions.cpp \
@@ -102,11 +104,6 @@ osx {
LIBS += -framework Security
}
-qbs_enable_unit_tests {
- HEADERS += $$PWD/tst_tools.h
- SOURCES += $$PWD/tst_tools.cpp
-}
-
!qbs_no_dev_install {
tools_headers.files = \
$$PWD/architectures.h \
@@ -124,6 +121,7 @@ qbs_enable_unit_tests {
$$PWD/generateoptions.h \
$$PWD/generatorpluginmanager.h \
$$PWD/installoptions.h \
+ $$PWD/qbspluginmanager.h \
$$PWD/setupprojectparameters.h \
$$PWD/toolchains.h
tools_headers.path = $${QBS_INSTALL_PREFIX}/include/qbs/tools
diff --git a/src/lib/corelib/tools/tst_tools.cpp b/src/lib/corelib/tools/tst_tools.cpp
deleted file mode 100644
index ca81aff00..000000000
--- a/src/lib/corelib/tools/tst_tools.cpp
+++ /dev/null
@@ -1,950 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qbs.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#undef QT_NO_CAST_FROM_ASCII // I am qmake, and I approve this hack.
-
-#include "tst_tools.h"
-
-#include "buildoptions.h"
-#include "error.h"
-#include "fileinfo.h"
-#include "hostosinfo.h"
-#include "processutils.h"
-#include "profile.h"
-#include "set.h"
-#include "settings.h"
-#include "setupprojectparameters.h"
-#include "version.h"
-
-#include <QtCore/qdir.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qsettings.h>
-#include <QtCore/qtemporarydir.h>
-#include <QtCore/qtemporaryfile.h>
-
-#include <QtTest/qtest.h>
-
-namespace qbs {
-namespace Internal {
-
-TestTools::TestTools(Settings *settings) : m_settings(settings)
-{
-}
-
-TestTools::~TestTools()
-{
- qDeleteAll(m_tmpDirs);
-}
-
-void TestTools::testFileInfo()
-{
- QCOMPARE(FileInfo::fileName("C:/waffl/copter.exe"), QString("copter.exe"));
- QCOMPARE(FileInfo::baseName("C:/waffl/copter.exe.lib"), QString("copter"));
- QCOMPARE(FileInfo::completeBaseName("C:/waffl/copter.exe.lib"), QString("copter.exe"));
- QCOMPARE(FileInfo::path("abc"), QString("."));
- QCOMPARE(FileInfo::path("/abc/lol"), QString("/abc"));
- QCOMPARE(FileInfo::path("/fileInRoot"), QString(QLatin1Char('/')));
- if (HostOsInfo::isWindowsHost())
- QCOMPARE(FileInfo::path("C:/fileInDriveRoot"), QString("C:/"));
- QVERIFY(!FileInfo::isAbsolute("bla/lol"));
- QVERIFY(FileInfo::isAbsolute("/bla/lol"));
- if (HostOsInfo::isWindowsHost())
- QVERIFY(FileInfo::isAbsolute("C:\\bla\\lol"));
- QCOMPARE(FileInfo::resolvePath("/abc/lol", "waffl"), QString("/abc/lol/waffl"));
- QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../foo/bar"), QString("/abc/def/ghi/foo/bar"));
- QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../../foo/bar"), QString("/abc/def/foo/bar"));
- QCOMPARE(FileInfo::resolvePath("/abc", "../../../foo/bar"), QString("/foo/bar"));
- QCOMPARE(FileInfo("/does/not/exist").lastModified(), FileTime());
-}
-
-void TestTools::fileCaseCheck()
-{
- QTemporaryFile tempFile(QDir::tempPath() + QLatin1String("/CamelCase"));
- QVERIFY2(tempFile.open(), qPrintable(tempFile.errorString()));
- QFileInfo tempFileInfo(tempFile.fileName());
- const QString lowerFilePath = tempFileInfo.absolutePath() + QLatin1Char('/')
- + tempFileInfo.fileName().toLower();
- const QString upperFilePath = tempFileInfo.absolutePath() + QLatin1Char('/')
- + tempFileInfo.fileName().toUpper();
- QVERIFY(FileInfo::isFileCaseCorrect(tempFileInfo.absoluteFilePath()));
- if (QFile::exists(lowerFilePath))
- QVERIFY(!FileInfo::isFileCaseCorrect(lowerFilePath));
- if (QFile::exists(upperFilePath))
- QVERIFY(!FileInfo::isFileCaseCorrect(upperFilePath));
-}
-
-void TestTools::testProfiles()
-{
- TemporaryProfile tpp("parent", m_settings);
- Profile parentProfile = tpp.p;
- TemporaryProfile tpc("child", m_settings);
- Profile childProfile = tpc.p;
- parentProfile.removeBaseProfile();
- parentProfile.remove("testKey");
- QCOMPARE(parentProfile.value("testKey", "none").toString(), QLatin1String("none"));
- parentProfile.setValue("testKey", "testValue");
- QCOMPARE(parentProfile.value("testKey").toString(), QLatin1String("testValue"));
-
- childProfile.remove("testKey");
- childProfile.removeBaseProfile();
- QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("none"));
- childProfile.setBaseProfile("parent");
- QCOMPARE(childProfile.value("testKey").toString(), QLatin1String("testValue"));
-
- // Change base profile and check if the inherited value also changes.
- TemporaryProfile tpf("foo", m_settings);
- Profile fooProfile = tpf.p;
- fooProfile.setValue("testKey", "gnampf");
- childProfile.setBaseProfile("foo");
- QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("gnampf"));
-
- ErrorInfo errorInfo;
- childProfile.setBaseProfile("SmurfAlongWithMe");
- childProfile.value("blubb", QString(), &errorInfo);
- QVERIFY(errorInfo.hasError());
-
- errorInfo.clear();
- childProfile.setBaseProfile("parent");
- parentProfile.setBaseProfile("child");
- QVERIFY(!childProfile.value("blubb", QString(), &errorInfo).isValid());
- QVERIFY(errorInfo.hasError());
-
- QVERIFY(!childProfile.allKeys(Profile::KeySelectionNonRecursive).isEmpty());
-
- errorInfo.clear();
- QVERIFY(childProfile.allKeys(Profile::KeySelectionRecursive, &errorInfo).isEmpty());
- QVERIFY(errorInfo.hasError());
-}
-
-void TestTools::testSettingsMigration()
-{
- QFETCH(QString, baseDir);
- QFETCH(bool, hasOldSettings);
- Settings settings(baseDir);
- if (hasOldSettings) {
- QVERIFY(QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles/right.txt")
- .exists());
- QCOMPARE(settings.value("key").toString(),
- settings.baseDirectory() + "/qbs/" QBS_VERSION "/profilesright");
- } else {
- QVERIFY(!QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles").exists());
- QVERIFY(settings.allKeys().isEmpty());
- }
-}
-
-void TestTools::testSettingsMigration_data()
-{
- QTest::addColumn<QString>("baseDir");
- QTest::addColumn<bool>("hasOldSettings");
- QTest::newRow("settings dir with lots of versions") << setupSettingsDir1() << true;
- QTest::newRow("settings dir with only a fallback") << setupSettingsDir2() << true;
- QTest::newRow("no previous settings") << setupSettingsDir3() << false;
-}
-
-QString TestTools::setupSettingsDir1()
-{
- QTemporaryDir * const baseDir = new QTemporaryDir;
- m_tmpDirs << baseDir;
-
- const Version thisVersion = Version::fromString(QBS_VERSION);
- Version predecessor;
- if (thisVersion.patchLevel() > 0) {
- predecessor.setMajorVersion(thisVersion.majorVersion());
- predecessor.setMinorVersion(thisVersion.minorVersion());
- predecessor.setPatchLevel(thisVersion.patchLevel() - 1);
- } else if (thisVersion.minorVersion() > 0) {
- predecessor.setMajorVersion(thisVersion.majorVersion());
- predecessor.setMinorVersion(thisVersion.minorVersion() - 1);
- predecessor.setPatchLevel(99);
- } else {
- predecessor.setMajorVersion(thisVersion.majorVersion() - 1);
- predecessor.setMajorVersion(99);
- predecessor.setPatchLevel(99);
- }
- const auto versions = QList<Version>() << Version(0, 1, 0) << Version(1, 0, 5) << predecessor
- << Version(thisVersion.majorVersion() + 1, thisVersion.minorVersion(),
- thisVersion.patchLevel())
- << Version(thisVersion.majorVersion(), thisVersion.minorVersion() + 1,
- thisVersion.patchLevel())
- << Version(thisVersion.majorVersion(), thisVersion.minorVersion(),
- thisVersion.patchLevel() + 1)
- << Version(99, 99, 99);
- foreach (const Version &v, versions) {
- const QString settingsDir = baseDir->path() + "/qbs/" + v.toString();
- QSettings s(settingsDir + "/qbs.conf",
- HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat);
- const QString profilesDir = settingsDir + "/profiles";
- QDir::root().mkpath(profilesDir);
- const QString magicString = v == predecessor ? "right" : "wrong";
- QFile f(profilesDir + '/' + magicString + ".txt");
- f.open(QIODevice::WriteOnly);
- s.setValue("org/qt-project/qbs/key", profilesDir + magicString);
- }
-
- return baseDir->path();
-}
-
-QString TestTools::setupSettingsDir2()
-{
- QTemporaryDir * const baseDir = new QTemporaryDir;
- m_tmpDirs << baseDir;
- const QString settingsDir = baseDir->path();
- QSettings s(settingsDir + QLatin1String("/qbs.conf"),
- HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat);
- const QString profilesDir = settingsDir + QLatin1String("/qbs/profiles");
- QDir::root().mkpath(profilesDir);
- QFile f(profilesDir + "/right.txt");
- f.open(QIODevice::WriteOnly);
- s.setValue("org/qt-project/qbs/key", profilesDir + "right");
-
- return baseDir->path();
-}
-
-QString TestTools::setupSettingsDir3()
-{
- auto * const baseDir = new QTemporaryDir;
- m_tmpDirs << baseDir;
- return baseDir->path();
-}
-
-void TestTools::testBuildConfigMerging()
-{
- Settings settings((QString()));
- TemporaryProfile tp(QLatin1String("tst_tools_profile"), &settings);
- Profile profile = tp.p;
- profile.setValue(QLatin1String("topLevelKey"), QLatin1String("topLevelValue"));
- profile.setValue(QLatin1String("qbs.toolchain"), QLatin1String("gcc"));
- profile.setValue(QLatin1String("qbs.architecture"),
- QLatin1String("Jean-Claude Pillemann"));
- profile.setValue(QLatin1String("cpp.treatWarningsAsErrors"), true);
- QVariantMap overrideMap;
- overrideMap.insert(QLatin1String("qbs.toolchain"), QLatin1String("clang"));
- overrideMap.insert(QLatin1String("qbs.installRoot"), QLatin1String("/blubb"));
- SetupProjectParameters params;
- params.setTopLevelProfile(profile.name());
- params.setConfigurationName(QLatin1String("debug"));
- params.setOverriddenValues(overrideMap);
- const ErrorInfo error = params.expandBuildConfiguration();
- QVERIFY2(!error.hasError(), qPrintable(error.toString()));
- const QVariantMap finalMap = params.finalBuildConfigurationTree();
- QCOMPARE(finalMap.count(), 3);
- QCOMPARE(finalMap.value(QLatin1String("topLevelKey")).toString(),
- QString::fromLatin1("topLevelValue"));
- const QVariantMap finalQbsMap = finalMap.value(QLatin1String("qbs")).toMap();
- QCOMPARE(finalQbsMap.count(), 4);
- QCOMPARE(finalQbsMap.value(QLatin1String("toolchain")).toString(),
- QString::fromLatin1("clang"));
- QCOMPARE(finalQbsMap.value(QLatin1String("configurationName")).toString(),
- QString::fromLatin1("debug"));
- QCOMPARE(finalQbsMap.value(QLatin1String("architecture")).toString(),
- QString::fromLatin1("Jean-Claude Pillemann"));
- QCOMPARE(finalQbsMap.value(QLatin1String("installRoot")).toString(), QLatin1String("/blubb"));
- const QVariantMap finalCppMap = finalMap.value(QLatin1String("cpp")).toMap();
- QCOMPARE(finalCppMap.count(), 1);
- QCOMPARE(finalCppMap.value(QLatin1String("treatWarningsAsErrors")).toBool(), true);
-}
-
-void TestTools::testProcessNameByPid()
-{
- QCOMPARE(qAppName(), processNameByPid(QCoreApplication::applicationPid()));
-}
-
-
-int toNumber(const QString &str)
-{
- int res = 0;
- for (int i = 0; i < str.length(); ++i)
- res = (res * 10) + str[i].digitValue();
- return res;
-}
-
-void TestTools::set_operator_eq()
-{
- {
- Set<int> set1, set2;
- QVERIFY(set1 == set2);
- QVERIFY(!(set1 != set2));
-
- set1.insert(1);
- QVERIFY(set1 != set2);
- QVERIFY(!(set1 == set2));
-
- set2.insert(1);
- QVERIFY(set1 == set2);
- QVERIFY(!(set1 != set2));
-
- set2.insert(1);
- QVERIFY(set1 == set2);
- QVERIFY(!(set1 != set2));
-
- set1.insert(2);
- QVERIFY(set1 != set2);
- QVERIFY(!(set1 == set2));
- }
-
- {
- Set<QString> set1, set2;
- QVERIFY(set1 == set2);
- QVERIFY(!(set1 != set2));
-
- set1.insert("one");
- QVERIFY(set1 != set2);
- QVERIFY(!(set1 == set2));
-
- set2.insert("one");
- QVERIFY(set1 == set2);
- QVERIFY(!(set1 != set2));
-
- set2.insert("one");
- QVERIFY(set1 == set2);
- QVERIFY(!(set1 != set2));
-
- set1.insert("two");
- QVERIFY(set1 != set2);
- QVERIFY(!(set1 == set2));
- }
-
- {
- Set<QString> a;
- Set<QString> b;
-
- a += "otto";
- b += "willy";
-
- QVERIFY(a != b);
- QVERIFY(!(a == b));
- }
-
- {
- Set<int> s1, s2;
- s1.reserve(100);
- s2.reserve(4);
- QVERIFY(s1 == s2);
- s1 << 100 << 200 << 300 << 400;
- s2 << 400 << 300 << 200 << 100;
- QVERIFY(s1 == s2);
- }
-}
-
-void TestTools::set_swap()
-{
- Set<int> s1, s2;
- s1.insert(1);
- s2.insert(2);
- s1.swap(s2);
- QCOMPARE(*s1.begin(),2);
- QCOMPARE(*s2.begin(),1);
-}
-
-void TestTools::set_size()
-{
- Set<int> set;
- QVERIFY(set.size() == 0);
- QVERIFY(set.isEmpty());
- QVERIFY(set.count() == set.size());
-
- set.insert(1);
- QVERIFY(set.size() == 1);
- QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
-
- set.insert(1);
- QVERIFY(set.size() == 1);
- QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
-
- set.insert(2);
- QVERIFY(set.size() == 2);
- QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
-
- set.remove(1);
- QVERIFY(set.size() == 1);
- QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
-
- set.remove(1);
- QVERIFY(set.size() == 1);
- QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
-
- set.remove(2);
- QVERIFY(set.size() == 0);
- QVERIFY(set.isEmpty());
- QVERIFY(set.count() == set.size());
-}
-
-void TestTools::set_capacity()
-{
- Set<int> set;
- int n = set.capacity();
- QVERIFY(n == 0);
-
- for (int i = 0; i < 1000; ++i) {
- set.insert(i);
- QVERIFY(set.capacity() >= set.size());
- }
-}
-
-void TestTools::set_reserve()
-{
- Set<int> set;
-
- set.reserve(1000);
- QVERIFY(set.capacity() >= 1000);
-
- for (int i = 0; i < 500; ++i)
- set.insert(i);
-
- QVERIFY(set.capacity() >= 1000);
-
- for (int j = 0; j < 500; ++j)
- set.remove(j);
-
- QVERIFY(set.capacity() >= 1000);
-}
-
-void TestTools::set_clear()
-{
- Set<QString> set1, set2;
- QVERIFY(set1.size() == 0);
-
- set1.clear();
- QVERIFY(set1.size() == 0);
-
- set1.insert("foo");
- QVERIFY(set1.size() != 0);
-
- set2 = set1;
-
- set1.clear();
- QVERIFY(set1.size() == 0);
- QVERIFY(set2.size() != 0);
-
- set2.clear();
- QVERIFY(set1.size() == 0);
- QVERIFY(set2.size() == 0);
-}
-
-void TestTools::set_remove()
-{
- Set<QString> set1;
-
- for (int i = 0; i < 500; ++i)
- set1.insert(QString::number(i));
-
- QCOMPARE(set1.size(), 500);
-
- for (int j = 0; j < 500; ++j) {
- set1.remove(QString::number((j * 17) % 500));
- QCOMPARE(set1.size(), 500 - j - 1);
- }
-}
-
-void TestTools::set_contains()
-{
- Set<QString> set1;
-
- for (int i = 0; i < 500; ++i) {
- QVERIFY(!set1.contains(QString::number(i)));
- set1.insert(QString::number(i));
- QVERIFY(set1.contains(QString::number(i)));
- }
-
- QCOMPARE(set1.size(), 500);
-
- for (int j = 0; j < 500; ++j) {
- int i = (j * 17) % 500;
- QVERIFY(set1.contains(QString::number(i)));
- set1.remove(QString::number(i));
- QVERIFY(!set1.contains(QString::number(i)));
- }
-}
-
-void TestTools::set_containsSet()
-{
- Set<QString> set1;
- Set<QString> set2;
-
- // empty set contains the empty set
- QVERIFY(set1.contains(set2));
-
- for (int i = 0; i < 500; ++i) {
- set1.insert(QString::number(i));
- set2.insert(QString::number(i));
- }
- QVERIFY(set1.contains(set2));
-
- set2.remove(QString::number(19));
- set2.remove(QString::number(82));
- set2.remove(QString::number(7));
- QVERIFY(set1.contains(set2));
-
- set1.remove(QString::number(23));
- QVERIFY(!set1.contains(set2));
-
- // filled set contains the empty set as well
- Set<QString> set3;
- QVERIFY(set1.contains(set3));
-
- // the empty set doesn't contain a filled set
- QVERIFY(!set3.contains(set1));
-
- // verify const signature
- const Set<QString> set4;
- QVERIFY(set3.contains(set4));
-}
-
-void TestTools::set_begin()
-{
- Set<int> set1;
- Set<int> set2 = set1;
-
- {
- Set<int>::const_iterator i = set1.constBegin();
- Set<int>::const_iterator j = set1.cbegin();
- Set<int>::const_iterator k = set2.constBegin();
- Set<int>::const_iterator ell = set2.cbegin();
-
- QVERIFY(i == j);
- QVERIFY(k == ell);
- }
-
- set1.insert(44);
-
- {
- Set<int>::const_iterator i = set1.constBegin();
- Set<int>::const_iterator j = set1.cbegin();
- Set<int>::const_iterator k = set2.constBegin();
- Set<int>::const_iterator ell = set2.cbegin();
-
- QVERIFY(i == j);
- QVERIFY(k == ell);
- }
-
- set2 = set1;
-
- {
- Set<int>::const_iterator i = set1.constBegin();
- Set<int>::const_iterator j = set1.cbegin();
- Set<int>::const_iterator k = set2.constBegin();
- Set<int>::const_iterator ell = set2.cbegin();
-
- QVERIFY(i == j);
- QVERIFY(k == ell);
- }
-}
-
-void TestTools::set_end()
-{
- Set<int> set1;
- Set<int> set2 = set1;
-
- {
- Set<int>::const_iterator i = set1.constEnd();
- Set<int>::const_iterator j = set1.cend();
- Set<int>::const_iterator k = set2.constEnd();
- Set<int>::const_iterator ell = set2.cend();
-
- QVERIFY(i == j);
- QVERIFY(k == ell);
-
- QVERIFY(set1.constBegin() == set1.constEnd());
- QVERIFY(set2.constBegin() == set2.constEnd());
- }
-
- set1.insert(44);
-
- {
- Set<int>::const_iterator i = set1.constEnd();
- Set<int>::const_iterator j = set1.cend();
- Set<int>::const_iterator k = set2.constEnd();
- Set<int>::const_iterator ell = set2.cend();
-
- QVERIFY(i == j);
- QVERIFY(k == ell);
-
- QVERIFY(set1.constBegin() != set1.constEnd());
- QVERIFY(set2.constBegin() == set2.constEnd());
- }
-
- set2 = set1;
-
- {
- Set<int>::const_iterator i = set1.constEnd();
- Set<int>::const_iterator j = set1.cend();
- Set<int>::const_iterator k = set2.constEnd();
- Set<int>::const_iterator ell = set2.cend();
-
- QVERIFY(i == j);
- QVERIFY(k == ell);
-
- QVERIFY(set1.constBegin() != set1.constEnd());
- QVERIFY(set2.constBegin() != set2.constEnd());
- }
-
- set1.clear();
- set2.clear();
- QVERIFY(set1.constBegin() == set1.constEnd());
- QVERIFY(set2.constBegin() == set2.constEnd());
-}
-
-struct IdentityTracker {
- int value, id;
-};
-inline bool operator==(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value == rhs.value; }
-inline bool operator<(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value < rhs.value; }
-
-void TestTools::set_insert()
-{
- {
- Set<int> set1;
- QVERIFY(set1.size() == 0);
- set1.insert(1);
- QVERIFY(set1.size() == 1);
- set1.insert(2);
- QVERIFY(set1.size() == 2);
- set1.insert(2);
- QVERIFY(set1.size() == 2);
- QVERIFY(set1.contains(2));
- set1.remove(2);
- QVERIFY(set1.size() == 1);
- QVERIFY(!set1.contains(2));
- set1.insert(2);
- QVERIFY(set1.size() == 2);
- QVERIFY(set1.contains(2));
- }
-
- {
- Set<int> set1;
- QVERIFY(set1.size() == 0);
- set1 << 1;
- QVERIFY(set1.size() == 1);
- set1 << 2;
- QVERIFY(set1.size() == 2);
- set1 << 2;
- QVERIFY(set1.size() == 2);
- QVERIFY(set1.contains(2));
- set1.remove(2);
- QVERIFY(set1.size() == 1);
- QVERIFY(!set1.contains(2));
- set1 << 2;
- QVERIFY(set1.size() == 2);
- QVERIFY(set1.contains(2));
- }
-
- {
- Set<IdentityTracker> set;
- QCOMPARE(set.size(), 0);
- const int dummy = -1;
- IdentityTracker id00 = {0, 0}, id01 = {0, 1}, searchKey = {0, dummy};
- QCOMPARE(set.insert(id00).first->id, id00.id);
- QCOMPARE(set.size(), 1);
- QCOMPARE(set.insert(id01).first->id, id00.id); // first inserted is kept
- QCOMPARE(set.size(), 1);
- QCOMPARE(set.find(searchKey)->id, id00.id);
- }
-}
-
-void TestTools::set_reverseIterators()
-{
- Set<int> s;
- s << 1 << 17 << 61 << 127 << 911;
- std::vector<int> v(s.begin(), s.end());
- std::reverse(v.begin(), v.end());
- const Set<int> &cs = s;
- QVERIFY(std::equal(v.begin(), v.end(), s.rbegin()));
- QVERIFY(std::equal(v.begin(), v.end(), s.crbegin()));
- QVERIFY(std::equal(v.begin(), v.end(), cs.rbegin()));
- QVERIFY(std::equal(s.rbegin(), s.rend(), v.begin()));
- QVERIFY(std::equal(s.crbegin(), s.crend(), v.begin()));
- QVERIFY(std::equal(cs.rbegin(), cs.rend(), v.begin()));
-}
-
-void TestTools::set_stlIterator()
-{
- Set<QString> set1;
- for (int i = 0; i < 25000; ++i)
- set1.insert(QString::number(i));
-
- {
- int sum = 0;
- Set<QString>::const_iterator i = set1.cbegin();
- while (i != set1.end()) {
- sum += toNumber(*i);
- ++i;
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
- int sum = 0;
- Set<QString>::const_iterator i = set1.cend();
- while (i != set1.begin()) {
- --i;
- sum += toNumber(*i);
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-}
-
-void TestTools::set_stlMutableIterator()
-{
- Set<QString> set1;
- for (int i = 0; i < 25000; ++i)
- set1.insert(QString::number(i));
-
- {
- int sum = 0;
- Set<QString>::iterator i = set1.begin();
- while (i != set1.end()) {
- sum += toNumber(*i);
- ++i;
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
- int sum = 0;
- Set<QString>::iterator i = set1.end();
- while (i != set1.begin()) {
- --i;
- sum += toNumber(*i);
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
- Set<QString> set2 = set1;
- Set<QString> set3 = set2;
-
- Set<QString>::iterator i = set2.begin();
- Set<QString>::iterator j = set3.begin();
-
- while (i != set2.end()) {
- i = set2.erase(i);
- }
- QVERIFY(set2.isEmpty());
- QVERIFY(!set3.isEmpty());
-
- j = set3.end();
- while (j != set3.begin()) {
- j--;
- if (j + 1 != set3.end())
- set3.erase(j + 1);
- }
- if (set3.begin() != set3.end())
- set3.erase(set3.begin());
-
- QVERIFY(set2.isEmpty());
- QVERIFY(set3.isEmpty());
-
- i = set2.insert("foo").first;
- QCOMPARE(*i, QLatin1String("foo"));
- }
-}
-
-void TestTools::set_setOperations()
-{
- Set<QString> set1, set2;
- set1 << "alpha" << "beta" << "gamma" << "delta" << "zeta" << "omega";
- set2 << "beta" << "gamma" << "delta" << "epsilon" << "iota" << "omega";
-
- Set<QString> set3 = set1;
- set3.unite(set2);
- QVERIFY(set3.size() == 8);
- QVERIFY(set3.contains("alpha"));
- QVERIFY(set3.contains("beta"));
- QVERIFY(set3.contains("gamma"));
- QVERIFY(set3.contains("delta"));
- QVERIFY(set3.contains("epsilon"));
- QVERIFY(set3.contains("zeta"));
- QVERIFY(set3.contains("iota"));
- QVERIFY(set3.contains("omega"));
-
- Set<QString> set4 = set2;
- set4.unite(set1);
- QVERIFY(set4.size() == 8);
- QVERIFY(set4.contains("alpha"));
- QVERIFY(set4.contains("beta"));
- QVERIFY(set4.contains("gamma"));
- QVERIFY(set4.contains("delta"));
- QVERIFY(set4.contains("epsilon"));
- QVERIFY(set4.contains("zeta"));
- QVERIFY(set4.contains("iota"));
- QVERIFY(set4.contains("omega"));
-
- QVERIFY(set3 == set4);
-
- Set<QString> set5 = set1;
- set5.intersect(set2);
- QVERIFY(set5.size() == 4);
- QVERIFY(set5.contains("beta"));
- QVERIFY(set5.contains("gamma"));
- QVERIFY(set5.contains("delta"));
- QVERIFY(set5.contains("omega"));
-
- Set<QString> set6 = set2;
- set6.intersect(set1);
- QVERIFY(set6.size() == 4);
- QVERIFY(set6.contains("beta"));
- QVERIFY(set6.contains("gamma"));
- QVERIFY(set6.contains("delta"));
- QVERIFY(set6.contains("omega"));
-
- QVERIFY(set5 == set6);
-
- Set<QString> set7 = set1;
- set7.subtract(set2);
- QVERIFY(set7.size() == 2);
- QVERIFY(set7.contains("alpha"));
- QVERIFY(set7.contains("zeta"));
-
- Set<QString> set8 = set2;
- set8.subtract(set1);
- QVERIFY(set8.size() == 2);
- QVERIFY(set8.contains("epsilon"));
- QVERIFY(set8.contains("iota"));
-
- Set<QString> set9 = set1 | set2;
- QVERIFY(set9 == set3);
-
- Set<QString> set10 = set1 & set2;
- QVERIFY(set10 == set5);
-
- Set<QString> set11 = set1 + set2;
- QVERIFY(set11 == set3);
-
- Set<QString> set12 = set1 - set2;
- QVERIFY(set12 == set7);
-
- Set<QString> set13 = set2 - set1;
- QVERIFY(set13 == set8);
-
- Set<QString> set14 = set1;
- set14 |= set2;
- QVERIFY(set14 == set3);
-
- Set<QString> set15 = set1;
- set15 &= set2;
- QVERIFY(set15 == set5);
-
- Set<QString> set16 = set1;
- set16 += set2;
- QVERIFY(set16 == set3);
-
- Set<QString> set17 = set1;
- set17 -= set2;
- QVERIFY(set17 == set7);
-
- Set<QString> set18 = set2;
- set18 -= set1;
- QVERIFY(set18 == set8);
-}
-
-void TestTools::set_makeSureTheComfortFunctionsCompile()
-{
- Set<int> set1, set2, set3;
- set1 << 5;
- set1 |= set2;
- set1 |= 5;
- set1 &= set2;
- set1 &= 5;
- set1 += set2;
- set1 += 5;
- set1 -= set2;
- set1 -= 5;
- set1 = set2 | set3;
- set1 = set2 & set3;
- set1 = set2 + set3;
- set1 = set2 - set3;
-}
-
-void TestTools::set_initializerList()
-{
- Set<int> set = {1, 1, 2, 3, 4, 5};
- QCOMPARE(set.count(), 5);
- QVERIFY(set.contains(1));
- QVERIFY(set.contains(2));
- QVERIFY(set.contains(3));
- QVERIFY(set.contains(4));
- QVERIFY(set.contains(5));
-
- // check _which_ of the equal elements gets inserted (in the QHash/QMap case, it's the last):
- const Set<IdentityTracker> set2 = {{1, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
- QCOMPARE(set2.count(), 5);
- const int dummy = -1;
- const IdentityTracker searchKey = {1, dummy};
- QCOMPARE(set2.find(searchKey)->id, 0);
-
- Set<int> emptySet{};
- QVERIFY(emptySet.isEmpty());
-
- Set<int> set3{{}, {}, {}};
- QVERIFY(!set3.isEmpty());
-}
-
-void TestTools::set_intersects()
-{
- Set<int> s1;
- Set<int> s2;
-
- QVERIFY(!s1.intersects(s1));
- QVERIFY(!s1.intersects(s2));
-
- s1 << 100;
- QVERIFY(s1.intersects(s1));
- QVERIFY(!s1.intersects(s2));
-
- s2 << 200;
- QVERIFY(!s1.intersects(s2));
-
- s1 << 200;
- QVERIFY(s1.intersects(s2));
-
- Set<int> s3;
- s3 << 500;
- QVERIFY(!s1.intersects(s3));
- s3 << 200;
- QVERIFY(s1.intersects(s3));
-}
-
-} // namespace Internal
-} // namespace qbs
diff --git a/src/lib/corelib/tools/weakpointer.h b/src/lib/corelib/tools/weakpointer.h
index 8f78f5d20..fecae6825 100644
--- a/src/lib/corelib/tools/weakpointer.h
+++ b/src/lib/corelib/tools/weakpointer.h
@@ -39,31 +39,55 @@
#ifndef QBS_WEAKPOINTER_H
#define QBS_WEAKPOINTER_H
-#include <QtCore/qpointer.h>
+#include <memory>
namespace qbs {
namespace Internal {
-template<typename T> class WeakPointer : public QWeakPointer<T>
+template<typename T> class WeakPointer : public std::weak_ptr<T>
{
public:
- WeakPointer() : QWeakPointer<T>() {}
- WeakPointer(const QSharedPointer<T> &sharedPointer) : QWeakPointer<T>(sharedPointer) {}
- template <class X> WeakPointer(const QSharedPointer<X> &sp) : QWeakPointer<T>(sp) { }
-
+ WeakPointer() : std::weak_ptr<T>() {}
+ WeakPointer(const std::shared_ptr<T> &sharedPointer) : std::weak_ptr<T>(sharedPointer) {}
+ template <class X> WeakPointer(const std::shared_ptr<X> &sp) : std::weak_ptr<T>(sp) { }
+ T *get() const { auto p = std::weak_ptr<T>::lock(); return p.get(); }
+ operator bool() const { return !std::weak_ptr<T>::expired(); }
+ bool operator!() const { return std::weak_ptr<T>::expired(); }
operator T*() const { return checkedData(); }
T *operator->() const { return checkedData(); }
T operator*() const { return *checkedData(); }
private:
T *checkedData() const {
- T * const d = QWeakPointer<T>::data();
+ T * const d = get();
Q_ASSERT(d); // Calling code is not expecting this situation.
return d;
}
};
+template <typename T> bool operator==(const WeakPointer<T> &a, const WeakPointer<T> &b)
+{
+ return a.get() == b.get();
+}
+
+template <typename T> bool operator!=(const WeakPointer<T> &a, const WeakPointer<T> &b)
+{
+ return a.get() != b.get();
+}
+
+template <typename T, typename V> bool operator==(const WeakPointer<T> &a,
+ const std::shared_ptr<V> &b)
+{
+ return a.lock() == b;
+}
+
+template <typename T, typename V> bool operator!=(const WeakPointer<T> &a,
+ const std::shared_ptr<V> &b)
+{
+ return a.lock() != b;
+}
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/use_corelib.pri b/src/lib/corelib/use_corelib.pri
index 4b0751470..e79fcce04 100644
--- a/src/lib/corelib/use_corelib.pri
+++ b/src/lib/corelib/use_corelib.pri
@@ -45,3 +45,4 @@ CONFIG(static, static|shared) {
DEFINES += QBS_STATIC_LIB
}
qbs_enable_project_file_updates:DEFINES += QBS_ENABLE_PROJECT_FILE_UPDATES
+qbs_enable_unit_tests:DEFINES += QBS_ENABLE_UNIT_TESTS
diff --git a/src/lib/corelib/use_installed_corelib.pri b/src/lib/corelib/use_installed_corelib.pri
index d8bed5038..fefa774ff 100644
--- a/src/lib/corelib/use_installed_corelib.pri
+++ b/src/lib/corelib/use_installed_corelib.pri
@@ -35,3 +35,4 @@ CONFIG(static, static|shared) {
DEFINES += QBS_STATIC_LIB
}
qbs_enable_project_file_updates:DEFINES += QBS_ENABLE_PROJECT_FILE_UPDATES
+qbs_enable_unit_tests:DEFINES += QBS_ENABLE_UNIT_TESTS
diff --git a/src/lib/library.pri b/src/lib/library.pri
index ce7ab7e45..63f48a9a7 100644
--- a/src/lib/library.pri
+++ b/src/lib/library.pri
@@ -13,6 +13,7 @@ CONFIG(static, static|shared) {
DEFINES += QBS_LIBRARY
}
DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_PROCESS_COMBINED_ARGUMENT_START
+qbs_enable_unit_tests:DEFINES += QBS_ENABLE_UNIT_TESTS
INCLUDEPATH += $${PWD}/../
contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols
win32:CONFIG(debug, debug|release):TARGET = $${TARGET}d
diff --git a/src/lib/libs.qbs b/src/lib/libs.qbs
index b9756b447..e31dd463d 100644
--- a/src/lib/libs.qbs
+++ b/src/lib/libs.qbs
@@ -3,7 +3,6 @@ import qbs
Project {
references: [
"corelib/corelib.qbs",
- "corelib/generators/generators.qbs",
"qtprofilesetup/qtprofilesetup.qbs",
]
}
diff --git a/src/lib/qtprofilesetup/qtenvironment.h b/src/lib/qtprofilesetup/qtenvironment.h
index b3450086f..6b52ab934 100644
--- a/src/lib/qtprofilesetup/qtenvironment.h
+++ b/src/lib/qtprofilesetup/qtenvironment.h
@@ -69,6 +69,10 @@ public:
QStringList qtConfigItems;
QString architecture;
QString qtVersion;
+ QString windowsVersion;
+ QString macosVersion;
+ QString iosVersion;
+ QString androidVersion;
int qtMajorVersion;
int qtMinorVersion;
int qtPatchVersion;
diff --git a/src/lib/qtprofilesetup/qtprofilesetup.cpp b/src/lib/qtprofilesetup/qtprofilesetup.cpp
index 6b09c4e8a..7ad837105 100644
--- a/src/lib/qtprofilesetup/qtprofilesetup.cpp
+++ b/src/lib/qtprofilesetup/qtprofilesetup.cpp
@@ -42,6 +42,7 @@
#include "qtmoduleinfo.h"
#include <logging/translator.h>
+#include <tools/architectures.h>
#include <tools/error.h>
#include <tools/jsliterals.h>
#include <tools/profile.h>
@@ -54,10 +55,10 @@
#include <QtCore/qfileinfo.h>
#include <QtCore/qlibrary.h>
#include <QtCore/qregexp.h>
-#include <QtCore/qregularexpression.h>
#include <QtCore/qtextstream.h>
#include <queue>
+#include <regex>
namespace qbs {
using namespace Internal;
@@ -111,19 +112,18 @@ static QString defaultQpaPlugin(const Profile &profile, const QtModuleInfo &modu
.arg(profile.name(), headerFile.fileName(),
headerFile.errorString()));
}
- static const QRegularExpression regexp(
- QStringLiteral("^#define QT_QPA_DEFAULT_PLATFORM_NAME \"(?<name>.+)\""));
- static const QRegularExpression includeRegexp(
- QStringLiteral("^#include \"(?<header>.+)\""));
+ static const std::regex regexp(
+ "^#define QT_QPA_DEFAULT_PLATFORM_NAME \"(.+)\".*$");
+ static const std::regex includeRegexp(
+ "^#include \"(.+)\".*$");
const QList<QByteArray> lines = headerFile.readAll().split('\n');
for (const QByteArray &line: lines) {
- const QString lineStr = QString::fromLatin1(line.simplified());
- QRegularExpressionMatch match = regexp.match(lineStr);
- if (match.hasMatch())
- return QLatin1Char('q') + match.captured(QStringLiteral("name"));
- match = includeRegexp.match(lineStr);
- if (match.hasMatch()) {
- QString filePath = match.captured(QStringLiteral("header"));
+ const auto lineStr = QString::fromLatin1(line.simplified()).toStdString();
+ std::smatch match;
+ if (std::regex_match(lineStr, match, regexp))
+ return QLatin1Char('q') + QString::fromStdString(match[1]);
+ if (std::regex_match(lineStr, match, includeRegexp)) {
+ QString filePath = QString::fromStdString(match[1]);
if (QFileInfo(filePath).isRelative()) {
filePath = QDir::cleanPath(QFileInfo(headerFile.fileName()).absolutePath()
+ QLatin1Char('/') + filePath);
@@ -139,9 +139,38 @@ static QString defaultQpaPlugin(const Profile &profile, const QtModuleInfo &modu
return QString();
}
+static QByteArray minVersionJsString(const QString &minVersion)
+{
+ if (minVersion.isEmpty())
+ return "original";
+ return utf8JSLiteral(minVersion);
+}
+
+static QString extractQbsArch(const QtEnvironment &qtEnv)
+{
+ QString qbsArch = canonicalArchitecture(qtEnv.architecture);
+ if (qbsArch == QLatin1String("arm") && qtEnv.mkspecPath.contains(QLatin1String("android")))
+ qbsArch = QLatin1String("armv7a");
+ return qbsArch;
+}
+
static void replaceSpecialValues(QByteArray *content, const Profile &profile,
const QtModuleInfo &module, const QtEnvironment &qtEnvironment)
{
+ content->replace("@arch@", utf8JSLiteral(extractQbsArch(qtEnvironment)));
+ content->replace("@config@", utf8JSLiteral(qtEnvironment.configItems));
+ content->replace("@qtConfig@", utf8JSLiteral(qtEnvironment.qtConfigItems));
+ content->replace("@binPath@", utf8JSLiteral(qtEnvironment.binaryPath));
+ content->replace("@libPath@", utf8JSLiteral(qtEnvironment.libraryPath));
+ content->replace("@pluginPath@", utf8JSLiteral(qtEnvironment.pluginPath));
+ content->replace("@incPath@", utf8JSLiteral(qtEnvironment.includePath));
+ content->replace("@docPath@", utf8JSLiteral(qtEnvironment.documentationPath));
+ content->replace("@mkspecPath@", utf8JSLiteral(qtEnvironment.mkspecPath));
+ content->replace("@version@", utf8JSLiteral(qtEnvironment.qtVersion));
+ content->replace("@libInfix@", utf8JSLiteral(qtEnvironment.qtLibInfix));
+ content->replace("@availableBuildVariants@", utf8JSLiteral(qtEnvironment.buildVariant));
+ content->replace("@staticBuild@", utf8JSLiteral(qtEnvironment.staticBuild));
+ content->replace("@frameworkBuild@", utf8JSLiteral(qtEnvironment.frameworkBuild));
content->replace("@name@", utf8JSLiteral(module.moduleNameWithoutPrefix()));
content->replace("@has_library@", utf8JSLiteral(module.hasLibrary));
content->replace("@dependencies@", utf8JSLiteral(module.dependencies));
@@ -165,6 +194,11 @@ static void replaceSpecialValues(QByteArray *content, const Profile &profile,
utf8JSLiteral(module.libNameForLinker(qtEnvironment, false)));
content->replace("@entryPointLibsDebug@", utf8JSLiteral(qtEnvironment.entryPointLibsDebug));
content->replace("@entryPointLibsRelease@", utf8JSLiteral(qtEnvironment.entryPointLibsRelease));
+ content->replace("@minWinVersion@", minVersionJsString(qtEnvironment.windowsVersion));
+ content->replace("@minMacVersion@", minVersionJsString(qtEnvironment.macosVersion));
+ content->replace("@minIosVersion@", minVersionJsString(qtEnvironment.iosVersion));
+ content->replace("@minAndroidVersion@", minVersionJsString(qtEnvironment.androidVersion));
+
QByteArray propertiesString;
QByteArray compilerDefines = utf8JSLiteral(module.compilerDefines);
if (module.qbsName == QLatin1String("declarative")
@@ -378,38 +412,17 @@ void doSetupQtProfile(const QString &profileName, Settings *settings,
if (qtEnvironment.qtConfigItems.contains(QLatin1String("c++11")) && qtEnvironment.staticBuild)
qtEnvironment.configItems.append(QLatin1String("c++11"));
- Profile profile(profileName, settings);
- profile.removeProfile();
- const QString settingsTemplate(QLatin1String("Qt.core.%1"));
- profile.setValue(settingsTemplate.arg(QLatin1String("config")), qtEnvironment.configItems);
- profile.setValue(settingsTemplate.arg(QLatin1String("qtConfig")), qtEnvironment.qtConfigItems);
- profile.setValue(settingsTemplate.arg(QLatin1String("binPath")), qtEnvironment.binaryPath);
- profile.setValue(settingsTemplate.arg(QLatin1String("libPath")), qtEnvironment.libraryPath);
- profile.setValue(settingsTemplate.arg(QLatin1String("pluginPath")), qtEnvironment.pluginPath);
- profile.setValue(settingsTemplate.arg(QLatin1String("incPath")), qtEnvironment.includePath);
- profile.setValue(settingsTemplate.arg(QLatin1String("mkspecPath")), qtEnvironment.mkspecPath);
- profile.setValue(settingsTemplate.arg(QLatin1String("docPath")),
- qtEnvironment.documentationPath);
- profile.setValue(settingsTemplate.arg(QLatin1String("version")), qtEnvironment.qtVersion);
- profile.setValue(settingsTemplate.arg(QLatin1String("libInfix")), qtEnvironment.qtLibInfix);
- profile.setValue(settingsTemplate.arg(QLatin1String("availableBuildVariants")),
- qtEnvironment.buildVariant);
- profile.setValue(settingsTemplate.arg(QLatin1String("staticBuild")), qtEnvironment.staticBuild);
-
// Set the minimum operating system versions appropriate for this Qt version
- const QString windowsVersion = guessMinimumWindowsVersion(qtEnvironment);
- QString macosVersion, iosVersion, androidVersion;
-
- if (!windowsVersion.isEmpty()) { // Is target OS Windows?
+ qtEnvironment.windowsVersion = guessMinimumWindowsVersion(qtEnvironment);
+ if (!qtEnvironment.windowsVersion.isEmpty()) { // Is target OS Windows?
const Version qtVersion = Version(qtEnvironment.qtMajorVersion,
qtEnvironment.qtMinorVersion,
qtEnvironment.qtPatchVersion);
qtEnvironment.entryPointLibsDebug = fillEntryPointLibs(qtEnvironment, qtVersion, true);
qtEnvironment.entryPointLibsRelease = fillEntryPointLibs(qtEnvironment, qtVersion, false);
} else if (qtEnvironment.mkspecPath.contains(QLatin1String("macx"))) {
- profile.setValue(settingsTemplate.arg(QLatin1String("frameworkBuild")), qtEnvironment.frameworkBuild);
if (qtEnvironment.qtMajorVersion >= 5) {
- macosVersion = QLatin1String("10.6");
+ qtEnvironment.macosVersion = QLatin1String("10.6");
} else if (qtEnvironment.qtMajorVersion == 4 && qtEnvironment.qtMinorVersion >= 6) {
QDir qconfigDir;
if (qtEnvironment.frameworkBuild) {
@@ -433,44 +446,38 @@ void doSetupQtProfile(const QString &profileName, Settings *settings,
}
} while (!line.isNull());
- if (ts.status() == QTextStream::Ok)
- macosVersion = qtCocoaBuild ? QLatin1String("10.5") : QLatin1String("10.4");
+ if (ts.status() == QTextStream::Ok) {
+ qtEnvironment.macosVersion = qtCocoaBuild ? QLatin1String("10.5")
+ : QLatin1String("10.4");
+ }
}
- if (macosVersion.isEmpty()) {
+ if (qtEnvironment.macosVersion.isEmpty()) {
throw ErrorInfo(Internal::Tr::tr("Error reading qconfig.h; could not determine "
"whether Qt is using Cocoa or Carbon"));
}
}
if (qtEnvironment.qtConfigItems.contains(QLatin1String("c++11")))
- macosVersion = QLatin1String("10.7");
+ qtEnvironment.macosVersion = QLatin1String("10.7");
}
- if (qtEnvironment.mkspecPath.contains(QLatin1String("ios")) && qtEnvironment.qtMajorVersion >= 5)
- iosVersion = QLatin1String("5.0");
+ if (qtEnvironment.mkspecPath.contains(QLatin1String("ios"))
+ && qtEnvironment.qtMajorVersion >= 5) {
+ qtEnvironment.iosVersion = QLatin1String("5.0");
+ }
if (qtEnvironment.mkspecPath.contains(QLatin1String("android"))) {
if (qtEnvironment.qtMajorVersion >= 5)
- androidVersion = QLatin1String("2.3");
+ qtEnvironment.androidVersion = QLatin1String("2.3");
else if (qtEnvironment.qtMajorVersion == 4 && qtEnvironment.qtMinorVersion >= 8)
- androidVersion = QLatin1String("1.6"); // Necessitas
+ qtEnvironment.androidVersion = QLatin1String("1.6"); // Necessitas
}
// ### TODO: wince, winphone, blackberry
- if (!windowsVersion.isEmpty())
- profile.setValue(QLatin1String("cpp.minimumWindowsVersion"), windowsVersion);
-
- if (!macosVersion.isEmpty())
- profile.setValue(QLatin1String("cpp.minimumMacosVersion"), macosVersion);
-
- if (!iosVersion.isEmpty())
- profile.setValue(QLatin1String("cpp.minimumIosVersion"), iosVersion);
-
- if (!androidVersion.isEmpty())
- profile.setValue(QLatin1String("cpp.minimumAndroidVersion"), androidVersion);
-
+ Profile profile(profileName, settings);
+ profile.removeProfile();
createModules(profile, settings, qtEnvironment);
}
diff --git a/src/lib/qtprofilesetup/templates/QtModule.qbs b/src/lib/qtprofilesetup/templates/QtModule.qbs
index 07618bf20..6291bae01 100644
--- a/src/lib/qtprofilesetup/templates/QtModule.qbs
+++ b/src/lib/qtprofilesetup/templates/QtModule.qbs
@@ -2,6 +2,8 @@ import qbs 1.0
import qbs.FileInfo
Module {
+ condition: !qbs.architecture || architecture === qbs.architecture
+
Depends { name: "cpp" }
Depends { name: "Qt.core" }
@@ -23,6 +25,7 @@ Module {
property bool isStaticLibrary: false
property bool isPlugin: false
+ property string architecture
property stringList staticLibsDebug
property stringList staticLibsRelease
property stringList dynamicLibsDebug
diff --git a/src/lib/qtprofilesetup/templates/core.qbs b/src/lib/qtprofilesetup/templates/core.qbs
index dae5f8a20..9dd56cfab 100644
--- a/src/lib/qtprofilesetup/templates/core.qbs
+++ b/src/lib/qtprofilesetup/templates/core.qbs
@@ -8,35 +8,39 @@ import "moc.js" as Moc
import "qdoc.js" as Qdoc
Module {
+ condition: !qbs.architecture || architecture === qbs.architecture
+
id: qtcore
Depends { name: "cpp" }
- property string libInfix: ""
- property stringList config
- property stringList qtConfig
- property path binPath
- property path incPath
- property path libPath
- property path pluginPath
- property path mkspecPath
+ version: @version@
+ property string architecture: @arch@
+ property string libInfix: @libInfix@
+ property stringList config: @config@
+ property stringList qtConfig: @qtConfig@
+ property path binPath: @binPath@
+ property path incPath: @incPath@
+ property path libPath: @libPath@
+ property path pluginPath: @pluginPath@
+ property path mkspecPath: @mkspecPath@
property string mocName: "moc"
property stringList mocFlags: []
property string lreleaseName: "lrelease"
property string qdocName: versionMajor >= 5 ? "qdoc" : "qdoc3"
property stringList qdocEnvironment
- property path docPath
+ property path docPath: @docPath@
property stringList helpGeneratorArgs: versionMajor >= 5 ? ["-platform", "minimal"] : []
property var versionParts: version ? version.split('.').map(function(item) { return parseInt(item, 10); }) : []
property int versionMajor: versionParts[0]
property int versionMinor: versionParts[1]
property int versionPatch: versionParts[2]
- property bool frameworkBuild
- property bool staticBuild
+ property bool frameworkBuild: @frameworkBuild@
+ property bool staticBuild: @staticBuild@
property stringList pluginMetaData: []
property bool enableKeywords: true
- property stringList availableBuildVariants
+ property stringList availableBuildVariants: @availableBuildVariants@
property string qtBuildVariant: {
if (availableBuildVariants.contains(qbs.buildVariant))
return qbs.buildVariant;
@@ -167,6 +171,10 @@ Module {
return "libc++";
return original;
}
+ cpp.minimumWindowsVersion: @minWinVersion@
+ cpp.minimumMacosVersion: @minMacVersion@
+ cpp.minimumIosVersion: @minIosVersion@
+ cpp.minimumAndroidVersion: @minAndroidVersion@
additionalProductTypes: ["qm"]
diff --git a/src/lib/qtprofilesetup/templates/dbus.qbs b/src/lib/qtprofilesetup/templates/dbus.qbs
index 3ab85966f..4e25536a5 100644
--- a/src/lib/qtprofilesetup/templates/dbus.qbs
+++ b/src/lib/qtprofilesetup/templates/dbus.qbs
@@ -47,6 +47,7 @@ QtModule {
}
}
+ architecture: @arch@
staticLibsDebug: @staticLibsDebug@
staticLibsRelease: @staticLibsRelease@
dynamicLibsDebug: @dynamicLibsDebug@
diff --git a/src/lib/qtprofilesetup/templates/gui.qbs b/src/lib/qtprofilesetup/templates/gui.qbs
index 48d839af1..0598cd1eb 100644
--- a/src/lib/qtprofilesetup/templates/gui.qbs
+++ b/src/lib/qtprofilesetup/templates/gui.qbs
@@ -33,6 +33,7 @@ QtModule {
}
property string defaultQpaPlugin: @defaultQpaPlugin@
+ architecture: @arch@
staticLibsDebug: @staticLibsDebug@
staticLibsRelease: @staticLibsRelease@
dynamicLibsDebug: @dynamicLibsDebug@
diff --git a/src/lib/qtprofilesetup/templates/module.qbs b/src/lib/qtprofilesetup/templates/module.qbs
index 4d5b80219..ada143038 100644
--- a/src/lib/qtprofilesetup/templates/module.qbs
+++ b/src/lib/qtprofilesetup/templates/module.qbs
@@ -5,6 +5,7 @@ QtModule {
qtModuleName: @name@
Depends { name: "Qt"; submodules: @dependencies@}
+ architecture: @arch@
hasLibrary: @has_library@
staticLibsDebug: @staticLibsDebug@
staticLibsRelease: @staticLibsRelease@
diff --git a/src/lib/qtprofilesetup/templates/plugin.qbs b/src/lib/qtprofilesetup/templates/plugin.qbs
index 3a07a363b..943bc8f1e 100644
--- a/src/lib/qtprofilesetup/templates/plugin.qbs
+++ b/src/lib/qtprofilesetup/templates/plugin.qbs
@@ -6,6 +6,7 @@ QtPlugin {
Depends { name: "Qt"; submodules: @dependencies@}
className: @className@
+ architecture: @arch@
staticLibsDebug: @staticLibsDebug@
staticLibsRelease: @staticLibsRelease@
dynamicLibsDebug: @dynamicLibsDebug@
diff --git a/src/lib/qtprofilesetup/templates/qml.qbs b/src/lib/qtprofilesetup/templates/qml.qbs
index cea3ab85a..0f3a9cb77 100644
--- a/src/lib/qtprofilesetup/templates/qml.qbs
+++ b/src/lib/qtprofilesetup/templates/qml.qbs
@@ -15,6 +15,7 @@ QtModule {
readonly property string pluginListFilePathRelease: product.buildDirectory + "/plugins.list"
hasLibrary: @has_library@
+ architecture: @arch@
staticLibsDebug: (isStaticLibrary ? ['@' + pluginListFilePathDebug] : []).concat(@staticLibsDebug@)
staticLibsRelease: (isStaticLibrary ? ['@' + pluginListFilePathRelease] : []).concat(@staticLibsRelease@)
dynamicLibsDebug: @dynamicLibsDebug@
@@ -39,29 +40,11 @@ QtModule {
fileTags: ["qt.qml.qml"]
}
- // This is needed for the case that there are no QML files in the project.
Rule {
condition: isStaticLibrary
multiplex: true
- Artifact {
- filePath: "qml_plugin_import.dummy"
- fileTags: ["qt.qml.import_dummy"]
- }
- prepare: {
- var cmd = new JavaScriptCommand();
- cmd.silent = true;
- cmd.sourceCode = function() {
- var f = new TextFile(output.filePath, TextFile.WriteOnly);
- f.close();
- }
- return [cmd];
- }
- }
-
- Rule {
- condition: isStaticLibrary
- multiplex: true
- inputs: ["qt.qml.qml", "qt.qml.import_dummy"]
+ requiresInputs: false
+ inputs: ["qt.qml.qml"]
outputFileTags: ["cpp", "qt.qml.pluginlist"]
outputArtifacts: {
var list = [];
diff --git a/src/lib/qtprofilesetup/templates/scxml.qbs b/src/lib/qtprofilesetup/templates/scxml.qbs
index 206d914a2..73a377798 100644
--- a/src/lib/qtprofilesetup/templates/scxml.qbs
+++ b/src/lib/qtprofilesetup/templates/scxml.qbs
@@ -45,6 +45,7 @@ QtModule {
}
}
+ architecture: @arch@
staticLibsDebug: @staticLibsDebug@
staticLibsRelease: @staticLibsRelease@
dynamicLibsDebug: @dynamicLibsDebug@
diff --git a/src/plugins/generator/clangcompilationdb/clangcompilationdb.pro b/src/plugins/generator/clangcompilationdb/clangcompilationdb.pro
new file mode 100644
index 000000000..030051271
--- /dev/null
+++ b/src/plugins/generator/clangcompilationdb/clangcompilationdb.pro
@@ -0,0 +1,12 @@
+include(../../plugins.pri)
+
+TARGET = clangcompilationdbgenerator
+
+QT = core
+
+HEADERS += \
+ $$PWD/clangcompilationdbgenerator.h
+
+SOURCES += \
+ $$PWD/clangcompilationdbgenerator.cpp \
+ $$PWD/clangcompilationdbgeneratorplugin.cpp
diff --git a/src/plugins/generator/clangcompilationdb/clangcompilationdb.qbs b/src/plugins/generator/clangcompilationdb/clangcompilationdb.qbs
new file mode 100644
index 000000000..741d6dbf0
--- /dev/null
+++ b/src/plugins/generator/clangcompilationdb/clangcompilationdb.qbs
@@ -0,0 +1,11 @@
+import qbs
+import "../../qbsplugin.qbs" as QbsPlugin
+
+QbsPlugin {
+ name: "clangcompilationdbgenerator"
+ files: [
+ "clangcompilationdbgenerator.cpp",
+ "clangcompilationdbgenerator.h",
+ "clangcompilationdbgeneratorplugin.cpp"
+ ]
+}
diff --git a/src/lib/corelib/generators/clangcompilationdb/clangcompilationdbgenerator.cpp b/src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.cpp
index a3407cb09..a3407cb09 100644
--- a/src/lib/corelib/generators/clangcompilationdb/clangcompilationdbgenerator.cpp
+++ b/src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.cpp
diff --git a/src/lib/corelib/generators/clangcompilationdb/clangcompilationdbgenerator.h b/src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.h
index 5a8505073..5a8505073 100644
--- a/src/lib/corelib/generators/clangcompilationdb/clangcompilationdbgenerator.h
+++ b/src/plugins/generator/clangcompilationdb/clangcompilationdbgenerator.h
diff --git a/src/plugins/generator/clangcompilationdb/clangcompilationdbgeneratorplugin.cpp b/src/plugins/generator/clangcompilationdb/clangcompilationdbgeneratorplugin.cpp
new file mode 100644
index 000000000..ab0e713aa
--- /dev/null
+++ b/src/plugins/generator/clangcompilationdb/clangcompilationdbgeneratorplugin.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "clangcompilationdbgenerator.h"
+
+#include <tools/projectgeneratormanager.h>
+#include <tools/qbspluginmanager.h>
+
+static void QbsClangDbGeneratorPluginLoad()
+{
+ qbs::ProjectGeneratorManager::registerGenerator(
+ std::make_shared<qbs::ClangCompilationDatabaseGenerator>());
+}
+
+static void QbsClangDbGeneratorPluginUnload()
+{
+}
+
+#ifndef GENERATOR_EXPORT
+#if defined(WIN32) || defined(_WIN32)
+#define GENERATOR_EXPORT __declspec(dllexport)
+#else
+#define GENERATOR_EXPORT __attribute__((visibility("default")))
+#endif
+#endif
+
+QBS_REGISTER_STATIC_PLUGIN(extern "C" GENERATOR_EXPORT, QbsClangDbGeneratorPlugin,
+ QbsClangDbGeneratorPluginLoad, QbsClangDbGeneratorPluginUnload)
diff --git a/src/plugins/generator/generator.pro b/src/plugins/generator/generator.pro
new file mode 100644
index 000000000..955e3f84f
--- /dev/null
+++ b/src/plugins/generator/generator.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = clangcompilationdb visualstudio
diff --git a/src/lib/corelib/generators/visualstudio/io/msbuildprojectwriter.cpp b/src/plugins/generator/visualstudio/io/msbuildprojectwriter.cpp
index f912f3a19..f912f3a19 100644
--- a/src/lib/corelib/generators/visualstudio/io/msbuildprojectwriter.cpp
+++ b/src/plugins/generator/visualstudio/io/msbuildprojectwriter.cpp
diff --git a/src/lib/corelib/generators/visualstudio/io/msbuildprojectwriter.h b/src/plugins/generator/visualstudio/io/msbuildprojectwriter.h
index c70889971..c70889971 100644
--- a/src/lib/corelib/generators/visualstudio/io/msbuildprojectwriter.h
+++ b/src/plugins/generator/visualstudio/io/msbuildprojectwriter.h
diff --git a/src/lib/corelib/generators/visualstudio/io/visualstudiosolutionwriter.cpp b/src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.cpp
index 99180e2e2..99180e2e2 100644
--- a/src/lib/corelib/generators/visualstudio/io/visualstudiosolutionwriter.cpp
+++ b/src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.cpp
diff --git a/src/lib/corelib/generators/visualstudio/io/visualstudiosolutionwriter.h b/src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.h
index d5b0107f0..d5b0107f0 100644
--- a/src/lib/corelib/generators/visualstudio/io/visualstudiosolutionwriter.h
+++ b/src/plugins/generator/visualstudio/io/visualstudiosolutionwriter.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildgroup.cpp b/src/plugins/generator/visualstudio/msbuild/imsbuildgroup.cpp
index c51f0e517..c51f0e517 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildgroup.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/imsbuildgroup.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildgroup.h b/src/plugins/generator/visualstudio/msbuild/imsbuildgroup.h
index 4d2436e52..4d2436e52 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildgroup.h
+++ b/src/plugins/generator/visualstudio/msbuild/imsbuildgroup.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildnode.cpp b/src/plugins/generator/visualstudio/msbuild/imsbuildnode.cpp
index 4c70405c2..4c70405c2 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildnode.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/imsbuildnode.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildnode.h b/src/plugins/generator/visualstudio/msbuild/imsbuildnode.h
index 67fb10081..67fb10081 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildnode.h
+++ b/src/plugins/generator/visualstudio/msbuild/imsbuildnode.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildnodevisitor.h b/src/plugins/generator/visualstudio/msbuild/imsbuildnodevisitor.h
index fe75c23f9..fe75c23f9 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildnodevisitor.h
+++ b/src/plugins/generator/visualstudio/msbuild/imsbuildnodevisitor.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildproperty.cpp b/src/plugins/generator/visualstudio/msbuild/imsbuildproperty.cpp
index 6e54f1e43..6e54f1e43 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildproperty.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/imsbuildproperty.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildproperty.h b/src/plugins/generator/visualstudio/msbuild/imsbuildproperty.h
index a1a7676e6..a1a7676e6 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/imsbuildproperty.h
+++ b/src/plugins/generator/visualstudio/msbuild/imsbuildproperty.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildclcompile.cpp b/src/plugins/generator/visualstudio/msbuild/items/msbuildclcompile.cpp
index d8a587454..d8a587454 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildclcompile.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildclcompile.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildclcompile.h b/src/plugins/generator/visualstudio/msbuild/items/msbuildclcompile.h
index 745c3ed7f..745c3ed7f 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildclcompile.h
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildclcompile.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildclinclude.cpp b/src/plugins/generator/visualstudio/msbuild/items/msbuildclinclude.cpp
index d9c61bece..d9c61bece 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildclinclude.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildclinclude.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildclinclude.h b/src/plugins/generator/visualstudio/msbuild/items/msbuildclinclude.h
index cfe31022f..cfe31022f 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildclinclude.h
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildclinclude.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildfileitem.cpp b/src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.cpp
index bce7488b4..bce7488b4 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildfileitem.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildfileitem.h b/src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.h
index d6e4d485b..d6e4d485b 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildfileitem.h
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildfileitem.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildfilter.cpp b/src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.cpp
index 3a5d98a98..3a5d98a98 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildfilter.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildfilter.h b/src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.h
index 344783a1e..344783a1e 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildfilter.h
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildfilter.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildlink.cpp b/src/plugins/generator/visualstudio/msbuild/items/msbuildlink.cpp
index cae1a63a3..cae1a63a3 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildlink.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildlink.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildlink.h b/src/plugins/generator/visualstudio/msbuild/items/msbuildlink.h
index caf125440..caf125440 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildlink.h
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildlink.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildnone.cpp b/src/plugins/generator/visualstudio/msbuild/items/msbuildnone.cpp
index a590c6e9f..a590c6e9f 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildnone.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildnone.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildnone.h b/src/plugins/generator/visualstudio/msbuild/items/msbuildnone.h
index 98dac7a76..98dac7a76 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/items/msbuildnone.h
+++ b/src/plugins/generator/visualstudio/msbuild/items/msbuildnone.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuildimport.cpp b/src/plugins/generator/visualstudio/msbuild/msbuildimport.cpp
index a0c693aff..a0c693aff 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuildimport.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildimport.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuildimport.h b/src/plugins/generator/visualstudio/msbuild/msbuildimport.h
index 352616e1b..352616e1b 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuildimport.h
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildimport.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuildimportgroup.cpp b/src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.cpp
index 56c48049e..56c48049e 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuildimportgroup.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuildimportgroup.h b/src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.h
index c2f0b8fc7..c2f0b8fc7 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuildimportgroup.h
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildimportgroup.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditem.cpp b/src/plugins/generator/visualstudio/msbuild/msbuilditem.cpp
index 9a2ffb734..9a2ffb734 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditem.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuilditem.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditem.h b/src/plugins/generator/visualstudio/msbuild/msbuilditem.h
index ca411c715..ca411c715 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditem.h
+++ b/src/plugins/generator/visualstudio/msbuild/msbuilditem.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp b/src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp
index 5228e850e..5228e850e 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditemdefinitiongroup.h b/src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.h
index a96f0fff8..a96f0fff8 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditemdefinitiongroup.h
+++ b/src/plugins/generator/visualstudio/msbuild/msbuilditemdefinitiongroup.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditemgroup.cpp b/src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.cpp
index 7a9bd122b..7a9bd122b 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditemgroup.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditemgroup.h b/src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.h
index 02ac6b082..02ac6b082 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditemgroup.h
+++ b/src/plugins/generator/visualstudio/msbuild/msbuilditemgroup.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditemmetadata.cpp b/src/plugins/generator/visualstudio/msbuild/msbuilditemmetadata.cpp
index daaa4c6b3..daaa4c6b3 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditemmetadata.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuilditemmetadata.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditemmetadata.h b/src/plugins/generator/visualstudio/msbuild/msbuilditemmetadata.h
index 7a42f1736..7a42f1736 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuilditemmetadata.h
+++ b/src/plugins/generator/visualstudio/msbuild/msbuilditemmetadata.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuildproject.cpp b/src/plugins/generator/visualstudio/msbuild/msbuildproject.cpp
index c872622b9..c872622b9 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuildproject.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildproject.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuildproject.h b/src/plugins/generator/visualstudio/msbuild/msbuildproject.h
index fc1a0f1f4..fc1a0f1f4 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuildproject.h
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildproject.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuildproperty.cpp b/src/plugins/generator/visualstudio/msbuild/msbuildproperty.cpp
index 410e2a694..410e2a694 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuildproperty.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildproperty.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuildproperty.h b/src/plugins/generator/visualstudio/msbuild/msbuildproperty.h
index 310fcc044..310fcc044 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuildproperty.h
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildproperty.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuildpropertygroup.cpp b/src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.cpp
index 4f9c72939..4f9c72939 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuildpropertygroup.cpp
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuild/msbuildpropertygroup.h b/src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.h
index 33fa07b3e..33fa07b3e 100644
--- a/src/lib/corelib/generators/visualstudio/msbuild/msbuildpropertygroup.h
+++ b/src/plugins/generator/visualstudio/msbuild/msbuildpropertygroup.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuildfiltersproject.cpp b/src/plugins/generator/visualstudio/msbuildfiltersproject.cpp
index 45a09236a..45a09236a 100644
--- a/src/lib/corelib/generators/visualstudio/msbuildfiltersproject.cpp
+++ b/src/plugins/generator/visualstudio/msbuildfiltersproject.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuildfiltersproject.h b/src/plugins/generator/visualstudio/msbuildfiltersproject.h
index 521a6e610..521a6e610 100644
--- a/src/lib/corelib/generators/visualstudio/msbuildfiltersproject.h
+++ b/src/plugins/generator/visualstudio/msbuildfiltersproject.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuildqbsgenerateproject.cpp b/src/plugins/generator/visualstudio/msbuildqbsgenerateproject.cpp
index 51c72ecd3..51c72ecd3 100644
--- a/src/lib/corelib/generators/visualstudio/msbuildqbsgenerateproject.cpp
+++ b/src/plugins/generator/visualstudio/msbuildqbsgenerateproject.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuildqbsgenerateproject.h b/src/plugins/generator/visualstudio/msbuildqbsgenerateproject.h
index 433bd31a1..433bd31a1 100644
--- a/src/lib/corelib/generators/visualstudio/msbuildqbsgenerateproject.h
+++ b/src/plugins/generator/visualstudio/msbuildqbsgenerateproject.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuildqbsproductproject.cpp b/src/plugins/generator/visualstudio/msbuildqbsproductproject.cpp
index fc9187ae2..fc9187ae2 100644
--- a/src/lib/corelib/generators/visualstudio/msbuildqbsproductproject.cpp
+++ b/src/plugins/generator/visualstudio/msbuildqbsproductproject.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuildqbsproductproject.h b/src/plugins/generator/visualstudio/msbuildqbsproductproject.h
index 7fb9e2a39..7fb9e2a39 100644
--- a/src/lib/corelib/generators/visualstudio/msbuildqbsproductproject.h
+++ b/src/plugins/generator/visualstudio/msbuildqbsproductproject.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuildsharedsolutionpropertiesproject.cpp b/src/plugins/generator/visualstudio/msbuildsharedsolutionpropertiesproject.cpp
index d8389817f..d8389817f 100644
--- a/src/lib/corelib/generators/visualstudio/msbuildsharedsolutionpropertiesproject.cpp
+++ b/src/plugins/generator/visualstudio/msbuildsharedsolutionpropertiesproject.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuildsharedsolutionpropertiesproject.h b/src/plugins/generator/visualstudio/msbuildsharedsolutionpropertiesproject.h
index f3848ce24..f3848ce24 100644
--- a/src/lib/corelib/generators/visualstudio/msbuildsharedsolutionpropertiesproject.h
+++ b/src/plugins/generator/visualstudio/msbuildsharedsolutionpropertiesproject.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuildsolutionpropertiesproject.cpp b/src/plugins/generator/visualstudio/msbuildsolutionpropertiesproject.cpp
index b0572e2e0..b0572e2e0 100644
--- a/src/lib/corelib/generators/visualstudio/msbuildsolutionpropertiesproject.cpp
+++ b/src/plugins/generator/visualstudio/msbuildsolutionpropertiesproject.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuildsolutionpropertiesproject.h b/src/plugins/generator/visualstudio/msbuildsolutionpropertiesproject.h
index 1c49f7901..1c49f7901 100644
--- a/src/lib/corelib/generators/visualstudio/msbuildsolutionpropertiesproject.h
+++ b/src/plugins/generator/visualstudio/msbuildsolutionpropertiesproject.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuildtargetproject.cpp b/src/plugins/generator/visualstudio/msbuildtargetproject.cpp
index 9a1d00476..9a1d00476 100644
--- a/src/lib/corelib/generators/visualstudio/msbuildtargetproject.cpp
+++ b/src/plugins/generator/visualstudio/msbuildtargetproject.cpp
diff --git a/src/lib/corelib/generators/visualstudio/msbuildtargetproject.h b/src/plugins/generator/visualstudio/msbuildtargetproject.h
index 13d890d72..13d890d72 100644
--- a/src/lib/corelib/generators/visualstudio/msbuildtargetproject.h
+++ b/src/plugins/generator/visualstudio/msbuildtargetproject.h
diff --git a/src/lib/corelib/generators/visualstudio/msbuildutils.h b/src/plugins/generator/visualstudio/msbuildutils.h
index 3eceeba2e..3eceeba2e 100644
--- a/src/lib/corelib/generators/visualstudio/msbuildutils.h
+++ b/src/plugins/generator/visualstudio/msbuildutils.h
diff --git a/src/lib/corelib/generators/visualstudio/solution/ivisualstudiosolutionproject.cpp b/src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.cpp
index f3a6a0cbd..f3a6a0cbd 100644
--- a/src/lib/corelib/generators/visualstudio/solution/ivisualstudiosolutionproject.cpp
+++ b/src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.cpp
diff --git a/src/lib/corelib/generators/visualstudio/solution/ivisualstudiosolutionproject.h b/src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.h
index 17de66e73..17de66e73 100644
--- a/src/lib/corelib/generators/visualstudio/solution/ivisualstudiosolutionproject.h
+++ b/src/plugins/generator/visualstudio/solution/ivisualstudiosolutionproject.h
diff --git a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolution.cpp b/src/plugins/generator/visualstudio/solution/visualstudiosolution.cpp
index a6d572425..a6d572425 100644
--- a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolution.cpp
+++ b/src/plugins/generator/visualstudio/solution/visualstudiosolution.cpp
diff --git a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolution.h b/src/plugins/generator/visualstudio/solution/visualstudiosolution.h
index 16f06f9e9..16f06f9e9 100644
--- a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolution.h
+++ b/src/plugins/generator/visualstudio/solution/visualstudiosolution.h
diff --git a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionfileproject.cpp b/src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.cpp
index d66f47cf7..d66f47cf7 100644
--- a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionfileproject.cpp
+++ b/src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.cpp
diff --git a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionfileproject.h b/src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.h
index fafafa494..fafafa494 100644
--- a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionfileproject.h
+++ b/src/plugins/generator/visualstudio/solution/visualstudiosolutionfileproject.h
diff --git a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionfolderproject.cpp b/src/plugins/generator/visualstudio/solution/visualstudiosolutionfolderproject.cpp
index d59d1e1ed..d59d1e1ed 100644
--- a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionfolderproject.cpp
+++ b/src/plugins/generator/visualstudio/solution/visualstudiosolutionfolderproject.cpp
diff --git a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionfolderproject.h b/src/plugins/generator/visualstudio/solution/visualstudiosolutionfolderproject.h
index a7fd180cc..a7fd180cc 100644
--- a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionfolderproject.h
+++ b/src/plugins/generator/visualstudio/solution/visualstudiosolutionfolderproject.h
diff --git a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionglobalsection.cpp b/src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.cpp
index 1e4f5fd01..1e4f5fd01 100644
--- a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionglobalsection.cpp
+++ b/src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.cpp
diff --git a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionglobalsection.h b/src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.h
index dd821fce0..dd821fce0 100644
--- a/src/lib/corelib/generators/visualstudio/solution/visualstudiosolutionglobalsection.h
+++ b/src/plugins/generator/visualstudio/solution/visualstudiosolutionglobalsection.h
diff --git a/src/lib/corelib/generators/visualstudio/visualstudio.pri b/src/plugins/generator/visualstudio/visualstudio.pro
index e7615d8cd..7f464f1ce 100644
--- a/src/lib/corelib/generators/visualstudio/visualstudio.pri
+++ b/src/plugins/generator/visualstudio/visualstudio.pro
@@ -1,3 +1,9 @@
+include(../../plugins.pri)
+
+TARGET = visualstudiogenerator
+
+QT = core
+
HEADERS += \
$$PWD/msbuildfiltersproject.h \
$$PWD/msbuildqbsgenerateproject.h \
@@ -17,6 +23,7 @@ SOURCES += \
$$PWD/msbuildsolutionpropertiesproject.cpp \
$$PWD/msbuildtargetproject.cpp \
$$PWD/visualstudiogenerator.cpp \
+ $$PWD/visualstudiogeneratorplugin.cpp \
$$PWD/visualstudioguidpool.cpp
HEADERS += \
diff --git a/src/lib/corelib/generators/visualstudio/visualstudio.qbs b/src/plugins/generator/visualstudio/visualstudio.qbs
index 44694d8d2..cb22ea5d9 100644
--- a/src/lib/corelib/generators/visualstudio/visualstudio.qbs
+++ b/src/plugins/generator/visualstudio/visualstudio.qbs
@@ -1,16 +1,10 @@
import qbs
+import "../../qbsplugin.qbs" as QbsPlugin
-QbsLibrary {
- type: ["staticlibrary"]
+QbsPlugin {
name: "visualstudiogenerator"
- install: false
- cpp.includePaths: base.concat([
- "../..",
- ])
-
- Depends { name: "cpp" }
- Depends { name: "Qt.core" }
+ files: ["visualstudiogeneratorplugin.cpp"]
Group {
name: "Visual Studio generator"
diff --git a/src/lib/corelib/generators/visualstudio/visualstudiogenerator.cpp b/src/plugins/generator/visualstudio/visualstudiogenerator.cpp
index 179232114..5b69ade31 100644
--- a/src/lib/corelib/generators/visualstudio/visualstudiogenerator.cpp
+++ b/src/plugins/generator/visualstudio/visualstudiogenerator.cpp
@@ -56,7 +56,6 @@
#include <tools/visualstudioversioninfo.h>
#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
#include <QtCore/qfile.h>
#include <QtCore/qfileinfo.h>
@@ -74,10 +73,10 @@ public:
Internal::VisualStudioVersionInfo versionInfo;
- QSharedPointer<VisualStudioGuidPool> guidPool;
- QSharedPointer<VisualStudioSolution> solution;
+ std::shared_ptr<VisualStudioGuidPool> guidPool;
+ std::shared_ptr<VisualStudioSolution> solution;
QString solutionFilePath;
- QMap<QString, QSharedPointer<MSBuildProject>> msbuildProjects;
+ QMap<QString, std::shared_ptr<MSBuildProject>> msbuildProjects;
QMap<QString, VisualStudioSolutionFileProject *> solutionProjects;
QMap<GeneratableProjectData::Id, VisualStudioSolutionFolderProject *> solutionFolders;
QList<std::pair<QString, bool>> propertySheetNames;
@@ -106,7 +105,7 @@ public:
void visitProject(const GeneratableProject &project) override {
Q_UNUSED(project);
nestedProjects = new VisualStudioSolutionGlobalSection(
- QStringLiteral("NestedProjects"), generator->d->solution.data());
+ QStringLiteral("NestedProjects"), generator->d->solution.get());
generator->d->solution->appendGlobalSection(nestedProjects);
}
@@ -172,7 +171,7 @@ void VisualStudioGenerator::addPropertySheets(const GeneratableProject &project)
const auto fileName = QStringLiteral("qbs.props");
d->propertySheetNames.append({ fileName, true });
d->msbuildProjects.insert(project.baseBuildDirectory().absoluteFilePath(fileName),
- QSharedPointer<MSBuildSolutionPropertiesProject>::create(
+ std::make_shared<MSBuildSolutionPropertiesProject>(
d->versionInfo, project,
qbsExecutableFilePath(), qbsSettingsDir()));
}
@@ -181,14 +180,14 @@ void VisualStudioGenerator::addPropertySheets(const GeneratableProject &project)
const auto fileName = QStringLiteral("qbs-shared.props");
d->propertySheetNames.append({ fileName, false });
d->msbuildProjects.insert(project.baseBuildDirectory().absoluteFilePath(fileName),
- QSharedPointer<MSBuildSharedSolutionPropertiesProject>::create(
+ std::make_shared<MSBuildSharedSolutionPropertiesProject>(
d->versionInfo, project,
qbsExecutableFilePath(), qbsSettingsDir()));
}
}
void VisualStudioGenerator::addPropertySheets(
- const QSharedPointer<MSBuildTargetProject> &targetProject)
+ const std::shared_ptr<MSBuildTargetProject> &targetProject)
{
for (const auto &pair : d->propertySheetNames) {
targetProject->appendPropertySheet(
@@ -243,10 +242,10 @@ static void addDefaultGlobalSections(const GeneratableProject &topLevelProject,
QStringLiteral("FALSE"));
}
-static void writeProjectFiles(const QMap<QString, QSharedPointer<MSBuildProject>> &projects)
+static void writeProjectFiles(const QMap<QString, std::shared_ptr<MSBuildProject>> &projects)
{
// Write out all the MSBuild project files to disk
- QMapIterator<QString, QSharedPointer<MSBuildProject>> it(projects);
+ QMapIterator<QString, std::shared_ptr<MSBuildProject>> it(projects);
while (it.hasNext()) {
it.next();
const auto projectFilePath = it.key();
@@ -254,15 +253,16 @@ static void writeProjectFiles(const QMap<QString, QSharedPointer<MSBuildProject>
if (!file.open())
throw ErrorInfo(Tr::tr("Cannot open %s for writing").arg(projectFilePath));
- QSharedPointer<MSBuildProject> project = it.value();
+ std::shared_ptr<MSBuildProject> project = it.value();
MSBuildProjectWriter writer(file.device());
- if (!(writer.write(project.data()) && file.commit()))
+ if (!(writer.write(project.get()) && file.commit()))
throw ErrorInfo(Tr::tr("Failed to generate %1").arg(projectFilePath));
}
}
-static void writeSolution(const QSharedPointer<VisualStudioSolution> &solution,
- const QString &solutionFilePath)
+static void writeSolution(const std::shared_ptr<VisualStudioSolution> &solution,
+ const QString &solutionFilePath,
+ const Internal::Logger &logger)
{
Internal::FileSaver file(solutionFilePath);
if (!file.open())
@@ -270,10 +270,10 @@ static void writeSolution(const QSharedPointer<VisualStudioSolution> &solution,
VisualStudioSolutionWriter writer(file.device());
writer.setProjectBaseDirectory(QFileInfo(solutionFilePath).path());
- if (!(writer.write(solution.data()) && file.commit()))
+ if (!(writer.write(solution.get()) && file.commit()))
throw ErrorInfo(Tr::tr("Failed to generate %1").arg(solutionFilePath));
- qDebug() << "Generated" << qPrintable(QFileInfo(solutionFilePath).fileName());
+ logger.qbsInfo() << Tr::tr("Generated %1").arg(QFileInfo(solutionFilePath).fileName());
}
void VisualStudioGenerator::generate()
@@ -281,46 +281,36 @@ void VisualStudioGenerator::generate()
GeneratableProjectIterator it(project());
it.accept(this);
- addDefaultGlobalSections(project(), d->solution.data());
+ addDefaultGlobalSections(project(), d->solution.get());
// Second pass: connection solution project interdependencies and project nesting hierarchy
SolutionDependenciesVisitor solutionDependenciesVisitor(this);
it.accept(&solutionDependenciesVisitor);
writeProjectFiles(d->msbuildProjects);
- writeSolution(d->solution, d->solutionFilePath);
+ writeSolution(d->solution, d->solutionFilePath, logger());
d->reset();
}
-std::vector<QSharedPointer<ProjectGenerator> > VisualStudioGenerator::createGeneratorList()
-{
- std::vector<QSharedPointer<ProjectGenerator> > result;
- for (const auto &info : VisualStudioVersionInfo::knownVersions()) {
- if (info.usesMsBuild())
- result.push_back(QSharedPointer<ProjectGenerator>(new VisualStudioGenerator(info)));
- }
- return result;
-}
-
void VisualStudioGenerator::visitProject(const GeneratableProject &project)
{
addPropertySheets(project);
const auto buildDir = project.baseBuildDirectory();
- d->guidPool = QSharedPointer<VisualStudioGuidPool>::create(
+ d->guidPool = std::make_shared<VisualStudioGuidPool>(
buildDir.absoluteFilePath(project.name() + QStringLiteral(".guid.txt")));
d->solutionFilePath = buildDir.absoluteFilePath(project.name() + QStringLiteral(".sln"));
- d->solution = QSharedPointer<VisualStudioSolution>::create(d->versionInfo);
+ d->solution = std::make_shared<VisualStudioSolution>(d->versionInfo);
// Create a helper project to re-run qbs generate
const auto qbsGenerate = QStringLiteral("qbs-generate");
const auto projectFilePath = targetFilePath(qbsGenerate, buildDir.absolutePath());
const auto relativeProjectFilePath = QFileInfo(d->solutionFilePath).dir()
.relativeFilePath(projectFilePath);
- auto targetProject = QSharedPointer<MSBuildQbsGenerateProject>::create(project, d->versionInfo);
+ auto targetProject = std::make_shared<MSBuildQbsGenerateProject>(project, d->versionInfo);
targetProject->setGuid(d->guidPool->drawProductGuid(relativeProjectFilePath));
d->msbuildProjects.insert(projectFilePath, targetProject);
@@ -328,7 +318,7 @@ void VisualStudioGenerator::visitProject(const GeneratableProject &project)
auto solutionProject = new VisualStudioSolutionFileProject(
targetFilePath(qbsGenerate, project.baseBuildDirectory().absolutePath()),
- d->solution.data());
+ d->solution.get());
solutionProject->setGuid(targetProject->guid());
d->solution->appendProject(solutionProject);
d->solutionProjects.insert(qbsGenerate, solutionProject);
@@ -338,7 +328,7 @@ void VisualStudioGenerator::visitProjectData(const GeneratableProject &project,
const GeneratableProjectData &projectData)
{
Q_UNUSED(project);
- auto solutionFolder = new VisualStudioSolutionFolderProject(d->solution.data());
+ auto solutionFolder = new VisualStudioSolutionFolderProject(d->solution.get());
solutionFolder->setName(projectData.name());
d->solution->appendProject(solutionFolder);
QBS_CHECK(!d->solutionFolders.contains(projectData.uniqueName()));
@@ -354,7 +344,7 @@ void VisualStudioGenerator::visitProduct(const GeneratableProject &project,
project.baseBuildDirectory().absolutePath());
const auto relativeProjectFilePath = QFileInfo(d->solutionFilePath)
.dir().relativeFilePath(projectFilePath);
- auto targetProject = QSharedPointer<MSBuildQbsProductProject>::create(project, productData,
+ auto targetProject = std::make_shared<MSBuildQbsProductProject>(project, productData,
d->versionInfo);
targetProject->setGuid(d->guidPool->drawProductGuid(relativeProjectFilePath));
@@ -362,11 +352,11 @@ void VisualStudioGenerator::visitProduct(const GeneratableProject &project,
d->msbuildProjects.insert(projectFilePath, targetProject);
d->msbuildProjects.insert(projectFilePath + QStringLiteral(".filters"),
- QSharedPointer<MSBuildFiltersProject>::create(productData));
+ std::make_shared<MSBuildFiltersProject>(productData));
auto solutionProject = new VisualStudioSolutionFileProject(
targetFilePath(productData, project.baseBuildDirectory().absolutePath()),
- d->solution.data());
+ d->solution.get());
solutionProject->setGuid(targetProject->guid());
d->solution->appendProject(solutionProject);
d->solutionProjects.insert(productData.name(), solutionProject);
diff --git a/src/lib/corelib/generators/visualstudio/visualstudiogenerator.h b/src/plugins/generator/visualstudio/visualstudiogenerator.h
index b8e9ad2ae..8e120d5cc 100644
--- a/src/lib/corelib/generators/visualstudio/visualstudiogenerator.h
+++ b/src/plugins/generator/visualstudio/visualstudiogenerator.h
@@ -61,8 +61,6 @@ public:
QString generatorName() const override;
void generate() override;
- static std::vector<QSharedPointer<ProjectGenerator> > createGeneratorList();
-
private:
virtual void visitProject(const GeneratableProject &project) override;
virtual void visitProjectData(const GeneratableProject &project,
@@ -72,7 +70,7 @@ private:
const GeneratableProductData &productData) override;
void addPropertySheets(const GeneratableProject &project);
- void addPropertySheets(const QSharedPointer<MSBuildTargetProject> &targetProject);
+ void addPropertySheets(const std::shared_ptr<MSBuildTargetProject> &targetProject);
QScopedPointer<VisualStudioGeneratorPrivate> d;
};
diff --git a/src/plugins/generator/visualstudio/visualstudiogeneratorplugin.cpp b/src/plugins/generator/visualstudio/visualstudiogeneratorplugin.cpp
new file mode 100644
index 000000000..9907c27f7
--- /dev/null
+++ b/src/plugins/generator/visualstudio/visualstudiogeneratorplugin.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "visualstudiogenerator.h"
+
+#include <tools/projectgeneratormanager.h>
+#include <tools/qbspluginmanager.h>
+
+static void QbsVisualStudioGeneratorPluginLoad()
+{
+ for (const auto &info : qbs::Internal::VisualStudioVersionInfo::knownVersions()) {
+ if (info.usesMsBuild())
+ qbs::ProjectGeneratorManager::registerGenerator(
+ std::make_shared<qbs::VisualStudioGenerator>(info));
+ }
+}
+
+static void QbsVisualStudioGeneratorPluginUnload()
+{
+}
+
+#ifndef GENERATOR_EXPORT
+#if defined(WIN32) || defined(_WIN32)
+#define GENERATOR_EXPORT __declspec(dllexport)
+#else
+#define GENERATOR_EXPORT __attribute__((visibility("default")))
+#endif
+#endif
+
+QBS_REGISTER_STATIC_PLUGIN(extern "C" GENERATOR_EXPORT, QbsVisualStudioGeneratorPlugin,
+ QbsVisualStudioGeneratorPluginLoad, QbsVisualStudioGeneratorPluginUnload)
diff --git a/src/lib/corelib/generators/visualstudio/visualstudioguidpool.cpp b/src/plugins/generator/visualstudio/visualstudioguidpool.cpp
index 543d64063..543d64063 100644
--- a/src/lib/corelib/generators/visualstudio/visualstudioguidpool.cpp
+++ b/src/plugins/generator/visualstudio/visualstudioguidpool.cpp
diff --git a/src/lib/corelib/generators/visualstudio/visualstudioguidpool.h b/src/plugins/generator/visualstudio/visualstudioguidpool.h
index a21bb1f94..a21bb1f94 100644
--- a/src/lib/corelib/generators/visualstudio/visualstudioguidpool.h
+++ b/src/plugins/generator/visualstudio/visualstudioguidpool.h
diff --git a/src/plugins/plugins.pri b/src/plugins/plugins.pri
index 050d1ceb5..b0eede442 100644
--- a/src/plugins/plugins.pri
+++ b/src/plugins/plugins.pri
@@ -10,7 +10,8 @@ DESTDIR = $${destdirPrefix}/qbs/plugins
CONFIG(static, static|shared) {
DEFINES += QBS_STATIC_LIB
} else {
- DEFINES += QBS_LIBRARY
+ isEmpty(QBSLIBDIR): QBSLIBDIR = $$OUT_PWD/../../../../$${QBS_LIBRARY_DIRNAME}
+ include($${PWD}/../lib/corelib/use_corelib.pri)
}
TEMPLATE = lib
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index d3823ae3e..9fe2e6b5b 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -1,2 +1,2 @@
TEMPLATE = subdirs
-SUBDIRS = scanner
+SUBDIRS = generator scanner
diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs
index eb2fb3610..2eb3670f2 100644
--- a/src/plugins/plugins.qbs
+++ b/src/plugins/plugins.qbs
@@ -3,6 +3,8 @@ import qbs
Project {
name: "qbs plugins"
references: [
+ "generator/clangcompilationdb/clangcompilationdb.qbs",
+ "generator/visualstudio/visualstudio.qbs",
"scanner/cpp/cpp.qbs",
"scanner/qt/qt.qbs"
]
diff --git a/src/plugins/scanner/scannerplugin.qbs b/src/plugins/qbsplugin.qbs
index ae87ca980..5f97a946a 100644
--- a/src/plugins/scanner/scannerplugin.qbs
+++ b/src/plugins/qbsplugin.qbs
@@ -5,9 +5,15 @@ QbsProduct {
Depends { name: "bundle"; condition: qbs.targetOS.contains("darwin") }
Depends { name: "Qt.core" }
Depends { name: "qbsbuildconfig" }
- type: Qt.core.staticBuild ? ["staticlibrary"] : ["dynamiclibrary"]
- cpp.defines: base.concat(type.contains("staticlibrary") ? ["QBS_STATIC_LIB"] : ["QBS_LIBRARY"])
+ Depends { name: "qbscore"; condition: !Qt.core.staticBuild }
+ type: (Qt.core.staticBuild ? ["staticlibrary"] : ["dynamiclibrary"]).concat(["qbsplugin"])
+ Properties {
+ condition: Qt.core.staticBuild
+ cpp.defines: ["QBS_STATIC_LIB"]
+ }
cpp.cxxLanguageVersion: "c++11"
+ cpp.includePaths: base.concat(["../../../lib/corelib"])
+ cpp.visibility: "hidden"
destinationDirectory: qbsbuildconfig.libDirName + "/qbs/plugins"
Group {
fileTagsFilter: ["dynamiclibrary"]
diff --git a/src/plugins/scanner/cpp/cpp.qbs b/src/plugins/scanner/cpp/cpp.qbs
index 33b576253..93a64e7cd 100644
--- a/src/plugins/scanner/cpp/cpp.qbs
+++ b/src/plugins/scanner/cpp/cpp.qbs
@@ -1,7 +1,7 @@
import qbs 1.0
-import "../scannerplugin.qbs" as ScannerPlugin
+import "../../qbsplugin.qbs" as QbsPlugin
-ScannerPlugin {
+QbsPlugin {
cpp.defines: base.concat(["CPLUSPLUS_NO_PARSER"])
name: "qbs_cpp_scanner"
files: [
diff --git a/src/plugins/scanner/cpp/cpp_global.h b/src/plugins/scanner/cpp/cpp_global.h
index 7ffa6e46d..80b101457 100644
--- a/src/plugins/scanner/cpp/cpp_global.h
+++ b/src/plugins/scanner/cpp/cpp_global.h
@@ -43,7 +43,7 @@
#if defined(WIN32) || defined(_WIN32)
#define CPPSCANNER_EXPORT __declspec(dllexport)
#else
-#define CPPSCANNER_EXPORT
+#define CPPSCANNER_EXPORT __attribute__((visibility("default")))
#endif
#endif // CPP_GLOBAL_H
diff --git a/src/plugins/scanner/cpp/cppscanner.cpp b/src/plugins/scanner/cpp/cppscanner.cpp
index 46d16e2f1..2d652b9e2 100644
--- a/src/plugins/scanner/cpp/cppscanner.cpp
+++ b/src/plugins/scanner/cpp/cppscanner.cpp
@@ -43,6 +43,9 @@
using namespace CPlusPlus;
+#include <tools/qbspluginmanager.h>
+#include <tools/scannerpluginmanager.h>
+
#ifdef Q_OS_UNIX
#include <sys/types.h>
#include <sys/stat.h>
@@ -295,8 +298,6 @@ static const char **additionalFileTags(void *opaq, int *size)
return 0;
}
-extern "C" {
-
ScannerPlugin includeScanner =
{
"include_scanner",
@@ -310,11 +311,15 @@ ScannerPlugin includeScanner =
ScannerPlugin *cppScanners[] = { &includeScanner, NULL };
-#ifndef QBS_STATIC_LIB
-CPPSCANNER_EXPORT ScannerPlugin **getScanners()
+static void QbsCppScannerPluginLoad()
{
- return cppScanners;
+ qbs::Internal::ScannerPluginManager::instance()->registerPlugins(cppScanners);
}
-#endif
-} // extern "C"
+static void QbsCppScannerPluginUnload()
+{
+}
+
+QBS_REGISTER_STATIC_PLUGIN(extern "C" CPPSCANNER_EXPORT, QbsCppScannerPlugin,
+ QbsCppScannerPluginLoad, QbsCppScannerPluginUnload)
+
diff --git a/src/plugins/scanner/qt/qt.qbs b/src/plugins/scanner/qt/qt.qbs
index ecc71f8cf..a6aea1c33 100644
--- a/src/plugins/scanner/qt/qt.qbs
+++ b/src/plugins/scanner/qt/qt.qbs
@@ -1,7 +1,7 @@
import qbs 1.0
-import "../scannerplugin.qbs" as ScannerPlugin
+import "../../qbsplugin.qbs" as QbsPlugin
-ScannerPlugin {
+QbsPlugin {
name: "qbs_qt_scanner"
files: [
"../scanner.h",
diff --git a/src/plugins/scanner/qt/qtscanner.cpp b/src/plugins/scanner/qt/qtscanner.cpp
index c53a69fd1..408a65220 100644
--- a/src/plugins/scanner/qt/qtscanner.cpp
+++ b/src/plugins/scanner/qt/qtscanner.cpp
@@ -40,11 +40,14 @@
#if defined(WIN32) || defined(_WIN32)
#define SCANNER_EXPORT __declspec(dllexport)
#else
-#define SCANNER_EXPORT
+#define SCANNER_EXPORT __attribute__((visibility("default")))
#endif
#include "../scanner.h"
+#include <tools/qbspluginmanager.h>
+#include <tools/scannerpluginmanager.h>
+
#include <QtCore/qglobal.h>
#ifdef Q_OS_UNIX
@@ -171,8 +174,6 @@ static const char **additionalFileTagsQrc(void *, int *size)
return 0;
}
-extern "C" {
-
ScannerPlugin qrcScanner =
{
"qt_qrc_scanner",
@@ -186,11 +187,14 @@ ScannerPlugin qrcScanner =
ScannerPlugin *qtScanners[] = {&qrcScanner, NULL};
-#ifndef QBS_STATIC_LIB
-SCANNER_EXPORT ScannerPlugin **getScanners()
+static void QbsQtScannerPluginLoad()
+{
+ qbs::Internal::ScannerPluginManager::instance()->registerPlugins(qtScanners);
+}
+
+static void QbsQtScannerPluginUnload()
{
- return qtScanners;
}
-#endif
-} // extern "C"
+QBS_REGISTER_STATIC_PLUGIN(extern "C" SCANNER_EXPORT, QbsQtScannerPlugin,
+ QbsQtScannerPluginLoad, QbsQtScannerPluginUnload)
diff --git a/src/plugins/scanner/scanner.h b/src/plugins/scanner/scanner.h
index 7843ceec5..0d62a2ea2 100644
--- a/src/plugins/scanner/scanner.h
+++ b/src/plugins/scanner/scanner.h
@@ -100,8 +100,6 @@ public:
int flags;
};
-typedef ScannerPlugin **(*getScanners_f)();
-
#ifdef __cplusplus
}
#endif
diff --git a/static.pro b/static.pro
index b4f15c784..562b68303 100644
--- a/static.pro
+++ b/static.pro
@@ -1,20 +1,33 @@
TEMPLATE = aux
DATA_DIRS = share/qbs/imports share/qbs/modules
+PYTHON_DATA_DIRS = src/3rdparty/python/lib
win32:DATA_FILES = $$PWD/bin/ibmsvc.xml $$PWD/bin/ibqbs.bat
+LIBEXEC_FILES = $$PWD/src/3rdparty/python/bin/dmgbuild
# For use in custom compilers which just copy files
defineReplace(stripSrcDir) {
return($$relative_path($$absolute_path($$1, $$OUT_PWD), $$_PRO_FILE_PWD_))
}
+defineReplace(stripPythonSrcDir) {
+ return($$relative_path($$absolute_path($$1, $$OUT_PWD), \
+ $$_PRO_FILE_PWD_/src/3rdparty/python/lib/python2.7/site-packages))
+}
+
for(data_dir, DATA_DIRS) {
files = $$files($$PWD/$$data_dir/*, true)
for(file, files):!exists($$file/*):FILES += $$file
}
FILES += $$DATA_FILES
-OTHER_FILES += $$FILES
+for(data_dir, PYTHON_DATA_DIRS) {
+ files = $$files($$PWD/$$data_dir/*, true)
+ for(file, files):!exists($$file/*):PYTHON_FILES += $$file
+}
+PYTHON_FILES += $$PYTHON_DATA_FILES
+
+OTHER_FILES += $$FILES $$LIBEXEC_FILES
!isEqual(PWD, $$OUT_PWD)|!isEmpty(QBS_RESOURCES_BUILD_DIR) {
copy2build.input = FILES
@@ -26,6 +39,26 @@ OTHER_FILES += $$FILES
copy2build.name = COPY ${QMAKE_FILE_IN}
copy2build.CONFIG += no_link target_predeps
QMAKE_EXTRA_COMPILERS += copy2build
+
+ copy2build_python.input = PYTHON_FILES
+ !isEmpty(QBS_RESOURCES_BUILD_DIR): \
+ copy2build_python.output = \
+ $${QBS_RESOURCES_BUILD_DIR}/share/qbs/python/${QMAKE_FUNC_FILE_IN_stripPythonSrcDir}
+ else: \
+ copy2build_python.output = share/qbs/python/${QMAKE_FUNC_FILE_IN_stripPythonSrcDir}
+ copy2build_python.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
+ copy2build_python.name = COPY ${QMAKE_FILE_IN}
+ copy2build_python.CONFIG += no_link target_predeps
+ QMAKE_EXTRA_COMPILERS += copy2build_python
+}
+
+!isEqual(PWD, $$OUT_PWD) {
+ libexec_copy.input = LIBEXEC_FILES
+ libexec_copy.output = libexec/qbs/${QMAKE_FILE_IN_BASE}${QMAKE_FILE_EXT}
+ libexec_copy.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
+ libexec_copy.name = COPY ${QMAKE_FILE_IN}
+ libexec_copy.CONFIG += no_link target_predeps
+ QMAKE_EXTRA_COMPILERS += libexec_copy
}
include(src/install_prefix.pri)
@@ -38,4 +71,11 @@ else: \
share.path = $${installPrefix}/share
examples.files = examples
examples.path = $${share.path}/qbs
-INSTALLS += share examples
+python_bin.files = $$files(src/3rdparty/python/bin/*)
+!isEmpty(QBS_LIBEXEC_INSTALL_DIR): \
+ python_bin.path = $${QBS_LIBEXEC_INSTALL_DIR}
+else: \
+ python_bin.path = $${QBS_INSTALL_PREFIX}/libexec/qbs
+python.files = $$files(src/3rdparty/python/lib/python2.7/site-packages/*)
+python.path = $${share.path}/qbs/python
+INSTALLS += share examples python_bin python
diff --git a/tests/auto/api/testdata/QBS-728/QBS-728.qbs b/tests/auto/api/testdata/QBS-728/QBS-728.qbs
index 6ab244c83..a3090f7ae 100644
--- a/tests/auto/api/testdata/QBS-728/QBS-728.qbs
+++ b/tests/auto/api/testdata/QBS-728/QBS-728.qbs
@@ -2,6 +2,6 @@ import qbs
Product {
property bool isBlubbOS: qbs.targetOS.contains("blubb-OS")
- profiles: isBlubbOS ? ["blubb-profile"] : [project.profile]
+ qbs.profiles: isBlubbOS ? ["blubb-profile"] : [project.profile]
qbs.architecture: "blubb-arch"
}
diff --git a/tests/auto/api/testdata/buildgraph-info/buildgraph-info.qbs b/tests/auto/api/testdata/buildgraph-info/buildgraph-info.qbs
new file mode 100644
index 000000000..8828f3a19
--- /dev/null
+++ b/tests/auto/api/testdata/buildgraph-info/buildgraph-info.qbs
@@ -0,0 +1,5 @@
+import qbs
+
+Product {
+ qbs.shellPath: "/bin/bash"
+}
diff --git a/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs b/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs
index d441f58a5..6155baf28 100644
--- a/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs
+++ b/tests/auto/api/testdata/infinite-loop-process/infinite-loop.qbs
@@ -1,7 +1,7 @@
import qbs
Project {
- QtApplication {
+ CppApplication {
type: "application"
consoleApplication: true // suppress bundle generation
files: "main.cpp"
diff --git a/tests/auto/api/testdata/infinite-loop-process/main.cpp b/tests/auto/api/testdata/infinite-loop-process/main.cpp
index c3d18a787..6a7a53672 100644
--- a/tests/auto/api/testdata/infinite-loop-process/main.cpp
+++ b/tests/auto/api/testdata/infinite-loop-process/main.cpp
@@ -26,15 +26,10 @@
**
****************************************************************************/
-#include <QThread>
-
-class MyThread : public QThread
-{
-public:
- static void mySleep(unsigned long secs) { sleep(secs); } // sleep() is protected in Qt 4.
-};
+#include <chrono>
+#include <thread>
int main()
{
- MyThread::mySleep(700);
+ std::this_thread::sleep_for(std::chrono::seconds(700));
}
diff --git a/tests/auto/api/testdata/multi-arch/multi-arch.qbs b/tests/auto/api/testdata/multi-arch/multi-arch.qbs
index d88c84ba7..d54809a41 100644
--- a/tests/auto/api/testdata/multi-arch/multi-arch.qbs
+++ b/tests/auto/api/testdata/multi-arch/multi-arch.qbs
@@ -6,9 +6,10 @@ Project {
property string hostProfile
property string targetProfile
Product {
+ property stringList myProfiles
name: "p1"
type: "output"
- profiles: [project.targetProfile, project.hostProfile]
+ qbs.profiles: myProfiles ? myProfiles : [project.targetProfile, project.hostProfile]
Group {
files: "host+target.input"
fileTags: "input"
@@ -16,13 +17,13 @@ Project {
Group {
fileTagsFilter: "output"
qbs.install: true
- qbs.installDir: profile
+ qbs.installDir: qbs.profile
}
}
Product {
name: "p2"
type: "output"
- profiles: project.hostProfile
+ qbs.profiles: [project.hostProfile]
Group {
files: "host-tool.input"
fileTags: "input"
@@ -30,7 +31,7 @@ Project {
Group {
fileTagsFilter: "output"
qbs.install: true
- qbs.installDir: profile
+ qbs.installDir: qbs.profile
}
}
diff --git a/tests/auto/api/testdata/multiplexing/foo.txt b/tests/auto/api/testdata/multiplexing/foo.txt
new file mode 100644
index 000000000..b596baf20
--- /dev/null
+++ b/tests/auto/api/testdata/multiplexing/foo.txt
@@ -0,0 +1 @@
+Behold! I am the input.
diff --git a/tests/auto/api/testdata/multiplexing/multiplexing.qbs b/tests/auto/api/testdata/multiplexing/multiplexing.qbs
new file mode 100644
index 000000000..9027743b4
--- /dev/null
+++ b/tests/auto/api/testdata/multiplexing/multiplexing.qbs
@@ -0,0 +1,124 @@
+import qbs
+import qbs.TextFile
+
+Project {
+ Product {
+ name: "no-multiplexing"
+ type: ["reversed-text"]
+ files: ["foo.txt"]
+ }
+ Product {
+ name: "multiplex-without-aggregator-2"
+ type: ["reversed-text"]
+ files: ["foo.txt"]
+ multiplexByQbsProperties: ["architectures"]
+ qbs.architectures: ["TRS-80", "C64"]
+ }
+ Product {
+ name: "multiplex-with-export"
+ type: ["reversed-text"]
+ files: ["foo.txt"]
+ multiplexByQbsProperties: ["architectures"]
+ qbs.architectures: ["TRS-80", "C64"]
+ Export { Depends { name: "multiplex-without-aggregator-2" } }
+ }
+ Product {
+ name: "nonmultiplex-with-export"
+ type: ["reversed-text"]
+ files: ["foo.txt"]
+ Export { Depends { name: "multiplex-without-aggregator-2" } }
+ }
+ Product {
+ name: "nonmultiplex-exporting-aggregation"
+ type: ["reversed-text"]
+ files: ["foo.txt"]
+ Export { Depends { name: "multiplex-with-aggregator-2" } }
+ }
+ Product {
+ name: "multiplex-using-export"
+ type: ["reversed-text"]
+ files: ["foo.txt"]
+ multiplexByQbsProperties: ["architectures"]
+ qbs.architectures: ["TRS-80", "C64"]
+ Depends { name: "multiplex-with-export" }
+ }
+ Product {
+ name: "multiplex-without-aggregator-2-depend-on-non-multiplexed"
+ type: ["reversed-text"]
+ files: ["foo.txt"]
+ multiplexByQbsProperties: ["architectures"]
+ qbs.architectures: ["TRS-80", "C64"]
+ Depends { name: "no-multiplexing" }
+ }
+ Product {
+ name: "multiplex-without-aggregator-4"
+ type: ["reversed-text"]
+ files: ["foo.txt"]
+ multiplexByQbsProperties: ["architectures", "buildVariants"]
+ qbs.architectures: ["TRS-80", "C64"]
+ qbs.buildVariants: ["debug", "release"]
+ }
+ Product {
+ name: "multiplex-with-aggregator-2"
+ type: ["reversed-text"]
+ files: ["foo.txt"]
+ aggregate: true
+ multiplexByQbsProperties: ["architectures"]
+ qbs.architectures: ["TRS-80", "C64"]
+ qbs.architecture: "Atari ST"
+ }
+ Product {
+ name: "multiplex-with-aggregator-2-dependent"
+ Depends { name: "multiplex-with-aggregator-2" }
+ type: ["something"]
+ files: ["foo.txt"]
+ }
+ Product {
+ name: "non-multiplexed-with-dependencies-on-multiplexed"
+ Depends { name: "multiplex-without-aggregator-2" }
+ }
+ Product {
+ name: "non-multiplexed-with-dependencies-on-multiplexed-via-export1"
+ Depends { name: "multiplex-with-export" }
+ }
+ Product {
+ name: "non-multiplexed-with-dependencies-on-multiplexed-via-export2"
+ Depends { name: "nonmultiplex-with-export" }
+ }
+ Product {
+ name: "non-multiplexed-with-dependencies-on-aggregation-via-export"
+ Depends { name: "nonmultiplex-exporting-aggregation" }
+ }
+ Product {
+ name: "aggregate-with-dependencies-on-aggregation-via-export"
+ Depends { name: "nonmultiplex-exporting-aggregation" }
+ aggregate: true
+ multiplexByQbsProperties: ["architectures"]
+ qbs.architectures: ["TRS-80", "C64"]
+ qbs.architecture: "Atari ST"
+ }
+ FileTagger {
+ patterns: ["*.txt"]
+ fileTags: ["text"]
+ }
+ Rule {
+ inputs: ["text"]
+ Artifact {
+ filePath: input.baseName + ".txet"
+ fileTags: ["reversed-text"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "reversing text";
+ cmd.sourceCode = function() {
+ var tf = new TextFile(input.filePath, TextFile.ReadOnly);
+ var content = tf.readAll();
+ tf.close();
+ tf = new TextFile(output.filePath, TextFile.WriteOnly);
+ tf.write(content.split("").reverse().join(""));
+ tf.close();
+ };
+ return cmd;
+ }
+ }
+}
diff --git a/tests/auto/api/testdata/new-output-artifact-in-dependency/lib.cpp b/tests/auto/api/testdata/new-output-artifact-in-dependency/lib.cpp
index 7e43bdccf..d3e799fd9 100644
--- a/tests/auto/api/testdata/new-output-artifact-in-dependency/lib.cpp
+++ b/tests/auto/api/testdata/new-output-artifact-in-dependency/lib.cpp
@@ -26,6 +26,11 @@
**
****************************************************************************/
-#include <QtGlobal>
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT __attribute__((visibility("default")))
+#endif
-Q_DECL_EXPORT void f() {}
+
+EXPORT void f() {}
diff --git a/tests/auto/api/testdata/new-output-artifact-in-dependency/new-output-artifact-in-dependency.qbs b/tests/auto/api/testdata/new-output-artifact-in-dependency/new-output-artifact-in-dependency.qbs
index ed08e8315..2695a8085 100644
--- a/tests/auto/api/testdata/new-output-artifact-in-dependency/new-output-artifact-in-dependency.qbs
+++ b/tests/auto/api/testdata/new-output-artifact-in-dependency/new-output-artifact-in-dependency.qbs
@@ -3,7 +3,6 @@ import qbs
Project {
DynamicLibrary {
//Depends { name: "cpp" }
- //Depends { name: "Qt.core" }
name: "lib"
files: "lib.cpp"
bundle.isBundle: false
diff --git a/tests/auto/api/testdata/objc/main.mm b/tests/auto/api/testdata/objc/main.mm
index 90cf06bff..c461fa433 100644
--- a/tests/auto/api/testdata/objc/main.mm
+++ b/tests/auto/api/testdata/objc/main.mm
@@ -1,11 +1,10 @@
#import <Foundation/Foundation.h>
-#include <QCoreApplication>
+#include <iostream>
int main(int argc, char **argv)
{
// We support both C++
- QCoreApplication app(argc, argv);
- Q_UNUSED(app);
+ std::cout << "Hello from C++" << std::endl;
// And Objective-C
NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"];
NSString *productVersion = [version objectForKey:@"ProductVersion"];
diff --git a/tests/auto/api/testdata/objc/objc.qbs b/tests/auto/api/testdata/objc/objc.qbs
index 0fa9eb62a..c88d4693c 100644
--- a/tests/auto/api/testdata/objc/objc.qbs
+++ b/tests/auto/api/testdata/objc/objc.qbs
@@ -1,7 +1,7 @@
import qbs 1.0
Project {
- QtApplication {
+ CppApplication {
condition: qbs.targetOS.contains("macos")
files: "main.mm"
cpp.frameworks: [ "Foundation" ]
diff --git a/tests/auto/api/testdata/rc/rc.qbs b/tests/auto/api/testdata/rc/rc.qbs
index 418ac2744..3a5ce9cab 100644
--- a/tests/auto/api/testdata/rc/rc.qbs
+++ b/tests/auto/api/testdata/rc/rc.qbs
@@ -3,7 +3,7 @@ import qbs 1.0
Application {
type: "application"
consoleApplication: true
- name: "rc"
+ name: "rctest"
Depends { name: 'cpp' }
diff --git a/tests/auto/api/testdata/rename-product/lib.cpp b/tests/auto/api/testdata/rename-product/lib.cpp
index 1bdd05e48..e0e8762d0 100644
--- a/tests/auto/api/testdata/rename-product/lib.cpp
+++ b/tests/auto/api/testdata/rename-product/lib.cpp
@@ -26,6 +26,10 @@
**
****************************************************************************/
-#include <QtGlobal>
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT __attribute__((visibility("default")))
+#endif
MY_EXPORT void f() { }
diff --git a/tests/auto/api/testdata/rename-product/rename.qbs b/tests/auto/api/testdata/rename-product/rename.qbs
index c7811059a..137de27a7 100644
--- a/tests/auto/api/testdata/rename-product/rename.qbs
+++ b/tests/auto/api/testdata/rename-product/rename.qbs
@@ -10,8 +10,7 @@ Project {
DynamicLibrary {
name: "TheLib"
Depends { name: "cpp" }
- Depends { name: "Qt.core" }
- cpp.defines: "MY_EXPORT=Q_DECL_EXPORT"
+ cpp.defines: "MY_EXPORT=EXPORT"
files: "lib.cpp"
bundle.isBundle: false
}
diff --git a/tests/auto/api/testdata/rename-target-artifact/lib.cpp b/tests/auto/api/testdata/rename-target-artifact/lib.cpp
index 1bdd05e48..e0e8762d0 100644
--- a/tests/auto/api/testdata/rename-target-artifact/lib.cpp
+++ b/tests/auto/api/testdata/rename-target-artifact/lib.cpp
@@ -26,6 +26,10 @@
**
****************************************************************************/
-#include <QtGlobal>
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT __attribute__((visibility("default")))
+#endif
MY_EXPORT void f() { }
diff --git a/tests/auto/api/testdata/rename-target-artifact/rename.qbs b/tests/auto/api/testdata/rename-target-artifact/rename.qbs
index e94cc7b45..27f91841a 100644
--- a/tests/auto/api/testdata/rename-target-artifact/rename.qbs
+++ b/tests/auto/api/testdata/rename-target-artifact/rename.qbs
@@ -11,8 +11,7 @@ Project {
name: "TheLib"
targetName: "the_lib"
Depends { name: "cpp" }
- Depends { name: "Qt.core" }
- cpp.defines: "MY_EXPORT=Q_DECL_EXPORT"
+ cpp.defines: "MY_EXPORT=EXPORT"
files: "lib.cpp"
bundle.isBundle: false
}
diff --git a/tests/auto/api/testdata/static-lib-deps/d.cpp b/tests/auto/api/testdata/static-lib-deps/d.cpp
index 7c6812837..a7ecfd1ee 100644
--- a/tests/auto/api/testdata/static-lib-deps/d.cpp
+++ b/tests/auto/api/testdata/static-lib-deps/d.cpp
@@ -31,6 +31,7 @@
#elif defined(WITH_LEX_YACC)
extern "C" int yywrap(void);
extern "C" void yyerror(char const *s);
+extern void printGreeting();
#elif defined(WITH_SETUPAPI)
#include <windows.h>
#include <Setupapi.h>
@@ -50,6 +51,7 @@ int d()
#elif defined(WITH_LEX_YACC)
yywrap();
yyerror("no error");
+ printGreeting();
return 0;
#elif defined(WITH_SETUPAPI)
CABINET_INFO ci;
diff --git a/tests/auto/api/testdata/static-lib-deps/d.mm b/tests/auto/api/testdata/static-lib-deps/d.mm
new file mode 100644
index 000000000..5bf48966f
--- /dev/null
+++ b/tests/auto/api/testdata/static-lib-deps/d.mm
@@ -0,0 +1,8 @@
+#import <Foundation/Foundation.h>
+
+void printGreeting()
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSLog (@"Hello darkness, my old friend!");
+ [pool drain];
+}
diff --git a/tests/auto/api/testdata/static-lib-deps/static-lib-deps.qbs b/tests/auto/api/testdata/static-lib-deps/static-lib-deps.qbs
index ccbe49a0b..c925d4d57 100644
--- a/tests/auto/api/testdata/static-lib-deps/static-lib-deps.qbs
+++ b/tests/auto/api/testdata/static-lib-deps/static-lib-deps.qbs
@@ -45,33 +45,26 @@ Project {
"d.cpp",
]
+ Group {
+ condition: qbs.targetOS.contains("macos")
+ files: ["d.mm"]
+ }
+
Properties {
condition: qbs.targetOS.contains("windows")
cpp.defines: ["WITH_SETUPAPI"]
+ cpp.staticLibraries: ["setupapi"]
}
Properties {
condition: qbs.targetOS.contains("macos")
cpp.defines: ["WITH_LEX_YACC"]
+ cpp.staticLibraries: ["l", "y"]
+ cpp.frameworks: ["Foundation"]
}
Properties {
condition: qbs.targetOS.contains("linux")
cpp.defines: ["WITH_PTHREAD"]
- }
-
- Export {
- Depends { name: "cpp" }
- Properties {
- condition: qbs.targetOS.contains("linux")
- cpp.staticLibraries: ["pthread"]
- }
- Properties {
- condition: qbs.targetOS.contains("macos")
- cpp.staticLibraries: ["l", "y"]
- }
- Properties {
- condition: qbs.targetOS.contains("windows")
- cpp.staticLibraries: ["setupapi"]
- }
+ cpp.staticLibraries: ["pthread"]
}
}
StaticLibrary {
diff --git a/tests/auto/api/tst_api.cpp b/tests/auto/api/tst_api.cpp
index ef4a6e71c..29891eecc 100644
--- a/tests/auto/api/tst_api.cpp
+++ b/tests/auto/api/tst_api.cpp
@@ -43,7 +43,6 @@
#include <QtCore/qeventloop.h>
#include <QtCore/qfile.h>
#include <QtCore/qfileinfo.h>
-#include <QtCore/qregularexpression.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qthread.h>
@@ -53,6 +52,8 @@
#include <algorithm>
#include <functional>
+#include <memory>
+#include <regex>
#include <utility>
#include <vector>
@@ -165,6 +166,7 @@ void TestApi::initTestCase()
void TestApi::init()
{
m_logSink->warnings.clear();
+ m_logSink->setLogLevel(qbs::LoggerInfo);
}
void TestApi::addQObjectMacroToCppFile()
@@ -253,6 +255,41 @@ void TestApi::baseProperties()
VERIFY_NO_ERROR(errorInfo);
}
+void TestApi::buildGraphInfo()
+{
+ SettingsPtr s = settings();
+ qbs::Internal::TemporaryProfile p("bgInfoProfile", s.get());
+ p.p.setValue("qbs.targetOS", QStringList{"xenix"});
+ qbs::SetupProjectParameters setupParams
+ = defaultSetupParameters("buildgraph-info");
+ setupParams.setTopLevelProfile(p.p.name());
+ setupParams.setOverriddenValues({std::make_pair("qbs.architecture", "arm")});
+ QScopedPointer<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams,
+ m_logSink, 0));
+ waitForFinished(setupJob.data());
+ QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString()));
+ const QString bgFilePath = setupParams.buildRoot() + QLatin1Char('/')
+ + relativeBuildGraphFilePath();
+ QVERIFY2(QFileInfo::exists(bgFilePath), qPrintable(bgFilePath));
+ qbs::Project::BuildGraphInfo bgInfo
+ = qbs::Project::getBuildGraphInfo(bgFilePath, QStringList());
+ QVERIFY(bgInfo.error.hasError()); // Build graph is still locked.
+ setupJob.reset(nullptr);
+ const QStringList requestedProperties({"qbs.architecture", "qbs.shellPath", "qbs.targetOS"});
+ bgInfo = qbs::Project::getBuildGraphInfo(bgFilePath, requestedProperties);
+ QVERIFY2(!bgInfo.error.hasError(), qPrintable(bgInfo.error.toString()));
+ QCOMPARE(bgFilePath, bgInfo.bgFilePath);
+ QCOMPARE(bgInfo.profileData.count(), 1);
+ QCOMPARE(bgInfo.profileData.value(p.p.name()).toMap().count(), 1);
+ QCOMPARE(bgInfo.profileData.value(p.p.name()).toMap().value("qbs").toMap().value("targetOS"),
+ p.p.value("qbs.targetOS"));
+ QCOMPARE(bgInfo.overriddenProperties, setupParams.overriddenValues());
+ QCOMPARE(bgInfo.requestedProperties.count(), requestedProperties.count());
+ QCOMPARE(bgInfo.requestedProperties.value("qbs.architecture").toString(), QString("arm"));
+ QCOMPARE(bgInfo.requestedProperties.value("qbs.shellPath").toString(), QString("/bin/bash"));
+ QCOMPARE(bgInfo.requestedProperties.value("qbs.targetOS").toStringList(), QStringList("xenix"));
+}
+
void TestApi::buildErrorCodeLocation()
{
const qbs::ErrorInfo errorInfo
@@ -1009,9 +1046,9 @@ void TestApi::errorInSetupRunEnvironment()
bool exceptionCaught = false;
try {
- qbs::Settings settings((QString()));
+ const SettingsPtr s = settings();
qbs::RunEnvironment runEnv = project.getRunEnvironment(product, qbs::InstallOptions(),
- QProcessEnvironment(), &settings);
+ QProcessEnvironment(), s.get());
qbs::ErrorInfo error;
const QProcessEnvironment env = runEnv.runEnvironment(&error);
QVERIFY(error.hasError());
@@ -1224,7 +1261,7 @@ void TestApi::infiniteLoopBuilding()
qbs::Project project = setupJob->project();
const QScopedPointer<qbs::BuildJob> buildJob(project.buildAllProducts(qbs::BuildOptions()));
QTimer::singleShot(1000, buildJob.data(), &qbs::AbstractJob::cancel);
- QVERIFY(waitForFinished(buildJob.data(), 600000));
+ QVERIFY(waitForFinished(buildJob.data(), testTimeoutInMsecs()));
QVERIFY(buildJob->error().hasError());
}
@@ -1241,7 +1278,7 @@ void TestApi::infiniteLoopResolving()
QScopedPointer<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams,
m_logSink, 0));
QTimer::singleShot(1000, setupJob.data(), &qbs::AbstractJob::cancel);
- QVERIFY(waitForFinished(setupJob.data(), 600000));
+ QVERIFY(waitForFinished(setupJob.data(), testTimeoutInMsecs()));
QVERIFY2(setupJob->error().toString().toLower().contains("cancel"),
qPrintable(setupJob->error().toString()));
}
@@ -1366,13 +1403,14 @@ void TestApi::linkDynamicAndStaticLibs()
VERIFY_NO_ERROR(errorInfo);
// The dependent static libs should not appear in the link command for the executable.
- qbs::Settings settings((QString()));
- const qbs::Profile buildProfile(profileName(), &settings);
+ const SettingsPtr s = settings();
+ const qbs::Profile buildProfile(profileName(), s.get());
if (buildProfile.value("qbs.toolchain").toStringList().contains("gcc")) {
- QRegularExpression appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " ");
+ static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " ");
QString appLinkCmd;
for (const QString &line : qAsConst(bdr.descriptionLines)) {
- if (line.contains(appLinkCmdRex)) {
+ const auto ln = line.toStdString();
+ if (std::regex_search(ln, appLinkCmdRex)) {
appLinkCmd = line;
break;
}
@@ -1394,13 +1432,14 @@ void TestApi::linkStaticAndDynamicLibs()
// The dependencies libdynamic1.so and libstatic2.a must not appear in the link command for the
// executable. The -rpath-link line for libdynamic1.so must be there.
- qbs::Settings settings((QString()));
- const qbs::Profile buildProfile(profileName(), &settings);
+ const SettingsPtr s = settings();
+ const qbs::Profile buildProfile(profileName(), s.get());
if (buildProfile.value("qbs.toolchain").toStringList().contains("gcc")) {
- QRegularExpression appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " ");
+ static const std::regex appLinkCmdRex(" -o [^ ]*/HelloWorld" QBS_HOST_EXE_SUFFIX " ");
QString appLinkCmd;
for (const QString &line : qAsConst(bdr.descriptionLines)) {
- if (line.contains(appLinkCmdRex)) {
+ const auto ln = line.toStdString();
+ if (std::regex_search(ln, appLinkCmdRex)) {
appLinkCmd = line;
break;
}
@@ -1408,9 +1447,10 @@ void TestApi::linkStaticAndDynamicLibs()
QVERIFY(!appLinkCmd.isEmpty());
const auto targetOs = buildProfile.value("qbs.targetOS").toStringList();
if (!targetOs.contains("darwin") && !targetOs.contains("windows")) {
- QRegularExpression rpathLinkRex(QString("-rpath-link=\\S*/")
- + relativeProductBuildDir("dynamic2"));
- QVERIFY(appLinkCmd.contains(rpathLinkRex));
+ const std::regex rpathLinkRex("-rpath-link=\\S*/"
+ + relativeProductBuildDir("dynamic2").toStdString());
+ const auto ln = appLinkCmd.toStdString();
+ QVERIFY(std::regex_search(ln, rpathLinkRex));
}
QVERIFY(!appLinkCmd.contains("libstatic2.a"));
QVERIFY(!appLinkCmd.contains("libdynamic2.so"));
@@ -1438,7 +1478,7 @@ void TestApi::missingSourceFile()
qbs::SetupProjectParameters setupParams
= defaultSetupParameters("missing-source-file/missing-source-file.qbs");
setupParams.setProductErrorMode(qbs::ErrorHandlingMode::Relaxed);
-
+ m_logSink->setLogLevel(qbs::LoggerMinLevel);
QScopedPointer<qbs::SetupProjectJob> job(qbs::Project().setupProject(setupParams,
m_logSink, 0));
waitForFinished(job.data());
@@ -1492,11 +1532,11 @@ void TestApi::mocCppIncluded()
void TestApi::multiArch()
{
qbs::SetupProjectParameters setupParams = defaultSetupParameters("multi-arch");
- qbs::Settings settings((QString()));
- qbs::Internal::TemporaryProfile tph("host", &settings);
+ const SettingsPtr s = settings();
+ qbs::Internal::TemporaryProfile tph("host", s.get());
qbs::Profile hostProfile = tph.p;
hostProfile.setValue("qbs.architecture", "host-arch");
- qbs::Internal::TemporaryProfile tpt("target", &settings);
+ qbs::Internal::TemporaryProfile tpt("target", s.get());
qbs::Profile targetProfile = tpt.p;
targetProfile.setValue("qbs.architecture", "target-arch");
QVariantMap overriddenValues;
@@ -1529,21 +1569,29 @@ void TestApi::multiArch()
QCOMPARE(hostProductNames.count("p1"), 1);
QCOMPARE(hostProductNames.count("p2"), 1);
+ const QString p1HostMultiplexCfgId = hostProducts.at(0).multiplexConfigurationId();
+ const QString p2HostMultiplexCfgId = hostProducts.at(1).multiplexConfigurationId();
+ const QString p1TargetMultiplexCfgId = targetProducts.at(0).multiplexConfigurationId();
+
QScopedPointer<qbs::BuildJob> buildJob(project.buildAllProducts(qbs::BuildOptions()));
waitForFinished(buildJob.data());
QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString()));
const QString outputBaseDir = setupParams.buildRoot() + '/';
QFile p1HostArtifact(outputBaseDir
- + relativeProductBuildDir("p1", "host") + "/host+target.output");
+ + relativeProductBuildDir("p1", p1HostMultiplexCfgId)
+ + "/host+target.output");
QVERIFY2(p1HostArtifact.exists(), qPrintable(p1HostArtifact.fileName()));
QVERIFY2(p1HostArtifact.open(QIODevice::ReadOnly), qPrintable(p1HostArtifact.errorString()));
QCOMPARE(p1HostArtifact.readAll().constData(), "host-arch");
- QFile p1TargetArtifact(outputBaseDir + relativeProductBuildDir("p1", "target")
+ QFile p1TargetArtifact(outputBaseDir
+ + relativeProductBuildDir("p1", p1TargetMultiplexCfgId)
+ "/host+target.output");
QVERIFY2(p1TargetArtifact.exists(), qPrintable(p1TargetArtifact.fileName()));
QVERIFY2(p1TargetArtifact.open(QIODevice::ReadOnly), qPrintable(p1TargetArtifact.errorString()));
QCOMPARE(p1TargetArtifact.readAll().constData(), "target-arch");
- QFile p2Artifact(outputBaseDir + relativeProductBuildDir("p2", "host") + "/host-tool.output");
+ QFile p2Artifact(outputBaseDir
+ + relativeProductBuildDir("p2", p2HostMultiplexCfgId)
+ + "/host-tool.output");
QVERIFY2(p2Artifact.exists(), qPrintable(p2Artifact.fileName()));
QVERIFY2(p2Artifact.open(QIODevice::ReadOnly), qPrintable(p2Artifact.errorString()));
QCOMPARE(p2Artifact.readAll().constData(), "host-arch");
@@ -1566,24 +1614,247 @@ void TestApi::multiArch()
setupJob.reset(project.setupProject(setupParams, m_logSink, 0));
waitForFinished(setupJob.data());
QVERIFY(setupJob->error().hasError());
- QVERIFY2(setupJob->error().toString().contains(hostProfile.name())
- && setupJob->error().toString().contains("not allowed"),
+ QVERIFY2(setupJob->error().toString().contains("Duplicate product name 'p1'"),
qPrintable(setupJob->error().toString()));
// Error check: Try to build for the same profile twice, this time attaching
// the properties via the product name.
- overriddenValues.clear();
- overriddenValues.insert("products.p1.profiles",
+ overriddenValues.remove(QLatin1String("project.targetProfile"));
+ overriddenValues.insert("products.p1.myProfiles",
targetProfile.name() + ',' + targetProfile.name());
setupParams.setOverriddenValues(overriddenValues);
setupJob.reset(project.setupProject(setupParams, m_logSink, 0));
waitForFinished(setupJob.data());
QVERIFY(setupJob->error().hasError());
- QVERIFY2(setupJob->error().toString().contains(targetProfile.name())
- && setupJob->error().toString().contains("not allowed"),
+ QVERIFY2(setupJob->error().toString().contains("Duplicate product name 'p1'"),
qPrintable(setupJob->error().toString()));
}
+struct ProductDataSelector
+{
+ void clear()
+ {
+ name.clear();
+ qbsProperties.clear();
+ }
+
+ bool matches(const qbs::ProductData &p) const
+ {
+ return name == p.name() && qbsPropertiesMatch(p);
+ }
+
+ bool qbsPropertiesMatch(const qbs::ProductData &p) const
+ {
+ for (auto it = qbsProperties.begin(); it != qbsProperties.end(); ++it) {
+ if (it.value() != p.moduleProperties().getModuleProperty("qbs", it.key()))
+ return false;
+ }
+ return true;
+ }
+
+ QString name;
+ QVariantMap qbsProperties;
+};
+
+static qbs::ProductData takeMatchingProduct(QList<qbs::ProductData> &products,
+ const ProductDataSelector &s)
+{
+ qbs::ProductData result;
+ auto it = std::find_if(products.begin(), products.end(),
+ [&s] (const qbs::ProductData &pd) { return s.matches(pd); });
+ if (it != products.end()) {
+ result = *it;
+ products.erase(it);
+ }
+ return result;
+}
+
+void TestApi::multiplexing()
+{
+ qbs::SetupProjectParameters setupParams = defaultSetupParameters("multiplexing");
+ std::unique_ptr<qbs::SetupProjectJob> setupJob(
+ qbs::Project().setupProject(setupParams, m_logSink, 0));
+ waitForFinished(setupJob.get());
+ QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString()));
+ qbs::Project project = setupJob->project();
+ QList<qbs::ProductData> products = project.projectData().products();
+ qbs::ProductData product;
+ ProductDataSelector selector;
+ selector.name = "no-multiplexing";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(!product.isMultiplexed());
+ QVERIFY(product.dependencies().isEmpty());
+
+ selector.clear();
+ selector.name = "multiplex-without-aggregator-2";
+ selector.qbsProperties["architecture"] = "TRS-80";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QVERIFY(product.dependencies().isEmpty());
+
+ selector.qbsProperties["architecture"] = "C64";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QVERIFY(product.dependencies().isEmpty());
+
+ selector.clear();
+ selector.name = "multiplex-with-export";
+ selector.qbsProperties["architecture"] = "TRS-80";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QVERIFY(product.dependencies().isEmpty());
+
+ selector.qbsProperties["architecture"] = "C64";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QVERIFY(product.dependencies().isEmpty());
+
+ selector.clear();
+ selector.name = "nonmultiplex-with-export";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(!product.isMultiplexed());
+ QVERIFY(product.dependencies().isEmpty());
+
+ selector.clear();
+ selector.name = "nonmultiplex-exporting-aggregation";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(!product.isMultiplexed());
+ QVERIFY(product.dependencies().isEmpty());
+
+ selector.clear();
+ selector.name = "multiplex-using-export";
+ selector.qbsProperties["architecture"] = "TRS-80";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 2);
+
+ selector.qbsProperties["architecture"] = "C64";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 2);
+
+ selector.clear();
+ selector.name = "multiplex-without-aggregator-2-depend-on-non-multiplexed";
+ selector.qbsProperties["architecture"] = "TRS-80";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 1);
+
+ selector.qbsProperties["architecture"] = "C64";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 1);
+
+ selector.clear();
+ selector.name = "multiplex-without-aggregator-4";
+ selector.qbsProperties["architecture"] = "C64";
+ selector.qbsProperties["buildVariant"] = "debug";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QVERIFY(product.dependencies().isEmpty());
+ selector.qbsProperties["buildVariant"] = "release";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QVERIFY(product.dependencies().isEmpty());
+ selector.qbsProperties["architecture"] = "TRS-80";
+ selector.qbsProperties["buildVariant"] = "debug";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QVERIFY(product.dependencies().isEmpty());
+ selector.qbsProperties["buildVariant"] = "release";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QVERIFY(product.dependencies().isEmpty());
+
+ selector.clear();
+ selector.name = "multiplex-with-aggregator-2";
+ selector.qbsProperties["architecture"] = "C64";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 0);
+ selector.qbsProperties["architecture"] = "TRS-80";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 0);
+ selector.qbsProperties["architecture"] = "Atari ST";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 2);
+
+ selector.clear();
+ selector.name = "multiplex-with-aggregator-2-dependent";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(!product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 1);
+
+ selector.clear();
+ selector.name = "non-multiplexed-with-dependencies-on-multiplexed";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(!product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 2);
+
+ selector.clear();
+ selector.name = "non-multiplexed-with-dependencies-on-multiplexed-via-export1";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(!product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 4);
+
+ selector.clear();
+ selector.name = "non-multiplexed-with-dependencies-on-multiplexed-via-export2";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(!product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 3);
+
+ selector.clear();
+ selector.name = "non-multiplexed-with-dependencies-on-aggregation-via-export";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(!product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 2);
+
+ selector.clear();
+ selector.name = "aggregate-with-dependencies-on-aggregation-via-export";
+ selector.qbsProperties["architecture"] = "C64";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 2);
+ selector.qbsProperties["architecture"] = "TRS-80";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 2);
+ selector.qbsProperties["architecture"] = "Atari ST";
+ product = takeMatchingProduct(products, selector);
+ QVERIFY(product.isValid());
+ QVERIFY(product.isMultiplexed());
+ QCOMPARE(product.dependencies().count(), 4);
+
+ QVERIFY(products.isEmpty());
+}
+
void TestApi::newOutputArtifactInDependency()
{
BuildDescriptionReceiver receiver;
@@ -1874,6 +2145,7 @@ void TestApi::referencedFileErrors()
params.setDryRun(true);
params.setProductErrorMode(relaxedMode ? qbs::ErrorHandlingMode::Relaxed
: qbs::ErrorHandlingMode::Strict);
+ m_logSink->setLogLevel(qbs::LoggerMinLevel);
QScopedPointer<qbs::SetupProjectJob> job(qbs::Project().setupProject(params, m_logSink, 0));
waitForFinished(job.data());
QVERIFY2(job->error().hasError() != relaxedMode, qPrintable(job->error().toString()));
@@ -1909,12 +2181,14 @@ qbs::SetupProjectParameters TestApi::defaultSetupParameters(const QString &proje
}
qbs::SetupProjectParameters setupParams;
+ setupParams.setEnvironment(QProcessEnvironment::systemEnvironment());
setupParams.setProjectFilePath(projectFilePath);
setupParams.setPropertyCheckingMode(qbs::ErrorHandlingMode::Strict);
+ setupParams.setOverrideBuildGraphData(true);
QDir::setCurrent(projectDirPath);
setupParams.setBuildRoot(projectDirPath);
- qbs::Settings settings((QString()));
- const qbs::Preferences prefs(&settings, profileName());
+ const SettingsPtr s = settings();
+ const qbs::Preferences prefs(s.get(), profileName());
setupParams.setSearchPaths(prefs.searchPaths(QDir::cleanPath(QCoreApplication::applicationDirPath()
+ QLatin1String("/" QBS_RELATIVE_SEARCH_PATH))));
setupParams.setPluginPaths(prefs.pluginPaths(QDir::cleanPath(QCoreApplication::applicationDirPath()
@@ -1923,6 +2197,7 @@ qbs::SetupProjectParameters TestApi::defaultSetupParameters(const QString &proje
+ QLatin1String("/" QBS_RELATIVE_LIBEXEC_PATH)));
setupParams.setTopLevelProfile(profileName());
setupParams.setConfigurationName(QStringLiteral("default"));
+ setupParams.setSettingsDirectory(settings()->baseDirectory());
return setupParams;
}
diff --git a/tests/auto/api/tst_api.h b/tests/auto/api/tst_api.h
index c78229779..beb0ab4ac 100644
--- a/tests/auto/api/tst_api.h
+++ b/tests/auto/api/tst_api.h
@@ -60,6 +60,7 @@ private slots:
void addedFilePersistent();
void baseProperties();
void buildErrorCodeLocation();
+ void buildGraphInfo();
void buildGraphLocking();
void buildProject();
void buildProject_data();
@@ -102,6 +103,7 @@ private slots:
void missingSourceFile();
void mocCppIncluded();
void multiArch();
+ void multiplexing();
void newOutputArtifactInDependency();
void newPatternMatch();
void nonexistingProjectPropertyFromCommandLine();
diff --git a/tests/auto/auto.pri b/tests/auto/auto.pri
index 545d1365c..f0d6e9be4 100644
--- a/tests/auto/auto.pri
+++ b/tests/auto/auto.pri
@@ -1,7 +1,7 @@
TEMPLATE = app
DESTDIR = ../../../bin
DEFINES += SRCDIR=\\\"$$_PRO_FILE_PWD_\\\"
-INCLUDEPATH += $$PWD/../../src
+INCLUDEPATH += $$PWD/../../src $$PWD/../../src/app/shared
QT = core testlib
CONFIG += depend_includepath testcase console
@@ -9,4 +9,7 @@ CONFIG -= app_bundle
CONFIG += c++11
target.CONFIG += no_default_install
+dev_lib_frameworks=$$QMAKE_XCODE_DEVELOPER_PATH/Library/Frameworks
+exists($$dev_lib_frameworks): LIBS += -F$$dev_lib_frameworks
+
include(../../src/lib/corelib/use_corelib.pri)
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index c835768ed..c46f0c260 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -10,6 +10,8 @@ qbs_enable_unit_tests {
SUBDIRS += \
cmdlineparser \
blackbox/blackbox.pro \
+ blackbox/blackbox-apple.pro \
blackbox/blackbox-clangdb.pro \
blackbox/blackbox-java.pro \
+ blackbox/blackbox-qt.pro \
api
diff --git a/tests/auto/auto.qbs b/tests/auto/auto.qbs
index aa5b3ff49..1840e07dd 100644
--- a/tests/auto/auto.qbs
+++ b/tests/auto/auto.qbs
@@ -5,6 +5,10 @@ Project {
references: [
"api/api.qbs",
"blackbox/blackbox.qbs",
+ "blackbox/blackbox-apple.qbs",
+ "blackbox/blackbox-clangdb.qbs",
+ "blackbox/blackbox-java.qbs",
+ "blackbox/blackbox-qt.qbs",
"buildgraph/buildgraph.qbs",
"cmdlineparser/cmdlineparser.qbs",
"language/language.qbs",
diff --git a/tests/auto/blackbox/blackbox-apple.pro b/tests/auto/blackbox/blackbox-apple.pro
new file mode 100644
index 000000000..1a009e222
--- /dev/null
+++ b/tests/auto/blackbox/blackbox-apple.pro
@@ -0,0 +1,20 @@
+TARGET = tst_blackbox-apple
+
+HEADERS = tst_blackboxapple.h tst_blackboxbase.h
+SOURCES = tst_blackboxapple.cpp tst_blackboxbase.cpp
+OBJECTS_DIR = apple
+MOC_DIR = $${OBJECTS_DIR}-moc
+
+include(../auto.pri)
+
+QT += xml
+
+DATA_DIRS = testdata-apple ../find
+
+for(data_dir, DATA_DIRS) {
+ files = $$files($$PWD/$$data_dir/*, true)
+ win32:files ~= s|\\\\|/|g
+ for(file, files):!exists($$file/*):FILES += $$file
+}
+
+OTHER_FILES += $$FILES
diff --git a/tests/auto/blackbox/blackbox-apple.qbs b/tests/auto/blackbox/blackbox-apple.qbs
new file mode 100644
index 000000000..34b7e372d
--- /dev/null
+++ b/tests/auto/blackbox/blackbox-apple.qbs
@@ -0,0 +1,23 @@
+import qbs
+
+QbsAutotest {
+ testName: "blackbox-apple"
+ Depends { name: "Qt.xml" }
+ Depends { name: "qbs_app" }
+ Depends { name: "qbs-setup-toolchains" }
+ Group {
+ name: "testdata"
+ prefix: "testdata-apple/"
+ files: ["**/*"]
+ fileTags: []
+ }
+ files: [
+ "../shared.h",
+ "tst_blackboxapple.cpp",
+ "tst_blackboxapple.h",
+ "tst_blackboxbase.cpp",
+ "tst_blackboxbase.h",
+ ]
+ // TODO: Use Utilities.cStringQuote
+ cpp.defines: base.concat(['SRCDIR="' + path + '"'])
+}
diff --git a/tests/auto/blackbox/blackbox-clangdb.qbs b/tests/auto/blackbox/blackbox-clangdb.qbs
new file mode 100644
index 000000000..b77c08d5e
--- /dev/null
+++ b/tests/auto/blackbox/blackbox-clangdb.qbs
@@ -0,0 +1,25 @@
+import qbs
+
+QbsAutotest {
+ testName: "blackbox-clangdb"
+
+ Depends { name: "qbs_app" }
+ Depends { name: "qbs-setup-toolchains" }
+
+ Group {
+ name: "testdata"
+ prefix: "testdata-clangdb/"
+ files: ["**/*"]
+ fileTags: []
+ }
+
+ files: [
+ "../shared.h",
+ "tst_blackboxbase.cpp",
+ "tst_blackboxbase.h",
+ "tst_clangdb.cpp",
+ "tst_clangdb.h",
+ ]
+ // TODO: Use Utilities.cStringQuote
+ cpp.defines: base.concat(['SRCDIR="' + path + '"'])
+}
diff --git a/tests/auto/blackbox/blackbox-java.qbs b/tests/auto/blackbox/blackbox-java.qbs
new file mode 100644
index 000000000..d8664a9bf
--- /dev/null
+++ b/tests/auto/blackbox/blackbox-java.qbs
@@ -0,0 +1,22 @@
+import qbs
+
+QbsAutotest {
+ testName: "blackbox-java"
+ Depends { name: "qbs_app" }
+ Depends { name: "qbs-setup-toolchains" }
+ Group {
+ name: "testdata"
+ prefix: "testdata-java/"
+ files: ["**/*"]
+ fileTags: []
+ }
+ files: [
+ "../shared.h",
+ "tst_blackboxbase.cpp",
+ "tst_blackboxbase.h",
+ "tst_blackboxjava.cpp",
+ "tst_blackboxjava.h",
+ ]
+ // TODO: Use Utilities.cStringQuote
+ cpp.defines: base.concat(['SRCDIR="' + path + '"'])
+}
diff --git a/tests/auto/blackbox/blackbox-qt.pro b/tests/auto/blackbox/blackbox-qt.pro
new file mode 100644
index 000000000..e17a04a7e
--- /dev/null
+++ b/tests/auto/blackbox/blackbox-qt.pro
@@ -0,0 +1,18 @@
+TARGET = tst_blackbox-qt
+
+HEADERS = tst_blackboxqt.h tst_blackboxbase.h
+SOURCES = tst_blackboxqt.cpp tst_blackboxbase.cpp
+OBJECTS_DIR = qt
+MOC_DIR = $${OBJECTS_DIR}-moc
+
+include(../auto.pri)
+
+DATA_DIRS = testdata-qt ../find
+
+for(data_dir, DATA_DIRS) {
+ files = $$files($$PWD/$$data_dir/*, true)
+ win32:files ~= s|\\\\|/|g
+ for(file, files):!exists($$file/*):FILES += $$file
+}
+
+OTHER_FILES += $$FILES
diff --git a/tests/auto/blackbox/blackbox-qt.qbs b/tests/auto/blackbox/blackbox-qt.qbs
new file mode 100644
index 000000000..f8a2f0ec4
--- /dev/null
+++ b/tests/auto/blackbox/blackbox-qt.qbs
@@ -0,0 +1,22 @@
+import qbs
+
+QbsAutotest {
+ testName: "blackbox-qt"
+ Depends { name: "qbs_app" }
+ Depends { name: "qbs-setup-toolchains" }
+ Group {
+ name: "testdata"
+ prefix: "testdata-qt/"
+ files: ["**/*"]
+ fileTags: []
+ }
+ files: [
+ "../shared.h",
+ "tst_blackboxbase.cpp",
+ "tst_blackboxbase.h",
+ "tst_blackboxqt.cpp",
+ "tst_blackboxqt.h",
+ ]
+ // TODO: Use Utilities.cStringQuote
+ cpp.defines: base.concat(['SRCDIR="' + path + '"'])
+}
diff --git a/tests/auto/blackbox/blackbox.qbs b/tests/auto/blackbox/blackbox.qbs
index 7ae40e471..0150876f7 100644
--- a/tests/auto/blackbox/blackbox.qbs
+++ b/tests/auto/blackbox/blackbox.qbs
@@ -1,72 +1,22 @@
-import qbs 1.0
+import qbs
-Project {
- name: "blackbox tests"
-
- QbsAutotest {
- testName: "blackbox"
- Depends { name: "Qt.xml" }
- Depends { name: "qbs_app" }
- Depends { name: "qbs-setup-toolchains" }
- Group {
- name: "testdata"
- prefix: "testdata/"
- files: ["**/*"]
- fileTags: []
- }
- files: [
- "../shared.h",
- "tst_blackboxbase.cpp",
- "tst_blackboxbase.h",
- "tst_blackbox.cpp",
- "tst_blackbox.h",
- ]
- // TODO: Use Utilities.cStringQuote
- cpp.defines: base.concat(['SRCDIR="' + path + '"'])
- }
-
- QbsAutotest {
- testName: "blackbox-java"
- Depends { name: "qbs_app" }
- Depends { name: "qbs-setup-toolchains" }
- Group {
- name: "testdata"
- prefix: "testdata-java/"
- files: ["**/*"]
- fileTags: []
- }
- files: [
- "../shared.h",
- "tst_blackboxbase.cpp",
- "tst_blackboxbase.h",
- "tst_blackboxjava.cpp",
- "tst_blackboxjava.h",
- ]
- // TODO: Use Utilities.cStringQuote
- cpp.defines: base.concat(['SRCDIR="' + path + '"'])
- }
-
- QbsAutotest {
- testName: "blackbox-clangdb"
-
- Depends { name: "qbs_app" }
- Depends { name: "qbs-setup-toolchains" }
-
- Group {
- name: "testdata"
- prefix: "testdata-clangdb/"
- files: ["**/*"]
- fileTags: []
- }
-
- files: [
- "../shared.h",
- "tst_blackboxbase.cpp",
- "tst_blackboxbase.h",
- "tst_clangdb.cpp",
- "tst_clangdb.h",
- ]
- // TODO: Use Utilities.cStringQuote
- cpp.defines: base.concat(['SRCDIR="' + path + '"'])
+QbsAutotest {
+ testName: "blackbox"
+ Depends { name: "qbs_app" }
+ Depends { name: "qbs-setup-toolchains" }
+ Group {
+ name: "testdata"
+ prefix: "testdata/"
+ files: ["**/*"]
+ fileTags: []
}
+ files: [
+ "../shared.h",
+ "tst_blackboxbase.cpp",
+ "tst_blackboxbase.h",
+ "tst_blackbox.cpp",
+ "tst_blackbox.h",
+ ]
+ // TODO: Use Utilities.cStringQuote
+ cpp.defines: base.concat(['SRCDIR="' + path + '"'])
}
diff --git a/tests/auto/blackbox/find/find-android.qbs b/tests/auto/blackbox/find/find-android.qbs
index 4b39afeea..23c8b2f91 100644
--- a/tests/auto/blackbox/find/find-android.qbs
+++ b/tests/auto/blackbox/find/find-android.qbs
@@ -8,7 +8,7 @@ Product {
Depends { name: "Android.ndk"; required: false }
type: ["json"]
Rule {
- inputs: ["qbs"]
+ multiplex: true
Artifact {
filePath: ["android.json"]
fileTags: ["json"]
@@ -24,6 +24,7 @@ Product {
if (product.moduleProperty("Android.ndk", "present")) {
tools["ndk"] = product.moduleProperty("Android.ndk", "ndkDir");
+ tools["ndk-samples"] = product.Android.ndk.ndkSamplesDir;
}
var tf;
diff --git a/tests/auto/blackbox/find/find-jdk.qbs b/tests/auto/blackbox/find/find-jdk.qbs
index 6bfc70ac5..411569f23 100644
--- a/tests/auto/blackbox/find/find-jdk.qbs
+++ b/tests/auto/blackbox/find/find-jdk.qbs
@@ -5,7 +5,7 @@ Product {
Depends { name: "java"; required: false }
type: ["json"]
Rule {
- inputs: ["qbs"]
+ multiplex: true
Artifact {
filePath: ["jdk.json"]
fileTags: ["json"]
diff --git a/tests/auto/blackbox/find/find-nodejs.qbs b/tests/auto/blackbox/find/find-nodejs.qbs
index 107937da7..d8b555ecd 100644
--- a/tests/auto/blackbox/find/find-nodejs.qbs
+++ b/tests/auto/blackbox/find/find-nodejs.qbs
@@ -5,7 +5,7 @@ Product {
Depends { name: "nodejs"; required: false }
type: ["json"]
Rule {
- inputs: ["qbs"]
+ multiplex: true
Artifact {
filePath: ["nodejs.json"]
fileTags: ["json"]
diff --git a/tests/auto/blackbox/find/find-typescript.qbs b/tests/auto/blackbox/find/find-typescript.qbs
index e5616633a..df2f86a84 100644
--- a/tests/auto/blackbox/find/find-typescript.qbs
+++ b/tests/auto/blackbox/find/find-typescript.qbs
@@ -6,7 +6,7 @@ Product {
Depends { name: "typescript"; required: false }
type: ["json"]
Rule {
- inputs: ["qbs"]
+ multiplex: true
Artifact {
filePath: ["typescript.json"]
fileTags: ["json"]
diff --git a/tests/auto/blackbox/find/find-xcode.qbs b/tests/auto/blackbox/find/find-xcode.qbs
new file mode 100644
index 000000000..b42b2deb7
--- /dev/null
+++ b/tests/auto/blackbox/find/find-xcode.qbs
@@ -0,0 +1,41 @@
+import qbs
+import qbs.TextFile
+
+Product {
+ Depends { name: "xcode"; required: false }
+ type: ["json"]
+ Rule {
+ multiplex: true
+ Artifact {
+ filePath: ["xcode.json"]
+ fileTags: ["json"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = output.filePath;
+ cmd.sourceCode = function() {
+ var tools = {};
+ if (product.moduleProperty("xcode", "present")) {
+ var keys = [
+ "developerPath",
+ "version"
+ ];
+ for (var i = 0; i < keys.length; ++i) {
+ var key = keys[i];
+ tools[key] = product.xcode[key];
+ }
+ }
+
+ var tf;
+ try {
+ tf = new TextFile(output.filePath, TextFile.WriteOnly);
+ tf.writeLine(JSON.stringify(tools, undefined, 4));
+ } finally {
+ if (tf)
+ tf.close();
+ }
+ };
+ return cmd;
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata-apple/apple-dmg/apple-dmg.qbs b/tests/auto/blackbox/testdata-apple/apple-dmg/apple-dmg.qbs
new file mode 100644
index 000000000..3bccebfd0
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/apple-dmg.qbs
@@ -0,0 +1,88 @@
+import qbs
+
+Project {
+ AppleApplicationDiskImage {
+ Depends { name: "myapp" }
+ Depends { name: "ib" }
+ dmg.volumeName: "My Great App"
+ dmg.iconSize: 128
+ dmg.windowWidth: 640
+ dmg.windowHeight: 280
+ files: [
+ "white.iconset",
+ ]
+ }
+
+ CppApplication {
+ name: "myapp"
+ targetName: "My Great App"
+ files: ["main.c"]
+
+ Group {
+ fileTagsFilter: ["bundle.content"]
+ qbs.install: true
+ qbs.installDir: "/Applications"
+ qbs.installSourceBase: product.buildDirectory
+ }
+ }
+
+ AppleDiskImage {
+ name: "hellodmg"
+ targetName: "hellodmg-1.0"
+ + (qbs.architecture ? "-" + qbs.architecture : "")
+
+ dmg.volumeName: "Hello DMG"
+
+ files: [
+ "hello.icns",
+ "hello.tif"
+ ]
+
+ Group {
+ files: ["en_US.lproj/eula.txt"]
+ fileTags: ["dmg.input", "dmg.license.input"]
+ dmg.iconX: 320
+ dmg.iconY: 240
+ dmg.licenseLocale: "en_US"
+ }
+
+ Group {
+ files: ["*.lproj/**"]
+ excludeFiles: ["en_US.lproj/eula.txt"]
+ }
+ }
+
+ AppleDiskImage {
+ name: "green"
+ dmg.backgroundColor: "green"
+ }
+
+ AppleDiskImage {
+ name: "german"
+ dmg.defaultLicenseLocale: "de_DE"
+
+ Group {
+ files: ["*.lproj/**"]
+ }
+ }
+
+ AppleDiskImage {
+ name: "custom-buttons"
+
+ Group {
+ files: ["ru_RU.lproj/eula.txt"]
+ dmg.licenseLocale: "sv_SE" // override auto-detected ru_RU with sv_SE
+ dmg.licenseLanguageName: "Swedish, not Russian"
+ dmg.licenseAgreeButtonText: "Of course"
+ dmg.licenseDisagreeButtonText: "Never!"
+ dmg.licensePrintButtonText: "Make Paper"
+ dmg.licenseSaveButtonText: "Make Bits"
+ dmg.licenseInstructionText: "Do please agree to the license!"
+ }
+
+ Group {
+ files: ["*.lproj/**"]
+ excludeFiles: ["ru_RU.lproj/eula.txt"]
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata-apple/apple-dmg/de_DE.lproj/eula.txt b/tests/auto/blackbox/testdata-apple/apple-dmg/de_DE.lproj/eula.txt
new file mode 100644
index 000000000..7ca2bf84b
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/de_DE.lproj/eula.txt
@@ -0,0 +1,6 @@
+FIKTIVE UNTERNEHMEN
+SOFTWARE BEISPIEL VEREINBARUNG
+
+Sie stimmen zu, dass Sie nicht mit dieser App auf Atomwaffen zu machen.
+
+Sie bestätigen, dass Qbs das Beste ist.
diff --git a/tests/auto/blackbox/testdata-apple/apple-dmg/en_GB.lproj/eula.txt b/tests/auto/blackbox/testdata-apple/apple-dmg/en_GB.lproj/eula.txt
new file mode 100644
index 000000000..e2b7adbed
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/en_GB.lproj/eula.txt
@@ -0,0 +1,6 @@
+FICTIONAL CORPORATION
+SOFTWARE EXAMPLE AGREEMENT
+
+You agree that you will not use this app to make nuclear weapons.
+
+You agree that Qbs is the best.
diff --git a/tests/auto/blackbox/testdata-apple/apple-dmg/en_US.lproj/eula.txt b/tests/auto/blackbox/testdata-apple/apple-dmg/en_US.lproj/eula.txt
new file mode 100644
index 000000000..e2b7adbed
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/en_US.lproj/eula.txt
@@ -0,0 +1,6 @@
+FICTIONAL CORPORATION
+SOFTWARE EXAMPLE AGREEMENT
+
+You agree that you will not use this app to make nuclear weapons.
+
+You agree that Qbs is the best.
diff --git a/tests/auto/blackbox/testdata-apple/apple-dmg/fr_FR.lproj/eula.txt b/tests/auto/blackbox/testdata-apple/apple-dmg/fr_FR.lproj/eula.txt
new file mode 100644
index 000000000..48a9af57c
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/fr_FR.lproj/eula.txt
@@ -0,0 +1,6 @@
+SOCIÉTÉ FICTIONNEL
+EXEMPLE D'ACCORD DU LOGICIEL
+
+Vous vous engagez à ne pas utiliser cette application pour fabriquer des armes nucléaires.
+
+Vous acceptez que Qbs est le meilleur.
diff --git a/tests/auto/blackbox/testdata-apple/apple-dmg/hello.icns b/tests/auto/blackbox/testdata-apple/apple-dmg/hello.icns
new file mode 100644
index 000000000..b8ff0c53b
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/hello.icns
Binary files differ
diff --git a/tests/auto/blackbox/testdata-apple/apple-dmg/hello.tif b/tests/auto/blackbox/testdata-apple/apple-dmg/hello.tif
new file mode 100644
index 000000000..b58b4548d
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/hello.tif
Binary files differ
diff --git a/tests/auto/blackbox/testdata-apple/apple-dmg/ja_JP.lproj/eula.txt b/tests/auto/blackbox/testdata-apple/apple-dmg/ja_JP.lproj/eula.txt
new file mode 100644
index 000000000..e44c34bb3
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/ja_JP.lproj/eula.txt
@@ -0,0 +1,6 @@
+架空CORPORATION
+ソフトウェア例契約
+
+あなたは核兵器を作るために、このアプリを使用しないことに同意します。
+
+あなたは、QBSがベストであることに同意するものとします。
diff --git a/tests/auto/blackbox/testdata-apple/apple-dmg/ko_KR.lproj/eula.rtf b/tests/auto/blackbox/testdata-apple/apple-dmg/ko_KR.lproj/eula.rtf
new file mode 100644
index 000000000..5b7c49d56
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/ko_KR.lproj/eula.rtf
@@ -0,0 +1,49 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1265
+{\fonttbl\f0\fnil\fcharset129 AppleSDGothicNeo-Regular;\f1\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\margl1440\margr1440\vieww10800\viewh8400\viewkind0
+\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural
+
+\f0\b\fs24 \cf0 \'c7\'e3\'b1\'b8
+\f1 CORPORATION\
+
+\f0 \'bc\'d2\'c7\'c1\'c6\'ae\'bf\'fe\'be\'ee
+\f1
+\f0 \'bf\'b9
+\f1
+\f0 \'b0\'e8\'be\'e0
+\f1\b0 \
+\
+
+\f0 \'b4\'e7\'bd\'c5\'c0\'ba
+\f1
+\f0 \'b4\'e7\'bd\'c5\'c0\'cc
+\f1
+\f0 \'c7\'d9\'b9\'ab\'b1\'e2\'b8\'a6
+\f1
+\f0 \'b8\'b8\'b5\'e9\'b1\'e2
+\f1
+\f0 \'c0\'a7\'c7\'d8\'c0\'cc
+\f1
+\f0 \'c0\'c0\'bf\'eb
+\f1
+\f0 \'c7\'c1\'b7\'ce\'b1\'d7\'b7\'a5\'c0\'bb
+\f1
+\f0 \'bb\'e7\'bf\'eb\'c7\'cf\'c1\'f6
+\f1
+\f0 \'be\'ca\'c0\'bb
+\f1
+\f0 \'b0\'cd\'bf\'a1
+\f1
+\f0 \'b5\'bf\'c0\'c7\'c7\'d5\'b4\'cf\'b4\'d9
+\f1 .\
+\
+
+\f0 \'b4\'e7\'bd\'c5\'c0\'ba
+\f1 QBS
+\f0 \'b0\'a1
+\f1
+\f0 \'c3\'d6\'b0\'ed\'b6\'f3\'b0\'ed
+\f1
+\f0 \'b5\'bf\'c0\'c7\'c7\'d5\'b4\'cf\'b4\'d9
+\f1 .} \ No newline at end of file
diff --git a/tests/auto/blackbox/testdata-apple/apple-dmg/main.c b/tests/auto/blackbox/testdata-apple/apple-dmg/main.c
new file mode 100644
index 000000000..76e819701
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/main.c
@@ -0,0 +1 @@
+int main() { return 0; }
diff --git a/tests/auto/blackbox/testdata-apple/apple-dmg/ru_RU.lproj/eula.txt b/tests/auto/blackbox/testdata-apple/apple-dmg/ru_RU.lproj/eula.txt
new file mode 100644
index 000000000..e2b7adbed
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/ru_RU.lproj/eula.txt
@@ -0,0 +1,6 @@
+FICTIONAL CORPORATION
+SOFTWARE EXAMPLE AGREEMENT
+
+You agree that you will not use this app to make nuclear weapons.
+
+You agree that Qbs is the best.
diff --git a/tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16.png b/tests/auto/blackbox/testdata-apple/apple-dmg/white.iconset/icon_16x16.png
index 60365798f..60365798f 100644
--- a/tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16.png
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/white.iconset/icon_16x16.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16@2x.png b/tests/auto/blackbox/testdata-apple/apple-dmg/white.iconset/icon_16x16@2x.png
index 20369000d..20369000d 100644
--- a/tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16@2x.png
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/white.iconset/icon_16x16@2x.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata-apple/apple-dmg/zh_CN.lproj/eula.odt b/tests/auto/blackbox/testdata-apple/apple-dmg/zh_CN.lproj/eula.odt
new file mode 100644
index 000000000..21345e536
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/zh_CN.lproj/eula.odt
Binary files differ
diff --git a/tests/auto/blackbox/testdata-apple/apple-dmg/zh_TW.lproj/eula.docx b/tests/auto/blackbox/testdata-apple/apple-dmg/zh_TW.lproj/eula.docx
new file mode 100644
index 000000000..9e48895ac
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-dmg/zh_TW.lproj/eula.docx
Binary files differ
diff --git a/tests/auto/blackbox/testdata-apple/apple-multiconfig/app.c b/tests/auto/blackbox/testdata-apple/apple-multiconfig/app.c
new file mode 100644
index 000000000..d0bb0c43c
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-multiconfig/app.c
@@ -0,0 +1,2 @@
+extern int foo();
+int main() { return foo(); }
diff --git a/tests/auto/blackbox/testdata-apple/apple-multiconfig/apple-multiconfig.qbs b/tests/auto/blackbox/testdata-apple/apple-multiconfig/apple-multiconfig.qbs
new file mode 100644
index 000000000..f34307bf1
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-multiconfig/apple-multiconfig.qbs
@@ -0,0 +1,136 @@
+import qbs
+import qbs.Utilities
+
+Project {
+ minimumQbsVersion: "1.8"
+
+ CppApplication {
+ Depends { name: "singlelib" }
+ Depends { name: "bundle" }
+ name: "singleapp"
+ targetName: "singleapp"
+ files: ["app.c"]
+ cpp.rpaths: qbs.targetOS.contains("darwin") ? ["@loader_path/../../../"] : []
+ cpp.minimumMacosVersion: "10.5"
+
+ // Turn off multiplexing
+ aggregate: false
+ multiplexByQbsProperties: []
+
+ Group {
+ fileTagsFilter: ["bundle.content"]
+ qbs.install: true
+ qbs.installSourceBase: product.buildDirectory
+ }
+ }
+
+ CppApplication {
+ Depends { name: "singlelib" }
+ Depends { name: "bundle" }
+ name: "singleapp_agg"
+ targetName: "singleapp_agg"
+ files: ["app.c"]
+ cpp.rpaths: qbs.targetOS.contains("darwin") ? ["@loader_path/../../../"] : []
+ cpp.minimumMacosVersion: "10.5"
+
+ // Force aggregation when not needed
+ aggregate: true
+ qbs.architectures: ["x86_64"]
+ qbs.buildVariants: ["release"]
+
+ Group {
+ fileTagsFilter: ["bundle.content"]
+ qbs.install: true
+ qbs.installSourceBase: product.buildDirectory
+ }
+ }
+
+ DynamicLibrary {
+ Depends { name: "cpp" }
+ Depends { name: "bundle" }
+ name: "singlelib"
+ targetName: "singlelib"
+ files: ["lib.c"]
+ cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined
+ cpp.defines: ["VARIANT=" + Utilities.cStringQuote(qbs.buildVariant)]
+
+ // Turn off multiplexing
+ aggregate: false
+ multiplexByQbsProperties: []
+
+ Group {
+ fileTagsFilter: ["bundle.content"]
+ qbs.install: true
+ qbs.installSourceBase: product.buildDirectory
+ }
+ }
+
+ CppApplication {
+ Depends { name: "multilib" }
+ Depends { name: "bundle" }
+ name: "multiapp"
+ targetName: "multiapp"
+ files: ["app.c"]
+ cpp.rpaths: qbs.targetOS.contains("darwin") ? ["@loader_path/../../../"] : []
+ cpp.minimumMacosVersion: "10.5"
+
+ Group {
+ fileTagsFilter: ["bundle.content"]
+ qbs.install: true
+ qbs.installSourceBase: product.buildDirectory
+ }
+ }
+
+ CppApplication {
+ Depends { name: "multilib" }
+ Depends { name: "bundle" }
+ name: "fatmultiapp"
+ targetName: "fatmultiapp"
+ files: ["app.c"]
+ cpp.rpaths: qbs.targetOS.contains("darwin") ? ["@loader_path/../../../"] : []
+ cpp.minimumMacosVersion: "10.5"
+ qbs.architectures: ["x86", "x86_64"]
+
+ Group {
+ fileTagsFilter: ["bundle.content"]
+ qbs.install: true
+ qbs.installSourceBase: product.buildDirectory
+ }
+ }
+
+ DynamicLibrary {
+ Depends { name: "cpp" }
+ Depends { name: "bundle" }
+ name: "multilib"
+ targetName: "multilib"
+ files: ["lib.c"]
+ cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined
+ cpp.defines: ["VARIANT=" + Utilities.cStringQuote(qbs.buildVariant)]
+ qbs.architectures: ["x86", "x86_64"]
+ qbs.buildVariants: ["release", "debug", "profile"]
+
+ Group {
+ fileTagsFilter: ["bundle.content"]
+ qbs.install: true
+ qbs.installSourceBase: product.buildDirectory
+ }
+ }
+
+ DynamicLibrary {
+ Depends { name: "cpp" }
+ Depends { name: "bundle" }
+ name: "multilib-no-release"
+ targetName: "multilib-no-release"
+ files: ["lib.c"]
+ cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined
+ cpp.defines: ["VARIANT=" + Utilities.cStringQuote(qbs.buildVariant)]
+ qbs.architectures: ["x86", "x86_64"]
+ qbs.buildVariants: ["debug", "profile"]
+
+ Group {
+ fileTagsFilter: ["bundle.content"]
+ qbs.install: true
+ qbs.installSourceBase: product.buildDirectory
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata-apple/apple-multiconfig/lib.c b/tests/auto/blackbox/testdata-apple/apple-multiconfig/lib.c
new file mode 100644
index 000000000..37dc6f016
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/apple-multiconfig/lib.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+int foo()
+{
+#ifdef __i386__
+ printf("Hello from " VARIANT " i386\n");
+#endif
+#ifdef __x86_64__
+ printf("Hello from " VARIANT " x86_64\n");
+#endif
+ return 0;
+}
diff --git a/tests/auto/blackbox/testdata/bundle-structure/bundle-structure.qbs b/tests/auto/blackbox/testdata-apple/bundle-structure/bundle-structure.qbs
index a7c3e20bf..a7c3e20bf 100644
--- a/tests/auto/blackbox/testdata/bundle-structure/bundle-structure.qbs
+++ b/tests/auto/blackbox/testdata-apple/bundle-structure/bundle-structure.qbs
diff --git a/tests/auto/blackbox/testdata/bundle-structure/dummy.c b/tests/auto/blackbox/testdata-apple/bundle-structure/dummy.c
index 210c8274e..210c8274e 100644
--- a/tests/auto/blackbox/testdata/bundle-structure/dummy.c
+++ b/tests/auto/blackbox/testdata-apple/bundle-structure/dummy.c
diff --git a/tests/auto/blackbox/testdata/bundle-structure/dummy.h b/tests/auto/blackbox/testdata-apple/bundle-structure/dummy.h
index 50841a226..50841a226 100644
--- a/tests/auto/blackbox/testdata/bundle-structure/dummy.h
+++ b/tests/auto/blackbox/testdata-apple/bundle-structure/dummy.h
diff --git a/tests/auto/blackbox/testdata/bundle-structure/dummy_p.h b/tests/auto/blackbox/testdata-apple/bundle-structure/dummy_p.h
index 50841a226..50841a226 100644
--- a/tests/auto/blackbox/testdata/bundle-structure/dummy_p.h
+++ b/tests/auto/blackbox/testdata-apple/bundle-structure/dummy_p.h
diff --git a/tests/auto/blackbox/testdata/bundle-structure/resource.txt b/tests/auto/blackbox/testdata-apple/bundle-structure/resource.txt
index e69de29bb..e69de29bb 100644
--- a/tests/auto/blackbox/testdata/bundle-structure/resource.txt
+++ b/tests/auto/blackbox/testdata-apple/bundle-structure/resource.txt
diff --git a/tests/auto/blackbox/testdata/deploymentTarget/deployment.qbs b/tests/auto/blackbox/testdata-apple/deploymentTarget/deployment.qbs
index f805de67c..f805de67c 100644
--- a/tests/auto/blackbox/testdata/deploymentTarget/deployment.qbs
+++ b/tests/auto/blackbox/testdata-apple/deploymentTarget/deployment.qbs
diff --git a/tests/auto/blackbox/testdata/deploymentTarget/main.c b/tests/auto/blackbox/testdata-apple/deploymentTarget/main.c
index 210c8274e..210c8274e 100644
--- a/tests/auto/blackbox/testdata/deploymentTarget/main.c
+++ b/tests/auto/blackbox/testdata-apple/deploymentTarget/main.c
diff --git a/tests/auto/blackbox/testdata/embedInfoPlist/embedInfoPlist.qbs b/tests/auto/blackbox/testdata-apple/embedInfoPlist/embedInfoPlist.qbs
index 93d94c66b..87c0aaa36 100644
--- a/tests/auto/blackbox/testdata/embedInfoPlist/embedInfoPlist.qbs
+++ b/tests/auto/blackbox/testdata-apple/embedInfoPlist/embedInfoPlist.qbs
@@ -9,6 +9,7 @@ Project {
files: ["main.m"]
cpp.frameworks: ["Foundation"]
cpp.rpaths: ["@loader_path"]
+ cpp.minimumMacosVersion: "10.5"
bundle.infoPlist: ({
"QBS": "org.qt-project.qbs.testdata.embedInfoPlist"
})
diff --git a/tests/auto/blackbox/testdata/embedInfoPlist/main.m b/tests/auto/blackbox/testdata-apple/embedInfoPlist/main.m
index b3f362223..b3f362223 100644
--- a/tests/auto/blackbox/testdata/embedInfoPlist/main.m
+++ b/tests/auto/blackbox/testdata-apple/embedInfoPlist/main.m
diff --git a/tests/auto/blackbox/testdata/frameworkStructure/BaseResource b/tests/auto/blackbox/testdata-apple/frameworkStructure/BaseResource
index e69de29bb..e69de29bb 100644
--- a/tests/auto/blackbox/testdata/frameworkStructure/BaseResource
+++ b/tests/auto/blackbox/testdata-apple/frameworkStructure/BaseResource
diff --git a/tests/auto/blackbox/testdata/frameworkStructure/Widget.cpp b/tests/auto/blackbox/testdata-apple/frameworkStructure/Widget.cpp
index e17b96750..e17b96750 100644
--- a/tests/auto/blackbox/testdata/frameworkStructure/Widget.cpp
+++ b/tests/auto/blackbox/testdata-apple/frameworkStructure/Widget.cpp
diff --git a/tests/auto/blackbox/testdata/frameworkStructure/Widget.h b/tests/auto/blackbox/testdata-apple/frameworkStructure/Widget.h
index e5dacdb56..e5dacdb56 100644
--- a/tests/auto/blackbox/testdata/frameworkStructure/Widget.h
+++ b/tests/auto/blackbox/testdata-apple/frameworkStructure/Widget.h
diff --git a/tests/auto/blackbox/testdata/frameworkStructure/WidgetPrivate.h b/tests/auto/blackbox/testdata-apple/frameworkStructure/WidgetPrivate.h
index 50841a226..50841a226 100644
--- a/tests/auto/blackbox/testdata/frameworkStructure/WidgetPrivate.h
+++ b/tests/auto/blackbox/testdata-apple/frameworkStructure/WidgetPrivate.h
diff --git a/tests/auto/blackbox/testdata/frameworkStructure/en.lproj/EnglishResource b/tests/auto/blackbox/testdata-apple/frameworkStructure/en.lproj/EnglishResource
index e69de29bb..e69de29bb 100644
--- a/tests/auto/blackbox/testdata/frameworkStructure/en.lproj/EnglishResource
+++ b/tests/auto/blackbox/testdata-apple/frameworkStructure/en.lproj/EnglishResource
diff --git a/tests/auto/blackbox/testdata/frameworkStructure/frameworkStructure.qbs b/tests/auto/blackbox/testdata-apple/frameworkStructure/frameworkStructure.qbs
index 39b3a1b58..39b3a1b58 100644
--- a/tests/auto/blackbox/testdata/frameworkStructure/frameworkStructure.qbs
+++ b/tests/auto/blackbox/testdata-apple/frameworkStructure/frameworkStructure.qbs
diff --git a/tests/auto/blackbox/testdata/ib/assetcatalog/EmptyStoryboard.storyboard b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/EmptyStoryboard.storyboard
index 71b6b6857..71b6b6857 100644
--- a/tests/auto/blackbox/testdata/ib/assetcatalog/EmptyStoryboard.storyboard
+++ b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/EmptyStoryboard.storyboard
diff --git a/tests/auto/blackbox/testdata-apple/ib/assetcatalog/MainMenu.xib b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/MainMenu.xib
new file mode 100644
index 000000000..07dd40b0b
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/MainMenu.xib
@@ -0,0 +1,4666 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
+ <data>
+ <int key="IBDocument.SystemTarget">1080</int>
+ <string key="IBDocument.SystemVersion">11D50</string>
+ <string key="IBDocument.InterfaceBuilderVersion">2457</string>
+ <string key="IBDocument.AppKitVersion">1138.32</string>
+ <string key="IBDocument.HIToolboxVersion">568.00</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="NS.object.0">2457</string>
+ </object>
+ <array key="IBDocument.IntegratedClassDependencies">
+ <string>NSWindowTemplate</string>
+ <string>NSView</string>
+ <string>NSMenu</string>
+ <string>NSMenuItem</string>
+ <string>NSCustomObject</string>
+ </array>
+ <array key="IBDocument.PluginDependencies">
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </array>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
+ <integer value="1" key="NS.object.0"/>
+ </object>
+ <array class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
+ <object class="NSCustomObject" id="1021">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSCustomObject" id="1014">
+ <string key="NSClassName">FirstResponder</string>
+ </object>
+ <object class="NSCustomObject" id="1050">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSMenu" id="649796088">
+ <string key="NSTitle">AMainMenu</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="694149608">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Test</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <object class="NSCustomResource" key="NSOnImage" id="35465992">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSMenuCheckmark</string>
+ </object>
+ <object class="NSCustomResource" key="NSMixedImage" id="502551668">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSMenuMixedState</string>
+ </object>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="110575045">
+ <string key="NSTitle">Test</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="238522557">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">About Test</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="304266470">
+ <reference key="NSMenu" ref="110575045"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="609285721">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Preferences…</string>
+ <string key="NSKeyEquiv">,</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="481834944">
+ <reference key="NSMenu" ref="110575045"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1046388886">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Services</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="752062318">
+ <string key="NSTitle">Services</string>
+ <array class="NSMutableArray" key="NSMenuItems"/>
+ <string key="NSName">_NSServicesMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="646227648">
+ <reference key="NSMenu" ref="110575045"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="755159360">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Hide Test</string>
+ <string key="NSKeyEquiv">h</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="342932134">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Hide Others</string>
+ <string key="NSKeyEquiv">h</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="908899353">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Show All</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1056857174">
+ <reference key="NSMenu" ref="110575045"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="632727374">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Quit Test</string>
+ <string key="NSKeyEquiv">q</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ <string key="NSName">_NSAppleMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="379814623">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">File</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="720053764">
+ <string key="NSTitle">File</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="705341025">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">New</string>
+ <string key="NSKeyEquiv">n</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="722745758">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Open…</string>
+ <string key="NSKeyEquiv">o</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1025936716">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Open Recent</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="1065607017">
+ <string key="NSTitle">Open Recent</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="759406840">
+ <reference key="NSMenu" ref="1065607017"/>
+ <string key="NSTitle">Clear Menu</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ <string key="NSName">_NSRecentDocumentsMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="425164168">
+ <reference key="NSMenu" ref="720053764"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="776162233">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Close</string>
+ <string key="NSKeyEquiv">w</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1023925487">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Save…</string>
+ <string key="NSKeyEquiv">s</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="579971712">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Revert to Saved</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1010469920">
+ <reference key="NSMenu" ref="720053764"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="294629803">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Page Setup...</string>
+ <string key="NSKeyEquiv">P</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSToolTip"/>
+ </object>
+ <object class="NSMenuItem" id="49223823">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Print…</string>
+ <string key="NSKeyEquiv">p</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="952259628">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Edit</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="789758025">
+ <string key="NSTitle">Edit</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="1058277027">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Undo</string>
+ <string key="NSKeyEquiv">z</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="790794224">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Redo</string>
+ <string key="NSKeyEquiv">Z</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1040322652">
+ <reference key="NSMenu" ref="789758025"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="296257095">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Cut</string>
+ <string key="NSKeyEquiv">x</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="860595796">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Copy</string>
+ <string key="NSKeyEquiv">c</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="29853731">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Paste</string>
+ <string key="NSKeyEquiv">v</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="82994268">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Paste and Match Style</string>
+ <string key="NSKeyEquiv">V</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="437104165">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Delete</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="583158037">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Select All</string>
+ <string key="NSKeyEquiv">a</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="212016141">
+ <reference key="NSMenu" ref="789758025"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="892235320">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Find</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="963351320">
+ <string key="NSTitle">Find</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="447796847">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Find…</string>
+ <string key="NSKeyEquiv">f</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">1</int>
+ </object>
+ <object class="NSMenuItem" id="738670835">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Find and Replace…</string>
+ <string key="NSKeyEquiv">f</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">12</int>
+ </object>
+ <object class="NSMenuItem" id="326711663">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Find Next</string>
+ <string key="NSKeyEquiv">g</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">2</int>
+ </object>
+ <object class="NSMenuItem" id="270902937">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Find Previous</string>
+ <string key="NSKeyEquiv">G</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">3</int>
+ </object>
+ <object class="NSMenuItem" id="159080638">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Use Selection for Find</string>
+ <string key="NSKeyEquiv">e</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">7</int>
+ </object>
+ <object class="NSMenuItem" id="88285865">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Jump to Selection</string>
+ <string key="NSKeyEquiv">j</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="972420730">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Spelling and Grammar</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="769623530">
+ <string key="NSTitle">Spelling and Grammar</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="679648819">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Show Spelling and Grammar</string>
+ <string key="NSKeyEquiv">:</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="96193923">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Check Document Now</string>
+ <string key="NSKeyEquiv">;</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="859480356">
+ <reference key="NSMenu" ref="769623530"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="948374510">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Check Spelling While Typing</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="967646866">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Check Grammar With Spelling</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="795346622">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Correct Spelling Automatically</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="507821607">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Substitutions</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="698887838">
+ <string key="NSTitle">Substitutions</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="65139061">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Show Substitutions</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="19036812">
+ <reference key="NSMenu" ref="698887838"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="605118523">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Smart Copy/Paste</string>
+ <string key="NSKeyEquiv">f</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">1</int>
+ </object>
+ <object class="NSMenuItem" id="197661976">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Smart Quotes</string>
+ <string key="NSKeyEquiv">g</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">2</int>
+ </object>
+ <object class="NSMenuItem" id="672708820">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Smart Dashes</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="708854459">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Smart Links</string>
+ <string key="NSKeyEquiv">G</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">3</int>
+ </object>
+ <object class="NSMenuItem" id="537092702">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Text Replacement</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="288088188">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Transformations</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="579392910">
+ <string key="NSTitle">Transformations</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="1060694897">
+ <reference key="NSMenu" ref="579392910"/>
+ <string key="NSTitle">Make Upper Case</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="879586729">
+ <reference key="NSMenu" ref="579392910"/>
+ <string key="NSTitle">Make Lower Case</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="56570060">
+ <reference key="NSMenu" ref="579392910"/>
+ <string key="NSTitle">Capitalize</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="676164635">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Speech</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="785027613">
+ <string key="NSTitle">Speech</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="731782645">
+ <reference key="NSMenu" ref="785027613"/>
+ <string key="NSTitle">Start Speaking</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="680220178">
+ <reference key="NSMenu" ref="785027613"/>
+ <string key="NSTitle">Stop Speaking</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ </object>
+ </object>
+ </array>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="302598603">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Format</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="941447902">
+ <string key="NSTitle">Format</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="792887677">
+ <reference key="NSMenu" ref="941447902"/>
+ <string key="NSTitle">Font</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="786677654">
+ <string key="NSTitle">Font</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="159677712">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Show Fonts</string>
+ <string key="NSKeyEquiv">t</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="305399458">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Bold</string>
+ <string key="NSKeyEquiv">b</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">2</int>
+ </object>
+ <object class="NSMenuItem" id="814362025">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Italic</string>
+ <string key="NSKeyEquiv">i</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">1</int>
+ </object>
+ <object class="NSMenuItem" id="330926929">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Underline</string>
+ <string key="NSKeyEquiv">u</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="533507878">
+ <reference key="NSMenu" ref="786677654"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="158063935">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Bigger</string>
+ <string key="NSKeyEquiv">+</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">3</int>
+ </object>
+ <object class="NSMenuItem" id="885547335">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Smaller</string>
+ <string key="NSKeyEquiv">-</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">4</int>
+ </object>
+ <object class="NSMenuItem" id="901062459">
+ <reference key="NSMenu" ref="786677654"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="767671776">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Kern</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="175441468">
+ <string key="NSTitle">Kern</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="252969304">
+ <reference key="NSMenu" ref="175441468"/>
+ <string key="NSTitle">Use Default</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="766922938">
+ <reference key="NSMenu" ref="175441468"/>
+ <string key="NSTitle">Use None</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="677519740">
+ <reference key="NSMenu" ref="175441468"/>
+ <string key="NSTitle">Tighten</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="238351151">
+ <reference key="NSMenu" ref="175441468"/>
+ <string key="NSTitle">Loosen</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="691570813">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Ligatures</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="1058217995">
+ <string key="NSTitle">Ligatures</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="706297211">
+ <reference key="NSMenu" ref="1058217995"/>
+ <string key="NSTitle">Use Default</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="568384683">
+ <reference key="NSMenu" ref="1058217995"/>
+ <string key="NSTitle">Use None</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="663508465">
+ <reference key="NSMenu" ref="1058217995"/>
+ <string key="NSTitle">Use All</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="769124883">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Baseline</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="18263474">
+ <string key="NSTitle">Baseline</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="257962622">
+ <reference key="NSMenu" ref="18263474"/>
+ <string key="NSTitle">Use Default</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="644725453">
+ <reference key="NSMenu" ref="18263474"/>
+ <string key="NSTitle">Superscript</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1037576581">
+ <reference key="NSMenu" ref="18263474"/>
+ <string key="NSTitle">Subscript</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="941806246">
+ <reference key="NSMenu" ref="18263474"/>
+ <string key="NSTitle">Raise</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1045724900">
+ <reference key="NSMenu" ref="18263474"/>
+ <string key="NSTitle">Lower</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="739652853">
+ <reference key="NSMenu" ref="786677654"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1012600125">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Show Colors</string>
+ <string key="NSKeyEquiv">C</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="214559597">
+ <reference key="NSMenu" ref="786677654"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="596732606">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Copy Style</string>
+ <string key="NSKeyEquiv">c</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="393423671">
+ <reference key="NSMenu" ref="786677654"/>
+ <string key="NSTitle">Paste Style</string>
+ <string key="NSKeyEquiv">v</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ <string key="NSName">_NSFontMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="215659978">
+ <reference key="NSMenu" ref="941447902"/>
+ <string key="NSTitle">Text</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="446991534">
+ <string key="NSTitle">Text</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="875092757">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Align Left</string>
+ <string key="NSKeyEquiv">{</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="630155264">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Center</string>
+ <string key="NSKeyEquiv">|</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="945678886">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Justify</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="512868991">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Align Right</string>
+ <string key="NSKeyEquiv">}</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="163117631">
+ <reference key="NSMenu" ref="446991534"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="31516759">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Writing Direction</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="956096989">
+ <string key="NSTitle">Writing Direction</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="257099033">
+ <reference key="NSMenu" ref="956096989"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <string key="NSTitle">Paragraph</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="551969625">
+ <reference key="NSMenu" ref="956096989"/>
+ <string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="249532473">
+ <reference key="NSMenu" ref="956096989"/>
+ <string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="607364498">
+ <reference key="NSMenu" ref="956096989"/>
+ <string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="508151438">
+ <reference key="NSMenu" ref="956096989"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="981751889">
+ <reference key="NSMenu" ref="956096989"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <string key="NSTitle">Selection</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="380031999">
+ <reference key="NSMenu" ref="956096989"/>
+ <string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="825984362">
+ <reference key="NSMenu" ref="956096989"/>
+ <string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="560145579">
+ <reference key="NSMenu" ref="956096989"/>
+ <string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="908105787">
+ <reference key="NSMenu" ref="446991534"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="644046920">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Show Ruler</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="231811626">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Copy Ruler</string>
+ <string key="NSKeyEquiv">c</string>
+ <int key="NSKeyEquivModMask">1310720</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="883618387">
+ <reference key="NSMenu" ref="446991534"/>
+ <string key="NSTitle">Paste Ruler</string>
+ <string key="NSKeyEquiv">v</string>
+ <int key="NSKeyEquivModMask">1310720</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ </object>
+ </object>
+ </array>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="586577488">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">View</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="466310130">
+ <string key="NSTitle">View</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="102151532">
+ <reference key="NSMenu" ref="466310130"/>
+ <string key="NSTitle">Show Toolbar</string>
+ <string key="NSKeyEquiv">t</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="237841660">
+ <reference key="NSMenu" ref="466310130"/>
+ <string key="NSTitle">Customize Toolbar…</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="713487014">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Window</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="835318025">
+ <string key="NSTitle">Window</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="1011231497">
+ <reference key="NSMenu" ref="835318025"/>
+ <string key="NSTitle">Minimize</string>
+ <string key="NSKeyEquiv">m</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="575023229">
+ <reference key="NSMenu" ref="835318025"/>
+ <string key="NSTitle">Zoom</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="299356726">
+ <reference key="NSMenu" ref="835318025"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="625202149">
+ <reference key="NSMenu" ref="835318025"/>
+ <string key="NSTitle">Bring All to Front</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ <string key="NSName">_NSWindowsMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="448692316">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Help</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="992780483">
+ <string key="NSTitle">Help</string>
+ <array class="NSMutableArray" key="NSMenuItems">
+ <object class="NSMenuItem" id="105068016">
+ <reference key="NSMenu" ref="992780483"/>
+ <string key="NSTitle">Test Help</string>
+ <string key="NSKeyEquiv">?</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </array>
+ <string key="NSName">_NSHelpMenu</string>
+ </object>
+ </object>
+ </array>
+ <string key="NSName">_NSMainMenu</string>
+ </object>
+ <object class="NSWindowTemplate" id="972006081">
+ <int key="NSWindowStyleMask">15</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{335, 390}, {480, 360}}</string>
+ <int key="NSWTFlags">1954021376</int>
+ <string key="NSWindowTitle">Test</string>
+ <string key="NSWindowClass">NSWindow</string>
+ <nil key="NSViewClass"/>
+ <nil key="NSUserInterfaceItemIdentifier"/>
+ <object class="NSView" key="NSWindowView" id="439893737">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{480, 360}</string>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {2560, 1418}}</string>
+ <string key="NSMaxSize">{10000000000000, 10000000000000}</string>
+ <bool key="NSWindowIsRestorable">YES</bool>
+ </object>
+ <object class="NSCustomObject" id="976324537">
+ <string key="NSClassName">AppDelegate</string>
+ </object>
+ <object class="NSCustomObject" id="755631768">
+ <string key="NSClassName">NSFontManager</string>
+ </object>
+ </array>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <array class="NSMutableArray" key="connectionRecords">
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">terminate:</string>
+ <reference key="source" ref="1050"/>
+ <reference key="destination" ref="632727374"/>
+ </object>
+ <int key="connectionID">449</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">orderFrontStandardAboutPanel:</string>
+ <reference key="source" ref="1021"/>
+ <reference key="destination" ref="238522557"/>
+ </object>
+ <int key="connectionID">142</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="1021"/>
+ <reference key="destination" ref="976324537"/>
+ </object>
+ <int key="connectionID">495</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performMiniaturize:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1011231497"/>
+ </object>
+ <int key="connectionID">37</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">arrangeInFront:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="625202149"/>
+ </object>
+ <int key="connectionID">39</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">print:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="49223823"/>
+ </object>
+ <int key="connectionID">86</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">runPageLayout:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="294629803"/>
+ </object>
+ <int key="connectionID">87</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">clearRecentDocuments:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="759406840"/>
+ </object>
+ <int key="connectionID">127</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performClose:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="776162233"/>
+ </object>
+ <int key="connectionID">193</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleContinuousSpellChecking:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="948374510"/>
+ </object>
+ <int key="connectionID">222</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">undo:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1058277027"/>
+ </object>
+ <int key="connectionID">223</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">copy:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="860595796"/>
+ </object>
+ <int key="connectionID">224</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">checkSpelling:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="96193923"/>
+ </object>
+ <int key="connectionID">225</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">paste:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="29853731"/>
+ </object>
+ <int key="connectionID">226</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">stopSpeaking:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="680220178"/>
+ </object>
+ <int key="connectionID">227</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">cut:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="296257095"/>
+ </object>
+ <int key="connectionID">228</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">showGuessPanel:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="679648819"/>
+ </object>
+ <int key="connectionID">230</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">redo:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="790794224"/>
+ </object>
+ <int key="connectionID">231</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">selectAll:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="583158037"/>
+ </object>
+ <int key="connectionID">232</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">startSpeaking:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="731782645"/>
+ </object>
+ <int key="connectionID">233</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">delete:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="437104165"/>
+ </object>
+ <int key="connectionID">235</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performZoom:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="575023229"/>
+ </object>
+ <int key="connectionID">240</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performFindPanelAction:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="447796847"/>
+ </object>
+ <int key="connectionID">241</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">centerSelectionInVisibleArea:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="88285865"/>
+ </object>
+ <int key="connectionID">245</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleGrammarChecking:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="967646866"/>
+ </object>
+ <int key="connectionID">347</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleSmartInsertDelete:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="605118523"/>
+ </object>
+ <int key="connectionID">355</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticQuoteSubstitution:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="197661976"/>
+ </object>
+ <int key="connectionID">356</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticLinkDetection:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="708854459"/>
+ </object>
+ <int key="connectionID">357</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">saveDocument:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1023925487"/>
+ </object>
+ <int key="connectionID">362</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">revertDocumentToSaved:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="579971712"/>
+ </object>
+ <int key="connectionID">364</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">runToolbarCustomizationPalette:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="237841660"/>
+ </object>
+ <int key="connectionID">365</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleToolbarShown:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="102151532"/>
+ </object>
+ <int key="connectionID">366</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">hide:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="755159360"/>
+ </object>
+ <int key="connectionID">367</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">hideOtherApplications:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="342932134"/>
+ </object>
+ <int key="connectionID">368</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">unhideAllApplications:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="908899353"/>
+ </object>
+ <int key="connectionID">370</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">newDocument:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="705341025"/>
+ </object>
+ <int key="connectionID">373</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">openDocument:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="722745758"/>
+ </object>
+ <int key="connectionID">374</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">raiseBaseline:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="941806246"/>
+ </object>
+ <int key="connectionID">426</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">lowerBaseline:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1045724900"/>
+ </object>
+ <int key="connectionID">427</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">copyFont:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="596732606"/>
+ </object>
+ <int key="connectionID">428</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">subscript:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1037576581"/>
+ </object>
+ <int key="connectionID">429</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">superscript:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="644725453"/>
+ </object>
+ <int key="connectionID">430</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">tightenKerning:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="677519740"/>
+ </object>
+ <int key="connectionID">431</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">underline:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="330926929"/>
+ </object>
+ <int key="connectionID">432</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">orderFrontColorPanel:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1012600125"/>
+ </object>
+ <int key="connectionID">433</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">useAllLigatures:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="663508465"/>
+ </object>
+ <int key="connectionID">434</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">loosenKerning:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="238351151"/>
+ </object>
+ <int key="connectionID">435</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">pasteFont:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="393423671"/>
+ </object>
+ <int key="connectionID">436</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">unscript:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="257962622"/>
+ </object>
+ <int key="connectionID">437</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">useStandardKerning:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="252969304"/>
+ </object>
+ <int key="connectionID">438</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">useStandardLigatures:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="706297211"/>
+ </object>
+ <int key="connectionID">439</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">turnOffLigatures:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="568384683"/>
+ </object>
+ <int key="connectionID">440</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">turnOffKerning:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="766922938"/>
+ </object>
+ <int key="connectionID">441</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticSpellingCorrection:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="795346622"/>
+ </object>
+ <int key="connectionID">456</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">orderFrontSubstitutionsPanel:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="65139061"/>
+ </object>
+ <int key="connectionID">458</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticDashSubstitution:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="672708820"/>
+ </object>
+ <int key="connectionID">461</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticTextReplacement:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="537092702"/>
+ </object>
+ <int key="connectionID">463</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">uppercaseWord:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1060694897"/>
+ </object>
+ <int key="connectionID">464</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">capitalizeWord:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="56570060"/>
+ </object>
+ <int key="connectionID">467</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">lowercaseWord:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="879586729"/>
+ </object>
+ <int key="connectionID">468</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">pasteAsPlainText:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="82994268"/>
+ </object>
+ <int key="connectionID">486</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performFindPanelAction:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="326711663"/>
+ </object>
+ <int key="connectionID">487</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performFindPanelAction:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="270902937"/>
+ </object>
+ <int key="connectionID">488</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performFindPanelAction:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="159080638"/>
+ </object>
+ <int key="connectionID">489</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">showHelp:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="105068016"/>
+ </object>
+ <int key="connectionID">493</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">alignCenter:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="630155264"/>
+ </object>
+ <int key="connectionID">518</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">pasteRuler:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="883618387"/>
+ </object>
+ <int key="connectionID">519</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleRuler:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="644046920"/>
+ </object>
+ <int key="connectionID">520</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">alignRight:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="512868991"/>
+ </object>
+ <int key="connectionID">521</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">copyRuler:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="231811626"/>
+ </object>
+ <int key="connectionID">522</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">alignJustified:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="945678886"/>
+ </object>
+ <int key="connectionID">523</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">alignLeft:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="875092757"/>
+ </object>
+ <int key="connectionID">524</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">makeBaseWritingDirectionNatural:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="551969625"/>
+ </object>
+ <int key="connectionID">525</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">makeBaseWritingDirectionLeftToRight:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="249532473"/>
+ </object>
+ <int key="connectionID">526</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">makeBaseWritingDirectionRightToLeft:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="607364498"/>
+ </object>
+ <int key="connectionID">527</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">makeTextWritingDirectionNatural:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="380031999"/>
+ </object>
+ <int key="connectionID">528</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">makeTextWritingDirectionLeftToRight:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="825984362"/>
+ </object>
+ <int key="connectionID">529</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">makeTextWritingDirectionRightToLeft:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="560145579"/>
+ </object>
+ <int key="connectionID">530</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performFindPanelAction:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="738670835"/>
+ </object>
+ <int key="connectionID">535</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">addFontTrait:</string>
+ <reference key="source" ref="755631768"/>
+ <reference key="destination" ref="305399458"/>
+ </object>
+ <int key="connectionID">421</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">addFontTrait:</string>
+ <reference key="source" ref="755631768"/>
+ <reference key="destination" ref="814362025"/>
+ </object>
+ <int key="connectionID">422</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">modifyFont:</string>
+ <reference key="source" ref="755631768"/>
+ <reference key="destination" ref="885547335"/>
+ </object>
+ <int key="connectionID">423</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">orderFrontFontPanel:</string>
+ <reference key="source" ref="755631768"/>
+ <reference key="destination" ref="159677712"/>
+ </object>
+ <int key="connectionID">424</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">modifyFont:</string>
+ <reference key="source" ref="755631768"/>
+ <reference key="destination" ref="158063935"/>
+ </object>
+ <int key="connectionID">425</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">window</string>
+ <reference key="source" ref="976324537"/>
+ <reference key="destination" ref="972006081"/>
+ </object>
+ <int key="connectionID">532</int>
+ </object>
+ </array>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <array key="orderedObjects">
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <array key="object" id="0"/>
+ <reference key="children" ref="1048"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="1021"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">File's Owner</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="1014"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="1050"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">29</int>
+ <reference key="object" ref="649796088"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="713487014"/>
+ <reference ref="694149608"/>
+ <reference ref="952259628"/>
+ <reference ref="379814623"/>
+ <reference ref="586577488"/>
+ <reference ref="302598603"/>
+ <reference ref="448692316"/>
+ </array>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">19</int>
+ <reference key="object" ref="713487014"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="835318025"/>
+ </array>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">56</int>
+ <reference key="object" ref="694149608"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="110575045"/>
+ </array>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">217</int>
+ <reference key="object" ref="952259628"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="789758025"/>
+ </array>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">83</int>
+ <reference key="object" ref="379814623"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="720053764"/>
+ </array>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">81</int>
+ <reference key="object" ref="720053764"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="1023925487"/>
+ <reference ref="49223823"/>
+ <reference ref="722745758"/>
+ <reference ref="705341025"/>
+ <reference ref="1025936716"/>
+ <reference ref="294629803"/>
+ <reference ref="776162233"/>
+ <reference ref="425164168"/>
+ <reference ref="579971712"/>
+ <reference ref="1010469920"/>
+ </array>
+ <reference key="parent" ref="379814623"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">75</int>
+ <reference key="object" ref="1023925487"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">78</int>
+ <reference key="object" ref="49223823"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">72</int>
+ <reference key="object" ref="722745758"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">82</int>
+ <reference key="object" ref="705341025"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">124</int>
+ <reference key="object" ref="1025936716"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="1065607017"/>
+ </array>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">77</int>
+ <reference key="object" ref="294629803"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">73</int>
+ <reference key="object" ref="776162233"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">79</int>
+ <reference key="object" ref="425164168"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">112</int>
+ <reference key="object" ref="579971712"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">74</int>
+ <reference key="object" ref="1010469920"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">125</int>
+ <reference key="object" ref="1065607017"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="759406840"/>
+ </array>
+ <reference key="parent" ref="1025936716"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">126</int>
+ <reference key="object" ref="759406840"/>
+ <reference key="parent" ref="1065607017"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">205</int>
+ <reference key="object" ref="789758025"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="437104165"/>
+ <reference ref="583158037"/>
+ <reference ref="1058277027"/>
+ <reference ref="212016141"/>
+ <reference ref="296257095"/>
+ <reference ref="29853731"/>
+ <reference ref="860595796"/>
+ <reference ref="1040322652"/>
+ <reference ref="790794224"/>
+ <reference ref="892235320"/>
+ <reference ref="972420730"/>
+ <reference ref="676164635"/>
+ <reference ref="507821607"/>
+ <reference ref="288088188"/>
+ <reference ref="82994268"/>
+ </array>
+ <reference key="parent" ref="952259628"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">202</int>
+ <reference key="object" ref="437104165"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">198</int>
+ <reference key="object" ref="583158037"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">207</int>
+ <reference key="object" ref="1058277027"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">214</int>
+ <reference key="object" ref="212016141"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">199</int>
+ <reference key="object" ref="296257095"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">203</int>
+ <reference key="object" ref="29853731"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">197</int>
+ <reference key="object" ref="860595796"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">206</int>
+ <reference key="object" ref="1040322652"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">215</int>
+ <reference key="object" ref="790794224"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">218</int>
+ <reference key="object" ref="892235320"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="963351320"/>
+ </array>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">216</int>
+ <reference key="object" ref="972420730"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="769623530"/>
+ </array>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">200</int>
+ <reference key="object" ref="769623530"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="948374510"/>
+ <reference ref="96193923"/>
+ <reference ref="679648819"/>
+ <reference ref="967646866"/>
+ <reference ref="859480356"/>
+ <reference ref="795346622"/>
+ </array>
+ <reference key="parent" ref="972420730"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">219</int>
+ <reference key="object" ref="948374510"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">201</int>
+ <reference key="object" ref="96193923"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">204</int>
+ <reference key="object" ref="679648819"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">220</int>
+ <reference key="object" ref="963351320"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="270902937"/>
+ <reference ref="88285865"/>
+ <reference ref="159080638"/>
+ <reference ref="326711663"/>
+ <reference ref="447796847"/>
+ <reference ref="738670835"/>
+ </array>
+ <reference key="parent" ref="892235320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">213</int>
+ <reference key="object" ref="270902937"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">210</int>
+ <reference key="object" ref="88285865"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">221</int>
+ <reference key="object" ref="159080638"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">208</int>
+ <reference key="object" ref="326711663"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">209</int>
+ <reference key="object" ref="447796847"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">57</int>
+ <reference key="object" ref="110575045"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="238522557"/>
+ <reference ref="755159360"/>
+ <reference ref="908899353"/>
+ <reference ref="632727374"/>
+ <reference ref="646227648"/>
+ <reference ref="609285721"/>
+ <reference ref="481834944"/>
+ <reference ref="304266470"/>
+ <reference ref="1046388886"/>
+ <reference ref="1056857174"/>
+ <reference ref="342932134"/>
+ </array>
+ <reference key="parent" ref="694149608"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">58</int>
+ <reference key="object" ref="238522557"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">134</int>
+ <reference key="object" ref="755159360"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">150</int>
+ <reference key="object" ref="908899353"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">136</int>
+ <reference key="object" ref="632727374"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">144</int>
+ <reference key="object" ref="646227648"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">129</int>
+ <reference key="object" ref="609285721"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">143</int>
+ <reference key="object" ref="481834944"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">236</int>
+ <reference key="object" ref="304266470"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">131</int>
+ <reference key="object" ref="1046388886"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="752062318"/>
+ </array>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">149</int>
+ <reference key="object" ref="1056857174"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">145</int>
+ <reference key="object" ref="342932134"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">130</int>
+ <reference key="object" ref="752062318"/>
+ <reference key="parent" ref="1046388886"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">24</int>
+ <reference key="object" ref="835318025"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="299356726"/>
+ <reference ref="625202149"/>
+ <reference ref="575023229"/>
+ <reference ref="1011231497"/>
+ </array>
+ <reference key="parent" ref="713487014"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">92</int>
+ <reference key="object" ref="299356726"/>
+ <reference key="parent" ref="835318025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">5</int>
+ <reference key="object" ref="625202149"/>
+ <reference key="parent" ref="835318025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">239</int>
+ <reference key="object" ref="575023229"/>
+ <reference key="parent" ref="835318025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">23</int>
+ <reference key="object" ref="1011231497"/>
+ <reference key="parent" ref="835318025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">295</int>
+ <reference key="object" ref="586577488"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="466310130"/>
+ </array>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">296</int>
+ <reference key="object" ref="466310130"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="102151532"/>
+ <reference ref="237841660"/>
+ </array>
+ <reference key="parent" ref="586577488"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">297</int>
+ <reference key="object" ref="102151532"/>
+ <reference key="parent" ref="466310130"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">298</int>
+ <reference key="object" ref="237841660"/>
+ <reference key="parent" ref="466310130"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">211</int>
+ <reference key="object" ref="676164635"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="785027613"/>
+ </array>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">212</int>
+ <reference key="object" ref="785027613"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="680220178"/>
+ <reference ref="731782645"/>
+ </array>
+ <reference key="parent" ref="676164635"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">195</int>
+ <reference key="object" ref="680220178"/>
+ <reference key="parent" ref="785027613"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">196</int>
+ <reference key="object" ref="731782645"/>
+ <reference key="parent" ref="785027613"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">346</int>
+ <reference key="object" ref="967646866"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">348</int>
+ <reference key="object" ref="507821607"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="698887838"/>
+ </array>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">349</int>
+ <reference key="object" ref="698887838"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="605118523"/>
+ <reference ref="197661976"/>
+ <reference ref="708854459"/>
+ <reference ref="65139061"/>
+ <reference ref="19036812"/>
+ <reference ref="672708820"/>
+ <reference ref="537092702"/>
+ </array>
+ <reference key="parent" ref="507821607"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">350</int>
+ <reference key="object" ref="605118523"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">351</int>
+ <reference key="object" ref="197661976"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">354</int>
+ <reference key="object" ref="708854459"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">371</int>
+ <reference key="object" ref="972006081"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="439893737"/>
+ </array>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">372</int>
+ <reference key="object" ref="439893737"/>
+ <reference key="parent" ref="972006081"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">375</int>
+ <reference key="object" ref="302598603"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="941447902"/>
+ </array>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">376</int>
+ <reference key="object" ref="941447902"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="792887677"/>
+ <reference ref="215659978"/>
+ </array>
+ <reference key="parent" ref="302598603"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">377</int>
+ <reference key="object" ref="792887677"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="786677654"/>
+ </array>
+ <reference key="parent" ref="941447902"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">388</int>
+ <reference key="object" ref="786677654"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="159677712"/>
+ <reference ref="305399458"/>
+ <reference ref="814362025"/>
+ <reference ref="330926929"/>
+ <reference ref="533507878"/>
+ <reference ref="158063935"/>
+ <reference ref="885547335"/>
+ <reference ref="901062459"/>
+ <reference ref="767671776"/>
+ <reference ref="691570813"/>
+ <reference ref="769124883"/>
+ <reference ref="739652853"/>
+ <reference ref="1012600125"/>
+ <reference ref="214559597"/>
+ <reference ref="596732606"/>
+ <reference ref="393423671"/>
+ </array>
+ <reference key="parent" ref="792887677"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">389</int>
+ <reference key="object" ref="159677712"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">390</int>
+ <reference key="object" ref="305399458"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">391</int>
+ <reference key="object" ref="814362025"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">392</int>
+ <reference key="object" ref="330926929"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">393</int>
+ <reference key="object" ref="533507878"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">394</int>
+ <reference key="object" ref="158063935"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">395</int>
+ <reference key="object" ref="885547335"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">396</int>
+ <reference key="object" ref="901062459"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">397</int>
+ <reference key="object" ref="767671776"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="175441468"/>
+ </array>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">398</int>
+ <reference key="object" ref="691570813"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="1058217995"/>
+ </array>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">399</int>
+ <reference key="object" ref="769124883"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="18263474"/>
+ </array>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">400</int>
+ <reference key="object" ref="739652853"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">401</int>
+ <reference key="object" ref="1012600125"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">402</int>
+ <reference key="object" ref="214559597"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">403</int>
+ <reference key="object" ref="596732606"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">404</int>
+ <reference key="object" ref="393423671"/>
+ <reference key="parent" ref="786677654"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">405</int>
+ <reference key="object" ref="18263474"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="257962622"/>
+ <reference ref="644725453"/>
+ <reference ref="1037576581"/>
+ <reference ref="941806246"/>
+ <reference ref="1045724900"/>
+ </array>
+ <reference key="parent" ref="769124883"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">406</int>
+ <reference key="object" ref="257962622"/>
+ <reference key="parent" ref="18263474"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">407</int>
+ <reference key="object" ref="644725453"/>
+ <reference key="parent" ref="18263474"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">408</int>
+ <reference key="object" ref="1037576581"/>
+ <reference key="parent" ref="18263474"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">409</int>
+ <reference key="object" ref="941806246"/>
+ <reference key="parent" ref="18263474"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">410</int>
+ <reference key="object" ref="1045724900"/>
+ <reference key="parent" ref="18263474"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">411</int>
+ <reference key="object" ref="1058217995"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="706297211"/>
+ <reference ref="568384683"/>
+ <reference ref="663508465"/>
+ </array>
+ <reference key="parent" ref="691570813"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">412</int>
+ <reference key="object" ref="706297211"/>
+ <reference key="parent" ref="1058217995"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">413</int>
+ <reference key="object" ref="568384683"/>
+ <reference key="parent" ref="1058217995"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">414</int>
+ <reference key="object" ref="663508465"/>
+ <reference key="parent" ref="1058217995"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">415</int>
+ <reference key="object" ref="175441468"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="252969304"/>
+ <reference ref="766922938"/>
+ <reference ref="677519740"/>
+ <reference ref="238351151"/>
+ </array>
+ <reference key="parent" ref="767671776"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">416</int>
+ <reference key="object" ref="252969304"/>
+ <reference key="parent" ref="175441468"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">417</int>
+ <reference key="object" ref="766922938"/>
+ <reference key="parent" ref="175441468"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">418</int>
+ <reference key="object" ref="677519740"/>
+ <reference key="parent" ref="175441468"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">419</int>
+ <reference key="object" ref="238351151"/>
+ <reference key="parent" ref="175441468"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">420</int>
+ <reference key="object" ref="755631768"/>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">450</int>
+ <reference key="object" ref="288088188"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="579392910"/>
+ </array>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">451</int>
+ <reference key="object" ref="579392910"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="1060694897"/>
+ <reference ref="879586729"/>
+ <reference ref="56570060"/>
+ </array>
+ <reference key="parent" ref="288088188"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">452</int>
+ <reference key="object" ref="1060694897"/>
+ <reference key="parent" ref="579392910"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">453</int>
+ <reference key="object" ref="859480356"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">454</int>
+ <reference key="object" ref="795346622"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">457</int>
+ <reference key="object" ref="65139061"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">459</int>
+ <reference key="object" ref="19036812"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">460</int>
+ <reference key="object" ref="672708820"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">462</int>
+ <reference key="object" ref="537092702"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">465</int>
+ <reference key="object" ref="879586729"/>
+ <reference key="parent" ref="579392910"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">466</int>
+ <reference key="object" ref="56570060"/>
+ <reference key="parent" ref="579392910"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">485</int>
+ <reference key="object" ref="82994268"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">490</int>
+ <reference key="object" ref="448692316"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="992780483"/>
+ </array>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">491</int>
+ <reference key="object" ref="992780483"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="105068016"/>
+ </array>
+ <reference key="parent" ref="448692316"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">492</int>
+ <reference key="object" ref="105068016"/>
+ <reference key="parent" ref="992780483"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">494</int>
+ <reference key="object" ref="976324537"/>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">496</int>
+ <reference key="object" ref="215659978"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="446991534"/>
+ </array>
+ <reference key="parent" ref="941447902"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">497</int>
+ <reference key="object" ref="446991534"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="875092757"/>
+ <reference ref="630155264"/>
+ <reference ref="945678886"/>
+ <reference ref="512868991"/>
+ <reference ref="163117631"/>
+ <reference ref="31516759"/>
+ <reference ref="908105787"/>
+ <reference ref="644046920"/>
+ <reference ref="231811626"/>
+ <reference ref="883618387"/>
+ </array>
+ <reference key="parent" ref="215659978"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">498</int>
+ <reference key="object" ref="875092757"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">499</int>
+ <reference key="object" ref="630155264"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">500</int>
+ <reference key="object" ref="945678886"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">501</int>
+ <reference key="object" ref="512868991"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">502</int>
+ <reference key="object" ref="163117631"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">503</int>
+ <reference key="object" ref="31516759"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="956096989"/>
+ </array>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">504</int>
+ <reference key="object" ref="908105787"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">505</int>
+ <reference key="object" ref="644046920"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">506</int>
+ <reference key="object" ref="231811626"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">507</int>
+ <reference key="object" ref="883618387"/>
+ <reference key="parent" ref="446991534"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">508</int>
+ <reference key="object" ref="956096989"/>
+ <array class="NSMutableArray" key="children">
+ <reference ref="257099033"/>
+ <reference ref="551969625"/>
+ <reference ref="249532473"/>
+ <reference ref="607364498"/>
+ <reference ref="508151438"/>
+ <reference ref="981751889"/>
+ <reference ref="380031999"/>
+ <reference ref="825984362"/>
+ <reference ref="560145579"/>
+ </array>
+ <reference key="parent" ref="31516759"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">509</int>
+ <reference key="object" ref="257099033"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">510</int>
+ <reference key="object" ref="551969625"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">511</int>
+ <reference key="object" ref="249532473"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">512</int>
+ <reference key="object" ref="607364498"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">513</int>
+ <reference key="object" ref="508151438"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">514</int>
+ <reference key="object" ref="981751889"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">515</int>
+ <reference key="object" ref="380031999"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">516</int>
+ <reference key="object" ref="825984362"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">517</int>
+ <reference key="object" ref="560145579"/>
+ <reference key="parent" ref="956096989"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">534</int>
+ <reference key="object" ref="738670835"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ </array>
+ </object>
+ <dictionary class="NSMutableDictionary" key="flattenedProperties">
+ <string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="112.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="124.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="125.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="126.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="129.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="130.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="131.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="134.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="136.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="143.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="144.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="145.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="149.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="150.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="19.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="195.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="196.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="197.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="198.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="199.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="200.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="201.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="202.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="203.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="204.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="205.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="206.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="207.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="208.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="209.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="210.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="211.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="212.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="213.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="214.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="215.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="216.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="217.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="218.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="219.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="220.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="221.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="23.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="236.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="239.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="24.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="29.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="295.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="296.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="297.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="298.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="346.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="348.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="349.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="350.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="351.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="354.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="371.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="371.IBWindowTemplateEditedContentRect">{{380, 496}, {480, 360}}</string>
+ <integer value="1" key="371.NSWindowTemplate.visibleAtLaunch"/>
+ <string key="372.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="375.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="376.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="377.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="388.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="389.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="390.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="391.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="392.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="393.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="394.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="395.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="396.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="397.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="398.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="399.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="400.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="401.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="402.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="403.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="404.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="405.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="406.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="407.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="408.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="409.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="410.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="411.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="412.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="413.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="414.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="415.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="416.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="417.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="418.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="419.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="420.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="450.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="451.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="452.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="453.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="454.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="457.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="459.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="460.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="462.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="465.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="466.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="485.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="490.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="491.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="492.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="494.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="496.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="497.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="498.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="499.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="5.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="500.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="501.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="502.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="503.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="504.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="505.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="506.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="507.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="508.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="509.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="510.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="511.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="512.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="513.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="514.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="515.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="516.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="517.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="534.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="56.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="57.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="58.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="72.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="73.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="74.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="75.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="77.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="78.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="79.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="81.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="82.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="83.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="92.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
+ <nil key="activeLocalization"/>
+ <dictionary class="NSMutableDictionary" key="localizations"/>
+ <nil key="sourceID"/>
+ <int key="maxID">535</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <array class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <object class="IBPartialClassDescription">
+ <string key="className">ABCardController</string>
+ <string key="superclassName">NSObject</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="addCardViewField:">id</string>
+ <string key="copy:">id</string>
+ <string key="cut:">id</string>
+ <string key="doDelete:">id</string>
+ <string key="find:">id</string>
+ <string key="paste:">id</string>
+ <string key="saveChanges:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="addCardViewField:">
+ <string key="name">addCardViewField:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="copy:">
+ <string key="name">copy:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="cut:">
+ <string key="name">cut:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="doDelete:">
+ <string key="name">doDelete:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="find:">
+ <string key="name">find:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="paste:">
+ <string key="name">paste:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="saveChanges:">
+ <string key="name">saveChanges:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="mCardView">ABCardView</string>
+ <string key="mEditButton">NSButton</string>
+ <string key="mManagedObjectContext">NSManagedObjectContext</string>
+ <string key="mSearchField">NSSearchField</string>
+ <string key="mStatusTextField">NSTextField</string>
+ <string key="mWindow">NSWindow</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="mCardView">
+ <string key="name">mCardView</string>
+ <string key="candidateClassName">ABCardView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="mEditButton">
+ <string key="name">mEditButton</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="mManagedObjectContext">
+ <string key="name">mManagedObjectContext</string>
+ <string key="candidateClassName">NSManagedObjectContext</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="mSearchField">
+ <string key="name">mSearchField</string>
+ <string key="candidateClassName">NSSearchField</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="mStatusTextField">
+ <string key="name">mStatusTextField</string>
+ <string key="candidateClassName">NSTextField</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="mWindow">
+ <string key="name">mWindow</string>
+ <string key="candidateClassName">NSWindow</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/ABCardController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">ABCardView</string>
+ <string key="superclassName">NSView</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="commitAndSave:">id</string>
+ <string key="statusImageClicked:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="commitAndSave:">
+ <string key="name">commitAndSave:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="statusImageClicked:">
+ <string key="name">statusImageClicked:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="mBindingsController">NSObjectController</string>
+ <string key="mBuddyStatusImage">NSImageView</string>
+ <string key="mHeaderView">NSView</string>
+ <string key="mNameView">ABNameFrameView</string>
+ <string key="mNextKeyView">NSView</string>
+ <string key="mUserImage">NSImage</string>
+ <string key="mUserImageView">ABImageView</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="mBindingsController">
+ <string key="name">mBindingsController</string>
+ <string key="candidateClassName">NSObjectController</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="mBuddyStatusImage">
+ <string key="name">mBuddyStatusImage</string>
+ <string key="candidateClassName">NSImageView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="mHeaderView">
+ <string key="name">mHeaderView</string>
+ <string key="candidateClassName">NSView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="mNameView">
+ <string key="name">mNameView</string>
+ <string key="candidateClassName">ABNameFrameView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="mNextKeyView">
+ <string key="name">mNextKeyView</string>
+ <string key="candidateClassName">NSView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="mUserImage">
+ <string key="name">mUserImage</string>
+ <string key="candidateClassName">NSImage</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="mUserImageView">
+ <string key="name">mUserImageView</string>
+ <string key="candidateClassName">ABImageView</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/ABCardView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">ABImageView</string>
+ <string key="superclassName">NSImageView</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="copy:">id</string>
+ <string key="cut:">id</string>
+ <string key="delete:">id</string>
+ <string key="paste:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="copy:">
+ <string key="name">copy:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="cut:">
+ <string key="name">cut:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="delete:">
+ <string key="name">delete:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="paste:">
+ <string key="name">paste:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/ABImageView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">DVTBorderedView</string>
+ <string key="superclassName">DVTLayoutView_ML</string>
+ <object class="NSMutableDictionary" key="outlets">
+ <string key="NS.key.0">contentView</string>
+ <string key="NS.object.0">NSView</string>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <string key="NS.key.0">contentView</string>
+ <object class="IBToOneOutletInfo" key="NS.object.0">
+ <string key="name">contentView</string>
+ <string key="candidateClassName">NSView</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/DVTBorderedView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">DVTDelayedMenuButton</string>
+ <string key="superclassName">NSButton</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/DVTDelayedMenuButton.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">DVTGradientImageButton</string>
+ <string key="superclassName">NSButton</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/DVTGradientImageButton.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">DVTImageAndTextCell</string>
+ <string key="superclassName">NSTextFieldCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/DVTImageAndTextCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">DVTImageAndTextColumn</string>
+ <string key="superclassName">NSTableColumn</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/DVTImageAndTextColumn.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">DVTLayoutView_ML</string>
+ <string key="superclassName">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/DVTLayoutView_ML.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">DVTOutlineView</string>
+ <string key="superclassName">NSOutlineView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/DVTOutlineView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">DVTSplitView</string>
+ <string key="superclassName">NSSplitView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/DVTSplitView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">DVTStackView_ML</string>
+ <string key="superclassName">DVTLayoutView_ML</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/DVTStackView_ML.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">DVTTableView</string>
+ <string key="superclassName">NSTableView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/DVTTableView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">DVTViewController</string>
+ <string key="superclassName">NSViewController</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/DVTViewController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">HFController</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">selectAll:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <string key="NS.key.0">selectAll:</string>
+ <object class="IBActionInfo" key="NS.object.0">
+ <string key="name">selectAll:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/HFController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">HFRepresenterTextView</string>
+ <string key="superclassName">NSView</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">selectAll:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <string key="NS.key.0">selectAll:</string>
+ <object class="IBActionInfo" key="NS.object.0">
+ <string key="name">selectAll:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/HFRepresenterTextView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IBEditor</string>
+ <string key="superclassName">NSObject</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="changeFont:">id</string>
+ <string key="performCopy:">id</string>
+ <string key="performCut:">id</string>
+ <string key="selectAll:">id</string>
+ <string key="sizeSelectionToFit:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="changeFont:">
+ <string key="name">changeFont:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="performCopy:">
+ <string key="name">performCopy:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="performCut:">
+ <string key="name">performCut:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="selectAll:">
+ <string key="name">selectAll:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="sizeSelectionToFit:">
+ <string key="name">sizeSelectionToFit:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IBEditor.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDECapsuleListView</string>
+ <string key="superclassName">DVTStackView_ML</string>
+ <object class="NSMutableDictionary" key="outlets">
+ <string key="NS.key.0">dataSource</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <string key="NS.key.0">dataSource</string>
+ <object class="IBToOneOutletInfo" key="NS.object.0">
+ <string key="name">dataSource</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDECapsuleListView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDMArrayController</string>
+ <string key="superclassName">NSArrayController</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDMArrayController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDMEditor</string>
+ <string key="superclassName">IDEEditor</string>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="bottomToolbarBorderView">DVTBorderedView</string>
+ <string key="sourceListSplitViewPane">NSView</string>
+ <string key="sourceListViewController">IDEDMEditorSourceListController</string>
+ <string key="splitView">DVTSplitView</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="bottomToolbarBorderView">
+ <string key="name">bottomToolbarBorderView</string>
+ <string key="candidateClassName">DVTBorderedView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="sourceListSplitViewPane">
+ <string key="name">sourceListSplitViewPane</string>
+ <string key="candidateClassName">NSView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="sourceListViewController">
+ <string key="name">sourceListViewController</string>
+ <string key="candidateClassName">IDEDMEditorSourceListController</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="splitView">
+ <string key="name">splitView</string>
+ <string key="candidateClassName">DVTSplitView</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDMEditor.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDMEditorController</string>
+ <string key="superclassName">IDEViewController</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDMEditorController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDMEditorSourceListController</string>
+ <string key="superclassName">IDEDMEditorController</string>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="borderedView">DVTBorderedView</string>
+ <string key="parentEditor">IDEDMEditor</string>
+ <string key="primaryColumn">DVTImageAndTextColumn</string>
+ <string key="sourceListOutlineView">DVTOutlineView</string>
+ <string key="sourceListTreeController">NSTreeController</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="borderedView">
+ <string key="name">borderedView</string>
+ <string key="candidateClassName">DVTBorderedView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="parentEditor">
+ <string key="name">parentEditor</string>
+ <string key="candidateClassName">IDEDMEditor</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="primaryColumn">
+ <string key="name">primaryColumn</string>
+ <string key="candidateClassName">DVTImageAndTextColumn</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="sourceListOutlineView">
+ <string key="name">sourceListOutlineView</string>
+ <string key="candidateClassName">DVTOutlineView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="sourceListTreeController">
+ <string key="name">sourceListTreeController</string>
+ <string key="candidateClassName">NSTreeController</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDMEditorSourceListController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDMHighlightImageAndTextCell</string>
+ <string key="superclassName">DVTImageAndTextCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDMHighlightImageAndTextCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDataModelBrowserEditor</string>
+ <string key="superclassName">IDEDMEditorController</string>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="attributesTableViewController">IDEDataModelPropertiesTableController</string>
+ <string key="capsuleView">IDECapsuleListView</string>
+ <string key="entityArrayController">NSArrayController</string>
+ <string key="fetchedPropertiesTableViewController">IDEDataModelPropertiesTableController</string>
+ <string key="parentEditor">IDEDataModelEntityContentsEditor</string>
+ <string key="relationshipsTableViewController">IDEDataModelPropertiesTableController</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="attributesTableViewController">
+ <string key="name">attributesTableViewController</string>
+ <string key="candidateClassName">IDEDataModelPropertiesTableController</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="capsuleView">
+ <string key="name">capsuleView</string>
+ <string key="candidateClassName">IDECapsuleListView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="entityArrayController">
+ <string key="name">entityArrayController</string>
+ <string key="candidateClassName">NSArrayController</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="fetchedPropertiesTableViewController">
+ <string key="name">fetchedPropertiesTableViewController</string>
+ <string key="candidateClassName">IDEDataModelPropertiesTableController</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="parentEditor">
+ <string key="name">parentEditor</string>
+ <string key="candidateClassName">IDEDataModelEntityContentsEditor</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="relationshipsTableViewController">
+ <string key="name">relationshipsTableViewController</string>
+ <string key="candidateClassName">IDEDataModelPropertiesTableController</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDataModelBrowserEditor.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDataModelConfigurationEditor</string>
+ <string key="superclassName">IDEDMEditorController</string>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="capsuleListView">IDECapsuleListView</string>
+ <string key="parentEditor">IDEDataModelEditor</string>
+ <string key="tableController">IDEDataModelConfigurationTableController</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="capsuleListView">
+ <string key="name">capsuleListView</string>
+ <string key="candidateClassName">IDECapsuleListView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="parentEditor">
+ <string key="name">parentEditor</string>
+ <string key="candidateClassName">IDEDataModelEditor</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="tableController">
+ <string key="name">tableController</string>
+ <string key="candidateClassName">IDEDataModelConfigurationTableController</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDataModelConfigurationEditor.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDataModelConfigurationTableController</string>
+ <string key="superclassName">IDEDMEditorController</string>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="configurationsArrayController">NSArrayController</string>
+ <string key="entitiesArrayController">NSArrayController</string>
+ <string key="parentEditor">IDEDataModelConfigurationEditor</string>
+ <string key="tableView">XDTableView</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="configurationsArrayController">
+ <string key="name">configurationsArrayController</string>
+ <string key="candidateClassName">NSArrayController</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="entitiesArrayController">
+ <string key="name">entitiesArrayController</string>
+ <string key="candidateClassName">NSArrayController</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="parentEditor">
+ <string key="name">parentEditor</string>
+ <string key="candidateClassName">IDEDataModelConfigurationEditor</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="tableView">
+ <string key="name">tableView</string>
+ <string key="candidateClassName">XDTableView</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDataModelConfigurationTableController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDataModelDiagramEditor</string>
+ <string key="superclassName">IDEDMEditorController</string>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="diagramView">XDDiagramView</string>
+ <string key="parentEditor">IDEDataModelEntityContentsEditor</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="diagramView">
+ <string key="name">diagramView</string>
+ <string key="candidateClassName">XDDiagramView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="parentEditor">
+ <string key="name">parentEditor</string>
+ <string key="candidateClassName">IDEDataModelEntityContentsEditor</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDataModelDiagramEditor.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDataModelEditor</string>
+ <string key="superclassName">IDEDMEditor</string>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="addEntityButton">DVTDelayedMenuButton</string>
+ <string key="addPropertyButton">DVTDelayedMenuButton</string>
+ <string key="browserDiagramSegmentControl">NSSegmentedControl</string>
+ <string key="configurationViewController">IDEDataModelConfigurationEditor</string>
+ <string key="entityContentsViewController">IDEDataModelEntityContentsEditor</string>
+ <string key="fetchRequestViewController">IDEDataModelFetchRequestEditor</string>
+ <string key="hierarchySegmentControl">NSSegmentedControl</string>
+ <string key="tabView">NSTabView</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="addEntityButton">
+ <string key="name">addEntityButton</string>
+ <string key="candidateClassName">DVTDelayedMenuButton</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="addPropertyButton">
+ <string key="name">addPropertyButton</string>
+ <string key="candidateClassName">DVTDelayedMenuButton</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="browserDiagramSegmentControl">
+ <string key="name">browserDiagramSegmentControl</string>
+ <string key="candidateClassName">NSSegmentedControl</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="configurationViewController">
+ <string key="name">configurationViewController</string>
+ <string key="candidateClassName">IDEDataModelConfigurationEditor</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="entityContentsViewController">
+ <string key="name">entityContentsViewController</string>
+ <string key="candidateClassName">IDEDataModelEntityContentsEditor</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="fetchRequestViewController">
+ <string key="name">fetchRequestViewController</string>
+ <string key="candidateClassName">IDEDataModelFetchRequestEditor</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="hierarchySegmentControl">
+ <string key="name">hierarchySegmentControl</string>
+ <string key="candidateClassName">NSSegmentedControl</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="tabView">
+ <string key="name">tabView</string>
+ <string key="candidateClassName">NSTabView</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDataModelEditor.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDataModelEntityContentsEditor</string>
+ <string key="superclassName">IDEDMEditorController</string>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="browserViewController">IDEDataModelBrowserEditor</string>
+ <string key="diagramViewController">IDEDataModelDiagramEditor</string>
+ <string key="parentEditor">IDEDataModelEditor</string>
+ <string key="tabView">NSTabView</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="browserViewController">
+ <string key="name">browserViewController</string>
+ <string key="candidateClassName">IDEDataModelBrowserEditor</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="diagramViewController">
+ <string key="name">diagramViewController</string>
+ <string key="candidateClassName">IDEDataModelDiagramEditor</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="parentEditor">
+ <string key="name">parentEditor</string>
+ <string key="candidateClassName">IDEDataModelEditor</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="tabView">
+ <string key="name">tabView</string>
+ <string key="candidateClassName">NSTabView</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDataModelEntityContentsEditor.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDataModelFetchRequestEditor</string>
+ <string key="superclassName">IDEDMEditorController</string>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="entityController">NSArrayController</string>
+ <string key="parentEditor">IDEDataModelEditor</string>
+ <string key="tableView">IDECapsuleListView</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="entityController">
+ <string key="name">entityController</string>
+ <string key="candidateClassName">NSArrayController</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="parentEditor">
+ <string key="name">parentEditor</string>
+ <string key="candidateClassName">IDEDataModelEditor</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="tableView">
+ <string key="name">tableView</string>
+ <string key="candidateClassName">IDECapsuleListView</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDataModelFetchRequestEditor.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDataModelPropertiesTableController</string>
+ <string key="superclassName">IDEDMEditorController</string>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="arrayController">IDEDMArrayController</string>
+ <string key="entitiesColumn">NSTableColumn</string>
+ <string key="entityArrayController">NSArrayController</string>
+ <string key="parentEditor">IDEDataModelBrowserEditor</string>
+ <string key="propertyNameAndImageCell">IDEDMHighlightImageAndTextCell</string>
+ <string key="tableView">XDTableView</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="arrayController">
+ <string key="name">arrayController</string>
+ <string key="candidateClassName">IDEDMArrayController</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="entitiesColumn">
+ <string key="name">entitiesColumn</string>
+ <string key="candidateClassName">NSTableColumn</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="entityArrayController">
+ <string key="name">entityArrayController</string>
+ <string key="candidateClassName">NSArrayController</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="parentEditor">
+ <string key="name">parentEditor</string>
+ <string key="candidateClassName">IDEDataModelBrowserEditor</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="propertyNameAndImageCell">
+ <string key="name">propertyNameAndImageCell</string>
+ <string key="candidateClassName">IDEDMHighlightImageAndTextCell</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="tableView">
+ <string key="name">tableView</string>
+ <string key="candidateClassName">XDTableView</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDataModelPropertiesTableController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDocDownloadsTableViewController</string>
+ <string key="superclassName">NSObject</string>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="_downloadButtonCell">NSButtonCell</string>
+ <string key="_tableView">DVTTableView</string>
+ <string key="prefPaneController">IDEDocViewingPrefPaneController</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="_downloadButtonCell">
+ <string key="name">_downloadButtonCell</string>
+ <string key="candidateClassName">NSButtonCell</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="_tableView">
+ <string key="name">_tableView</string>
+ <string key="candidateClassName">DVTTableView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="prefPaneController">
+ <string key="name">prefPaneController</string>
+ <string key="candidateClassName">IDEDocViewingPrefPaneController</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDocDownloadsTableViewController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDocSetOutlineView</string>
+ <string key="superclassName">NSOutlineView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDocSetOutlineView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDocSetOutlineViewController</string>
+ <string key="superclassName">NSObject</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="getDocSetAction:">id</string>
+ <string key="showProblemInfoForUpdate:">id</string>
+ <string key="subscribeToPublisherAction:">id</string>
+ <string key="unsubscribeFromPublisher:">id</string>
+ <string key="updateDocSetAction:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="getDocSetAction:">
+ <string key="name">getDocSetAction:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="showProblemInfoForUpdate:">
+ <string key="name">showProblemInfoForUpdate:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="subscribeToPublisherAction:">
+ <string key="name">subscribeToPublisherAction:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="unsubscribeFromPublisher:">
+ <string key="name">unsubscribeFromPublisher:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="updateDocSetAction:">
+ <string key="name">updateDocSetAction:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <object class="NSMutableDictionary" key="outlets">
+ <string key="NS.key.0">docSetOutlineView</string>
+ <string key="NS.object.0">IDEDocSetOutlineView</string>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <string key="NS.key.0">docSetOutlineView</string>
+ <object class="IBToOneOutletInfo" key="NS.object.0">
+ <string key="name">docSetOutlineView</string>
+ <string key="candidateClassName">IDEDocSetOutlineView</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDocSetOutlineViewController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEDocViewingPrefPaneController</string>
+ <string key="superclassName">IDEViewController</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="addSubscription:">id</string>
+ <string key="checkForAndInstallUpdatesNow:">id</string>
+ <string key="deleteDocSet:">id</string>
+ <string key="downloadAction:">id</string>
+ <string key="minimumFontSizeComboBoxAction:">id</string>
+ <string key="minimumFontSizeEnabledAction:">id</string>
+ <string key="showHelp:">id</string>
+ <string key="showSubscriptionSheet:">id</string>
+ <string key="subscriptionCancelAction:">id</string>
+ <string key="toggleAutoCheckForAndInstallUpdates:">id</string>
+ <string key="toggleDocSetInfo:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="addSubscription:">
+ <string key="name">addSubscription:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="checkForAndInstallUpdatesNow:">
+ <string key="name">checkForAndInstallUpdatesNow:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="deleteDocSet:">
+ <string key="name">deleteDocSet:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="downloadAction:">
+ <string key="name">downloadAction:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="minimumFontSizeComboBoxAction:">
+ <string key="name">minimumFontSizeComboBoxAction:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="minimumFontSizeEnabledAction:">
+ <string key="name">minimumFontSizeEnabledAction:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="showHelp:">
+ <string key="name">showHelp:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="showSubscriptionSheet:">
+ <string key="name">showSubscriptionSheet:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="subscriptionCancelAction:">
+ <string key="name">subscriptionCancelAction:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="toggleAutoCheckForAndInstallUpdates:">
+ <string key="name">toggleAutoCheckForAndInstallUpdates:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="toggleDocSetInfo:">
+ <string key="name">toggleDocSetInfo:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="outlets">
+ <string key="_addButton">DVTGradientImageButton</string>
+ <string key="_deleteButton">DVTGradientImageButton</string>
+ <string key="_showInfoAreaButton">DVTGradientImageButton</string>
+ <string key="_splitView">NSSplitView</string>
+ <string key="_splitViewDocSetInfoSubview">NSView</string>
+ <string key="_splitViewDocSetsListSubview">NSView</string>
+ <string key="borderedViewAroundSplitView">DVTBorderedView</string>
+ <string key="borderedViewBelowTable">DVTBorderedView</string>
+ <string key="checkAndInstallNowButton">NSButton</string>
+ <string key="docSetInfoTextView">NSTextView</string>
+ <string key="docSetOutlineViewController">IDEDocSetOutlineViewController</string>
+ <string key="downloadsTableViewController">IDEDocDownloadsTableViewController</string>
+ <string key="minimumFontSizeControl">NSComboBox</string>
+ <string key="noUpdatesAvailableMessage">NSTextField</string>
+ <string key="showInfoButton">NSButton</string>
+ <string key="subscriptionTextField">NSTextField</string>
+ <string key="subscriptionWindow">NSWindow</string>
+ <string key="validateAddSubscriptionButton">NSButton</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <object class="IBToOneOutletInfo" key="_addButton">
+ <string key="name">_addButton</string>
+ <string key="candidateClassName">DVTGradientImageButton</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="_deleteButton">
+ <string key="name">_deleteButton</string>
+ <string key="candidateClassName">DVTGradientImageButton</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="_showInfoAreaButton">
+ <string key="name">_showInfoAreaButton</string>
+ <string key="candidateClassName">DVTGradientImageButton</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="_splitView">
+ <string key="name">_splitView</string>
+ <string key="candidateClassName">NSSplitView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="_splitViewDocSetInfoSubview">
+ <string key="name">_splitViewDocSetInfoSubview</string>
+ <string key="candidateClassName">NSView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="_splitViewDocSetsListSubview">
+ <string key="name">_splitViewDocSetsListSubview</string>
+ <string key="candidateClassName">NSView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="borderedViewAroundSplitView">
+ <string key="name">borderedViewAroundSplitView</string>
+ <string key="candidateClassName">DVTBorderedView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="borderedViewBelowTable">
+ <string key="name">borderedViewBelowTable</string>
+ <string key="candidateClassName">DVTBorderedView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="checkAndInstallNowButton">
+ <string key="name">checkAndInstallNowButton</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="docSetInfoTextView">
+ <string key="name">docSetInfoTextView</string>
+ <string key="candidateClassName">NSTextView</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="docSetOutlineViewController">
+ <string key="name">docSetOutlineViewController</string>
+ <string key="candidateClassName">IDEDocSetOutlineViewController</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="downloadsTableViewController">
+ <string key="name">downloadsTableViewController</string>
+ <string key="candidateClassName">IDEDocDownloadsTableViewController</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="minimumFontSizeControl">
+ <string key="name">minimumFontSizeControl</string>
+ <string key="candidateClassName">NSComboBox</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="noUpdatesAvailableMessage">
+ <string key="name">noUpdatesAvailableMessage</string>
+ <string key="candidateClassName">NSTextField</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="showInfoButton">
+ <string key="name">showInfoButton</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="subscriptionTextField">
+ <string key="name">subscriptionTextField</string>
+ <string key="candidateClassName">NSTextField</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="subscriptionWindow">
+ <string key="name">subscriptionWindow</string>
+ <string key="candidateClassName">NSWindow</string>
+ </object>
+ <object class="IBToOneOutletInfo" key="validateAddSubscriptionButton">
+ <string key="name">validateAddSubscriptionButton</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEDocViewingPrefPaneController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEEditor</string>
+ <string key="superclassName">IDEViewController</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEEditor.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IDEViewController</string>
+ <string key="superclassName">DVTViewController</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IDEViewController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">IKImageView</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="copy:">id</string>
+ <string key="crop:">id</string>
+ <string key="cut:">id</string>
+ <string key="paste:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="copy:">
+ <string key="name">copy:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="crop:">
+ <string key="name">crop:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="cut:">
+ <string key="name">cut:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="paste:">
+ <string key="name">paste:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/IKImageView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSDocument</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="printDocument:">id</string>
+ <string key="revertDocumentToSaved:">id</string>
+ <string key="runPageLayout:">id</string>
+ <string key="saveDocument:">id</string>
+ <string key="saveDocumentAs:">id</string>
+ <string key="saveDocumentTo:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="printDocument:">
+ <string key="name">printDocument:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="revertDocumentToSaved:">
+ <string key="name">revertDocumentToSaved:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="runPageLayout:">
+ <string key="name">runPageLayout:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="saveDocument:">
+ <string key="name">saveDocument:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="saveDocumentAs:">
+ <string key="name">saveDocumentAs:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="saveDocumentTo:">
+ <string key="name">saveDocumentTo:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/NSDocument.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSResponder</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">_insertFindPattern:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <string key="NS.key.0">_insertFindPattern:</string>
+ <object class="IBActionInfo" key="NS.object.0">
+ <string key="name">_insertFindPattern:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/NSResponder.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">QLPreviewBubble</string>
+ <string key="superclassName">NSObject</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="hide:">id</string>
+ <string key="show:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="hide:">
+ <string key="name">hide:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="show:">
+ <string key="name">show:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <object class="NSMutableDictionary" key="outlets">
+ <string key="NS.key.0">parentWindow</string>
+ <string key="NS.object.0">NSWindow</string>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <string key="NS.key.0">parentWindow</string>
+ <object class="IBToOneOutletInfo" key="NS.object.0">
+ <string key="name">parentWindow</string>
+ <string key="candidateClassName">NSWindow</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/QLPreviewBubble.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">QTMovieView</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="showAll:">id</string>
+ <string key="showCustomButton:">id</string>
+ <string key="toggleLoops:">id</string>
+ <string key="zoomIn:">id</string>
+ <string key="zoomOut:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="showAll:">
+ <string key="name">showAll:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="showCustomButton:">
+ <string key="name">showCustomButton:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="toggleLoops:">
+ <string key="name">toggleLoops:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="zoomIn:">
+ <string key="name">zoomIn:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="zoomOut:">
+ <string key="name">zoomOut:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/QTMovieView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">WebView</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="reloadFromOrigin:">id</string>
+ <string key="resetPageZoom:">id</string>
+ <string key="zoomPageIn:">id</string>
+ <string key="zoomPageOut:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="reloadFromOrigin:">
+ <string key="name">reloadFromOrigin:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="resetPageZoom:">
+ <string key="name">resetPageZoom:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="zoomPageIn:">
+ <string key="name">zoomPageIn:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="zoomPageOut:">
+ <string key="name">zoomPageOut:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/WebView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">XDDiagramView</string>
+ <string key="superclassName">NSView</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="_graphLayouterMenuItemAction:">id</string>
+ <string key="_zoomPopUpButtonAction:">id</string>
+ <string key="alignBottomEdges:">id</string>
+ <string key="alignCentersHorizontallyInContainer:">id</string>
+ <string key="alignCentersVerticallyInContainer:">id</string>
+ <string key="alignHorizontalCenters:">id</string>
+ <string key="alignLeftEdges:">id</string>
+ <string key="alignRightEdges:">id</string>
+ <string key="alignTopEdges:">id</string>
+ <string key="alignVerticalCenters:">id</string>
+ <string key="bringToFront:">id</string>
+ <string key="collapseAllCompartments:">id</string>
+ <string key="copy:">id</string>
+ <string key="cut:">id</string>
+ <string key="delete:">id</string>
+ <string key="deleteBackward:">id</string>
+ <string key="deleteForward:">id</string>
+ <string key="deselectAll:">id</string>
+ <string key="diagramZoomIn:">id</string>
+ <string key="diagramZoomOut:">id</string>
+ <string key="expandAllCompartments:">id</string>
+ <string key="flipHorizontally:">id</string>
+ <string key="flipVertically:">id</string>
+ <string key="layoutGraphicsConcentrically:">id</string>
+ <string key="layoutGraphicsHierarchically:">id</string>
+ <string key="lock:">id</string>
+ <string key="makeSameHeight:">id</string>
+ <string key="makeSameWidth:">id</string>
+ <string key="moveDown:">id</string>
+ <string key="moveDownAndModifySelection:">id</string>
+ <string key="moveLeft:">id</string>
+ <string key="moveLeftAndModifySelection:">id</string>
+ <string key="moveRight:">id</string>
+ <string key="moveRightAndModifySelection:">id</string>
+ <string key="moveUp:">id</string>
+ <string key="moveUpAndModifySelection:">id</string>
+ <string key="paste:">id</string>
+ <string key="rollDownAllCompartments:">id</string>
+ <string key="rollUpAllCompartments:">id</string>
+ <string key="selectAll:">id</string>
+ <string key="sendToBack:">id</string>
+ <string key="sizeToFit:">id</string>
+ <string key="toggleGridShown:">id</string>
+ <string key="toggleHiddenGraphicsShown:">id</string>
+ <string key="togglePageBreaksShown:">id</string>
+ <string key="toggleRuler:">id</string>
+ <string key="toggleSnapsToGrid:">id</string>
+ <string key="unlock:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="_graphLayouterMenuItemAction:">
+ <string key="name">_graphLayouterMenuItemAction:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="_zoomPopUpButtonAction:">
+ <string key="name">_zoomPopUpButtonAction:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="alignBottomEdges:">
+ <string key="name">alignBottomEdges:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="alignCentersHorizontallyInContainer:">
+ <string key="name">alignCentersHorizontallyInContainer:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="alignCentersVerticallyInContainer:">
+ <string key="name">alignCentersVerticallyInContainer:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="alignHorizontalCenters:">
+ <string key="name">alignHorizontalCenters:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="alignLeftEdges:">
+ <string key="name">alignLeftEdges:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="alignRightEdges:">
+ <string key="name">alignRightEdges:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="alignTopEdges:">
+ <string key="name">alignTopEdges:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="alignVerticalCenters:">
+ <string key="name">alignVerticalCenters:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="bringToFront:">
+ <string key="name">bringToFront:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="collapseAllCompartments:">
+ <string key="name">collapseAllCompartments:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="copy:">
+ <string key="name">copy:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="cut:">
+ <string key="name">cut:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="delete:">
+ <string key="name">delete:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="deleteBackward:">
+ <string key="name">deleteBackward:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="deleteForward:">
+ <string key="name">deleteForward:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="deselectAll:">
+ <string key="name">deselectAll:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="diagramZoomIn:">
+ <string key="name">diagramZoomIn:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="diagramZoomOut:">
+ <string key="name">diagramZoomOut:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="expandAllCompartments:">
+ <string key="name">expandAllCompartments:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="flipHorizontally:">
+ <string key="name">flipHorizontally:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="flipVertically:">
+ <string key="name">flipVertically:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="layoutGraphicsConcentrically:">
+ <string key="name">layoutGraphicsConcentrically:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="layoutGraphicsHierarchically:">
+ <string key="name">layoutGraphicsHierarchically:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="lock:">
+ <string key="name">lock:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="makeSameHeight:">
+ <string key="name">makeSameHeight:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="makeSameWidth:">
+ <string key="name">makeSameWidth:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="moveDown:">
+ <string key="name">moveDown:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="moveDownAndModifySelection:">
+ <string key="name">moveDownAndModifySelection:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="moveLeft:">
+ <string key="name">moveLeft:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="moveLeftAndModifySelection:">
+ <string key="name">moveLeftAndModifySelection:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="moveRight:">
+ <string key="name">moveRight:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="moveRightAndModifySelection:">
+ <string key="name">moveRightAndModifySelection:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="moveUp:">
+ <string key="name">moveUp:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="moveUpAndModifySelection:">
+ <string key="name">moveUpAndModifySelection:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="paste:">
+ <string key="name">paste:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="rollDownAllCompartments:">
+ <string key="name">rollDownAllCompartments:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="rollUpAllCompartments:">
+ <string key="name">rollUpAllCompartments:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="selectAll:">
+ <string key="name">selectAll:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="sendToBack:">
+ <string key="name">sendToBack:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="sizeToFit:">
+ <string key="name">sizeToFit:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="toggleGridShown:">
+ <string key="name">toggleGridShown:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="toggleHiddenGraphicsShown:">
+ <string key="name">toggleHiddenGraphicsShown:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="togglePageBreaksShown:">
+ <string key="name">togglePageBreaksShown:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="toggleRuler:">
+ <string key="name">toggleRuler:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="toggleSnapsToGrid:">
+ <string key="name">toggleSnapsToGrid:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="unlock:">
+ <string key="name">unlock:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <object class="NSMutableDictionary" key="outlets">
+ <string key="NS.key.0">_diagramController</string>
+ <string key="NS.object.0">IDEDataModelDiagramEditor</string>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <string key="NS.key.0">_diagramController</string>
+ <object class="IBToOneOutletInfo" key="NS.object.0">
+ <string key="name">_diagramController</string>
+ <string key="candidateClassName">IDEDataModelDiagramEditor</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/XDDiagramView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">XDTableView</string>
+ <string key="superclassName">NSTableView</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">showAllTableColumns:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <string key="NS.key.0">showAllTableColumns:</string>
+ <object class="IBActionInfo" key="NS.object.0">
+ <string key="name">showAllTableColumns:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/XDTableView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">AppDelegate</string>
+ <string key="superclassName">NSObject</string>
+ <dictionary class="NSMutableDictionary" key="actions">
+ <string key="applicationShouldTerminate:">id</string>
+ <string key="applicationWillFinishLaunching:">id</string>
+ </dictionary>
+ <dictionary class="NSMutableDictionary" key="actionInfosByName">
+ <object class="IBActionInfo" key="applicationShouldTerminate:">
+ <string key="name">applicationShouldTerminate:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo" key="applicationWillFinishLaunching:">
+ <string key="name">applicationWillFinishLaunching:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </dictionary>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">./Classes/AppDelegate.h</string>
+ </object>
+ </object>
+ </array>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
+ <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ <dictionary class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
+ <string key="NSMenuCheckmark">{11, 11}</string>
+ <string key="NSMenuMixedState">{10, 3}</string>
+ </dictionary>
+ <bool key="IBDocument.UseAutolayout">YES</bool>
+ </data>
+</archive>
diff --git a/tests/auto/blackbox/testdata/ib/assetcatalog/Storyboard.storyboard b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/Storyboard.storyboard
index 41510ae29..41510ae29 100644
--- a/tests/auto/blackbox/testdata/ib/assetcatalog/Storyboard.storyboard
+++ b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/Storyboard.storyboard
diff --git a/tests/auto/blackbox/testdata/ib/assetcatalog/assetcatalogempty.qbs b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/assetcatalogempty.qbs
index e79d0dd18..298f60e2e 100644
--- a/tests/auto/blackbox/testdata/ib/assetcatalog/assetcatalogempty.qbs
+++ b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/assetcatalogempty.qbs
@@ -1,4 +1,5 @@
import qbs
+import qbs.Utilities
Project {
property bool includeIconset
@@ -9,7 +10,7 @@ Project {
var filez = ["main.c", "MainMenu.xib"];
if (project.includeIconset)
filez.push("empty.xcassets/empty.iconset");
- else
+ else if (Utilities.versionCompare(xcode.version, "5") >= 0)
filez.push("empty.xcassets");
if (qbs.hostOSVersionMinor >= 10) // need macOS 10.10 to build SBs
filez.push("Storyboard.storyboard");
diff --git a/tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16.png b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16.png
index 60365798f..60365798f 100644
--- a/tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16.png
+++ b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16@2x.png b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16@2x.png
index 20369000d..20369000d 100644
--- a/tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16@2x.png
+++ b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/empty.iconset/icon_16x16@2x.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/other.imageset/Contents.json b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/Contents.json
index 4b1cfb1f0..4b1cfb1f0 100644
--- a/tests/auto/blackbox/testdata/ib/assetcatalog/empty.xcassets/other.imageset/Contents.json
+++ b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/Contents.json
diff --git a/tests/auto/blackbox/testdata/ib/iconset/white.iconset/icon_16x16.png b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16.png
index 60365798f..60365798f 100644
--- a/tests/auto/blackbox/testdata/ib/iconset/white.iconset/icon_16x16.png
+++ b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata/ib/iconset/white.iconset/icon_16x16@2x.png b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16@2x.png
index 20369000d..20369000d 100644
--- a/tests/auto/blackbox/testdata/ib/iconset/white.iconset/icon_16x16@2x.png
+++ b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/empty.xcassets/other.imageset/icon_16x16@2x.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata/ib/assetcatalog/main.c b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/main.c
index ed95605b3..ed95605b3 100644
--- a/tests/auto/blackbox/testdata/ib/assetcatalog/main.c
+++ b/tests/auto/blackbox/testdata-apple/ib/assetcatalog/main.c
diff --git a/tests/auto/blackbox/testdata/ib/empty-asset-catalogs/assetcatalog1.xcassets/.keep b/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/assetcatalog1.xcassets/.keep
index e69de29bb..e69de29bb 100644
--- a/tests/auto/blackbox/testdata/ib/empty-asset-catalogs/assetcatalog1.xcassets/.keep
+++ b/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/assetcatalog1.xcassets/.keep
diff --git a/tests/auto/blackbox/testdata/ib/empty-asset-catalogs/assetcatalog2.xcassets/.keep b/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/assetcatalog2.xcassets/.keep
index e69de29bb..e69de29bb 100644
--- a/tests/auto/blackbox/testdata/ib/empty-asset-catalogs/assetcatalog2.xcassets/.keep
+++ b/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/assetcatalog2.xcassets/.keep
diff --git a/tests/auto/blackbox/testdata/ib/empty-asset-catalogs/main.c b/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/main.c
index 210c8274e..210c8274e 100644
--- a/tests/auto/blackbox/testdata/ib/empty-asset-catalogs/main.c
+++ b/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/main.c
diff --git a/tests/auto/blackbox/testdata/ib/empty-asset-catalogs/multiple-asset-catalogs.qbs b/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/multiple-asset-catalogs.qbs
index 454d3c482..454d3c482 100644
--- a/tests/auto/blackbox/testdata/ib/empty-asset-catalogs/multiple-asset-catalogs.qbs
+++ b/tests/auto/blackbox/testdata-apple/ib/empty-asset-catalogs/multiple-asset-catalogs.qbs
diff --git a/tests/auto/blackbox/testdata/ib/iconset/iconset.qbs b/tests/auto/blackbox/testdata-apple/ib/iconset/iconset.qbs
index 1d563f180..1d563f180 100644
--- a/tests/auto/blackbox/testdata/ib/iconset/iconset.qbs
+++ b/tests/auto/blackbox/testdata-apple/ib/iconset/iconset.qbs
diff --git a/tests/auto/blackbox/testdata/ib/iconsetapp/white.iconset/icon_16x16.png b/tests/auto/blackbox/testdata-apple/ib/iconset/white.iconset/icon_16x16.png
index 60365798f..60365798f 100644
--- a/tests/auto/blackbox/testdata/ib/iconsetapp/white.iconset/icon_16x16.png
+++ b/tests/auto/blackbox/testdata-apple/ib/iconset/white.iconset/icon_16x16.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata/ib/iconsetapp/white.iconset/icon_16x16@2x.png b/tests/auto/blackbox/testdata-apple/ib/iconset/white.iconset/icon_16x16@2x.png
index 20369000d..20369000d 100644
--- a/tests/auto/blackbox/testdata/ib/iconsetapp/white.iconset/icon_16x16@2x.png
+++ b/tests/auto/blackbox/testdata-apple/ib/iconset/white.iconset/icon_16x16@2x.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata/ib/iconsetapp/iconsetapp.qbs b/tests/auto/blackbox/testdata-apple/ib/iconsetapp/iconsetapp.qbs
index 7e5323a0c..7e5323a0c 100644
--- a/tests/auto/blackbox/testdata/ib/iconsetapp/iconsetapp.qbs
+++ b/tests/auto/blackbox/testdata-apple/ib/iconsetapp/iconsetapp.qbs
diff --git a/tests/auto/blackbox/testdata/ib/iconsetapp/main.c b/tests/auto/blackbox/testdata-apple/ib/iconsetapp/main.c
index ed95605b3..ed95605b3 100644
--- a/tests/auto/blackbox/testdata/ib/iconsetapp/main.c
+++ b/tests/auto/blackbox/testdata-apple/ib/iconsetapp/main.c
diff --git a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16.png b/tests/auto/blackbox/testdata-apple/ib/iconsetapp/white.iconset/icon_16x16.png
index 60365798f..60365798f 100644
--- a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16.png
+++ b/tests/auto/blackbox/testdata-apple/ib/iconsetapp/white.iconset/icon_16x16.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16@2x.png b/tests/auto/blackbox/testdata-apple/ib/iconsetapp/white.iconset/icon_16x16@2x.png
index 20369000d..20369000d 100644
--- a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16@2x.png
+++ b/tests/auto/blackbox/testdata-apple/ib/iconsetapp/white.iconset/icon_16x16@2x.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/Contents.json b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/Contents.json
index 4b1cfb1f0..4b1cfb1f0 100644
--- a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/Contents.json
+++ b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/Contents.json
diff --git a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16.png b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16.png
index 60365798f..60365798f 100644
--- a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16.png
+++ b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16@2x.png b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16@2x.png
index 20369000d..20369000d 100644
--- a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16@2x.png
+++ b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog1.xcassets/other.imageset/icon_16x16@2x.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/Contents.json b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/Contents.json
index 4b1cfb1f0..4b1cfb1f0 100644
--- a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/Contents.json
+++ b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/Contents.json
diff --git a/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16.png b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16.png
new file mode 100644
index 000000000..60365798f
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16@2x.png b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16@2x.png
new file mode 100644
index 000000000..20369000d
--- /dev/null
+++ b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/assetcatalog2.xcassets/other.imageset/icon_16x16@2x.png
Binary files differ
diff --git a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/main.c b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/main.c
index 210c8274e..210c8274e 100644
--- a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/main.c
+++ b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/main.c
diff --git a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/multiple-asset-catalogs.qbs b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/multiple-asset-catalogs.qbs
index 454d3c482..454d3c482 100644
--- a/tests/auto/blackbox/testdata/ib/multiple-asset-catalogs/multiple-asset-catalogs.qbs
+++ b/tests/auto/blackbox/testdata-apple/ib/multiple-asset-catalogs/multiple-asset-catalogs.qbs
diff --git a/tests/auto/blackbox/testdata/infoplist/infoplist.qbs b/tests/auto/blackbox/testdata-apple/infoplist/infoplist.qbs
index 58cb361dd..58cb361dd 100644
--- a/tests/auto/blackbox/testdata/infoplist/infoplist.qbs
+++ b/tests/auto/blackbox/testdata-apple/infoplist/infoplist.qbs
diff --git a/tests/auto/blackbox/testdata/infoplist/main.c b/tests/auto/blackbox/testdata-apple/infoplist/main.c
index 210c8274e..210c8274e 100644
--- a/tests/auto/blackbox/testdata/infoplist/main.c
+++ b/tests/auto/blackbox/testdata-apple/infoplist/main.c
diff --git a/tests/auto/blackbox/testdata/objc-arc/arc.m b/tests/auto/blackbox/testdata-apple/objc-arc/arc.m
index 6d8e22f09..6d8e22f09 100644
--- a/tests/auto/blackbox/testdata/objc-arc/arc.m
+++ b/tests/auto/blackbox/testdata-apple/objc-arc/arc.m
diff --git a/tests/auto/blackbox/testdata/objc-arc/arc.mm b/tests/auto/blackbox/testdata-apple/objc-arc/arc.mm
index 6d8e22f09..6d8e22f09 100644
--- a/tests/auto/blackbox/testdata/objc-arc/arc.mm
+++ b/tests/auto/blackbox/testdata-apple/objc-arc/arc.mm
diff --git a/tests/auto/blackbox/testdata/objc-arc/main.m b/tests/auto/blackbox/testdata-apple/objc-arc/main.m
index 071c53c9f..071c53c9f 100644
--- a/tests/auto/blackbox/testdata/objc-arc/main.m
+++ b/tests/auto/blackbox/testdata-apple/objc-arc/main.m
diff --git a/tests/auto/blackbox/testdata/objc-arc/mrc.m b/tests/auto/blackbox/testdata-apple/objc-arc/mrc.m
index 1d907b5bf..1d907b5bf 100644
--- a/tests/auto/blackbox/testdata/objc-arc/mrc.m
+++ b/tests/auto/blackbox/testdata-apple/objc-arc/mrc.m
diff --git a/tests/auto/blackbox/testdata/objc-arc/mrc.mm b/tests/auto/blackbox/testdata-apple/objc-arc/mrc.mm
index 1d907b5bf..1d907b5bf 100644
--- a/tests/auto/blackbox/testdata/objc-arc/mrc.mm
+++ b/tests/auto/blackbox/testdata-apple/objc-arc/mrc.mm
diff --git a/tests/auto/blackbox/testdata/objc-arc/objc-arc.qbs b/tests/auto/blackbox/testdata-apple/objc-arc/objc-arc.qbs
index 672de3cb5..672de3cb5 100644
--- a/tests/auto/blackbox/testdata/objc-arc/objc-arc.qbs
+++ b/tests/auto/blackbox/testdata-apple/objc-arc/objc-arc.qbs
diff --git a/tests/auto/blackbox/testdata/xcode/xcode-project.qbs b/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs
index 0c2b0b93d..0c2b0b93d 100644
--- a/tests/auto/blackbox/testdata/xcode/xcode-project.qbs
+++ b/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs
diff --git a/tests/auto/blackbox/testdata-java/android/multiple-apks-per-project/product1/product1.qbs b/tests/auto/blackbox/testdata-java/android/multiple-apks-per-project/product1/product1.qbs
index 721b292e3..0ddd7526c 100644
--- a/tests/auto/blackbox/testdata-java/android/multiple-apks-per-project/product1/product1.qbs
+++ b/tests/auto/blackbox/testdata-java/android/multiple-apks-per-project/product1/product1.qbs
@@ -7,7 +7,7 @@ Project {
name: "p1lib1"
files: ["src/main/jni/lib1.cpp"]
Android.ndk.appStl: "stlport_shared"
- architectures: !qbs.architecture ? ["mips", "x86"] : undefined
+ qbs.architectures: !qbs.architecture ? ["mips", "x86"] : undefined
cpp.useRPaths: false
}
diff --git a/tests/auto/blackbox/testdata-java/android/teapot/teapot.qbs b/tests/auto/blackbox/testdata-java/android/teapot/teapot.qbs
index 337d3eb77..ff3077335 100644
--- a/tests/auto/blackbox/testdata-java/android/teapot/teapot.qbs
+++ b/tests/auto/blackbox/testdata-java/android/teapot/teapot.qbs
@@ -1,12 +1,9 @@
import qbs
+import qbs.File
Project {
minimumQbsVersion: qbs.version
- property stringList architectures: !qbs.architecture
- ? ["arm64", "armv7a", "x86", "x86_64", "mips", "mips64"]
- : undefined
StaticLibrary {
- architectures: project.architectures
name: "native-glue"
Depends { name: "cpp" }
Group {
@@ -23,7 +20,6 @@ Project {
}
StaticLibrary {
- architectures: project.architectures
name: "ndk-helper"
Depends { name: "Android.ndk" }
Depends { name: "cpp" }
@@ -44,7 +40,6 @@ Project {
}
StaticLibrary {
- architectures: project.architectures
name: "cpufeatures"
Depends { name: "cpp" }
Group {
@@ -62,16 +57,30 @@ Project {
DynamicLibrary {
name: "TeapotNativeActivity"
- architectures: project.architectures
Depends { name: "Android.ndk" }
Depends { name: "cpp" }
Depends { name: "cpufeatures" }
Depends { name: "native-glue" }
Depends { name: "ndk-helper" }
+ Probe {
+ id: teapotProbeJni
+ property string samplesDir: Android.ndk.ndkSamplesDir
+ property string jniDir
+ configure: {
+ var paths = ["/teapots/classic-teapot/src/main/cpp/", "/Teapot/app/src/main/jni/"];
+ for (var i = 0; i < paths.length; ++i) {
+ if (File.exists(samplesDir + paths[i])) {
+ jniDir = samplesDir + paths[i];
+ break;
+ }
+ }
+ }
+ }
+
Group {
name: "C++ sources"
- prefix: Android.ndk.ndkDir + "/samples/Teapot/app/src/main/jni/"
+ prefix: teapotProbeJni.jniDir
files: [
"TeapotNativeActivity.cpp",
"TeapotRenderer.cpp",
@@ -88,8 +97,23 @@ Project {
}
AndroidApk {
+ Probe {
+ id: teapotProbe
+ property string samplesDir: Android.sdk.ndkSamplesDir
+ property string dir
+ configure: {
+ var paths = ["/teapots/classic-teapot/src/main", "/Teapot/app/src/main"];
+ for (var i = 0; i < paths.length; ++i) {
+ if (File.exists(samplesDir + paths[i])) {
+ dir = samplesDir + paths[i];
+ break;
+ }
+ }
+ }
+ }
+
name: "com.sample.teapot"
- sourceSetDir: Android.sdk.ndkDir + "/samples/Teapot/app/src/main"
+ sourceSetDir: teapotProbe.dir
Depends { productTypes: ["android.nativelibrary"] }
}
}
diff --git a/tests/auto/blackbox/testdata/auto-qrc/auto-qrc.qbs b/tests/auto/blackbox/testdata-qt/auto-qrc/auto-qrc.qbs
index 3055e51b8..3055e51b8 100644
--- a/tests/auto/blackbox/testdata/auto-qrc/auto-qrc.qbs
+++ b/tests/auto/blackbox/testdata-qt/auto-qrc/auto-qrc.qbs
diff --git a/tests/auto/blackbox/testdata/auto-qrc/main.cpp b/tests/auto/blackbox/testdata-qt/auto-qrc/main.cpp
index 53a33854d..53a33854d 100644
--- a/tests/auto/blackbox/testdata/auto-qrc/main.cpp
+++ b/tests/auto/blackbox/testdata-qt/auto-qrc/main.cpp
diff --git a/tests/auto/blackbox/testdata/auto-qrc/qrc-base/resource1.txt b/tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/resource1.txt
index edf22a3d6..edf22a3d6 100644
--- a/tests/auto/blackbox/testdata/auto-qrc/qrc-base/resource1.txt
+++ b/tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/resource1.txt
diff --git a/tests/auto/blackbox/testdata/auto-qrc/qrc-base/subdir/resource2.txt b/tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/subdir/resource2.txt
index b7c270096..b7c270096 100644
--- a/tests/auto/blackbox/testdata/auto-qrc/qrc-base/subdir/resource2.txt
+++ b/tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/subdir/resource2.txt
diff --git a/tests/auto/blackbox/testdata/auto-qrc/qrc-base/subdir/resource3.txt b/tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/subdir/resource3.txt
index 6df9761da..6df9761da 100644
--- a/tests/auto/blackbox/testdata/auto-qrc/qrc-base/subdir/resource3.txt
+++ b/tests/auto/blackbox/testdata-qt/auto-qrc/qrc-base/subdir/resource3.txt
diff --git a/tests/auto/blackbox/testdata/combined-moc/combined-moc.qbs b/tests/auto/blackbox/testdata-qt/combined-moc/combined-moc.qbs
index 34529fce6..34529fce6 100644
--- a/tests/auto/blackbox/testdata/combined-moc/combined-moc.qbs
+++ b/tests/auto/blackbox/testdata-qt/combined-moc/combined-moc.qbs
diff --git a/tests/auto/blackbox/testdata/combined-moc/main.cpp b/tests/auto/blackbox/testdata-qt/combined-moc/main.cpp
index 8fc13028b..8fc13028b 100644
--- a/tests/auto/blackbox/testdata/combined-moc/main.cpp
+++ b/tests/auto/blackbox/testdata-qt/combined-moc/main.cpp
diff --git a/tests/auto/blackbox/testdata/combined-moc/theobject.h b/tests/auto/blackbox/testdata-qt/combined-moc/theobject.h
index 759eae8fb..759eae8fb 100644
--- a/tests/auto/blackbox/testdata/combined-moc/theobject.h
+++ b/tests/auto/blackbox/testdata-qt/combined-moc/theobject.h
diff --git a/tests/auto/blackbox/testdata/create-project/dummy.txt b/tests/auto/blackbox/testdata-qt/create-project/dummy.txt
index e69de29bb..e69de29bb 100644
--- a/tests/auto/blackbox/testdata/create-project/dummy.txt
+++ b/tests/auto/blackbox/testdata-qt/create-project/dummy.txt
diff --git a/tests/auto/blackbox/testdata/dbus-adaptors/THIS.IS.A.STRANGE.FILENAME.CAR.XML b/tests/auto/blackbox/testdata-qt/dbus-adaptors/THIS.IS.A.STRANGE.FILENAME.CAR.XML
index 6d8c9d19f..6d8c9d19f 100644
--- a/tests/auto/blackbox/testdata/dbus-adaptors/THIS.IS.A.STRANGE.FILENAME.CAR.XML
+++ b/tests/auto/blackbox/testdata-qt/dbus-adaptors/THIS.IS.A.STRANGE.FILENAME.CAR.XML
diff --git a/tests/auto/blackbox/testdata/dbus-adaptors/car.cpp b/tests/auto/blackbox/testdata-qt/dbus-adaptors/car.cpp
index 466ed4b8e..466ed4b8e 100644
--- a/tests/auto/blackbox/testdata/dbus-adaptors/car.cpp
+++ b/tests/auto/blackbox/testdata-qt/dbus-adaptors/car.cpp
diff --git a/tests/auto/blackbox/testdata/dbus-adaptors/car.h b/tests/auto/blackbox/testdata-qt/dbus-adaptors/car.h
index f14b1062d..f14b1062d 100644
--- a/tests/auto/blackbox/testdata/dbus-adaptors/car.h
+++ b/tests/auto/blackbox/testdata-qt/dbus-adaptors/car.h
diff --git a/tests/auto/blackbox/testdata/dbus-adaptors/car.qbs b/tests/auto/blackbox/testdata-qt/dbus-adaptors/car.qbs
index 67ba5e7ea..67ba5e7ea 100644
--- a/tests/auto/blackbox/testdata/dbus-adaptors/car.qbs
+++ b/tests/auto/blackbox/testdata-qt/dbus-adaptors/car.qbs
diff --git a/tests/auto/blackbox/testdata/dbus-adaptors/main.cpp b/tests/auto/blackbox/testdata-qt/dbus-adaptors/main.cpp
index 2c6db4403..2c6db4403 100644
--- a/tests/auto/blackbox/testdata/dbus-adaptors/main.cpp
+++ b/tests/auto/blackbox/testdata-qt/dbus-adaptors/main.cpp
diff --git a/tests/auto/blackbox/testdata/dbus-interfaces/car.xml b/tests/auto/blackbox/testdata-qt/dbus-interfaces/car.xml
index 6d8c9d19f..6d8c9d19f 100644
--- a/tests/auto/blackbox/testdata/dbus-interfaces/car.xml
+++ b/tests/auto/blackbox/testdata-qt/dbus-interfaces/car.xml
diff --git a/tests/auto/blackbox/testdata/dbus-interfaces/controller.cpp b/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.cpp
index eaff5c775..eaff5c775 100644
--- a/tests/auto/blackbox/testdata/dbus-interfaces/controller.cpp
+++ b/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.cpp
diff --git a/tests/auto/blackbox/testdata/dbus-interfaces/controller.h b/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.h
index 3a63c6a06..3a63c6a06 100644
--- a/tests/auto/blackbox/testdata/dbus-interfaces/controller.h
+++ b/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.h
diff --git a/tests/auto/blackbox/testdata/dbus-interfaces/controller.qbs b/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.qbs
index b5fb3d698..b5fb3d698 100644
--- a/tests/auto/blackbox/testdata/dbus-interfaces/controller.qbs
+++ b/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.qbs
diff --git a/tests/auto/blackbox/testdata/dbus-interfaces/controller.ui b/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.ui
index 379015bf3..379015bf3 100644
--- a/tests/auto/blackbox/testdata/dbus-interfaces/controller.ui
+++ b/tests/auto/blackbox/testdata-qt/dbus-interfaces/controller.ui
diff --git a/tests/auto/blackbox/testdata/dbus-interfaces/main.cpp b/tests/auto/blackbox/testdata-qt/dbus-interfaces/main.cpp
index fdd9fc590..fdd9fc590 100644
--- a/tests/auto/blackbox/testdata/dbus-interfaces/main.cpp
+++ b/tests/auto/blackbox/testdata-qt/dbus-interfaces/main.cpp
diff --git a/tests/auto/blackbox/testdata/lrelease/de.ts b/tests/auto/blackbox/testdata-qt/lrelease/de.ts
index 5beb013bd..5beb013bd 100644
--- a/tests/auto/blackbox/testdata/lrelease/de.ts
+++ b/tests/auto/blackbox/testdata-qt/lrelease/de.ts
diff --git a/tests/auto/blackbox/testdata/lrelease/hu.ts b/tests/auto/blackbox/testdata-qt/lrelease/hu.ts
index dc45eac46..dc45eac46 100644
--- a/tests/auto/blackbox/testdata/lrelease/hu.ts
+++ b/tests/auto/blackbox/testdata-qt/lrelease/hu.ts
diff --git a/tests/auto/blackbox/testdata/lrelease/lrelease.qbs b/tests/auto/blackbox/testdata-qt/lrelease/lrelease.qbs
index b4119402f..b4119402f 100644
--- a/tests/auto/blackbox/testdata/lrelease/lrelease.qbs
+++ b/tests/auto/blackbox/testdata-qt/lrelease/lrelease.qbs
diff --git a/tests/auto/blackbox/testdata/mixed-build-variants/main.cpp b/tests/auto/blackbox/testdata-qt/mixed-build-variants/main.cpp
index 141d7ebec..141d7ebec 100644
--- a/tests/auto/blackbox/testdata/mixed-build-variants/main.cpp
+++ b/tests/auto/blackbox/testdata-qt/mixed-build-variants/main.cpp
diff --git a/tests/auto/blackbox/testdata-qt/mixed-build-variants/mixed-build-variants.qbs b/tests/auto/blackbox/testdata-qt/mixed-build-variants/mixed-build-variants.qbs
new file mode 100644
index 000000000..8f2c1c7fd
--- /dev/null
+++ b/tests/auto/blackbox/testdata-qt/mixed-build-variants/mixed-build-variants.qbs
@@ -0,0 +1,11 @@
+import qbs
+
+QtApplication {
+ Properties {
+ condition: qbs.toolchain.contains("msvc")
+ Qt.core.qtBuildVariant: "release"
+ }
+ Qt.core.qtBuildVariant: "dummy"
+
+ files: ["main.cpp"]
+}
diff --git a/tests/auto/blackbox/testdata/moc-flags/blubb.h b/tests/auto/blackbox/testdata-qt/moc-flags/blubb.h
index 54e2fdd7a..54e2fdd7a 100644
--- a/tests/auto/blackbox/testdata/moc-flags/blubb.h
+++ b/tests/auto/blackbox/testdata-qt/moc-flags/blubb.h
diff --git a/tests/auto/blackbox/testdata/moc-flags/main.cpp b/tests/auto/blackbox/testdata-qt/moc-flags/main.cpp
index 8e7c9e287..8e7c9e287 100644
--- a/tests/auto/blackbox/testdata/moc-flags/main.cpp
+++ b/tests/auto/blackbox/testdata-qt/moc-flags/main.cpp
diff --git a/tests/auto/blackbox/testdata/moc-flags/moc-flags.qbs b/tests/auto/blackbox/testdata-qt/moc-flags/moc-flags.qbs
index d42c7ad87..d42c7ad87 100644
--- a/tests/auto/blackbox/testdata/moc-flags/moc-flags.qbs
+++ b/tests/auto/blackbox/testdata-qt/moc-flags/moc-flags.qbs
diff --git a/tests/auto/blackbox/testdata/plugin-meta-data/app.cpp b/tests/auto/blackbox/testdata-qt/plugin-meta-data/app.cpp
index 2cd748b00..2cd748b00 100644
--- a/tests/auto/blackbox/testdata/plugin-meta-data/app.cpp
+++ b/tests/auto/blackbox/testdata-qt/plugin-meta-data/app.cpp
diff --git a/tests/auto/blackbox/testdata/plugin-meta-data/metadata.json b/tests/auto/blackbox/testdata-qt/plugin-meta-data/metadata.json
index 1377879e2..1377879e2 100644
--- a/tests/auto/blackbox/testdata/plugin-meta-data/metadata.json
+++ b/tests/auto/blackbox/testdata-qt/plugin-meta-data/metadata.json
diff --git a/tests/auto/blackbox/testdata/plugin-meta-data/plugin-meta-data.qbs b/tests/auto/blackbox/testdata-qt/plugin-meta-data/plugin-meta-data.qbs
index 0d623a739..0d623a739 100644
--- a/tests/auto/blackbox/testdata/plugin-meta-data/plugin-meta-data.qbs
+++ b/tests/auto/blackbox/testdata-qt/plugin-meta-data/plugin-meta-data.qbs
diff --git a/tests/auto/blackbox/testdata/plugin-meta-data/theplugin.cpp b/tests/auto/blackbox/testdata-qt/plugin-meta-data/theplugin.cpp
index 90ce230e2..90ce230e2 100644
--- a/tests/auto/blackbox/testdata/plugin-meta-data/theplugin.cpp
+++ b/tests/auto/blackbox/testdata-qt/plugin-meta-data/theplugin.cpp
diff --git a/tests/auto/blackbox/testdata/qml-debugging/main.cpp b/tests/auto/blackbox/testdata-qt/qml-debugging/main.cpp
index 535d6d63f..535d6d63f 100644
--- a/tests/auto/blackbox/testdata/qml-debugging/main.cpp
+++ b/tests/auto/blackbox/testdata-qt/qml-debugging/main.cpp
diff --git a/tests/auto/blackbox/testdata/qml-debugging/qml-debugging.qbs b/tests/auto/blackbox/testdata-qt/qml-debugging/qml-debugging.qbs
index 3606b4aa3..3606b4aa3 100644
--- a/tests/auto/blackbox/testdata/qml-debugging/qml-debugging.qbs
+++ b/tests/auto/blackbox/testdata-qt/qml-debugging/qml-debugging.qbs
diff --git a/tests/auto/blackbox/testdata/qobject-in-mm/main.mm b/tests/auto/blackbox/testdata-qt/qobject-in-mm/main.mm
index 40c464b88..40c464b88 100644
--- a/tests/auto/blackbox/testdata/qobject-in-mm/main.mm
+++ b/tests/auto/blackbox/testdata-qt/qobject-in-mm/main.mm
diff --git a/tests/auto/blackbox/testdata/qobject-in-mm/qobject-in-mm.qbs b/tests/auto/blackbox/testdata-qt/qobject-in-mm/qobject-in-mm.qbs
index 2f819d012..2f819d012 100644
--- a/tests/auto/blackbox/testdata/qobject-in-mm/qobject-in-mm.qbs
+++ b/tests/auto/blackbox/testdata-qt/qobject-in-mm/qobject-in-mm.qbs
diff --git a/tests/auto/blackbox/testdata/qrc/bla.cpp b/tests/auto/blackbox/testdata-qt/qrc/bla.cpp
index e04f873a6..e04f873a6 100644
--- a/tests/auto/blackbox/testdata/qrc/bla.cpp
+++ b/tests/auto/blackbox/testdata-qt/qrc/bla.cpp
diff --git a/tests/auto/blackbox/testdata/qrc/bla.qrc b/tests/auto/blackbox/testdata-qt/qrc/bla.qrc
index 46c93847e..46c93847e 100644
--- a/tests/auto/blackbox/testdata/qrc/bla.qrc
+++ b/tests/auto/blackbox/testdata-qt/qrc/bla.qrc
diff --git a/tests/auto/blackbox/testdata/qrc/i.qbs b/tests/auto/blackbox/testdata-qt/qrc/i.qbs
index 67b836dd4..67b836dd4 100644
--- a/tests/auto/blackbox/testdata/qrc/i.qbs
+++ b/tests/auto/blackbox/testdata-qt/qrc/i.qbs
diff --git a/tests/auto/blackbox/testdata/qrc/stuff.txt b/tests/auto/blackbox/testdata-qt/qrc/stuff.txt
index 78f0d32c6..78f0d32c6 100644
--- a/tests/auto/blackbox/testdata/qrc/stuff.txt
+++ b/tests/auto/blackbox/testdata-qt/qrc/stuff.txt
diff --git a/tests/auto/blackbox/testdata/qt-keywords/main.cpp b/tests/auto/blackbox/testdata-qt/qt-keywords/main.cpp
index 4ef493cce..4ef493cce 100644
--- a/tests/auto/blackbox/testdata/qt-keywords/main.cpp
+++ b/tests/auto/blackbox/testdata-qt/qt-keywords/main.cpp
diff --git a/tests/auto/blackbox/testdata/qt-keywords/qt-keywords.qbs b/tests/auto/blackbox/testdata-qt/qt-keywords/qt-keywords.qbs
index 59e964258..59e964258 100644
--- a/tests/auto/blackbox/testdata/qt-keywords/qt-keywords.qbs
+++ b/tests/auto/blackbox/testdata-qt/qt-keywords/qt-keywords.qbs
diff --git a/tests/auto/blackbox/testdata/qtscxml/dummystatemachine.scxml b/tests/auto/blackbox/testdata-qt/qtscxml/dummystatemachine.scxml
index 6c751866f..6c751866f 100644
--- a/tests/auto/blackbox/testdata/qtscxml/dummystatemachine.scxml
+++ b/tests/auto/blackbox/testdata-qt/qtscxml/dummystatemachine.scxml
diff --git a/tests/auto/blackbox/testdata/qtscxml/main.cpp b/tests/auto/blackbox/testdata-qt/qtscxml/main.cpp
index c9a7d7741..c9a7d7741 100644
--- a/tests/auto/blackbox/testdata/qtscxml/main.cpp
+++ b/tests/auto/blackbox/testdata-qt/qtscxml/main.cpp
diff --git a/tests/auto/blackbox/testdata/qtscxml/qtscxml.qbs b/tests/auto/blackbox/testdata-qt/qtscxml/qtscxml.qbs
index 9610825ec..9610825ec 100644
--- a/tests/auto/blackbox/testdata/qtscxml/qtscxml.qbs
+++ b/tests/auto/blackbox/testdata-qt/qtscxml/qtscxml.qbs
diff --git a/tests/auto/blackbox/testdata/static-qt-plugin-linking/static-qt-plugin-linking.qbs b/tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/static-qt-plugin-linking.qbs
index a72ce0098..a72ce0098 100644
--- a/tests/auto/blackbox/testdata/static-qt-plugin-linking/static-qt-plugin-linking.qbs
+++ b/tests/auto/blackbox/testdata-qt/static-qt-plugin-linking/static-qt-plugin-linking.qbs
diff --git a/tests/auto/blackbox/testdata/trackAddMocInclude/after/main.cpp b/tests/auto/blackbox/testdata-qt/trackAddMocInclude/after/main.cpp
index 566024acd..566024acd 100644
--- a/tests/auto/blackbox/testdata/trackAddMocInclude/after/main.cpp
+++ b/tests/auto/blackbox/testdata-qt/trackAddMocInclude/after/main.cpp
diff --git a/tests/auto/blackbox/testdata/trackAddMocInclude/before/main.cpp b/tests/auto/blackbox/testdata-qt/trackAddMocInclude/before/main.cpp
index 2a44ceec4..2a44ceec4 100644
--- a/tests/auto/blackbox/testdata/trackAddMocInclude/before/main.cpp
+++ b/tests/auto/blackbox/testdata-qt/trackAddMocInclude/before/main.cpp
diff --git a/tests/auto/blackbox/testdata/trackAddMocInclude/before/test.qbs b/tests/auto/blackbox/testdata-qt/trackAddMocInclude/before/test.qbs
index 1e1d79682..1e1d79682 100644
--- a/tests/auto/blackbox/testdata/trackAddMocInclude/before/test.qbs
+++ b/tests/auto/blackbox/testdata-qt/trackAddMocInclude/before/test.qbs
diff --git a/tests/auto/blackbox/testdata/trackQObjChange/bla.cpp b/tests/auto/blackbox/testdata-qt/trackQObjChange/bla.cpp
index 74c8bdac0..74c8bdac0 100644
--- a/tests/auto/blackbox/testdata/trackQObjChange/bla.cpp
+++ b/tests/auto/blackbox/testdata-qt/trackQObjChange/bla.cpp
diff --git a/tests/auto/blackbox/testdata/trackQObjChange/bla_noqobject.h b/tests/auto/blackbox/testdata-qt/trackQObjChange/bla_noqobject.h
index ca45b65be..ca45b65be 100644
--- a/tests/auto/blackbox/testdata/trackQObjChange/bla_noqobject.h
+++ b/tests/auto/blackbox/testdata-qt/trackQObjChange/bla_noqobject.h
diff --git a/tests/auto/blackbox/testdata/trackQObjChange/bla_qobject.h b/tests/auto/blackbox/testdata-qt/trackQObjChange/bla_qobject.h
index 840465e86..840465e86 100644
--- a/tests/auto/blackbox/testdata/trackQObjChange/bla_qobject.h
+++ b/tests/auto/blackbox/testdata-qt/trackQObjChange/bla_qobject.h
diff --git a/tests/auto/blackbox/testdata/trackQObjChange/i.qbs b/tests/auto/blackbox/testdata-qt/trackQObjChange/i.qbs
index c18fab086..c18fab086 100644
--- a/tests/auto/blackbox/testdata/trackQObjChange/i.qbs
+++ b/tests/auto/blackbox/testdata-qt/trackQObjChange/i.qbs
diff --git a/tests/auto/blackbox/testdata/assembly/assembly.qbs b/tests/auto/blackbox/testdata/assembly/assembly.qbs
index f14a21bfe..39ecc021c 100644
--- a/tests/auto/blackbox/testdata/assembly/assembly.qbs
+++ b/tests/auto/blackbox/testdata/assembly/assembly.qbs
@@ -1,6 +1,32 @@
import qbs 1.0
+import qbs.TextFile
Project {
+ Product {
+ type: ["properties"]
+ Depends { name: "cpp" }
+ Rule {
+ multiplex: true
+ Artifact {
+ filePath: "properties.json"
+ fileTags: ["properties"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.outputFilePath = outputs.properties[0].filePath;
+ cmd.tc = product.qbs.toolchain;
+ cmd.sourceCode = function () {
+ var tf = new TextFile(outputFilePath, TextFile.WriteOnly);
+ try {
+ tf.writeLine(JSON.stringify({ "qbs.toolchain": tc }, undefined, 4));
+ } finally {
+ tf.close();
+ }
+ };
+ return [cmd];
+ }
+ }
+ }
StaticLibrary {
name : "testa"
files : [ "testa.s" ]
diff --git a/tests/auto/blackbox/testdata/aux-inputs-from-deps/aux-inputs-from-deps.qbs b/tests/auto/blackbox/testdata/aux-inputs-from-deps/aux-inputs-from-deps.qbs
new file mode 100644
index 000000000..e5be44b76
--- /dev/null
+++ b/tests/auto/blackbox/testdata/aux-inputs-from-deps/aux-inputs-from-deps.qbs
@@ -0,0 +1,80 @@
+import qbs
+import qbs.File
+import qbs.TextFile
+
+import "util.js" as Utils
+
+Project {
+ CppApplication {
+ name: "app"
+ files: ["main.cpp"]
+ Depends { name: "dep" }
+ }
+ Product {
+ name: "p"
+ type: ["p.out"]
+ Depends { name: "dep" }
+ Rule {
+ multiplex: true
+ explicitlyDependsOn: ["hpp"]
+ Artifact {
+ filePath: "dummy.out"
+ fileTags: ["p.out"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating dummy.out";
+ cmd.sourceCode = function() {
+ File.copy(project.buildDirectory + "/dummy.h", output.filePath);
+ };
+ return [cmd];
+ }
+ }
+ }
+ Product {
+ name: "dep"
+ type: ["hpp"]
+ property bool sleep: true
+ Rule {
+ inputs: ["blubb.in"]
+ Artifact {
+ filePath: project.buildDirectory + "/dummy.h"
+ fileTags: ["hpp"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating header";
+ cmd.sourceCode = function() {
+ if (product.sleep)
+ Utils.sleep(1000);
+ File.copy(input.filePath, output.filePath);
+ }
+ return [cmd];
+ }
+ }
+ Rule {
+ multiplex: true
+ Artifact {
+ filePath: "dummy.blubb"
+ fileTags: ["blubb.in"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "generating blubb.in";
+ cmd.sourceCode = function() {
+ if (product.sleep)
+ Utils.sleep(1000);
+ var f = new TextFile(output.filePath, TextFile.WriteOnly);
+ f.close();
+ }
+ return [cmd];
+ }
+ }
+ Export {
+ Depends { name: "cpp" }
+ cpp.includePaths: [project.buildDirectory]
+ }
+ }
+}
+
+
diff --git a/tests/auto/blackbox/testdata/aux-inputs-from-deps/main.cpp b/tests/auto/blackbox/testdata/aux-inputs-from-deps/main.cpp
new file mode 100644
index 000000000..d16404623
--- /dev/null
+++ b/tests/auto/blackbox/testdata/aux-inputs-from-deps/main.cpp
@@ -0,0 +1,3 @@
+#include <dummy.h>
+
+int main() { }
diff --git a/tests/auto/blackbox/testdata/aux-inputs-from-deps/util.js b/tests/auto/blackbox/testdata/aux-inputs-from-deps/util.js
new file mode 100644
index 000000000..a37a8cbb1
--- /dev/null
+++ b/tests/auto/blackbox/testdata/aux-inputs-from-deps/util.js
@@ -0,0 +1,8 @@
+function sleep(timeInMs)
+{
+ var referenceTime = new Date();
+ var time = null;
+ do {
+ time = new Date();
+ } while (time - referenceTime < timeInMs);
+}
diff --git a/tests/auto/blackbox/testdata/buildenv-change/buildenv-change.qbs b/tests/auto/blackbox/testdata/buildenv-change/buildenv-change.qbs
new file mode 100644
index 000000000..acf9d0890
--- /dev/null
+++ b/tests/auto/blackbox/testdata/buildenv-change/buildenv-change.qbs
@@ -0,0 +1,17 @@
+import qbs
+
+CppApplication {
+ Probe {
+ id: dummy
+ configure: {
+ if (qbs.toolchain.contains("msvc"))
+ console.info("msvc");
+ }
+ }
+ files: [
+ "file.c",
+ "main.cpp",
+ "subdir/theheader.h",
+ "subdir2/theheader.h",
+ ]
+}
diff --git a/tests/auto/blackbox/testdata/buildenv-change/file.c b/tests/auto/blackbox/testdata/buildenv-change/file.c
new file mode 100644
index 000000000..4b74880f3
--- /dev/null
+++ b/tests/auto/blackbox/testdata/buildenv-change/file.c
@@ -0,0 +1 @@
+void func(void) { }
diff --git a/tests/auto/blackbox/testdata/buildenv-change/main.cpp b/tests/auto/blackbox/testdata/buildenv-change/main.cpp
new file mode 100644
index 000000000..b98fc3c23
--- /dev/null
+++ b/tests/auto/blackbox/testdata/buildenv-change/main.cpp
@@ -0,0 +1,3 @@
+#include <theheader.h>
+
+int main() {}
diff --git a/tests/auto/blackbox/testdata/buildenv-change/subdir/theheader.h b/tests/auto/blackbox/testdata/buildenv-change/subdir/theheader.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/buildenv-change/subdir/theheader.h
diff --git a/tests/auto/blackbox/testdata/buildenv-change/subdir2/theheader.h b/tests/auto/blackbox/testdata/buildenv-change/subdir2/theheader.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/buildenv-change/subdir2/theheader.h
diff --git a/tests/auto/blackbox/testdata/clean/clean.qbs b/tests/auto/blackbox/testdata/clean/clean.qbs
index cf16e7c85..8221d0544 100644
--- a/tests/auto/blackbox/testdata/clean/clean.qbs
+++ b/tests/auto/blackbox/testdata/clean/clean.qbs
@@ -3,7 +3,6 @@ import qbs 1.0
Project {
DynamicLibrary {
Depends { name: "cpp" }
- Depends { name: "Qt.core" }
version: "1.1.0"
name: "dep"
files: "dep.cpp"
diff --git a/tests/auto/blackbox/testdata/clean/dep.cpp b/tests/auto/blackbox/testdata/clean/dep.cpp
index 7e43bdccf..cd271195e 100644
--- a/tests/auto/blackbox/testdata/clean/dep.cpp
+++ b/tests/auto/blackbox/testdata/clean/dep.cpp
@@ -26,6 +26,10 @@
**
****************************************************************************/
-#include <QtGlobal>
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT __attribute__((visibility("default")))
+#endif
-Q_DECL_EXPORT void f() {}
+EXPORT void f() {}
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
index ad39a8c5f..ef2dee093 100644
--- a/tests/auto/blackbox/testdata/dependency-profile-mismatch/dependency-profile-mismatch.qbs
+++ b/tests/auto/blackbox/testdata/dependency-profile-mismatch/dependency-profile-mismatch.qbs
@@ -5,7 +5,7 @@ Project {
property string depProfile
Product {
name: "dep"
- profiles: [project.depProfile]
+ qbs.profiles: [project.depProfile]
}
Product {
name: "main"
diff --git a/tests/auto/blackbox/testdata/deprecated-property/modules/themodule/m.qbs b/tests/auto/blackbox/testdata/deprecated-property/modules/themodule/m.qbs
index 47f1ea664..106ed4135 100644
--- a/tests/auto/blackbox/testdata/deprecated-property/modules/themodule/m.qbs
+++ b/tests/auto/blackbox/testdata/deprecated-property/modules/themodule/m.qbs
@@ -3,7 +3,7 @@ import qbs
Module {
property bool newProp
property bool oldProp
- property bool veryOldProp
+ property bool forgottenProp
PropertyOptions {
name: "newProp"
@@ -19,4 +19,9 @@ Module {
description: "Use newProp instead."
removalVersion: "1.3"
}
+ PropertyOptions {
+ name: "forgottenProp"
+ description: "Use newProp instead."
+ removalVersion: "1.8"
+ }
}
diff --git a/tests/auto/blackbox/testdata/disappeared-profile/disappeared-profile.qbs b/tests/auto/blackbox/testdata/disappeared-profile/disappeared-profile.qbs
new file mode 100644
index 000000000..659864b14
--- /dev/null
+++ b/tests/auto/blackbox/testdata/disappeared-profile/disappeared-profile.qbs
@@ -0,0 +1,14 @@
+import qbs
+
+Product {
+ type: ["out1", "out2"]
+ Depends { name: "m" }
+ Group {
+ files: ["in1.txt"]
+ fileTags: ["in1"]
+ }
+ Group {
+ files: ["in2.txt"]
+ fileTags: ["in2"]
+ }
+}
diff --git a/tests/auto/blackbox/testdata/disappeared-profile/in1.txt b/tests/auto/blackbox/testdata/disappeared-profile/in1.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/disappeared-profile/in1.txt
diff --git a/tests/auto/blackbox/testdata/disappeared-profile/in2.txt b/tests/auto/blackbox/testdata/disappeared-profile/in2.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/disappeared-profile/in2.txt
diff --git a/tests/auto/blackbox/testdata/disappeared-profile/modules-dir/modules/m/m.qbs b/tests/auto/blackbox/testdata/disappeared-profile/modules-dir/modules/m/m.qbs
new file mode 100644
index 000000000..a9c898889
--- /dev/null
+++ b/tests/auto/blackbox/testdata/disappeared-profile/modules-dir/modules/m/m.qbs
@@ -0,0 +1,34 @@
+import qbs
+
+Module {
+ property string p1
+ property string p2
+
+ Rule {
+ inputs: ["in1"]
+ Artifact {
+ filePath: "dummy1.txt"
+ fileTags: ["out1"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "Creating " + output.fileName + " with " + product.m.p1;
+ cmd.sourceCode = function() {};
+ return [cmd];
+ }
+ }
+
+ Rule {
+ inputs: ["in2"]
+ Artifact {
+ filePath: "dummy2.txt"
+ fileTags: ["out2"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "Creating " + output.fileName + " with " + product.m.p2;
+ cmd.sourceCode = function() {};
+ return [cmd];
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/enableExceptions/main.cpp b/tests/auto/blackbox/testdata/enableExceptions/main.cpp
index 70511e9fa..95a75710c 100644
--- a/tests/auto/blackbox/testdata/enableExceptions/main.cpp
+++ b/tests/auto/blackbox/testdata/enableExceptions/main.cpp
@@ -28,6 +28,10 @@
#include <stdexcept>
+#if defined(__GNUC__) && !(defined(__cpp_exceptions) || defined(__EXCEPTIONS))
+#error Exceptions are disabled!
+#endif
+
int main() {
#ifdef FORCE_FAIL_VS
#error "Microsoft Visual C++ cannot disable exceptions at compile-time"
diff --git a/tests/auto/blackbox/testdata/enableRtti/main.cpp b/tests/auto/blackbox/testdata/enableRtti/main.cpp
index 1a30228d6..6301561b3 100644
--- a/tests/auto/blackbox/testdata/enableRtti/main.cpp
+++ b/tests/auto/blackbox/testdata/enableRtti/main.cpp
@@ -28,6 +28,10 @@
#include <typeinfo>
+#if defined(__GNUC__) && !(defined(__cpp_rtti) || defined(__GXX_RTTI))
+#error RTTI is disabled!
+#endif
+
class I {
public:
virtual ~I() { }
diff --git a/tests/auto/blackbox/testdata/error-info/error-info.qbs b/tests/auto/blackbox/testdata/error-info/error-info.qbs
index a830be36c..afd44c246 100644
--- a/tests/auto/blackbox/testdata/error-info/error-info.qbs
+++ b/tests/auto/blackbox/testdata/error-info/error-info.qbs
@@ -15,7 +15,7 @@ Project {
type: ["foo", "bar"]
Rule {
- inputs: ["qbs"]
+ multiplex: true
Artifact {
fileTags: ["foo"]
@@ -42,7 +42,7 @@ Project {
}
Rule {
- inputs: ["qbs"]
+ multiplex: true
outputFileTags: ["bar"]
outputArtifacts: {
diff --git a/tests/auto/blackbox/testdata/export-rule/export-rule.qbs b/tests/auto/blackbox/testdata/export-rule/export-rule.qbs
index 51dd787a4..0b1f9f99b 100644
--- a/tests/auto/blackbox/testdata/export-rule/export-rule.qbs
+++ b/tests/auto/blackbox/testdata/export-rule/export-rule.qbs
@@ -6,14 +6,17 @@ Project {
name: "MyApp"
files: ["myapp.blubb"]
Depends { name: "blubber" }
- Depends { name: "cpp" }
}
StaticLibrary {
name: "blubber"
files: ["blubber.cpp"]
Depends { name: "cpp" }
Export {
+ Depends { name: "cpp" }
+ property bool enableTagger
+ property string description: "Creating C++ source file.";
FileTagger {
+ condition: enableTagger
patterns: ["*.blubb"]
fileTags: ["blubb"]
}
@@ -25,7 +28,7 @@ Project {
}
prepare: {
var cmd = new JavaScriptCommand();
- cmd.description = "Creating C++ source file.";
+ cmd.description = product.blubber.description;
cmd.sourceCode = function() {
File.copy(input.filePath, output.filePath);
}
diff --git a/tests/auto/blackbox/testdata/find/find-cli.qbs b/tests/auto/blackbox/testdata/find/find-cli.qbs
index ab33fbf8d..63609b3b2 100644
--- a/tests/auto/blackbox/testdata/find/find-cli.qbs
+++ b/tests/auto/blackbox/testdata/find/find-cli.qbs
@@ -5,7 +5,7 @@ Product {
Depends { name: "cli"; required: false }
type: ["json"]
Rule {
- inputs: ["qbs"]
+ multiplex: true
Artifact {
filePath: ["cli.json"]
fileTags: ["json"]
diff --git a/tests/auto/blackbox/testdata/ib/assetcatalog/MainMenu.xib b/tests/auto/blackbox/testdata/ib/assetcatalog/MainMenu.xib
deleted file mode 100644
index 14312411a..000000000
--- a/tests/auto/blackbox/testdata/ib/assetcatalog/MainMenu.xib
+++ /dev/null
@@ -1,680 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6157" systemVersion="14A237a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
- <dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6157"/>
- </dependencies>
- <objects>
- <customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
- <connections>
- <outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
- </connections>
- </customObject>
- <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
- <customObject id="-3" userLabel="Application"/>
- <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModuleProvider="">
- <connections>
- <outlet property="window" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
- </connections>
- </customObject>
- <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
- <menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
- <items>
- <menuItem title="CocoaApp" id="1Xt-HY-uBw">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="CocoaApp" systemMenu="apple" id="uQy-DD-JDr">
- <items>
- <menuItem title="About CocoaApp" id="5kV-Vb-QxS">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
- </connections>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
- <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
- <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
- <menuItem title="Services" id="NMo-om-nkz">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
- <menuItem title="Hide CocoaApp" keyEquivalent="h" id="Olw-nP-bQN">
- <connections>
- <action selector="hide:" target="-1" id="PnN-Uc-m68"/>
- </connections>
- </menuItem>
- <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
- <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
- <connections>
- <action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
- </connections>
- </menuItem>
- <menuItem title="Show All" id="Kd2-mp-pUS">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
- </connections>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
- <menuItem title="Quit CocoaApp" keyEquivalent="q" id="4sb-4s-VLi">
- <connections>
- <action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem title="File" id="dMs-cI-mzQ">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="File" id="bib-Uj-vzu">
- <items>
- <menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
- <connections>
- <action selector="newDocument:" target="-1" id="4Si-XN-c54"/>
- </connections>
- </menuItem>
- <menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
- <connections>
- <action selector="openDocument:" target="-1" id="bVn-NM-KNZ"/>
- </connections>
- </menuItem>
- <menuItem title="Open Recent" id="tXI-mr-wws">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
- <items>
- <menuItem title="Clear Menu" id="vNY-rz-j42">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="clearRecentDocuments:" target="-1" id="Daa-9d-B3U"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
- <menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
- <connections>
- <action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/>
- </connections>
- </menuItem>
- <menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
- <connections>
- <action selector="saveDocument:" target="-1" id="teZ-XB-qJY"/>
- </connections>
- </menuItem>
- <menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
- <connections>
- <action selector="saveDocumentAs:" target="-1" id="mDf-zr-I0C"/>
- </connections>
- </menuItem>
- <menuItem title="Revert to Saved" id="KaW-ft-85H">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="revertDocumentToSaved:" target="-1" id="iJ3-Pv-kwq"/>
- </connections>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
- <menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
- <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
- <connections>
- <action selector="runPageLayout:" target="-1" id="Din-rz-gC5"/>
- </connections>
- </menuItem>
- <menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
- <connections>
- <action selector="print:" target="-1" id="qaZ-4w-aoO"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem title="Edit" id="5QF-Oa-p0T">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Edit" id="W48-6f-4Dl">
- <items>
- <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
- <connections>
- <action selector="undo:" target="-1" id="M6e-cu-g7V"/>
- </connections>
- </menuItem>
- <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
- <connections>
- <action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
- </connections>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
- <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
- <connections>
- <action selector="cut:" target="-1" id="YJe-68-I9s"/>
- </connections>
- </menuItem>
- <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
- <connections>
- <action selector="copy:" target="-1" id="G1f-GL-Joy"/>
- </connections>
- </menuItem>
- <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
- <connections>
- <action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
- </connections>
- </menuItem>
- <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
- <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
- <connections>
- <action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
- </connections>
- </menuItem>
- <menuItem title="Delete" id="pa3-QI-u2k">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
- </connections>
- </menuItem>
- <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
- <connections>
- <action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
- </connections>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
- <menuItem title="Find" id="4EN-yA-p0u">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Find" id="1b7-l0-nxx">
- <items>
- <menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
- <connections>
- <action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
- </connections>
- </menuItem>
- <menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
- <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
- <connections>
- <action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
- </connections>
- </menuItem>
- <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
- <connections>
- <action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
- </connections>
- </menuItem>
- <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
- <connections>
- <action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
- </connections>
- </menuItem>
- <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
- <connections>
- <action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
- </connections>
- </menuItem>
- <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
- <connections>
- <action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
- <items>
- <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
- <connections>
- <action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
- </connections>
- </menuItem>
- <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
- <connections>
- <action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
- </connections>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
- <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
- </connections>
- </menuItem>
- <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
- </connections>
- </menuItem>
- <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem title="Substitutions" id="9ic-FL-obx">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
- <items>
- <menuItem title="Show Substitutions" id="z6F-FW-3nz">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
- </connections>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
- <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
- </connections>
- </menuItem>
- <menuItem title="Smart Quotes" id="hQb-2v-fYv">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
- </connections>
- </menuItem>
- <menuItem title="Smart Dashes" id="rgM-f4-ycn">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
- </connections>
- </menuItem>
- <menuItem title="Smart Links" id="cwL-P1-jid">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
- </connections>
- </menuItem>
- <menuItem title="Data Detectors" id="tRr-pd-1PS">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
- </connections>
- </menuItem>
- <menuItem title="Text Replacement" id="HFQ-gK-NFA">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem title="Transformations" id="2oI-Rn-ZJC">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Transformations" id="c8a-y6-VQd">
- <items>
- <menuItem title="Make Upper Case" id="vmV-6d-7jI">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
- </connections>
- </menuItem>
- <menuItem title="Make Lower Case" id="d9M-CD-aMd">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
- </connections>
- </menuItem>
- <menuItem title="Capitalize" id="UEZ-Bs-lqG">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem title="Speech" id="xrE-MZ-jX0">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Speech" id="3rS-ZA-NoH">
- <items>
- <menuItem title="Start Speaking" id="Ynk-f8-cLZ">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
- </connections>
- </menuItem>
- <menuItem title="Stop Speaking" id="Oyz-dy-DGm">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem title="Format" id="jxT-CU-nIS">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Format" id="GEO-Iw-cKr">
- <items>
- <menuItem title="Font" id="Gi5-1S-RQB">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
- <items>
- <menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
- <connections>
- <action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
- </connections>
- </menuItem>
- <menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
- <connections>
- <action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
- </connections>
- </menuItem>
- <menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
- <connections>
- <action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
- </connections>
- </menuItem>
- <menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
- <connections>
- <action selector="underline:" target="-1" id="FYS-2b-JAY"/>
- </connections>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
- <menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
- <connections>
- <action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
- </connections>
- </menuItem>
- <menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
- <connections>
- <action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
- </connections>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
- <menuItem title="Kern" id="jBQ-r6-VK2">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Kern" id="tlD-Oa-oAM">
- <items>
- <menuItem title="Use Default" id="GUa-eO-cwY">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="useStandardKerning:" target="-1" id="6dk-9l-Ckg"/>
- </connections>
- </menuItem>
- <menuItem title="Use None" id="cDB-IK-hbR">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="turnOffKerning:" target="-1" id="U8a-gz-Maa"/>
- </connections>
- </menuItem>
- <menuItem title="Tighten" id="46P-cB-AYj">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="tightenKerning:" target="-1" id="hr7-Nz-8ro"/>
- </connections>
- </menuItem>
- <menuItem title="Loosen" id="ogc-rX-tC1">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="loosenKerning:" target="-1" id="8i4-f9-FKE"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem title="Ligatures" id="o6e-r0-MWq">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
- <items>
- <menuItem title="Use Default" id="agt-UL-0e3">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="useStandardLigatures:" target="-1" id="7uR-wd-Dx6"/>
- </connections>
- </menuItem>
- <menuItem title="Use None" id="J7y-lM-qPV">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="turnOffLigatures:" target="-1" id="iX2-gA-Ilz"/>
- </connections>
- </menuItem>
- <menuItem title="Use All" id="xQD-1f-W4t">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="useAllLigatures:" target="-1" id="KcB-kA-TuK"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem title="Baseline" id="OaQ-X3-Vso">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Baseline" id="ijk-EB-dga">
- <items>
- <menuItem title="Use Default" id="3Om-Ey-2VK">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="unscript:" target="-1" id="0vZ-95-Ywn"/>
- </connections>
- </menuItem>
- <menuItem title="Superscript" id="Rqc-34-cIF">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="superscript:" target="-1" id="3qV-fo-wpU"/>
- </connections>
- </menuItem>
- <menuItem title="Subscript" id="I0S-gh-46l">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="subscript:" target="-1" id="Q6W-4W-IGz"/>
- </connections>
- </menuItem>
- <menuItem title="Raise" id="2h7-ER-AoG">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="raiseBaseline:" target="-1" id="4sk-31-7Q9"/>
- </connections>
- </menuItem>
- <menuItem title="Lower" id="1tx-W0-xDw">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="lowerBaseline:" target="-1" id="OF1-bc-KW4"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
- <menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
- <connections>
- <action selector="orderFrontColorPanel:" target="-1" id="mSX-Xz-DV3"/>
- </connections>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
- <menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
- <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
- <connections>
- <action selector="copyFont:" target="-1" id="GJO-xA-L4q"/>
- </connections>
- </menuItem>
- <menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
- <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
- <connections>
- <action selector="pasteFont:" target="-1" id="JfD-CL-leO"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem title="Text" id="Fal-I4-PZk">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Text" id="d9c-me-L2H">
- <items>
- <menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
- <connections>
- <action selector="alignLeft:" target="-1" id="zUv-R1-uAa"/>
- </connections>
- </menuItem>
- <menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
- <connections>
- <action selector="alignCenter:" target="-1" id="spX-mk-kcS"/>
- </connections>
- </menuItem>
- <menuItem title="Justify" id="J5U-5w-g23">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="alignJustified:" target="-1" id="ljL-7U-jND"/>
- </connections>
- </menuItem>
- <menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
- <connections>
- <action selector="alignRight:" target="-1" id="r48-bG-YeY"/>
- </connections>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
- <menuItem title="Writing Direction" id="H1b-Si-o9J">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
- <items>
- <menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
- <modifierMask key="keyEquivalentModifierMask"/>
- </menuItem>
- <menuItem id="YGs-j5-SAR">
- <string key="title"> Default</string>
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="makeBaseWritingDirectionNatural:" target="-1" id="qtV-5e-UBP"/>
- </connections>
- </menuItem>
- <menuItem id="Lbh-J2-qVU">
- <string key="title"> Left to Right</string>
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="makeBaseWritingDirectionLeftToRight:" target="-1" id="S0X-9S-QSf"/>
- </connections>
- </menuItem>
- <menuItem id="jFq-tB-4Kx">
- <string key="title"> Right to Left</string>
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="makeBaseWritingDirectionRightToLeft:" target="-1" id="5fk-qB-AqJ"/>
- </connections>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
- <menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
- <modifierMask key="keyEquivalentModifierMask"/>
- </menuItem>
- <menuItem id="Nop-cj-93Q">
- <string key="title"> Default</string>
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="makeTextWritingDirectionNatural:" target="-1" id="lPI-Se-ZHp"/>
- </connections>
- </menuItem>
- <menuItem id="BgM-ve-c93">
- <string key="title"> Left to Right</string>
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="makeTextWritingDirectionLeftToRight:" target="-1" id="caW-Bv-w94"/>
- </connections>
- </menuItem>
- <menuItem id="RB4-Sm-HuC">
- <string key="title"> Right to Left</string>
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="makeTextWritingDirectionRightToLeft:" target="-1" id="EXD-6r-ZUu"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
- <menuItem title="Show Ruler" id="vLm-3I-IUL">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="toggleRuler:" target="-1" id="FOx-HJ-KwY"/>
- </connections>
- </menuItem>
- <menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
- <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
- <connections>
- <action selector="copyRuler:" target="-1" id="71i-fW-3W2"/>
- </connections>
- </menuItem>
- <menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
- <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
- <connections>
- <action selector="pasteRuler:" target="-1" id="cSh-wd-qM2"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem title="View" id="H8h-7b-M4v">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="View" id="HyV-fh-RgO">
- <items>
- <menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
- <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
- <connections>
- <action selector="toggleToolbarShown:" target="-1" id="BXY-wc-z0C"/>
- </connections>
- </menuItem>
- <menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="runToolbarCustomizationPalette:" target="-1" id="pQI-g3-MTW"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem title="Window" id="aUF-d1-5bR">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
- <items>
- <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
- <connections>
- <action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
- </connections>
- </menuItem>
- <menuItem title="Zoom" id="R4o-n2-Eq4">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
- </connections>
- </menuItem>
- <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
- <menuItem title="Bring All to Front" id="LE2-aR-0XJ">
- <modifierMask key="keyEquivalentModifierMask"/>
- <connections>
- <action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- <menuItem title="Help" id="wpr-3q-Mcd">
- <modifierMask key="keyEquivalentModifierMask"/>
- <menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
- <items>
- <menuItem title="CocoaApp Help" keyEquivalent="?" id="FKE-Sm-Kum">
- <connections>
- <action selector="showHelp:" target="-1" id="y7X-2Q-9no"/>
- </connections>
- </menuItem>
- </items>
- </menu>
- </menuItem>
- </items>
- </menu>
- <window title="CocoaApp" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
- <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
- <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
- <rect key="contentRect" x="335" y="390" width="480" height="360"/>
- <rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
- <view key="contentView" id="EiT-Mj-1SZ">
- <rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
- <autoresizingMask key="autoresizingMask"/>
- </view>
- </window>
- </objects>
-</document>
diff --git a/tests/auto/blackbox/testdata/install-root-from-project-file/file.txt b/tests/auto/blackbox/testdata/install-root-from-project-file/file.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/install-root-from-project-file/file.txt
diff --git a/tests/auto/blackbox/testdata/install-root-from-project-file/install-root-from-project-file.qbs b/tests/auto/blackbox/testdata/install-root-from-project-file/install-root-from-project-file.qbs
new file mode 100644
index 000000000..ea7284a05
--- /dev/null
+++ b/tests/auto/blackbox/testdata/install-root-from-project-file/install-root-from-project-file.qbs
@@ -0,0 +1,13 @@
+import qbs
+
+Product {
+ name: "p"
+ property string installRoot
+ qbs.installRoot: installRoot
+ Group {
+ qbs.install: true
+ qbs.installPrefix: "/install-prefix"
+ qbs.installDir: "/install-dir"
+ files: ["file.txt"]
+ }
+}
diff --git a/tests/auto/blackbox/testdata/installpackage/installpackage.qbs b/tests/auto/blackbox/testdata/installpackage/installpackage.qbs
index 9ea561fca..0468e6bc0 100644
--- a/tests/auto/blackbox/testdata/installpackage/installpackage.qbs
+++ b/tests/auto/blackbox/testdata/installpackage/installpackage.qbs
@@ -1,7 +1,7 @@
import qbs
Project {
- QtApplication {
+ CppApplication {
name: "public_tool"
Depends { name: "mylib" }
files: ["main.cpp"]
@@ -11,14 +11,14 @@ Project {
qbs.installDir: "bin"
}
}
- QtApplication {
+ CppApplication {
name: "internal_tool"
Depends { name: "mylib" }
files: ["main.cpp"]
}
DynamicLibrary {
+ Depends { name: "cpp" }
name: "mylib"
- Depends { name: "Qt.core" }
files: ["lib.cpp"]
Group {
name: "public headers"
diff --git a/tests/auto/blackbox/testdata/installpackage/lib.h b/tests/auto/blackbox/testdata/installpackage/lib.h
index a464118a5..51d79758e 100644
--- a/tests/auto/blackbox/testdata/installpackage/lib.h
+++ b/tests/auto/blackbox/testdata/installpackage/lib.h
@@ -26,12 +26,18 @@
**
****************************************************************************/
-#include <QtGlobal>
-
#ifdef MYLIB
-#define MYLIB_EXPORT Q_DECL_EXPORT
+# if defined(_WIN32) || defined(WIN32)
+# define MYLIB_EXPORT __declspec(dllexport)
+# else
+# define MYLIB_EXPORT __attribute__((visibility("default")))
+# endif
#else
-#define MYLIB_EXPORT Q_DECL_IMPORT
+# if defined(_WIN32) || defined(WIN32)
+# define MYLIB_EXPORT __declspec(dllimport)
+# else
+# define MYLIB_EXPORT
+# endif
#endif
MYLIB_EXPORT void f();
diff --git a/tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs b/tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs
index c42c73129..388eef4e0 100644
--- a/tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs
+++ b/tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs
@@ -28,6 +28,7 @@ Product {
output.writeLine(FileInfo.isAbsolutePath("blubb.tar.gz"));
output.writeLine(FileInfo.isAbsolutePath("../blubb.tar.gz"));
output.writeLine(FileInfo.joinPaths("/", "tmp", "blubb.tar.gz"));
+ output.writeLine(FileInfo.joinPaths("//", "/tmp/", "/blubb.tar.gz"));
output.writeLine(FileInfo.path("/tmp/blubb.tar.gz"));
output.writeLine(FileInfo.path("/tmp/"));
output.writeLine(FileInfo.path("/"));
diff --git a/tests/auto/blackbox/testdata/jsextensions-process/main.cpp b/tests/auto/blackbox/testdata/jsextensions-process/main.cpp
new file mode 100644
index 000000000..df769de87
--- /dev/null
+++ b/tests/auto/blackbox/testdata/jsextensions-process/main.cpp
@@ -0,0 +1,20 @@
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+int main(int argc, char *argv[])
+{
+ if (argc != 2 || strcmp(argv[1], "help") != 0) {
+ fprintf(stderr, "First argument to this program must be 'help'.\n");
+ return 1;
+ }
+
+ const char *env = std::getenv("SOME_ENV");
+ if (!env || strcmp(env, "why, hello!") != 0) {
+ fprintf(stderr, "The SOME_ENV environment variable must be 'why, hello!'.\n");
+ return 1;
+ }
+
+ printf("qbs jsextensions-process test\n");
+ return 0;
+}
diff --git a/tests/auto/blackbox/testdata/jsextensions-process/process.qbs b/tests/auto/blackbox/testdata/jsextensions-process/process.qbs
index a6bb2506f..dc8c8c669 100644
--- a/tests/auto/blackbox/testdata/jsextensions-process/process.qbs
+++ b/tests/auto/blackbox/testdata/jsextensions-process/process.qbs
@@ -4,12 +4,14 @@ import qbs.Process
import qbs.TextFile
Project {
- property string qbsFilePath
Product {
- Depends { name: "Qt.core" }
+ Depends { name: "cpp" }
type: ["dummy"]
+ name: "dummy"
+ files: ["main.cpp"]
Rule {
multiplex: true
+ inputs: ["application"]
Artifact {
filePath: "dummy.txt"
fileTags: ["dummy"]
@@ -18,12 +20,16 @@ Project {
var cmd = new JavaScriptCommand();
cmd.silent = true;
cmd.sourceCode = function() {
+ var exeFilePath = FileInfo.joinPaths(product.buildDirectory,
+ product.cpp.executablePrefix
+ + "dummy"
+ + product.cpp.executableSuffix);
+
// Synchronous run, successful.
var process = new Process();
- var pathVal = [process.getEnv("PATH"), product.Qt.core.binPath]
- .join(product.qbs.pathListSeparator);
- process.setEnv("PATH", pathVal);
- process.exec(project.qbsFilePath, ["help"], true);
+ var pathVal = "why, hello!";
+ process.setEnv("SOME_ENV", pathVal);
+ process.exec(exeFilePath, ["help"], true);
var output = new TextFile("output.txt", TextFile.WriteOnly);
output.writeLine(process.exitCode());
output.writeLine(process.readLine());
@@ -31,8 +37,8 @@ Project {
// Asynchronous run, successful.
process = new Process();
- process.setEnv("PATH", pathVal);
- output.writeLine(process.start(project.qbsFilePath, ["help"]));
+ process.setEnv("SOME_ENV", pathVal);
+ output.writeLine(process.start(exeFilePath, ["help"]));
output.writeLine(process.waitForFinished());
output.writeLine(process.exitCode());
output.writeLine(process.readLine());
diff --git a/tests/auto/blackbox/testdata/jsextensions-propertylist/propertylist.qbs b/tests/auto/blackbox/testdata/jsextensions-propertylist/propertylist.qbs
index a2898f69f..a70b81625 100644
--- a/tests/auto/blackbox/testdata/jsextensions-propertylist/propertylist.qbs
+++ b/tests/auto/blackbox/testdata/jsextensions-propertylist/propertylist.qbs
@@ -4,7 +4,8 @@ import qbs.PropertyList
import qbs.TextFile
Product {
- type: {
+ type: ["Pineapple Steve"]
+ property bool dummy: {
var plistobj = new PropertyList();
if (!plistobj.isEmpty()) {
throw "newly created PropertyList was not empty!";
@@ -124,6 +125,6 @@ Product {
throw 'toString("xml1") and toXMLString() were not equivalent';
}
- return "Pineapple Steve";
+ return true;
}
}
diff --git a/tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs b/tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs
index 2cdf9f3f0..677828906 100644
--- a/tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs
+++ b/tests/auto/blackbox/testdata/lexyacc/one-grammar/one-grammar.qbs
@@ -6,6 +6,7 @@ CppApplication {
lex_yacc.yaccFlags: ["-l"]
cpp.includePaths: ["."]
cpp.cxxLanguageVersion: "c++11"
+ cpp.minimumMacosVersion: "10.7"
consoleApplication: true
files: [
"lexer.l",
diff --git a/tests/auto/blackbox/testdata/loadablemodule/exported.h b/tests/auto/blackbox/testdata/loadablemodule/exported.h
index 7745b5c97..24eb8b1a0 100644
--- a/tests/auto/blackbox/testdata/loadablemodule/exported.h
+++ b/tests/auto/blackbox/testdata/loadablemodule/exported.h
@@ -26,8 +26,12 @@
**
****************************************************************************/
-#include <QtCore/QtGlobal>
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT __attribute__((visibility("default")))
+#endif
extern "C" {
- Q_DECL_EXPORT int foo();
+ EXPORT int foo();
}
diff --git a/tests/auto/blackbox/testdata/loadablemodule/loadablemodule.qbs b/tests/auto/blackbox/testdata/loadablemodule/loadablemodule.qbs
index f50442681..a3327454d 100644
--- a/tests/auto/blackbox/testdata/loadablemodule/loadablemodule.qbs
+++ b/tests/auto/blackbox/testdata/loadablemodule/loadablemodule.qbs
@@ -4,7 +4,6 @@ Project {
LoadableModule {
Depends { name: "cpp" }
Depends { name: "bundle" }
- Depends { name: "Qt.core" }
bundle.isBundle: false
name: "CoolPlugIn"
files: ["exported.cpp", "exported.h"]
@@ -17,13 +16,20 @@ Project {
CppApplication {
Depends { name: "cpp" }
- Depends { name: "CoolPlugIn" }
+ Depends { name: "CoolPlugIn"; cpp.link: false }
Depends { name: "bundle" }
- Depends { name: "Qt.core" }
bundle.isBundle: false
name: "CoolApp"
files: ["main.cpp"]
+ cpp.cxxLanguageVersion: "c++11"
+ cpp.dynamicLibraries: [qbs.targetOS.contains("windows") ? "kernel32" : "dl"]
+
+ Properties {
+ condition: qbs.targetOS.contains("unix") && !qbs.targetOS.contains("darwin")
+ cpp.rpaths: ["$ORIGIN"]
+ }
+
Group {
fileTagsFilter: product.type
qbs.install: true
diff --git a/tests/auto/blackbox/testdata/loadablemodule/main.cpp b/tests/auto/blackbox/testdata/loadablemodule/main.cpp
index 259d2bb76..442480442 100644
--- a/tests/auto/blackbox/testdata/loadablemodule/main.cpp
+++ b/tests/auto/blackbox/testdata/loadablemodule/main.cpp
@@ -49,16 +49,39 @@
**
****************************************************************************/
-#include <QtCore/QDebug>
-#include <QtCore/QLibrary>
+#include <iostream>
+
+#ifdef _WIN32
+#include <windows.h>
+#define PREFIX ""
+#define SUFFIX ".dll"
+#define dlopen(path, mode) LoadLibraryA(path)
+#define dlsym(handle, symbol) GetProcAddress(handle, symbol)
+#define dlclose(handle) FreeLibrary(handle)
+#elif defined(__APPLE__)
+#define PREFIX ""
+#define SUFFIX ".bundle"
+#else
+#define PREFIX "lib"
+#define SUFFIX ".so"
+#endif
+
+#ifndef _WIN32
+#include <dlfcn.h>
+#endif
int main() {
- QLibrary lib("CoolPlugIn");
- if (lib.load()) {
- QFunctionPointer fptr = lib.resolve("foo");
- if (fptr) {
- qDebug() << "foo =" << ((int (*)(void))fptr)();
- }
+ auto lib = dlopen(PREFIX "CoolPlugIn" SUFFIX, RTLD_LAZY);
+ if (lib) {
+ auto fptr = dlsym(lib, "foo");
+ if (fptr)
+ std::cout << "foo = " << ((int (*)(void))fptr)() << std::endl;
+ else
+ std::cout << "function foo not found in CoolPlugIn" << std::endl;
+ dlclose(lib);
+ return fptr ? 0 : 1;
+ } else {
+ std::cout << "CoolPlugIn not loaded" << std::endl;
}
- return 0;
+ return 1;
}
diff --git a/tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p1.qbs b/tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p1.qbs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p1.qbs
diff --git a/tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p2.qbs b/tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p2.qbs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p2.qbs
diff --git a/tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p3.qbs b/tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p3.qbs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/missing-project-file/ambiguous-dir/p3.qbs
diff --git a/tests/auto/blackbox/testdata/missing-project-file/empty-dir/irrelevant.txt b/tests/auto/blackbox/testdata/missing-project-file/empty-dir/irrelevant.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/missing-project-file/empty-dir/irrelevant.txt
diff --git a/tests/auto/blackbox/testdata/missing-project-file/project-dir/file.cpp b/tests/auto/blackbox/testdata/missing-project-file/project-dir/file.cpp
new file mode 100644
index 000000000..8101b05dc
--- /dev/null
+++ b/tests/auto/blackbox/testdata/missing-project-file/project-dir/file.cpp
@@ -0,0 +1 @@
+void f() { }
diff --git a/tests/auto/blackbox/testdata/missing-project-file/project-dir/main.cpp b/tests/auto/blackbox/testdata/missing-project-file/project-dir/main.cpp
new file mode 100644
index 000000000..237c8ce18
--- /dev/null
+++ b/tests/auto/blackbox/testdata/missing-project-file/project-dir/main.cpp
@@ -0,0 +1 @@
+int main() {}
diff --git a/tests/auto/blackbox/testdata/missing-project-file/project-dir/missing-project-file.qbs b/tests/auto/blackbox/testdata/missing-project-file/project-dir/missing-project-file.qbs
new file mode 100644
index 000000000..a294cbd24
--- /dev/null
+++ b/tests/auto/blackbox/testdata/missing-project-file/project-dir/missing-project-file.qbs
@@ -0,0 +1,8 @@
+import qbs
+
+CppApplication {
+ files: [
+ "file.cpp",
+ "main.cpp"
+ ]
+}
diff --git a/tests/auto/blackbox/testdata/mixed-build-variants/mixed-build-variants.qbs b/tests/auto/blackbox/testdata/mixed-build-variants/mixed-build-variants.qbs
deleted file mode 100644
index 2b208f3d4..000000000
--- a/tests/auto/blackbox/testdata/mixed-build-variants/mixed-build-variants.qbs
+++ /dev/null
@@ -1,6 +0,0 @@
-import qbs
-
-QtApplication {
- Qt.core.qtBuildVariant: "release"
- files: ["main.cpp"]
-}
diff --git a/tests/auto/blackbox/testdata/pch-change-tracking/header1.h b/tests/auto/blackbox/testdata/pch-change-tracking/header1.h
index 2837dbdb8..828c2eab7 100644
--- a/tests/auto/blackbox/testdata/pch-change-tracking/header1.h
+++ b/tests/auto/blackbox/testdata/pch-change-tracking/header1.h
@@ -26,4 +26,10 @@
**
****************************************************************************/
+#pragma once
#include <iostream>
+
+inline void printGreeting()
+{
+ std::cout << "Tach." << std::endl;
+}
diff --git a/tests/auto/blackbox/testdata/pch-change-tracking/header2.cpp b/tests/auto/blackbox/testdata/pch-change-tracking/header2.cpp
new file mode 100644
index 000000000..17213a4a9
--- /dev/null
+++ b/tests/auto/blackbox/testdata/pch-change-tracking/header2.cpp
@@ -0,0 +1,8 @@
+#include "header2.h"
+// header1 is forced-included via pch.
+
+void printPersonalGreeting()
+{
+ printGreeting();
+ std::cout << "Was geht, Rumpelstilzchen?" << std::endl;
+}
diff --git a/tests/auto/blackbox/testdata/pch-change-tracking/header2.h b/tests/auto/blackbox/testdata/pch-change-tracking/header2.h
index 50841a226..e0d28dcb3 100644
--- a/tests/auto/blackbox/testdata/pch-change-tracking/header2.h
+++ b/tests/auto/blackbox/testdata/pch-change-tracking/header2.h
@@ -25,3 +25,6 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+
+#pragma once
+void printPersonalGreeting();
diff --git a/tests/auto/blackbox/testdata/pch-change-tracking/main.cpp b/tests/auto/blackbox/testdata/pch-change-tracking/main.cpp
index 609293e60..b3badcc56 100644
--- a/tests/auto/blackbox/testdata/pch-change-tracking/main.cpp
+++ b/tests/auto/blackbox/testdata/pch-change-tracking/main.cpp
@@ -31,5 +31,6 @@
int main()
{
- std::cout << "Tach." << std::endl;
+ printGreeting();
+ printPersonalGreeting();
}
diff --git a/tests/auto/blackbox/testdata/pch-change-tracking/pch-change-tracking.qbs b/tests/auto/blackbox/testdata/pch-change-tracking/pch-change-tracking.qbs
index 76fd41a83..273ec682b 100644
--- a/tests/auto/blackbox/testdata/pch-change-tracking/pch-change-tracking.qbs
+++ b/tests/auto/blackbox/testdata/pch-change-tracking/pch-change-tracking.qbs
@@ -4,6 +4,7 @@ CppApplication {
cpp.useCxxPrecompiledHeader: true
files: [
"header1.h",
+ "header2.cpp",
"header2.h",
"main.cpp",
]
diff --git a/tests/auto/blackbox/testdata/plugin-dependency/helper.cpp b/tests/auto/blackbox/testdata/plugin-dependency/helper.cpp
new file mode 100644
index 000000000..3a7f851f4
--- /dev/null
+++ b/tests/auto/blackbox/testdata/plugin-dependency/helper.cpp
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+EXPORT void helper_hello()
+{
+ puts("helper says hello!");
+}
diff --git a/tests/auto/blackbox/testdata/plugin-dependency/main.cpp b/tests/auto/blackbox/testdata/plugin-dependency/main.cpp
new file mode 100644
index 000000000..048adf952
--- /dev/null
+++ b/tests/auto/blackbox/testdata/plugin-dependency/main.cpp
@@ -0,0 +1,17 @@
+#if defined(_WIN32) || defined(WIN32)
+# define IMPORT __declspec(dllimport)
+#else
+# define IMPORT
+#endif
+
+IMPORT void plugin3_hello();
+IMPORT void plugin4_hello();
+IMPORT void helper_hello();
+
+int main()
+{
+ plugin3_hello();
+ plugin4_hello();
+ helper_hello();
+ return 0;
+}
diff --git a/tests/auto/blackbox/testdata/plugin-dependency/plugin-dependency.qbs b/tests/auto/blackbox/testdata/plugin-dependency/plugin-dependency.qbs
new file mode 100644
index 000000000..97d602ced
--- /dev/null
+++ b/tests/auto/blackbox/testdata/plugin-dependency/plugin-dependency.qbs
@@ -0,0 +1,53 @@
+import qbs
+
+Project {
+ CppApplication {
+ name: "myapp"
+ files: ["main.cpp"]
+ Depends { name: "plugin1"; cpp.link: false } // not to be linked
+ Depends { name: "plugin2" } // not to be linked
+ Depends { name: "plugin3"; cpp.link: true } // supposed to be linked
+ Depends { name: "plugin4" } // supposed to be linked
+ Depends { name: "helper" } // supposed to be linked
+ }
+ DynamicLibrary {
+ name: "plugin1"
+ files: ["plugin1.cpp"]
+ Depends { name: "cpp" }
+ }
+ DynamicLibrary {
+ name: "plugin2"
+ files: ["plugin2.cpp"]
+ Depends { name: "cpp" }
+ Export {
+ Parameters {
+ cpp.link: false
+ }
+ }
+ }
+ DynamicLibrary {
+ name: "plugin3"
+ files: ["plugin3.cpp"]
+ Depends { name: "cpp" }
+ Export {
+ Parameters {
+ cpp.link: false
+ }
+ }
+ }
+ DynamicLibrary {
+ name: "plugin4"
+ files: ["plugin4.cpp"]
+ Depends { name: "cpp" }
+ Export {
+ Parameters {
+ cpp.link: true
+ }
+ }
+ }
+ DynamicLibrary {
+ name: "helper"
+ files: ["helper.cpp"]
+ Depends { name: "cpp" }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/plugin-dependency/plugin1.cpp b/tests/auto/blackbox/testdata/plugin-dependency/plugin1.cpp
new file mode 100644
index 000000000..e21aca28f
--- /dev/null
+++ b/tests/auto/blackbox/testdata/plugin-dependency/plugin1.cpp
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+EXPORT void plugin1_hello()
+{
+ puts("plugin1 says hello!");
+}
diff --git a/tests/auto/blackbox/testdata/plugin-dependency/plugin2.cpp b/tests/auto/blackbox/testdata/plugin-dependency/plugin2.cpp
new file mode 100644
index 000000000..27c72d421
--- /dev/null
+++ b/tests/auto/blackbox/testdata/plugin-dependency/plugin2.cpp
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+EXPORT void plugin2_hello()
+{
+ puts("plugin2 says hello!");
+}
diff --git a/tests/auto/blackbox/testdata/plugin-dependency/plugin3.cpp b/tests/auto/blackbox/testdata/plugin-dependency/plugin3.cpp
new file mode 100644
index 000000000..9b011eba3
--- /dev/null
+++ b/tests/auto/blackbox/testdata/plugin-dependency/plugin3.cpp
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+EXPORT void plugin3_hello()
+{
+ puts("plugin3 says hello!");
+}
diff --git a/tests/auto/blackbox/testdata/plugin-dependency/plugin4.cpp b/tests/auto/blackbox/testdata/plugin-dependency/plugin4.cpp
new file mode 100644
index 000000000..fa1c520fc
--- /dev/null
+++ b/tests/auto/blackbox/testdata/plugin-dependency/plugin4.cpp
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+EXPORT void plugin4_hello()
+{
+ puts("plugin4 says hello!");
+}
diff --git a/tests/auto/blackbox/testdata/probes-in-nested-modules/probes-in-nested-modules.qbs b/tests/auto/blackbox/testdata/probes-in-nested-modules/probes-in-nested-modules.qbs
index 334dfda2f..ffc273e18 100644
--- a/tests/auto/blackbox/testdata/probes-in-nested-modules/probes-in-nested-modules.qbs
+++ b/tests/auto/blackbox/testdata/probes-in-nested-modules/probes-in-nested-modules.qbs
@@ -5,31 +5,34 @@ Project {
name: "a"
Depends { name: "outer" }
inner.alt: true
- type: {
+ property bool dummy: {
console.info("product " + name + ", inner.something = " + inner.something);
console.info("product " + name + ", outer.something = " + outer.something);
console.info("product " + name + ", outer.somethingElse = " + outer.somethingElse);
- return ["foo"];
+ return true;
}
+ type: ["foo"]
}
Product {
name: "b"
Depends { name: "inner" }
inner.alt: true
- type: {
+ property bool dummy: {
console.info("product " + name + ", inner.something = " + inner.something);
- return ["foo"];
+ return true;
}
+ type: ["foo"]
}
Product {
name: "c"
Depends { name: "inner" }
inner.alt: false
- type: {
+ property bool dummy: {
console.info("product " + name + ", inner.something = " + inner.something);
- return ["foo"];
+ return true;
}
+ type: ["foo"]
}
}
diff --git a/tests/auto/blackbox/testdata/project_filepath_check/main2.cpp b/tests/auto/blackbox/testdata/project_filepath_check/main2.cpp
new file mode 100644
index 000000000..237c8ce18
--- /dev/null
+++ b/tests/auto/blackbox/testdata/project_filepath_check/main2.cpp
@@ -0,0 +1 @@
+int main() {}
diff --git a/tests/auto/blackbox/testdata/project_filepath_check/project2.qbs b/tests/auto/blackbox/testdata/project_filepath_check/project2.qbs
index 5fc79d432..9abdac987 100644
--- a/tests/auto/blackbox/testdata/project_filepath_check/project2.qbs
+++ b/tests/auto/blackbox/testdata/project_filepath_check/project2.qbs
@@ -1,5 +1,5 @@
import qbs 1.0
CppApplication {
- files: "main.cpp"
+ files: "main2.cpp"
}
diff --git a/tests/auto/blackbox/testdata/propertyChanges/lib.cpp b/tests/auto/blackbox/testdata/propertyChanges/lib.cpp
index 7e43bdccf..cd271195e 100644
--- a/tests/auto/blackbox/testdata/propertyChanges/lib.cpp
+++ b/tests/auto/blackbox/testdata/propertyChanges/lib.cpp
@@ -26,6 +26,10 @@
**
****************************************************************************/
-#include <QtGlobal>
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT __attribute__((visibility("default")))
+#endif
-Q_DECL_EXPORT void f() {}
+EXPORT void f() {}
diff --git a/tests/auto/blackbox/testdata/propertyChanges/propertyChanges.qbs b/tests/auto/blackbox/testdata/propertyChanges/propertyChanges.qbs
index a2b42a626..5574c5fb4 100644
--- a/tests/auto/blackbox/testdata/propertyChanges/propertyChanges.qbs
+++ b/tests/auto/blackbox/testdata/propertyChanges/propertyChanges.qbs
@@ -24,8 +24,8 @@ Project {
files: "source3.cpp"
}
DynamicLibrary {
+ Depends { name: "cpp" }
name: "library"
- Depends { name: "Qt.core" }
files: "lib.cpp"
bundle.isBundle: false
}
diff --git a/tests/auto/blackbox/testdata/qbsVersion/qbs-version.qbs b/tests/auto/blackbox/testdata/qbsVersion/qbs-version.qbs
index b07ee494e..d7ef0d68b 100644
--- a/tests/auto/blackbox/testdata/qbsVersion/qbs-version.qbs
+++ b/tests/auto/blackbox/testdata/qbsVersion/qbs-version.qbs
@@ -7,7 +7,7 @@ Project {
property int qbsVersionPatch
Product {
- name: {
+ property bool dummy: {
if (qbsVersion !== qbs.version ||
qbsVersionMajor !== qbs.versionMajor ||
qbsVersionMinor !== qbs.versionMinor ||
@@ -16,7 +16,7 @@ Project {
+ [qbsVersion, qbsVersionMajor, qbsVersionMinor, qbsVersionPatch].join(", ")
+ ", got "
+ [qbs.version, qbs.versionMajor, qbs.versionMinor, qbs.versionPatch].join(", "));
- return "foo";
+ return false;
}
}
}
diff --git a/tests/auto/blackbox/testdata/rule-with-non-required-inputs/a.inp b/tests/auto/blackbox/testdata/rule-with-non-required-inputs/a.inp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/rule-with-non-required-inputs/a.inp
diff --git a/tests/auto/blackbox/testdata/rule-with-non-required-inputs/b.inp b/tests/auto/blackbox/testdata/rule-with-non-required-inputs/b.inp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/rule-with-non-required-inputs/b.inp
diff --git a/tests/auto/blackbox/testdata/rule-with-non-required-inputs/c.inp b/tests/auto/blackbox/testdata/rule-with-non-required-inputs/c.inp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/rule-with-non-required-inputs/c.inp
diff --git a/tests/auto/blackbox/testdata/rule-with-non-required-inputs/rule-with-non-required-inputs.qbs b/tests/auto/blackbox/testdata/rule-with-non-required-inputs/rule-with-non-required-inputs.qbs
new file mode 100644
index 000000000..6719bc69d
--- /dev/null
+++ b/tests/auto/blackbox/testdata/rule-with-non-required-inputs/rule-with-non-required-inputs.qbs
@@ -0,0 +1,42 @@
+import qbs
+import qbs.TextFile
+
+Product {
+ name: "p"
+ type: ["p.out"]
+
+ property bool enableTagger
+
+ FileTagger {
+ condition: enableTagger
+ patterns: ["*.inp"]
+ fileTags: ["p.in"]
+ }
+
+ Rule {
+ multiplex: true
+ requiresInputs: false
+ inputs: ["p.in"]
+ Artifact {
+ filePath: "output.txt"
+ fileTags: ["p.out"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "Generating " + output.fileName;
+ cmd.sourceCode = function() {
+ var f = new TextFile(output.filePath, TextFile.WriteOnly);
+ f.write('(');
+ var inputsList = inputs["p.in"];
+ if (inputsList) {
+ for (var i = 0; i < inputsList.length; ++i)
+ f.write(inputsList[i].fileName + ',');
+ }
+ f.write(')');
+ };
+ return [cmd];
+ }
+ }
+
+ files: ["a.inp", "b.inp", "c.inp"]
+}
diff --git a/tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs b/tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs
index c0498df3d..1ecbe0f36 100644
--- a/tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs
+++ b/tests/auto/blackbox/testdata/separate-debug-info/separate-debug-info.qbs
@@ -46,7 +46,10 @@ Project {
type: ["application"]
files: ["main.cpp"]
cpp.separateDebugInformation: true
- cpp.dsymutilFlags: ["--flat"]
+ Properties {
+ condition: qbs.targetOS.contains("darwin")
+ cpp.dsymutilFlags: ["--flat"]
+ }
}
DynamicLibrary {
Depends { name: "cpp" }
@@ -54,14 +57,20 @@ Project {
type: ["dynamiclibrary"]
files: ["foo.cpp"]
cpp.separateDebugInformation: true
- cpp.dsymutilFlags: ["--flat"]
+ Properties {
+ condition: qbs.targetOS.contains("darwin")
+ cpp.dsymutilFlags: ["--flat"]
+ }
}
LoadableModule {
Depends { name: "cpp" }
name: "bar3"
files: ["foo.cpp"]
cpp.separateDebugInformation: true
- cpp.dsymutilFlags: ["--flat"]
+ Properties {
+ condition: qbs.targetOS.contains("darwin")
+ cpp.dsymutilFlags: ["--flat"]
+ }
}
CppApplication {
@@ -93,7 +102,10 @@ Project {
files: ["main.cpp"]
bundle.isBundle: false
cpp.separateDebugInformation: true
- cpp.dsymutilFlags: ["--flat"]
+ Properties {
+ condition: qbs.targetOS.contains("darwin")
+ cpp.dsymutilFlags: ["--flat"]
+ }
}
DynamicLibrary {
Depends { name: "cpp" }
@@ -102,7 +114,10 @@ Project {
files: ["foo.cpp"]
bundle.isBundle: false
cpp.separateDebugInformation: true
- cpp.dsymutilFlags: ["--flat"]
+ Properties {
+ condition: qbs.targetOS.contains("darwin")
+ cpp.dsymutilFlags: ["--flat"]
+ }
}
LoadableModule {
Depends { name: "cpp" }
@@ -110,6 +125,9 @@ Project {
files: ["foo.cpp"]
bundle.isBundle: false
cpp.separateDebugInformation: true
- cpp.dsymutilFlags: ["--flat"]
+ Properties {
+ condition: qbs.targetOS.contains("darwin")
+ cpp.dsymutilFlags: ["--flat"]
+ }
}
}
diff --git a/tests/auto/blackbox/testdata/subprofile-change-tracking/subprofile-change-tracking.qbs b/tests/auto/blackbox/testdata/subprofile-change-tracking/subprofile-change-tracking.qbs
index 4805c5272..b3fba23fe 100644
--- a/tests/auto/blackbox/testdata/subprofile-change-tracking/subprofile-change-tracking.qbs
+++ b/tests/auto/blackbox/testdata/subprofile-change-tracking/subprofile-change-tracking.qbs
@@ -1,9 +1,10 @@
import qbs
Project {
- CppApplication { files: ["main1.cpp"] }
+ CppApplication { name: "app1"; files: ["main1.cpp"] }
CppApplication {
- profiles: ["qbs-autotests-subprofile"]
+ name: "app2"
+ qbs.profiles: ["qbs-autotests-subprofile"]
files: ["main2.cpp"]
}
}
diff --git a/tests/auto/blackbox/testdata/symbolLinkMode/indirect.cpp b/tests/auto/blackbox/testdata/symbolLinkMode/indirect.cpp
new file mode 100644
index 000000000..023acf40f
--- /dev/null
+++ b/tests/auto/blackbox/testdata/symbolLinkMode/indirect.cpp
@@ -0,0 +1,3 @@
+void indirect()
+{
+}
diff --git a/tests/auto/blackbox/testdata/symbolLinkMode/lib.cpp b/tests/auto/blackbox/testdata/symbolLinkMode/lib.cpp
new file mode 100644
index 000000000..8d96f5094
--- /dev/null
+++ b/tests/auto/blackbox/testdata/symbolLinkMode/lib.cpp
@@ -0,0 +1,11 @@
+int somefunction()
+{
+ return 42;
+}
+
+#include <stdio.h>
+
+static const auto func = []() {
+ printf("Lib was loaded!\n");
+ return 0;
+}();
diff --git a/tests/auto/blackbox/testdata/symbolLinkMode/main.cpp b/tests/auto/blackbox/testdata/symbolLinkMode/main.cpp
new file mode 100644
index 000000000..801491634
--- /dev/null
+++ b/tests/auto/blackbox/testdata/symbolLinkMode/main.cpp
@@ -0,0 +1,17 @@
+extern WEAK_IMPORT int somefunction();
+extern void indirect();
+
+#include <stdio.h>
+
+int main()
+{
+ printf("meow\n");
+ if (&somefunction != nullptr)
+ printf("somefunction existed and it returned %d\n", somefunction());
+ else
+ printf("somefunction did not exist\n");
+#if SHOULD_INSTALL_LIB
+ indirect();
+#endif
+ return 0;
+}
diff --git a/tests/auto/blackbox/testdata/symbolLinkMode/symbolLinkMode.qbs b/tests/auto/blackbox/testdata/symbolLinkMode/symbolLinkMode.qbs
new file mode 100644
index 000000000..95adaa4ba
--- /dev/null
+++ b/tests/auto/blackbox/testdata/symbolLinkMode/symbolLinkMode.qbs
@@ -0,0 +1,105 @@
+import qbs
+import qbs.FileInfo
+
+Project {
+ property bool shouldInstallLibrary: true
+ property bool lazy: false
+
+ Application {
+ Depends { name: "cpp" }
+ Depends {
+ name: "functions";
+ cpp.symbolLinkMode: product.symbolLinkMode
+ cpp.link: !(product.qbs.targetOS.contains("linux") && product.symbolLinkMode === "weak")
+ }
+
+ property string symbolLinkMode: project.lazy ? "lazy" : "weak"
+
+ name: "driver"
+ files: ["main.cpp"]
+ consoleApplication: true
+ property string installLib: "SHOULD_INSTALL_LIB=" + project.shouldInstallLibrary
+ cpp.defines: {
+ if (symbolLinkMode === "weak") {
+ return qbs.targetOS.contains("darwin")
+ ? ["WEAK_IMPORT=__attribute__((weak_import))", installLib]
+ : ["WEAK_IMPORT=__attribute__((weak))", installLib];
+ }
+ return ["WEAK_IMPORT=", installLib];
+ }
+ cpp.cxxLanguageVersion: "c++11"
+ cpp.minimumMacosVersion: "10.5"
+ cpp.rpaths: qbs.targetOS.contains("darwin") ? ["@loader_path/../lib"] : ["$ORIGIN/../lib"]
+
+ Group {
+ fileTagsFilter: product.type
+ qbs.install: true
+ qbs.installDir: "bin"
+ }
+ }
+
+ DynamicLibrary {
+ Depends { name: "bundle" }
+ Depends { name: "cpp" }
+ Depends { name: "indirect"; cpp.symbolLinkMode: "reexport" }
+
+ bundle.isBundle: false
+ name: "functions"
+ files: ["lib.cpp"]
+ cpp.cxxLanguageVersion: "c++11"
+ cpp.minimumMacosVersion: "10.5"
+ cpp.rpaths: qbs.targetOS.contains("darwin") ? ["@loader_path"] : ["$ORIGIN"]
+
+ Properties {
+ condition: qbs.targetOS.contains("darwin")
+ cpp.sonamePrefix: "@rpath"
+ }
+
+ Group {
+ condition: project.shouldInstallLibrary
+ fileTagsFilter: product.type
+ qbs.install: true
+ qbs.installDir: "lib"
+ }
+
+ Export {
+ // let the autotest pass on Linux where reexport is not supported
+ Depends { name: "indirect"; condition: !qbs.targetOS.contains("darwin") }
+
+ // on Linux, there is no LC_WEAK_LOAD_DYLIB equivalent (the library is simply omitted
+ // from the list of load commands entirely), so use LD_PRELOAD to emulate
+ qbs.commonRunEnvironment: {
+ var env = original || {};
+ if (project.shouldInstallLibrary) {
+ env["LD_PRELOAD"] = FileInfo.joinPaths(qbs.installRoot,
+ "lib", "libfunctions.so");
+ }
+ return env;
+ }
+ }
+ }
+
+ DynamicLibrary {
+ Depends { name: "bundle" }
+ Depends { name: "cpp" }
+
+ bundle.isBundle: false
+ name: "indirect"
+ files: ["indirect.cpp"]
+ cpp.cxxLanguageVersion: "c++11"
+ cpp.minimumMacosVersion: "10.5"
+
+ Properties {
+ condition: qbs.targetOS.contains("darwin")
+ // reexport is incompatible with rpath,
+ // "ERROR: ld: file not found: @rpath/libindirect.dylib for architecture x86_64"
+ cpp.sonamePrefix: qbs.installRoot + "/lib"
+ }
+
+ Group {
+ fileTagsFilter: product.type
+ qbs.install: true
+ qbs.installDir: "lib"
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/whole-archive/dynamiclib.cpp b/tests/auto/blackbox/testdata/whole-archive/dynamiclib.cpp
new file mode 100644
index 000000000..60fd0a148
--- /dev/null
+++ b/tests/auto/blackbox/testdata/whole-archive/dynamiclib.cpp
@@ -0,0 +1,9 @@
+void usedFunc();
+
+#if defined(_WIN32) || defined(WIN32)
+# define EXPORT __declspec(dllexport)
+#else
+# define EXPORT
+#endif
+
+EXPORT void f() { usedFunc(); }
diff --git a/tests/auto/blackbox/testdata/whole-archive/main1.cpp b/tests/auto/blackbox/testdata/whole-archive/main1.cpp
new file mode 100644
index 000000000..6a8af0299
--- /dev/null
+++ b/tests/auto/blackbox/testdata/whole-archive/main1.cpp
@@ -0,0 +1,6 @@
+DLLIMPORT void unusedFunc1();
+
+int main()
+{
+ unusedFunc1();
+}
diff --git a/tests/auto/blackbox/testdata/whole-archive/main2.cpp b/tests/auto/blackbox/testdata/whole-archive/main2.cpp
new file mode 100644
index 000000000..08f443f65
--- /dev/null
+++ b/tests/auto/blackbox/testdata/whole-archive/main2.cpp
@@ -0,0 +1,6 @@
+DLLIMPORT void unusedFunc2();
+
+int main()
+{
+ unusedFunc2();
+}
diff --git a/tests/auto/blackbox/testdata/whole-archive/main3.cpp b/tests/auto/blackbox/testdata/whole-archive/main3.cpp
new file mode 100644
index 000000000..1bc67c7d3
--- /dev/null
+++ b/tests/auto/blackbox/testdata/whole-archive/main3.cpp
@@ -0,0 +1,6 @@
+DLLIMPORT void unusedFunc3();
+
+int main()
+{
+ unusedFunc3();
+}
diff --git a/tests/auto/blackbox/testdata/whole-archive/main4.cpp b/tests/auto/blackbox/testdata/whole-archive/main4.cpp
new file mode 100644
index 000000000..2295261b1
--- /dev/null
+++ b/tests/auto/blackbox/testdata/whole-archive/main4.cpp
@@ -0,0 +1,6 @@
+DLLIMPORT void unusedFunc4();
+
+int main()
+{
+ unusedFunc4();
+}
diff --git a/tests/auto/blackbox/testdata/whole-archive/unused1.cpp b/tests/auto/blackbox/testdata/whole-archive/unused1.cpp
new file mode 100644
index 000000000..4b1600423
--- /dev/null
+++ b/tests/auto/blackbox/testdata/whole-archive/unused1.cpp
@@ -0,0 +1 @@
+DLLEXPORT void unusedFunc1() { }
diff --git a/tests/auto/blackbox/testdata/whole-archive/unused2.cpp b/tests/auto/blackbox/testdata/whole-archive/unused2.cpp
new file mode 100644
index 000000000..e1436ef4a
--- /dev/null
+++ b/tests/auto/blackbox/testdata/whole-archive/unused2.cpp
@@ -0,0 +1 @@
+DLLEXPORT void unusedFunc2() { }
diff --git a/tests/auto/blackbox/testdata/whole-archive/unused3.cpp b/tests/auto/blackbox/testdata/whole-archive/unused3.cpp
new file mode 100644
index 000000000..28937a5c2
--- /dev/null
+++ b/tests/auto/blackbox/testdata/whole-archive/unused3.cpp
@@ -0,0 +1 @@
+DLLEXPORT void unusedFunc3() { }
diff --git a/tests/auto/blackbox/testdata/whole-archive/unused4.cpp b/tests/auto/blackbox/testdata/whole-archive/unused4.cpp
new file mode 100644
index 000000000..79c9c818e
--- /dev/null
+++ b/tests/auto/blackbox/testdata/whole-archive/unused4.cpp
@@ -0,0 +1 @@
+DLLEXPORT void unusedFunc4() { }
diff --git a/tests/auto/blackbox/testdata/whole-archive/used.cpp b/tests/auto/blackbox/testdata/whole-archive/used.cpp
new file mode 100644
index 000000000..fe7afff2f
--- /dev/null
+++ b/tests/auto/blackbox/testdata/whole-archive/used.cpp
@@ -0,0 +1 @@
+void usedFunc() { }
diff --git a/tests/auto/blackbox/testdata/whole-archive/whole-archive.qbs b/tests/auto/blackbox/testdata/whole-archive/whole-archive.qbs
new file mode 100644
index 000000000..ed1d24ce0
--- /dev/null
+++ b/tests/auto/blackbox/testdata/whole-archive/whole-archive.qbs
@@ -0,0 +1,70 @@
+import qbs
+
+Project {
+ property string importSymbol: qbs.targetOS.contains("windows") ? "__declspec(dllimport)" : ""
+ property string importDefine: "DLLIMPORT=" + importSymbol
+ property string exportSymbol: qbs.targetOS.contains("windows") ? "__declspec(dllexport)" : ""
+ property string exportDefine: "DLLEXPORT=" + exportSymbol
+
+ StaticLibrary {
+ name: "staticlib 1"
+ Depends { name: "cpp" }
+ cpp.defines: [project.exportDefine]
+ files: ["unused1.cpp", "used.cpp"]
+ }
+ StaticLibrary {
+ name: "staticlib2"
+ Depends { name: "cpp" }
+ cpp.defines: [project.exportDefine]
+ files: ["unused2.cpp"]
+ }
+ StaticLibrary {
+ name: "staticlib3"
+ Depends { name: "cpp" }
+ cpp.defines: [project.exportDefine]
+ files: ["unused3.cpp"]
+ }
+ StaticLibrary {
+ name: "staticlib4"
+ Depends { name: "cpp" }
+ cpp.defines: [project.exportDefine]
+ files: ["unused4.cpp"]
+ }
+
+ DynamicLibrary {
+ name: "dynamiclib"
+ property string linkWholeArchive
+ Depends { name: "cpp" }
+ Depends { name: "staticlib 1"; cpp.linkWholeArchive: product.linkWholeArchive }
+ Depends { name: "staticlib2"; cpp.linkWholeArchive: product.linkWholeArchive }
+ Depends { name: "staticlib3" }
+ Depends { name: "staticlib4"; cpp.linkWholeArchive: product.linkWholeArchive }
+ files: ["dynamiclib.cpp"]
+ }
+
+ CppApplication {
+ name: "app1"
+ Depends { name: "dynamiclib" }
+ cpp.defines: [project.importDefine]
+ files: ["main1.cpp"]
+ }
+
+ CppApplication {
+ name: "app2"
+ Depends { name: "dynamiclib" }
+ cpp.defines: [project.importDefine]
+ files: ["main2.cpp"]
+ }
+ CppApplication {
+ name: "app3"
+ Depends { name: "dynamiclib" }
+ cpp.defines: [project.importDefine]
+ files: ["main3.cpp"]
+ }
+ CppApplication {
+ name: "app4"
+ Depends { name: "dynamiclib" }
+ cpp.defines: [project.importDefine]
+ files: ["main4.cpp"]
+ }
+}
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
index 5115c7ddb..959589813 100644
--- a/tests/auto/blackbox/tst_blackbox.cpp
+++ b/tests/auto/blackbox/tst_blackbox.cpp
@@ -32,7 +32,6 @@
#include <tools/hostosinfo.h>
#include <tools/profile.h>
-#include <tools/settings.h>
#include <tools/shellutils.h>
#include <tools/version.h>
@@ -43,19 +42,16 @@
#include <QtCore/qjsonvalue.h>
#include <QtCore/qlocale.h>
#include <QtCore/qregexp.h>
-#include <QtCore/qregularexpression.h>
#include <QtCore/qtemporarydir.h>
#include <QtCore/qtemporaryfile.h>
-#include <QtXml/qdom.h>
-
#include <functional>
+#include <regex>
#define WAIT_FOR_NEW_TIMESTAMP() waitForNewTimestamp(testDataDir)
using qbs::Internal::HostOsInfo;
using qbs::Profile;
-using qbs::Settings;
class MacosTarHealer {
public:
@@ -136,27 +132,20 @@ QString TestBlackbox::findArchiver(const QString &fileName, int *status)
QString binary = findExecutable(QStringList(fileName));
if (binary.isEmpty()) {
- Settings s((QString()));
- Profile p(profileName(), &s);
+ const SettingsPtr s = settings();
+ Profile p(profileName(), s.get());
binary = findExecutable(p.value("archiver.command").toStringList());
}
return binary;
}
-static bool isXcodeProfile(const QString &profileName)
-{
- qbs::Settings settings((QString()));
- qbs::Profile profile(profileName, &settings);
- return profile.value("qbs.toolchain").toStringList().contains("xcode");
-}
-
void TestBlackbox::sevenZip()
{
QDir::setCurrent(testDataDir + "/archiver");
QString binary = findArchiver("7z");
if (binary.isEmpty())
QSKIP("7zip not found");
- QCOMPARE(runQbs(QbsRunParameters(QStringList() << "archiver.type:7zip")), 0);
+ QCOMPARE(runQbs(QbsRunParameters(QStringList() << "modules.archiver.type:7zip")), 0);
const QString outputFile = relativeProductBuildDir("archivable") + "/archivable.7z";
QVERIFY2(regularFileExists(outputFile), qPrintable(outputFile));
QProcess listContents;
@@ -170,14 +159,6 @@ void TestBlackbox::sevenZip()
QVERIFY2(output.contains("archivable.qbs"), output.constData());
}
-void TestBlackbox::staticQtPluginLinking()
-{
- QDir::setCurrent(testDataDir + "/static-qt-plugin-linking");
- QCOMPARE(runQbs(), 0);
- const bool isStaticQt = m_qbsStdout.contains("Qt is static");
- QVERIFY2(m_qbsStdout.contains("Creating static import") == isStaticQt, m_qbsStdout.constData());
-}
-
void TestBlackbox::suspiciousCalls()
{
const QString projectDir = testDataDir + "/suspicious-calls";
@@ -213,10 +194,11 @@ void TestBlackbox::tar()
QSKIP("Beware of the msys tar");
MacosTarHealer tarHealer;
QDir::setCurrent(testDataDir + "/archiver");
+ rmDirR(relativeBuildDir());
QString binary = findArchiver("tar");
if (binary.isEmpty())
QSKIP("tar not found");
- QCOMPARE(runQbs(QbsRunParameters(QStringList() << "archiver.type:tar")), 0);
+ QCOMPARE(runQbs(QbsRunParameters(QStringList() << "modules.archiver.type:tar")), 0);
const QString outputFile = relativeProductBuildDir("archivable") + "/archivable.tar.gz";
QVERIFY2(regularFileExists(outputFile), qPrintable(outputFile));
QProcess listContents;
@@ -246,8 +228,9 @@ void TestBlackbox::zip()
QSKIP("zip tool not found");
QDir::setCurrent(testDataDir + "/archiver");
+ rmDirR(relativeBuildDir());
QbsRunParameters params(QStringList()
- << "archiver.type:zip" << "archiver.command:" + binary);
+ << "modules.archiver.type:zip" << "modules.archiver.command:" + binary);
QCOMPARE(runQbs(params), 0);
const QString outputFile = relativeProductBuildDir("archivable") + "/archivable.zip";
QVERIFY2(regularFileExists(outputFile), qPrintable(outputFile));
@@ -267,8 +250,10 @@ void TestBlackbox::zip()
sortedFileList(listFile.readAll()));
// Make sure the module is still loaded when the java/jar fallback is not available
- params.arguments << "java.jdkPath:/blubb";
+ params.command = "resolve";
+ params.arguments << "modules.java.jdkPath:/blubb";
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
}
void TestBlackbox::zip_data()
@@ -281,8 +266,9 @@ void TestBlackbox::zip_data()
void TestBlackbox::zipInvalid()
{
QDir::setCurrent(testDataDir + "/archiver");
- QbsRunParameters params(QStringList() << "archiver.type:zip"
- << "archiver.command:/bin/something");
+ rmDirR(relativeBuildDir());
+ QbsRunParameters params(QStringList() << "modules.archiver.type:zip"
+ << "modules.archiver.command:/bin/something");
params.expectFailure = true;
QVERIFY(runQbs(params) != 0);
QVERIFY2(m_qbsStderr.contains("unrecognized archive tool: 'something'"), m_qbsStderr.constData());
@@ -335,7 +321,7 @@ void TestBlackbox::artifactScanning()
{
const QString projectDir = testDataDir + "/artifact-scanning";
QDir::setCurrent(projectDir);
- QbsRunParameters params("-vv");
+ QbsRunParameters params(QStringList("-vv"));
QCOMPARE(runQbs(params), 0);
QCOMPARE(m_qbsStderr.count("scanning p1.cpp"), 1);
@@ -433,7 +419,10 @@ void TestBlackbox::artifactScanning()
WAIT_FOR_NEW_TIMESTAMP();
touch("p1.cpp");
- params.arguments << "cpp.treatSystemHeadersAsDependencies:true";
+ params.command = "resolve";
+ params.arguments << "modules.cpp.treatSystemHeadersAsDependencies:true";
+ QCOMPARE(runQbs(params), 0);
+ params.command = "build";
QCOMPARE(runQbs(params), 0);
QCOMPARE(m_qbsStderr.count("scanning p1.cpp"), 1);
QCOMPARE(m_qbsStderr.count("scanning p2.cpp"), 0);
@@ -462,246 +451,38 @@ void TestBlackbox::buildDirectories()
QVERIFY2(outputLines.contains(projectDir), m_qbsStdout.constData());
}
-class QFileInfo2 : public QFileInfo {
-public:
- QFileInfo2(const QString &path) : QFileInfo(path) { }
- bool isRegularFile() const { return isFile() && !isSymLink(); }
- bool isRegularDir() const { return isDir() && !isSymLink(); }
- bool isFileSymLink() const { return isFile() && isSymLink(); }
- bool isDirSymLink() const { return isDir() && isSymLink(); }
-};
-
-void TestBlackbox::bundleStructure()
+void TestBlackbox::buildEnvChange()
{
- if (!HostOsInfo::isMacosHost())
- QSKIP("only applies on macOS");
-
- QFETCH(QString, productName);
- QFETCH(QString, productTypeIdentifier);
- QFETCH(bool, isShallow);
-
- QDir::setCurrent(testDataDir + "/bundle-structure");
+ QDir::setCurrent(testDataDir + "/buildenv-change");
QbsRunParameters params;
- params.arguments << "project.buildableProducts:" + productName;
- if (isShallow) {
- // Coerce shallow bundles - don't set bundle.isShallow directly because we want to test the
- // automatic detection
- params.arguments
- << "qbs.targetOS:ios,darwin,bsd,unix"
- << "qbs.architecture:arm64";
- }
-
- if (productName == "ABadApple" || productName == "ABadThirdParty")
- params.expectFailure = true;
-
- rmDirR(relativeBuildDir());
- const int status = runQbs(params);
- if (status != 0) {
- QVERIFY2(m_qbsStderr.contains("Bundle product type "
- + productTypeIdentifier.toLatin1()
- + " is not supported."),
- m_qbsStderr.constData());
- return;
- }
-
- QCOMPARE(status, 0);
-
- if (!isShallow) {
- if (productName == "A") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/Info.plist").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/MacOS").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/MacOS/A").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/PkgInfo").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/Resources").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/Resources/resource.txt").isRegularFile());
- }
-
- if (productName == "B") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/B").isFileSymLink());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Headers").isDirSymLink());
- //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Modules").isDirSymLink());
- QVERIFY(!QFileInfo2(defaultInstallRoot + "/B.framework/PkgInfo").exists());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/PrivateHeaders").isDirSymLink());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Resources").isDirSymLink());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/B").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Headers").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Headers/dummy.h").isRegularFile());
- //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Modules").isRegularDir());
- //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Modules/module.modulemap").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/PrivateHeaders").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/PrivateHeaders/dummy_p.h").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Resources").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Resources/Info.plist").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/Current").isDirSymLink());
- }
-
- if (productName == "C") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/C").isFileSymLink());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Headers").isDirSymLink());
- //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Modules").isDirSymLink());
- QVERIFY(!QFileInfo2(defaultInstallRoot + "/C.framework/PkgInfo").exists());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/PrivateHeaders").isDirSymLink());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Resources").isDirSymLink());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/C").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Headers").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Headers/dummy.h").isRegularFile());
- //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Modules").isRegularDir());
- //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Modules/module.modulemap").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/PrivateHeaders").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/PrivateHeaders/dummy_p.h").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Resources").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Resources/Info.plist").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/Current").isDirSymLink());
- }
-
- if (productName == "D") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/Info.plist").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/MacOS").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/MacOS/D").isRegularFile());
- QVERIFY(!QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/PkgInfo").exists());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/Resources").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/Resources/resource.txt").isRegularFile());
- }
-
- if (productName == "E") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/Info.plist").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/MacOS").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/MacOS/E").isRegularFile());
- QVERIFY(!QFileInfo2(defaultInstallRoot + "/E.appex/Contents/PkgInfo").exists());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/Resources").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/Resources/resource.txt").isRegularFile());
- }
-
- if (productName == "F") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/Info.plist").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/MacOS").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/MacOS/F").isRegularFile());
- QVERIFY(!QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/PkgInfo").exists());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/Resources").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/Resources/resource.txt").isRegularFile());
- }
-
- if (productName == "G") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/G").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/G/ContentInfo.plist").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/G/Contents/resource.txt").isRegularFile());
- }
- } else {
- if (productName == "A") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/A").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Info.plist").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/PkgInfo").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/resource.txt").isRegularFile());
- }
-
- if (productName == "B") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/B").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Headers").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Headers/dummy.h").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Info.plist").isRegularFile());
- //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Modules").isRegularDir());
- //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Modules/module.modulemap").isRegularFile());
- QVERIFY(!QFileInfo2(defaultInstallRoot + "/B.framework/PkgInfo").exists());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/PrivateHeaders").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/PrivateHeaders/dummy_p.h").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/resource.txt").isRegularFile());
- }
-
- if (productName == "C") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/C").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Headers").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Headers/dummy.h").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Info.plist").isRegularFile());
- //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Modules").isRegularDir());
- //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Modules/module.modulemap").isRegularFile());
- QVERIFY(!QFileInfo2(defaultInstallRoot + "/C.framework/PkgInfo").exists());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/PrivateHeaders").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/PrivateHeaders/dummy_p.h").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/resource.txt").isRegularFile());
- }
-
- if (productName == "D") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/D").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Headers").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Headers/dummy.h").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Info.plist").isRegularFile());
- QVERIFY(!QFileInfo2(defaultInstallRoot + "/D.bundle/PkgInfo").exists());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/PrivateHeaders").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/PrivateHeaders/dummy_p.h").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/resource.txt").isRegularFile());
- }
-
- if (productName == "E") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/E").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Headers").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Headers/dummy.h").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Info.plist").isRegularFile());
- QVERIFY(!QFileInfo2(defaultInstallRoot + "/E.appex/PkgInfo").exists());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/PrivateHeaders").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/PrivateHeaders/dummy_p.h").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/resource.txt").isRegularFile());
- }
-
- if (productName == "F") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/F").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Headers").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Headers/dummy.h").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Info.plist").isRegularFile());
- QVERIFY(!QFileInfo2(defaultInstallRoot + "/F.xpc/PkgInfo").exists());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/PrivateHeaders").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/PrivateHeaders/dummy_p.h").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/resource.txt").isRegularFile());
- }
-
- if (productName == "G") {
- QVERIFY(QFileInfo2(defaultInstallRoot + "/G").isRegularDir());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/G/ContentInfo.plist").isRegularFile());
- QVERIFY(QFileInfo2(defaultInstallRoot + "/G/Contents/resource.txt").isRegularFile());
- }
- }
-}
-
-void TestBlackbox::bundleStructure_data()
-{
- QTest::addColumn<QString>("productName");
- QTest::addColumn<QString>("productTypeIdentifier");
- QTest::addColumn<bool>("isShallow");
-
- const auto addRows = [](bool isShallow) {
- const QString s = (isShallow ? " shallow" : "");
- QTest::newRow(("A" + s).toLatin1()) << "A" << "com.apple.product-type.application" << isShallow;
- QTest::newRow(("ABadApple" + s).toLatin1()) << "ABadApple" << "com.apple.product-type.will.never.exist.ever.guaranteed" << isShallow;
- QTest::newRow(("ABadThirdParty" + s).toLatin1()) << "ABadThirdParty" << "org.special.third.party.non.existent.product.type" << isShallow;
- QTest::newRow(("B" + s).toLatin1()) << "B" << "com.apple.product-type.framework" << isShallow;
- QTest::newRow(("C" + s).toLatin1()) << "C" << "com.apple.product-type.framework.static" << isShallow;
- QTest::newRow(("D" + s).toLatin1()) << "D" << "com.apple.product-type.bundle" << isShallow;
- QTest::newRow(("E" + s).toLatin1()) << "E" << "com.apple.product-type.app-extension" << isShallow;
- QTest::newRow(("F" + s).toLatin1()) << "F" << "com.apple.product-type.xpc-service" << isShallow;
- QTest::newRow(("G" + s).toLatin1()) << "G" << "com.apple.product-type.in-app-purchase-content" << isShallow;
- };
-
- addRows(true);
- addRows(false);
+ params.expectFailure = true;
+ params.arguments << "-k";
+ QVERIFY(runQbs(params) != 0);
+ const bool isMsvc = m_qbsStdout.contains("msvc");
+ QVERIFY2(m_qbsStdout.contains("compiling file.c"), m_qbsStdout.constData());
+ QString includePath = QDir::currentPath() + "/subdir";
+ params.environment.insert("CPLUS_INCLUDE_PATH", includePath);
+ params.environment.insert("CL", "/I" + includePath);
+ QVERIFY(runQbs(params) != 0);
+ params.command = "resolve";
+ params.expectFailure = false;
+ params.arguments.clear();
+ QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
+ QCOMPARE(m_qbsStdout.contains("compiling file.c"), isMsvc);
+ includePath = QDir::currentPath() + "/subdir2";
+ params.environment.insert("CPLUS_INCLUDE_PATH", includePath);
+ params.environment.insert("CL", "/I" + includePath);
+ QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
+ QCOMPARE(m_qbsStdout.contains("compiling file.c"), isMsvc);
+ params.environment = QProcessEnvironment::systemEnvironment();
+ QCOMPARE(runQbs(params), 0);
+ params.command = "build";
+ params.expectFailure = true;
+ QVERIFY(runQbs(params) != 0);
}
void TestBlackbox::changedFiles_data()
@@ -828,154 +609,109 @@ void TestBlackbox::dependenciesProperty()
void TestBlackbox::dependencyProfileMismatch()
{
QDir::setCurrent(testDataDir + "/dependency-profile-mismatch");
- qbs::Settings s((QString()));
- qbs::Internal::TemporaryProfile depProfile("qbs_autotests_profileMismatch", &s);
+ 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();
+ s->sync();
QbsRunParameters params(QStringList() << ("project.mainProfile:" + profileName())
<< ("project.depProfile:" + depProfile.p.name()));
params.expectFailure = true;
- QVERIFY(runQbs(params) != 0);
- QVERIFY2(m_qbsStderr.contains(profileName().toLocal8Bit() + "', which does not exist"),
+ QVERIFY2(runQbs(params) != 0, m_qbsStderr.constData());
+ QVERIFY2(m_qbsStderr.contains(profileName().toLocal8Bit())
+ && m_qbsStderr.contains("', which does not exist"),
m_qbsStderr.constData());
}
-void TestBlackbox::deploymentTarget()
-{
- if (!HostOsInfo::isMacosHost())
- QSKIP("only applies on macOS");
-
- QFETCH(QString, sdk);
- QFETCH(QString, os);
- QFETCH(QString, arch);
- QFETCH(QString, cflags);
- QFETCH(QString, lflags);
-
- QDir::setCurrent(testDataDir + "/deploymentTarget");
-
- QbsRunParameters params;
- params.arguments = QStringList()
- << "--command-echo-mode"
- << "command-line"
- << "qbs.targetOS:" + os
- << "qbs.architecture:" + arch;
-
- rmDirR(relativeBuildDir());
- int status = runQbs(params);
-
- const QStringList skippableMessages = QStringList()
- << "There is no matching SDK available for " + sdk + "."
- << "x86_64h will be mis-detected as x86_64 with Apple Clang < 6.0"
- << "clang: error: unknown argument: '-mtvos-version-min"
- << "clang: error: unknown argument: '-mtvos-simulator-version-min"
- << "clang: error: unknown argument: '-mwatchos-version-min"
- << "clang: error: unknown argument: '-mwatchos-simulator-version-min";
- if (status != 0) {
- for (const auto &message : skippableMessages) {
- if (m_qbsStderr.contains(message.toUtf8()))
- QSKIP(message.toUtf8());
- }
- }
-
- QCOMPARE(status, 0);
- QVERIFY2(m_qbsStderr.contains(cflags.toLatin1()), m_qbsStderr.constData());
- QVERIFY2(m_qbsStderr.contains(lflags.toLatin1()), m_qbsStderr.constData());
-}
-
-static qbs::Internal::Version findXcodeVersion()
-{
- QProcess process;
- process.start("pkgutil", QStringList("--pkg-info-plist=com.apple.pkg.Xcode"));
- process.waitForFinished();
-
- QDomDocument xcodeVersionDoc;
- if (xcodeVersionDoc.setContent(process.readAllStandardOutput())) {
- QDomNodeList nodes = xcodeVersionDoc.elementsByTagName(QStringLiteral("key"));
- for (int i = 0; i < nodes.count(); ++i) {
- QDomElement elem = nodes.at(i).toElement();
- if (elem.text().compare(QStringLiteral("pkg-version")) == 0) {
- return qbs::Internal::Version::fromString(
- QStringList(elem.nextSiblingElement().text().split(
- QLatin1Char('.')).mid(0, 3)).join(QLatin1Char('.')), true);
- }
- }
- }
-
- return qbs::Internal::Version();
-}
-
-void TestBlackbox::deploymentTarget_data()
-{
- static const QString macos = QStringLiteral("macos,darwin,bsd,unix");
- static const QString ios = QStringLiteral("ios,darwin,bsd,unix");
- static const QString ios_sim = QStringLiteral("ios-simulator,") + ios;
- static const QString tvos = QStringLiteral("tvos,darwin,bsd,unix");
- static const QString tvos_sim = QStringLiteral("tvos-simulator,") + tvos;
- static const QString watchos = QStringLiteral("watchos,darwin,bsd,unix");
- static const QString watchos_sim = QStringLiteral("watchos-simulator,") + watchos;
-
- QTest::addColumn<QString>("sdk");
- QTest::addColumn<QString>("os");
- QTest::addColumn<QString>("arch");
- QTest::addColumn<QString>("cflags");
- QTest::addColumn<QString>("lflags");
-
- QTest::newRow("macos x86") << "macosx" << macos << "x86"
- << "-triple i386-apple-macosx10.4"
- << "-macosx_version_min 10.4";
- QTest::newRow("macos x86_64") << "macosx" << macos << "x86_64"
- << "-triple x86_64-apple-macosx10.4"
- << "-macosx_version_min 10.4";
-
- if (findXcodeVersion() >= qbs::Internal::Version(6))
- QTest::newRow("macos x86_64h") << "macosx" << macos << "x86_64h"
- << "-triple x86_64h-apple-macosx10.12"
- << "-macosx_version_min 10.12";
-
- QTest::newRow("ios armv7a") << "iphoneos" << ios << "armv7a"
- << "-triple thumbv7-apple-ios6.0"
- << "-iphoneos_version_min 6.0";
- QTest::newRow("ios armv7s") << "iphoneos" <<ios << "armv7s"
- << "-triple thumbv7s-apple-ios7.0"
- << "-iphoneos_version_min 7.0";
- QTest::newRow("ios arm64") << "iphoneos" <<ios << "arm64"
- << "-triple arm64-apple-ios7.0"
- << "-iphoneos_version_min 7.0";
- QTest::newRow("ios-simulator x86") << "iphonesimulator" << ios_sim << "x86"
- << "-triple i386-apple-ios6.0"
- << "-ios_simulator_version_min 6.0";
- QTest::newRow("ios-simulator x86_64") << "iphonesimulator" << ios_sim << "x86_64"
- << "-triple x86_64-apple-ios7.0"
- << "-ios_simulator_version_min 7.0";
-
- QTest::newRow("tvos arm64") << "appletvos" << tvos << "arm64"
- << "-triple arm64-apple-tvos9.0"
- << "-tvos_version_min 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";
-
- QTest::newRow("watchos armv7k") << "watchos" << watchos << "armv7k"
- << "-triple thumbv7k-apple-watchos2.0"
- << "-watchos_version_min 2.0";
- QTest::newRow("watchos-simulator x86") << "watchsimulator" << watchos_sim << "x86"
- << "-triple i386-apple-watchos2.0"
- << "-watchos_simulator_version_min 2.0";
-}
-
void TestBlackbox::deprecatedProperty()
{
QDir::setCurrent(testDataDir + "/deprecated-property");
- QCOMPARE(runQbs(QStringList("-q")), 0);
+ QVERIFY(runQbs(QStringList("-q")) != 0);
QVERIFY2(m_qbsStderr.contains("deprecated-property.qbs:6:24 The property 'oldProp' is "
"deprecated and will be removed in Qbs 99.9.0."), m_qbsStderr.constData());
QVERIFY2(m_qbsStderr.contains("deprecated-property.qbs:7:28 The property 'veryOldProp' can no "
"longer be used. It was removed in Qbs 1.3.0."), m_qbsStderr.constData());
+
+
+ // TODO: Uncomment in 1.10
+// QVERIFY2(m_qbsStderr.contains("Property 'forgottenProp' was scheduled for removal in version "
+// "1.8.0, but is still present."), m_qbsStderr.constData());
+// QVERIFY2(m_qbsStderr.contains("themodule/m.qbs:22:5 Removal version for 'forgottenProp' "
+// "specified here."), m_qbsStderr.constData());
+
QVERIFY2(m_qbsStderr.count("Use newProp instead.") == 2, m_qbsStderr.constData());
QVERIFY2(m_qbsStderr.count("is deprecated") == 1, m_qbsStderr.constData());
QVERIFY2(m_qbsStderr.count("was removed") == 1, m_qbsStderr.constData());
}
+void TestBlackbox::disappearedProfile()
+{
+ QDir::setCurrent(testDataDir + "/disappeared-profile");
+ QbsRunParameters resolveParams;
+
+ // First, we need to fail, because we don't tell qbs where the module is.
+ resolveParams.expectFailure = true;
+ QVERIFY(runQbs(resolveParams) != 0);
+
+ // Now we set up a profile with all the necessary information, and qbs succeeds.
+ qbs::Settings settings(QDir::currentPath() + "/settings-dir");
+ qbs::Profile profile("p", &settings);
+ profile.setValue("m.p1", "p1 from profile");
+ profile.setValue("m.p2", "p2 from profile");
+ profile.setValue("preferences.qbsSearchPaths",
+ QStringList({QDir::currentPath() + "/modules-dir"}));
+ settings.sync();
+ resolveParams.command = "resolve";
+ resolveParams.expectFailure = false;
+ resolveParams.settingsDir = settings.baseDirectory();
+ resolveParams.profile = profile.name();
+ QCOMPARE(runQbs(resolveParams), 0);
+
+ // Now we change a property in the profile, but because we don't use the "resolve" command,
+ // the old profile contents stored in the build graph are used.
+ profile.setValue("m.p2", "p2 new from profile");
+ settings.sync();
+ QbsRunParameters buildParams;
+ buildParams.profile.clear();
+ QCOMPARE(runQbs(buildParams), 0);
+ QVERIFY2(m_qbsStdout.contains("Creating dummy1.txt with p1 from profile"),
+ m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("Creating dummy2.txt with p2 from profile"),
+ m_qbsStdout.constData());
+
+ // Now we do use the "resolve" command, so the new property value is taken into account.
+ QCOMPARE(runQbs(resolveParams), 0);
+ QCOMPARE(runQbs(buildParams), 0);
+ QVERIFY2(!m_qbsStdout.contains("Creating dummy1.txt"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("Creating dummy2.txt with p2 new from profile"),
+ m_qbsStdout.constData());
+
+ // Now we change the profile again without a "resolve" command. However, this time we
+ // force re-resolving indirectly by changing a project file. The updated property value
+ // must still not be taken into account.
+ profile.setValue("m.p1", "p1 new from profile");
+ settings.sync();
+ WAIT_FOR_NEW_TIMESTAMP();
+ QFile f(QDir::currentPath() + "/modules-dir/modules/m/m.qbs");
+ QVERIFY2(f.open(QIODevice::ReadWrite), qPrintable(f.errorString()));
+ QByteArray contents = f.readAll();
+ contents.replace("property string p1", "property string p1: 'p1 from module'");
+ f.seek(0);
+ f.write(contents);
+ f.close();
+ QCOMPARE(runQbs(buildParams), 0);
+ QVERIFY2(m_qbsStdout.contains("Resolving"), m_qbsStdout.constData());
+ QVERIFY2(!m_qbsStdout.contains("Creating dummy1.txt"), m_qbsStdout.constData());
+ QVERIFY2(!m_qbsStdout.contains("Creating dummy2.txt"), m_qbsStdout.constData());
+
+ // Now we run the "resolve" command without giving the necessary settings path to find
+ // the profile.
+ resolveParams.expectFailure = true;
+ resolveParams.settingsDir.clear();
+ resolveParams.profile.clear();
+ QVERIFY(runQbs(resolveParams) != 0);
+ QVERIFY2(m_qbsStderr.contains("profile"), m_qbsStderr.constData());
+}
+
void TestBlackbox::symlinkRemoval()
{
if (HostOsInfo::isWindowsHost())
@@ -1042,8 +778,8 @@ void TestBlackbox::versionCheck_data()
void TestBlackbox::versionScript()
{
- Settings settings((QString()));
- Profile buildProfile(profileName(), &settings);
+ const SettingsPtr s = settings();
+ Profile buildProfile(profileName(), s.get());
QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList();
if (!toolchain.contains("gcc") || targetOs() != HostOsInfo::HostOsLinux)
QSKIP("version script test only applies to Linux");
@@ -1074,6 +810,47 @@ void TestBlackbox::versionScript()
QVERIFY2(globalSymbols.contains("dummyGlobal"), allSymbols.constData());
}
+void TestBlackbox::wholeArchive()
+{
+ QDir::setCurrent(testDataDir + "/whole-archive");
+ QFETCH(QString, wholeArchiveString);
+ QFETCH(bool, ruleInvalidationExpected);
+ QFETCH(bool, dllLinkingExpected);
+ const QbsRunParameters resolveParams("resolve",
+ QStringList("-vv") << "products.dynamiclib.linkWholeArchive:" + wholeArchiveString);
+ QCOMPARE(runQbs(QbsRunParameters(resolveParams)), 0);
+ const QByteArray resolveStderr = m_qbsStderr;
+ QCOMPARE(runQbs(QbsRunParameters(QStringList({ "-p", "dynamiclib" }))), 0);
+ const bool wholeArchive = !wholeArchiveString.isEmpty();
+ const bool outdatedVisualStudio = wholeArchive && m_qbsStderr.contains("upgrade");
+ const QByteArray invalidationOutput
+ = "Value for property 'staticlib 1:cpp.linkWholeArchive' has changed.";
+ if (!outdatedVisualStudio)
+ QCOMPARE(resolveStderr.contains(invalidationOutput), ruleInvalidationExpected);
+ QCOMPARE(m_qbsStdout.contains("linking"), dllLinkingExpected && !outdatedVisualStudio);
+ QbsRunParameters buildParams(QStringList("-p"));
+ buildParams.expectFailure = !wholeArchive || outdatedVisualStudio;
+ buildParams.arguments << "app1";
+ QCOMPARE(runQbs(QbsRunParameters(buildParams)) == 0, wholeArchive && !outdatedVisualStudio);
+ buildParams.arguments.last() = "app2";
+ QCOMPARE(runQbs(QbsRunParameters(buildParams)) == 0, wholeArchive && !outdatedVisualStudio);
+ buildParams.arguments.last() = "app4";
+ QCOMPARE(runQbs(QbsRunParameters(buildParams)) == 0, wholeArchive && !outdatedVisualStudio);
+ buildParams.arguments.last() = "app3";
+ buildParams.expectFailure = true;
+ QVERIFY(runQbs(QbsRunParameters(buildParams)) != 0);
+}
+
+void TestBlackbox::wholeArchive_data()
+{
+ QTest::addColumn<QString>("wholeArchiveString");
+ QTest::addColumn<bool>("ruleInvalidationExpected");
+ QTest::addColumn<bool>("dllLinkingExpected");
+ QTest::newRow("link normally") << QString() << false << true;
+ QTest::newRow("link whole archive") << "true" << true << true;
+ QTest::newRow("link whole archive again") << "notfalse" << false << false;
+}
+
static bool symlinkExists(const QString &linkFilePath)
{
return QFileInfo(linkFilePath).isSymLink();
@@ -1120,10 +897,13 @@ void TestBlackbox::clean()
// Remove all, with a forced re-resolve in between.
// This checks that rescuable artifacts are also removed.
- QCOMPARE(runQbs(QbsRunParameters(QStringList() << "cpp.optimization:none")), 0);
+ QCOMPARE(runQbs(QbsRunParameters("resolve",
+ QStringList() << "modules.cpp.optimization:none")), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY(regularFileExists(appObjectFilePath));
QVERIFY(regularFileExists(appExeFilePath));
- QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList() << "cpp.optimization:fast")), 0);
+ QCOMPARE(runQbs(QbsRunParameters("resolve",
+ QStringList() << "modules.cpp.optimization:fast")), 0);
QVERIFY(regularFileExists(appObjectFilePath));
QVERIFY(regularFileExists(appExeFilePath));
QCOMPARE(runQbs(QbsRunParameters("clean")), 0);
@@ -1192,6 +972,9 @@ void TestBlackbox::conditionalExport()
params.expectFailure = false;
params.arguments << "project.enableExport:true";
+ params.command = "resolve";
+ QCOMPARE(runQbs(params), 0);
+ params.command = "build";
QCOMPARE(runQbs(params), 0);
}
@@ -1202,6 +985,9 @@ void TestBlackbox::conditionalFileTagger()
QCOMPARE(runQbs(params), 0);
QVERIFY(!m_qbsStdout.contains("compiling"));
params.arguments = QStringList("products.theApp.enableTagger:true");
+ params.command = "resolve";
+ QCOMPARE(runQbs(params), 0);
+ params.command = "build";
QCOMPARE(runQbs(params), 0);
QVERIFY(m_qbsStdout.contains("compiling"));
}
@@ -1215,33 +1001,6 @@ void TestBlackbox::conflictingArtifacts()
QVERIFY2(m_qbsStderr.contains("Conflicting artifacts"), m_qbsStderr.constData());
}
-void TestBlackbox::createProject()
-{
- QDir::setCurrent(testDataDir + "/create-project");
- QVERIFY(QFile::copy(SRCDIR "/../../../examples/helloworld-qt/main.cpp",
- QDir::currentPath() + "/main.cpp"));
- QbsRunParameters createParams("create-project");
- createParams.useProfile = false;
- QCOMPARE(runQbs(createParams), 0);
- createParams.expectFailure = true;
- QVERIFY(runQbs(createParams) != 0);
- QVERIFY2(m_qbsStderr.contains("already contains qbs files"), m_qbsStderr.constData());
- QCOMPARE(runQbs(), 0);
- QVERIFY2(m_qbsStdout.contains("compiling"), m_qbsStdout.constData());
-}
-
-void TestBlackbox::dbusAdaptors()
-{
- QDir::setCurrent(testDataDir + "/dbus-adaptors");
- QCOMPARE(runQbs(), 0);
-}
-
-void TestBlackbox::dbusInterfaces()
-{
- QDir::setCurrent(testDataDir + "/dbus-interfaces");
- QCOMPARE(runQbs(), 0);
-}
-
void TestBlackbox::renameDependency()
{
QDir::setCurrent(testDataDir + "/renameDependency");
@@ -1267,8 +1026,8 @@ void TestBlackbox::separateDebugInfo()
QDir::setCurrent(testDataDir + "/separate-debug-info");
QCOMPARE(runQbs(QbsRunParameters(QStringList("qbs.debugInformation:true"))), 0);
- Settings settings((QString()));
- Profile buildProfile(profileName(), &settings);
+ const SettingsPtr s = settings();
+ Profile buildProfile(profileName(), s.get());
QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList();
QStringList targetOS = buildProfile.value("qbs.targetOS").toStringList();
if (targetOS.contains("darwin") || (targetOS.isEmpty() && HostOsInfo::isMacosHost())) {
@@ -1359,44 +1118,6 @@ void TestBlackbox::separateDebugInfo()
}
}
-void TestBlackbox::track_qrc()
-{
- QDir::setCurrent(testDataDir + "/qrc");
- QCOMPARE(runQbs(), 0);
- const QString fileName = relativeExecutableFilePath("i");
- QVERIFY2(regularFileExists(fileName), qPrintable(fileName));
- QDateTime dt = QFileInfo(fileName).lastModified();
- WAIT_FOR_NEW_TIMESTAMP();
- {
- QFile f("stuff.txt");
- f.remove();
- QVERIFY(f.open(QFile::WriteOnly));
- f.write("bla");
- f.close();
- }
- QCOMPARE(runQbs(), 0);
- QVERIFY(regularFileExists(fileName));
- QVERIFY(dt < QFileInfo(fileName).lastModified());
-}
-
-void TestBlackbox::track_qobject_change()
-{
- QDir::setCurrent(testDataDir + "/trackQObjChange");
- copyFileAndUpdateTimestamp("bla_qobject.h", "bla.h");
- QCOMPARE(runQbs(), 0);
- const QString productFilePath = relativeExecutableFilePath("i");
- QVERIFY2(regularFileExists(productFilePath), qPrintable(productFilePath));
- QString moc_bla_objectFileName = relativeProductBuildDir("i") + "/.obj/"
- + inputDirHash("qt.headers") + objectFileName("/moc_bla.cpp", profileName());
- QVERIFY2(regularFileExists(moc_bla_objectFileName), qPrintable(moc_bla_objectFileName));
-
- WAIT_FOR_NEW_TIMESTAMP();
- copyFileAndUpdateTimestamp("bla_noqobject.h", "bla.h");
- QCOMPARE(runQbs(), 0);
- QVERIFY(regularFileExists(productFilePath));
- QVERIFY(!QFile(moc_bla_objectFileName).exists());
-}
-
void TestBlackbox::trackAddFile()
{
QProcess process;
@@ -1453,9 +1174,17 @@ void TestBlackbox::trackExternalProductChanges()
params.environment.insert("QBS_TEST_PULL_IN_FILE_VIA_ENV", "1");
QCOMPARE(runQbs(params), 0);
QVERIFY(!m_qbsStdout.contains("compiling main.cpp"));
- QVERIFY(m_qbsStdout.contains("compiling environmentChange.cpp"));
+ QVERIFY(!m_qbsStdout.contains("compiling environmentChange.cpp"));
QVERIFY(!m_qbsStdout.contains("compiling jsFileChange.cpp"));
QVERIFY(!m_qbsStdout.contains("compiling fileExists.cpp"));
+ params.command = "resolve";
+ QCOMPARE(runQbs(params), 0);
+ params.command = "build";
+ QCOMPARE(runQbs(params), 0);
+ QVERIFY(!m_qbsStdout.contains("compiling main.cpp"));
+ QVERIFY(m_qbsStdout.contains("compiling environmentChange.cpp"));
+ QVERIFY2(!m_qbsStdout.contains("compiling jsFileChange.cpp"), m_qbsStdout.constData());
+ QVERIFY(!m_qbsStdout.contains("compiling fileExists.cpp"));
rmDirR(relativeBuildDir());
QCOMPARE(runQbs(), 0);
@@ -1502,8 +1231,8 @@ void TestBlackbox::trackExternalProductChanges()
QVERIFY(m_qbsStdout.contains("compiling fileExists.cpp"));
rmDirR(relativeBuildDir());
- Settings s((QString()));
- const Profile profile(profileName(), &s);
+ const SettingsPtr s = settings();
+ const Profile profile(profileName(), s.get());
const QStringList toolchainTypes = profile.value("qbs.toolchain").toStringList();
if (!toolchainTypes.contains("gcc"))
QSKIP("Need GCC-like compiler to run this test");
@@ -1512,10 +1241,13 @@ void TestBlackbox::trackExternalProductChanges()
params.expectFailure = true;
QVERIFY(runQbs(params) != 0);
QVERIFY2(m_qbsStderr.contains("hiddenheaderqbs.h"), m_qbsStderr.constData());
+ params.command = "resolve";
params.environment.insert("CPLUS_INCLUDE_PATH",
QDir::toNativeSeparators(QDir::currentPath() + "/hidden"));
params.expectFailure = false;
QCOMPARE(runQbs(params), 0);
+ params.command = "build";
+ QCOMPARE(runQbs(params), 0);
}
void TestBlackbox::trackGroupConditionChange()
@@ -1526,9 +1258,11 @@ void TestBlackbox::trackGroupConditionChange()
QVERIFY(runQbs(params) != 0);
QVERIFY(m_qbsStderr.contains("jibbetnich"));
+ params.command = "resolve";
params.arguments = QStringList("project.kaputt:false");
params.expectFailure = false;
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
}
void TestBlackbox::trackRemoveFile()
@@ -1664,25 +1398,6 @@ void TestBlackbox::trackRemoveFileTag()
QCOMPARE(regularFileExists(relativeProductBuildDir("someapp") + "/main.foo"), false);
}
-void TestBlackbox::trackAddMocInclude()
-{
- QDir::setCurrent(testDataDir + "/trackAddMocInclude");
- if (QFile::exists("work"))
- rmDirR("work");
- QDir().mkdir("work");
- ccp("before", "work");
- QDir::setCurrent(testDataDir + "/trackAddMocInclude/work");
- // The build must fail because the main.moc include is missing.
- QbsRunParameters params;
- params.expectFailure = true;
- QVERIFY(runQbs(params) != 0);
-
- WAIT_FOR_NEW_TIMESTAMP();
- ccp("../after", ".");
- touch("main.cpp");
- QCOMPARE(runQbs(), 0);
-}
-
void TestBlackbox::trackAddProduct()
{
QDir::setCurrent(testDataDir + "/trackProducts");
@@ -1789,8 +1504,8 @@ void TestBlackbox::referenceErrorInExport()
void TestBlackbox::reproducibleBuild()
{
- Settings s((QString()));
- const Profile profile(profileName(), &s);
+ 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"))
QSKIP("reproducible builds only supported for gcc");
@@ -1799,8 +1514,9 @@ void TestBlackbox::reproducibleBuild()
QDir::setCurrent(testDataDir + "/reproducible-build");
QbsRunParameters params;
- params.arguments << QString("cpp.enableReproducibleBuilds:")
+ params.arguments << QString("modules.cpp.enableReproducibleBuilds:")
+ (reproducible ? "true" : "false");
+ rmDirR(relativeBuildDir());
QCOMPARE(runQbs(params), 0);
QFile object(relativeProductBuildDir("the product") + "/.obj/" + inputDirHash(".") + '/'
+ objectFileName("file1.cpp", profileName()));
@@ -1869,14 +1585,38 @@ void TestBlackbox::ruleWithNoInputs()
QVERIFY2(m_qbsStdout.contains("creating output"), m_qbsStdout.constData());
QVERIFY2(runQbs() == 0, m_qbsStderr.constData());
QVERIFY2(!m_qbsStdout.contains("creating output"), m_qbsStdout.constData());
- QbsRunParameters params(QStringList() << "theProduct.version:1");
+ QbsRunParameters params("resolve", QStringList() << "products.theProduct.version:1");
+ QVERIFY2(runQbs(params) == 0, m_qbsStderr.constData());
+ params.command = "build";
QVERIFY2(runQbs(params) == 0, m_qbsStderr.constData());
QVERIFY2(!m_qbsStdout.contains("creating output"), m_qbsStdout.constData());
+ params.command = "resolve";
params.arguments = QStringList() << "products.theProduct.version:2";
QVERIFY2(runQbs(params) == 0, m_qbsStderr.constData());
+ params.command = "build";
+ QVERIFY2(runQbs(params) == 0, m_qbsStderr.constData());
QVERIFY2(m_qbsStdout.contains("creating output"), m_qbsStdout.constData());
}
+void TestBlackbox::ruleWithNonRequiredInputs()
+{
+ QDir::setCurrent(testDataDir + "/rule-with-non-required-inputs");
+ QbsRunParameters params("build", {"products.p.enableTagger:false"});
+ QCOMPARE(runQbs(params), 0);
+ QFile outFile(relativeProductBuildDir("p") + "/output.txt");
+ QVERIFY2(outFile.open(QIODevice::ReadOnly), qPrintable(outFile.errorString()));
+ QByteArray output = outFile.readAll();
+ QCOMPARE(output, QByteArray("()"));
+ outFile.close();
+ params.command = "resolve";
+ params.arguments = QStringList({"products.p.enableTagger:true"});
+ QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(outFile.open(QIODevice::ReadOnly), qPrintable(outFile.errorString()));
+ output = outFile.readAll();
+ QCOMPARE(output, QByteArray("(a.inp,b.inp,c.inp,)"));
+}
+
void TestBlackbox::smartRelinking()
{
QDir::setCurrent(testDataDir + "/smart-relinking");
@@ -1899,8 +1639,10 @@ void TestBlackbox::smartRelinking()
// Add new private symbol.
WAIT_FOR_NEW_TIMESTAMP();
+ params.command = "resolve";
params.arguments << "products.lib.defines:PRIV2";
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData());
QVERIFY2(!m_qbsStdout.contains("linking app"), m_qbsStdout.constData());
@@ -1908,6 +1650,7 @@ void TestBlackbox::smartRelinking()
WAIT_FOR_NEW_TIMESTAMP();
params.arguments.removeLast();
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData());
QVERIFY2(!m_qbsStdout.contains("linking app"), m_qbsStdout.constData());
@@ -1915,6 +1658,7 @@ void TestBlackbox::smartRelinking()
WAIT_FOR_NEW_TIMESTAMP();
params.arguments << "products.lib.defines:PUB2";
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData());
QVERIFY2(m_qbsStdout.contains("linking app"), m_qbsStdout.constData());
@@ -1922,6 +1666,7 @@ void TestBlackbox::smartRelinking()
WAIT_FOR_NEW_TIMESTAMP();
params.arguments.removeLast();
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData());
QVERIFY2(m_qbsStdout.contains("linking app"), m_qbsStdout.constData());
@@ -1929,6 +1674,7 @@ void TestBlackbox::smartRelinking()
WAIT_FOR_NEW_TIMESTAMP();
params.arguments << "products.lib.defines:PRINTF";
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData());
QVERIFY2(strictChecking == m_qbsStdout.contains("linking app"), m_qbsStdout.constData());
@@ -1936,6 +1682,7 @@ void TestBlackbox::smartRelinking()
WAIT_FOR_NEW_TIMESTAMP();
params.arguments.removeLast();
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY2(m_qbsStdout.contains("linking lib"), m_qbsStdout.constData());
QVERIFY2(strictChecking == m_qbsStdout.contains("linking app"), m_qbsStdout.constData());
}
@@ -1986,6 +1733,7 @@ void TestBlackbox::soVersion()
params.arguments << ("modules.cpp.soVersion:" + soVersion);
const QString libFilePath = relativeProductBuildDir("mylib") + "/libmylib.so"
+ (useVersion ? ".1.2.3" : QString());
+ rmDirR(relativeBuildDir());
QCOMPARE(runQbs(params), 0);
QVERIFY2(regularFileExists(libFilePath), qPrintable(libFilePath));
QCOMPARE(soName(readElfPath, libFilePath), expectedSoName);
@@ -2037,15 +1785,17 @@ void TestBlackbox::pchChangeTracking()
{
QDir::setCurrent(testDataDir + "/pch-change-tracking");
QCOMPARE(runQbs(), 0);
- QVERIFY(m_qbsStdout.contains("compiling pch.h"));
+ QVERIFY(m_qbsStdout.contains("precompiling pch.h (cpp)"));
WAIT_FOR_NEW_TIMESTAMP();
touch("header1.h");
QCOMPARE(runQbs(), 0);
- QVERIFY(m_qbsStdout.contains("compiling pch.h"));
+ QVERIFY(m_qbsStdout.contains("precompiling pch.h (cpp)"));
+ QVERIFY(m_qbsStdout.contains("compiling header2.cpp"));
+ QVERIFY(m_qbsStdout.contains("compiling main.cpp"));
WAIT_FOR_NEW_TIMESTAMP();
touch("header2.h");
QCOMPARE(runQbs(), 0);
- QVERIFY2(!m_qbsStdout.contains("compiling pch.h"), m_qbsStdout.constData());
+ QVERIFY2(!m_qbsStdout.contains("precompiling pch.h (cpp)"), m_qbsStdout.constData());
}
void TestBlackbox::pkgConfigProbe()
@@ -2062,6 +1812,7 @@ void TestBlackbox::pkgConfigProbe()
QFETCH(QStringList, cflags);
QFETCH(QStringList, version);
+ rmDirR(relativeBuildDir());
QbsRunParameters params(QStringList() << ("project.packageBaseName:" + packageBaseName));
QCOMPARE(runQbs(params), 0);
const QString stdOut = m_qbsStdout;
@@ -2117,22 +1868,30 @@ void TestBlackbox::pkgConfigProbeSysroot()
m_qbsStdout.constData());
}
-void TestBlackbox::pluginMetaData()
+void TestBlackbox::pluginDependency()
{
- QDir::setCurrent(testDataDir + "/plugin-meta-data");
- QCOMPARE(runQbs(), 0);
- const QString appFilePath = relativeBuildDir() + "/install-root/"
- + qbs::Internal::HostOsInfo::appendExecutableSuffix("plugin-meta-data");
- QVERIFY(regularFileExists(appFilePath));
- QProcess app;
- app.start(appFilePath);
- QVERIFY(app.waitForStarted());
- QVERIFY(app.waitForFinished());
- QVERIFY2(app.exitCode() == 0, app.readAllStandardError().constData());
- WAIT_FOR_NEW_TIMESTAMP();
- touch("metadata.json");
- QCOMPARE(runQbs(), 0);
- QVERIFY2(m_qbsStdout.contains("moc"), m_qbsStdout.constData());
+ QDir::setCurrent(testDataDir + "/plugin-dependency");
+
+ // Build the plugin.
+ QCOMPARE(runQbs(QStringList{"--products", "plugin1,plugin2,plugin3,plugin4"}), 0);
+ QVERIFY(m_qbsStdout.contains("plugin1"));
+ QVERIFY(m_qbsStdout.contains("plugin2"));
+ QVERIFY(m_qbsStdout.contains("plugin3"));
+ QVERIFY(m_qbsStdout.contains("plugin4"));
+
+ // Build the app. Plugins 1 and 2 must not be linked. Plugin 3 must be linked.
+ QCOMPARE(runQbs(QStringList{"--command-echo-mode", "command-line"}), 0);
+ QByteArray output = m_qbsStdout + '\n' + m_qbsStderr;
+ QVERIFY(!output.contains("plugin1"));
+ QVERIFY(!output.contains("plugin2"));
+
+ // Check that the build dependency still works.
+ QCOMPARE(runQbs(QStringLiteral("clean")), 0);
+ QCOMPARE(runQbs(QStringList{"--products", "myapp", "--command-echo-mode", "command-line"}), 0);
+ QVERIFY(m_qbsStdout.contains("plugin1"));
+ QVERIFY(m_qbsStdout.contains("plugin2"));
+ QVERIFY(m_qbsStdout.contains("plugin3"));
+ QVERIFY(m_qbsStdout.contains("plugin4"));
}
void TestBlackbox::probeChangeTracking()
@@ -2141,6 +1900,7 @@ void TestBlackbox::probeChangeTracking()
// Product probe disabled, other probes enabled.
QbsRunParameters params;
+ params.command = "resolve";
params.arguments = QStringList("products.theProduct.runProbe:false");
QCOMPARE(runQbs(params), 0);
QVERIFY(m_qbsStdout.contains("running tlpProbe"));
@@ -2385,14 +2145,17 @@ void TestBlackbox::propertyChanges()
QVERIFY(!m_qbsStdout.contains("Making output from other output"));
// Incremental build, input property changed via command line for second product.
+ params.command = "resolve";
params.arguments << "project.projectDefines:blubb002";
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY(!m_qbsStdout.contains("linking product 1"));
QVERIFY(m_qbsStdout.contains("compiling source2.cpp"));
QVERIFY(!m_qbsStdout.contains("linking product 3"));
QVERIFY(!m_qbsStdout.contains("generated.txt"));
params.arguments.removeLast();
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY(!m_qbsStdout.contains("linking product 1"));
QVERIFY(m_qbsStdout.contains("compiling source2.cpp"));
QVERIFY(!m_qbsStdout.contains("linking product 3"));
@@ -2405,10 +2168,26 @@ void TestBlackbox::propertyChanges()
QCOMPARE(runQbs(params), 0);
QVERIFY(!m_qbsStdout.contains("linking product 1"));
QVERIFY(!m_qbsStdout.contains("linking product 2"));
+ QVERIFY(!m_qbsStdout.contains("compiling source3.cpp"));
+ QVERIFY(!m_qbsStdout.contains("generated.txt"));
+ params.environment.remove("QBS_BLACKBOX_DEFINE");
+ QCOMPARE(runQbs(params), 0);
+ QVERIFY(!m_qbsStdout.contains("linking product 1"));
+ QVERIFY(!m_qbsStdout.contains("linking product 2"));
+ QVERIFY(!m_qbsStdout.contains("compiling source3.cpp"));
+ QVERIFY(!m_qbsStdout.contains("generated.txt"));
+ QVERIFY(!m_qbsStdout.contains("Making output from input"));
+ QVERIFY(!m_qbsStdout.contains("Making output from other output"));
+ params.environment.insert("QBS_BLACKBOX_DEFINE", "newvalue");
+ QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
+ QVERIFY(!m_qbsStdout.contains("linking product 1"));
+ QVERIFY(!m_qbsStdout.contains("linking product 2"));
QVERIFY(m_qbsStdout.contains("compiling source3.cpp"));
QVERIFY(!m_qbsStdout.contains("generated.txt"));
- params.environment.clear();
+ params.environment.remove("QBS_BLACKBOX_DEFINE");
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY(!m_qbsStdout.contains("linking product 1"));
QVERIFY(!m_qbsStdout.contains("linking product 2"));
QVERIFY(m_qbsStdout.contains("compiling source3.cpp"));
@@ -2419,6 +2198,7 @@ void TestBlackbox::propertyChanges()
// Incremental build, module property changed via command line.
params.arguments << "qbs.enableDebugCode:false";
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY(m_qbsStdout.contains("compiling source1.cpp"));
QVERIFY(m_qbsStdout.contains("linking product 1.release"));
QVERIFY(m_qbsStdout.contains("compiling source2.cpp"));
@@ -2427,6 +2207,7 @@ void TestBlackbox::propertyChanges()
QVERIFY(!m_qbsStdout.contains("generated.txt"));
params.arguments.removeLast();
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY(m_qbsStdout.contains("compiling source1.cpp"));
QVERIFY(m_qbsStdout.contains("linking product 1.debug"));
QVERIFY(m_qbsStdout.contains("compiling source2.cpp"));
@@ -2443,6 +2224,7 @@ void TestBlackbox::propertyChanges()
projectFile.resize(0);
projectFile.write(contents);
projectFile.close();
+ params.command = "build";
QCOMPARE(runQbs(params), 0);
QVERIFY(!m_qbsStdout.contains("linking product 1"));
QVERIFY(m_qbsStdout.contains("linking product 2"));
@@ -2550,50 +2332,21 @@ void TestBlackbox::propertyChanges()
QVERIFY(m_qbsStdout.contains("Making output from other output"));
}
-void TestBlackbox::qobjectInObjectiveCpp()
-{
- if (!HostOsInfo::isMacosHost())
- QSKIP("only applies on macOS");
- const QString testDir = testDataDir + "/qobject-in-mm";
- QDir::setCurrent(testDir);
- QCOMPARE(runQbs(), 0);
-}
-
void TestBlackbox::qtBug51237()
{
const QString profileName = "profile-qtBug51237";
const QString propertyName = "mymodule.theProperty";
{
- Settings settings((QString()));
- Profile profile(profileName, &settings);
+ const SettingsPtr s = settings();
+ Profile profile(profileName, s.get());
profile.setValue(propertyName, QStringList());
}
QDir::setCurrent(testDataDir + "/QTBUG-51237");
QbsRunParameters params;
- params.arguments << "profile:" + profileName;
- params.useProfile = false;
+ params.profile = profileName;
QCOMPARE(runQbs(params), 0);
}
-void TestBlackbox::qtKeywords()
-{
- QDir::setCurrent(testDataDir + "/qt-keywords");
- QbsRunParameters params(QStringList("Qt.core.enableKeywords:false"));
- params.expectFailure = true;
- QVERIFY(runQbs(QbsRunParameters(params)) != 0);
- QCOMPARE(runQbs(), 0);
-}
-
-void TestBlackbox::qtScxml()
-{
- QDir::setCurrent(testDataDir + "/qtscxml");
- QCOMPARE(runQbs(), 0);
- if (m_qbsStdout.contains("QtScxml not present"))
- QSKIP("QtScxml module not present");
- QVERIFY2(m_qbsStdout.contains("state machine name: qbs_test_machine"),
- m_qbsStdout.constData());
-}
-
void TestBlackbox::dynamicMultiplexRule()
{
const QString testDir = testDataDir + "/dynamicMultiplexRule";
@@ -2682,50 +2435,69 @@ void TestBlackbox::errorInfo()
QDir::setCurrent(testDataDir + "/error-info");
QCOMPARE(runQbs(), 0);
- QbsRunParameters params;
- params.expectFailure = true;
+ QbsRunParameters resolveParams;
+ QbsRunParameters buildParams;
+ buildParams.expectFailure = true;
- params.arguments = QStringList() << "project.fail1:true";
- QVERIFY(runQbs(params) != 0);
+ resolveParams.command = "resolve";
+ resolveParams.arguments = QStringList() << "project.fail1:true";
+ QCOMPARE(runQbs(resolveParams), 0);
+ buildParams.arguments = resolveParams.arguments;
+ QVERIFY(runQbs(buildParams) != 0);
QVERIFY2(m_qbsStderr.contains("error-info.qbs:25"), m_qbsStderr);
- params.arguments = QStringList() << "project.fail2:true";
- QVERIFY(runQbs(params) != 0);
+ resolveParams.arguments = QStringList() << "project.fail2:true";
+ QCOMPARE(runQbs(resolveParams), 0);
+ buildParams.arguments = resolveParams.arguments;
+ QVERIFY(runQbs(buildParams) != 0);
QVERIFY2(m_qbsStderr.contains("error-info.qbs:37"), m_qbsStderr);
- params.arguments = QStringList() << "project.fail3:true";
- QVERIFY(runQbs(params) != 0);
+ resolveParams.arguments = QStringList() << "project.fail3:true";
+ QCOMPARE(runQbs(resolveParams), 0);
+ buildParams.arguments = resolveParams.arguments;
+ QVERIFY(runQbs(buildParams) != 0);
QVERIFY2(m_qbsStderr.contains("error-info.qbs:52"), m_qbsStderr);
- params.arguments = QStringList() << "project.fail4:true";
- QVERIFY(runQbs(params) != 0);
+ resolveParams.arguments = QStringList() << "project.fail4:true";
+ QCOMPARE(runQbs(resolveParams), 0);
+ buildParams.arguments = resolveParams.arguments;
+ QVERIFY(runQbs(buildParams) != 0);
QVERIFY2(m_qbsStderr.contains("error-info.qbs:67"), m_qbsStderr);
- params.arguments = QStringList() << "project.fail5:true";
- QVERIFY(runQbs(params) != 0);
+ resolveParams.arguments = QStringList() << "project.fail5:true";
+ QCOMPARE(runQbs(resolveParams), 0);
+ buildParams.arguments = resolveParams.arguments;
+ QVERIFY(runQbs(buildParams) != 0);
QVERIFY2(m_qbsStderr.contains("helper.js:4"), m_qbsStderr);
- params.arguments = QStringList() << "project.fail6:true";
- QVERIFY(runQbs(params) != 0);
+ resolveParams.arguments = QStringList() << "project.fail6:true";
+ QCOMPARE(runQbs(resolveParams), 0);
+ buildParams.arguments = resolveParams.arguments;
+ QVERIFY(runQbs(buildParams) != 0);
QVERIFY2(m_qbsStderr.contains("helper.js:8"), m_qbsStderr);
- params.arguments = QStringList() << "project.fail7:true";
- QVERIFY(runQbs(params) != 0);
+ resolveParams.arguments = QStringList() << "project.fail7:true";
+ QCOMPARE(runQbs(resolveParams), 0);
+ buildParams.arguments = resolveParams.arguments;
+ QVERIFY(runQbs(buildParams) != 0);
QVERIFY2(m_qbsStderr.contains("JavaScriptCommand.sourceCode"), m_qbsStderr);
QVERIFY2(m_qbsStderr.contains("error-info.qbs:58"), m_qbsStderr);
}
void TestBlackbox::escapedLinkerFlags()
{
- Settings settings((QString()));
- const Profile buildProfile(profileName(), &settings);
+ 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)
QSKIP("escaped linker flags test only applies with gcc and GNU ld");
QDir::setCurrent(testDataDir + "/escaped-linker-flags");
QbsRunParameters params(QStringList("products.app.escapeLinkerFlags:false"));
QCOMPARE(runQbs(params), 0);
+ params.command = "resolve";
params.arguments = QStringList() << "products.app.escapeLinkerFlags:true";
+ QCOMPARE(runQbs(params), 0);
+ params.command = "build";
params.expectFailure = true;
QVERIFY(runQbs(params) != 0);
QVERIFY2(m_qbsStderr.contains("Encountered escaped linker flag"), m_qbsStderr.constData());
@@ -2733,8 +2505,8 @@ void TestBlackbox::escapedLinkerFlags()
void TestBlackbox::systemRunPaths()
{
- Settings settings((QString()));
- const Profile buildProfile(profileName(), &settings);
+ const SettingsPtr s = settings();
+ const Profile buildProfile(profileName(), s.get());
switch (targetOs()) {
case HostOsInfo::HostOsLinux:
case HostOsInfo::HostOsMacos:
@@ -2749,6 +2521,7 @@ void TestBlackbox::systemRunPaths()
QSKIP("ldd not found");
QDir::setCurrent(testDataDir + "/system-run-paths");
QFETCH(bool, setRunPaths);
+ rmDirR(relativeBuildDir());
QbsRunParameters params;
params.arguments << QString("project.setRunPaths:") + (setRunPaths ? "true" : "false");
QCOMPARE(runQbs(params), 0);
@@ -2780,8 +2553,16 @@ void TestBlackbox::systemRunPaths_data()
void TestBlackbox::exportRule()
{
QDir::setCurrent(testDataDir + "/export-rule");
- QbsRunParameters params;
+ QbsRunParameters params(QStringList{"modules.blubber.enableTagger:false"});
+ params.expectFailure = true;
+ QVERIFY(runQbs(params) != 0);
+ params.command = "resolve";
+ params.arguments = QStringList{"modules.blubber.enableTagger:true"};
+ params.expectFailure = false;
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("Creating C++ source file"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("compiling myapp.cpp"), m_qbsStdout.constData());
}
void TestBlackbox::exportToOutsideSearchPath()
@@ -2883,6 +2664,16 @@ void TestBlackbox::installPackage()
}
}
+void TestBlackbox::installRootFromProjectFile()
+{
+ QDir::setCurrent(testDataDir + "/install-root-from-project-file");
+ const QString installRoot = QDir::currentPath() + '/' + relativeBuildDir()
+ + "/my-install-root/";
+ QCOMPARE(runQbs(QbsRunParameters(QStringList("products.p.installRoot:" + installRoot))), 0);
+ const QString installedFile = installRoot + "/install-prefix/install-dir/file.txt";
+ QVERIFY2(QFile::exists(installedFile), qPrintable(installedFile));
+}
+
void TestBlackbox::installable()
{
QDir::setCurrent(testDataDir + "/installable");
@@ -2945,6 +2736,7 @@ void TestBlackbox::invalidLibraryNames_data()
void TestBlackbox::invalidExtensionInstantiation()
{
+ rmDirR(relativeBuildDir());
QDir::setCurrent(testDataDir + "/invalid-extension-instantiation");
QbsRunParameters params;
params.expectFailure = true;
@@ -2981,16 +2773,15 @@ void TestBlackbox::cli()
findCli(&status);
QCOMPARE(status, 0);
- Settings s((QString()));
- Profile p("qbs_autotests-cli", &s);
+ const SettingsPtr s = settings();
+ Profile p("qbs_autotests-cli", s.get());
const QStringList toolchain = p.value("qbs.toolchain").toStringList();
if (!p.exists() || !(toolchain.contains("dotnet") || toolchain.contains("mono")))
QSKIP("No suitable Common Language Infrastructure test profile");
QDir::setCurrent(testDataDir + "/cli");
- QbsRunParameters params(QStringList() << "-f" << "dotnettest.qbs"
- << "profile:" + p.name());
- params.useProfile = false;
+ QbsRunParameters params(QStringList() << "-f" << "dotnettest.qbs");
+ params.profile = p.name();
status = runQbs(params);
if (p.value("cli.toolchainInstallPath").toString().isEmpty()
@@ -3000,41 +2791,29 @@ void TestBlackbox::cli()
QCOMPARE(status, 0);
rmDirR(relativeBuildDir());
- QbsRunParameters params2(QStringList() << "-f" << "fshello.qbs"
- << "profile:" + p.name());
- params2.useProfile = false;
+ QbsRunParameters params2(QStringList() << "-f" << "fshello.qbs");
+ params2.profile = p.name();
QCOMPARE(runQbs(params2), 0);
rmDirR(relativeBuildDir());
}
-void TestBlackbox::combinedMoc()
-{
- QDir::setCurrent(testDataDir + "/combined-moc");
- QCOMPARE(runQbs(), 0);
- QVERIFY(m_qbsStdout.contains("compiling moc_theobject.cpp"));
- QVERIFY(!m_qbsStdout.contains("creating amalgamated_moc_theapp.cpp"));
- QVERIFY(!m_qbsStdout.contains("compiling amalgamated_moc_theapp.cpp"));
- QbsRunParameters params(QStringList("Qt.core.combineMocOutput:true"));
- QCOMPARE(runQbs(params), 0);
- QVERIFY(!m_qbsStdout.contains("compiling moc_theobject.cpp"));
- QVERIFY(m_qbsStdout.contains("creating amalgamated_moc_theapp.cpp"));
- QVERIFY(m_qbsStdout.contains("compiling amalgamated_moc_theapp.cpp"));
-}
-
void TestBlackbox::combinedSources()
{
QDir::setCurrent(testDataDir + "/combined-sources");
- QbsRunParameters params(QStringList("cpp.combineCxxSources:false"));
+ QbsRunParameters params(QStringList("modules.cpp.combineCxxSources:false"));
QCOMPARE(runQbs(params), 0);
QVERIFY(m_qbsStdout.contains("compiling main.cpp"));
QVERIFY(m_qbsStdout.contains("compiling combinable.cpp"));
QVERIFY(m_qbsStdout.contains("compiling uncombinable.cpp"));
QVERIFY(!m_qbsStdout.contains("compiling amalgamated_theapp.cpp"));
- params.arguments = QStringList("cpp.combineCxxSources:true");
+ params.arguments = QStringList("modules.cpp.combineCxxSources:true");
+ params.command = "resolve";
+ QCOMPARE(runQbs(params), 0);
WAIT_FOR_NEW_TIMESTAMP();
touch("combinable.cpp");
touch("main.cpp");
touch("uncombinable.cpp");
+ params.command = "build";
QCOMPARE(runQbs(params), 0);
QVERIFY(!m_qbsStdout.contains("compiling main.cpp"));
QVERIFY(!m_qbsStdout.contains("compiling combinable.cpp"));
@@ -3075,7 +2854,7 @@ void TestBlackbox::jsExtensionsFileInfo()
QVERIFY(output.exists());
QVERIFY(output.open(QIODevice::ReadOnly));
const QList<QByteArray> lines = output.readAll().trimmed().split('\n');
- QCOMPARE(lines.count(), 23);
+ QCOMPARE(lines.count(), 24);
int i = 0;
QCOMPARE(lines.at(i++).trimmed().constData(), "blubb");
QCOMPARE(lines.at(i++).trimmed().constData(), "blubb.tar");
@@ -3089,6 +2868,7 @@ void TestBlackbox::jsExtensionsFileInfo()
QCOMPARE(lines.at(i++).trimmed().constData(), "false");
QCOMPARE(lines.at(i++).trimmed().constData(), "false");
QCOMPARE(lines.at(i++).trimmed().constData(), "/tmp/blubb.tar.gz");
+ QCOMPARE(lines.at(i++).trimmed().constData(), "/tmp/blubb.tar.gz");
QCOMPARE(lines.at(i++).trimmed().constData(), "/tmp");
QCOMPARE(lines.at(i++).trimmed().constData(), "/tmp");
QCOMPARE(lines.at(i++).trimmed().constData(), "/");
@@ -3105,8 +2885,7 @@ void TestBlackbox::jsExtensionsFileInfo()
void TestBlackbox::jsExtensionsProcess()
{
QDir::setCurrent(testDataDir + "/jsextensions-process");
- QbsRunParameters params(QStringList() << "-f" << "process.qbs" << "project.qbsFilePath:"
- + qbsExecutableFilePath);
+ QbsRunParameters params(QStringList() << "-f" << "process.qbs");
QCOMPARE(runQbs(params), 0);
QFile output("output.txt");
QVERIFY(output.exists());
@@ -3189,6 +2968,47 @@ void TestBlackbox::ld()
QCOMPARE(runQbs(), 0);
}
+void TestBlackbox::symbolLinkMode()
+{
+ if (!HostOsInfo::isAnyUnixHost())
+ QSKIP("only applies on Unix");
+
+ QDir::setCurrent(testDataDir + "/symbolLinkMode");
+
+ QbsRunParameters params;
+
+ rmDirR(relativeBuildDir());
+ params.command = "run";
+ params.arguments = QStringList() << "-p" << "driver"
+ << "project.shouldInstallLibrary:true";
+ QCOMPARE(runQbs(params), 0);
+ QVERIFY2(m_qbsStdout.contains("somefunction existed and it returned 42"),
+ m_qbsStdout.constData());
+
+ rmDirR(relativeBuildDir());
+ params.command = "run";
+ params.arguments = QStringList() << "-p" << "driver"
+ << "project.shouldInstallLibrary:false";
+ QCOMPARE(runQbs(params), 0);
+ QVERIFY2(m_qbsStdout.contains("somefunction did not exist"), m_qbsStdout.constData());
+
+ rmDirR(relativeBuildDir());
+ params.command = "run";
+ params.arguments = QStringList() << "-p" << "driver"
+ << "project.lazy:false";
+ QCOMPARE(runQbs(params), 0);
+ QVERIFY2(m_qbsStdout.contains("Lib was loaded!\nmeow\n"), m_qbsStdout.constData());
+
+ if (HostOsInfo::isMacosHost()) {
+ rmDirR(relativeBuildDir());
+ params.command = "run";
+ params.arguments = QStringList() << "-p" << "driver"
+ << "project.lazy:true";
+ QCOMPARE(runQbs(params), 0);
+ QVERIFY2(m_qbsStdout.contains("meow\nLib was loaded!\n"), m_qbsStdout.constData());
+ }
+}
+
void TestBlackbox::linkerMode()
{
if (!HostOsInfo::isAnyUnixHost())
@@ -3265,18 +3085,21 @@ void TestBlackbox::lexyacc()
QVERIFY(runQbs(params) != 0);
params.expectFailure = false;
- params.arguments << (QStringList() << "lex_yacc.uniqueSymbolPrefix:true");
+ params.command = "resolve";
+ params.arguments << (QStringList() << "modules.lex_yacc.uniqueSymbolPrefix:true");
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY2(!m_qbsStderr.contains("whatever"), m_qbsStderr.constData());
- params.arguments << "lex_yacc.enableCompilerWarnings:true";
+ params.arguments << "modules.lex_yacc.enableCompilerWarnings:true";
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY2(m_qbsStderr.contains("whatever"), m_qbsStderr.constData());
}
void TestBlackbox::linkerScripts()
{
- Settings settings((QString()));
- Profile buildProfile(profileName(), &settings);
+ const SettingsPtr s = settings();
+ Profile buildProfile(profileName(), s.get());
QStringList toolchain = buildProfile.value("qbs.toolchain").toStringList();
if (!toolchain.contains("gcc") || targetOs() != HostOsInfo::HostOsLinux)
QSKIP("linker script test only applies to Linux ");
@@ -3333,45 +3156,12 @@ void TestBlackbox::requireDeprecated()
{
QDir::setCurrent(testDataDir + "/require-deprecated");
QCOMPARE(runQbs(), 0);
- // TODO: Revert conditions in 1.9
- QVERIFY2(!m_qbsStderr.contains("loadExtension() function is deprecated"),
+ QVERIFY2(m_qbsStderr.contains("loadExtension() function is deprecated"),
m_qbsStderr.constData());
- QVERIFY2(!m_qbsStderr.contains("loadFile() function is deprecated"),
+ QVERIFY2(m_qbsStderr.contains("loadFile() function is deprecated"),
m_qbsStderr.constData());
}
-void TestBlackbox::mixedBuildVariants()
-{
- QDir::setCurrent(testDataDir + "/mixed-build-variants");
- Settings settings((QString()));
- Profile profile(profileName(), &settings);
- if (profile.value("qbs.toolchain").toStringList().contains("msvc")) {
- QbsRunParameters params;
- params.arguments << "qbs.buildVariant:debug";
- params.expectFailure = true;
- QVERIFY(runQbs(params) != 0);
- QVERIFY2(m_qbsStderr.contains("not allowed"), m_qbsStderr.constData());
- } else if (!profile.value("Qt.core.availableBuildVariants").toStringList().contains("release")) {
- QbsRunParameters params;
- params.expectFailure = true;
- QVERIFY(runQbs(params) != 0);
- QVERIFY2(m_qbsStderr.contains("not supported"), m_qbsStderr.constData());
- } else {
- QCOMPARE(runQbs(), 0);
- }
-}
-
-void TestBlackbox::mocFlags()
-{
- QDir::setCurrent(testDataDir + "/moc-flags");
- QCOMPARE(runQbs(), 0);
- WAIT_FOR_NEW_TIMESTAMP();
- QbsRunParameters params;
- params.expectFailure = true;
- params.arguments << "Qt.core.mocFlags:-E";
- QVERIFY(runQbs(params) != 0);
-}
-
void TestBlackbox::multipleChanges()
{
QDir::setCurrent(testDataDir + "/multiple-changes");
@@ -3379,7 +3169,8 @@ void TestBlackbox::multipleChanges()
QFile newFile("test.blubb");
QVERIFY(newFile.open(QIODevice::WriteOnly));
newFile.close();
- QCOMPARE(runQbs(QStringList() << "project.prop:true"), 0);
+ QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList() << "project.prop:true")), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY(m_qbsStdout.contains("prop: true"));
}
@@ -3404,8 +3195,9 @@ void TestBlackbox::newOutputArtifact()
QVERIFY(regularFileExists(relativeBuildDir() + "/install-root/output_98.out"));
const QString the100thArtifact = relativeBuildDir() + "/install-root/output_99.out";
QVERIFY(!regularFileExists(the100thArtifact));
- QbsRunParameters params(QStringList() << "products.theProduct.artifactCount:100");
+ QbsRunParameters params("resolve", QStringList() << "products.theProduct.artifactCount:100");
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY(regularFileExists(the100thArtifact));
}
@@ -3434,7 +3226,7 @@ void TestBlackbox::nonDefaultProduct()
QVERIFY2(QFile::exists(nonDefaultAppExe), qPrintable(nonDefaultAppExe));
}
-static void switchProfileContents(qbs::Profile &p, Settings *s, bool on)
+static void switchProfileContents(qbs::Profile &p, qbs::Settings *s, bool on)
{
const QString scalarKey = "leaf.scalarProp";
const QString listKey = "leaf.listProp";
@@ -3464,23 +3256,26 @@ static void switchFileContents(QFile &f, bool on)
void TestBlackbox::propertyPrecedence()
{
QDir::setCurrent(testDataDir + "/property-precedence");
- qbs::Settings s((QString()));
- qbs::Internal::TemporaryProfile profile("qbs_autotests_propPrecedence", &s);
+ const SettingsPtr s = settings();
+ qbs::Internal::TemporaryProfile profile("qbs_autotests_propPrecedence", s.get());
profile.p.setValue("qbs.architecture", "x86"); // Profiles must not be empty...
- s.sync();
- const QStringList args = QStringList() << "-f" << "property-precedence.qbs"
- << ("profile:" + profile.p.name());
+ s->sync();
+ const QStringList args = QStringList() << "-f" << "property-precedence.qbs";
QbsRunParameters params(args);
- params.useProfile = false;
+ params.profile = profile.p.name();
+ QbsRunParameters resolveParams = params;
+ resolveParams.command = "resolve";
// Case 1: [cmdline=0,prod=0,export=0,nonleaf=0,profile=0]
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: leaf\n")
&& m_qbsStdout.contains("list prop: [\"leaf\"]\n"),
m_qbsStdout.constData());
+ params.arguments.clear();
// Case 2: [cmdline=0,prod=0,export=0,nonleaf=0,profile=1]
- switchProfileContents(profile.p, &s, true);
+ switchProfileContents(profile.p, s.get(), true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: profile\n")
&& m_qbsStdout.contains("list prop: [\"profile\"]\n"),
@@ -3489,15 +3284,17 @@ void TestBlackbox::propertyPrecedence()
// Case 3: [cmdline=0,prod=0,export=0,nonleaf=1,profile=0]
QFile nonleafFile("modules/nonleaf/nonleaf.qbs");
QVERIFY2(nonleafFile.open(QIODevice::ReadWrite), qPrintable(nonleafFile.errorString()));
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: nonleaf\n")
&& m_qbsStdout.contains("list prop: [\"nonleaf\",\"leaf\"]\n"),
m_qbsStdout.constData());
// Case 4: [cmdline=0,prod=0,export=0,nonleaf=1,profile=1]
- switchProfileContents(profile.p, &s, true);
+ switchProfileContents(profile.p, s.get(), true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: nonleaf\n")
&& m_qbsStdout.contains("list prop: [\"nonleaf\",\"profile\"]\n"),
@@ -3506,31 +3303,35 @@ void TestBlackbox::propertyPrecedence()
// Case 5: [cmdline=0,prod=0,export=1,nonleaf=0,profile=0]
QFile depFile("dep.qbs");
QVERIFY2(depFile.open(QIODevice::ReadWrite), qPrintable(depFile.errorString()));
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, false);
switchFileContents(depFile, true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: export\n")
&& m_qbsStdout.contains("list prop: [\"export\",\"leaf\"]\n"),
m_qbsStdout.constData());
// Case 6: [cmdline=0,prod=0,export=1,nonleaf=0,profile=1]
- switchProfileContents(profile.p, &s, true);
+ switchProfileContents(profile.p, s.get(), true);
+ QCOMPARE(runQbs(resolveParams), 0);
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, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: export\n")
&& m_qbsStdout.contains("list prop: [\"export\",\"nonleaf\",\"leaf\"]\n"),
m_qbsStdout.constData());
// Case 8: [cmdline=0,prod=0,export=1,nonleaf=1,profile=1]
- switchProfileContents(profile.p, &s, true);
+ switchProfileContents(profile.p, s.get(), true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: export\n")
&& m_qbsStdout.contains("list prop: [\"export\",\"nonleaf\",\"profile\"]\n"),
@@ -3539,63 +3340,71 @@ void TestBlackbox::propertyPrecedence()
// Case 9: [cmdline=0,prod=1,export=0,nonleaf=0,profile=0]
QFile productFile("property-precedence.qbs");
QVERIFY2(productFile.open(QIODevice::ReadWrite), qPrintable(productFile.errorString()));
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, false);
switchFileContents(depFile, false);
switchFileContents(productFile, true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"leaf\"]\n"),
m_qbsStdout.constData());
// Case 10: [cmdline=0,prod=1,export=0,nonleaf=0,profile=1]
- switchProfileContents(profile.p, &s, true);
+ switchProfileContents(profile.p, s.get(), true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"profile\"]\n"),
m_qbsStdout.constData());
// Case 11: [cmdline=0,prod=1,export=0,nonleaf=1,profile=0]
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"nonleaf\",\"leaf\"]\n"),
m_qbsStdout.constData());
// Case 12: [cmdline=0,prod=1,export=0,nonleaf=1,profile=1]
- switchProfileContents(profile.p, &s, true);
+ switchProfileContents(profile.p, s.get(), true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"nonleaf\",\"profile\"]\n"),
m_qbsStdout.constData());
// Case 13: [cmdline=0,prod=1,export=1,nonleaf=0,profile=0]
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, false);
switchFileContents(depFile, true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"export\",\"leaf\"]\n"),
m_qbsStdout.constData());
// Case 14: [cmdline=0,prod=1,export=1,nonleaf=0,profile=1]
- switchProfileContents(profile.p, &s, true);
+ switchProfileContents(profile.p, s.get(), true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"export\",\"profile\"]\n"),
m_qbsStdout.constData());
// Case 15: [cmdline=0,prod=1,export=1,nonleaf=1,profile=0]
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"export\",\"nonleaf\",\"leaf\"]\n"),
m_qbsStdout.constData());
// Case 16: [cmdline=0,prod=1,export=1,nonleaf=1,profile=1]
- switchProfileContents(profile.p, &s, true);
+ switchProfileContents(profile.p, s.get(), true);
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: product\n")
&& m_qbsStdout.contains("list prop: [\"product\",\"export\",\"nonleaf\",\"profile\"]\n"),
@@ -3603,166 +3412,164 @@ void TestBlackbox::propertyPrecedence()
// Command line properties wipe everything, including lists.
// Case 17: [cmdline=1,prod=0,export=0,nonleaf=0,profile=0]
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, false);
switchFileContents(depFile, false);
switchFileContents(productFile, false);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 18: [cmdline=1,prod=0,export=0,nonleaf=0,profile=1]
- switchProfileContents(profile.p, &s, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ switchProfileContents(profile.p, s.get(), true);
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 19: [cmdline=1,prod=0,export=0,nonleaf=1,profile=0]
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 20: [cmdline=1,prod=0,export=0,nonleaf=1,profile=1]
- switchProfileContents(profile.p, &s, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ switchProfileContents(profile.p, s.get(), true);
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 21: [cmdline=1,prod=0,export=1,nonleaf=0,profile=0]
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, false);
switchFileContents(depFile, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 22: [cmdline=1,prod=0,export=1,nonleaf=0,profile=1]
- switchProfileContents(profile.p, &s, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ switchProfileContents(profile.p, s.get(), true);
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 23: [cmdline=1,prod=0,export=1,nonleaf=1,profile=0]
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 24: [cmdline=1,prod=0,export=1,nonleaf=1,profile=1]
- switchProfileContents(profile.p, &s, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ switchProfileContents(profile.p, s.get(), true);
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 25: [cmdline=1,prod=1,export=0,nonleaf=0,profile=0]
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, false);
switchFileContents(depFile, false);
switchFileContents(productFile, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 26: [cmdline=1,prod=1,export=0,nonleaf=0,profile=1]
- switchProfileContents(profile.p, &s, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ switchProfileContents(profile.p, s.get(), true);
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 27: [cmdline=1,prod=1,export=0,nonleaf=1,profile=0]
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 28: [cmdline=1,prod=1,export=0,nonleaf=1,profile=1]
- switchProfileContents(profile.p, &s, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ switchProfileContents(profile.p, s.get(), true);
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 29: [cmdline=1,prod=1,export=1,nonleaf=0,profile=0]
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, false);
switchFileContents(depFile, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 30: [cmdline=1,prod=1,export=1,nonleaf=0,profile=1]
- switchProfileContents(profile.p, &s, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ switchProfileContents(profile.p, s.get(), true);
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 31: [cmdline=1,prod=1,export=1,nonleaf=1,profile=0]
- switchProfileContents(profile.p, &s, false);
+ switchProfileContents(profile.p, s.get(), false);
switchFileContents(nonleafFile, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
// Case 32: [cmdline=1,prod=1,export=1,nonleaf=1,profile=1]
- switchProfileContents(profile.p, &s, true);
- params.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ switchProfileContents(profile.p, s.get(), true);
+ resolveParams.arguments << "modules.leaf.scalarProp:cmdline" << "modules.leaf.listProp:cmdline";
+ QCOMPARE(runQbs(resolveParams), 0);
QCOMPARE(runQbs(params), 0);
QVERIFY2(m_qbsStdout.contains("scalar prop: cmdline\n")
&& m_qbsStdout.contains("list prop: [\"cmdline\"]\n"),
m_qbsStdout.constData());
}
-void TestBlackbox::qmlDebugging()
-{
- QDir::setCurrent(testDataDir + "/qml-debugging");
- QCOMPARE(runQbs(), 0);
- Settings settings((QString()));
- Profile profile(profileName(), &settings);
- if (!profile.value("qbs.toolchain").toStringList().contains("gcc"))
- return;
- QProcess nm;
- nm.start("nm", QStringList(relativeExecutableFilePath("debuggable-app")));
- if (nm.waitForStarted()) { // Let's ignore hosts without nm.
- QVERIFY2(nm.waitForFinished(), qPrintable(nm.errorString()));
- QVERIFY2(nm.exitCode() == 0, nm.readAllStandardError().constData());
- const QByteArray output = nm.readAllStandardOutput();
- QVERIFY2(output.toLower().contains("debugginghelper"), output.constData());
- }
-}
-
void TestBlackbox::productDependenciesByType()
{
QDir::setCurrent(testDataDir + "/product-dependencies-by-type");
@@ -3869,16 +3676,20 @@ void TestBlackbox::radAfterIncompleteBuild()
void TestBlackbox::subProfileChangeTracking()
{
QDir::setCurrent(testDataDir + "/subprofile-change-tracking");
- qbs::Settings settings((QString()));
- qbs::Internal::TemporaryProfile subProfile("qbs-autotests-subprofile", &settings);
+ const SettingsPtr s = settings();
+ qbs::Internal::TemporaryProfile subProfile("qbs-autotests-subprofile", s.get());
subProfile.p.setValue("baseProfile", profileName());
subProfile.p.setValue("cpp.includePaths", QStringList("/tmp/include1"));
- settings.sync();
+ s->sync();
QCOMPARE(runQbs(), 0);
subProfile.p.setValue("cpp.includePaths", QStringList("/tmp/include2"));
- settings.sync();
- QCOMPARE(runQbs(), 0);
+ s->sync();
+ QbsRunParameters params;
+ params.command = "resolve";
+ QCOMPARE(runQbs(params), 0);
+ params.command = "build";
+ QCOMPARE(runQbs(params), 0);
QVERIFY(!m_qbsStdout.contains("main1.cpp"));
QVERIFY(m_qbsStdout.contains("main2.cpp"));
}
@@ -3888,11 +3699,13 @@ void TestBlackbox::successiveChanges()
QDir::setCurrent(testDataDir + "/successive-changes");
QCOMPARE(runQbs(), 0);
- QbsRunParameters params(QStringList() << "theProduct.type:output,blubb");
+ QbsRunParameters params("resolve", QStringList() << "products.theProduct.type:output,blubb");
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
params.arguments << "project.version:2";
QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
QFile output(relativeProductBuildDir("theProduct") + "/output.out");
QVERIFY2(output.open(QIODevice::ReadOnly), qPrintable(output.errorString()));
const QByteArray version = output.readAll();
@@ -3907,8 +3720,9 @@ void TestBlackbox::installedApp()
QVERIFY(regularFileExists(defaultInstallRoot
+ HostOsInfo::appendExecutableSuffix(QLatin1String("/usr/bin/installedApp"))));
- QCOMPARE(runQbs(QbsRunParameters(QStringList("qbs.installRoot:" + testDataDir
- + "/installed-app"))), 0);
+ QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("qbs.installRoot:" + testDataDir
+ + "/installed-app"))), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY(regularFileExists(testDataDir
+ HostOsInfo::appendExecutableSuffix("/installed-app/usr/bin/installedApp")));
@@ -3916,7 +3730,8 @@ void TestBlackbox::installedApp()
QVERIFY(addedFile.open(QIODevice::WriteOnly));
addedFile.close();
QVERIFY(addedFile.exists());
- QCOMPARE(runQbs(QbsRunParameters(QStringList("--clean-install-root"))), 0);
+ QCOMPARE(runQbs(QbsRunParameters("resolve")), 0);
+ QCOMPARE(runQbs(QbsRunParameters(QStringList() << "--clean-install-root")), 0);
QVERIFY(regularFileExists(defaultInstallRoot
+ HostOsInfo::appendExecutableSuffix(QLatin1String("/usr/bin/installedApp"))));
QVERIFY(regularFileExists(defaultInstallRoot + QLatin1String("/usr/src/main.cpp")));
@@ -3956,18 +3771,18 @@ void TestBlackbox::installedApp()
QVERIFY(regularFileExists(defaultInstallRoot + QLatin1String("/usr/local/source/main.cpp")));
// Check whether changing install parameters on the command line causes re-installation.
- QbsRunParameters(QStringList("qbs.installRoot:" + relativeBuildDir() + "/blubb"));
- QCOMPARE(runQbs(QbsRunParameters(QStringList("qbs.installRoot:" + relativeBuildDir()
+ QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("qbs.installRoot:" + relativeBuildDir()
+ "/blubb"))), 0);
+ QCOMPARE(runQbs(), 0);
QVERIFY(regularFileExists(relativeBuildDir() + "/blubb/usr/local/source/main.cpp"));
// Check --no-install
rmDirR(relativeBuildDir());
- QCOMPARE(runQbs(QbsRunParameters(QStringList("--no-install"))), 0);
+ QCOMPARE(runQbs(QbsRunParameters(QStringList() << "--no-install")), 0);
QCOMPARE(QDir(defaultInstallRoot).entryList(QDir::NoDotAndDotDot).count(), 0);
// Check --no-build (with and without an existing build graph)
- QbsRunParameters params("install", QStringList("--no-build"));
+ QbsRunParameters params("install", QStringList() << "--no-build");
QCOMPARE(runQbs(params), 0);
rmDirR(relativeBuildDir());
params.expectFailure = true;
@@ -3997,7 +3812,7 @@ void TestBlackbox::installedSourceFiles()
void TestBlackbox::toolLookup()
{
QbsRunParameters params(QLatin1String("setup-toolchains"), QStringList("--help"));
- params.useProfile = false;
+ params.profile.clear();
QCOMPARE(runQbs(params), 0);
}
@@ -4018,6 +3833,7 @@ void TestBlackbox::checkProjectFilePath()
QDir::setCurrent(testDataDir + "/project_filepath_check");
QbsRunParameters params(QStringList("-f") << "project1.qbs");
QCOMPARE(runQbs(params), 0);
+ QVERIFY2(m_qbsStdout.contains("main.cpp"), m_qbsStdout.constData());
QCOMPARE(runQbs(params), 0);
params.arguments = QStringList("-f") << "project2.qbs";
@@ -4025,16 +3841,19 @@ void TestBlackbox::checkProjectFilePath()
QVERIFY(runQbs(params) != 0);
QVERIFY(m_qbsStderr.contains("project file"));
- params.arguments = QStringList("-f") << "project2.qbs" << "--force";
+ params.arguments = QStringList("-f") << "project2.qbs";
+ params.command = "resolve";
params.expectFailure = false;
QCOMPARE(runQbs(params), 0);
- QVERIFY(m_qbsStderr.contains("project file"));
+ params.command = "build";
+ QCOMPARE(runQbs(params), 0);
+ QVERIFY2(m_qbsStdout.contains("main2.cpp"), m_qbsStdout.constData());
}
class TemporaryDefaultProfileRemover
{
public:
- TemporaryDefaultProfileRemover(Settings *settings)
+ TemporaryDefaultProfileRemover(qbs::Settings *settings)
: m_settings(settings), m_defaultProfile(settings->defaultProfile())
{
m_settings->remove(QLatin1String("defaultProfile"));
@@ -4047,18 +3866,27 @@ public:
}
private:
- Settings *m_settings;
+ qbs::Settings *m_settings;
const QString m_defaultProfile;
};
void TestBlackbox::assembly()
{
- Settings settings((QString()));
- Profile profile(profileName(), &settings);
- bool haveGcc = profile.value("qbs.toolchain").toStringList().contains("gcc");
- bool haveMSVC = profile.value("qbs.toolchain").toStringList().contains("msvc");
QDir::setCurrent(testDataDir + "/assembly");
QVERIFY(runQbs() == 0);
+
+ const QVariantMap properties = ([&]() {
+ QFile propertiesFile(relativeProductBuildDir("assembly") + "/properties.json");
+ if (propertiesFile.open(QIODevice::ReadOnly))
+ return QJsonDocument::fromJson(propertiesFile.readAll()).toVariant().toMap();
+ return QVariantMap();
+ })();
+ QVERIFY(!properties.isEmpty());
+ const auto toolchain = properties.value("qbs.toolchain").toStringList();
+ QVERIFY(!toolchain.isEmpty());
+ const bool haveGcc = toolchain.contains("gcc");
+ const bool haveMSVC = toolchain.contains("msvc");
+
QCOMPARE(m_qbsStdout.contains("assembling testa.s"), haveGcc);
QCOMPARE(m_qbsStdout.contains("compiling testb.S"), haveGcc);
QCOMPARE(m_qbsStdout.contains("compiling testc.sx"), haveGcc);
@@ -4068,6 +3896,18 @@ void TestBlackbox::assembly()
QCOMPARE(m_qbsStdout.contains("creating testd.lib"), haveMSVC);
}
+void TestBlackbox::auxiliaryInputsFromDependencies()
+{
+ QDir::setCurrent(testDataDir + "/aux-inputs-from-deps");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("generating dummy.out"), m_qbsStdout.constData());
+ QCOMPARE(runQbs(QbsRunParameters("resolve", QStringList("products.dep.sleep:false"))), 0);
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
+ QVERIFY2(m_qbsStdout.contains("generating dummy.out"), m_qbsStdout.constData());
+}
+
void TestBlackbox::nsis()
{
QStringList regKeys;
@@ -4106,38 +3946,6 @@ void TestBlackbox::nsis()
QVERIFY(!QFile::exists(defaultInstallRoot + "/you-should-not-see-a-file-with-this-name.exe"));
}
-QString getEmbeddedBinaryPlist(const QString &file)
-{
- QProcess p;
- p.start("otool", QStringList() << "-v" << "-X" << "-s" << "__TEXT" << "__info_plist" << file);
- p.waitForFinished();
- return QString::fromUtf8(p.readAllStandardOutput()).trimmed();
-}
-
-void TestBlackbox::embedInfoPlist()
-{
- if (!HostOsInfo::isMacosHost())
- QSKIP("only applies on macOS");
-
- QDir::setCurrent(testDataDir + QLatin1String("/embedInfoPlist"));
-
- QbsRunParameters params;
- QCOMPARE(runQbs(params), 0);
-
- QVERIFY(!getEmbeddedBinaryPlist(defaultInstallRoot + "/app").isEmpty());
- QVERIFY(!getEmbeddedBinaryPlist(defaultInstallRoot + "/liblib.dylib").isEmpty());
- QVERIFY(!getEmbeddedBinaryPlist(defaultInstallRoot + "/mod.bundle").isEmpty());
-
- params.arguments = QStringList(QLatin1String("modules.bundle.embedInfoPlist:false"));
- params.expectFailure = true;
- rmDirR(relativeBuildDir());
- QCOMPARE(runQbs(params), 0);
-
- QVERIFY(getEmbeddedBinaryPlist(defaultInstallRoot + "/app").isEmpty());
- QVERIFY(getEmbeddedBinaryPlist(defaultInstallRoot + "/liblib.dylib").isEmpty());
- QVERIFY(getEmbeddedBinaryPlist(defaultInstallRoot + "/mod.bundle").isEmpty());
-}
-
void TestBlackbox::enableExceptions()
{
QFETCH(QString, file);
@@ -4147,8 +3955,9 @@ void TestBlackbox::enableExceptions()
QDir::setCurrent(testDataDir + QStringLiteral("/enableExceptions"));
QbsRunParameters params;
- params.arguments = QStringList() << "-f" << file << (QStringLiteral("cpp.enableExceptions:")
- + (enable ? "true" : "false"));
+ params.arguments = QStringList() << "-f" << file
+ << (QStringLiteral("modules.cpp.enableExceptions:")
+ + (enable ? "true" : "false"));
params.expectFailure = !expectSuccess;
rmDirR(relativeBuildDir());
if (!params.expectFailure)
@@ -4185,57 +3994,31 @@ void TestBlackbox::enableRtti()
QbsRunParameters params;
- params.arguments = QStringList() << "cpp.enableRtti:true";
+ params.arguments = QStringList() << "modules.cpp.enableRtti:true";
rmDirR(relativeBuildDir());
QCOMPARE(runQbs(params), 0);
if (HostOsInfo::isMacosHost()) {
- params.arguments = QStringList() << "cpp.enableRtti:true" << "project.treatAsObjcpp:true";
+ params.arguments = QStringList() << "modules.cpp.enableRtti:true"
+ << "project.treatAsObjcpp:true";
rmDirR(relativeBuildDir());
QCOMPARE(runQbs(params), 0);
}
params.expectFailure = true;
- params.arguments = QStringList() << "cpp.enableRtti:false";
+ params.arguments = QStringList() << "modules.cpp.enableRtti:false";
rmDirR(relativeBuildDir());
QVERIFY(runQbs(params) != 0);
if (HostOsInfo::isMacosHost()) {
- params.arguments = QStringList() << "cpp.enableRtti:false" << "project.treatAsObjcpp:true";
+ params.arguments = QStringList() << "modules.cpp.enableRtti:false"
+ << "project.treatAsObjcpp:true";
rmDirR(relativeBuildDir());
QVERIFY(runQbs(params) != 0);
}
}
-void TestBlackbox::frameworkStructure()
-{
- if (!HostOsInfo::isMacosHost())
- QSKIP("only applies on macOS");
-
- QDir::setCurrent(testDataDir + QLatin1String("/frameworkStructure"));
-
- QbsRunParameters params;
- QCOMPARE(runQbs(params), 0);
-
- QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Widget"));
- QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Headers/Widget.h"));
- QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/PrivateHeaders/WidgetPrivate.h"));
- QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Resources/BaseResource"));
- QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Resources/en.lproj/EnglishResource"));
- QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/Current"));
- QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Widget"));
- QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Headers"));
- QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/PrivateHeaders"));
- QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Resources"));
-
- params.arguments = QStringList() << "project.includeHeaders:false";
- QCOMPARE(runQbs(params), 0);
-
- QVERIFY(!directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Headers"));
- QVERIFY(!directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/PrivateHeaders"));
-}
-
void TestBlackbox::generatedArtifactAsInputToDynamicRule()
{
QDir::setCurrent(testDataDir + "/generated-artifact-as-input-to-dynamic-rule");
@@ -4295,8 +4078,8 @@ static bool haveWiX(const Profile &profile)
void TestBlackbox::wix()
{
- Settings settings((QString()));
- Profile profile(profileName(), &settings);
+ const SettingsPtr s = settings();
+ Profile profile(profileName(), s.get());
if (!haveWiX(profile)) {
QSKIP("WiX is not installed");
@@ -4326,8 +4109,8 @@ void TestBlackbox::wix()
void TestBlackbox::nodejs()
{
- Settings settings((QString()));
- Profile p(profileName(), &settings);
+ const SettingsPtr s = settings();
+ Profile p(profileName(), s.get());
int status;
findNodejs(&status);
@@ -4357,8 +4140,8 @@ void TestBlackbox::nodejs()
void TestBlackbox::typescript()
{
- Settings settings((QString()));
- Profile p(profileName(), &settings);
+ const SettingsPtr s = settings();
+ Profile p(profileName(), s.get());
int status;
findTypeScript(&status);
@@ -4392,34 +4175,6 @@ void TestBlackbox::typescript()
QVERIFY(regularFileExists(relativeProductBuildDir("animals") + "/main.js"));
}
-void TestBlackbox::iconset()
-{
- if (!HostOsInfo::isMacosHost() || !isXcodeProfile(profileName()))
- QSKIP("only applies on macOS with Xcode based profiles");
-
- QDir::setCurrent(testDataDir + QLatin1String("/ib/iconset"));
-
- QbsRunParameters params;
- params.arguments = QStringList() << "-f" << "iconset.qbs";
- QCOMPARE(runQbs(params), 0);
-
- QVERIFY(regularFileExists(relativeProductBuildDir("iconset") + "/white.icns"));
-}
-
-void TestBlackbox::iconsetApp()
-{
- if (!HostOsInfo::isMacosHost() || !isXcodeProfile(profileName()))
- QSKIP("only applies on macOS with Xcode based profiles");
-
- QDir::setCurrent(testDataDir + QLatin1String("/ib/iconsetapp"));
-
- QbsRunParameters params;
- params.arguments = QStringList() << "-f" << "iconsetapp.qbs";
- QCOMPARE(runQbs(params), 0);
-
- QVERIFY(regularFileExists(relativeProductBuildDir("iconsetapp") + "/iconsetapp.app/Contents/Resources/white.icns"));
-}
-
void TestBlackbox::importInPropertiesCondition()
{
QDir::setCurrent(testDataDir + "/import-in-properties-condition");
@@ -4438,25 +4193,6 @@ void TestBlackbox::importsConflict()
QCOMPARE(runQbs(), 0);
}
-void TestBlackbox::infoPlist()
-{
- if (!HostOsInfo::isMacosHost())
- QSKIP("only applies on macOS");
-
- QDir::setCurrent(testDataDir + "/infoplist");
-
- QbsRunParameters params;
- params.arguments = QStringList() << "-f" << "infoplist.qbs";
- QCOMPARE(runQbs(params), 0);
-
- QFile infoplist(relativeProductBuildDir("infoplist") + "/infoplist.app/Contents/Info.plist");
- QVERIFY(infoplist.open(QIODevice::ReadOnly));
- const QByteArray fileContents = infoplist.readAll();
- QVERIFY2(fileContents.contains("<key>LSMinimumSystemVersion</key>"), fileContents.constData());
- QVERIFY2(fileContents.contains("<string>10.7</string>"), fileContents.constData());
- QVERIFY2(fileContents.contains("<key>NSPrincipalClass</key>"), fileContents.constData());
-}
-
static bool haveInnoSetup(const Profile &profile)
{
if (profile.value("innosetup.toolchainInstallPath").isValid())
@@ -4487,8 +4223,8 @@ static bool haveInnoSetup(const Profile &profile)
void TestBlackbox::innoSetup()
{
- Settings settings((QString()));
- Profile profile(profileName(), &settings);
+ const SettingsPtr s = settings();
+ Profile profile(profileName(), s.get());
if (!haveInnoSetup(profile)) {
QSKIP("Inno Setup is not installed");
@@ -4506,134 +4242,6 @@ void TestBlackbox::innoSetup()
QVERIFY(regularFileExists(relativeProductBuildDir("Example1") + "/Example1.exe"));
}
-void TestBlackbox::assetCatalog()
-{
- QFETCH(bool, flatten);
-
- if (!HostOsInfo::isMacosHost() || !isXcodeProfile(profileName()))
- QSKIP("only applies on macOS with Xcode based profiles");
-
- if (HostOsInfo::hostOsVersion() < qbs::Internal::Version(10, 9))
- QSKIP("This test needs at least macOS 10.9.");
-
- QDir::setCurrent(testDataDir + QLatin1String("/ib/assetcatalog"));
-
- rmDirR(relativeBuildDir());
-
- QbsRunParameters params;
- const QString flattens = "ib.flatten:" + QString(flatten ? "true" : "false");
-
- // Make sure a dry run does not write anything
- params.arguments = QStringList() << "-f" << "assetcatalogempty.qbs" << "--dry-run" << flattens;
- QCOMPARE(runQbs(params), 0);
- QVERIFY(!directoryExists(relativeBuildDir()));
-
- params.arguments = QStringList() << "-f" << "assetcatalogempty.qbs" << flattens;
- QCOMPARE(runQbs(params), 0);
-
- // empty asset catalogs must still produce output
- QVERIFY((bool)m_qbsStdout.contains("compiling empty.xcassets"));
-
- // should not produce a CAR since minimumMacosVersion will be < 10.9
- QVERIFY(!regularFileExists(relativeProductBuildDir("assetcatalogempty") + "/assetcatalogempty.app/Contents/Resources/Assets.car"));
-
- rmDirR(relativeBuildDir());
- params.arguments.append("cpp.minimumMacosVersion:10.9"); // force CAR generation
- QCOMPARE(runQbs(params), 0);
-
- // empty asset catalogs must still produce output
- QVERIFY((bool)m_qbsStdout.contains("compiling empty.xcassets"));
- QVERIFY(regularFileExists(relativeProductBuildDir("assetcatalogempty") + "/assetcatalogempty.app/Contents/Resources/Assets.car"));
-
- // this asset catalog happens to have an embedded icon set,
- // but this should NOT be built since it is not in the files list
- QVERIFY(!(bool)m_qbsStdout.contains(".iconset"));
-
- // now we'll add the iconset
- rmDirR(relativeBuildDir());
- params.arguments.append("project.includeIconset:true");
- QCOMPARE(runQbs(params), 0);
- QVERIFY(!(bool)m_qbsStdout.contains("compiling empty.xcassets"));
- QVERIFY((bool)m_qbsStdout.contains("compiling empty.iconset"));
-
- // make sure the nibs/storyboards are in there
- QString nib = relativeProductBuildDir("assetcatalogempty") + "/assetcatalogempty.app/Contents/Resources/MainMenu.nib";
- QStringList nibFiles;
- if (flatten) {
- QVERIFY(regularFileExists(nib));
- } else {
- QVERIFY(directoryExists(nib));
- nibFiles = QStringList() << "designable.nib" << "keyedobjects.nib";
- }
-
- QString storyboardc = relativeProductBuildDir("assetcatalogempty") + "/assetcatalogempty.app/Contents/Resources/Storyboard.storyboardc";
- QStringList storyboardcFiles;
- if (HostOsInfo::hostOsVersion() >= qbs::Internal::Version(10, 10)) {
- QVERIFY(directoryExists(storyboardc));
-
- storyboardcFiles = QStringList()
- << "1os-k8-h10-view-qKA-a5-eUe.nib"
- << "Info.plist"
- << "Iqk-Fi-Vhk-view-HRv-3O-Qxh.nib"
- << "Main.nib"
- << "NSViewController-Iqk-Fi-Vhk.nib"
- << "NSViewController-Yem-rc-72E.nib"
- << "Yem-rc-72E-view-ODp-aO-Dmf.nib";
-
- if (!flatten) {
- storyboardcFiles << "designable.storyboard";
- storyboardcFiles.sort();
- }
- }
-
- QCOMPARE(QDir(nib).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name), nibFiles);
- QCOMPARE(QDir(storyboardc).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name), storyboardcFiles);
- QbsRunParameters params2 = params;
- params2.command = "clean";
- QCOMPARE(runQbs(params2), 0);
- QCOMPARE(QDir(nib).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name), QStringList());
- QCOMPARE(QDir(storyboardc).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name), QStringList());
-
- QDir::setCurrent(testDataDir + QLatin1String("/ib/multiple-asset-catalogs"));
- rmDirR(relativeBuildDir());
- params.arguments = QStringList();
- QCOMPARE(runQbs(params), 0);
- QVERIFY2(m_qbsStdout.contains("compiling assetcatalog1.xcassets"), m_qbsStdout);
- QVERIFY2(m_qbsStdout.contains("compiling assetcatalog2.xcassets"), m_qbsStdout);
-
- QDir::setCurrent(testDataDir + QLatin1String("/ib/empty-asset-catalogs"));
- rmDirR(relativeBuildDir());
- params.arguments = QStringList();
- QCOMPARE(runQbs(params), 0);
- QVERIFY2(!m_qbsStdout.contains("compiling assetcatalog1.xcassets"), m_qbsStdout);
- QVERIFY2(!m_qbsStdout.contains("compiling assetcatalog2.xcassets"), m_qbsStdout);
-}
-
-void TestBlackbox::assetCatalog_data()
-{
- QTest::addColumn<bool>("flatten");
- QTest::newRow("flattened") << true;
- QTest::newRow("unflattened") << false;
-}
-
-void TestBlackbox::autoQrc()
-{
- QDir::setCurrent(testDataDir + "/auto-qrc");
- QCOMPARE(runQbs(), 0);
- QVERIFY2(m_qbsStdout.simplified().contains("resource data: resource1 resource2"),
- m_qbsStdout.constData());
-}
-
-void TestBlackbox::objcArc()
-{
- if (!HostOsInfo::isMacosHost())
- QSKIP("only applies on platforms supporting Objective-C");
-
- QDir::setCurrent(testDataDir + QLatin1String("/objc-arc"));
-
- QCOMPARE(runQbs(), 0);
-}
-
void TestBlackbox::outputArtifactAutoTagging()
{
QDir::setCurrent(testDataDir + QLatin1String("/output-artifact-auto-tagging"));
@@ -4678,30 +4286,10 @@ void TestBlackbox::loadableModule()
{
QDir::setCurrent(testDataDir + QLatin1String("/loadablemodule"));
- QCOMPARE(runQbs(), 0);
-}
-
-void TestBlackbox::lrelease()
-{
- QDir::setCurrent(testDataDir + QLatin1String("/lrelease"));
- QCOMPARE(runQbs(), 0);
- QVERIFY(regularFileExists(relativeProductBuildDir("lrelease-test") + "/de.qm"));
- QVERIFY(regularFileExists(relativeProductBuildDir("lrelease-test") + "/hu.qm"));
-
- QCOMPARE(runQbs(QString("clean")), 0);
- QbsRunParameters params(QStringList({ "Qt.core.lreleaseMultiplexMode:true"}));
- QCOMPARE(runQbs(params), 0);
- QVERIFY(regularFileExists(relativeProductBuildDir("lrelease-test") + "/lrelease-test.qm"));
- QVERIFY(!regularFileExists(relativeProductBuildDir("lrelease-test") + "/de.qm"));
- QVERIFY(!regularFileExists(relativeProductBuildDir("lrelease-test") + "/hu.qm"));
-
- QCOMPARE(runQbs(QString("clean")), 0);
- params.arguments << "Qt.core.qmBaseName:somename";
+ QbsRunParameters params;
+ params.command = "run";
QCOMPARE(runQbs(params), 0);
- QVERIFY(regularFileExists(relativeProductBuildDir("lrelease-test") + "/somename.qm"));
- QVERIFY(!regularFileExists(relativeProductBuildDir("lrelease-test") + "/lrelease-test.qm"));
- QVERIFY(!regularFileExists(relativeProductBuildDir("lrelease-test") + "/de.qm"));
- QVERIFY(!regularFileExists(relativeProductBuildDir("lrelease-test") + "/hu.qm"));
+ QVERIFY2(m_qbsStdout.contains("foo = 42"), m_qbsStdout.constData());
}
void TestBlackbox::missingDependency()
@@ -4719,13 +4307,39 @@ void TestBlackbox::missingDependency()
QVERIFY(m_qbsStderr.contains("false positive"));
}
+void TestBlackbox::missingProjectFile()
+{
+ QDir::setCurrent(testDataDir + "/missing-project-file/empty-dir");
+ QbsRunParameters params;
+ params.expectFailure = true;
+ QVERIFY(runQbs(params) != 0);
+ QVERIFY2(m_qbsStderr.contains("No project file given and none found in current directory"),
+ m_qbsStderr.constData());
+ QDir::setCurrent(testDataDir + "/missing-project-file");
+ params.arguments << "-f" << "empty-dir";
+ QVERIFY(runQbs(params) != 0);
+ QVERIFY2(m_qbsStderr.contains("No project file found in directory"), m_qbsStderr.constData());
+ params.arguments = QStringList() << "-f" << "ambiguous-dir";
+ QVERIFY(runQbs(params) != 0);
+ QVERIFY2(m_qbsStderr.contains("More than one project file found in directory"),
+ m_qbsStderr.constData());
+ params.expectFailure = false;
+ params.arguments = QStringList() << "-f" << "project-dir";
+ QCOMPARE(runQbs(params), 0);
+ WAIT_FOR_NEW_TIMESTAMP();
+ touch("project-dir/file.cpp");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling file.cpp"), m_qbsStdout.constData());
+ QVERIFY2(!m_qbsStdout.contains("compiling main.cpp"), m_qbsStdout.constData());
+}
+
void TestBlackbox::missingOverridePrefix()
{
QDir::setCurrent(testDataDir + "/missing-override-prefix");
QbsRunParameters params;
params.expectFailure = true;
params.arguments << "blubb.whatever:false";
- QCOMPARE(runQbs(params), 0);
+ QVERIFY(runQbs(params) != 0);
QVERIFY2(m_qbsStderr.contains("Property override key 'blubb.whatever' not understood"),
m_qbsStderr.constData());
}
@@ -4832,43 +4446,4 @@ void TestBlackbox::probesInNestedModules()
QVERIFY(m_qbsStdout.contains("product a, outer.something = hahaha"));
}
-void TestBlackbox::xcode()
-{
- if (!HostOsInfo::isMacosHost() || !isXcodeProfile(profileName()))
- QSKIP("only applies on macOS with Xcode based profiles");
-
- QProcess xcodeSelect;
- xcodeSelect.start("xcode-select", QStringList() << "--print-path");
- QVERIFY2(xcodeSelect.waitForStarted(), qPrintable(xcodeSelect.errorString()));
- QVERIFY2(xcodeSelect.waitForFinished(), qPrintable(xcodeSelect.errorString()));
- QVERIFY2(xcodeSelect.exitCode() == 0, qPrintable(xcodeSelect.readAllStandardError().constData()));
- const QString developerPath(QString::fromLocal8Bit(xcodeSelect.readAllStandardOutput().trimmed()));
-
- QMultiMap<QString, QString> sdks;
-
- QProcess xcodebuildShowSdks;
- xcodebuildShowSdks.start("xcrun", QStringList() << "xcodebuild" << "-showsdks");
- QVERIFY2(xcodebuildShowSdks.waitForStarted(), qPrintable(xcodebuildShowSdks.errorString()));
- QVERIFY2(xcodebuildShowSdks.waitForFinished(), qPrintable(xcodebuildShowSdks.errorString()));
- QVERIFY2(xcodebuildShowSdks.exitCode() == 0, qPrintable(xcodebuildShowSdks.readAllStandardError().constData()));
- for (const QString &line : QString::fromLocal8Bit(xcodebuildShowSdks.readAllStandardOutput().trimmed()).split('\n', QString::SkipEmptyParts)) {
- static const QRegularExpression regexp(QStringLiteral("\\s+\\-sdk\\s+(?<platform>[a-z]+)(?<version>[0-9]+\\.[0-9]+)$"));
- QRegularExpressionMatch match = regexp.match(line);
- if (match.isValid()) {
- sdks.insert(match.captured("platform"), match.captured("version"));
- }
- }
-
- // values() returns items with most recently added first; we want the reverse of that
- QStringList sdkValues(sdks.values("macosx"));
- std::reverse(std::begin(sdkValues), std::end(sdkValues));
-
- QDir::setCurrent(testDataDir + "/xcode");
- QbsRunParameters params;
- params.arguments = (QStringList()
- << (QStringLiteral("xcode.developerPath:") + developerPath)
- << (QStringLiteral("project.sdks:['") + sdkValues.join("','") + "']"));
- QCOMPARE(runQbs(params), 0);
-}
-
QTEST_MAIN(TestBlackbox)
diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h
index bb6426daa..77f5762fb 100644
--- a/tests/auto/blackbox/tst_blackbox.h
+++ b/tests/auto/blackbox/tst_blackbox.h
@@ -43,13 +43,10 @@ private slots:
void alwaysRun_data();
void artifactScanning();
void assembly();
- void assetCatalog();
- void assetCatalog_data();
- void autoQrc();
+ void auxiliaryInputsFromDependencies();
void badInterpreter();
void buildDirectories();
- void bundleStructure();
- void bundleStructure_data();
+ void buildEnvChange();
void changedFiles_data();
void changedFiles();
void changeInDisabledProduct();
@@ -57,24 +54,18 @@ private slots:
void checkProjectFilePath();
void clean();
void cli();
- void combinedMoc();
void combinedSources();
void commandFile();
void concurrentExecutor();
void conditionalExport();
void conditionalFileTagger();
void conflictingArtifacts();
- void createProject();
- void dbusAdaptors();
- void dbusInterfaces();
void dependenciesProperty();
void dependencyProfileMismatch();
- void deploymentTarget();
- void deploymentTarget_data();
void deprecatedProperty();
+ void disappearedProfile();
void dynamicMultiplexRule();
void dynamicRuleOutputs();
- void embedInfoPlist();
void enableExceptions();
void enableExceptions_data();
void enableRtti();
@@ -86,15 +77,11 @@ private slots:
void exportToOutsideSearchPath();
void externalLibs();
void fileDependencies();
- void frameworkStructure();
void generatedArtifactAsInputToDynamicRule();
void groupsInModules();
- void iconset();
- void iconsetApp();
void importInPropertiesCondition();
void importingProduct();
void importsConflict();
- void infoPlist();
void innoSetup();
void inputsFromDependencies();
void installable();
@@ -103,6 +90,7 @@ private slots:
void installedSourceFiles();
void installedTransformerOutput();
void installPackage();
+ void installRootFromProjectFile();
void installTree();
void invalidCommandProperty();
void invalidExtensionInstantiation();
@@ -123,11 +111,9 @@ private slots:
void listPropertiesWithOuter();
void listPropertyOrder();
void loadableModule();
- void lrelease();
void missingDependency();
+ void missingProjectFile();
void missingOverridePrefix();
- void mixedBuildVariants();
- void mocFlags();
void multipleChanges();
void nestedGroups();
void nestedProperties();
@@ -136,14 +122,13 @@ private slots:
void nonBrokenFilesInBrokenProduct();
void nonDefaultProduct();
void nsis();
- void objcArc();
void outputArtifactAutoTagging();
void overrideProjectProperties();
void pchChangeTracking();
void pkgConfigProbe();
void pkgConfigProbe_data();
void pkgConfigProbeSysroot();
- void pluginMetaData();
+ void pluginDependency();
void probeChangeTracking();
void probeProperties();
void probeInExportedModule();
@@ -157,11 +142,7 @@ private slots:
void properQuoting();
void propertiesInExportItems();
void qbsVersion();
- void qmlDebugging();
- void qobjectInObjectiveCpp();
void qtBug51237();
- void qtKeywords();
- void qtScxml();
void radAfterIncompleteBuild();
void radAfterIncompleteBuild_data();
void recursiveRenaming();
@@ -175,17 +156,18 @@ private slots:
void ruleConditions();
void ruleCycle();
void ruleWithNoInputs();
+ void ruleWithNonRequiredInputs();
void smartRelinking();
void smartRelinking_data();
void soVersion();
void soVersion_data();
void subProfileChangeTracking();
void successiveChanges();
+ void symbolLinkMode();
void symlinkRemoval();
void renameDependency();
void separateDebugInfo();
void sevenZip();
- void staticQtPluginLinking();
void suspiciousCalls();
void suspiciousCalls_data();
void systemRunPaths();
@@ -193,11 +175,8 @@ private slots:
void tar();
void toolLookup();
void topLevelSearchPath();
- void track_qobject_change();
- void track_qrc();
void trackAddFile();
void trackAddFileTag();
- void trackAddMocInclude();
void trackAddProduct();
void trackExternalProductChanges();
void trackGroupConditionChange();
@@ -210,10 +189,11 @@ private slots:
void versionCheck();
void versionCheck_data();
void versionScript();
+ void wholeArchive();
+ void wholeArchive_data();
void wildCardsAndRules();
void wildcardRenaming();
void wix();
- void xcode();
void zip();
void zip_data();
void zipInvalid();
diff --git a/tests/auto/blackbox/tst_blackboxapple.cpp b/tests/auto/blackbox/tst_blackboxapple.cpp
new file mode 100644
index 000000000..1829d173e
--- /dev/null
+++ b/tests/auto/blackbox/tst_blackboxapple.cpp
@@ -0,0 +1,755 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "tst_blackboxapple.h"
+
+#include "../shared.h"
+#include <tools/hostosinfo.h>
+#include <tools/profile.h>
+
+#include <QtCore/qjsondocument.h>
+#include <QtXml/qdom.h>
+
+#include <regex>
+
+#define WAIT_FOR_NEW_TIMESTAMP() waitForNewTimestamp(testDataDir)
+
+using qbs::Internal::HostOsInfo;
+using qbs::Profile;
+
+class QFileInfo2 : public QFileInfo {
+public:
+ QFileInfo2(const QString &path) : QFileInfo(path) { }
+ bool isRegularFile() const { return isFile() && !isSymLink(); }
+ bool isRegularDir() const { return isDir() && !isSymLink(); }
+ bool isFileSymLink() const { return isFile() && isSymLink(); }
+ bool isDirSymLink() const { return isDir() && isSymLink(); }
+};
+
+static QString getEmbeddedBinaryPlist(const QString &file)
+{
+ QProcess p;
+ p.start("otool", QStringList() << "-v" << "-X" << "-s" << "__TEXT" << "__info_plist" << file);
+ p.waitForFinished();
+ return QString::fromUtf8(p.readAllStandardOutput()).trimmed();
+}
+
+TestBlackboxApple::TestBlackboxApple()
+ : TestBlackboxBase (SRCDIR "/testdata-apple", "blackbox-apple")
+{
+}
+
+void TestBlackboxApple::initTestCase()
+{
+ if (!HostOsInfo::isMacosHost()) {
+ QSKIP("only applies on macOS");
+ return;
+ }
+
+ TestBlackboxBase::initTestCase();
+}
+
+void TestBlackboxApple::appleMultiConfig()
+{
+ QDir::setCurrent(testDataDir + "/apple-multiconfig");
+ QCOMPARE(runQbs(), 0);
+
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Contents/MacOS/singleapp").isExecutable());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Contents/Info.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp.app/Contents/PkgInfo").isRegularFile());
+
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Contents/MacOS/singleapp_agg").isExecutable());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Contents/Info.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singleapp_agg.app/Contents/PkgInfo").isRegularFile());
+
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/singlelib").isFileSymLink());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Resources").isDirSymLink());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A/singlelib").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A/Resources").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/A/Resources/Info.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/singlelib.framework/Versions/Current").isDirSymLink());
+
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Contents/MacOS/multiapp").isExecutable());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Contents/Info.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/multiapp.app/Contents/PkgInfo").isRegularFile());
+
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Contents/MacOS/fatmultiapp").isFileSymLink());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Contents/MacOS/fatmultiapp_debug").isExecutable());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Contents/Info.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/fatmultiapp.app/Contents/PkgInfo").isRegularFile());
+
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/multilib").isFileSymLink());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Resources").isDirSymLink());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/multilib").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/multilib_debug").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/multilib_profile").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/Resources").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/A/Resources/Info.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/multilib.framework/Versions/Current").isDirSymLink());
+
+ for (const QString &variant : { "release", "debug", "profile" }) {
+ for (const QString &arch : { "x86_64" }) {
+ QProcess process;
+ process.setProgram("/usr/bin/arch");
+ process.setArguments({
+ "-arch", arch,
+ "-e", "DYLD_IMAGE_SUFFIX=_" + variant,
+ defaultInstallRoot + "/multiapp.app/Contents/MacOS/multiapp"
+ });
+ process.start();
+ process.waitForFinished();
+ QCOMPARE(process.exitCode(), 0);
+ const auto processStdout = process.readAllStandardOutput();
+ QVERIFY2(processStdout.contains("Hello from " + variant.toUtf8() + " " + arch.toUtf8()),
+ processStdout.constData());
+ }
+ }
+}
+
+void TestBlackboxApple::assetCatalog()
+{
+ QFETCH(bool, flatten);
+
+ const auto xcodeVersion = findXcodeVersion();
+
+ QDir::setCurrent(testDataDir + QLatin1String("/ib/assetcatalog"));
+
+ rmDirR(relativeBuildDir());
+
+ QbsRunParameters params;
+ const QString flattens = "modules.ib.flatten:" + QString(flatten ? "true" : "false");
+
+ // Make sure a dry run does not write anything
+ params.arguments = QStringList() << "-f" << "assetcatalogempty.qbs" << "--dry-run" << flattens;
+ QCOMPARE(runQbs(params), 0);
+ QVERIFY(!directoryExists(relativeBuildDir()));
+
+ params.arguments = QStringList() << "-f" << "assetcatalogempty.qbs" << flattens;
+ QCOMPARE(runQbs(params), 0);
+
+ // empty asset catalogs must still produce output
+ if (xcodeVersion >= qbs::Internal::Version(5))
+ QVERIFY((bool)m_qbsStdout.contains("compiling empty.xcassets"));
+
+ // should not produce a CAR since minimumMacosVersion will be < 10.9
+ QVERIFY(!regularFileExists(relativeProductBuildDir("assetcatalogempty") + "/assetcatalogempty.app/Contents/Resources/Assets.car"));
+
+ rmDirR(relativeBuildDir());
+ params.arguments.append("modules.cpp.minimumMacosVersion:10.9"); // force CAR generation
+ QCOMPARE(runQbs(params), 0);
+
+ // empty asset catalogs must still produce output
+ if (xcodeVersion >= qbs::Internal::Version(5)) {
+ QVERIFY((bool)m_qbsStdout.contains("compiling empty.xcassets"));
+ // No matter what, we need a 10.9 host to build CAR files
+ if (HostOsInfo::hostOsVersion() >= qbs::Internal::Version(10, 9)) {
+ QVERIFY(regularFileExists(relativeProductBuildDir("assetcatalogempty")
+ + "/assetcatalogempty.app/Contents/Resources/Assets.car"));
+ } else {
+ QVERIFY(regularFileExists(relativeProductBuildDir("assetcatalogempty")
+ + "/assetcatalogempty.app/Contents/Resources/empty.icns"));
+ QVERIFY(regularFileExists(relativeProductBuildDir("assetcatalogempty")
+ + "/assetcatalogempty.app/Contents/Resources/other.png"));
+ QVERIFY(regularFileExists(relativeProductBuildDir("assetcatalogempty")
+ + "/assetcatalogempty.app/Contents/Resources/other@2x.png"));
+ }
+ }
+
+ // this asset catalog happens to have an embedded icon set,
+ // but this should NOT be built since it is not in the files list
+ QVERIFY(!(bool)m_qbsStdout.contains(".iconset"));
+
+ // now we'll add the iconset
+ rmDirR(relativeBuildDir());
+ params.arguments.append("project.includeIconset:true");
+ QCOMPARE(runQbs(params), 0);
+ QVERIFY(!(bool)m_qbsStdout.contains("compiling empty.xcassets"));
+ QVERIFY((bool)m_qbsStdout.contains("compiling empty.iconset"));
+
+ // make sure the nibs/storyboards are in there
+ QString nib = relativeProductBuildDir("assetcatalogempty") + "/assetcatalogempty.app/Contents/Resources/MainMenu.nib";
+ QStringList nibFiles;
+ if (flatten) {
+ QVERIFY(regularFileExists(nib));
+ } else {
+ QVERIFY(directoryExists(nib));
+ nibFiles = QStringList() << "designable.nib" << "keyedobjects.nib";
+ }
+
+ QString storyboardc = relativeProductBuildDir("assetcatalogempty") + "/assetcatalogempty.app/Contents/Resources/Storyboard.storyboardc";
+ QStringList storyboardcFiles;
+ if (HostOsInfo::hostOsVersion() >= qbs::Internal::Version(10, 10)) {
+ QVERIFY(directoryExists(storyboardc));
+
+ storyboardcFiles = QStringList()
+ << "1os-k8-h10-view-qKA-a5-eUe.nib"
+ << "Info.plist"
+ << "Iqk-Fi-Vhk-view-HRv-3O-Qxh.nib"
+ << "Main.nib"
+ << "NSViewController-Iqk-Fi-Vhk.nib"
+ << "NSViewController-Yem-rc-72E.nib"
+ << "Yem-rc-72E-view-ODp-aO-Dmf.nib";
+
+ if (!flatten) {
+ storyboardcFiles << "designable.storyboard";
+ storyboardcFiles.sort();
+ }
+ }
+
+ QCOMPARE(QDir(nib).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name), nibFiles);
+ QCOMPARE(QDir(storyboardc).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name), storyboardcFiles);
+ QbsRunParameters params2 = params;
+ params2.command = "clean";
+ QCOMPARE(runQbs(params2), 0);
+ QCOMPARE(QDir(nib).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name), QStringList());
+ QCOMPARE(QDir(storyboardc).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name), QStringList());
+}
+
+void TestBlackboxApple::assetCatalog_data()
+{
+ QTest::addColumn<bool>("flatten");
+ QTest::newRow("flattened") << true;
+ QTest::newRow("unflattened") << false;
+}
+
+void TestBlackboxApple::assetCatalogsEmpty() {
+ if (findXcodeVersion() < qbs::Internal::Version(5))
+ QSKIP("requires Xcode 5 or above");
+ QDir::setCurrent(testDataDir + QLatin1String("/ib/empty-asset-catalogs"));
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(!m_qbsStdout.contains("compiling assetcatalog1.xcassets"), m_qbsStdout);
+ QVERIFY2(!m_qbsStdout.contains("compiling assetcatalog2.xcassets"), m_qbsStdout);
+}
+
+void TestBlackboxApple::assetCatalogsMultiple() {
+ if (findXcodeVersion() < qbs::Internal::Version(5))
+ QSKIP("requires Xcode 5 or above");
+ QDir::setCurrent(testDataDir + QLatin1String("/ib/multiple-asset-catalogs"));
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling assetcatalog1.xcassets"), m_qbsStdout);
+ QVERIFY2(m_qbsStdout.contains("compiling assetcatalog2.xcassets"), m_qbsStdout);
+}
+
+void TestBlackboxApple::bundleStructure()
+{
+ QFETCH(QString, productName);
+ QFETCH(QString, productTypeIdentifier);
+ QFETCH(bool, isShallow);
+
+ QDir::setCurrent(testDataDir + "/bundle-structure");
+ QbsRunParameters params;
+ params.arguments << "project.buildableProducts:" + productName;
+ if (isShallow) {
+ // Coerce shallow bundles - don't set bundle.isShallow directly because we want to test the
+ // automatic detection
+ const auto xcode5 = findXcodeVersion() >= qbs::Internal::Version(5);
+ params.arguments
+ << "qbs.targetOS:ios,darwin,bsd,unix"
+ << (xcode5 ? "qbs.architectures:arm64" : "qbs.architectures:armv7a");
+ }
+
+ if (productName == "ABadApple" || productName == "ABadThirdParty")
+ params.expectFailure = true;
+
+ rmDirR(relativeBuildDir());
+ const int status = runQbs(params);
+ if (status != 0) {
+ QVERIFY2(m_qbsStderr.contains("Bundle product type "
+ + productTypeIdentifier.toLatin1()
+ + " is not supported."),
+ m_qbsStderr.constData());
+ return;
+ }
+
+ QCOMPARE(status, 0);
+
+ if (!isShallow) {
+ if (productName == "A") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/Info.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/MacOS").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/MacOS/A").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/PkgInfo").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/Resources").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Contents/Resources/resource.txt").isRegularFile());
+ }
+
+ if (productName == "B") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/B").isFileSymLink());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Headers").isDirSymLink());
+ //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Modules").isDirSymLink());
+ QVERIFY(!QFileInfo2(defaultInstallRoot + "/B.framework/PkgInfo").exists());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/PrivateHeaders").isDirSymLink());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Resources").isDirSymLink());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/B").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Headers").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Headers/dummy.h").isRegularFile());
+ //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Modules").isRegularDir());
+ //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Modules/module.modulemap").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/PrivateHeaders").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/PrivateHeaders/dummy_p.h").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Resources").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/A/Resources/Info.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Versions/Current").isDirSymLink());
+ }
+
+ if (productName == "C") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/C").isFileSymLink());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Headers").isDirSymLink());
+ //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Modules").isDirSymLink());
+ QVERIFY(!QFileInfo2(defaultInstallRoot + "/C.framework/PkgInfo").exists());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/PrivateHeaders").isDirSymLink());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Resources").isDirSymLink());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/C").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Headers").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Headers/dummy.h").isRegularFile());
+ //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Modules").isRegularDir());
+ //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Modules/module.modulemap").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/PrivateHeaders").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/PrivateHeaders/dummy_p.h").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Resources").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/A/Resources/Info.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Versions/Current").isDirSymLink());
+ }
+
+ if (productName == "D") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/Info.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/MacOS").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/MacOS/D").isRegularFile());
+ QVERIFY(!QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/PkgInfo").exists());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/Resources").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Contents/Resources/resource.txt").isRegularFile());
+ }
+
+ if (productName == "E") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/Info.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/MacOS").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/MacOS/E").isRegularFile());
+ QVERIFY(!QFileInfo2(defaultInstallRoot + "/E.appex/Contents/PkgInfo").exists());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/Resources").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Contents/Resources/resource.txt").isRegularFile());
+ }
+
+ if (productName == "F") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/Info.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/MacOS").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/MacOS/F").isRegularFile());
+ QVERIFY(!QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/PkgInfo").exists());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/Resources").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Contents/Resources/resource.txt").isRegularFile());
+ }
+
+ if (productName == "G") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/G").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/G/ContentInfo.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/G/Contents/resource.txt").isRegularFile());
+ }
+ } else {
+ if (productName == "A") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/A").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/Info.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/PkgInfo").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/A.app/resource.txt").isRegularFile());
+ }
+
+ if (productName == "B") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/B").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Headers").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Headers/dummy.h").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Info.plist").isRegularFile());
+ //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Modules").isRegularDir());
+ //QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/Modules/module.modulemap").isRegularFile());
+ QVERIFY(!QFileInfo2(defaultInstallRoot + "/B.framework/PkgInfo").exists());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/PrivateHeaders").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/PrivateHeaders/dummy_p.h").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/B.framework/resource.txt").isRegularFile());
+ }
+
+ if (productName == "C") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/C").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Headers").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Headers/dummy.h").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Info.plist").isRegularFile());
+ //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Modules").isRegularDir());
+ //QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/Modules/module.modulemap").isRegularFile());
+ QVERIFY(!QFileInfo2(defaultInstallRoot + "/C.framework/PkgInfo").exists());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/PrivateHeaders").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/PrivateHeaders/dummy_p.h").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/C.framework/resource.txt").isRegularFile());
+ }
+
+ if (productName == "D") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/D").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Headers").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Headers/dummy.h").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/Info.plist").isRegularFile());
+ QVERIFY(!QFileInfo2(defaultInstallRoot + "/D.bundle/PkgInfo").exists());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/PrivateHeaders").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/PrivateHeaders/dummy_p.h").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/D.bundle/resource.txt").isRegularFile());
+ }
+
+ if (productName == "E") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/E").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Headers").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Headers/dummy.h").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/Info.plist").isRegularFile());
+ QVERIFY(!QFileInfo2(defaultInstallRoot + "/E.appex/PkgInfo").exists());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/PrivateHeaders").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/PrivateHeaders/dummy_p.h").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/E.appex/resource.txt").isRegularFile());
+ }
+
+ if (productName == "F") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/F").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Headers").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Headers/dummy.h").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/Info.plist").isRegularFile());
+ QVERIFY(!QFileInfo2(defaultInstallRoot + "/F.xpc/PkgInfo").exists());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/PrivateHeaders").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/PrivateHeaders/dummy_p.h").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/F.xpc/resource.txt").isRegularFile());
+ }
+
+ if (productName == "G") {
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/G").isRegularDir());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/G/ContentInfo.plist").isRegularFile());
+ QVERIFY(QFileInfo2(defaultInstallRoot + "/G/Contents/resource.txt").isRegularFile());
+ }
+ }
+}
+
+void TestBlackboxApple::bundleStructure_data()
+{
+ QTest::addColumn<QString>("productName");
+ QTest::addColumn<QString>("productTypeIdentifier");
+ QTest::addColumn<bool>("isShallow");
+
+ const auto addRows = [](bool isShallow) {
+ const QString s = (isShallow ? " shallow" : "");
+ QTest::newRow(("A" + s).toLatin1()) << "A" << "com.apple.product-type.application" << isShallow;
+ QTest::newRow(("ABadApple" + s).toLatin1()) << "ABadApple" << "com.apple.product-type.will.never.exist.ever.guaranteed" << isShallow;
+ QTest::newRow(("ABadThirdParty" + s).toLatin1()) << "ABadThirdParty" << "org.special.third.party.non.existent.product.type" << isShallow;
+ QTest::newRow(("B" + s).toLatin1()) << "B" << "com.apple.product-type.framework" << isShallow;
+ QTest::newRow(("C" + s).toLatin1()) << "C" << "com.apple.product-type.framework.static" << isShallow;
+ QTest::newRow(("D" + s).toLatin1()) << "D" << "com.apple.product-type.bundle" << isShallow;
+ QTest::newRow(("E" + s).toLatin1()) << "E" << "com.apple.product-type.app-extension" << isShallow;
+ QTest::newRow(("F" + s).toLatin1()) << "F" << "com.apple.product-type.xpc-service" << isShallow;
+ QTest::newRow(("G" + s).toLatin1()) << "G" << "com.apple.product-type.in-app-purchase-content" << isShallow;
+ };
+
+ addRows(true);
+ addRows(false);
+}
+
+void TestBlackboxApple::deploymentTarget()
+{
+ QFETCH(QString, sdk);
+ QFETCH(QString, os);
+ QFETCH(QString, arch);
+ QFETCH(QString, cflags);
+ QFETCH(QString, lflags);
+
+ QDir::setCurrent(testDataDir + "/deploymentTarget");
+
+ QbsRunParameters params;
+ params.arguments = QStringList()
+ << "--command-echo-mode"
+ << "command-line"
+ << "qbs.targetOS:" + os
+ << "qbs.architectures:" + arch;
+
+ rmDirR(relativeBuildDir());
+ int status = runQbs(params);
+
+ const QStringList skippableMessages = QStringList()
+ << "There is no matching SDK available for " + sdk + "."
+ << "x86_64h will be mis-detected as x86_64 with Apple Clang < 6.0"
+ << "clang: error: unknown argument: '-mtvos-version-min"
+ << "clang: error: unknown argument: '-mtvos-simulator-version-min"
+ << "clang: error: unknown argument: '-mwatchos-version-min"
+ << "clang: error: unknown argument: '-mwatchos-simulator-version-min";
+ if (status != 0) {
+ for (const auto &message : skippableMessages) {
+ if (m_qbsStderr.contains(message.toUtf8()))
+ QSKIP(message.toUtf8());
+ }
+ }
+
+ QCOMPARE(status, 0);
+ QVERIFY2(m_qbsStderr.contains(cflags.toLatin1()), m_qbsStderr.constData());
+ QVERIFY2(m_qbsStderr.contains(lflags.toLatin1()), m_qbsStderr.constData());
+}
+
+void TestBlackboxApple::deploymentTarget_data()
+{
+ static const QString macos = QStringLiteral("macos,darwin,bsd,unix");
+ static const QString ios = QStringLiteral("ios,darwin,bsd,unix");
+ static const QString ios_sim = QStringLiteral("ios-simulator,") + ios;
+ static const QString tvos = QStringLiteral("tvos,darwin,bsd,unix");
+ static const QString tvos_sim = QStringLiteral("tvos-simulator,") + tvos;
+ static const QString watchos = QStringLiteral("watchos,darwin,bsd,unix");
+ static const QString watchos_sim = QStringLiteral("watchos-simulator,") + watchos;
+
+ QTest::addColumn<QString>("sdk");
+ QTest::addColumn<QString>("os");
+ QTest::addColumn<QString>("arch");
+ QTest::addColumn<QString>("cflags");
+ QTest::addColumn<QString>("lflags");
+
+ QTest::newRow("macos x86") << "macosx" << macos << "x86"
+ << "-triple i386-apple-macosx10.4"
+ << "-macosx_version_min 10.4";
+ QTest::newRow("macos x86_64") << "macosx" << macos << "x86_64"
+ << "-triple x86_64-apple-macosx10.4"
+ << "-macosx_version_min 10.4";
+
+ const auto xcodeVersion = findXcodeVersion();
+ if (xcodeVersion >= qbs::Internal::Version(6))
+ QTest::newRow("macos x86_64h") << "macosx" << macos << "x86_64h"
+ << "-triple x86_64h-apple-macosx10.12"
+ << "-macosx_version_min 10.12";
+
+ QTest::newRow("ios armv7a") << "iphoneos" << ios << "armv7a"
+ << "-triple thumbv7-apple-ios6.0"
+ << "-iphoneos_version_min 6.0";
+ QTest::newRow("ios armv7s") << "iphoneos" <<ios << "armv7s"
+ << "-triple thumbv7s-apple-ios7.0"
+ << "-iphoneos_version_min 7.0";
+ if (xcodeVersion >= qbs::Internal::Version(5))
+ QTest::newRow("ios arm64") << "iphoneos" <<ios << "arm64"
+ << "-triple arm64-apple-ios7.0"
+ << "-iphoneos_version_min 7.0";
+ QTest::newRow("ios-simulator x86") << "iphonesimulator" << ios_sim << "x86"
+ << "-triple i386-apple-ios6.0"
+ << "-ios_simulator_version_min 6.0";
+ if (xcodeVersion >= qbs::Internal::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";
+
+ if (xcodeVersion >= qbs::Internal::Version(7)) {
+ if (xcodeVersion >= qbs::Internal::Version(7, 1)) {
+ QTest::newRow("tvos arm64") << "appletvos" << tvos << "arm64"
+ << "-triple arm64-apple-tvos9.0"
+ << "-tvos_version_min 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";
+ }
+
+ QTest::newRow("watchos armv7k") << "watchos" << watchos << "armv7k"
+ << "-triple thumbv7k-apple-watchos2.0"
+ << "-watchos_version_min 2.0";
+ QTest::newRow("watchos-simulator x86") << "watchsimulator" << watchos_sim << "x86"
+ << "-triple i386-apple-watchos2.0"
+ << "-watchos_simulator_version_min 2.0";
+ }
+}
+
+void TestBlackboxApple::dmg()
+{
+ QDir::setCurrent(testDataDir + "/apple-dmg");
+ QCOMPARE(runQbs(), 0);
+}
+
+void TestBlackboxApple::embedInfoPlist()
+{
+ QDir::setCurrent(testDataDir + QLatin1String("/embedInfoPlist"));
+
+ QbsRunParameters params;
+ QCOMPARE(runQbs(params), 0);
+
+ QVERIFY(!getEmbeddedBinaryPlist(defaultInstallRoot + "/app").isEmpty());
+ QVERIFY(!getEmbeddedBinaryPlist(defaultInstallRoot + "/liblib.dylib").isEmpty());
+ QVERIFY(!getEmbeddedBinaryPlist(defaultInstallRoot + "/mod.bundle").isEmpty());
+
+ params.arguments = QStringList(QLatin1String("modules.bundle.embedInfoPlist:false"));
+ params.expectFailure = true;
+ rmDirR(relativeBuildDir());
+ QCOMPARE(runQbs(params), 0);
+
+ QVERIFY(getEmbeddedBinaryPlist(defaultInstallRoot + "/app").isEmpty());
+ QVERIFY(getEmbeddedBinaryPlist(defaultInstallRoot + "/liblib.dylib").isEmpty());
+ QVERIFY(getEmbeddedBinaryPlist(defaultInstallRoot + "/mod.bundle").isEmpty());
+}
+
+void TestBlackboxApple::frameworkStructure()
+{
+ QDir::setCurrent(testDataDir + QLatin1String("/frameworkStructure"));
+
+ QbsRunParameters params;
+ QCOMPARE(runQbs(params), 0);
+
+ QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Widget"));
+ QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Headers/Widget.h"));
+ QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/PrivateHeaders/WidgetPrivate.h"));
+ QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Resources/BaseResource"));
+ QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/A/Resources/en.lproj/EnglishResource"));
+ QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Versions/Current"));
+ QVERIFY(regularFileExists(relativeProductBuildDir("Widget") + "/Widget.framework/Widget"));
+ QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Headers"));
+ QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/PrivateHeaders"));
+ QVERIFY(directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Resources"));
+
+ params.command = "resolve";
+ params.arguments = QStringList() << "project.includeHeaders:false";
+ QCOMPARE(runQbs(params), 0);
+ QCOMPARE(runQbs(), 0);
+
+ QVERIFY(!directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/Headers"));
+ QVERIFY(!directoryExists(relativeProductBuildDir("Widget") + "/Widget.framework/PrivateHeaders"));
+}
+
+void TestBlackboxApple::iconset()
+{
+ QDir::setCurrent(testDataDir + QLatin1String("/ib/iconset"));
+
+ QbsRunParameters params;
+ params.arguments = QStringList() << "-f" << "iconset.qbs";
+ QCOMPARE(runQbs(params), 0);
+
+ QVERIFY(regularFileExists(relativeProductBuildDir("iconset") + "/white.icns"));
+}
+
+void TestBlackboxApple::iconsetApp()
+{
+ QDir::setCurrent(testDataDir + QLatin1String("/ib/iconsetapp"));
+
+ QbsRunParameters params;
+ params.arguments = QStringList() << "-f" << "iconsetapp.qbs";
+ QCOMPARE(runQbs(params), 0);
+
+ QVERIFY(regularFileExists(relativeProductBuildDir("iconsetapp") + "/iconsetapp.app/Contents/Resources/white.icns"));
+}
+
+void TestBlackboxApple::infoPlist()
+{
+ QDir::setCurrent(testDataDir + "/infoplist");
+
+ QbsRunParameters params;
+ params.arguments = QStringList() << "-f" << "infoplist.qbs";
+ QCOMPARE(runQbs(params), 0);
+
+ QFile infoplist(relativeProductBuildDir("infoplist") + "/infoplist.app/Contents/Info.plist");
+ QVERIFY(infoplist.open(QIODevice::ReadOnly));
+ const QByteArray fileContents = infoplist.readAll();
+ QVERIFY2(fileContents.contains("<key>LSMinimumSystemVersion</key>"), fileContents.constData());
+ QVERIFY2(fileContents.contains("<string>10.7</string>"), fileContents.constData());
+ QVERIFY2(fileContents.contains("<key>NSPrincipalClass</key>"), fileContents.constData());
+}
+
+void TestBlackboxApple::objcArc()
+{
+ QDir::setCurrent(testDataDir + QLatin1String("/objc-arc"));
+
+ QCOMPARE(runQbs(), 0);
+}
+
+void TestBlackboxApple::xcode()
+{
+ QProcess xcodeSelect;
+ xcodeSelect.start("xcode-select", QStringList() << "--print-path");
+ QVERIFY2(xcodeSelect.waitForStarted(), qPrintable(xcodeSelect.errorString()));
+ QVERIFY2(xcodeSelect.waitForFinished(), qPrintable(xcodeSelect.errorString()));
+ QVERIFY2(xcodeSelect.exitCode() == 0, qPrintable(xcodeSelect.readAllStandardError().constData()));
+ const QString developerPath(QString::fromLocal8Bit(xcodeSelect.readAllStandardOutput().trimmed()));
+
+ std::multimap<std::string, std::string> sdks;
+
+ QProcess xcodebuildShowSdks;
+ xcodebuildShowSdks.start("xcrun", QStringList() << "xcodebuild" << "-showsdks");
+ QVERIFY2(xcodebuildShowSdks.waitForStarted(), qPrintable(xcodebuildShowSdks.errorString()));
+ QVERIFY2(xcodebuildShowSdks.waitForFinished(), qPrintable(xcodebuildShowSdks.errorString()));
+ QVERIFY2(xcodebuildShowSdks.exitCode() == 0, qPrintable(xcodebuildShowSdks.readAllStandardError().constData()));
+ for (const QString &line : QString::fromLocal8Bit(xcodebuildShowSdks.readAllStandardOutput().trimmed()).split('\n', QString::SkipEmptyParts)) {
+ static const std::regex regexp("^.+\\s+\\-sdk\\s+([a-z]+)([0-9]+\\.[0-9]+)$");
+ const auto ln = line.toStdString();
+ std::smatch match;
+ if (std::regex_match(ln, match, regexp))
+ sdks.insert({ match[1], match[2] });
+ }
+
+ auto range = sdks.equal_range("macosx");
+ QStringList sdkValues;
+ for (auto i = range.first; i != range.second; ++i)
+ sdkValues.push_back(QString::fromStdString(i->second));
+
+ QDir::setCurrent(testDataDir + "/xcode");
+ QbsRunParameters params;
+ params.arguments = (QStringList()
+ << (QStringLiteral("modules.xcode.developerPath:") + developerPath)
+ << (QStringLiteral("project.sdks:['") + sdkValues.join("','") + "']"));
+ QCOMPARE(runQbs(params), 0);
+}
+
+QTEST_MAIN(TestBlackboxApple)
+
+QVariantMap TestBlackboxApple::findXcode(int *status)
+{
+ QTemporaryDir temp;
+ QbsRunParameters params = QStringList({"-f", testDataDir + "/find/find-xcode.qbs"});
+ params.profile = "none";
+ params.buildDirectory = temp.path();
+ const int res = runQbs(params);
+ if (status)
+ *status = res;
+ QFile file(temp.path() + "/" + relativeProductBuildDir("find-xcode")
+ + "/xcode.json");
+ if (!file.open(QIODevice::ReadOnly))
+ return QVariantMap { };
+ return QJsonDocument::fromJson(file.readAll()).toVariant().toMap();
+}
+
+qbs::Internal::Version TestBlackboxApple::findXcodeVersion()
+{
+ return qbs::Internal::Version::fromString(findXcode().value("version").toString());
+}
diff --git a/tests/auto/blackbox/tst_blackboxapple.h b/tests/auto/blackbox/tst_blackboxapple.h
new file mode 100644
index 000000000..b9bb64104
--- /dev/null
+++ b/tests/auto/blackbox/tst_blackboxapple.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TST_BLACKBOXAPPLE_H
+#define TST_BLACKBOXAPPLE_H
+
+#include "tst_blackboxbase.h"
+
+namespace qbs {
+namespace Internal {
+class Version;
+} // namespace Internal
+} // namespace qbs
+
+class TestBlackboxApple : public TestBlackboxBase
+{
+ Q_OBJECT
+
+public:
+ TestBlackboxApple();
+
+public slots:
+ void initTestCase() override;
+
+private slots:
+ void appleMultiConfig();
+ void assetCatalog();
+ void assetCatalog_data();
+ void assetCatalogsEmpty();
+ void assetCatalogsMultiple();
+ void bundleStructure();
+ void bundleStructure_data();
+ void deploymentTarget();
+ void deploymentTarget_data();
+ void dmg();
+ void embedInfoPlist();
+ void frameworkStructure();
+ void iconset();
+ void iconsetApp();
+ void infoPlist();
+ void objcArc();
+ void xcode();
+
+private:
+ QVariantMap findXcode(int *status = nullptr);
+ qbs::Internal::Version findXcodeVersion();
+};
+
+#endif // TST_BLACKBOXAPPLE_H
diff --git a/tests/auto/blackbox/tst_blackboxbase.cpp b/tests/auto/blackbox/tst_blackboxbase.cpp
index 53e54b251..e484aab6a 100644
--- a/tests/auto/blackbox/tst_blackboxbase.cpp
+++ b/tests/auto/blackbox/tst_blackboxbase.cpp
@@ -34,7 +34,6 @@
#include <tools/hostosinfo.h>
#include <tools/installoptions.h>
#include <tools/profile.h>
-#include <tools/settings.h>
#include <QtCore/qdiriterator.h>
#include <QtCore/qjsondocument.h>
@@ -44,7 +43,6 @@ using qbs::Internal::HostOsInfo;
using qbs::Internal::removeDirectoryWithContents;
using qbs::InstallOptions;
using qbs::Profile;
-using qbs::Settings;
static QString initQbsExecutableFilePath()
{
@@ -59,6 +57,10 @@ static bool supportsBuildDirectoryOption(const QString &command) {
.contains(command);
}
+static bool supportsSettingsDirOption(const QString &command) {
+ return !(QStringList() << "help" << "create-project"<< "qmltypes").contains(command);
+}
+
TestBlackboxBase::TestBlackboxBase(const QString &testDataSrcDir, const QString &testName)
: testDataDir(testWorkDir(testName)),
testSourceDir(QDir::cleanPath(testDataSrcDir)),
@@ -73,18 +75,19 @@ int TestBlackboxBase::runQbs(const QbsRunParameters &params)
QStringList args;
if (!params.command.isEmpty())
args << params.command;
+ if (!params.settingsDir.isEmpty() && supportsSettingsDirOption(params.command))
+ args << "--settings-dir" << params.settingsDir;
if (supportsBuildDirectoryOption(params.command)) {
args.append(QLatin1String("-d"));
args.append(params.buildDirectory.isEmpty() ? QLatin1String(".") : params.buildDirectory);
}
args << params.arguments;
- if (params.useProfile)
- args.append(QLatin1String("profile:") + profileName());
+ if (!params.profile.isEmpty())
+ args.append(QLatin1String("profile:") + params.profile);
QProcess process;
process.setProcessEnvironment(params.environment);
process.start(qbsExecutableFilePath, args);
- const int waitTime = 10 * 60000;
- if (!process.waitForStarted() || !process.waitForFinished(waitTime)
+ if (!process.waitForStarted() || !process.waitForFinished(testTimeoutInMsecs())
|| process.exitStatus() != QProcess::NormalExit) {
m_qbsStderr = process.readAllStandardError();
QTest::qFail("qbs did not run correctly", __FILE__, __LINE__);
@@ -163,19 +166,12 @@ void TestBlackboxBase::initTestCase()
{
QVERIFY(regularFileExists(qbsExecutableFilePath));
- Settings settings((QString()));
- if (!settings.profiles().contains(profileName()))
+ const SettingsPtr s = settings();
+ if (!s->profiles().contains(profileName()))
QFAIL(QByteArray("The build profile '" + profileName().toLocal8Bit() +
"' could not be found. Please set it up on your machine."));
- Profile buildProfile(profileName(), &settings);
- QVariant qtBinPath = buildProfile.value(QLatin1String("Qt.core.binPath"));
- if (!qtBinPath.isValid())
- QFAIL(QByteArray("The build profile '" + profileName().toLocal8Bit() +
- "' is not a valid Qt profile."));
- if (!QFile::exists(qtBinPath.toString()))
- QFAIL(QByteArray("The build profile '" + profileName().toLocal8Bit() +
- "' points to an invalid Qt path."));
+ validateTestProfile();
// Initialize the test data directory.
QVERIFY(testDataDir != testSourceDir);
diff --git a/tests/auto/blackbox/tst_blackboxbase.h b/tests/auto/blackbox/tst_blackboxbase.h
index 8623d898b..1c3b9b4bb 100644
--- a/tests/auto/blackbox/tst_blackboxbase.h
+++ b/tests/auto/blackbox/tst_blackboxbase.h
@@ -28,6 +28,8 @@
#ifndef TST_BLACKBOXBASE_H
#define TST_BLACKBOXBASE_H
+#include "../shared.h"
+
#include <QtCore/qmap.h>
#include <QtCore/qprocess.h>
#include <QtCore/qstringlist.h>
@@ -55,7 +57,8 @@ public:
void init()
{
expectFailure = false;
- useProfile = true;
+ profile = profileName();
+ settingsDir = settings()->baseDirectory();
environment = QProcessEnvironment::systemEnvironment();
}
@@ -63,8 +66,9 @@ public:
QStringList arguments;
QString buildDirectory;
QProcessEnvironment environment;
+ QString profile;
+ QString settingsDir;
bool expectFailure;
- bool useProfile;
};
class TestBlackboxBase : public QObject
@@ -74,9 +78,10 @@ public:
TestBlackboxBase(const QString &testDataSrcDir, const QString &testName);
public slots:
- void initTestCase();
+ virtual void initTestCase();
protected:
+ virtual void validateTestProfile() { }
int runQbs(const QbsRunParameters &params = QbsRunParameters());
void rmDirR(const QString &dir);
static QByteArray unifiedLineEndings(const QByteArray &ba);
diff --git a/tests/auto/blackbox/tst_blackboxjava.cpp b/tests/auto/blackbox/tst_blackboxjava.cpp
index 097fabca8..aee3cce3f 100644
--- a/tests/auto/blackbox/tst_blackboxjava.cpp
+++ b/tests/auto/blackbox/tst_blackboxjava.cpp
@@ -31,31 +31,32 @@
#include "../shared.h"
#include <tools/hostosinfo.h>
#include <tools/profile.h>
-#include <tools/settings.h>
#include <QtCore/qjsondocument.h>
#include <QtCore/qtemporarydir.h>
using qbs::Internal::HostOsInfo;
using qbs::Profile;
-using qbs::Settings;
-QMap<QString, QString> TestBlackboxJava::findAndroid(int *status)
+QMap<QString, QString> TestBlackboxJava::findAndroid(int *status, const QString &profile)
{
QTemporaryDir temp;
QDir::setCurrent(testDataDir + "/find");
- QbsRunParameters params = QStringList() << "-f" << "find-android.qbs";
+ QbsRunParameters params = QStringList({"-f", "find-android.qbs", "qbs.architecture:x86"});
+ params.profile = profile;
params.buildDirectory = temp.path();
const int res = runQbs(params);
if (status)
*status = res;
- QFile file(temp.path() + "/" + relativeProductBuildDir("find-android") + "/android.json");
+ QFile file(temp.path() + "/" + relativeProductBuildDir("find-android")
+ + "/android.json");
if (!file.open(QIODevice::ReadOnly))
return QMap<QString, QString> { };
const auto tools = QJsonDocument::fromJson(file.readAll()).toVariant().toMap();
return QMap<QString, QString> {
{"sdk", QDir::fromNativeSeparators(tools["sdk"].toString())},
{"ndk", QDir::fromNativeSeparators(tools["ndk"].toString())},
+ {"ndk-samples", QDir::fromNativeSeparators(tools["ndk-samples"].toString())},
};
}
@@ -69,28 +70,29 @@ void TestBlackboxJava::android()
QFETCH(QStringList, productNames);
QFETCH(QList<int>, apkFileCounts);
+ const SettingsPtr s = settings();
+ Profile p("qbs_autotests-android", s.get());
+ if (!p.exists())
+ QSKIP("No Android test profile");
int status;
- const auto androidPaths = findAndroid(&status);
+ const auto androidPaths = findAndroid(&status, p.name());
+ QCOMPARE(status, 0);
const auto ndkPath = androidPaths["ndk"];
+ const auto ndkSamplesPath = androidPaths["ndk-samples"];
static const QStringList ndkSamplesDirs = QStringList() << "teapot" << "no-native";
- if (!ndkPath.isEmpty() && !QFileInfo(ndkPath + "/samples").isDir()
+ if (!ndkPath.isEmpty() && !QFileInfo(ndkSamplesPath).isDir()
&& ndkSamplesDirs.contains(projectDir))
QSKIP("NDK samples directory not present");
QDir::setCurrent(testDataDir + "/android/" + projectDir);
- Settings s((QString()));
- Profile p("qbs_autotests-android", &s);
- if (!p.exists() || (status != 0 && !p.value("Android.sdk.ndkDir").isValid()))
- QSKIP("No suitable Android test profile");
- QbsRunParameters params(QStringList("profile:" + p.name())
- << "Android.ndk.platform:android-21");
- params.useProfile = false;
+ QbsRunParameters params(QStringList() << "modules.Android.ndk.platform:android-21");
+ params.profile = p.name();
QCOMPARE(runQbs(params), 0);
for (int i = 0; i < productNames.count(); ++i) {
const QString productName = productNames.at(i);
QVERIFY(m_qbsStdout.contains("Creating " + productName.toLocal8Bit() + ".apk"));
- const QString apkFilePath = relativeProductBuildDir(productName, p.name())
+ const QString apkFilePath = relativeProductBuildDir(productName)
+ '/' + productName + ".apk";
QVERIFY2(regularFileExists(apkFilePath), qPrintable(apkFilePath));
const QString jarFilePath = findExecutable(QStringList("jar"));
@@ -106,17 +108,22 @@ void TestBlackboxJava::android()
void TestBlackboxJava::android_data()
{
+ const SettingsPtr s = settings();
+ const Profile p("qbs_autotests-android", s.get());
+ const int archCount = p.value(QLatin1String("qbs.architectures")).toStringList().count();
+
QTest::addColumn<QString>("projectDir");
QTest::addColumn<QStringList>("productNames");
QTest::addColumn<QList<int>>("apkFileCounts");
- QTest::newRow("teapot") << "teapot" << QStringList("com.sample.teapot") << (QList<int>() << 31);
+ QTest::newRow("teapot") << "teapot" << QStringList("com.sample.teapot")
+ << (QList<int>() << (13 + 3*archCount));
QTest::newRow("no native") << "no-native"
<< QStringList("com.example.android.basicmediadecoder") << (QList<int>() << 22);
QTest::newRow("multiple libs") << "multiple-libs-per-apk" << QStringList("twolibs")
- << (QList<int>() << 10);
+ << (QList<int>() << (6 + 4 * archCount));
QTest::newRow("multiple apks") << "multiple-apks-per-project"
<< (QStringList() << "twolibs1" << "twolibs2")
- << (QList<int>() << 15 << 9);
+ << QList<int>({6 + archCount * 3 + 2, 5 + archCount * 4});
}
static QProcessEnvironment processEnvironmentWithCurrentDirectoryInLibraryPath()
@@ -134,8 +141,8 @@ void TestBlackboxJava::java()
QSKIP("QTBUG-3845");
#endif
- Settings settings((QString()));
- Profile p(profileName(), &settings);
+ const SettingsPtr s = settings();
+ Profile p(profileName(), s.get());
int status;
const auto jdkTools = findJdkTools(&status);
@@ -219,15 +226,14 @@ void TestBlackboxJava::javaDependencyTracking()
{
QFETCH(QString, jdkPath);
QFETCH(QString, javaVersion);
- QFETCH(QString, flag);
QDir::setCurrent(testDataDir + "/java");
QbsRunParameters rp;
- rp.arguments.append(flag);
+ rp.arguments.append("--check-outputs");
if (!jdkPath.isEmpty())
- rp.arguments << ("java.jdkPath:" + jdkPath);
+ rp.arguments << ("modules.java.jdkPath:" + jdkPath);
if (!javaVersion.isEmpty())
- rp.arguments << ("java.languageVersion:'" + javaVersion + "'");
+ rp.arguments << ("modules.java.languageVersion:'" + javaVersion + "'");
rmDirR(relativeBuildDir());
QCOMPARE(runQbs(rp), 0);
}
@@ -236,10 +242,9 @@ void TestBlackboxJava::javaDependencyTracking_data()
{
QTest::addColumn<QString>("jdkPath");
QTest::addColumn<QString>("javaVersion");
- QTest::addColumn<QString>("flag");
- Settings settings((QString()));
- Profile p(profileName(), &settings);
+ const SettingsPtr s = settings();
+ Profile p(profileName(), s.get());
auto getSpecificJdkVersion = [](const QString &jdkVersion) -> QString {
if (HostOsInfo::isMacosHost()) {
@@ -293,10 +298,8 @@ void TestBlackboxJava::javaDependencyTracking_data()
+ (!currentJavaVersion.isEmpty()
? ("Java " + currentJavaVersion)
: "default Java version");
- QTest::newRow((rowName + ", --check-outputs").toLatin1().constData())
- << jdkPath << currentJavaVersion << "--check-outputs";
- QTest::newRow((rowName + ", --dry-run").toLatin1().constData())
- << jdkPath << currentJavaVersion << "--dry-run";
+ QTest::newRow(rowName.toLatin1().constData())
+ << jdkPath << currentJavaVersion;
}
}
}
@@ -308,20 +311,17 @@ void TestBlackboxJava::javaDependencyTracking_data()
void TestBlackboxJava::javaDependencyTrackingInnerClass()
{
- Settings settings((QString()));
- Profile p(profileName(), &settings);
+ const SettingsPtr s = settings();
+ Profile p(profileName(), s.get());
QDir::setCurrent(testDataDir + "/java/inner-class");
QbsRunParameters params;
- params.expectFailure = true;
int status = runQbs(params);
if (p.value("java.jdkPath").toString().isEmpty()
&& status != 0 && m_qbsStderr.contains("jdkPath")) {
QSKIP("java.jdkPath not set and automatic detection failed");
}
QCOMPARE(status, 0);
- QEXPECT_FAIL(0, "QBS-1069", Abort);
- QVERIFY(!m_qbsStderr.contains("QBS-1069"));
}
QTEST_MAIN(TestBlackboxJava)
diff --git a/tests/auto/blackbox/tst_blackboxjava.h b/tests/auto/blackbox/tst_blackboxjava.h
index f7c41f8ba..f85259f46 100644
--- a/tests/auto/blackbox/tst_blackboxjava.h
+++ b/tests/auto/blackbox/tst_blackboxjava.h
@@ -47,7 +47,7 @@ private slots:
void javaDependencyTrackingInnerClass();
private:
- QMap<QString, QString> findAndroid(int *status);
+ QMap<QString, QString> findAndroid(int *status, const QString &profile);
};
#endif // TST_BLACKBOX_H
diff --git a/tests/auto/blackbox/tst_blackboxqt.cpp b/tests/auto/blackbox/tst_blackboxqt.cpp
new file mode 100644
index 000000000..8bf892fb0
--- /dev/null
+++ b/tests/auto/blackbox/tst_blackboxqt.cpp
@@ -0,0 +1,311 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "tst_blackboxqt.h"
+
+#include "../shared.h"
+#include <tools/hostosinfo.h>
+#include <tools/profile.h>
+
+#include <QtCore/qjsondocument.h>
+
+#define WAIT_FOR_NEW_TIMESTAMP() waitForNewTimestamp(testDataDir)
+
+using qbs::Internal::HostOsInfo;
+using qbs::Profile;
+
+TestBlackboxQt::TestBlackboxQt() : TestBlackboxBase (SRCDIR "/testdata-qt", "blackbox-qt")
+{
+}
+
+void TestBlackboxQt::validateTestProfile()
+{
+ const SettingsPtr s = settings();
+ if (!s->profiles().contains(profileName()))
+ QFAIL(QByteArray("The build profile '" + profileName().toLocal8Bit() +
+ "' could not be found. Please set it up on your machine."));
+
+ Profile buildProfile(profileName(), s.get());
+ const QStringList searchPaths
+ = buildProfile.value(QLatin1String("preferences.qbsSearchPaths")).toStringList();
+ if (searchPaths.isEmpty())
+ QFAIL(QByteArray("The build profile '" + profileName().toLocal8Bit() +
+ "' is not a valid Qt profile."));
+ if (!QFileInfo(searchPaths.first()).isDir())
+ QFAIL(QByteArray("The build profile '" + profileName().toLocal8Bit() +
+ "' points to an invalid qbs search path."));
+}
+
+void TestBlackboxQt::autoQrc()
+{
+ QDir::setCurrent(testDataDir + "/auto-qrc");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.simplified().contains("resource data: resource1 resource2"),
+ m_qbsStdout.constData());
+}
+
+void TestBlackboxQt::combinedMoc()
+{
+ QDir::setCurrent(testDataDir + "/combined-moc");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY(m_qbsStdout.contains("compiling moc_theobject.cpp"));
+ QVERIFY(!m_qbsStdout.contains("creating amalgamated_moc_theapp.cpp"));
+ QVERIFY(!m_qbsStdout.contains("compiling amalgamated_moc_theapp.cpp"));
+ QbsRunParameters params(QStringList("modules.Qt.core.combineMocOutput:true"));
+ params.command = "resolve";
+ QCOMPARE(runQbs(params), 0);
+ params.command = "build";
+ QCOMPARE(runQbs(params), 0);
+ QVERIFY(!m_qbsStdout.contains("compiling moc_theobject.cpp"));
+ QVERIFY(m_qbsStdout.contains("creating amalgamated_moc_theapp.cpp"));
+ QVERIFY(m_qbsStdout.contains("compiling amalgamated_moc_theapp.cpp"));
+}
+
+void TestBlackboxQt::createProject()
+{
+ QDir::setCurrent(testDataDir + "/create-project");
+ QVERIFY(QFile::copy(SRCDIR "/../../../examples/helloworld-qt/main.cpp",
+ QDir::currentPath() + "/main.cpp"));
+ QbsRunParameters createParams("create-project");
+ createParams.profile.clear();
+ QCOMPARE(runQbs(createParams), 0);
+ createParams.expectFailure = true;
+ QVERIFY(runQbs(createParams) != 0);
+ QVERIFY2(m_qbsStderr.contains("already contains qbs files"), m_qbsStderr.constData());
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("compiling"), m_qbsStdout.constData());
+}
+
+void TestBlackboxQt::dbusAdaptors()
+{
+ QDir::setCurrent(testDataDir + "/dbus-adaptors");
+ QCOMPARE(runQbs(), 0);
+}
+
+void TestBlackboxQt::dbusInterfaces()
+{
+ QDir::setCurrent(testDataDir + "/dbus-interfaces");
+ QCOMPARE(runQbs(), 0);
+}
+
+void TestBlackboxQt::lrelease()
+{
+ QDir::setCurrent(testDataDir + QLatin1String("/lrelease"));
+ QCOMPARE(runQbs(), 0);
+ QVERIFY(regularFileExists(relativeProductBuildDir("lrelease-test") + "/de.qm"));
+ QVERIFY(regularFileExists(relativeProductBuildDir("lrelease-test") + "/hu.qm"));
+
+ QCOMPARE(runQbs(QString("clean")), 0);
+ QbsRunParameters params(QStringList({"modules.Qt.core.lreleaseMultiplexMode:true"}));
+ params.command = "resolve";
+ QCOMPARE(runQbs(params), 0);
+ params.command = "build";
+ QCOMPARE(runQbs(params), 0);
+ QVERIFY(regularFileExists(relativeProductBuildDir("lrelease-test") + "/lrelease-test.qm"));
+ QVERIFY(!regularFileExists(relativeProductBuildDir("lrelease-test") + "/de.qm"));
+ QVERIFY(!regularFileExists(relativeProductBuildDir("lrelease-test") + "/hu.qm"));
+
+ QCOMPARE(runQbs(QString("clean")), 0);
+ params.command = "resolve";
+ params.arguments << "modules.Qt.core.qmBaseName:somename";
+ QCOMPARE(runQbs(params), 0);
+ params.command = "build";
+ params.arguments.clear();
+ QCOMPARE(runQbs(params), 0);
+ QVERIFY(regularFileExists(relativeProductBuildDir("lrelease-test") + "/somename.qm"));
+ QVERIFY(!regularFileExists(relativeProductBuildDir("lrelease-test") + "/lrelease-test.qm"));
+ QVERIFY(!regularFileExists(relativeProductBuildDir("lrelease-test") + "/de.qm"));
+ QVERIFY(!regularFileExists(relativeProductBuildDir("lrelease-test") + "/hu.qm"));
+}
+
+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")) {
+ QbsRunParameters params;
+ params.arguments << "qbs.buildVariant:debug";
+ params.expectFailure = true;
+ QVERIFY(runQbs(params) != 0);
+ QVERIFY2(m_qbsStderr.contains("not allowed"), m_qbsStderr.constData());
+ } else {
+ QbsRunParameters params;
+ params.expectFailure = true;
+ QVERIFY(runQbs(params) != 0);
+ QVERIFY2(m_qbsStderr.contains("not supported"), m_qbsStderr.constData());
+ }
+}
+
+void TestBlackboxQt::mocFlags()
+{
+ QDir::setCurrent(testDataDir + "/moc-flags");
+ QCOMPARE(runQbs(), 0);
+ WAIT_FOR_NEW_TIMESTAMP();
+ QbsRunParameters params;
+ params.expectFailure = true;
+ params.arguments << "Qt.core.mocFlags:-E";
+ QVERIFY(runQbs(params) != 0);
+}
+
+void TestBlackboxQt::pluginMetaData()
+{
+ QDir::setCurrent(testDataDir + "/plugin-meta-data");
+ QCOMPARE(runQbs(), 0);
+ const QString appFilePath = relativeBuildDir() + "/install-root/"
+ + qbs::Internal::HostOsInfo::appendExecutableSuffix("plugin-meta-data");
+ QVERIFY(regularFileExists(appFilePath));
+ QProcess app;
+ app.start(appFilePath);
+ QVERIFY(app.waitForStarted());
+ QVERIFY(app.waitForFinished());
+ QVERIFY2(app.exitCode() == 0, app.readAllStandardError().constData());
+ WAIT_FOR_NEW_TIMESTAMP();
+ touch("metadata.json");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY2(m_qbsStdout.contains("moc"), m_qbsStdout.constData());
+}
+
+void TestBlackboxQt::qmlDebugging()
+{
+ QDir::setCurrent(testDataDir + "/qml-debugging");
+ QCOMPARE(runQbs(), 0);
+ const SettingsPtr s = settings();
+ Profile profile(profileName(), s.get());
+ if (!profile.value("qbs.toolchain").toStringList().contains("gcc"))
+ return;
+ QProcess nm;
+ nm.start("nm", QStringList(relativeExecutableFilePath("debuggable-app")));
+ if (nm.waitForStarted()) { // Let's ignore hosts without nm.
+ QVERIFY2(nm.waitForFinished(), qPrintable(nm.errorString()));
+ QVERIFY2(nm.exitCode() == 0, nm.readAllStandardError().constData());
+ const QByteArray output = nm.readAllStandardOutput();
+ QVERIFY2(output.toLower().contains("debugginghelper"), output.constData());
+ }
+}
+
+void TestBlackboxQt::qobjectInObjectiveCpp()
+{
+ if (!HostOsInfo::isMacosHost())
+ QSKIP("only applies on macOS");
+ const QString testDir = testDataDir + "/qobject-in-mm";
+ QDir::setCurrent(testDir);
+ QCOMPARE(runQbs(), 0);
+}
+
+void TestBlackboxQt::qtKeywords()
+{
+ QDir::setCurrent(testDataDir + "/qt-keywords");
+ QbsRunParameters params(QStringList("modules.Qt.core.enableKeywords:false"));
+ params.expectFailure = true;
+ QVERIFY(runQbs(params) != 0);
+ params.arguments.clear();
+ QVERIFY(runQbs(params) != 0);
+ params.command = "resolve";
+ QCOMPARE(runQbs(params), 0);
+ params.command = "build";
+ QCOMPARE(runQbs(params), 0);
+}
+
+void TestBlackboxQt::qtScxml()
+{
+ QDir::setCurrent(testDataDir + "/qtscxml");
+ QCOMPARE(runQbs(), 0);
+ if (m_qbsStdout.contains("QtScxml not present"))
+ QSKIP("QtScxml module not present");
+ QVERIFY2(m_qbsStdout.contains("state machine name: qbs_test_machine"),
+ m_qbsStdout.constData());
+}
+
+
+void TestBlackboxQt::staticQtPluginLinking()
+{
+ QDir::setCurrent(testDataDir + "/static-qt-plugin-linking");
+ QCOMPARE(runQbs(), 0);
+ const bool isStaticQt = m_qbsStdout.contains("Qt is static");
+ QVERIFY2(m_qbsStdout.contains("Creating static import") == isStaticQt, m_qbsStdout.constData());
+}
+
+void TestBlackboxQt::trackAddMocInclude()
+{
+ QDir::setCurrent(testDataDir + "/trackAddMocInclude");
+ if (QFile::exists("work"))
+ rmDirR("work");
+ QDir().mkdir("work");
+ ccp("before", "work");
+ QDir::setCurrent(testDataDir + "/trackAddMocInclude/work");
+ // The build must fail because the main.moc include is missing.
+ QbsRunParameters params;
+ params.expectFailure = true;
+ QVERIFY(runQbs(params) != 0);
+
+ WAIT_FOR_NEW_TIMESTAMP();
+ ccp("../after", ".");
+ touch("main.cpp");
+ QCOMPARE(runQbs(), 0);
+}
+
+void TestBlackboxQt::track_qobject_change()
+{
+ QDir::setCurrent(testDataDir + "/trackQObjChange");
+ copyFileAndUpdateTimestamp("bla_qobject.h", "bla.h");
+ QCOMPARE(runQbs(), 0);
+ const QString productFilePath = relativeExecutableFilePath("i");
+ QVERIFY2(regularFileExists(productFilePath), qPrintable(productFilePath));
+ QString moc_bla_objectFileName = relativeProductBuildDir("i") + "/.obj/"
+ + inputDirHash("qt.headers") + objectFileName("/moc_bla.cpp", profileName());
+ QVERIFY2(regularFileExists(moc_bla_objectFileName), qPrintable(moc_bla_objectFileName));
+
+ WAIT_FOR_NEW_TIMESTAMP();
+ copyFileAndUpdateTimestamp("bla_noqobject.h", "bla.h");
+ QCOMPARE(runQbs(), 0);
+ QVERIFY(regularFileExists(productFilePath));
+ QVERIFY(!QFile(moc_bla_objectFileName).exists());
+}
+
+void TestBlackboxQt::track_qrc()
+{
+ QDir::setCurrent(testDataDir + "/qrc");
+ QCOMPARE(runQbs(), 0);
+ const QString fileName = relativeExecutableFilePath("i");
+ QVERIFY2(regularFileExists(fileName), qPrintable(fileName));
+ QDateTime dt = QFileInfo(fileName).lastModified();
+ WAIT_FOR_NEW_TIMESTAMP();
+ {
+ QFile f("stuff.txt");
+ f.remove();
+ QVERIFY(f.open(QFile::WriteOnly));
+ f.write("bla");
+ f.close();
+ }
+ QCOMPARE(runQbs(), 0);
+ QVERIFY(regularFileExists(fileName));
+ QVERIFY(dt < QFileInfo(fileName).lastModified());
+}
+
+QTEST_MAIN(TestBlackboxQt)
diff --git a/tests/auto/blackbox/tst_blackboxqt.h b/tests/auto/blackbox/tst_blackboxqt.h
new file mode 100644
index 000000000..5b8ceaae4
--- /dev/null
+++ b/tests/auto/blackbox/tst_blackboxqt.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TST_BLACKBOXQT_H
+#define TST_BLACKBOXQT_H
+
+#include "tst_blackboxbase.h"
+
+class TestBlackboxQt : public TestBlackboxBase
+{
+ Q_OBJECT
+
+public:
+ TestBlackboxQt();
+
+protected:
+ void validateTestProfile() override;
+
+private slots:
+ void autoQrc();
+ void combinedMoc();
+ void createProject();
+ void dbusAdaptors();
+ void dbusInterfaces();
+ void lrelease();
+ void mixedBuildVariants();
+ void mocFlags();
+ void pluginMetaData();
+ void qmlDebugging();
+ void qobjectInObjectiveCpp();
+ void qtKeywords();
+ void qtScxml();
+ void staticQtPluginLinking();
+ void trackAddMocInclude();
+ void track_qobject_change();
+ void track_qrc();
+};
+
+#endif // TST_BLACKBOXQT_H
diff --git a/tests/auto/blackbox/tst_clangdb.cpp b/tests/auto/blackbox/tst_clangdb.cpp
index c7b85b51f..c910362a5 100644
--- a/tests/auto/blackbox/tst_clangdb.cpp
+++ b/tests/auto/blackbox/tst_clangdb.cpp
@@ -110,8 +110,8 @@ void TestClangDb::ensureBuildTreeCreated()
QCOMPARE(runQbs(), 0);
QVERIFY(QFile::exists(buildDir));
- qbs::Settings settings((QString()));
- qbs::Profile profile(profileName(), &settings);
+ const SettingsPtr s = settings();
+ qbs::Profile profile(profileName(), s.get());
if (profile.value("qbs.toolchain").toStringList().contains("msvc")) {
sanitizeOutput(&m_qbsStdout);
for (const auto &line : m_qbsStdout.split('\n')) {
@@ -199,8 +199,8 @@ void TestClangDb::checkClangDetectsSourceCodeProblems()
QSKIP("This test requires clang-check to be based on at least LLVM 3.7.0.");
// clang-check.exe does not understand MSVC command-line syntax
- qbs::Settings settings((QString()));
- qbs::Profile profile(profileName(), &settings);
+ const SettingsPtr s = settings();
+ qbs::Profile profile(profileName(), s.get());
if (profile.value("qbs.toolchain").toStringList().contains("msvc")) {
arguments << "-extra-arg-before=--driver-mode=cl";
} else if (profile.value("qbs.toolchain").toStringList().contains("mingw")) {
diff --git a/tests/auto/buildgraph/buildgraph.pro b/tests/auto/buildgraph/buildgraph.pro
index 4388aac1e..10f8c071b 100644
--- a/tests/auto/buildgraph/buildgraph.pro
+++ b/tests/auto/buildgraph/buildgraph.pro
@@ -1,6 +1,7 @@
TARGET = tst_buildgraph
SOURCES = tst_buildgraph.cpp
+HEADERS = tst_buildgraph.h
include(../auto.pri)
include(../../../src/app/shared/logging/logging.pri)
diff --git a/tests/auto/buildgraph/buildgraph.qbs b/tests/auto/buildgraph/buildgraph.qbs
index f6c1cd1f7..aa3cdc3f0 100644
--- a/tests/auto/buildgraph/buildgraph.qbs
+++ b/tests/auto/buildgraph/buildgraph.qbs
@@ -3,5 +3,8 @@ import qbs
QbsAutotest {
testName: "buildgraph"
condition: qbsbuildconfig.enableUnitTests
- files: "tst_buildgraph.cpp"
+ files: [
+ "tst_buildgraph.cpp",
+ "tst_buildgraph.h"
+ ]
}
diff --git a/tests/auto/buildgraph/tst_buildgraph.cpp b/tests/auto/buildgraph/tst_buildgraph.cpp
index be45f5f03..04d32c1fd 100644
--- a/tests/auto/buildgraph/tst_buildgraph.cpp
+++ b/tests/auto/buildgraph/tst_buildgraph.cpp
@@ -5,7 +5,7 @@
**
** This file is part of Qbs.
**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** $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
@@ -14,26 +14,133 @@
** 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 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+** 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 <app/shared/logging/consolelogger.h>
-#include <buildgraph/tst_buildgraph.h>
+#include "tst_buildgraph.h"
+
+#include <buildgraph/artifact.h>
+#include <buildgraph/buildgraph.h>
+#include <buildgraph/cycledetector.h>
+#include <buildgraph/productbuilddata.h>
+#include <buildgraph/projectbuilddata.h>
+#include <language/language.h>
+#include <logging/logger.h>
+#include <tools/error.h>
+
+#include "../shared/logging/consolelogger.h"
-#include <QtCore/qcoreapplication.h>
#include <QtTest/qtest.h>
+using namespace qbs;
+using namespace qbs::Internal;
+
+const TopLevelProjectPtr project = TopLevelProject::create();
+
+TestBuildGraph::TestBuildGraph(ILogSink *logSink) : m_logSink(logSink)
+{
+ project->buildData.reset(new ProjectBuildData);
+}
+
+void TestBuildGraph::initTestCase()
+{
+}
+
+void TestBuildGraph::cleanupTestCase()
+{
+}
+
+
+bool TestBuildGraph::cycleDetected(const ResolvedProductConstPtr &product)
+{
+ try {
+ CycleDetector(Logger(m_logSink)).visitProduct(product);
+ return false;
+ } catch (const ErrorInfo &) {
+ return true;
+ }
+}
+
+ResolvedProductConstPtr TestBuildGraph::productWithDirectCycle()
+{
+ const ResolvedProductPtr product = ResolvedProduct::create();
+ product->project = project;
+ product->buildData.reset(new ProductBuildData);
+ Artifact * const root = new Artifact;
+ root->product = product;
+ Artifact * const child = new Artifact;
+ child->product = product;
+ product->buildData->roots.insert(root);
+ product->buildData->nodes << root << child;
+ qbs::Internal::connect(root, child);
+ qbs::Internal::connect(child, root);
+ return product;
+}
+
+ResolvedProductConstPtr TestBuildGraph::productWithLessDirectCycle()
+{
+ const ResolvedProductPtr product = ResolvedProduct::create();
+ product->project = project;
+ product->buildData.reset(new ProductBuildData);
+ Artifact * const root = new Artifact;
+ Artifact * const child = new Artifact;
+ Artifact * const grandchild = new Artifact;
+ root->product = product;
+ child->product = product;
+ grandchild->product = product;
+ product->buildData->roots << root;
+ product->buildData->nodes << root << child << grandchild;
+ qbs::Internal::connect(root, child);
+ qbs::Internal::connect(child, grandchild);
+ qbs::Internal::connect(grandchild, root);
+ return product;
+}
+
+// root appears as a child, but in a different tree
+ResolvedProductConstPtr TestBuildGraph::productWithNoCycle()
+{
+ const ResolvedProductPtr product = ResolvedProduct::create();
+ product->project = project;
+ product->buildData.reset(new ProductBuildData);
+ Artifact * const root = new Artifact;
+ Artifact * const root2 = new Artifact;
+ root->product = product;
+ root2->product = product;
+ product->buildData->roots << root << root2;
+ product->buildData->nodes << root << root2;
+ qbs::Internal::connect(root2, root);
+ return product;
+}
+
+void TestBuildGraph::testCycle()
+{
+ QVERIFY(cycleDetected(productWithDirectCycle()));
+ QVERIFY(cycleDetected(productWithLessDirectCycle()));
+ QVERIFY(!cycleDetected(productWithNoCycle()));
+}
+
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
- qbs::Internal::TestBuildGraph tbg(ConsoleLogger::instance().logSink());
+ TestBuildGraph tbg(ConsoleLogger::instance().logSink());
return QTest::qExec(&tbg, argc, argv);
}
diff --git a/src/lib/corelib/buildgraph/tst_buildgraph.h b/tests/auto/buildgraph/tst_buildgraph.h
index e33037b30..756be2f0a 100644
--- a/src/lib/corelib/buildgraph/tst_buildgraph.h
+++ b/tests/auto/buildgraph/tst_buildgraph.h
@@ -42,19 +42,15 @@
#include <buildgraph/forward_decls.h>
#include <language/forward_decls.h>
#include <logging/ilogsink.h>
-#include <tools/qbs_export.h>
#include <QtCore/qlist.h>
#include <QtCore/qobject.h>
-namespace qbs {
-namespace Internal {
-
-class QBS_EXPORT TestBuildGraph : public QObject
+class TestBuildGraph : public QObject
{
Q_OBJECT
public:
- TestBuildGraph(ILogSink *logSink);
+ TestBuildGraph(qbs::ILogSink *logSink);
private slots:
void initTestCase();
@@ -62,15 +58,13 @@ private slots:
void testCycle();
private:
- ResolvedProductConstPtr productWithDirectCycle();
- ResolvedProductConstPtr productWithLessDirectCycle();
- ResolvedProductConstPtr productWithNoCycle();
- bool cycleDetected(const ResolvedProductConstPtr &product);
+ qbs::Internal::ResolvedProductConstPtr productWithDirectCycle();
+ qbs::Internal::ResolvedProductConstPtr productWithLessDirectCycle();
+ qbs::Internal::ResolvedProductConstPtr productWithNoCycle();
+ bool cycleDetected(const qbs::Internal::ResolvedProductConstPtr &product);
- ILogSink * const m_logSink;
+ qbs::ILogSink * const m_logSink;
};
-} // namespace Internal
-} // namespace qbs
-
#endif // TST_BUILDGRAPH_H
+
diff --git a/tests/auto/cmdlineparser/cmdlineparser.qbs b/tests/auto/cmdlineparser/cmdlineparser.qbs
index 774372c61..717814661 100644
--- a/tests/auto/cmdlineparser/cmdlineparser.qbs
+++ b/tests/auto/cmdlineparser/cmdlineparser.qbs
@@ -1,13 +1,13 @@
import qbs
-import QbsFunctions
QbsAutotest {
+ Depends { name: "qbsversion" }
testName: "cmdlineparser"
files: ["tst_cmdlineparser.cpp", "../../../src/app/qbs/qbstool.cpp"]
// TODO: Use Utilities.cStringQuote
cpp.defines: base.concat([
'SRCDIR="' + path + '"',
- "QBS_VERSION=\"" + QbsFunctions.qbsVersion() + "\""
+ "QBS_VERSION=\"" + qbsversion.version + "\""
])
// TODO: Make parser a static library?
diff --git a/tests/auto/language/language.pro b/tests/auto/language/language.pro
index 1206bd328..118d0f95c 100644
--- a/tests/auto/language/language.pro
+++ b/tests/auto/language/language.pro
@@ -1,10 +1,13 @@
TARGET = tst_language
SOURCES = tst_language.cpp
+HEADERS = tst_language.h
include(../auto.pri)
include(../../../src/app/shared/logging/logging.pri)
+QT += script
+
DATA_DIRS = testdata
for(data_dir, DATA_DIRS) {
diff --git a/tests/auto/language/language.qbs b/tests/auto/language/language.qbs
index b78c568a6..27f390e94 100644
--- a/tests/auto/language/language.qbs
+++ b/tests/auto/language/language.qbs
@@ -1,9 +1,21 @@
import qbs
QbsAutotest {
+ Depends { name: "qbsversion" }
+ Depends { name: "Qt.script" }
+
testName: "language"
condition: qbsbuildconfig.enableUnitTests
- files: "tst_language.cpp"
+ files: [
+ "tst_language.cpp",
+ "tst_language.h"
+ ]
+
+ // TODO: Use Utilities.cStringQuote
+ cpp.defines: base.concat([
+ 'QBS_VERSION="' + qbsversion.version + '"',
+ "SRCDIR=\"" + path + "\""
+ ])
Group {
name: "testdata"
diff --git a/tests/auto/language/testdata/conditionaldepends.qbs b/tests/auto/language/testdata/conditionaldepends.qbs
index 8ad3660ec..263237030 100644
--- a/tests/auto/language/testdata/conditionaldepends.qbs
+++ b/tests/auto/language/testdata/conditionaldepends.qbs
@@ -49,6 +49,17 @@ Project {
}
Product {
+ name: "multilevel_module_props_true"
+ Depends { name: "dummy3" }
+ dummy3.loadDummy: true
+ }
+
+ Product {
+ name: "multilevel_module_props_false"
+ Depends { name: "dummy3" }
+ }
+
+ Product {
name: "contradictory_conditions1"
Depends { condition: false; name: "dummy" }
Depends { condition: true; name: "dummy" } // this one wins
diff --git a/tests/auto/language/testdata/dependencyOnAllProfiles.qbs b/tests/auto/language/testdata/dependencyOnAllProfiles.qbs
index f3b771315..f0ca56a8a 100644
--- a/tests/auto/language/testdata/dependencyOnAllProfiles.qbs
+++ b/tests/auto/language/testdata/dependencyOnAllProfiles.qbs
@@ -6,14 +6,13 @@ Project {
Product {
name: "dep"
- profiles: [project.profile1, project.profile2]
+ qbs.profiles: [project.profile1, project.profile2]
}
Product {
name: "main"
Depends {
name: "dep"
- profiles: []
}
}
}
diff --git a/tests/auto/language/testdata/enum-project-props.qbs b/tests/auto/language/testdata/enum-project-props.qbs
new file mode 100644
index 000000000..185ab7c28
--- /dev/null
+++ b/tests/auto/language/testdata/enum-project-props.qbs
@@ -0,0 +1,14 @@
+import qbs
+
+Project {
+ property string anExistingFile: "dummy.txt"
+ Product {
+ files: {
+ for (var k in project) {
+ if (k === "anExistingFile")
+ return [project[k]];
+ }
+ return [];
+ }
+ }
+}
diff --git a/tests/auto/language/testdata/erroneous/invalid-parameter-rhs.qbs b/tests/auto/language/testdata/erroneous/invalid-parameter-rhs.qbs
new file mode 100644
index 000000000..75dc83b3e
--- /dev/null
+++ b/tests/auto/language/testdata/erroneous/invalid-parameter-rhs.qbs
@@ -0,0 +1,7 @@
+import qbs
+
+Product {
+ Depends { name: "prefix2.suffix" }
+ Depends { name: "readonly"; prefix2.suffix.nope: access.will.fail }
+}
+
diff --git a/tests/auto/language/testdata/erroneous/invalid-parameter-type.qbs b/tests/auto/language/testdata/erroneous/invalid-parameter-type.qbs
new file mode 100644
index 000000000..6a18a596c
--- /dev/null
+++ b/tests/auto/language/testdata/erroneous/invalid-parameter-type.qbs
@@ -0,0 +1,10 @@
+import qbs
+
+Product {
+ Depends { name: "module_with_parameters" }
+ Depends {
+ name: "readonly"
+ module_with_parameters.boolParameter: "This is not an error."
+ module_with_parameters.stringParameter: 123
+ }
+}
diff --git a/tests/auto/language/testdata/erroneous/mismatching-multiplex-dependency.qbs b/tests/auto/language/testdata/erroneous/mismatching-multiplex-dependency.qbs
new file mode 100644
index 000000000..4d9f7a380
--- /dev/null
+++ b/tests/auto/language/testdata/erroneous/mismatching-multiplex-dependency.qbs
@@ -0,0 +1,15 @@
+import qbs
+
+Project {
+ Product {
+ name: "a"
+ multiplexByQbsProperties: ["architectures"]
+ qbs.architectures: ["x86", "arm"]
+ }
+ Product {
+ name: "b"
+ Depends { name: "a" }
+ multiplexByQbsProperties: ["architectures"]
+ qbs.architectures: ["mips", "ppc"]
+ }
+}
diff --git a/tests/auto/language/testdata/erroneous/modules/module_with_parameters/module_with_parameters.qbs b/tests/auto/language/testdata/erroneous/modules/module_with_parameters/module_with_parameters.qbs
new file mode 100644
index 000000000..869576b01
--- /dev/null
+++ b/tests/auto/language/testdata/erroneous/modules/module_with_parameters/module_with_parameters.qbs
@@ -0,0 +1,6 @@
+Module {
+ Parameter { property bool boolParameter }
+ Parameter { property int intParameter }
+ Parameter { property stringList stringListParameter }
+ Parameter { property string stringParameter }
+}
diff --git a/tests/auto/language/testdata/erroneous/undeclared-parameter1.qbs b/tests/auto/language/testdata/erroneous/undeclared-parameter1.qbs
new file mode 100644
index 000000000..14f141678
--- /dev/null
+++ b/tests/auto/language/testdata/erroneous/undeclared-parameter1.qbs
@@ -0,0 +1,7 @@
+import qbs
+
+Product {
+ Depends { name: "prefix2.suffix" }
+ Depends { name: "readonly"; prefix2.suffix.nope: "nope" }
+}
+
diff --git a/tests/auto/language/testdata/erroneous/undeclared-parameter2.qbs b/tests/auto/language/testdata/erroneous/undeclared-parameter2.qbs
new file mode 100644
index 000000000..074acc1a3
--- /dev/null
+++ b/tests/auto/language/testdata/erroneous/undeclared-parameter2.qbs
@@ -0,0 +1,7 @@
+import qbs
+
+Product {
+ name: "myproduct"
+ Depends { name: "readonly"; foo.bar: "bla" }
+}
+
diff --git a/tests/auto/language/testdata/getNativeSetting.qbs b/tests/auto/language/testdata/getNativeSetting.qbs
index ab2943499..975aefebc 100644
--- a/tests/auto/language/testdata/getNativeSetting.qbs
+++ b/tests/auto/language/testdata/getNativeSetting.qbs
@@ -3,7 +3,8 @@ import qbs.Utilities
Project {
Product {
- name: {
+ name: "p1"
+ targetName: {
if (qbs.hostOS.contains("macos")) {
return Utilities.getNativeSetting("/System/Library/CoreServices/SystemVersion.plist", "ProductName");
} else if (qbs.hostOS.contains("windows")) {
@@ -19,6 +20,7 @@ Project {
}
Product {
- name: Utilities.getNativeSetting("/dev/null", undefined, "fallback");
+ name: "p2"
+ targetName: Utilities.getNativeSetting("/dev/null", undefined, "fallback");
}
}
diff --git a/tests/auto/language/testdata/module-property-overrides-per-product.qbs b/tests/auto/language/testdata/module-property-overrides-per-product.qbs
new file mode 100644
index 000000000..e58f563a0
--- /dev/null
+++ b/tests/auto/language/testdata/module-property-overrides-per-product.qbs
@@ -0,0 +1,16 @@
+import qbs
+
+Project {
+ Product {
+ Depends { name: "dummy" }
+ name: "a"
+ }
+ Product {
+ Depends { name: "dummy" }
+ name: "b"
+ }
+ Product {
+ Depends { name: "dummy" }
+ name: "c"
+ }
+}
diff --git a/tests/auto/language/testdata/modules/dummy3/dummy3.qbs b/tests/auto/language/testdata/modules/dummy3/dummy3.qbs
new file mode 100644
index 000000000..c7451693f
--- /dev/null
+++ b/tests/auto/language/testdata/modules/dummy3/dummy3.qbs
@@ -0,0 +1,4 @@
+Module {
+ property bool loadDummy: false
+ Depends { name: "dummy"; condition: loadDummy }
+}
diff --git a/tests/auto/language/testdata/parameter-types.qbs b/tests/auto/language/testdata/parameter-types.qbs
new file mode 100644
index 000000000..6406d56c9
--- /dev/null
+++ b/tests/auto/language/testdata/parameter-types.qbs
@@ -0,0 +1,19 @@
+import qbs
+
+Project {
+ Product {
+ name: "foo"
+ qbsSearchPaths: "./erroneous"
+ Depends { name: "module_with_parameters" }
+ Depends {
+ name: "bar"
+ module_with_parameters.boolParameter: true
+ module_with_parameters.intParameter: 156
+ module_with_parameters.stringParameter: "hello"
+ module_with_parameters.stringListParameter: ["la", "le", "lu"]
+ }
+ }
+ Product {
+ name: "bar"
+ }
+}
diff --git a/tests/auto/language/testdata/profilevaluesandoverriddenvalues.qbs b/tests/auto/language/testdata/profilevaluesandoverriddenvalues.qbs
index 156f9f1bb..1cb88e18f 100644
--- a/tests/auto/language/testdata/profilevaluesandoverriddenvalues.qbs
+++ b/tests/auto/language/testdata/profilevaluesandoverriddenvalues.qbs
@@ -3,14 +3,14 @@ import qbs 1.0
Project {
Application {
name: "product1"
- type: {
+ property bool dummyProp: {
if (!(dummy.cFlags instanceof Array))
throw new Error("dummy.cFlags: Array type expected.");
if (!(dummy.cxxFlags instanceof Array))
throw new Error("dummy.cxxFlags: Array type expected.");
if (!(dummy.defines instanceof Array))
throw new Error("dummy.defines: Array type expected.");
- return "application";
+ return true;
}
consoleApplication: true
Depends { name: "dummy" }
diff --git a/tests/auto/language/tst_language.cpp b/tests/auto/language/tst_language.cpp
index 2c59e0a07..702621871 100644
--- a/tests/auto/language/tst_language.cpp
+++ b/tests/auto/language/tst_language.cpp
@@ -5,7 +5,7 @@
**
** This file is part of Qbs.
**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** $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
@@ -14,30 +14,2455 @@
** 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 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+** 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 <language/tst_language.h>
+#undef QT_NO_CAST_FROM_ASCII // I am qmake, and I approve this hack.
+
+#include "tst_language.h"
+
+#include "../shared.h"
+
+#include <language/evaluator.h>
+#include <language/filecontext.h>
+#include <language/identifiersearch.h>
+#include <language/item.h>
+#include <language/itempool.h>
+#include <language/language.h>
+#include <language/propertymapinternal.h>
+#include <language/scriptengine.h>
+#include <language/value.h>
+#include <parser/qmljslexer_p.h>
+#include <parser/qmljsparser_p.h>
+#include <tools/scripttools.h>
+#include <tools/error.h>
+#include <tools/fileinfo.h>
+#include <tools/hostosinfo.h>
+#include <tools/jsliterals.h>
+#include <tools/profile.h>
+#include <tools/settings.h>
+
+#include "../shared/logging/consolelogger.h"
+
+#include <QtCore/qprocess.h>
+
+#include <algorithm>
+#include <utility>
+#include <vector>
+
+Q_DECLARE_METATYPE(QList<bool>)
+
+using namespace qbs;
+using namespace qbs::Internal;
+
+static QString testDataDir() {
+ return FileInfo::resolvePath(QLatin1String(SRCDIR),
+ QLatin1String("../../../tests/auto/language/testdata"));
+}
+static QString testProject(const char *fileName) {
+ return testDataDir() + QLatin1Char('/') + QLatin1String(fileName);
+}
+
+TestLanguage::TestLanguage(ILogSink *logSink, Settings *settings)
+ : m_logSink(logSink)
+ , m_settings(settings)
+ , m_wildcardsTestDirPath(QDir::tempPath() + QLatin1String("/_wildcards_test_dir_"))
+{
+ qsrand(QTime::currentTime().msec());
+ qRegisterMetaType<QList<bool> >("QList<bool>");
+ defaultParameters.setBuildRoot("/some/build/directory");
+ defaultParameters.setPropertyCheckingMode(ErrorHandlingMode::Strict);
+ defaultParameters.setSettingsDirectory(m_settings->baseDirectory());
+}
+
+TestLanguage::~TestLanguage()
+{
+}
+
+QHash<QString, ResolvedProductPtr> TestLanguage::productsFromProject(ResolvedProjectPtr project)
+{
+ QHash<QString, ResolvedProductPtr> result;
+ foreach (const ResolvedProductPtr &product, project->allProducts())
+ result.insert(product->name, product);
+ return result;
+}
+
+ResolvedModuleConstPtr TestLanguage::findModuleByName(ResolvedProductPtr product, const QString &name)
+{
+ foreach (const ResolvedModuleConstPtr &module, product->modules)
+ if (module->name == name)
+ return module;
+ return ResolvedModuleConstPtr();
+}
+
+QVariant TestLanguage::productPropertyValue(ResolvedProductPtr product, QString propertyName)
+{
+ QStringList propertyNameComponents = propertyName.split(QLatin1Char('.'));
+ if (propertyNameComponents.count() > 1) {
+ propertyNameComponents.prepend(QLatin1String("modules"));
+ return product->moduleProperties->property(propertyNameComponents);
+ }
+ return getConfigProperty(product->productProperties, propertyNameComponents);
+}
+
+void TestLanguage::handleInitCleanupDataTags(const char *projectFileName, bool *handled)
+{
+ const QByteArray dataTag = QTest::currentDataTag();
+ if (dataTag == "init") {
+ *handled = true;
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject(projectFileName));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+ } else if (dataTag == "cleanup") {
+ *handled = true;
+ project.reset();
+ } else {
+ *handled = false;
+ }
+}
+
+void TestLanguage::init()
+{
+ m_logSink->setLogLevel(LoggerInfo);
+}
+
+#define HANDLE_INIT_CLEANUP_DATATAGS(fn) {\
+ bool handled;\
+ handleInitCleanupDataTags(fn, &handled);\
+ if (handled)\
+ return;\
+ QVERIFY(!!project);\
+}
+
+void TestLanguage::initTestCase()
+{
+ m_logger = Logger(m_logSink);
+ m_engine = new ScriptEngine(m_logger, EvalContext::PropertyEvaluation, this);
+ loader = new Loader(m_engine, m_logger);
+ loader->setSearchPaths(QStringList()
+ << QLatin1String(SRCDIR "/../../../share/qbs"));
+ defaultParameters.setTopLevelProfile(profileName());
+ defaultParameters.setConfigurationName("default");
+ defaultParameters.expandBuildConfiguration();
+ defaultParameters.setEnvironment(QProcessEnvironment::systemEnvironment());
+ QVERIFY(QFileInfo(m_wildcardsTestDirPath).isAbsolute());
+}
+
+void TestLanguage::cleanupTestCase()
+{
+ delete loader;
+}
+
+void TestLanguage::baseProperty()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("baseproperty.qbs"));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value("product1");
+ QVERIFY(!!product);
+ QVariantMap cfg = product->productProperties;
+ QCOMPARE(cfg.value("narf").toStringList(), QStringList() << "boo");
+ QCOMPARE(cfg.value("zort").toStringList(), QStringList() << "bar" << "boo");
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::baseValidation()
+{
+ qbs::SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("base-validate/base-validate.qbs"));
+ try {
+ project = loader->loadProject(params);
+ QVERIFY2(false, "exception expected");
+ } catch (const qbs::ErrorInfo &e) {
+ QVERIFY2(e.toString().contains("Parent succeeded, child failed."),
+ qPrintable(e.toString()));
+ }
+}
+
+void TestLanguage::buildConfigStringListSyntax()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters parameters = defaultParameters;
+ QVariantMap overriddenValues;
+ overriddenValues.insert("project.someStrings", "foo,bar,baz");
+ parameters.setOverriddenValues(overriddenValues);
+ parameters.setProjectFilePath(testProject("buildconfigstringlistsyntax.qbs"));
+ project = loader->loadProject(parameters);
+ QVERIFY(!!project);
+ QCOMPARE(project->projectProperties().value("someStrings").toStringList(),
+ QStringList() << "foo" << "bar" << "baz");
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::builtinFunctionInSearchPathsProperty()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters parameters = defaultParameters;
+ parameters.setProjectFilePath(testProject("builtinFunctionInSearchPathsProperty.qbs"));
+ QVERIFY(!!loader->loadProject(parameters));
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::chainedProbes()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters parameters = defaultParameters;
+ parameters.setProjectFilePath(testProject("chained-probes/chained-probes.qbs"));
+ const TopLevelProjectConstPtr project = loader->loadProject(parameters);
+ QVERIFY(!!project);
+ QCOMPARE(project->products.count(), 1);
+ const QString prop2Val = project->products.first()->moduleProperties
+ ->moduleProperty("m", "prop2").toString();
+ QCOMPARE(prop2Val, QLatin1String("probe1Valprobe2Val"));
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+
+}
+
+void TestLanguage::versionCompare()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters parameters = defaultParameters;
+ parameters.setProjectFilePath(testProject("versionCompare.qbs"));
+ QVERIFY(!!loader->loadProject(parameters));
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::canonicalArchitecture()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("canonicalArchitecture.qbs"));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value(QLatin1String("x86"));
+ QVERIFY(!!product);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::rfc1034Identifier()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("rfc1034identifier.qbs"));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value(QLatin1String("this-has-special-characters-"
+ "uh-oh-Undersc0r3s-Are.Bad"));
+ QVERIFY(!!product);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::conditionalDepends()
+{
+ bool exceptionCaught = false;
+ ResolvedProductPtr product;
+ ResolvedModuleConstPtr dependency;
+ try {
+ defaultParameters.setProjectFilePath(testProject("conditionaldepends.qbs"));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+
+ product = products.value("conditionaldepends_derived");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QVERIFY(!!dependency);
+
+ product = products.value("conditionaldepends_derived_false");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QCOMPARE(dependency, ResolvedModuleConstPtr());
+
+ product = products.value("product_props_true");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QVERIFY(!!dependency);
+
+ product = products.value("product_props_false");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QCOMPARE(dependency, ResolvedModuleConstPtr());
+
+ product = products.value("project_props_true");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QVERIFY(!!dependency);
+
+ product = products.value("project_props_false");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QCOMPARE(dependency, ResolvedModuleConstPtr());
+
+ product = products.value("module_props_true");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy2");
+ QVERIFY(!!dependency);
+ dependency = findModuleByName(product, "dummy");
+ QVERIFY(!!dependency);
+
+ product = products.value("module_props_false");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy2");
+ QVERIFY(!!dependency);
+ dependency = findModuleByName(product, "dummy");
+ QCOMPARE(dependency, ResolvedModuleConstPtr());
+
+ product = products.value("multilevel_module_props_true");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy3");
+ QVERIFY(!!dependency);
+ dependency = findModuleByName(product, "dummy");
+ QEXPECT_FAIL("", "This is broken. Sad!", Continue);
+ QVERIFY(!!dependency);
+
+ product = products.value("multilevel_module_props_false");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy3");
+ QVERIFY(!!dependency);
+ dependency = findModuleByName(product, "dummy");
+ QCOMPARE(dependency, ResolvedModuleConstPtr());
+
+ product = products.value("contradictory_conditions1");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QVERIFY(!!dependency);
+
+ product = products.value("contradictory_conditions2");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "dummy");
+ QVERIFY(!!dependency);
+
+ product = products.value("unknown_dependency_condition_false");
+ QVERIFY(!!product);
+ dependency = findModuleByName(product, "doesonlyexistifhellfreezesover");
+ QVERIFY(!dependency);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::delayedError()
+{
+ QFETCH(bool, productEnabled);
+ try {
+ QFETCH(QString, projectFileName);
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject(projectFileName.toLatin1()));
+ QVariantMap overriddenValues;
+ overriddenValues.insert("project.enableProduct", productEnabled);
+ params.setOverriddenValues(overriddenValues);
+ project = loader->loadProject(params);
+ QCOMPARE(productEnabled, false);
+ QVERIFY(!!project);
+ QCOMPARE(project->products.count(), 1);
+ const ResolvedProductConstPtr theProduct = productsFromProject(project).value("theProduct");
+ QVERIFY(!!theProduct);
+ QCOMPARE(theProduct->enabled, false);
+ } catch (const ErrorInfo &e) {
+ if (!productEnabled)
+ qDebug() << e.toString();
+ QCOMPARE(productEnabled, true);
+ }
+}
+
+void TestLanguage::delayedError_data()
+{
+ QTest::addColumn<QString>("projectFileName");
+ QTest::addColumn<bool>("productEnabled");
+ QTest::newRow("product enabled, module validation error")
+ << "delayed-error/validation.qbs" << true;
+ QTest::newRow("product disabled, module validation error")
+ << "delayed-error/validation.qbs" << false;
+ QTest::newRow("product enabled, module not found")
+ << "delayed-error/nonexisting.qbs" << true;
+ QTest::newRow("product disabled, module not found")
+ << "delayed-error/nonexisting.qbs" << false;
+}
+
+void TestLanguage::dependencyOnAllProfiles()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("dependencyOnAllProfiles.qbs"));
+ TemporaryProfile p1("p1", m_settings);
+ p1.p.setValue("qbs.architecture", "arch1");
+ TemporaryProfile p2("p2", m_settings);
+ p2.p.setValue("qbs.architecture", "arch2");
+ QVariantMap overriddenValues;
+ overriddenValues.insert("project.profile1", "p1");
+ overriddenValues.insert("project.profile2", "p2");
+ params.setOverriddenValues(overriddenValues);
+ project = loader->loadProject(params);
+ QVERIFY(!!project);
+ QCOMPARE(project->products.count(), 3);
+ const ResolvedProductConstPtr mainProduct = productsFromProject(project).value("main");
+ QVERIFY(!!mainProduct);
+ QCOMPARE(mainProduct->dependencies.count(), 2);
+ foreach (const ResolvedProductConstPtr &p, mainProduct->dependencies) {
+ QCOMPARE(p->name, QLatin1String("dep"));
+ QVERIFY(p->profile == "p1" || p->profile == "p2");
+ }
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::derivedSubProject()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("derived-sub-project/project.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::enumerateProjectProperties()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("enum-project-props.qbs"));
+ auto project = loader->loadProject(params);
+ QVERIFY(!!project);
+ auto products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+ auto product = products.values().first();
+ auto files = product->groups.first()->allFiles();
+ QCOMPARE(product->groups.count(), 1);
+ QCOMPARE(files.count(), 1);
+ auto fileName = FileInfo::fileName(files.first()->absoluteFilePath);
+ QCOMPARE(fileName, QString("dummy.txt"));
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::defaultValue()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("defaultvalue/egon.qbs"));
+ QFETCH(QString, prop1Value);
+ QVariantMap overridden;
+ if (!prop1Value.isEmpty())
+ overridden.insert("modules.lower.prop1", prop1Value);
+ params.setOverriddenValues(overridden);
+ TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 2);
+ const ResolvedProductPtr product = products.value("egon");
+ QVERIFY(!!product);
+ QStringList propertyName = QStringList() << "modules" << "lower" << "prop2";
+ QVariant propertyValue = product->moduleProperties->property(propertyName);
+ QFETCH(QVariant, expectedProp2Value);
+ QCOMPARE(propertyValue, expectedProp2Value);
+ propertyName = QStringList() << "modules" << "lower" << "listProp";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QFETCH(QVariant, expectedListPropValue);
+ QCOMPARE(propertyValue.toStringList(), expectedListPropValue.toStringList());
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::defaultValue_data()
+{
+ QTest::addColumn<QString>("prop1Value");
+ QTest::addColumn<QVariant>("expectedProp2Value");
+ QTest::addColumn<QVariant>("expectedListPropValue");
+ QTest::newRow("controlling property with random value") << "random" << QVariant("withoutBlubb")
+ << QVariant(QStringList({"other"}));
+ QTest::newRow("controlling property with blubb value") << "blubb" << QVariant("withBlubb")
+ << QVariant(QStringList({"blubb", "other"}));
+ QTest::newRow("controlling property with egon value") << "egon" << QVariant("withEgon")
+ << QVariant(QStringList({"egon", "other"}));
+ QTest::newRow("controlling property not overwritten") << "" << QVariant("withBlubb")
+ << QVariant(QStringList({"blubb", "other"}));
+}
+
+void TestLanguage::environmentVariable()
+{
+ bool exceptionCaught = false;
+ try {
+ // Create new environment:
+ const QString varName = QLatin1String("PRODUCT_NAME");
+ const QString productName = QLatin1String("MyApp") + QString::number(qrand());
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert(varName, productName);
+
+ QProcessEnvironment origEnv = defaultParameters.environment(); // store orig environment
+
+ defaultParameters.setEnvironment(env);
+ defaultParameters.setProjectFilePath(testProject("environmentvariable.qbs"));
+ project = loader->loadProject(defaultParameters);
+
+ defaultParameters.setEnvironment(origEnv); // reset environment
+
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value(productName);
+ QVERIFY(!!product);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::erroneousFiles_data()
+{
+ QTest::addColumn<QString>("errorMessage");
+ QTest::newRow("unknown_module")
+ << "Dependency 'neitherModuleNorProduct' not found";
+ QTest::newRow("multiple_exports")
+ << "Multiple Export items in one product are prohibited.";
+ QTest::newRow("multiple_properties_in_subproject")
+ << "Multiple instances of item 'Properties' found where at most one "
+ "is allowed.";
+ QTest::newRow("importloop1")
+ << "Loop detected when importing";
+ QTest::newRow("nonexistentouter")
+ << "Can't find variable: outer";
+ QTest::newRow("invalid_file")
+ << "does not exist";
+ QTest::newRow("invalid-parameter-rhs")
+ << "ReferenceError: Can't find variable: access";
+ QTest::newRow("invalid-parameter-type")
+ << "Value assigned to property 'stringParameter' does not have type 'string'.";
+ QTest::newRow("invalid_property_type")
+ << "Unknown type 'nonsense' in property declaration.";
+ QTest::newRow("reserved_name_in_import")
+ << "Cannot reuse the name of built-in extension 'TextFile'.";
+ QTest::newRow("throw_in_property_binding")
+ << "something is wrong";
+ QTest::newRow("dependency_cycle")
+ << "Cyclic dependencies detected.";
+ QTest::newRow("dependency_cycle2")
+ << "Cyclic dependencies detected.";
+ QTest::newRow("dependency_cycle3")
+ << "Cyclic dependencies detected.";
+ QTest::newRow("dependency_cycle4")
+ << "Cyclic dependencies detected.";
+ QTest::newRow("references_cycle")
+ << "Cycle detected while referencing file 'references_cycle.qbs'.";
+ QTest::newRow("subproject_cycle")
+ << "Cycle detected while loading subproject file 'subproject_cycle.qbs'.";
+ QTest::newRow("invalid_stringlist_element")
+ << "Element at index 1 of list property 'files' does not have string type.";
+ QTest::newRow("undefined_stringlist_element")
+ << "Element at index 1 of list property 'files' is undefined. String expected.";
+ QTest::newRow("undeclared_item")
+ << "Item 'cpp' is not declared.";
+ QTest::newRow("undeclared-parameter1")
+ << "Parameter 'prefix2.suffix.nope' is not declared.";
+ QTest::newRow("undeclared-parameter2")
+ << "Cannot set parameter 'foo.bar', "
+ "because 'myproduct' does not have a dependency on 'foo'.";
+ QTest::newRow("undeclared_property_wrapper")
+ << "Property 'doesntexist' is not declared.";
+ QTest::newRow("undeclared_property_in_export_item")
+ << "Property 'blubb' is not declared.";
+ QTest::newRow("undeclared_property_in_export_item2")
+ << "Item 'something' is not declared.";
+ QTest::newRow("undeclared_property_in_export_item3")
+ << "Property 'blubb' is not declared.";
+ QTest::newRow("unknown_item_type")
+ << "Unexpected item type 'Narf'";
+ QTest::newRow("invalid_child_item_type")
+ << "Items of type 'Project' cannot contain items of type 'Depends'.";
+ QTest::newRow("conflicting_fileTagsFilter")
+ << "Conflicting fileTagsFilter in Group items";
+ QTest::newRow("duplicate_sources")
+ << "Duplicate source file '.*main.cpp'"
+ ".*duplicate_sources.qbs:4:12.*duplicate_sources.qbs:6:16.";
+ QTest::newRow("duplicate_sources_wildcards")
+ << "Duplicate source file '.*duplicate_sources_wildcards.qbs'"
+ ".*duplicate_sources_wildcards.qbs:4:12"
+ ".*duplicate_sources_wildcards.qbs:6:16.";
+ QTest::newRow("oldQbsVersion")
+ << "The project requires at least qbs version \\d+\\.\\d+.\\d+, "
+ "but this is qbs version " QBS_VERSION ".";
+ QTest::newRow("wrongQbsVersionFormat")
+ << "The value '.*' of Project.minimumQbsVersion is not a valid version string.";
+ QTest::newRow("properties-item-with-invalid-condition")
+ << "TypeError: Result of expression 'cpp.nonexistingproperty'";
+ QTest::newRow("misused-inherited-property") << "Binding to non-item property";
+ QTest::newRow("undeclared_property_in_Properties_item") << "Item 'blubb' is not declared";
+ QTest::newRow("same-module-prefix1") << "The name of module 'prefix1' is equal to the first "
+ "component of the name of module 'prefix1.suffix'";
+ QTest::newRow("same-module-prefix2") << "The name of module 'prefix2' is equal to the first "
+ "component of the name of module 'prefix2.suffix'";
+ QTest::newRow("conflicting-properties-in-export-items")
+ << "Export item in inherited item redeclares property 'theProp' with different type.";
+ QTest::newRow("invalid-property-option")
+ << "PropertyOptions item refers to non-existing property 's0meProp'";
+ QTest::newRow("missing-colon")
+ << "Invalid item 'cpp.dynamicLibraries'. Did you mean to set a module property?";
+ QTest::newRow("wrong-toplevel-item")
+ << "wrong-toplevel-item.qbs:3:1.*The top-level item must be of type 'Project' or "
+ "'Product', but it is of type 'Artifact'.";
+ QTest::newRow("module-depends-on-product")
+ << "module-with-product-dependency.qbs:4:5.*Modules cannot depend on products.";
+ QTest::newRow("overwrite-inherited-readonly-property")
+ << "overwrite-inherited-readonly-property.qbs"
+ ":4:21.*Cannot set read-only property 'readOnlyString'.";
+ QTest::newRow("overwrite-readonly-module-property")
+ << "overwrite-readonly-module-property.qbs"
+ ":5:30.*Cannot set read-only property 'readOnlyString'.";
+ QTest::newRow("mismatching-multiplex-dependency")
+ << "mismatching-multiplex-dependency.qbs:9:5 Dependency from product 'b' to "
+ "product 'a' not fulfilled.\nNo product 'a' found with a matching multiplex "
+ "configuration:\n\tqbs.architecture: mips";
+}
+
+void TestLanguage::erroneousFiles()
+{
+ QFETCH(QString, errorMessage);
+ QString fileName = QString::fromLocal8Bit(QTest::currentDataTag()) + QLatin1String(".qbs");
+ try {
+ defaultParameters.setProjectFilePath(testProject("/erroneous/") + fileName);
+ loader->loadProject(defaultParameters);
+ } catch (const ErrorInfo &e) {
+ if (!e.toString().contains(QRegExp(errorMessage))) {
+ qDebug() << "Message: " << e.toString();
+ qDebug() << "Expected: " << errorMessage;
+ QFAIL("Unexpected error message.");
+ }
+ return;
+ }
+ QEXPECT_FAIL("undeclared_property_in_Properties_item", "Too expensive to check", Continue);
+ QVERIFY(!"No error thrown on invalid input.");
+}
+
+void TestLanguage::exports()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("exports.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 17);
+ ResolvedProductPtr product;
+ product = products.value("myapp");
+ QVERIFY(!!product);
+ QStringList propertyName = QStringList() << "modules" << "dummy" << "defines";
+ QVariant propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYAPP" << "USE_MYLIB"
+ << "USE_MYLIB2");
+ propertyName = QStringList() << "modules" << "dummy" << "includePaths";
+ QVariantList propertyValues = product->moduleProperties->property(propertyName).toList();
+ QCOMPARE(propertyValues.count(), 3);
+ QVERIFY(propertyValues.at(0).toString().endsWith("/app"));
+ QVERIFY(propertyValues.at(1).toString().endsWith("/subdir/lib"));
+ QVERIFY(propertyValues.at(2).toString().endsWith("/subdir2/lib"));
+
+ QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(),
+ QString("myapp"));
+
+ product = products.value("mylib");
+ QVERIFY(!!product);
+ propertyName = QStringList() << "modules" << "dummy" << "defines";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYLIB");
+
+ product = products.value("mylib2");
+ QVERIFY(!!product);
+ propertyName = QStringList() << "modules" << "dummy" << "defines";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(), QStringList() << "BUILD_MYLIB2");
+
+ product = products.value("A");
+ QVERIFY(!!product);
+ QVERIFY(product->dependencies.contains(products.value("B")));
+ QVERIFY(product->dependencies.contains(products.value("C")));
+ QVERIFY(product->dependencies.contains(products.value("D")));
+ product = products.value("B");
+ QVERIFY(!!product);
+ QVERIFY(product->dependencies.isEmpty());
+ product = products.value("C");
+ QVERIFY(!!product);
+ QVERIFY(product->dependencies.isEmpty());
+ product = products.value("D");
+ QVERIFY(!!product);
+ QVERIFY(product->dependencies.isEmpty());
+
+ product = products.value("myapp2");
+ QVERIFY(!!product);
+ propertyName = QStringList() << "modules" << "dummy" << "cFlags";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(), QStringList()
+ << "BASE_PRODUCTWITHINHERITEDEXPORTITEM"
+ << "PRODUCT_PRODUCTWITHINHERITEDEXPORTITEM");
+ propertyName = QStringList() << "modules" << "dummy" << "cxxFlags";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(), QStringList() << "-bar");
+ propertyName = QStringList() << "modules" << "dummy" << "defines";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(), QStringList() << "ABC");
+ QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(),
+ QString("myapp2"));
+ QCOMPARE(product->moduleProperties->moduleProperty("dummy",
+ "upperCaseProductName").toString(), QString("MYAPP2"));
+
+ // Check whether we're returning incorrect cached values.
+ product = products.value("myapp3");
+ QVERIFY(!!product);
+ QCOMPARE(product->moduleProperties->moduleProperty("dummy", "productName").toString(),
+ QString("myapp3"));
+ QCOMPARE(product->moduleProperties->moduleProperty("dummy",
+ "upperCaseProductName").toString(), QString("MYAPP3"));
+
+ // Verify we refer to the right "project" variable.
+ product = products.value("sub p2");
+ QVERIFY(!!product);
+ QCOMPARE(product->moduleProperties->moduleProperty("dummy", "someString").toString(),
+ QString("sub1"));
+
+ product = products.value("libE");
+ QVERIFY(!!product);
+ propertyName = QStringList() << "modules" << "dummy" << "defines";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toStringList(),
+ QStringList() << "LIBA" << "LIBB" << "LIBC" << "LIBD");
+ propertyName = QStringList() << "modules" << "dummy" << "productName";
+ propertyValue = product->moduleProperties->property(propertyName);
+ QCOMPARE(propertyValue.toString(), QString("libE"));
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::fileContextProperties()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("filecontextproperties.qbs"));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value("product1");
+ QVERIFY(!!product);
+ QVariantMap cfg = product->productProperties;
+ QCOMPARE(cfg.value("narf").toString(), defaultParameters.projectFilePath());
+ QString dirPath = QFileInfo(defaultParameters.projectFilePath()).absolutePath();
+ QCOMPARE(cfg.value("zort").toString(), dirPath);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::getNativeSetting()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("getNativeSetting.qbs"));
+ project = loader->loadProject(defaultParameters);
+
+ QString expectedTargetName;
+ if (HostOsInfo::isMacosHost())
+ expectedTargetName = QLatin1String("Mac OS X");
+ else if (HostOsInfo::isWindowsHost())
+ expectedTargetName = QLatin1String("Windows");
+ else
+ expectedTargetName = QLatin1String("Unix");
+
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products;
+ for (const ResolvedProductPtr &product : project->allProducts())
+ products.insert(product->targetName, product);
+ ResolvedProductPtr product = products.value(expectedTargetName);
+ QVERIFY(!!product);
+ ResolvedProductPtr product2 = products.value(QLatin1String("fallback"));
+ QVERIFY(!!product2);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::groupConditions_data()
+{
+ QTest::addColumn<int>("groupCount");
+ QTest::addColumn<QList<bool> >("groupEnabled");
+ QTest::newRow("init") << 0 << QList<bool>();
+ QTest::newRow("no_condition_no_group")
+ << 1 << (QList<bool>() << true);
+ QTest::newRow("no_condition")
+ << 2 << (QList<bool>() << true << true);
+ QTest::newRow("true_condition")
+ << 2 << (QList<bool>() << true << true);
+ QTest::newRow("false_condition")
+ << 2 << (QList<bool>() << true << false);
+ QTest::newRow("true_condition_from_product")
+ << 2 << (QList<bool>() << true << true);
+ QTest::newRow("true_condition_from_project")
+ << 2 << (QList<bool>() << true << true);
+ QTest::newRow("condition_accessing_module_property")
+ << 2 << (QList<bool>() << true << false);
+ QTest::newRow("cleanup") << 0 << QList<bool>();
+}
+
+void TestLanguage::groupConditions()
+{
+ HANDLE_INIT_CLEANUP_DATATAGS("groupconditions.qbs");
+ QFETCH(int, groupCount);
+ QFETCH(QList<bool>, groupEnabled);
+ QCOMPARE(groupCount, groupEnabled.count());
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
+ ResolvedProductPtr product = products.value(productName);
+ QVERIFY(!!product);
+ QCOMPARE(product->name, productName);
+ QCOMPARE(product->groups.count(), groupCount);
+ for (int i = 0; i < groupCount; ++i) {
+ if (product->groups.at(i)->enabled != groupEnabled.at(i)) {
+ QFAIL(qPrintable(
+ QString("groups.at(%1)->enabled != %2").arg(i).arg(groupEnabled.at(i))));
+ }
+ }
+}
+
+void TestLanguage::groupName()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("groupname.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 2);
+
+ ResolvedProductPtr product = products.value("MyProduct");
+ QVERIFY(!!product);
+ QCOMPARE(product->groups.count(), 2);
+ GroupConstPtr group = product->groups.at(0);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, QString("MyProduct"));
+ group = product->groups.at(1);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, QString("MyProduct.MyGroup"));
+
+ product = products.value("My2ndProduct");
+ QVERIFY(!!product);
+ QCOMPARE(product->groups.count(), 3);
+ group = product->groups.at(0);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, QString("My2ndProduct"));
+ group = product->groups.at(1);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, QString("My2ndProduct.MyGroup"));
+ group = product->groups.at(2);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, QString("Group 2"));
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::homeDirectory()
+{
+ try {
+ defaultParameters.setProjectFilePath(testProject("homeDirectory.qbs"));
+ ResolvedProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+
+ ResolvedProductPtr product = products.value("home");
+ QVERIFY(!!product);
+
+ QDir dir = QDir::home();
+ QCOMPARE(product->productProperties.value("home").toString(), dir.path());
+ QCOMPARE(product->productProperties.value("homeSlash").toString(), dir.path());
+
+ dir.cdUp();
+ QCOMPARE(product->productProperties.value("homeUp").toString(), dir.path());
+
+ dir = QDir::home();
+ QCOMPARE(product->productProperties.value("homeFile").toString(),
+ dir.filePath("a"));
+
+ QCOMPARE(product->productProperties.value("bogus1").toString(),
+ FileInfo::resolvePath(product->sourceDirectory, QLatin1String("a~b")));
+ QCOMPARE(product->productProperties.value("bogus2").toString(),
+ FileInfo::resolvePath(product->sourceDirectory, QLatin1String("a/~/bb")));
+ QCOMPARE(product->productProperties.value("user").toString(),
+ FileInfo::resolvePath(product->sourceDirectory, QLatin1String("~foo/bar")));
+ }
+ catch (const ErrorInfo &e) {
+ qDebug() << e.toString();
+ }
+}
+
+void TestLanguage::identifierSearch_data()
+{
+ QTest::addColumn<bool>("expectedHasNarf");
+ QTest::addColumn<bool>("expectedHasZort");
+ QTest::addColumn<QString>("sourceCode");
+ QTest::newRow("no narf, no zort") << false << false << QString(
+ "Product {\n"
+ " name: {\n"
+ " var foo = 'bar';\n"
+ " console.info(foo);\n"
+ " return foo;\n"
+ " }\n"
+ "}\n");
+ QTest::newRow("narf, no zort") << true << false << QString(
+ "Product {\n"
+ " name: {\n"
+ " var foo = 'zort';\n"
+ " console.info(narf + foo);\n"
+ " return foo;\n"
+ " }\n"
+ "}\n");
+ QTest::newRow("no narf, zort") << false << true << QString(
+ "Product {\n"
+ " name: {\n"
+ " var foo = 'narf';\n"
+ " console.info(zort + foo);\n"
+ " return foo;\n"
+ " }\n"
+ "}\n");
+ QTest::newRow("narf, zort") << true << true << QString(
+ "Product {\n"
+ " name: {\n"
+ " var foo = narf;\n"
+ " foo = foo + zort;\n"
+ " return foo;\n"
+ " }\n"
+ "}\n");
+ QTest::newRow("2 narfs, 1 zort") << true << true << QString(
+ "Product {\n"
+ " name: {\n"
+ " var foo = narf;\n"
+ " foo = narf + foo + zort;\n"
+ " return foo;\n"
+ " }\n"
+ "}\n");
+}
+
+void TestLanguage::identifierSearch()
+{
+ QFETCH(bool, expectedHasNarf);
+ QFETCH(bool, expectedHasZort);
+ QFETCH(QString, sourceCode);
+
+ bool hasNarf = !expectedHasNarf;
+ bool hasZort = !expectedHasZort;
+ IdentifierSearch isearch;
+ isearch.add("narf", &hasNarf);
+ isearch.add("zort", &hasZort);
-#include <app/shared/logging/consolelogger.h>
+ QbsQmlJS::Engine engine;
+ QbsQmlJS::Lexer lexer(&engine);
+ lexer.setCode(sourceCode, 1);
+ QbsQmlJS::Parser parser(&engine);
+ QVERIFY(parser.parse());
+ QVERIFY(parser.ast());
+ isearch.start(parser.ast());
+ QCOMPARE(hasNarf, expectedHasNarf);
+ QCOMPARE(hasZort, expectedHasZort);
+}
+
+void TestLanguage::idUsage()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("idusage.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 4);
+ QVERIFY(products.contains("product1_1"));
+ QVERIFY(products.contains("product2_2"));
+ QVERIFY(products.contains("product3_3"));
+ ResolvedProductPtr product4 = products.value("product4_4");
+ QVERIFY(!!product4);
+ QEXPECT_FAIL("", "QBS-1016", Continue);
+ QCOMPARE(product4->productProperties.value("productName").toString(), product4->name);
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QVERIFY(!exceptionCaught);
+}
+
+void TestLanguage::idUniqueness()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("id-uniqueness.qbs"));
+ loader->loadProject(defaultParameters);
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ const QList<ErrorItem> items = e.items();
+ QCOMPARE(items.count(), 3);
+ QCOMPARE(items.at(0).toString(), QString::fromUtf8("The id 'baseProduct' is not unique."));
+ QVERIFY(items.at(1).toString().contains("id-uniqueness.qbs:6:5 First occurrence is here."));
+ QVERIFY(items.at(2).toString().contains("id-uniqueness.qbs:9:5 Next occurrence is here."));
+ }
+ QVERIFY(exceptionCaught);
+}
+
+void TestLanguage::importCollection()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("import-collection/project.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ const ResolvedProductConstPtr product = products.value("da product");
+ QCOMPARE(product->productProperties.value("targetName").toString(),
+ QLatin1String("C1f1C1f2C2f1C2f2"));
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QVERIFY(!exceptionCaught);
+}
+
+void TestLanguage::invalidBindingInDisabledItem()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("invalidBindingInDisabledItem.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 2);
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QVERIFY(!exceptionCaught);
+}
+
+class JSSourceValueCreator
+{
+ FileContextPtr m_fileContext;
+ QList<QString *> m_strings;
+public:
+ JSSourceValueCreator(const FileContextPtr &fileContext)
+ : m_fileContext(fileContext)
+ {
+ }
+
+ ~JSSourceValueCreator()
+ {
+ qDeleteAll(m_strings);
+ }
+
+ JSSourceValuePtr create(const QString &sourceCode)
+ {
+ JSSourceValuePtr value = JSSourceValue::create();
+ value->setFile(m_fileContext);
+ QString *str = new QString(sourceCode);
+ m_strings += str;
+ value->setSourceCode(QStringRef(str));
+ return value;
+ }
+};
+
+void TestLanguage::itemPrototype()
+{
+ FileContextPtr fileContext = FileContext::create();
+ fileContext->setFilePath("/dev/null");
+ JSSourceValueCreator sourceValueCreator(fileContext);
+ ItemPool pool;
+ Item *proto = Item::create(&pool, ItemType::Product);
+ proto->setProperty("x", sourceValueCreator.create("1"));
+ proto->setProperty("y", sourceValueCreator.create("1"));
+ Item *item = Item::create(&pool, ItemType::Product);
+ item->setPrototype(proto);
+ item->setProperty("y", sourceValueCreator.create("x + 1"));
+ item->setProperty("z", sourceValueCreator.create("2"));
+
+ Evaluator evaluator(m_engine);
+ QCOMPARE(evaluator.property(proto, "x").toVariant().toInt(), 1);
+ QCOMPARE(evaluator.property(proto, "y").toVariant().toInt(), 1);
+ QVERIFY(!evaluator.property(proto, "z").isValid());
+ QCOMPARE(evaluator.property(item, "x").toVariant().toInt(), 1);
+ QCOMPARE(evaluator.property(item, "y").toVariant().toInt(), 2);
+ QCOMPARE(evaluator.property(item, "z").toVariant().toInt(), 2);
+}
+
+void TestLanguage::itemScope()
+{
+ FileContextPtr fileContext = FileContext::create();
+ fileContext->setFilePath("/dev/null");
+ JSSourceValueCreator sourceValueCreator(fileContext);
+ ItemPool pool;
+ Item *scope1 = Item::create(&pool, ItemType::Scope);
+ scope1->setProperty("x", sourceValueCreator.create("1"));
+ Item *scope2 = Item::create(&pool, ItemType::Scope);
+ scope2->setScope(scope1);
+ scope2->setProperty("y", sourceValueCreator.create("x + 1"));
+ Item *item = Item::create(&pool, ItemType::Scope);
+ item->setScope(scope2);
+ item->setProperty("z", sourceValueCreator.create("x + y"));
+
+ Evaluator evaluator(m_engine);
+ QCOMPARE(evaluator.property(scope1, "x").toVariant().toInt(), 1);
+ QCOMPARE(evaluator.property(scope2, "y").toVariant().toInt(), 2);
+ QVERIFY(!evaluator.property(scope2, "x").isValid());
+ QCOMPARE(evaluator.property(item, "z").toVariant().toInt(), 3);
+}
+
+void TestLanguage::jsExtensions()
+{
+ QFile file(testProject("jsextensions.js"));
+ QVERIFY(file.open(QFile::ReadOnly));
+ QTextStream ts(&file);
+ QString code = ts.readAll();
+ QVERIFY(!code.isEmpty());
+ QScriptValue evaluated = m_engine->evaluate(code, file.fileName(), 1);
+ if (m_engine->hasErrorOrException(evaluated)) {
+ qDebug() << m_engine->uncaughtExceptionBacktrace();
+ QFAIL(qPrintable(m_engine->lastErrorString(evaluated)));
+ }
+}
+
+void TestLanguage::jsImportUsedInMultipleScopes_data()
+{
+ QTest::addColumn<QString>("buildVariant");
+ QTest::addColumn<QString>("expectedProductName");
+ QTest::newRow("debug") << QString("debug") << QString("MyProduct_debug");
+ QTest::newRow("release") << QString("release") << QString("MyProduct");
+}
+
+void TestLanguage::jsImportUsedInMultipleScopes()
+{
+ QFETCH(QString, buildVariant);
+ QFETCH(QString, expectedProductName);
+
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("jsimportsinmultiplescopes.qbs"));
+ params.setOverriddenValues({std::make_pair(QLatin1String("qbs.buildVariant"),
+ buildVariant)});
+ params.expandBuildConfiguration();
+ TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+ ResolvedProductPtr product = products.values().first();
+ QVERIFY(!!product);
+ QCOMPARE(product->name, expectedProductName);
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QVERIFY(!exceptionCaught);
+}
+
+void TestLanguage::moduleProperties_data()
+{
+ QTest::addColumn<QString>("propertyName");
+ QTest::addColumn<QVariant>("expectedValue");
+ QTest::newRow("init") << QString() << QVariant();
+ QTest::newRow("merge_lists")
+ << "defines"
+ << QVariant(QStringList() << "THE_PRODUCT" << "QT_CORE" << "QT_GUI" << "QT_NETWORK");
+ QTest::newRow("merge_lists_and_values")
+ << "defines"
+ << QVariant(QStringList() << "THE_PRODUCT" << "QT_CORE" << "QT_GUI" << "QT_NETWORK");
+ QTest::newRow("merge_lists_with_duplicates")
+ << "cxxFlags"
+ << QVariant(QStringList() << "-foo" << "BAR" << "-foo" << "BAZ");
+ QTest::newRow("merge_lists_with_prototype_values")
+ << "rpaths"
+ << QVariant(QStringList() << "/opt/qt/lib" << "$ORIGIN");
+ QTest::newRow("list_property_that_references_product")
+ << "listProp"
+ << QVariant(QStringList() << "x" << "123");
+ QTest::newRow("list_property_depending_on_overridden_property")
+ << "listProp2"
+ << QVariant(QStringList() << "PRODUCT_STUFF" << "DEFAULT_STUFF" << "EXTRA_STUFF");
+ QTest::newRow("overridden_list_property")
+ << "listProp"
+ << QVariant(QStringList() << "PRODUCT_STUFF");
+ QTest::newRow("shadowed-list-property")
+ << "defines"
+ << QVariant(QStringList() << "MyProject" << "shadowed-list-property");
+ QTest::newRow("shadowed-scalar-property")
+ << "someString"
+ << QVariant(QString("MyProject_shadowed-scalar-property"));
+ QTest::newRow("cleanup") << QString() << QVariant();
+}
+
+void TestLanguage::moduleProperties()
+{
+ HANDLE_INIT_CLEANUP_DATATAGS("moduleproperties.qbs");
+ QFETCH(QString, propertyName);
+ QFETCH(QVariant, expectedValue);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
+ ResolvedProductPtr product = products.value(productName);
+ QVERIFY(!!product);
+ const QVariant value = product->moduleProperties->moduleProperty("dummy", propertyName);
+ QCOMPARE(value, expectedValue);
+}
+
+void TestLanguage::modulePropertiesInGroups()
+{
+ defaultParameters.setProjectFilePath(testProject("modulepropertiesingroups.qbs"));
+ bool exceptionCaught = false;
+ try {
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ const ResolvedProductPtr product = products.value("grouptest");
+ QVERIFY(!!product);
+ GroupConstPtr g1;
+ GroupConstPtr g11;
+ GroupConstPtr g12;
+ GroupConstPtr g2;
+ GroupConstPtr g21;
+ GroupConstPtr g211;
+ foreach (const GroupConstPtr &g, product->groups) {
+ if (g->name == "g1")
+ g1= g;
+ else if (g->name == "g2")
+ g2 = g;
+ else if (g->name == "g1.1")
+ g11 = g;
+ else if (g->name == "g1.2")
+ g12 = g;
+ else if (g->name == "g2.1")
+ g21 = g;
+ else if (g->name == "g2.1.1")
+ g211 = g;
+ }
+ QVERIFY(!!g1);
+ QVERIFY(!!g2);
+ QVERIFY(!!g11);
+ QVERIFY(!!g12);
+ QVERIFY(!!g21);
+ QVERIFY(!!g211);
+
+ const QVariantMap productProps = product->moduleProperties->value();
+ const auto &productGmod1List1 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(productGmod1List1, QStringList() << "gmod1_list1_proto" << "gmod1_string_proto");
+ const auto &productGmod1List2 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QCOMPARE(productGmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
+ << "gmod1_list2_proto");
+ const auto &productGmod1List3 = moduleProperty(productProps, "gmod.gmod1", "gmod1_list3")
+ .toStringList();
+ QCOMPARE(productGmod1List3, QStringList() << "product" << "gmod1_string_proto");
+ const int productP0 = moduleProperty(productProps, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(productP0, 1);
+ const int productDepProp = moduleProperty(productProps, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(productDepProp, 0);
+ const auto &productGmod2String = moduleProperty(productProps, "gmod2", "gmod2_string")
+ .toString();
+ QCOMPARE(productGmod2String, QString("gmod1_string_proto"));
+ const auto &productGmod2List = moduleProperty(productProps, "gmod2", "gmod2_list")
+ .toStringList();
+ QCOMPARE(productGmod2List, QStringList() << "gmod1_string_proto" << "commonName_in_gmod1"
+ << "gmod4_string_proto_gmod3_string_proto" << "gmod3_string_proto"
+ << "gmod2_list_proto");
+
+ const QVariantMap g1Props = g1->properties->value();
+ const auto &g1Gmod1List1 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(g1Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1");
+ const auto &g1Gmod1List2 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QCOMPARE(g1Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
+ << "gmod1_list2_proto" << "g1");
+ const auto &g1Gmod1List3 = moduleProperty(g1Props, "gmod.gmod1", "gmod1_list3")
+ .toStringList();
+ QCOMPARE(g1Gmod1List3, QStringList() << "product" << "g1");
+ const int g1P0 = moduleProperty(g1Props, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(g1P0, 3);
+ const int g1DepProp = moduleProperty(g1Props, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(g1DepProp, 1);
+ const auto &g1Gmod2String = moduleProperty(g1Props, "gmod2", "gmod2_string").toString();
+ QCOMPARE(g1Gmod2String, QString("g1"));
+ const auto &g1Gmod2List = moduleProperty(g1Props, "gmod2", "gmod2_list")
+ .toStringList();
+ QCOMPARE(g1Gmod2List, QStringList() << "g1" << "commonName_in_gmod1" << "g1_gmod4_g1_gmod3"
+ << "g1_gmod3" << "gmod2_list_proto");
+
+ const QVariantMap g11Props = g11->properties->value();
+ const auto &g11Gmod1List1 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(g11Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1.1");
+ const auto &g11Gmod1List2 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QCOMPARE(g11Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
+ << "gmod1_list2_proto" << "g1" << "g1.1");
+ const auto &g11Gmod1List3 = moduleProperty(g11Props, "gmod.gmod1", "gmod1_list3")
+ .toStringList();
+ QCOMPARE(g11Gmod1List3, QStringList() << "product" << "g1.1");
+ const int g11P0 = moduleProperty(g11Props, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(g11P0, 5);
+ const int g11DepProp = moduleProperty(g11Props, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(g11DepProp, 2);
+ const auto &g11Gmod2String = moduleProperty(g11Props, "gmod2", "gmod2_string").toString();
+ QCOMPARE(g11Gmod2String, QString("g1.1"));
+ const auto &g11Gmod2List = moduleProperty(g11Props, "gmod2", "gmod2_list")
+ .toStringList();
+ QCOMPARE(g11Gmod2List, QStringList() << "g1.1" << "commonName_in_gmod1"
+ << "g1.1_gmod4_g1.1_gmod3" << "g1.1_gmod3" << "gmod2_list_proto");
+
+ const QVariantMap g12Props = g12->properties->value();
+ const auto &g12Gmod1List1 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(g12Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1.2");
+ const auto &g12Gmod1List2 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QCOMPARE(g12Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto"
+ << "gmod1_list2_proto" << "g1" << "g1.2");
+ const auto &g12Gmod1List3 = moduleProperty(g12Props, "gmod.gmod1", "gmod1_list3")
+ .toStringList();
+ QCOMPARE(g12Gmod1List3, QStringList() << "product" << "g1.2");
+ const int g12P0 = moduleProperty(g12Props, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(g12P0, 9);
+ const int g12DepProp = moduleProperty(g12Props, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(g12DepProp, 1);
+ const auto &g12Gmod2String = moduleProperty(g12Props, "gmod2", "gmod2_string").toString();
+ QCOMPARE(g12Gmod2String, QString("g1.2"));
+ const auto &g12Gmod2List = moduleProperty(g12Props, "gmod2", "gmod2_list")
+ .toStringList();
+ QCOMPARE(g12Gmod2List, QStringList() << "g1.2" << "commonName_in_gmod1"
+ << "g1_gmod4_g1.2_gmod3" << "g1.2_gmod3" << "gmod2_list_proto");
+
+ const QVariantMap g2Props = g2->properties->value();
+ const auto &g2Gmod1List1 = moduleProperty(g2Props, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(g2Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2");
+ const auto &g2Gmod1List2 = moduleProperty(g2Props, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QCOMPARE(g2Gmod1List2, QStringList() << "grouptest" << "g2" << "gmod1_list2_proto");
+ const int g2P0 = moduleProperty(g2Props, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(g2P0, 6);
+ const int g2DepProp = moduleProperty(g2Props, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(g2DepProp, 2);
+ const auto &g2Gmod2String = moduleProperty(g2Props, "gmod2", "gmod2_string").toString();
+ QCOMPARE(g2Gmod2String, QString("g2"));
+ const auto &g2Gmod2List = moduleProperty(g2Props, "gmod2", "gmod2_list")
+ .toStringList();
+ QCOMPARE(g2Gmod2List, QStringList() << "g2" << "commonName_in_gmod1" << "g2_gmod4_g2_gmod3"
+ << "g2_gmod3" << "gmod2_list_proto");
+
+ const QVariantMap g21Props = g21->properties->value();
+ const auto &g21Gmod1List1 = moduleProperty(g21Props, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(g21Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2");
+ const auto &g21Gmod1List2 = moduleProperty(g21Props, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QEXPECT_FAIL(0, "no re-eval when no module props set", Continue);
+ QCOMPARE(g21Gmod1List2, QStringList() << "grouptest" << "g2.1" << "gmod1_list2_proto");
+ const int g21P0 = moduleProperty(g21Props, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(g21P0, 6);
+ const int g21DepProp = moduleProperty(g21Props, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(g21DepProp, 2);
+ const auto &g21Gmod2String = moduleProperty(g21Props, "gmod2", "gmod2_string").toString();
+ QCOMPARE(g21Gmod2String, QString("g2"));
+ const auto &g21Gmod2List = moduleProperty(g21Props, "gmod2", "gmod2_list")
+ .toStringList();
+ QEXPECT_FAIL(0, "no re-eval when no module props set", Continue);
+ QCOMPARE(g21Gmod2List, QStringList() << "g2" << "commonName_in_gmod1"
+ << "g2.1_gmod4_g2.1_gmod3" << "g2.1_gmod3" << "gmod2_list_proto");
+
+ const QVariantMap g211Props = g211->properties->value();
+ const auto &g211Gmod1List1 = moduleProperty(g211Props, "gmod.gmod1", "gmod1_list1")
+ .toStringList();
+ QCOMPARE(g211Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2");
+ const auto &g211Gmod1List2 = moduleProperty(g211Props, "gmod.gmod1", "gmod1_list2")
+ .toStringList();
+ QCOMPARE(g211Gmod1List2, QStringList() << "g2.1.1");
+ const int g211P0 = moduleProperty(g211Props, "gmod.gmod1", "p0").toInt();
+ QCOMPARE(g211P0, 17);
+ const int g211DepProp = moduleProperty(g211Props, "gmod.gmod1", "depProp").toInt();
+ QCOMPARE(g211DepProp, 2);
+ const auto &g211Gmod2String
+ = moduleProperty(g211Props, "gmod2", "gmod2_string").toString();
+ QEXPECT_FAIL(0, "re-eval not triggered", Continue);
+ QCOMPARE(g211Gmod2String, QString("g2.1.1"));
+ const auto &g211Gmod2List = moduleProperty(g211Props, "gmod2", "gmod2_list")
+ .toStringList();
+ QEXPECT_FAIL(0, "re-eval not triggered", Continue);
+ QCOMPARE(g211Gmod2List, QStringList() << "g2.1.1" << "commonName_in_gmod1"
+ << "g2.1.1_gmod4_g2.1.1_gmod3" << "g2.1.1_gmod3" << "gmod2_list_proto");
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::modulePropertyOverridesPerProduct()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setOverriddenValues({
+ std::make_pair("modules.dummy.someString", "m"),
+ std::make_pair("products.b.dummy.someString", "b"),
+ std::make_pair("products.c.dummy.someString", "c")
+ });
+ params.setProjectFilePath(
+ testProject("module-property-overrides-per-product.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 3);
+ const ResolvedProductConstPtr a = products.value("a");
+ QVERIFY(!!a);
+ const ResolvedProductConstPtr b = products.value("b");
+ QVERIFY(!!b);
+ const ResolvedProductConstPtr c = products.value("c");
+ QVERIFY(!!c);
+
+ const auto propertyValue = [](const ResolvedProductConstPtr &p) -> QString
+ {
+ return p->moduleProperties->moduleProperty("dummy", "someString").toString();
+ };
+
+ QCOMPARE(propertyValue(a), QString("m"));
+ QCOMPARE(propertyValue(b), QString("b"));
+ QCOMPARE(propertyValue(c), QString("c"));
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::moduleScope()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("modulescope.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+ ResolvedProductPtr product = products.value("product1");
+ QVERIFY(!!product);
+
+ auto intModuleValue = [product] (const QString &name) -> int
+ {
+ return product->moduleProperties->moduleProperty("scopemod", name).toInt();
+ };
+
+ QCOMPARE(intModuleValue("a"), 2); // overridden in module instance
+ QCOMPARE(intModuleValue("b"), 1); // genuine
+ QCOMPARE(intModuleValue("c"), 3); // genuine, dependent on overridden value
+ QCOMPARE(intModuleValue("d"), 2); // genuine, dependent on genuine value
+ QCOMPARE(intModuleValue("e"), 1); // genuine
+ QCOMPARE(intModuleValue("f"), 2); // overridden
+ QCOMPARE(intModuleValue("g"), 156); // overridden, dependent on product properties
+ QCOMPARE(intModuleValue("h"), 158); // overridden, base dependent on product properties
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+
+}
+
+void TestLanguage::modules_data()
+{
+ QTest::addColumn<QStringList>("expectedModulesInProduct");
+ QTest::addColumn<QString>("expectedProductProperty");
+ QTest::newRow("init") << QStringList();
+ QTest::newRow("no_modules")
+ << (QStringList() << "qbs")
+ << QString();
+ QTest::newRow("qt_core")
+ << (QStringList() << "qbs" << "dummy" << "dummyqt.core")
+ << QString("1.2.3");
+ QTest::newRow("qt_gui")
+ << (QStringList() << "qbs" << "dummy" << "dummyqt.core" << "dummyqt.gui")
+ << QString("guiProperty");
+ QTest::newRow("qt_gui_network")
+ << (QStringList() << "qbs" << "dummy" << "dummyqt.core" << "dummyqt.gui"
+ << "dummyqt.network")
+ << QString("guiProperty,networkProperty");
+ QTest::newRow("deep_module_name")
+ << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy")
+ << QString("abysmal");
+ QTest::newRow("deep_module_name_submodule_syntax1")
+ << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy")
+ << QString("abysmal");
+ QTest::newRow("deep_module_name_submodule_syntax2")
+ << (QStringList() << "qbs" << "deepdummy.deep.moat" << "dummy")
+ << QString("abysmal");
+ QTest::newRow("dummy_twice")
+ << (QStringList() << "qbs" << "dummy")
+ << QString();
+ QTest::newRow("cleanup") << QStringList();
+}
+
+void TestLanguage::modules()
+{
+ HANDLE_INIT_CLEANUP_DATATAGS("modules.qbs");
+ QFETCH(QStringList, expectedModulesInProduct);
+ QFETCH(QString, expectedProductProperty);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
+ ResolvedProductPtr product = products.value(productName);
+ QVERIFY(!!product);
+ QCOMPARE(product->name, productName);
+ QStringList modulesInProduct;
+ foreach (ResolvedModuleConstPtr m, product->modules)
+ modulesInProduct += m->name;
+ modulesInProduct.sort();
+ expectedModulesInProduct.sort();
+ QCOMPARE(modulesInProduct, expectedModulesInProduct);
+ QCOMPARE(product->productProperties.value("foo").toString(), expectedProductProperty);
+}
+
+void TestLanguage::nonRequiredProducts()
+{
+ bool exceptionCaught = false;
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("non-required-products.qbs"));
+ QFETCH(bool, subProjectEnabled);
+ QFETCH(bool, dependeeEnabled);
+ QVariantMap overriddenValues;
+ if (!subProjectEnabled)
+ overriddenValues.insert("projects.subproject.condition", false);
+ else if (!dependeeEnabled)
+ overriddenValues.insert("products.dependee.condition", false);
+ params.setOverriddenValues(overriddenValues);
+ const TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ const auto products = productsFromProject(project);
+ QCOMPARE(products.count(), 4 + !!subProjectEnabled);
+ const ResolvedProductConstPtr dependee = products.value("dependee");
+ QCOMPARE(subProjectEnabled, !!dependee);
+ if (dependee)
+ QCOMPARE(dependeeEnabled, dependee->enabled);
+ const ResolvedProductConstPtr depender = products.value("depender");
+ QVERIFY(!!depender);
+ const QStringList defines = depender->moduleProperties->moduleProperty("dummy", "defines")
+ .toStringList();
+ QCOMPARE(subProjectEnabled && dependeeEnabled, defines.contains("WITH_DEPENDEE"));
+
+ for (const auto &name : std::vector<const char *>({ "p3", "p2", "p1"})) {
+ const ResolvedProductConstPtr &product = products.value(name);
+ QVERIFY2(product, name);
+ QVERIFY2(!product->enabled, name);
+ }
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::nonRequiredProducts_data()
+{
+ QTest::addColumn<bool>("subProjectEnabled");
+ QTest::addColumn<bool>("dependeeEnabled");
+ QTest::newRow("dependee enabled") << true << true;
+ QTest::newRow("dependee disabled") << true << false;
+ QTest::newRow("sub project disabled") << false << true;
+}
+
+void TestLanguage::outerInGroup()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("outerInGroup.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+ ResolvedProductPtr product = products.value("OuterInGroup");
+ QVERIFY(!!product);
+ QCOMPARE(product->groups.count(), 2);
+ GroupPtr group = product->groups.at(0);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, product->name);
+ QCOMPARE(group->files.count(), 1);
+ SourceArtifactConstPtr artifact = group->files.first();
+ QVariant installDir = artifact->properties->qbsPropertyValue("installDir");
+ QCOMPARE(installDir.toString(), QString("/somewhere"));
+ group = product->groups.at(1);
+ QVERIFY(!!group);
+ QCOMPARE(group->name, QString("Special Group"));
+ QCOMPARE(group->files.count(), 1);
+ artifact = group->files.first();
+ installDir = artifact->properties->qbsPropertyValue("installDir");
+ QCOMPARE(installDir.toString(), QString("/somewhere/else"));
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::parameterTypes()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("parameter-types.qbs"));
+ loader->loadProject(defaultParameters);
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
-#include <QtCore/qcoreapplication.h>
+void TestLanguage::pathProperties()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("pathproperties.qbs"));
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value("product1");
+ QVERIFY(!!product);
+ QString projectFileDir = QFileInfo(defaultParameters.projectFilePath()).absolutePath();
+ const QVariantMap productProps = product->productProperties;
+ QCOMPARE(productProps.value("projectFileDir").toString(), projectFileDir);
+ QStringList filesInProjectFileDir = QStringList()
+ << FileInfo::resolvePath(projectFileDir, "aboutdialog.h")
+ << FileInfo::resolvePath(projectFileDir, "aboutdialog.cpp");
+ QCOMPARE(productProps.value("filesInProjectFileDir").toStringList(), filesInProjectFileDir);
+ QStringList includePaths = product->moduleProperties->property(
+ QStringList() << "modules" << "dummy" << "includePaths").toStringList();
+ QCOMPARE(includePaths, QStringList() << projectFileDir);
+ QCOMPARE(productProps.value("base_fileInProductDir").toString(),
+ FileInfo::resolvePath(projectFileDir, QLatin1String("foo")));
+ QCOMPARE(productProps.value("base_fileInBaseProductDir").toString(),
+ FileInfo::resolvePath(projectFileDir, QLatin1String("subdir/bar")));
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::profileValuesAndOverriddenValues()
+{
+ bool exceptionCaught = false;
+ try {
+ TemporaryProfile tp(QLatin1String("tst_lang_profile"), m_settings);
+ Profile profile = tp.p;
+ profile.setValue("dummy.defines", "IN_PROFILE");
+ profile.setValue("dummy.cFlags", "IN_PROFILE");
+ profile.setValue("dummy.cxxFlags", "IN_PROFILE");
+ profile.setValue("qbs.architecture", "x86");
+ SetupProjectParameters parameters = defaultParameters;
+ parameters.setTopLevelProfile(profile.name());
+ QVariantMap overriddenValues;
+ overriddenValues.insert("modules.dummy.cFlags", "OVERRIDDEN");
+ parameters.setOverriddenValues(overriddenValues);
+ parameters.setProjectFilePath(testProject("profilevaluesandoverriddenvalues.qbs"));
+ parameters.expandBuildConfiguration();
+ project = loader->loadProject(parameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product = products.value("product1");
+ QVERIFY(!!product);
+ QVariantList values;
+ values = product->moduleProperties->moduleProperty("dummy", "cxxFlags").toList();
+ QCOMPARE(values.length(), 1);
+ QCOMPARE(values.first().toString(), QString("IN_PROFILE"));
+ values = product->moduleProperties->moduleProperty("dummy", "defines").toList();
+ QCOMPARE(values, QVariantList() << QLatin1String("IN_FILE") << QLatin1String("IN_PROFILE"));
+ values = product->moduleProperties->moduleProperty("dummy", "cFlags").toList();
+ QCOMPARE(values.length(), 1);
+ QCOMPARE(values.first().toString(), QString("OVERRIDDEN"));
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::productConditions()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("productconditions.qbs"));
+ TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 6);
+ ResolvedProductPtr product;
+ product = products.value("product_no_condition");
+ QVERIFY(!!product);
+ QVERIFY(product->enabled);
+
+ product = products.value("product_true_condition");
+ QVERIFY(!!product);
+ QVERIFY(product->enabled);
+
+ product = products.value("product_condition_dependent_of_module");
+ QVERIFY(!!product);
+ QVERIFY(product->enabled);
+
+ product = products.value("product_false_condition");
+ QVERIFY(!!product);
+ QVERIFY(!product->enabled);
+
+ product = products.value("product_probe_condition_false");
+ QVERIFY(!!product);
+ QVERIFY(!product->enabled);
+
+ product = products.value("product_probe_condition_true");
+ QVERIFY(!!product);
+ QVERIFY(product->enabled);
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::productDirectories()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("productdirectories.qbs"));
+ ResolvedProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 1);
+ ResolvedProductPtr product;
+ product = products.value("MyApp");
+ QVERIFY(!!product);
+ const QVariantMap config = product->productProperties;
+ QCOMPARE(config.value(QLatin1String("buildDirectory")).toString(),
+ product->buildDirectory());
+ QCOMPARE(config.value(QLatin1String("sourceDirectory")).toString(), testDataDir());
+ }
+ catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::propertiesBlocks_data()
+{
+ QTest::addColumn<QString>("propertyName");
+ QTest::addColumn<QStringList>("expectedValues");
+ QTest::addColumn<QString>("expectedStringValue");
+
+ QTest::newRow("init") << QString() << QStringList() << QString();
+ QTest::newRow("property_overwrite")
+ << QString("dummy.defines")
+ << QStringList("OVERWRITTEN")
+ << QString();
+ QTest::newRow("property_set_indirect")
+ << QString("dummy.cFlags")
+ << QStringList("VAL")
+ << QString();
+ QTest::newRow("property_overwrite_no_outer")
+ << QString("dummy.defines")
+ << QStringList("OVERWRITTEN")
+ << QString();
+ QTest::newRow("property_append_to_outer")
+ << QString("dummy.defines")
+ << (QStringList() << QString("ONE") << QString("TWO"))
+ << QString();
+
+ QTest::newRow("multiple_exclusive_properties")
+ << QString("dummy.defines")
+ << QStringList("OVERWRITTEN")
+ << QString();
+ QTest::newRow("multiple_exclusive_properties_no_outer")
+ << QString("dummy.defines")
+ << QStringList("OVERWRITTEN")
+ << QString();
+ QTest::newRow("multiple_exclusive_properties_append_to_outer")
+ << QString("dummy.defines")
+ << (QStringList() << QString("ONE") << QString("TWO"))
+ << QString();
+
+ QTest::newRow("condition_refers_to_product_property")
+ << QString("dummy.defines")
+ << QStringList("OVERWRITTEN")
+ << QString("OVERWRITTEN");
+ QTest::newRow("condition_refers_to_project_property")
+ << QString("dummy.defines")
+ << QStringList("OVERWRITTEN")
+ << QString("OVERWRITTEN");
-#include <QtTest/qtest.h>
+ QTest::newRow("ambiguous_properties")
+ << QString("dummy.defines")
+ << (QStringList() << QString("ONE") << QString("TWO"))
+ << QString();
+ QTest::newRow("inheritance_overwrite_in_subitem")
+ << QString("dummy.defines")
+ << (QStringList() << QString("OVERWRITTEN_IN_SUBITEM"))
+ << QString();
+ QTest::newRow("inheritance_retain_base1")
+ << QString("dummy.defines")
+ << (QStringList() << QString("BASE") << QString("SUB"))
+ << QString();
+ QTest::newRow("inheritance_retain_base2")
+ << QString("dummy.defines")
+ << (QStringList() << QString("BASE") << QString("SUB"))
+ << QString();
+ QTest::newRow("inheritance_retain_base3")
+ << QString("dummy.defines")
+ << (QStringList() << QString("BASE") << QString("SUB"))
+ << QString();
+ QTest::newRow("inheritance_retain_base4")
+ << QString("dummy.defines")
+ << (QStringList() << QString("BASE"))
+ << QString();
+ QTest::newRow("inheritance_condition_in_subitem1")
+ << QString("dummy.defines")
+ << (QStringList() << QString("SOMETHING") << QString("SUB"))
+ << QString();
+ QTest::newRow("inheritance_condition_in_subitem2")
+ << QString("dummy.defines")
+ << (QStringList() << QString("SOMETHING"))
+ << QString();
+ QTest::newRow("condition_references_id")
+ << QString("dummy.defines")
+ << (QStringList() << QString("OVERWRITTEN"))
+ << QString();
+ QTest::newRow("using_derived_Properties_item") << "dummy.defines"
+ << (QStringList() << "string from MyProperties") << QString();
+ QTest::newRow("conditional-depends")
+ << QString("dummy.defines")
+ << QStringList()
+ << QString();
+ QTest::newRow("cleanup") << QString() << QStringList() << QString();
+}
+
+void TestLanguage::propertiesBlocks()
+{
+ HANDLE_INIT_CLEANUP_DATATAGS("propertiesblocks.qbs");
+ QFETCH(QString, propertyName);
+ QFETCH(QStringList, expectedValues);
+ QFETCH(QString, expectedStringValue);
+ QVERIFY(!!project);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
+ ResolvedProductPtr product = products.value(productName);
+ QVERIFY(!!product);
+ QCOMPARE(product->name, productName);
+ QVariant v = productPropertyValue(product, propertyName);
+ QCOMPARE(v.toStringList(), expectedValues);
+ if (!expectedStringValue.isEmpty()) {
+ v = productPropertyValue(product, "someString");
+ QCOMPARE(v.toString(), expectedStringValue);
+ }
+}
+
+void TestLanguage::propertiesBlockInGroup()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(testProject("properties-block-in-group.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ QCOMPARE(project->allProducts().count(), 1);
+ const ResolvedProductConstPtr product = project->allProducts().first();
+ const auto groupIt = std::find_if(product->groups.constBegin(), product->groups.constEnd(),
+ [](const GroupConstPtr &g) { return g->name == "the group"; });
+ QVERIFY(groupIt != product->groups.constEnd());
+ const QVariantMap propertyMap = (*groupIt)->properties->value();
+ const QVariantList value = moduleProperty(propertyMap, "dummy", "defines").toList();
+ QStringList stringListValue;
+ std::transform(value.constBegin(), value.constEnd(), std::back_inserter(stringListValue),
+ [](const QVariant &v) { return v.toString(); });
+ QCOMPARE(stringListValue, QStringList() << "BASEDEF" << "FEATURE_ENABLED");
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::propertiesItemInModule()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(
+ testProject("properties-item-in-module.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 2);
+ for (const ResolvedProductConstPtr &p : products) {
+ QCOMPARE(p->moduleProperties->moduleProperty("dummy", "productName").toString(),
+ p->name);
+ }
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::qbsPropertiesInProjectCondition()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(
+ testProject("qbs-properties-in-project-condition.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 0);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::relaxedErrorMode()
+{
+ m_logSink->setLogLevel(LoggerMinLevel);
+ QFETCH(bool, strictMode);
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("relaxed-error-mode/relaxed-error-mode.qbs"));
+ params.setProductErrorMode(strictMode ? ErrorHandlingMode::Strict
+ : ErrorHandlingMode::Relaxed);
+ const TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!strictMode);
+ const auto productMap = productsFromProject(project);
+ const ResolvedProductConstPtr brokenProduct = productMap.value("broken");
+ QVERIFY(!brokenProduct->enabled);
+ QVERIFY(brokenProduct->location.isValid());
+ QCOMPARE(brokenProduct->allFiles().count(), 0);
+ const ResolvedProductConstPtr dependerRequired = productMap.value("depender required");
+ QVERIFY(!dependerRequired->enabled);
+ QVERIFY(dependerRequired->location.isValid());
+ QCOMPARE(dependerRequired->allFiles().count(), 1);
+ const ResolvedProductConstPtr dependerNonRequired
+ = productMap.value("depender nonrequired");
+ QVERIFY(dependerNonRequired->enabled);
+ QCOMPARE(dependerNonRequired->allFiles().count(), 1);
+ const ResolvedProductConstPtr recursiveDepender = productMap.value("recursive depender");
+ QVERIFY(!recursiveDepender->enabled);
+ QVERIFY(recursiveDepender->location.isValid());
+ QCOMPARE(recursiveDepender->allFiles().count(), 1);
+ const ResolvedProductConstPtr missingFile = productMap.value("missing file");
+ QVERIFY(missingFile->enabled);
+ QCOMPARE(missingFile->groups.count(), 1);
+ QVERIFY(missingFile->groups.first()->enabled);
+ QCOMPARE(missingFile->groups.first()->allFiles().count(), 2);
+ const ResolvedProductConstPtr fine = productMap.value("fine");
+ QVERIFY(fine->enabled);
+ QCOMPARE(fine->allFiles().count(), 1);
+ } catch (const ErrorInfo &e) {
+ QVERIFY2(strictMode, qPrintable(e.toString()));
+ }
+}
+
+void TestLanguage::relaxedErrorMode_data()
+{
+ QTest::addColumn<bool>("strictMode");
+
+ QTest::newRow("strict mode") << true;
+ QTest::newRow("relaxed mode") << false;
+}
+
+void TestLanguage::requiredAndNonRequiredDependencies()
+{
+ QFETCH(QString, projectFile);
+ QFETCH(bool, exceptionExpected);
+ try {
+ SetupProjectParameters params = defaultParameters;
+ const QString projectFilePath = "required-and-nonrequired-dependencies/" + projectFile;
+ params.setProjectFilePath(testProject(projectFilePath.toLocal8Bit()));
+ const TopLevelProjectConstPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ QVERIFY(!exceptionExpected);
+ } catch (const ErrorInfo &e) {
+ QVERIFY(exceptionExpected);
+ QVERIFY2(e.toString().contains("validation error!"), qPrintable(e.toString()));
+ }
+}
+
+void TestLanguage::requiredAndNonRequiredDependencies_data()
+{
+ QTest::addColumn<QString>("projectFile");
+ QTest::addColumn<bool>("exceptionExpected");
+
+ QTest::newRow("same file") << "direct-dependencies.qbs" << true;
+ QTest::newRow("dependency via module") << "dependency-via-module.qbs" << true;
+ QTest::newRow("dependency via export") << "dependency-via-export.qbs" << true;
+ QTest::newRow("more indirection") << "complicated.qbs" << true;
+ QTest::newRow("required chain (module)") << "required-chain-module.qbs" << false;
+ QTest::newRow("required chain (export)") << "required-chain-export.qbs" << false;
+ QTest::newRow("required chain (export indirect)") << "required-chain-export-indirect.qbs"
+ << false;
+}
+
+void TestLanguage::throwingProbe()
+{
+ QFETCH(bool, enableProbe);
+ try {
+ SetupProjectParameters params = defaultParameters;
+ params.setProjectFilePath(testProject("throwing-probe.qbs"));
+ QVariantMap properties;
+ properties.insert(QLatin1String("products.theProduct.enableProbe"), enableProbe);
+ params.setOverriddenValues(properties);
+ const TopLevelProjectPtr project = loader->loadProject(params);
+ QVERIFY(!!project);
+ QVERIFY(!enableProbe);
+ } catch (const ErrorInfo &e) {
+ QVERIFY2(enableProbe, qPrintable(e.toString()));
+ }
+}
+
+void TestLanguage::throwingProbe_data()
+{
+ QTest::addColumn<bool>("enableProbe");
+
+ QTest::newRow("enabled probe") << true;
+ QTest::newRow("disabled probe") << false;
+}
+
+void TestLanguage::qualifiedId()
+{
+ QString str = "foo.bar.baz";
+ QualifiedId id = QualifiedId::fromString(str);
+ QCOMPARE(id.count(), 3);
+ QCOMPARE(id.toString(), str);
+
+ id = QualifiedId("blubb.di.blubb"); // c'tor does not split
+ QCOMPARE(id.count(), 1);
+
+ QList<QualifiedId> ids;
+ ids << QualifiedId::fromString("a")
+ << QualifiedId::fromString("a.a")
+ << QualifiedId::fromString("b")
+ << QualifiedId::fromString("c.a")
+ << QualifiedId::fromString("c.b.a")
+ << QualifiedId::fromString("c.c");
+ QList<QualifiedId> sorted = ids;
+ std::sort(sorted.begin(), sorted.end());
+ QCOMPARE(ids, sorted);
+}
+
+void TestLanguage::recursiveProductDependencies()
+{
+ bool exceptionCaught = false;
+ try {
+ defaultParameters.setProjectFilePath(
+ testProject("recursive-dependencies/recursive-dependencies.qbs"));
+ const TopLevelProjectPtr project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ QCOMPARE(products.count(), 4);
+ const ResolvedProductConstPtr p1 = products.value("p1");
+ QVERIFY(!!p1);
+ const ResolvedProductConstPtr p2 = products.value("p2");
+ QVERIFY(!!p2);
+ const ResolvedProductPtr p3 = products.value("p3");
+ QVERIFY(!!p3);
+ const ResolvedProductPtr p4 = products.value("p4");
+ QVERIFY(!!p4);
+ QVERIFY(p1->dependencies == Set<ResolvedProductPtr>() << p3 << p4);
+ QVERIFY(p2->dependencies == Set<ResolvedProductPtr>() << p3 << p4);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
+
+void TestLanguage::fileTags_data()
+{
+ QTest::addColumn<int>("numberOfGroups");
+ QTest::addColumn<QStringList>("expectedFileTags");
+
+ QTest::newRow("init") << 0 << QStringList();
+ QTest::newRow("filetagger_project_scope") << 1 << (QStringList() << "cpp");
+ QTest::newRow("filetagger_product_scope") << 1 << (QStringList() << "asm");
+ QTest::newRow("filetagger_static_pattern") << 1 << (QStringList() << "yellow");
+ QTest::newRow("unknown_file_tag") << 1 << (QStringList() << "unknown-file-tag");
+ QTest::newRow("set_file_tag_via_group") << 2 << (QStringList() << "c++");
+ QTest::newRow("override_file_tag_via_group") << 2 << (QStringList() << "c++");
+ QTest::newRow("add_file_tag_via_group") << 2 << (QStringList() << "cpp" << "zzz");
+ QTest::newRow("cleanup") << 0 << QStringList();
+}
+
+void TestLanguage::fileTags()
+{
+ HANDLE_INIT_CLEANUP_DATATAGS("filetags.qbs");
+ QFETCH(int, numberOfGroups);
+ QFETCH(QStringList, expectedFileTags);
+ QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ ResolvedProductPtr product;
+ const QString productName = QString::fromLocal8Bit(QTest::currentDataTag());
+ QVERIFY(!!(product = products.value(productName)));
+ QCOMPARE(product->groups.count(), numberOfGroups);
+ GroupPtr group = product->groups.last();
+ QVERIFY(!!group);
+ QCOMPARE(group->files.count(), 1);
+ SourceArtifactConstPtr sourceFile = group->files.first();
+ QStringList fileTags = sourceFile->fileTags.toStringList();
+ fileTags.sort();
+ QCOMPARE(fileTags, expectedFileTags);
+}
+
+void TestLanguage::wildcards_data()
+{
+ QTest::addColumn<bool>("useGroup");
+ QTest::addColumn<QStringList>("filesToCreate");
+ QTest::addColumn<QString>("projectFileSubDir");
+ QTest::addColumn<QString>("prefix");
+ QTest::addColumn<QStringList>("patterns");
+ QTest::addColumn<QStringList>("excludePatterns");
+ QTest::addColumn<QStringList>("expected");
+
+ const bool useGroup = true;
+ for (int i = 0; i <= 1; ++i) {
+ const bool useGroup = i;
+ const QByteArray dataTagSuffix = useGroup ? " group" : " nogroup";
+ QTest::newRow(QByteArray("simple 1") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "*.h")
+ << QStringList()
+ << (QStringList() << "foo.h" << "bar.h");
+ QTest::newRow(QByteArray("simple 2") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "foo.*")
+ << QStringList()
+ << (QStringList() << "foo.h" << "foo.cpp");
+ QTest::newRow(QByteArray("simple 3") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "*.h" << "*.cpp")
+ << QStringList()
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp");
+ QTest::newRow(QByteArray("exclude 1") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "*.h" << "*.cpp")
+ << (QStringList() << "bar*")
+ << (QStringList() << "foo.h" << "foo.cpp");
+ QTest::newRow(QByteArray("exclude 2") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "*")
+ << (QStringList() << "*.qbs")
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp");
+ QTest::newRow(QByteArray("non-recursive") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "a/*")
+ << QStringList()
+ << (QStringList() << "a/foo.h" << "a/foo.cpp");
+ QTest::newRow(QByteArray("absolute paths") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "foo.h" << "foo.cpp" << "bar.h" << "bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << m_wildcardsTestDirPath + "/?oo.*")
+ << QStringList()
+ << (QStringList() << "foo.h" << "foo.cpp");
+ QTest::newRow(QByteArray("relative paths with dotdot") + dataTagSuffix)
+ << useGroup
+ << (QStringList() << "bar.h" << "bar.cpp")
+ << QString("TheLaughingLlama")
+ << QString()
+ << (QStringList() << "../bar.*")
+ << QStringList()
+ << (QStringList() << "bar.h" << "bar.cpp");
+ }
+ QTest::newRow(QByteArray("recursive 1"))
+ << useGroup
+ << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "a/**")
+ << QStringList()
+ << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp");
+ QTest::newRow(QByteArray("recursive 2"))
+ << useGroup
+ << (QStringList()
+ << "d/1.h" << "b/d/1.h" << "b/c/d/1.h"
+ << "d/e/1.h" << "b/d/e/1.h" << "b/c/d/e/1.h"
+ << "a/d/1.h" << "a/b/d/1.h" << "a/b/c/d/1.h"
+ << "a/d/e/1.h" << "a/b/d/e/1.h" << "a/b/c/d/e/1.h"
+ << "a/d/1.cpp" << "a/b/d/1.cpp" << "a/b/c/d/1.h"
+ << "a/d/e/1.cpp" << "a/b/d/e/1.cpp" << "a/b/c/d/e/1.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "a/**/d/*.h")
+ << QStringList()
+ << (QStringList() << "a/d/1.h" << "a/b/d/1.h" << "a/b/c/d/1.h");
+ QTest::newRow(QByteArray("recursive 3"))
+ << useGroup
+ << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp")
+ << QString()
+ << QString()
+ << (QStringList() << "a/**/**/**")
+ << QStringList()
+ << (QStringList() << "a/foo.h" << "a/foo.cpp" << "a/b/bar.h" << "a/b/bar.cpp");
+ QTest::newRow(QByteArray("prefix"))
+ << useGroup
+ << (QStringList() << "subdir/foo.h" << "subdir/foo.cpp" << "subdir/bar.h"
+ << "subdir/bar.cpp")
+ << QString()
+ << QString("subdir/")
+ << (QStringList() << "*.h")
+ << QStringList()
+ << (QStringList() << "subdir/foo.h" << "subdir/bar.h");
+ QTest::newRow(QByteArray("non-existing absolute path"))
+ << useGroup
+ << QStringList()
+ << QString()
+ << QString("/dir")
+ << (QStringList() << "*.whatever")
+ << QStringList()
+ << QStringList();
+}
+
+void TestLanguage::wildcards()
+{
+ QFETCH(bool, useGroup);
+ QFETCH(QStringList, filesToCreate);
+ QFETCH(QString, projectFileSubDir);
+ QFETCH(QString, prefix);
+ QFETCH(QStringList, patterns);
+ QFETCH(QStringList, excludePatterns);
+ QFETCH(QStringList, expected);
+
+ // create test directory
+ QDir::setCurrent(QDir::tempPath());
+ {
+ QString errorMessage;
+ if (QFile::exists(m_wildcardsTestDirPath)) {
+ if (!removeDirectoryWithContents(m_wildcardsTestDirPath, &errorMessage)) {
+ qDebug() << errorMessage;
+ QVERIFY2(false, "removeDirectoryWithContents failed");
+ }
+ }
+ QVERIFY(QDir().mkdir(m_wildcardsTestDirPath));
+ }
+
+ // create project file
+ const QString groupName = "Keks";
+ QString dataTag = QString::fromLocal8Bit(QTest::currentDataTag());
+ dataTag.replace(' ', '_');
+ if (!projectFileSubDir.isEmpty()) {
+ if (!projectFileSubDir.startsWith('/'))
+ projectFileSubDir.prepend('/');
+ if (projectFileSubDir.endsWith('/'))
+ projectFileSubDir.chop(1);
+ QVERIFY(QDir().mkpath(m_wildcardsTestDirPath + projectFileSubDir));
+ }
+ const QString projectFilePath = m_wildcardsTestDirPath + projectFileSubDir + "/test_" + dataTag
+ + ".qbs";
+ {
+ QFile projectFile(projectFilePath);
+ QVERIFY(projectFile.open(QIODevice::WriteOnly));
+ QTextStream s(&projectFile);
+ s << "import qbs.base 1.0" << endl << endl
+ << "Application {" << endl
+ << " name: \"MyProduct\"" << endl;
+ if (useGroup) {
+ s << " Group {" << endl
+ << " name: " << toJSLiteral(groupName) << endl;
+ }
+ if (!prefix.isEmpty())
+ s << " prefix: " << toJSLiteral(prefix) << endl;
+ if (!patterns.isEmpty())
+ s << " files: " << toJSLiteral(patterns) << endl;
+ if (!excludePatterns.isEmpty())
+ s << " excludeFiles: " << toJSLiteral(excludePatterns) << endl;
+ if (useGroup)
+ s << " }" << endl;
+ s << "}" << endl << endl;
+ }
+
+ // create files
+ foreach (QString filePath, filesToCreate) {
+ filePath.prepend(m_wildcardsTestDirPath + '/');
+ QFileInfo fi(filePath);
+ if (!QDir(fi.path()).exists())
+ QVERIFY(QDir().mkpath(fi.path()));
+ QFile file(filePath);
+ QVERIFY(file.open(QIODevice::WriteOnly));
+ }
+
+ // read the project
+ bool exceptionCaught = false;
+ ResolvedProductPtr product;
+ try {
+ defaultParameters.setProjectFilePath(projectFilePath);
+ project = loader->loadProject(defaultParameters);
+ QVERIFY(!!project);
+ const QHash<QString, ResolvedProductPtr> products = productsFromProject(project);
+ product = products.value("MyProduct");
+ QVERIFY(!!product);
+ GroupPtr group;
+ if (useGroup) {
+ QCOMPARE(product->groups.count(), HostOsInfo::isMacosHost() ? 3 : 2);
+ foreach (const GroupPtr &rg, product->groups) {
+ if (rg->name == groupName) {
+ group = rg;
+ break;
+ }
+ }
+ } else {
+ QCOMPARE(product->groups.count(), HostOsInfo::isMacosHost() ? 2 : 1);
+ group = product->groups.first();
+ }
+ QVERIFY(!!group);
+ QCOMPARE(group->files.count(), 0);
+ SourceWildCards::Ptr wildcards = group->wildcards;
+ QVERIFY(!!wildcards);
+ QStringList actualFilePaths;
+ foreach (const SourceArtifactConstPtr &artifact, wildcards->files) {
+ QString str = artifact->absoluteFilePath;
+ int idx = str.indexOf(m_wildcardsTestDirPath);
+ if (idx != -1)
+ str.remove(0, idx + m_wildcardsTestDirPath.count() + 1);
+ actualFilePaths << str;
+ }
+ actualFilePaths.sort();
+ expected.sort();
+ QCOMPARE(actualFilePaths, expected);
+ } catch (const ErrorInfo &e) {
+ exceptionCaught = true;
+ qDebug() << e.toString();
+ }
+ QCOMPARE(exceptionCaught, false);
+}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
- qbs::Internal::TestLanguage tl(ConsoleLogger::instance().logSink());
+ const SettingsPtr s = settings();
+ TestLanguage tl(ConsoleLogger::instance().logSink(), s.get());
return QTest::qExec(&tl, argc, argv);
}
diff --git a/src/lib/corelib/language/tst_language.h b/tests/auto/language/tst_language.h
index de5d8f474..9d63414a5 100644
--- a/src/lib/corelib/language/tst_language.h
+++ b/tests/auto/language/tst_language.h
@@ -44,34 +44,35 @@
#include <language/loader.h>
#include <logging/ilogsink.h>
#include <tools/setupprojectparameters.h>
-#include <tools/qbs_export.h>
-#include <QtTest/qtest.h>
-namespace qbs {
-namespace Internal {
+#include <QtTest/qtest.h>
-class QBS_EXPORT TestLanguage : public QObject
+class TestLanguage : public QObject
{
Q_OBJECT
public:
- TestLanguage(ILogSink *logSink);
+ TestLanguage(qbs::ILogSink *logSink, qbs::Settings *settings);
~TestLanguage();
private:
- ILogSink *m_logSink;
- Logger m_logger;
- ScriptEngine *m_engine;
- Loader *loader;
- TopLevelProjectPtr project;
- SetupProjectParameters defaultParameters;
+ qbs::ILogSink *m_logSink;
+ qbs::Settings * const m_settings;
+ qbs::Internal::Logger m_logger;
+ qbs::Internal::ScriptEngine *m_engine;
+ qbs::Internal::Loader *loader;
+ qbs::Internal::TopLevelProjectPtr project;
+ qbs::SetupProjectParameters defaultParameters;
const QString m_wildcardsTestDirPath;
- QHash<QString, ResolvedProductPtr> productsFromProject(ResolvedProjectPtr project);
- ResolvedModuleConstPtr findModuleByName(ResolvedProductPtr product, const QString &name);
- QVariant productPropertyValue(ResolvedProductPtr product, QString propertyName);
+ QHash<QString, qbs::Internal::ResolvedProductPtr> productsFromProject(
+ qbs::Internal::ResolvedProjectPtr project);
+ qbs::Internal::ResolvedModuleConstPtr findModuleByName(
+ qbs::Internal::ResolvedProductPtr product, const QString &name);
+ QVariant productPropertyValue(qbs::Internal::ResolvedProductPtr product, QString propertyName);
void handleInitCleanupDataTags(const char *projectFileName, bool *handled);
private slots:
+ void init();
void initTestCase();
void cleanupTestCase();
@@ -86,6 +87,7 @@ private slots:
void delayedError_data();
void dependencyOnAllProfiles();
void derivedSubProject();
+ void enumerateProjectProperties();
void environmentVariable();
void erroneousFiles_data();
void erroneousFiles();
@@ -112,12 +114,14 @@ private slots:
void moduleProperties_data();
void moduleProperties();
void modulePropertiesInGroups();
+ void modulePropertyOverridesPerProduct();
void moduleScope();
void modules_data();
void modules();
void nonRequiredProducts();
void nonRequiredProducts_data();
void outerInGroup();
+ void parameterTypes();
void pathProperties();
void productConditions();
void productDirectories();
@@ -143,7 +147,5 @@ private slots:
void wildcards();
};
-} // namespace Internal
-} // namespace qbs
-
#endif // TST_LANGUAGE_H
+
diff --git a/tests/auto/shared.h b/tests/auto/shared.h
index 777239c26..36a15ca74 100644
--- a/tests/auto/shared.h
+++ b/tests/auto/shared.h
@@ -37,10 +37,29 @@
#include <QtCore/qdir.h>
#include <QtCore/qfile.h>
#include <QtCore/qfileinfo.h>
+#include <QtCore/qstring.h>
#include <QtCore/qtemporaryfile.h>
#include <QtTest/qtest.h>
+#include <memory>
+
+inline int testTimeoutInMsecs()
+{
+ bool ok;
+ int timeoutInSecs = qEnvironmentVariableIntValue("QBS_AUTOTEST_TIMEOUT", &ok);
+ if (!ok)
+ timeoutInSecs = 600;
+ return timeoutInSecs * 1000;
+}
+
+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));
+}
+
inline QString profileName() { return QLatin1String("qbs_autotests"); }
inline QString relativeBuildDir(const QString &configurationName = QString())
{
@@ -63,16 +82,24 @@ inline bool directoryExists(const QString &dirPath)
return fi.exists() && fi.isDir();
}
-inline QString uniqueProductName(const QString &productName, const QString &_profileName)
+template <typename T>
+inline QString prefixedIfNonEmpty(const T &prefix, const QString &str)
+{
+ if (str.isEmpty())
+ return QString();
+ return prefix + str;
+}
+
+inline QString uniqueProductName(const QString &productName,
+ const QString &multiplexConfigurationId)
{
- const QString p = _profileName.isEmpty() ? profileName() : _profileName;
- return productName + '.' + p;
+ return productName + prefixedIfNonEmpty(QLatin1Char('.'), multiplexConfigurationId);
}
inline QString relativeProductBuildDir(const QString &productName,
- const QString &productProfileName = QString())
+ const QString &multiplexConfigurationId = QString())
{
- const QString fullName = uniqueProductName(productName, productProfileName);
+ const QString fullName = uniqueProductName(productName, multiplexConfigurationId);
QString dirName = qbs::Internal::HostOsInfo::rfc1034Identifier(fullName);
const QByteArray hash = QCryptographicHash::hash(fullName.toUtf8(), QCryptographicHash::Sha1);
dirName.append('.').append(hash.toHex().left(8));
@@ -127,8 +154,8 @@ inline void copyFileAndUpdateTimestamp(const QString &source, const QString &tar
inline QString objectFileName(const QString &baseName, const QString &profileName)
{
- qbs::Settings settings((QString()));
- qbs::Profile profile(profileName, &settings);
+ const SettingsPtr s = settings();
+ qbs::Profile profile(profileName, s.get());
const QString suffix = profile.value("qbs.toolchain").toStringList().contains("msvc")
? "obj" : "o";
return baseName + '.' + suffix;
@@ -153,8 +180,8 @@ inline QString testWorkDir(const QString &testName)
inline qbs::Internal::HostOsInfo::HostOs targetOs()
{
- qbs::Settings settings((QString()));
- const qbs::Profile buildProfile(profileName(), &settings);
+ const SettingsPtr s = settings();
+ const qbs::Profile buildProfile(profileName(), s.get());
const QStringList targetOS = buildProfile.value("qbs.targetOS").toStringList();
if (targetOS.contains("windows"))
return qbs::Internal::HostOsInfo::HostOsWindows;
diff --git a/tests/auto/tools/tools.pro b/tests/auto/tools/tools.pro
index 0ee10216e..ba293f417 100644
--- a/tests/auto/tools/tools.pro
+++ b/tests/auto/tools/tools.pro
@@ -1,5 +1,6 @@
TARGET = tst_tools
SOURCES = tst_tools.cpp ../../../src/app/qbs/qbstool.cpp
+HEADERS = tst_tools.h
include(../auto.pri)
diff --git a/tests/auto/tools/tools.qbs b/tests/auto/tools/tools.qbs
index 612a70a40..c626c7704 100644
--- a/tests/auto/tools/tools.qbs
+++ b/tests/auto/tools/tools.qbs
@@ -1,7 +1,15 @@
import qbs
QbsAutotest {
+ Depends { name: "qbsversion" }
+
testName: "tools"
condition: qbsbuildconfig.enableUnitTests
- files: ["tst_tools.cpp"]
+ files: [
+ "tst_tools.cpp",
+ "tst_tools.h"
+ ]
+
+ // TODO: Use Utilities.cStringQuote
+ cpp.defines: ['QBS_VERSION="' + qbsversion.version + '"']
}
diff --git a/tests/auto/tools/tst_tools.cpp b/tests/auto/tools/tst_tools.cpp
index bd88d01df..13bc18b36 100644
--- a/tests/auto/tools/tst_tools.cpp
+++ b/tests/auto/tools/tst_tools.cpp
@@ -5,7 +5,7 @@
**
** This file is part of Qbs.
**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** $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
@@ -14,29 +14,944 @@
** 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 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
+#undef QT_NO_CAST_FROM_ASCII // I am qmake, and I approve this hack.
+
+#include "tst_tools.h"
+
+#include "../shared.h"
+
+#include <tools/buildoptions.h>
+#include <tools/error.h>
+#include <tools/fileinfo.h>
+#include <tools/hostosinfo.h>
+#include <tools/processutils.h>
+#include <tools/profile.h>
+#include <tools/set.h>
#include <tools/settings.h>
-#include <tools/tst_tools.h>
+#include <tools/setupprojectparameters.h>
+#include <tools/version.h>
-#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qsettings.h>
+#include <QtCore/qtemporarydir.h>
+#include <QtCore/qtemporaryfile.h>
#include <QtTest/qtest.h>
+using namespace qbs;
+using namespace qbs::Internal;
+
+TestTools::TestTools(Settings *settings) : m_settings(settings)
+{
+}
+
+TestTools::~TestTools()
+{
+ qDeleteAll(m_tmpDirs);
+}
+
+void TestTools::testFileInfo()
+{
+ QCOMPARE(FileInfo::fileName("C:/waffl/copter.exe"), QString("copter.exe"));
+ QCOMPARE(FileInfo::baseName("C:/waffl/copter.exe.lib"), QString("copter"));
+ QCOMPARE(FileInfo::completeBaseName("C:/waffl/copter.exe.lib"), QString("copter.exe"));
+ QCOMPARE(FileInfo::path("abc"), QString("."));
+ QCOMPARE(FileInfo::path("/abc/lol"), QString("/abc"));
+ QCOMPARE(FileInfo::path("/fileInRoot"), QString(QLatin1Char('/')));
+ if (HostOsInfo::isWindowsHost())
+ QCOMPARE(FileInfo::path("C:/fileInDriveRoot"), QString("C:/"));
+ QVERIFY(!FileInfo::isAbsolute("bla/lol"));
+ QVERIFY(FileInfo::isAbsolute("/bla/lol"));
+ if (HostOsInfo::isWindowsHost())
+ QVERIFY(FileInfo::isAbsolute("C:\\bla\\lol"));
+ QCOMPARE(FileInfo::resolvePath("/abc/lol", "waffl"), QString("/abc/lol/waffl"));
+ QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../foo/bar"), QString("/abc/def/ghi/foo/bar"));
+ QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../../foo/bar"), QString("/abc/def/foo/bar"));
+ QCOMPARE(FileInfo::resolvePath("/abc", "../../../foo/bar"), QString("/foo/bar"));
+ QCOMPARE(FileInfo("/does/not/exist").lastModified(), FileTime());
+}
+
+void TestTools::fileCaseCheck()
+{
+ QTemporaryFile tempFile(QDir::tempPath() + QLatin1String("/CamelCase"));
+ QVERIFY2(tempFile.open(), qPrintable(tempFile.errorString()));
+ QFileInfo tempFileInfo(tempFile.fileName());
+ const QString lowerFilePath = tempFileInfo.absolutePath() + QLatin1Char('/')
+ + tempFileInfo.fileName().toLower();
+ const QString upperFilePath = tempFileInfo.absolutePath() + QLatin1Char('/')
+ + tempFileInfo.fileName().toUpper();
+ QVERIFY(FileInfo::isFileCaseCorrect(tempFileInfo.absoluteFilePath()));
+ if (QFile::exists(lowerFilePath))
+ QVERIFY(!FileInfo::isFileCaseCorrect(lowerFilePath));
+ if (QFile::exists(upperFilePath))
+ QVERIFY(!FileInfo::isFileCaseCorrect(upperFilePath));
+}
+
+void TestTools::testProfiles()
+{
+ TemporaryProfile tpp("parent", m_settings);
+ Profile parentProfile = tpp.p;
+ TemporaryProfile tpc("child", m_settings);
+ Profile childProfile = tpc.p;
+ parentProfile.removeBaseProfile();
+ parentProfile.remove("testKey");
+ QCOMPARE(parentProfile.value("testKey", "none").toString(), QLatin1String("none"));
+ parentProfile.setValue("testKey", "testValue");
+ QCOMPARE(parentProfile.value("testKey").toString(), QLatin1String("testValue"));
+
+ childProfile.remove("testKey");
+ childProfile.removeBaseProfile();
+ QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("none"));
+ childProfile.setBaseProfile("parent");
+ QCOMPARE(childProfile.value("testKey").toString(), QLatin1String("testValue"));
+
+ // Change base profile and check if the inherited value also changes.
+ TemporaryProfile tpf("foo", m_settings);
+ Profile fooProfile = tpf.p;
+ fooProfile.setValue("testKey", "gnampf");
+ childProfile.setBaseProfile("foo");
+ QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("gnampf"));
+
+ ErrorInfo errorInfo;
+ childProfile.setBaseProfile("SmurfAlongWithMe");
+ childProfile.value("blubb", QString(), &errorInfo);
+ QVERIFY(errorInfo.hasError());
+
+ errorInfo.clear();
+ childProfile.setBaseProfile("parent");
+ parentProfile.setBaseProfile("child");
+ QVERIFY(!childProfile.value("blubb", QString(), &errorInfo).isValid());
+ QVERIFY(errorInfo.hasError());
+
+ QVERIFY(!childProfile.allKeys(Profile::KeySelectionNonRecursive).isEmpty());
+
+ errorInfo.clear();
+ QVERIFY(childProfile.allKeys(Profile::KeySelectionRecursive, &errorInfo).isEmpty());
+ QVERIFY(errorInfo.hasError());
+}
+
+void TestTools::testSettingsMigration()
+{
+ QFETCH(QString, baseDir);
+ QFETCH(bool, hasOldSettings);
+ Settings settings(baseDir);
+ if (hasOldSettings) {
+ QVERIFY(QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles/right.txt")
+ .exists());
+ QCOMPARE(settings.value("key").toString(),
+ settings.baseDirectory() + "/qbs/" QBS_VERSION "/profilesright");
+ } else {
+ QVERIFY(!QFileInfo(settings.baseDirectory() + "/qbs/" QBS_VERSION "/profiles").exists());
+ QVERIFY(settings.allKeys().isEmpty());
+ }
+}
+
+void TestTools::testSettingsMigration_data()
+{
+ QTest::addColumn<QString>("baseDir");
+ QTest::addColumn<bool>("hasOldSettings");
+ QTest::newRow("settings dir with lots of versions") << setupSettingsDir1() << true;
+ QTest::newRow("settings dir with only a fallback") << setupSettingsDir2() << true;
+ QTest::newRow("no previous settings") << setupSettingsDir3() << false;
+}
+
+QString TestTools::setupSettingsDir1()
+{
+ QTemporaryDir * const baseDir = new QTemporaryDir;
+ m_tmpDirs << baseDir;
+
+ const Version thisVersion = Version::fromString(QBS_VERSION);
+ Version predecessor;
+ if (thisVersion.patchLevel() > 0) {
+ predecessor.setMajorVersion(thisVersion.majorVersion());
+ predecessor.setMinorVersion(thisVersion.minorVersion());
+ predecessor.setPatchLevel(thisVersion.patchLevel() - 1);
+ } else if (thisVersion.minorVersion() > 0) {
+ predecessor.setMajorVersion(thisVersion.majorVersion());
+ predecessor.setMinorVersion(thisVersion.minorVersion() - 1);
+ predecessor.setPatchLevel(99);
+ } else {
+ predecessor.setMajorVersion(thisVersion.majorVersion() - 1);
+ predecessor.setMajorVersion(99);
+ predecessor.setPatchLevel(99);
+ }
+ const auto versions = QList<Version>() << Version(0, 1, 0) << Version(1, 0, 5) << predecessor
+ << Version(thisVersion.majorVersion() + 1, thisVersion.minorVersion(),
+ thisVersion.patchLevel())
+ << Version(thisVersion.majorVersion(), thisVersion.minorVersion() + 1,
+ thisVersion.patchLevel())
+ << Version(thisVersion.majorVersion(), thisVersion.minorVersion(),
+ thisVersion.patchLevel() + 1)
+ << Version(99, 99, 99);
+ foreach (const Version &v, versions) {
+ const QString settingsDir = baseDir->path() + "/qbs/" + v.toString();
+ QSettings s(settingsDir + "/qbs.conf",
+ HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat);
+ const QString profilesDir = settingsDir + "/profiles";
+ QDir::root().mkpath(profilesDir);
+ const QString magicString = v == predecessor ? "right" : "wrong";
+ QFile f(profilesDir + '/' + magicString + ".txt");
+ f.open(QIODevice::WriteOnly);
+ s.setValue("org/qt-project/qbs/key", profilesDir + magicString);
+ }
+
+ return baseDir->path();
+}
+
+QString TestTools::setupSettingsDir2()
+{
+ QTemporaryDir * const baseDir = new QTemporaryDir;
+ m_tmpDirs << baseDir;
+ const QString settingsDir = baseDir->path();
+ QSettings s(settingsDir + QLatin1String("/qbs.conf"),
+ HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat);
+ const QString profilesDir = settingsDir + QLatin1String("/qbs/profiles");
+ QDir::root().mkpath(profilesDir);
+ QFile f(profilesDir + "/right.txt");
+ f.open(QIODevice::WriteOnly);
+ s.setValue("org/qt-project/qbs/key", profilesDir + "right");
+
+ return baseDir->path();
+}
+
+QString TestTools::setupSettingsDir3()
+{
+ auto * const baseDir = new QTemporaryDir;
+ m_tmpDirs << baseDir;
+ return baseDir->path();
+}
+
+void TestTools::testBuildConfigMerging()
+{
+ TemporaryProfile tp(QLatin1String("tst_tools_profile"), m_settings);
+ Profile profile = tp.p;
+ profile.setValue(QLatin1String("topLevelKey"), QLatin1String("topLevelValue"));
+ profile.setValue(QLatin1String("qbs.toolchain"), QLatin1String("gcc"));
+ profile.setValue(QLatin1String("qbs.architecture"),
+ QLatin1String("Jean-Claude Pillemann"));
+ profile.setValue(QLatin1String("cpp.treatWarningsAsErrors"), true);
+ QVariantMap overrideMap;
+ overrideMap.insert(QLatin1String("qbs.toolchain"), QLatin1String("clang"));
+ overrideMap.insert(QLatin1String("qbs.installRoot"), QLatin1String("/blubb"));
+ SetupProjectParameters params;
+ params.setSettingsDirectory(m_settings->baseDirectory());
+ params.setTopLevelProfile(profile.name());
+ params.setConfigurationName(QLatin1String("debug"));
+ params.setOverriddenValues(overrideMap);
+ const ErrorInfo error = params.expandBuildConfiguration();
+ QVERIFY2(!error.hasError(), qPrintable(error.toString()));
+ const QVariantMap finalMap = params.finalBuildConfigurationTree();
+ QCOMPARE(finalMap.count(), 3);
+ QCOMPARE(finalMap.value(QLatin1String("topLevelKey")).toString(),
+ QString::fromLatin1("topLevelValue"));
+ const QVariantMap finalQbsMap = finalMap.value(QLatin1String("qbs")).toMap();
+ QCOMPARE(finalQbsMap.count(), 4);
+ QCOMPARE(finalQbsMap.value(QLatin1String("toolchain")).toString(),
+ QString::fromLatin1("clang"));
+ QCOMPARE(finalQbsMap.value(QLatin1String("configurationName")).toString(),
+ QString::fromLatin1("debug"));
+ QCOMPARE(finalQbsMap.value(QLatin1String("architecture")).toString(),
+ QString::fromLatin1("Jean-Claude Pillemann"));
+ QCOMPARE(finalQbsMap.value(QLatin1String("installRoot")).toString(), QLatin1String("/blubb"));
+ const QVariantMap finalCppMap = finalMap.value(QLatin1String("cpp")).toMap();
+ QCOMPARE(finalCppMap.count(), 1);
+ QCOMPARE(finalCppMap.value(QLatin1String("treatWarningsAsErrors")).toBool(), true);
+}
+
+void TestTools::testProcessNameByPid()
+{
+ QCOMPARE(qAppName(), processNameByPid(QCoreApplication::applicationPid()));
+}
+
+
+int toNumber(const QString &str)
+{
+ int res = 0;
+ for (int i = 0; i < str.length(); ++i)
+ res = (res * 10) + str[i].digitValue();
+ return res;
+}
+
+void TestTools::set_operator_eq()
+{
+ {
+ Set<int> set1, set2;
+ QVERIFY(set1 == set2);
+ QVERIFY(!(set1 != set2));
+
+ set1.insert(1);
+ QVERIFY(set1 != set2);
+ QVERIFY(!(set1 == set2));
+
+ set2.insert(1);
+ QVERIFY(set1 == set2);
+ QVERIFY(!(set1 != set2));
+
+ set2.insert(1);
+ QVERIFY(set1 == set2);
+ QVERIFY(!(set1 != set2));
+
+ set1.insert(2);
+ QVERIFY(set1 != set2);
+ QVERIFY(!(set1 == set2));
+ }
+
+ {
+ Set<QString> set1, set2;
+ QVERIFY(set1 == set2);
+ QVERIFY(!(set1 != set2));
+
+ set1.insert("one");
+ QVERIFY(set1 != set2);
+ QVERIFY(!(set1 == set2));
+
+ set2.insert("one");
+ QVERIFY(set1 == set2);
+ QVERIFY(!(set1 != set2));
+
+ set2.insert("one");
+ QVERIFY(set1 == set2);
+ QVERIFY(!(set1 != set2));
+
+ set1.insert("two");
+ QVERIFY(set1 != set2);
+ QVERIFY(!(set1 == set2));
+ }
+
+ {
+ Set<QString> a;
+ Set<QString> b;
+
+ a += "otto";
+ b += "willy";
+
+ QVERIFY(a != b);
+ QVERIFY(!(a == b));
+ }
+
+ {
+ Set<int> s1, s2;
+ s1.reserve(100);
+ s2.reserve(4);
+ QVERIFY(s1 == s2);
+ s1 << 100 << 200 << 300 << 400;
+ s2 << 400 << 300 << 200 << 100;
+ QVERIFY(s1 == s2);
+ }
+}
+
+void TestTools::set_swap()
+{
+ Set<int> s1, s2;
+ s1.insert(1);
+ s2.insert(2);
+ s1.swap(s2);
+ QCOMPARE(*s1.begin(),2);
+ QCOMPARE(*s2.begin(),1);
+}
+
+void TestTools::set_size()
+{
+ Set<int> set;
+ QVERIFY(set.size() == 0);
+ QVERIFY(set.isEmpty());
+ QVERIFY(set.count() == set.size());
+
+ set.insert(1);
+ QVERIFY(set.size() == 1);
+ QVERIFY(!set.isEmpty());
+ QVERIFY(set.count() == set.size());
+
+ set.insert(1);
+ QVERIFY(set.size() == 1);
+ QVERIFY(!set.isEmpty());
+ QVERIFY(set.count() == set.size());
+
+ set.insert(2);
+ QVERIFY(set.size() == 2);
+ QVERIFY(!set.isEmpty());
+ QVERIFY(set.count() == set.size());
+
+ set.remove(1);
+ QVERIFY(set.size() == 1);
+ QVERIFY(!set.isEmpty());
+ QVERIFY(set.count() == set.size());
+
+ set.remove(1);
+ QVERIFY(set.size() == 1);
+ QVERIFY(!set.isEmpty());
+ QVERIFY(set.count() == set.size());
+
+ set.remove(2);
+ QVERIFY(set.size() == 0);
+ QVERIFY(set.isEmpty());
+ QVERIFY(set.count() == set.size());
+}
+
+void TestTools::set_capacity()
+{
+ Set<int> set;
+ int n = set.capacity();
+ QVERIFY(n == 0);
+
+ for (int i = 0; i < 1000; ++i) {
+ set.insert(i);
+ QVERIFY(set.capacity() >= set.size());
+ }
+}
+
+void TestTools::set_reserve()
+{
+ Set<int> set;
+
+ set.reserve(1000);
+ QVERIFY(set.capacity() >= 1000);
+
+ for (int i = 0; i < 500; ++i)
+ set.insert(i);
+
+ QVERIFY(set.capacity() >= 1000);
+
+ for (int j = 0; j < 500; ++j)
+ set.remove(j);
+
+ QVERIFY(set.capacity() >= 1000);
+}
+
+void TestTools::set_clear()
+{
+ Set<QString> set1, set2;
+ QVERIFY(set1.size() == 0);
+
+ set1.clear();
+ QVERIFY(set1.size() == 0);
+
+ set1.insert("foo");
+ QVERIFY(set1.size() != 0);
+
+ set2 = set1;
+
+ set1.clear();
+ QVERIFY(set1.size() == 0);
+ QVERIFY(set2.size() != 0);
+
+ set2.clear();
+ QVERIFY(set1.size() == 0);
+ QVERIFY(set2.size() == 0);
+}
+
+void TestTools::set_remove()
+{
+ Set<QString> set1;
+
+ for (int i = 0; i < 500; ++i)
+ set1.insert(QString::number(i));
+
+ QCOMPARE(set1.size(), 500);
+
+ for (int j = 0; j < 500; ++j) {
+ set1.remove(QString::number((j * 17) % 500));
+ QCOMPARE(set1.size(), 500 - j - 1);
+ }
+}
+
+void TestTools::set_contains()
+{
+ Set<QString> set1;
+
+ for (int i = 0; i < 500; ++i) {
+ QVERIFY(!set1.contains(QString::number(i)));
+ set1.insert(QString::number(i));
+ QVERIFY(set1.contains(QString::number(i)));
+ }
+
+ QCOMPARE(set1.size(), 500);
+
+ for (int j = 0; j < 500; ++j) {
+ int i = (j * 17) % 500;
+ QVERIFY(set1.contains(QString::number(i)));
+ set1.remove(QString::number(i));
+ QVERIFY(!set1.contains(QString::number(i)));
+ }
+}
+
+void TestTools::set_containsSet()
+{
+ Set<QString> set1;
+ Set<QString> set2;
+
+ // empty set contains the empty set
+ QVERIFY(set1.contains(set2));
+
+ for (int i = 0; i < 500; ++i) {
+ set1.insert(QString::number(i));
+ set2.insert(QString::number(i));
+ }
+ QVERIFY(set1.contains(set2));
+
+ set2.remove(QString::number(19));
+ set2.remove(QString::number(82));
+ set2.remove(QString::number(7));
+ QVERIFY(set1.contains(set2));
+
+ set1.remove(QString::number(23));
+ QVERIFY(!set1.contains(set2));
+
+ // filled set contains the empty set as well
+ Set<QString> set3;
+ QVERIFY(set1.contains(set3));
+
+ // the empty set doesn't contain a filled set
+ QVERIFY(!set3.contains(set1));
+
+ // verify const signature
+ const Set<QString> set4;
+ QVERIFY(set3.contains(set4));
+}
+
+void TestTools::set_begin()
+{
+ Set<int> set1;
+ Set<int> set2 = set1;
+
+ {
+ Set<int>::const_iterator i = set1.constBegin();
+ Set<int>::const_iterator j = set1.cbegin();
+ Set<int>::const_iterator k = set2.constBegin();
+ Set<int>::const_iterator ell = set2.cbegin();
+
+ QVERIFY(i == j);
+ QVERIFY(k == ell);
+ }
+
+ set1.insert(44);
+
+ {
+ Set<int>::const_iterator i = set1.constBegin();
+ Set<int>::const_iterator j = set1.cbegin();
+ Set<int>::const_iterator k = set2.constBegin();
+ Set<int>::const_iterator ell = set2.cbegin();
+
+ QVERIFY(i == j);
+ QVERIFY(k == ell);
+ }
+
+ set2 = set1;
+
+ {
+ Set<int>::const_iterator i = set1.constBegin();
+ Set<int>::const_iterator j = set1.cbegin();
+ Set<int>::const_iterator k = set2.constBegin();
+ Set<int>::const_iterator ell = set2.cbegin();
+
+ QVERIFY(i == j);
+ QVERIFY(k == ell);
+ }
+}
+
+void TestTools::set_end()
+{
+ Set<int> set1;
+ Set<int> set2 = set1;
+
+ {
+ Set<int>::const_iterator i = set1.constEnd();
+ Set<int>::const_iterator j = set1.cend();
+ Set<int>::const_iterator k = set2.constEnd();
+ Set<int>::const_iterator ell = set2.cend();
+
+ QVERIFY(i == j);
+ QVERIFY(k == ell);
+
+ QVERIFY(set1.constBegin() == set1.constEnd());
+ QVERIFY(set2.constBegin() == set2.constEnd());
+ }
+
+ set1.insert(44);
+
+ {
+ Set<int>::const_iterator i = set1.constEnd();
+ Set<int>::const_iterator j = set1.cend();
+ Set<int>::const_iterator k = set2.constEnd();
+ Set<int>::const_iterator ell = set2.cend();
+
+ QVERIFY(i == j);
+ QVERIFY(k == ell);
+
+ QVERIFY(set1.constBegin() != set1.constEnd());
+ QVERIFY(set2.constBegin() == set2.constEnd());
+ }
+
+ set2 = set1;
+
+ {
+ Set<int>::const_iterator i = set1.constEnd();
+ Set<int>::const_iterator j = set1.cend();
+ Set<int>::const_iterator k = set2.constEnd();
+ Set<int>::const_iterator ell = set2.cend();
+
+ QVERIFY(i == j);
+ QVERIFY(k == ell);
+
+ QVERIFY(set1.constBegin() != set1.constEnd());
+ QVERIFY(set2.constBegin() != set2.constEnd());
+ }
+
+ set1.clear();
+ set2.clear();
+ QVERIFY(set1.constBegin() == set1.constEnd());
+ QVERIFY(set2.constBegin() == set2.constEnd());
+}
+
+struct IdentityTracker {
+ int value, id;
+};
+inline bool operator==(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value == rhs.value; }
+inline bool operator<(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value < rhs.value; }
+
+void TestTools::set_insert()
+{
+ {
+ Set<int> set1;
+ QVERIFY(set1.size() == 0);
+ set1.insert(1);
+ QVERIFY(set1.size() == 1);
+ set1.insert(2);
+ QVERIFY(set1.size() == 2);
+ set1.insert(2);
+ QVERIFY(set1.size() == 2);
+ QVERIFY(set1.contains(2));
+ set1.remove(2);
+ QVERIFY(set1.size() == 1);
+ QVERIFY(!set1.contains(2));
+ set1.insert(2);
+ QVERIFY(set1.size() == 2);
+ QVERIFY(set1.contains(2));
+ }
+
+ {
+ Set<int> set1;
+ QVERIFY(set1.size() == 0);
+ set1 << 1;
+ QVERIFY(set1.size() == 1);
+ set1 << 2;
+ QVERIFY(set1.size() == 2);
+ set1 << 2;
+ QVERIFY(set1.size() == 2);
+ QVERIFY(set1.contains(2));
+ set1.remove(2);
+ QVERIFY(set1.size() == 1);
+ QVERIFY(!set1.contains(2));
+ set1 << 2;
+ QVERIFY(set1.size() == 2);
+ QVERIFY(set1.contains(2));
+ }
+
+ {
+ Set<IdentityTracker> set;
+ QCOMPARE(set.size(), 0);
+ const int dummy = -1;
+ IdentityTracker id00 = {0, 0}, id01 = {0, 1}, searchKey = {0, dummy};
+ QCOMPARE(set.insert(id00).first->id, id00.id);
+ QCOMPARE(set.size(), 1);
+ QCOMPARE(set.insert(id01).first->id, id00.id); // first inserted is kept
+ QCOMPARE(set.size(), 1);
+ QCOMPARE(set.find(searchKey)->id, id00.id);
+ }
+}
+
+void TestTools::set_reverseIterators()
+{
+ Set<int> s;
+ s << 1 << 17 << 61 << 127 << 911;
+ std::vector<int> v(s.begin(), s.end());
+ std::reverse(v.begin(), v.end());
+ const Set<int> &cs = s;
+ QVERIFY(std::equal(v.begin(), v.end(), s.rbegin()));
+ QVERIFY(std::equal(v.begin(), v.end(), s.crbegin()));
+ QVERIFY(std::equal(v.begin(), v.end(), cs.rbegin()));
+ QVERIFY(std::equal(s.rbegin(), s.rend(), v.begin()));
+ QVERIFY(std::equal(s.crbegin(), s.crend(), v.begin()));
+ QVERIFY(std::equal(cs.rbegin(), cs.rend(), v.begin()));
+}
+
+void TestTools::set_stlIterator()
+{
+ Set<QString> set1;
+ for (int i = 0; i < 25000; ++i)
+ set1.insert(QString::number(i));
+
+ {
+ int sum = 0;
+ Set<QString>::const_iterator i = set1.cbegin();
+ while (i != set1.end()) {
+ sum += toNumber(*i);
+ ++i;
+ }
+ QVERIFY(sum == 24999 * 25000 / 2);
+ }
+
+ {
+ int sum = 0;
+ Set<QString>::const_iterator i = set1.cend();
+ while (i != set1.begin()) {
+ --i;
+ sum += toNumber(*i);
+ }
+ QVERIFY(sum == 24999 * 25000 / 2);
+ }
+}
+
+void TestTools::set_stlMutableIterator()
+{
+ Set<QString> set1;
+ for (int i = 0; i < 25000; ++i)
+ set1.insert(QString::number(i));
+
+ {
+ int sum = 0;
+ Set<QString>::iterator i = set1.begin();
+ while (i != set1.end()) {
+ sum += toNumber(*i);
+ ++i;
+ }
+ QVERIFY(sum == 24999 * 25000 / 2);
+ }
+
+ {
+ int sum = 0;
+ Set<QString>::iterator i = set1.end();
+ while (i != set1.begin()) {
+ --i;
+ sum += toNumber(*i);
+ }
+ QVERIFY(sum == 24999 * 25000 / 2);
+ }
+
+ {
+ Set<QString> set2 = set1;
+ Set<QString> set3 = set2;
+
+ Set<QString>::iterator i = set2.begin();
+ Set<QString>::iterator j = set3.begin();
+
+ while (i != set2.end()) {
+ i = set2.erase(i);
+ }
+ QVERIFY(set2.isEmpty());
+ QVERIFY(!set3.isEmpty());
+
+ j = set3.end();
+ while (j != set3.begin()) {
+ j--;
+ if (j + 1 != set3.end())
+ set3.erase(j + 1);
+ }
+ if (set3.begin() != set3.end())
+ set3.erase(set3.begin());
+
+ QVERIFY(set2.isEmpty());
+ QVERIFY(set3.isEmpty());
+
+ i = set2.insert("foo").first;
+ QCOMPARE(*i, QLatin1String("foo"));
+ }
+}
+
+void TestTools::set_setOperations()
+{
+ Set<QString> set1, set2;
+ set1 << "alpha" << "beta" << "gamma" << "delta" << "zeta" << "omega";
+ set2 << "beta" << "gamma" << "delta" << "epsilon" << "iota" << "omega";
+
+ Set<QString> set3 = set1;
+ set3.unite(set2);
+ QVERIFY(set3.size() == 8);
+ QVERIFY(set3.contains("alpha"));
+ QVERIFY(set3.contains("beta"));
+ QVERIFY(set3.contains("gamma"));
+ QVERIFY(set3.contains("delta"));
+ QVERIFY(set3.contains("epsilon"));
+ QVERIFY(set3.contains("zeta"));
+ QVERIFY(set3.contains("iota"));
+ QVERIFY(set3.contains("omega"));
+
+ Set<QString> set4 = set2;
+ set4.unite(set1);
+ QVERIFY(set4.size() == 8);
+ QVERIFY(set4.contains("alpha"));
+ QVERIFY(set4.contains("beta"));
+ QVERIFY(set4.contains("gamma"));
+ QVERIFY(set4.contains("delta"));
+ QVERIFY(set4.contains("epsilon"));
+ QVERIFY(set4.contains("zeta"));
+ QVERIFY(set4.contains("iota"));
+ QVERIFY(set4.contains("omega"));
+
+ QVERIFY(set3 == set4);
+
+ Set<QString> set5 = set1;
+ set5.intersect(set2);
+ QVERIFY(set5.size() == 4);
+ QVERIFY(set5.contains("beta"));
+ QVERIFY(set5.contains("gamma"));
+ QVERIFY(set5.contains("delta"));
+ QVERIFY(set5.contains("omega"));
+
+ Set<QString> set6 = set2;
+ set6.intersect(set1);
+ QVERIFY(set6.size() == 4);
+ QVERIFY(set6.contains("beta"));
+ QVERIFY(set6.contains("gamma"));
+ QVERIFY(set6.contains("delta"));
+ QVERIFY(set6.contains("omega"));
+
+ QVERIFY(set5 == set6);
+
+ Set<QString> set7 = set1;
+ set7.subtract(set2);
+ QVERIFY(set7.size() == 2);
+ QVERIFY(set7.contains("alpha"));
+ QVERIFY(set7.contains("zeta"));
+
+ Set<QString> set8 = set2;
+ set8.subtract(set1);
+ QVERIFY(set8.size() == 2);
+ QVERIFY(set8.contains("epsilon"));
+ QVERIFY(set8.contains("iota"));
+
+ Set<QString> set9 = set1 | set2;
+ QVERIFY(set9 == set3);
+
+ Set<QString> set10 = set1 & set2;
+ QVERIFY(set10 == set5);
+
+ Set<QString> set11 = set1 + set2;
+ QVERIFY(set11 == set3);
+
+ Set<QString> set12 = set1 - set2;
+ QVERIFY(set12 == set7);
+
+ Set<QString> set13 = set2 - set1;
+ QVERIFY(set13 == set8);
+
+ Set<QString> set14 = set1;
+ set14 |= set2;
+ QVERIFY(set14 == set3);
+
+ Set<QString> set15 = set1;
+ set15 &= set2;
+ QVERIFY(set15 == set5);
+
+ Set<QString> set16 = set1;
+ set16 += set2;
+ QVERIFY(set16 == set3);
+
+ Set<QString> set17 = set1;
+ set17 -= set2;
+ QVERIFY(set17 == set7);
+
+ Set<QString> set18 = set2;
+ set18 -= set1;
+ QVERIFY(set18 == set8);
+}
+
+void TestTools::set_makeSureTheComfortFunctionsCompile()
+{
+ Set<int> set1, set2, set3;
+ set1 << 5;
+ set1 |= set2;
+ set1 |= 5;
+ set1 &= set2;
+ set1 &= 5;
+ set1 += set2;
+ set1 += 5;
+ set1 -= set2;
+ set1 -= 5;
+ set1 = set2 | set3;
+ set1 = set2 & set3;
+ set1 = set2 + set3;
+ set1 = set2 - set3;
+}
+
+void TestTools::set_initializerList()
+{
+ Set<int> set = {1, 1, 2, 3, 4, 5};
+ QCOMPARE(set.count(), 5);
+ QVERIFY(set.contains(1));
+ QVERIFY(set.contains(2));
+ QVERIFY(set.contains(3));
+ QVERIFY(set.contains(4));
+ QVERIFY(set.contains(5));
+
+ // check _which_ of the equal elements gets inserted (in the QHash/QMap case, it's the last):
+ const Set<IdentityTracker> set2 = {{1, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+ QCOMPARE(set2.count(), 5);
+ const int dummy = -1;
+ const IdentityTracker searchKey = {1, dummy};
+ QCOMPARE(set2.find(searchKey)->id, 0);
+
+ Set<int> emptySet{};
+ QVERIFY(emptySet.isEmpty());
+
+ Set<int> set3{{}, {}, {}};
+ QVERIFY(!set3.isEmpty());
+}
+
+void TestTools::set_intersects()
+{
+ Set<int> s1;
+ Set<int> s2;
+
+ QVERIFY(!s1.intersects(s1));
+ QVERIFY(!s1.intersects(s2));
+
+ s1 << 100;
+ QVERIFY(s1.intersects(s1));
+ QVERIFY(!s1.intersects(s2));
+
+ s2 << 200;
+ QVERIFY(!s1.intersects(s2));
+
+ s1 << 200;
+ QVERIFY(s1.intersects(s2));
+
+ Set<int> s3;
+ s3 << 500;
+ QVERIFY(!s1.intersects(s3));
+ s3 << 200;
+ QVERIFY(s1.intersects(s3));
+}
+
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
- qbs::Settings settings((QString()));
- qbs::Internal::TestTools tt(&settings);
+ const SettingsPtr s = settings();
+ TestTools tt(s.get());
return QTest::qExec(&tt, argc, argv);
}
diff --git a/src/lib/corelib/tools/tst_tools.h b/tests/auto/tools/tst_tools.h
index 27a6b5da0..cb6828ee8 100644
--- a/src/lib/corelib/tools/tst_tools.h
+++ b/tests/auto/tools/tst_tools.h
@@ -36,7 +36,6 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#include "qbs_export.h"
#include <QtCore/qlist.h>
#include <QtCore/qobject.h>
@@ -47,15 +46,14 @@ QT_END_NAMESPACE
namespace qbs {
class Settings;
+}
-namespace Internal {
-
-class QBS_EXPORT TestTools : public QObject
+class TestTools : public QObject
{
Q_OBJECT
public:
- TestTools(Settings *settings);
+ TestTools(qbs::Settings *settings);
~TestTools();
private slots:
@@ -92,9 +90,6 @@ private:
QString setupSettingsDir2();
QString setupSettingsDir3();
- Settings * const m_settings;
+ qbs::Settings * const m_settings;
QList<QTemporaryDir *> m_tmpDirs;
};
-
-} // namespace Internal
-} // namespace qbs
diff --git a/tests/fuzzy-test/fuzzytester.cpp b/tests/fuzzy-test/fuzzytester.cpp
index c1b6f1dd3..16e05ae36 100644
--- a/tests/fuzzy-test/fuzzytester.cpp
+++ b/tests/fuzzy-test/fuzzytester.cpp
@@ -200,18 +200,19 @@ bool FuzzyTester::runQbs(const QString &buildDir, const QString &command, QStrin
QStringList commandLine = QStringList(command) << "-d" << buildDir;
if (m_log) {
commandLine << "-vv";
- const int maxLoggedCommits = 2;
- Q_ASSERT(m_commitsWithLogFiles.count() <= maxLoggedCommits + 1);
- if (m_commitsWithLogFiles.count() == maxLoggedCommits + 1) {
+ const size_t maxLoggedCommits = 2;
+ Q_ASSERT(m_commitsWithLogFiles.size() <= maxLoggedCommits + 1);
+ if (m_commitsWithLogFiles.size() == maxLoggedCommits + 1) {
static const QStringList allActivities = QStringList() << resolveIncrementalActivity()
<< buildIncrementalActivity() << buildFromScratchActivity();
- const QString oldCommit = m_commitsWithLogFiles.dequeue();
+ const QString oldCommit = m_commitsWithLogFiles.front();
+ m_commitsWithLogFiles.pop();
foreach (const QString &a, allActivities)
QFile::remove(logFilePath(oldCommit, a));
}
qbs.setStandardErrorFile(logFilePath(m_currentCommit, m_currentActivity));
- if (m_commitsWithLogFiles.isEmpty() || m_commitsWithLogFiles.last() != m_currentCommit)
- m_commitsWithLogFiles.enqueue(m_currentCommit);
+ if (m_commitsWithLogFiles.empty() || m_commitsWithLogFiles.back() != m_currentCommit)
+ m_commitsWithLogFiles.push(m_currentCommit);
} else {
commandLine << "-qq";
}
diff --git a/tests/fuzzy-test/fuzzytester.h b/tests/fuzzy-test/fuzzytester.h
index 03a0b5fec..846e7d14f 100644
--- a/tests/fuzzy-test/fuzzytester.h
+++ b/tests/fuzzy-test/fuzzytester.h
@@ -28,10 +28,10 @@
#ifndef QBS_FUZZYTESTER_H
#define QBS_FUZZYTESTER_H
-#include <QtCore/qqueue.h>
#include <QtCore/qstringlist.h>
#include <exception>
+#include <queue>
class TestError {
public:
@@ -76,7 +76,7 @@ private:
QString m_headCommit;
QString m_currentCommit;
QString m_currentActivity;
- QQueue<QString> m_commitsWithLogFiles;
+ std::queue<QString> m_commitsWithLogFiles;
QStringList m_unbuildableCommits;
QStringList m_buildableCommits;
};