aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README4
-rw-r--r--doc/qbs.qdoc8
-rw-r--r--doc/reference/commands.qdoc7
-rw-r--r--doc/reference/items/artifact.qdoc5
-rw-r--r--doc/reference/items/rule.qdoc37
-rw-r--r--doc/reference/items/subproject.qdoc2
-rw-r--r--doc/reference/items/transformer.qdoc115
-rw-r--r--doc/reference/items/xpcservice.qdoc2
-rw-r--r--doc/reference/modules/cpp-module.qdoc58
-rw-r--r--examples/cocoa-application/CocoaApplication.qbs5
-rw-r--r--examples/cocoa-touch-application/CocoaTouchApplication.qbs5
-rw-r--r--examples/collidingmice/main.cpp2
-rw-r--r--qbs-resources/imports/QbsApp.qbs2
-rw-r--r--qbs-resources/imports/QbsAutotest.qbs1
-rw-r--r--qbs-resources/imports/QbsFunctions/functions.js2
-rw-r--r--qbs-resources/imports/QbsLibrary.qbs10
-rw-r--r--qbs-resources/imports/QbsProduct.qbs3
-rw-r--r--qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs25
-rw-r--r--qbs.pro4
-rw-r--r--qbs.qbs21
-rw-r--r--qbs_version.pri2
-rw-r--r--share/qbs/imports/qbs/DarwinTools/darwin-tools.js1
-rw-r--r--share/qbs/imports/qbs/ModUtils/utils.js74
-rw-r--r--share/qbs/imports/qbs/Probes/GccProbe.qbs96
-rw-r--r--share/qbs/imports/qbs/base/Application.qbs6
-rw-r--r--share/qbs/imports/qbs/base/Library.qbs6
-rw-r--r--share/qbs/modules/Android/ndk/ndk.qbs228
-rw-r--r--share/qbs/modules/Android/ndk/utils.js41
-rw-r--r--share/qbs/modules/bundle/BundleModule.qbs4
-rw-r--r--share/qbs/modules/cpp/CppModule.qbs30
-rw-r--r--share/qbs/modules/cpp/DarwinGCC.qbs4
-rw-r--r--share/qbs/modules/cpp/GenericGCC.qbs129
-rw-r--r--share/qbs/modules/cpp/LinuxGCC.qbs (renamed from share/qbs/modules/cpp/linux-gcc.qbs)2
-rw-r--r--share/qbs/modules/cpp/android-gcc.qbs268
-rw-r--r--share/qbs/modules/cpp/gcc.js121
-rw-r--r--share/qbs/modules/cpp/msvc.js21
-rw-r--r--share/qbs/modules/cpp/windows-msvc.qbs43
-rw-r--r--share/qbs/modules/java/JavaModule.qbs1
-rw-r--r--share/qbs/modules/qbs/common.qbs41
-rw-r--r--share/qbs/modules/typescript/TypeScriptModule.qbs2
-rw-r--r--share/qbs/modules/xcode/xcode.qbs2
-rw-r--r--share/share.qbs8
-rw-r--r--src/app/config-ui/config-ui.qbs6
-rw-r--r--src/app/config-ui/mainwindow.cpp16
-rw-r--r--src/app/config-ui/mainwindow.h3
-rw-r--r--src/app/qbs-setup-android/android-setup.cpp8
-rw-r--r--src/app/qbs-setup-toolchains/compilerversion.cpp66
-rw-r--r--src/app/qbs-setup-toolchains/probe.cpp32
-rw-r--r--src/app/qbs/commandlinefrontend.cpp27
-rw-r--r--src/app/qbs/commandlinefrontend.h5
-rw-r--r--src/app/qbs/main.cpp2
-rw-r--r--src/app/qbs/qbs.qbs6
-rw-r--r--src/lib/corelib/api/internaljobs.cpp36
-rw-r--r--src/lib/corelib/api/internaljobs.h23
-rw-r--r--src/lib/corelib/api/jobs.cpp27
-rw-r--r--src/lib/corelib/api/jobs.h3
-rw-r--r--src/lib/corelib/api/project.cpp3
-rw-r--r--src/lib/corelib/api/runenvironment.cpp1
-rw-r--r--src/lib/corelib/buildgraph/abstractcommandexecutor.h1
-rw-r--r--src/lib/corelib/buildgraph/artifact.cpp10
-rw-r--r--src/lib/corelib/buildgraph/artifact.h4
-rw-r--r--src/lib/corelib/buildgraph/buildgraph.cpp35
-rw-r--r--src/lib/corelib/buildgraph/buildgraphloader.cpp19
-rw-r--r--src/lib/corelib/buildgraph/command.cpp10
-rw-r--r--src/lib/corelib/buildgraph/command.h3
-rw-r--r--src/lib/corelib/buildgraph/depscanner.cpp6
-rw-r--r--src/lib/corelib/buildgraph/executor.cpp40
-rw-r--r--src/lib/corelib/buildgraph/executor.h6
-rw-r--r--src/lib/corelib/buildgraph/executorjob.cpp20
-rw-r--r--src/lib/corelib/buildgraph/executorjob.h3
-rw-r--r--src/lib/corelib/buildgraph/jscommandexecutor.cpp30
-rw-r--r--src/lib/corelib/buildgraph/jscommandexecutor.h3
-rw-r--r--src/lib/corelib/buildgraph/nodeset.h64
-rw-r--r--src/lib/corelib/buildgraph/processcommandexecutor.cpp53
-rw-r--r--src/lib/corelib/buildgraph/processcommandexecutor.h4
-rw-r--r--src/lib/corelib/buildgraph/productbuilddata.cpp4
-rw-r--r--src/lib/corelib/buildgraph/productbuilddata.h2
-rw-r--r--src/lib/corelib/buildgraph/productinstaller.cpp2
-rw-r--r--src/lib/corelib/buildgraph/projectbuilddata.cpp33
-rw-r--r--src/lib/corelib/buildgraph/rescuableartifactdata.cpp6
-rw-r--r--src/lib/corelib/buildgraph/rescuableartifactdata.h7
-rw-r--r--src/lib/corelib/buildgraph/rulenode.cpp9
-rw-r--r--src/lib/corelib/buildgraph/rulesapplicator.cpp47
-rw-r--r--src/lib/corelib/buildgraph/rulesevaluationcontext.cpp8
-rw-r--r--src/lib/corelib/buildgraph/transformer.cpp67
-rw-r--r--src/lib/corelib/corelib.qbs31
-rw-r--r--src/lib/corelib/jsextensions/environmentextension.cpp33
-rw-r--r--src/lib/corelib/jsextensions/environmentextension.h3
-rw-r--r--src/lib/corelib/jsextensions/propertylist.mm12
-rw-r--r--src/lib/corelib/jsextensions/propertylistutils.h45
-rw-r--r--src/lib/corelib/jsextensions/propertylistutils.mm12
-rw-r--r--src/lib/corelib/jsextensions/utilitiesextension.cpp27
-rw-r--r--src/lib/corelib/language/builtindeclarations.cpp1
-rw-r--r--src/lib/corelib/language/evaluator.cpp3
-rw-r--r--src/lib/corelib/language/evaluatorscriptclass.cpp66
-rw-r--r--src/lib/corelib/language/evaluatorscriptclass.h17
-rw-r--r--src/lib/corelib/language/forward_decls.h4
-rw-r--r--src/lib/corelib/language/item.cpp3
-rw-r--r--src/lib/corelib/language/itemdeclaration.cpp7
-rw-r--r--src/lib/corelib/language/itemdeclaration.h6
-rw-r--r--src/lib/corelib/language/itemreaderastvisitor.cpp29
-rw-r--r--src/lib/corelib/language/itemreaderastvisitor.h3
-rw-r--r--src/lib/corelib/language/language.cpp28
-rw-r--r--src/lib/corelib/language/language.h2
-rw-r--r--src/lib/corelib/language/language.pri5
-rw-r--r--src/lib/corelib/language/moduleloader.cpp7
-rw-r--r--src/lib/corelib/language/projectresolver.cpp11
-rw-r--r--src/lib/corelib/language/property.cpp107
-rw-r--r--src/lib/corelib/language/property.h7
-rw-r--r--src/lib/corelib/language/scriptengine.cpp157
-rw-r--r--src/lib/corelib/language/scriptengine.h14
-rw-r--r--src/lib/corelib/language/scriptimporter.cpp161
-rw-r--r--src/lib/corelib/language/scriptimporter.h (renamed from src/lib/corelib/language/builtinvalue.h)33
-rw-r--r--src/lib/corelib/language/tst_language.cpp4
-rw-r--r--src/lib/corelib/language/value.h4
-rw-r--r--src/lib/corelib/qbs.h1
-rw-r--r--src/lib/corelib/tools/commandechomode.cpp4
-rw-r--r--src/lib/corelib/tools/commandechomode.h3
-rw-r--r--src/lib/corelib/tools/persistence.cpp2
-rw-r--r--src/lib/corelib/tools/qbsassert.h5
-rw-r--r--src/lib/corelib/tools/scripttools.cpp12
-rw-r--r--src/lib/corelib/tools/scripttools.h31
-rw-r--r--src/lib/corelib/tools/toolchains.cpp95
-rw-r--r--src/lib/corelib/tools/toolchains.h (renamed from src/lib/corelib/language/builtinvalue.cpp)28
-rw-r--r--src/lib/corelib/tools/tools.pri5
-rw-r--r--src/lib/qtprofilesetup/qtprofilesetup.qbs2
-rw-r--r--src/lib/qtprofilesetup/templates/QtPlugin.qbs3
-rw-r--r--src/lib/qtprofilesetup/templates/core.qbs1
-rw-r--r--src/lib/qtprofilesetup/templates/moc.js4
-rw-r--r--src/plugins/scanner/scannerplugin.qbs5
-rw-r--r--tests/auto/api/api.qbs8
-rw-r--r--tests/auto/api/testdata/explicitly-depends-on/project.qbs3
-rw-r--r--tests/auto/api/testdata/infinite-loop-js/infinite-loop.qbs3
-rw-r--r--tests/auto/api/testdata/qt5-plugin/project.qbs11
-rw-r--r--tests/auto/api/testdata/rule-conflict/main.cpp1
-rw-r--r--tests/auto/api/testdata/rule-conflict/pch1.h0
-rw-r--r--tests/auto/api/testdata/rule-conflict/pch2.h0
-rw-r--r--tests/auto/api/testdata/rule-conflict/rule-conflict.qbs11
-rw-r--r--tests/auto/api/testdata/transformers/transformers.qbs16
-rw-r--r--tests/auto/api/tst_api.cpp149
-rw-r--r--tests/auto/api/tst_api.h11
-rw-r--r--tests/auto/auto.qbs9
-rw-r--r--tests/auto/blackbox/testdata/android/multiple-apks-per-project/product1/product1.qbs6
-rw-r--r--tests/auto/blackbox/testdata/android/multiple-apks-per-project/product2/product2.qbs3
-rw-r--r--tests/auto/blackbox/testdata/android/multiple-libs-per-apk/multiple-libs-per-apk.qbs4
-rw-r--r--tests/auto/blackbox/testdata/android/no-native/no-native.qbs2
-rw-r--r--tests/auto/blackbox/testdata/android/teapot/teapot.qbs13
-rw-r--r--tests/auto/blackbox/testdata/build-directories/project.qbs3
-rw-r--r--tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs3
-rw-r--r--tests/auto/blackbox/testdata/erroneous/nonexistentWorkingDir/project.qbs4
-rw-r--r--tests/auto/blackbox/testdata/installed-transformer-output/qbs668.qbs4
-rw-r--r--tests/auto/blackbox/testdata/jsextensions-file/file.qbs3
-rw-r--r--tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs3
-rw-r--r--tests/auto/blackbox/testdata/jsextensions-process/process.qbs3
-rw-r--r--tests/auto/blackbox/testdata/jsextensions-textfile/textfile.qbs3
-rw-r--r--tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs3
-rw-r--r--tests/auto/blackbox/testdata/output-artifact-auto-tagging/output-artifact-auto-tagging.qbs1
-rw-r--r--tests/auto/blackbox/testdata/productproperties/header.qbs3
-rw-r--r--tests/auto/blackbox/testdata/propertyChanges/project.qbs11
-rw-r--r--tests/auto/blackbox/testdata/rule-with-no-inputs/rule-with-no-inputs.qbs26
-rw-r--r--tests/auto/blackbox/testdata/successive-changes/input.in0
-rw-r--r--tests/auto/blackbox/testdata/successive-changes/successive-changes.qbs30
-rw-r--r--tests/auto/blackbox/testdata/symlink-removal/symlink-removal.qbs3
-rw-r--r--tests/auto/blackbox/testdata/versionscript/versionscript.qbs3
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp37
-rw-r--r--tests/auto/blackbox/tst_blackbox.h2
-rw-r--r--tests/auto/buildgraph/buildgraph.qbs1
-rw-r--r--tests/auto/language/language.qbs1
-rw-r--r--tests/auto/tools/tools.qbs1
169 files changed, 2180 insertions, 1469 deletions
diff --git a/README b/README
index 2c988bf72..99cc606c8 100644
--- a/README
+++ b/README
@@ -10,12 +10,12 @@ Windows XP SP2 or later
OS X 10.6 or later
Linux (tested on Debian 6/7 and Ubuntu 13)
-Building the sources requires Qt 5.1.0 or later.
+Building the sources requires Qt 5.4.0 or later.
Build Instructions
==================
Prerequisites:
- * Qt 5.1.0 or later
+ * Qt 5.4.0 or later
* On Windows:
- MinGW or Visual Studio
* On OS X: Xcode
diff --git a/doc/qbs.qdoc b/doc/qbs.qdoc
index 3db14b6ee..574ed4a2f 100644
--- a/doc/qbs.qdoc
+++ b/doc/qbs.qdoc
@@ -118,13 +118,7 @@
\title System Requirements
- To build \QBS from the source, you need the following:
-
- \list
-
- \li Qt >= 5.1.0
-
- \endlist
+ To build \QBS from the source, you need Qt 5.4.0, or later
*/
diff --git a/doc/reference/commands.qdoc b/doc/reference/commands.qdoc
index 232cab63c..c985e1818 100644
--- a/doc/reference/commands.qdoc
+++ b/doc/reference/commands.qdoc
@@ -35,12 +35,11 @@
\page commands.html
\title Command and JavaScriptCommand
- \brief Types of commands to be used in rules and transformers
+ \brief Types of commands to be used in rules
A \e command is what \QBS executes at build time. It is represented in the language by an object
of type \c Command, which runs a process, or \c JavaScriptCommand, which executes arbitrary
- JavaScript code. A command is always created in the prepare script of a \c Rule or
- \c Transformer.
+ JavaScript code. A command is always created in the prepare script of a \c Rule.
\section1 Command
@@ -69,7 +68,7 @@
\c outputs are available. As the example shows, arbitrary properties can be set on the command
object and then used within the source code. This technique is typically used to forward values
from the prepare script to the command.
- The \l{Transformer Item} documentation shows a \c JavaScriptCommand in context.
+ The \l{Rule Item} documentation shows a \c JavaScriptCommand in context.
\section1 Properties
diff --git a/doc/reference/items/artifact.qdoc b/doc/reference/items/artifact.qdoc
index 597594c05..606632a12 100644
--- a/doc/reference/items/artifact.qdoc
+++ b/doc/reference/items/artifact.qdoc
@@ -35,10 +35,9 @@
\ingroup list-of-items
\title Artifact Item
- \brief Describes a file produced by a \c Rule or \c Transformer.
+ \brief Describes a file produced by a \c Rule.
- An \c Artifact represents a single file produced by a \l{Rule Item}{Rule} or
- \l{Transformer Item}{Transformer}.
+ An \c Artifact represents a single file produced by a \l{Rule Item}{Rule}.
For example, if a rule produces three files, it needs to contain three Artifact items.
diff --git a/doc/reference/items/rule.qdoc b/doc/reference/items/rule.qdoc
index a578c14ca..509839d2d 100644
--- a/doc/reference/items/rule.qdoc
+++ b/doc/reference/items/rule.qdoc
@@ -42,6 +42,39 @@
one or more artifacts (e.g. C++ linker).
A \e {simplex rule} creates one transformer per matching input file
(e.g. C++ compiler).
+ For instance, the following rule transforms text files:
+ \code
+ Rule {
+ inputs: ["txt_input"]
+ Artifact {
+ filePath: "output.txt"
+ fileTags: "txt_output"
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "Processing '" + input.filePath + "'";
+ cmd.highlight = "codegen";
+ cmd.sourceCode = function() {
+ var file = new TextFile(input.filePath);
+ var content = file.readAll();
+ file.close()
+ content = content.replace(/\r\n/g, "\n");
+ file = new TextFile(output.filePath, TextFile.WriteOnly);
+ file.write(content);
+ file.close();
+ }
+ return cmd;
+ }
+ }
+ \endcode
+ This example exhibits some interesting features of rules:
+ \list
+ \li If there is only one input file, the property \c input is available as syntactic sugar
+ for \c inputs[0].
+ \li The filenames of the output artifacts are available as \c outputs. If there is only one
+ of these, it can be referred to it as \c output.
+ \endlist
+
As a real-world example of a simplex rule, here is a simplified version
of \QBS' rule for transforming C++ sources into object files using gcc:
\code
@@ -114,8 +147,8 @@
\li auxiliaryInputs
\li string list
\li undefined
- \li A list of file tags. This rule will be dependent on every other rule and
- transformer that produces artifacts that are compatible with \a{auxiliaryInputs}.
+ \li A list of file tags. This rule will be dependent on every other rule
+ 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.
\row
diff --git a/doc/reference/items/subproject.qdoc b/doc/reference/items/subproject.qdoc
index b7b53f2bd..e790e945a 100644
--- a/doc/reference/items/subproject.qdoc
+++ b/doc/reference/items/subproject.qdoc
@@ -31,7 +31,7 @@
\contentspage list-of-items.html
\previouspage staticlibrary-item.html
\page subproject-item.html
- \nextpage transformer-item.html
+ \nextpage xpcservice-item.html
\ingroup list-of-items
\title SubProject Item
diff --git a/doc/reference/items/transformer.qdoc b/doc/reference/items/transformer.qdoc
deleted file mode 100644
index e496e62e9..000000000
--- a/doc/reference/items/transformer.qdoc
+++ /dev/null
@@ -1,115 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 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.
-**
-****************************************************************************/
-/*!
- \contentspage list-of-items.html
- \page transformer-item.html
- \previouspage subproject-item.html
- \nextpage xpcservice-item.html
- \ingroup list-of-items
-
- \title Transformer Item
- \brief Creates files, typically from other files.
-
- A \e transformer takes zero or more inputs and produces one or more output artifacts
- from them. The following transformer creates one output file from one input file:
- \code
- Transformer {
- inputs: "raw_input.txt"
- Artifact {
- filePath: "processed_input.txt"
- fileTags: "processed_file"
- }
- prepare: {
- var cmd = new JavaScriptCommand();
- cmd.description = "Processing '" + input.filePath + "'";
- cmd.highlight = "codegen";
- cmd.sourceCode = function() {
- var file = new TextFile(input.filePath);
- var content = file.readAll();
- file.close()
- content = content.replace(/\r\n/g, "\n");
- file = new TextFile(output.filePath, TextFile.WriteOnly);
- file.truncate();
- file.write(content);
- file.close();
- }
- return cmd;
- }
- }
- \endcode
- This example exhibits some interesting features of transformers:
- \list
- \li If there is only one input file, the property \c input is available as syntactic sugar
- for \c inputs[0].
- \li The filenames of the output artifacts are available as \c outputs. If there is only one
- of these, it can be referred to it as \c output.
- \endlist
-
- A \c Transformer is always attached to a \c Product, possibly indirectly via a \c Module.
-
- \section1 Transformer Properties
-
- \table
- \header
- \li Property
- \li Type
- \li Default
- \li Description
- \row
- \li inputs
- \li stringList
- \li empty list
- \li The list of inputs to the transformer.
- \row
- \li prepare
- \li list of Javascript commands
- \li empty list
- \li The commands that the transformer runs. These typically read from the input files and
- write to the output files in some way.
- \row
- \li condition
- \li bool
- \li true
- \li If true, the transformer is enabled, otherwise it does nothing.
- \row
- \li explicitlyDependsOn
- \li stringList
- \li \c{undefined}
- \li A list of file tags. All output artifacts of this transformer will have a dependency
- to all artifacts with the given file tags.
- \row
- \li alwaysRun
- \li bool
- \li false
- \li If true, the transformer's commands are always executed, even if all output artifacts
- are up to date.
- \endtable
-
-*/
diff --git a/doc/reference/items/xpcservice.qdoc b/doc/reference/items/xpcservice.qdoc
index cdbe8e5c8..a20f8d708 100644
--- a/doc/reference/items/xpcservice.qdoc
+++ b/doc/reference/items/xpcservice.qdoc
@@ -31,7 +31,7 @@
/*!
\contentspage list-of-items.html
\page xpcservice-item.html
- \previouspage transformer-item.html
+ \previouspage subproject-item.html
\ingroup list-of-items
\title XPCService Item
diff --git a/doc/reference/modules/cpp-module.qdoc b/doc/reference/modules/cpp-module.qdoc
index 03b6393bb..5042e92f2 100644
--- a/doc/reference/modules/cpp-module.qdoc
+++ b/doc/reference/modules/cpp-module.qdoc
@@ -93,13 +93,6 @@
\li List of preprocessor macros that are used for all projects that are built for the
current target platform. User project files usually do not set this property.
\row
- \li compilerDefines
- \li \c{stringList}
- \li 1.0
- \li \c{undefined}
- \li List of preprocessor macros that are used for all projects that are using the current
- toolchain. User project files usually do not set this property.
- \row
\li includePaths
\li \c{pathList}
\li 1.0
@@ -410,15 +403,6 @@
\li List of frameworks to be weakly linked.
If the framework is part of your project, consider using a Depends item instead.
\row
- \li installNamePrefix
- \li \c{string}
- \li 1.0
- \li \c{undefined}
- \li The prefix for the internal install name (LC_ID_DYLIB) of a dynamic library on Darwin
- (OS X and iOS). Typically this should be set to \c{"@rpath"} on modern platforms that
- support it, which includes OS X 10.5 and above, and all versions of iOS.
- \b Deprecated: use \c{cpp.sonamePrefix} instead.
- \row
\li automaticReferenceCounting
\li \c{bool}
\li 1.4
@@ -631,6 +615,48 @@
If undefined, compiler defaults will be used.
\endtable
+ \section1 Advanced Properties
+
+ \table
+ \header
+ \li Property
+ \li Type
+ \li Since
+ \li Default
+ \li Description
+ \row
+ \li compilerDefines
+ \li \c{stringList}
+ \li 1.0
+ \li \c{undefined}
+ \li List of preprocessor macros that are used for all projects that are using the current
+ toolchain. User project files usually do not set this property.
+ \row
+ \li compilerIncludePaths
+ \li \c{pathList}
+ \li 1.6
+ \li determined automatically
+ \li List of #include search paths that are used for all projects that are using the current
+ toolchain. Determined automatically by probing the compiler.
+ User project files usually do not set this property.
+ \row
+ \li compilerFrameworkPaths
+ \li \c{pathList}
+ \li 1.6
+ \li determined automatically
+ \li List of framework search paths that are used for all projects that are using the current
+ toolchain. Determined automatically by probing the compiler.
+ User project files usually do not set this property.
+ \row
+ \li compilerLibraryPaths
+ \li \c{pathList}
+ \li 1.6
+ \li determined automatically
+ \li List of library search paths that are used for all projects that are using the current
+ toolchain. Determined automatically by probing the compiler.
+ User project files usually do not set this property.
+ \endtable
+
\section1 Relevant File Tags
\table
diff --git a/examples/cocoa-application/CocoaApplication.qbs b/examples/cocoa-application/CocoaApplication.qbs
index 472f22231..a04acfb6b 100644
--- a/examples/cocoa-application/CocoaApplication.qbs
+++ b/examples/cocoa-application/CocoaApplication.qbs
@@ -45,9 +45,6 @@ CppApplication {
cpp.precompiledHeader: "CocoaApplication/CocoaApplication-Prefix.pch"
- // TODO: Remove in 1.6
- bundle.infoPlistFile: "CocoaApplication/CocoaApplication-Info.plist"
-
cpp.frameworks: ["Cocoa"]
Group {
@@ -55,7 +52,7 @@ CppApplication {
files: [
"AppDelegate.h",
"AppDelegate.m",
- //"CocoaApplication-Info.plist",
+ "CocoaApplication-Info.plist",
"CocoaApplication-Prefix.pch",
"main.m"
]
diff --git a/examples/cocoa-touch-application/CocoaTouchApplication.qbs b/examples/cocoa-touch-application/CocoaTouchApplication.qbs
index c0660d564..4e09f81ca 100644
--- a/examples/cocoa-touch-application/CocoaTouchApplication.qbs
+++ b/examples/cocoa-touch-application/CocoaTouchApplication.qbs
@@ -45,9 +45,6 @@ CppApplication {
cpp.precompiledHeader: "CocoaTouchApplication/CocoaTouchApplication-Prefix.pch"
- // TODO: Remove in 1.6
- bundle.infoPlistFile: "CocoaTouchApplication/CocoaTouchApplication-Info.plist"
-
cpp.frameworks: [ "UIKit", "Foundation", "CoreGraphics" ]
Group {
@@ -55,7 +52,7 @@ CppApplication {
files: [
"AppDelegate.h",
"AppDelegate.m",
- //"CocoaTouchApplication-Info.plist",
+ "CocoaTouchApplication-Info.plist",
"CocoaTouchApplication-Prefix.pch",
"Default-568h@2x.png",
"Default.png",
diff --git a/examples/collidingmice/main.cpp b/examples/collidingmice/main.cpp
index 1d98a9449..3873be610 100644
--- a/examples/collidingmice/main.cpp
+++ b/examples/collidingmice/main.cpp
@@ -77,7 +77,7 @@ int main(int argc, char **argv)
view.show();
QTimer timer;
- QObject::connect(&timer, SIGNAL(timeout()), &scene, SLOT(advance()));
+ QObject::connect(&timer, &QTimer::timeout, &scene, &QGraphicsScene::advance);
timer.start(1000 / 33);
return app.exec();
diff --git a/qbs-resources/imports/QbsApp.qbs b/qbs-resources/imports/QbsApp.qbs
index 530e9fddb..a6a53048e 100644
--- a/qbs-resources/imports/QbsApp.qbs
+++ b/qbs-resources/imports/QbsApp.qbs
@@ -13,7 +13,7 @@ QbsProduct {
Group {
fileTagsFilter: product.type
qbs.install: true
- qbs.installDir: project.appInstallDir
+ qbs.installDir: qbsbuildconfig.appInstallDir
}
Group {
name: "logging"
diff --git a/qbs-resources/imports/QbsAutotest.qbs b/qbs-resources/imports/QbsAutotest.qbs
index 43db835a9..6e955971c 100644
--- a/qbs-resources/imports/QbsAutotest.qbs
+++ b/qbs-resources/imports/QbsAutotest.qbs
@@ -7,6 +7,7 @@ QtApplication {
name: "tst_" + testName
Depends { name: "Qt.test" }
Depends { name: "qbscore" }
+ Depends { name: "qbsbuildconfig" }
cpp.includePaths: "../../../src"
cpp.cxxLanguageVersion: "c++11"
destinationDirectory: "bin"
diff --git a/qbs-resources/imports/QbsFunctions/functions.js b/qbs-resources/imports/QbsFunctions/functions.js
index a58b917fa..7ffebd147 100644
--- a/qbs-resources/imports/QbsFunctions/functions.js
+++ b/qbs-resources/imports/QbsFunctions/functions.js
@@ -1,4 +1,4 @@
-function qbsVersion() { return "1.5.1"; }
+function qbsVersion() { return "1.6.0"; }
function versionIsAtLeast(actualVersion, expectedVersion)
{
diff --git a/qbs-resources/imports/QbsLibrary.qbs b/qbs-resources/imports/QbsLibrary.qbs
index 4d05ea004..2d3e10fb1 100644
--- a/qbs-resources/imports/QbsLibrary.qbs
+++ b/qbs-resources/imports/QbsLibrary.qbs
@@ -7,9 +7,9 @@ QbsProduct {
version: QbsFunctions.qbsVersion()
type: Qt.core.staticBuild ? "staticlibrary" : "dynamiclibrary"
targetName: (qbs.enableDebugCode && qbs.targetOS.contains("windows")) ? (name + 'd') : name
- destinationDirectory: qbs.targetOS.contains("windows") ? "bin" : project.libDirName
+ destinationDirectory: qbs.targetOS.contains("windows") ? "bin" : qbsbuildconfig.libDirName
cpp.defines: base.concat(type == "staticlibrary" ? ["QBS_STATIC_LIB"] : ["QBS_LIBRARY"])
- cpp.installNamePrefix: "@rpath"
+ cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined
cpp.visibility: "minimal"
cpp.cxxLanguageVersion: "c++11"
bundle.isBundle: false
@@ -17,12 +17,14 @@ QbsProduct {
Group {
fileTagsFilter: product.type.concat("dynamiclibrary_symlink")
qbs.install: true
- qbs.installDir: project.libInstallDir
+ qbs.installDir: qbsbuildconfig.libInstallDir
}
Export {
Depends { name: "cpp" }
Depends { name: "Qt"; submodules: ["core"] }
- cpp.rpaths: project.libRPaths
+ Depends { name: "qbsbuildconfig" }
+
+ cpp.rpaths: qbsbuildconfig.libRPaths
cpp.includePaths: [product.sourceDirectory]
cpp.defines: product.type === "staticlibrary" ? ["QBS_STATIC_LIB"] : []
}
diff --git a/qbs-resources/imports/QbsProduct.qbs b/qbs-resources/imports/QbsProduct.qbs
index de5f7f12a..305e4c755 100644
--- a/qbs-resources/imports/QbsProduct.qbs
+++ b/qbs-resources/imports/QbsProduct.qbs
@@ -2,8 +2,9 @@ import qbs
import QbsFunctions
Product {
+ Depends { name: "qbsbuildconfig" }
Depends { name: "Qt.core" }
- property string minimumQtVersion: "5.1.0"
+ property string minimumQtVersion: "5.4.0"
cpp.defines: {
var res = ["QT_NO_CAST_FROM_ASCII", "QT_NO_PROCESS_COMBINED_ARGUMENT_START"];
if (qbs.toolchain.contains("msvc"))
diff --git a/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs b/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs
new file mode 100644
index 000000000..0ceca7dd4
--- /dev/null
+++ b/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs
@@ -0,0 +1,25 @@
+import qbs
+
+Module {
+ property bool enableUnitTests: false
+ property bool enableProjectFileUpdates: false
+ property bool enableRPath: true
+ property bool installApiHeaders: true
+ property string libDirName: "lib"
+ property string appInstallDir: "bin"
+ property string libInstallDir: qbs.targetOS.contains("windows") ? "bin" : libDirName
+ property string libexecInstallDir: "libexec/qbs"
+ property string relativeLibexecPath: "../" + libexecInstallDir
+ property string relativePluginsPath: "../" + libDirName
+ property string relativeSearchPath: ".."
+ property stringList libRPaths: {
+ if (!enableRPath)
+ return undefined;
+ if (qbs.targetOS.contains("linux"))
+ return ["$ORIGIN/../" + libDirName];
+ if (qbs.targetOS.contains("osx"))
+ return ["@loader_path/../" + libDirName]
+ }
+ property string resourcesInstallDir: ""
+ property string pluginsInstallDir: libDirName
+}
diff --git a/qbs.pro b/qbs.pro
index 68d7aa5d9..1ff1e02eb 100644
--- a/qbs.pro
+++ b/qbs.pro
@@ -21,9 +21,9 @@ defineTest(minQtVersion) {
return(false)
}
-!minQtVersion(5, 1, 0) {
+!minQtVersion(5, 4, 0) {
message("Cannot build qbs with Qt version $${QT_VERSION}.")
- error("Use at least Qt 5.1.0.")
+ error("Use at least Qt 5.4.0.")
}
TEMPLATE = subdirs
diff --git a/qbs.qbs b/qbs.qbs
index d126cf69a..43c0dc204 100644
--- a/qbs.qbs
+++ b/qbs.qbs
@@ -3,28 +3,7 @@ import qbs 1.0
Project {
minimumQbsVersion: "1.4"
qbsSearchPaths: ["qbs-resources"]
- property bool enableUnitTests: false
- property bool enableProjectFileUpdates: false
- property bool enableRPath: true
- property bool installApiHeaders: true
property bool withExamples: false
- property string libDirName: "lib"
- property string appInstallDir: "bin"
- property string libInstallDir: qbs.targetOS.contains("windows") ? "bin" : libDirName
- property string libexecInstallDir: "libexec/qbs"
- property string relativeLibexecPath: "../" + libexecInstallDir
- property string relativePluginsPath: "../" + libDirName
- property string relativeSearchPath: ".."
- property stringList libRPaths: {
- if (!enableRPath)
- return undefined;
- if (qbs.targetOS.contains("linux"))
- return ["$ORIGIN/../" + libDirName];
- if (qbs.targetOS.contains("osx"))
- return ["@loader_path/../" + libDirName]
- }
- property string resourcesInstallDir: ""
- property string pluginsInstallDir: libDirName
references: [
"dist/dist.qbs",
diff --git a/qbs_version.pri b/qbs_version.pri
index c7011efac..4977f48da 100644
--- a/qbs_version.pri
+++ b/qbs_version.pri
@@ -1,3 +1,3 @@
-QBS_VERSION = 1.5.1
+QBS_VERSION = 1.6.0
QBS_VERSION_MAJ = $$section(QBS_VERSION, ., 0, 0)
DEFINES += QBS_VERSION=\\\"$$QBS_VERSION\\\"
diff --git a/share/qbs/imports/qbs/DarwinTools/darwin-tools.js b/share/qbs/imports/qbs/DarwinTools/darwin-tools.js
index 50605c84b..d33eb92e4 100644
--- a/share/qbs/imports/qbs/DarwinTools/darwin-tools.js
+++ b/share/qbs/imports/qbs/DarwinTools/darwin-tools.js
@@ -199,6 +199,7 @@ function expandPlistEnvironmentVariables(obj, env, warn) {
// skip replacement
if (warn)
console.warn("undefined variable " + varName + " in variable expansion");
+ i = j + repl.syntax.close.length;
} else {
changes = true;
varValue = String(varValue);
diff --git a/share/qbs/imports/qbs/ModUtils/utils.js b/share/qbs/imports/qbs/ModUtils/utils.js
index f019bec6f..670c3894c 100644
--- a/share/qbs/imports/qbs/ModUtils/utils.js
+++ b/share/qbs/imports/qbs/ModUtils/utils.js
@@ -33,6 +33,7 @@ var File = loadExtension("qbs.File");
var FileInfo = loadExtension("qbs.FileInfo");
var Process = loadExtension("qbs.Process");
var TemporaryDir = loadExtension("qbs.TemporaryDir");
+var Utilities = loadExtension("qbs.Utilities");
function artifactInstalledFilePath(artifact, product) {
var relativeInstallDir = artifact.moduleProperty("qbs", "installDir");
@@ -103,31 +104,26 @@ function languagePropertyName(propertyName, fileTag) {
"c": {
"flags": "cFlags",
"platformFlags": "platformCFlags",
- "precompiledHeader": "cPrecompiledHeader", // TODO: Remove in 1.6
"usePrecompiledHeader": "useCPrecompiledHeader"
},
"cpp": {
"flags": "cxxFlags",
"platformFlags": "platformCxxFlags",
- "precompiledHeader": "cxxPrecompiledHeader", // TODO: Remove in 1.6
"usePrecompiledHeader": "useCxxPrecompiledHeader"
},
"objc": {
"flags": "objcFlags",
"platformFlags": "platformObjcFlags",
- "precompiledHeader": "objcPrecompiledHeader", // TODO: Remove in 1.6
"usePrecompiledHeader": "useObjcPrecompiledHeader"
},
"objcpp": {
"flags": "objcxxFlags",
"platformFlags": "platformObjcxxFlags",
- "precompiledHeader": "objcxxPrecompiledHeader", // TODO: Remove in 1.6
"usePrecompiledHeader": "useObjcxxPrecompiledHeader"
},
"common": {
"flags": "commonCompilerFlags",
- "platformFlags": "platformCommonCompilerFlags",
- "precompiledHeader": "precompiledHeader" // TODO: Remove in 1.6
+ "platformFlags": "platformCommonCompilerFlags"
},
"asm": asm,
"asm_cpp": asm
@@ -478,3 +474,69 @@ var BlackboxOutputArtifactTracker = (function () {
};
return BlackboxOutputArtifactTracker;
})();
+
+function guessArchitecture(m) {
+ function hasAnyOf(m, tokens) {
+ for (var i = 0; i < tokens.length; ++i) {
+ if (m[tokens[i]] !== undefined)
+ return true;
+ }
+ }
+
+ 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__"])) {
+ architecture = "arm64";
+ } else {
+ architecture = "arm";
+
+ var foundSubarch = false;
+ for (var i = 7; i >= 4; --i) {
+ var codes = ["zk", "tej", "te", "t2"].concat([].concat.apply([],
+ new Array(26)).map(function(_, i) { return String.fromCharCode(122 - i); }));
+ for (var j = 0; j < codes.length; ++j) {
+ if (m["__ARM_ARCH_" + i + codes[j].toUpperCase() + "__"] !== undefined) {
+ architecture += "v" + i + codes[j].toLowerCase();
+ foundSubarch = true;
+ break;
+ }
+ }
+
+ if (i === 7 && m["_ARM_ARCH_7"] !== undefined) {
+ architecture += "v7";
+ foundSubarch = true;
+ }
+
+ if (foundSubarch)
+ break;
+ }
+ }
+ } else if (hasAnyOf(m, ["__i386", "__i386__", "_M_IX86"])) {
+ architecture = "x86";
+ } else if (hasAnyOf(m, ["__x86_64", "__x86_64__", "__amd64", "_M_X64"])) {
+ architecture = "x86_64";
+ } else if (hasAnyOf(m, ["__ia64", "__ia64__", "_M_IA64"])) {
+ architecture = "ia64";
+ } else if (hasAnyOf(m, ["__mips", "__mips__", "_M_MRX000"])) {
+ architecture = "mips";
+ if (hasAnyOf(m, ["_MIPS_ARCH_MIPS64", "__mips64"]))
+ architecture += "64";
+ } else if (hasAnyOf(m, ["__ppc__", "__ppc", "__powerpc__",
+ "_ARCH_COM", "_ARCH_PWR", "_ARCH_PPC", "_M_MPPC", "_M_PPC"])) {
+ architecture = "ppc";
+ if (hasAnyOf(m, ["__ppc64__", "__powerpc64__", "__64BIT__"]))
+ architecture += "64";
+ } else if (hasAnyOf(m, ["__s390__"])) {
+ if (hasAnyOf(m, ["__s390x__"]))
+ architecture = "s390x";
+ } else if (hasAnyOf(m, ["__sparc__"])) {
+ architecture = "sparc";
+ if (hasAnyOf(m, ["__sparc64__"]))
+ architecture += "64";
+ }
+ }
+
+ return Utilities.canonicalArchitecture(architecture);
+}
diff --git a/share/qbs/imports/qbs/Probes/GccProbe.qbs b/share/qbs/imports/qbs/Probes/GccProbe.qbs
new file mode 100644
index 000000000..35a1371be
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/GccProbe.qbs
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+import qbs
+import qbs.ModUtils
+import "../../../modules/cpp/gcc.js" as Gcc
+
+PathProbe {
+ // Inputs
+ property string compilerFilePath
+ property string preferredArchitecture
+ property string preferredMachineType
+ property stringList flags: []
+
+ property bool _haveArchFlag: qbs.targetOS.contains("darwin")
+ property string _nullDevice: qbs.nullDevice
+ property string _toolchain: qbs.toolchain
+ property string _pathListSeparator: qbs.pathListSeparator
+ property string _targetOS: qbs.targetOS
+ property string _sysroot: qbs.sysroot
+
+ // Outputs
+ property string architecture
+ property int versionMajor
+ property int versionMinor
+ property int versionPatch
+ property stringList includePaths
+ property stringList libraryPaths
+ property stringList frameworkPaths
+
+ configure: {
+ var args = flags;
+ if (_haveArchFlag) {
+ if (preferredArchitecture)
+ args.push("-arch", preferredArchitecture);
+ } else {
+ if (preferredArchitecture === "i386")
+ args.push("-m32");
+ else if (preferredArchitecture === "x86_64")
+ args.push("-m64");
+
+ if (preferredMachineType)
+ args.push("-march=" + preferredMachineType);
+ }
+
+ var macros = Gcc.dumpMacros(compilerFilePath, args, _nullDevice);
+ var defaultPaths = Gcc.dumpDefaultPaths(compilerFilePath, args, _nullDevice,
+ _pathListSeparator, _targetOS, _sysroot);
+ found = !!macros && !!defaultPaths;
+
+ includePaths = defaultPaths.includePaths;
+ libraryPaths = defaultPaths.libraryPaths;
+ frameworkPaths = defaultPaths.frameworkPaths;
+
+ // We have to dump the compiler's macros; -dumpmachine is not suitable because it is not
+ // always complete (for example, the subarch is not included for arm architectures).
+ architecture = ModUtils.guessArchitecture(macros) || preferredArchitecture;
+
+ if (_toolchain.contains("clang")) {
+ versionMajor = macros["__clang_major__"];
+ versionMinor = macros["__clang_minor__"];
+ versionPatch = macros["__clang_patchlevel__"];
+ } else {
+ versionMajor = macros["__GNUC__"];
+ versionMinor = macros["__GNUC_MINOR__"];
+ versionPatch = macros["__GNUC_PATCHLEVEL__"];
+ }
+ }
+}
diff --git a/share/qbs/imports/qbs/base/Application.qbs b/share/qbs/imports/qbs/base/Application.qbs
index 7deb5871d..fb9a429a7 100644
--- a/share/qbs/imports/qbs/base/Application.qbs
+++ b/share/qbs/imports/qbs/base/Application.qbs
@@ -36,13 +36,11 @@ Product {
}
property bool isForAndroid: qbs.targetOS.contains("android")
- property stringList architectures: isForAndroid ? ["armv5"] : undefined
+ property stringList architectures: isForAndroid ? ["armv5te"] : undefined
- Depends { name: "Android.ndk"; condition: isForAndroid }
Depends { name: "bundle" }
- Depends { name: "cpp"; condition: isForAndroid }
- profiles: isForAndroid
+ profiles: architectures
? architectures.map(function(arch) { return project.profile + '-' + arch; })
: [project.profile]
}
diff --git a/share/qbs/imports/qbs/base/Library.qbs b/share/qbs/imports/qbs/base/Library.qbs
index e754a24bf..ea5bd2959 100644
--- a/share/qbs/imports/qbs/base/Library.qbs
+++ b/share/qbs/imports/qbs/base/Library.qbs
@@ -36,13 +36,11 @@ Product {
}
property bool isForAndroid: qbs.targetOS.contains("android")
- property stringList architectures: isForAndroid ? ["armv5"] : undefined
+ property stringList architectures: isForAndroid ? ["armv5te"] : undefined
- Depends { name: "Android.ndk"; condition: isForAndroid }
Depends { name: "bundle" }
- Depends { name: "cpp"; condition: isForAndroid }
- profiles: isForAndroid
+ profiles: architectures
? architectures.map(function(arch) { return project.profile + '-' + arch; })
: [project.profile]
}
diff --git a/share/qbs/modules/Android/ndk/ndk.qbs b/share/qbs/modules/Android/ndk/ndk.qbs
index 8d8316acb..71cc4b38f 100644
--- a/share/qbs/modules/Android/ndk/ndk.qbs
+++ b/share/qbs/modules/Android/ndk/ndk.qbs
@@ -33,13 +33,10 @@ import qbs.File
import qbs.FileInfo
import qbs.ModUtils
import qbs.Probes
-import qbs.TextFile
import "utils.js" as NdkUtils
Module {
- Depends { name: "cpp" }
-
Probes.AndroidNdkProbe {
id: ndkProbe
environmentPaths: [ndkDir].concat(base)
@@ -69,13 +66,6 @@ Module {
}
property string hostArch: ndkProbe.hostArch
- property string toolchainDir: {
- if (qbs.toolchain && qbs.toolchain.contains("clang"))
- return "llvm-" + toolchainVersionNumber;
- if (["x86", "x86_64"].contains(abi))
- return abi + "-" + toolchainVersionNumber;
- return cpp.toolchainPrefix + toolchainVersionNumber;
- }
property bool hardFloat
property string ndkDir: ndkProbe.path
@@ -87,18 +77,15 @@ Module {
File.Dirs | File.NoDotAndDotDot)
property stringList availableToolchainVersions: {
- var prefix = ["x86", "x86_64"].contains(abi) ? (abi + "-") : cpp.toolchainPrefix;
- if (qbs.toolchain.contains("clang"))
- prefix = "llvm-";
-
var tcs = availableToolchains;
var versions = [];
for (var i = 0; i < tcs.length; ++i) {
- if (tcs[i].startsWith(prefix)) {
- var v = tcs[i].substr(prefix.length);
- var re = /^([0-9]+)\.([0-9]+)$/;
- if (v.match(re))
- versions.push(v);
+ if ((qbs.toolchain.contains("clang") && tcs[i].startsWith("llvm-"))
+ || toolchainDirPrefixAbis.contains(tcs[i].split("-")[0])) {
+ var re = /\-((?:[0-9]+)\.(?:[0-9]+))$/;
+ var m = tcs[i].match(re);
+ if (m)
+ versions.push(m[1]);
}
}
@@ -138,6 +125,15 @@ Module {
return list;
}
+ property stringList toolchainDirPrefixAbis: {
+ var list = ["arm"];
+ if (platformVersion >= 9)
+ list.push("mipsel", "x86");
+ if (platformVersion >= 21)
+ list.push("aarch64", "mips64el", "x86_64");
+ return list;
+ }
+
property string toolchainVersionNumber: {
var prefix = "clang";
if (toolchainVersion && toolchainVersion.startsWith(prefix))
@@ -145,198 +141,28 @@ Module {
return toolchainVersion;
}
- property stringList defines: ["ANDROID"]
property string buildProfile: (abi === "armeabi-v7a" && hardFloat) ? (abi + "-hard") : abi
- property string cxxStlBaseDir: FileInfo.joinPaths(ndkDir, "sources/cxx-stl")
- property string gabiBaseDir: FileInfo.joinPaths(cxxStlBaseDir, "gabi++")
- property string stlPortBaseDir: FileInfo.joinPaths(cxxStlBaseDir, "stlport")
- property string gnuStlBaseDir: FileInfo.joinPaths(cxxStlBaseDir, "gnu-libstdc++",
- toolchainVersionNumber)
- property string llvmStlBaseDir: FileInfo.joinPaths(cxxStlBaseDir, "llvm-libc++")
- property string stlBaseDir: {
- if (appStl.startsWith("gabi++_"))
- return gabiBaseDir;
- else if (appStl.startsWith("stlport_"))
- return stlPortBaseDir;
- else if (appStl.startsWith("gnustl_"))
- return gnuStlBaseDir;
- else if (appStl.startsWith("c++_"))
- return llvmStlBaseDir;
- return undefined;
- }
- property string stlLibsDir: {
- if (stlBaseDir) {
- var infix = buildProfile;
- if (armMode === "thumb")
- infix = FileInfo.joinPaths(infix, "thumb");
- return FileInfo.joinPaths(stlBaseDir, "libs", infix);
- }
- return undefined;
- }
-
- property string sharedStlFilePath: (stlLibsDir && appStl.endsWith("_shared"))
- ? FileInfo.joinPaths(stlLibsDir, cpp.dynamicLibraryPrefix + appStl + cpp.dynamicLibrarySuffix)
- : undefined
- property string staticStlFilePath: (stlLibsDir && appStl.endsWith("_static"))
- ? FileInfo.joinPaths(stlLibsDir, cpp.staticLibraryPrefix + appStl + cpp.staticLibrarySuffix)
- : undefined
property string gdbserverFileName: "gdbserver"
- property string armMode: abi.startsWith("armeabi")
+ property string armMode: abi && abi.startsWith("armeabi")
? (qbs.buildVariant === "debug" ? "arm" : "thumb")
: undefined;
PropertyOptions {
- name: "armModeType"
+ name: "armMode"
description: "Determines the instruction set for armeabi configurations."
allowedValues: ["arm", "thumb"]
}
- cpp.toolchainInstallPath: FileInfo.joinPaths(ndkDir, "toolchains", toolchainDir, "prebuilt",
- hostArch, "bin")
-
- cpp.toolchainPrefix: {
- if (qbs.toolchain && qbs.toolchain.contains("clang"))
- return undefined;
- return [cpp.targetAbi === "androideabi" ? "arm" : cpp.targetArch,
- cpp.targetSystem, cpp.targetAbi].join("-") + "-";
- }
-
- qbs.optimization: cpp.targetAbi === "androideabi" ? "small" : base
-
- cpp.enableExceptions: appStl !== "system"
- cpp.enableRtti: appStl !== "system"
-
- cpp.commonCompilerFlags: NdkUtils.commonCompilerFlags(qbs.buildVariant, abi, hardFloat, armMode)
-
- cpp.linkerFlags: NdkUtils.commonLinkerFlags(abi, hardFloat)
-
- cpp.libraryPaths: {
- var prefix = FileInfo.joinPaths(cpp.sysroot, "usr");
- var paths = [];
- if (abi === "mips64" || abi === "x86_64") // no lib64 for arm64-v8a
- paths.push(FileInfo.joinPaths(prefix, "lib64"));
- paths.push(FileInfo.joinPaths(prefix, "lib"));
- return paths;
- }
-
- cpp.dynamicLibraries: {
- var libs = ["c"];
- if (!hardFloat)
- libs.push("m");
- if (sharedStlFilePath)
- libs.push(sharedStlFilePath);
- return libs;
- }
- cpp.staticLibraries: {
- var libs = ["gcc"];
- if (hardFloat)
- libs.push("m_hard");
- if (staticStlFilePath)
- libs.push(staticStlFilePath);
- return libs;
- }
- cpp.systemIncludePaths: {
- var includes = [];
- if (appStl === "system") {
- includes.push(FileInfo.joinPaths(cxxStlBaseDir, "system", "include"));
- } else if (appStl.startsWith("gabi++")) {
- includes.push(FileInfo.joinPaths(gabiBaseDir, "include"));
- } else if (appStl.startsWith("stlport")) {
- includes.push(FileInfo.joinPaths(stlPortBaseDir, "stlport"));
- } else if (appStl.startsWith("gnustl")) {
- includes.push(FileInfo.joinPaths(gnuStlBaseDir, "include"));
- includes.push(FileInfo.joinPaths(gnuStlBaseDir, "libs", buildProfile, "include"));
- includes.push(FileInfo.joinPaths(gnuStlBaseDir, "include", "backward"));
- } else if (appStl.startsWith("c++_")) {
- includes.push(FileInfo.joinPaths(llvmStlBaseDir, "libcxx", "include"));
- includes.push(FileInfo.joinPaths(llvmStlBaseDir + "abi", "libcxxabi", "include"));
- }
- return includes;
- }
- cpp.defines: {
- var list = defines;
- if (hardFloat)
- list.push("_NDK_MATH_NO_SOFTFP=1");
- return list;
- }
- cpp.sysroot: FileInfo.joinPaths(ndkDir, "platforms", platform,
- "arch-" + NdkUtils.abiNameToDirName(abi))
-
- cpp.targetArch: {
- if (qbs.architecture === "arm64")
- return "aarch64";
- if (qbs.architecture === "armv5")
- return qbs.architecture + "te";
- if (qbs.architecture === "x86")
- return "i686";
- return qbs.architecture;
- }
-
- cpp.targetVendor: "none"
- cpp.targetSystem: "linux"
- cpp.targetAbi: "android" + (["armeabi", "armeabi-v7a"].contains(abi) ? "eabi" : "")
-
- Rule {
- inputs: ["dynamiclibrary"]
- outputFileTags: ["android.nativelibrary", "android.gdbserver-info", "android.stl-info"]
- outputArtifacts: {
- var artifacts = [{
- filePath: FileInfo.joinPaths("stripped-libs",
- inputs["dynamiclibrary"][0].fileName),
- fileTags: ["android.nativelibrary"]
- }];
- if (product.moduleProperty("qbs", "buildVariant") === "debug") {
- artifacts.push({
- filePath: "android.gdbserver-info.txt",
- fileTags: ["android.gdbserver-info"]
- });
- }
- var stlFilePath = ModUtils.moduleProperty(product, "sharedStlFilePath");
- if (stlFilePath)
- artifacts.push({filePath: "android.stl-info.txt", fileTags: ["android.stl-info"]});
- return artifacts;
- }
-
- prepare: {
- var stlFilePath = ModUtils.moduleProperty(product, "sharedStlFilePath");
- var copyCmd = new JavaScriptCommand();
- copyCmd.silent = true;
- copyCmd.stlFilePath = stlFilePath;
- copyCmd.sourceCode = function() {
- File.copy(inputs["dynamiclibrary"][0].filePath,
- outputs["android.nativelibrary"][0].filePath);
- var destDir = FileInfo.joinPaths("lib", ModUtils.moduleProperty(product, "abi"));
- if (product.moduleProperty("qbs", "buildVariant") === "debug") {
- var arch = ModUtils.moduleProperty(product, "abi");
- arch = NdkUtils.abiNameToDirName(arch);
- var srcPath = FileInfo.joinPaths(ModUtils.moduleProperty(product, "ndkDir"),
- "prebuilt/android-" + arch, "gdbserver/gdbserver");
- var targetPath = FileInfo.joinPaths(destDir, ModUtils.moduleProperty(product,
- "gdbserverFileName"));
- var infoFile = new TextFile(outputs["android.gdbserver-info"][0].filePath,
- TextFile.WriteOnly);
- infoFile.writeLine(srcPath);
- infoFile.writeLine(targetPath);
- infoFile.close();
- }
- if (stlFilePath) {
- var srcPath = stlFilePath;
- var targetPath = FileInfo.joinPaths(destDir, FileInfo.fileName(srcPath));
- var infoFile = new TextFile(outputs["android.stl-info"][0].filePath,
- TextFile.WriteOnly);
- infoFile.writeLine(srcPath);
- infoFile.writeLine(targetPath);
- infoFile.close();
- }
- }
- var stripArgs = ["--strip-unneeded", outputs["android.nativelibrary"][0].filePath];
- if (stlFilePath)
- stripArgs.push(stlFilePath);
- var stripCmd = new Command(product.moduleProperty("cpp", "stripPath"), stripArgs);
- stripCmd.description = "Stripping unneeded symbols from "
- + outputs["android.nativelibrary"][0].fileName;
- return [copyCmd, stripCmd];
- }
+ validate: {
+ var validator = new ModUtils.PropertyValidator("Android.ndk");
+ validator.setRequiredProperty("abi", abi);
+ validator.setRequiredProperty("appStl", appStl);
+ validator.setRequiredProperty("toolchainVersion", toolchainVersion);
+ validator.setRequiredProperty("hostArch", hostArch);
+ validator.setRequiredProperty("ndkDir", ndkDir);
+ validator.setRequiredProperty("platform", platform);
+ validator.setRequiredProperty("toolchainVersionNumber", toolchainVersionNumber);
+ return validator.validate();
}
}
diff --git a/share/qbs/modules/Android/ndk/utils.js b/share/qbs/modules/Android/ndk/utils.js
index 8c4f2cd70..ba7118dea 100644
--- a/share/qbs/modules/Android/ndk/utils.js
+++ b/share/qbs/modules/Android/ndk/utils.js
@@ -29,23 +29,36 @@
****************************************************************************/
function abiNameToDirName(abiName) {
- if (abiName.startsWith("armeabi"))
+ switch (abiName) {
+ case "armeabi":
+ case "armeabi-v7a":
return "arm";
- if (abiName.startsWith("arm64"))
+ case "arm64-v8a":
return "arm64";
- return abiName;
+ default:
+ return abiName;
+ }
}
function androidAbi(arch) {
- if (arch === "x86" || arch === "x86_64")
+ switch (arch) {
+ case "arm64":
+ return "arm64-v8a";
+ case "armv5":
+ case "armv5te":
+ return "armeabi";
+ case "armv7":
+ case "armv7a":
+ return "armeabi-v7a";
+ case "mips":
+ case "mipsel":
+ return "mips";
+ case "mips64":
+ case "mips64el":
+ return "mips64";
+ default:
return arch;
- return {
- "arm64": "arm64-v8a",
- "armv5": "armeabi",
- "armv7": "armeabi-v7a",
- "mipsel": "mips",
- "mips64el": "mips64"
- }[arch];
+ }
}
function commonCompilerFlags(buildVariant, abi, hardFloat, armMode) {
@@ -67,10 +80,10 @@ function commonCompilerFlags(buildVariant, abi, hardFloat, armMode) {
flags.push("-fpic", "-fstack-protector", "-finline-limit=64");
if (abi === "armeabi")
- flags.push("-march=armv5te", "-mtune=xscale", "-msoft-float");
+ flags.push("-mtune=xscale", "-msoft-float");
if (abi === "armeabi-v7a") {
- flags.push("-march=armv7-a", "-mfpu=vfpv3-d16");
+ flags.push("-mfpu=vfpv3-d16");
flags.push(hardFloat ? "-mhard-float" : "-mfloat-abi=softfp");
}
@@ -102,7 +115,7 @@ function commonLinkerFlags(abi, hardFloat) {
var flags = ["-no-canonical-prefixes", "-Wl,-z,noexecstack", "-Wl,-z,relro", "-Wl,-z,now"];
if (abi === "armeabi-v7a") {
- flags.push("-march=armv7-a", "-Wl,--fix-cortex-a8");
+ flags.push("-Wl,--fix-cortex-a8");
if (hardFloat)
flags.push("-Wl,-no-warn-mismatch");
}
diff --git a/share/qbs/modules/bundle/BundleModule.qbs b/share/qbs/modules/bundle/BundleModule.qbs
index f1a80a668..005f5f363 100644
--- a/share/qbs/modules/bundle/BundleModule.qbs
+++ b/share/qbs/modules/bundle/BundleModule.qbs
@@ -260,10 +260,6 @@ Module {
patterns: ["Info.plist", "*-Info.plist"]
}
- // TODO: Remove in 1.6 (deprecated, backwards compatibility)
- property path infoPlistFile
- Group { name: "Info.plist"; files: bundle.infoPlistFile ? [bundle.infoPlistFile] : [] }
-
Rule {
condition: qbs.targetOS.contains("darwin")
multiplex: true
diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs
index 7dabab95e..a32e40e95 100644
--- a/share/qbs/modules/cpp/CppModule.qbs
+++ b/share/qbs/modules/cpp/CppModule.qbs
@@ -35,12 +35,15 @@ import qbs.WindowsUtils
Module {
condition: false
+ property string compilerVersion:
+ [compilerVersionMajor, compilerVersionMinor, compilerVersionPatch].join(".")
property int compilerVersionMajor
property int compilerVersionMinor
property int compilerVersionPatch
property string warningLevel : 'all' // 'none', 'all'
property bool treatWarningsAsErrors : false
property string architecture: qbs.architecture
+ property string machineType // undocumented
property string optimization: qbs.optimization
property bool debugInformation: qbs.debugInformation
property bool enableReproducibleBuilds: false
@@ -51,15 +54,6 @@ Module {
property bool useObjcPrecompiledHeader: false
property bool useObjcxxPrecompiledHeader: false
- // TODO: Remove these in 1.6
- property path cxxPrecompiledHeader: precompiledHeader
- // ### default to undefined on non-Apple platforms for now - QBS-346
- property path precompiledHeader
- property path cPrecompiledHeader: precompiledHeader
- property path objcPrecompiledHeader: qbs.targetOS.contains("darwin") ? precompiledHeader : undefined
- property path objcxxPrecompiledHeader: qbs.targetOS.contains("darwin") ? precompiledHeader : undefined
- property path precompiledHeaderDir: product.buildDirectory
-
property stringList defines
property stringList platformDefines: qbs.enableDebugCode ? [] : ["NDEBUG"]
property stringList compilerDefines
@@ -131,26 +125,14 @@ Module {
be set."
}
- property string installNamePrefix
- PropertyOptions {
- name: "installNamePrefix"
- description: "The prefix for the internal install name (LC_ID_DYLIB) of a dynamic library \
- on Darwin (OS X and iOS)."
- }
-
property pathList includePaths
property pathList systemIncludePaths
+ property pathList compilerIncludePaths
property pathList libraryPaths
+ property pathList compilerLibraryPaths
property pathList frameworkPaths
property pathList systemFrameworkPaths
-
- // TODO: Remove in 1.6 (deprecated, backwards compatibility)
- property pathList linkerScripts
- Group {
- name: "qbs_cpp_linkerscript"
- files: cpp.linkerScripts || []
- fileTags: ["linkerscript"]
- }
+ property pathList compilerFrameworkPaths
property string assemblerName
property string assemblerPath: assemblerName
diff --git a/share/qbs/modules/cpp/DarwinGCC.qbs b/share/qbs/modules/cpp/DarwinGCC.qbs
index 7232eb0d8..d0ce5a35e 100644
--- a/share/qbs/modules/cpp/DarwinGCC.qbs
+++ b/share/qbs/modules/cpp/DarwinGCC.qbs
@@ -38,7 +38,7 @@ import qbs.TextFile
UnixGCC {
condition: false
- Depends { name: "xcode"; required: false }
+ Depends { name: "xcode"; required: qbs.toolchain && qbs.toolchain.contains("xcode") }
targetVendor: "apple"
targetSystem: "darwin"
@@ -56,8 +56,6 @@ UnixGCC {
? FileInfo.joinPaths(xcode.toolchainPath, "usr", "bin") : base
sysroot: xcode.present ? xcode.sdkPath : base
- sonamePrefix: installNamePrefix // TODO: Remove in 1.6 (deprecated, backwards compatibility)
-
setupBuildEnvironment: {
for (var key in buildEnv) {
v = new ModUtils.EnvironmentVariable(key);
diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs
index 82ce7bb85..e5fecb332 100644
--- a/share/qbs/modules/cpp/GenericGCC.qbs
+++ b/share/qbs/modules/cpp/GenericGCC.qbs
@@ -33,6 +33,7 @@ import qbs.File
import qbs.FileInfo
import qbs.ModUtils
import qbs.PathTools
+import qbs.Probes
import qbs.Process
import qbs.Utilities
import qbs.UnixUtils
@@ -48,13 +49,29 @@ CppModule {
}
}
+ Probes.GccProbe {
+ id: gccProbe
+ compilerFilePath: compilerPath
+ preferredArchitecture: targetArch
+ preferredMachineType: machineType
+ }
+
+ qbs.architecture: gccProbe.found ? gccProbe.architecture : original
+
+ compilerVersionMajor: gccProbe.versionMajor
+ compilerVersionMinor: gccProbe.versionMinor
+ compilerVersionPatch: gccProbe.versionPatch
+
+ compilerIncludePaths: gccProbe.includePaths
+ compilerFrameworkPaths: gccProbe.frameworkPaths
+ compilerLibraryPaths: gccProbe.libraryPaths
+
property string target: [targetArch, targetVendor, targetSystem, targetAbi].join("-")
property string targetArch: qbs.architecture === "x86" ? "i386" : qbs.architecture
property string targetVendor: "unknown"
property string targetSystem: "unknown"
property string targetAbi: "unknown"
- property stringList transitiveSOs
property string toolchainPrefix
property path toolchainInstallPath
assemblerName: 'as'
@@ -162,6 +179,66 @@ CppModule {
return base;
}
+ validate: {
+ var validator = new ModUtils.PropertyValidator("cpp");
+ validator.setRequiredProperty("architecture", architecture,
+ "you might want to re-run 'qbs-setup-toolchains'");
+ if (gccProbe.architecture) {
+ validator.addCustomValidator("architecture", architecture, function (value) {
+ return Utilities.canonicalArchitecture(architecture) === Utilities.canonicalArchitecture(gccProbe.architecture);
+ }, "'" + architecture + "' differs from the architecture produced by this compiler (" +
+ gccProbe.architecture +")");
+ } else {
+ // This is a warning and not an error on the rare chance some new architecture comes
+ // about which qbs does not know about the macros of. But it *might* still work.
+ if (architecture)
+ console.warn("Unknown architecture '" + architecture + "' " +
+ "may not be supported by this compiler.");
+ }
+
+ var validateFlagsFunction = function (value) {
+ if (value) {
+ for (var i = 0; i < value.length; ++i) {
+ if (["-target", "-triple", "-arch"].contains(value[i])
+ || value[i].startsWith("-march="))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ var msg = "'-target', '-triple', '-arch' and '-march' cannot appear in flags; set qbs.architecture instead";
+ validator.addCustomValidator("assemblerFlags", assemblerFlags, validateFlagsFunction, msg);
+ validator.addCustomValidator("cppFlags", cppFlags, validateFlagsFunction, msg);
+ validator.addCustomValidator("cFlags", cFlags, validateFlagsFunction, msg);
+ validator.addCustomValidator("cxxFlags", cxxFlags, validateFlagsFunction, msg);
+ validator.addCustomValidator("objcFlags", objcFlags, validateFlagsFunction, msg);
+ validator.addCustomValidator("objcxxFlags", objcxxFlags, validateFlagsFunction, msg);
+ validator.addCustomValidator("commonCompilerFlags", commonCompilerFlags, validateFlagsFunction, msg);
+ validator.addCustomValidator("platformAssemblerFlags", platformAssemblerFlags, validateFlagsFunction, msg);
+ //validator.addCustomValidator("platformCppFlags", platformCppFlags, validateFlagsFunction, msg);
+ validator.addCustomValidator("platformCFlags", platformCFlags, validateFlagsFunction, msg);
+ validator.addCustomValidator("platformCxxFlags", platformCxxFlags, validateFlagsFunction, msg);
+ validator.addCustomValidator("platformObjcFlags", platformObjcFlags, validateFlagsFunction, msg);
+ validator.addCustomValidator("platformObjcxxFlags", platformObjcxxFlags, validateFlagsFunction, msg);
+ validator.addCustomValidator("platformCommonCompilerFlags", platformCommonCompilerFlags, validateFlagsFunction, msg);
+
+ validator.setRequiredProperty("compilerVersion", compilerVersion);
+ validator.setRequiredProperty("compilerVersionMajor", compilerVersionMajor);
+ validator.setRequiredProperty("compilerVersionMinor", compilerVersionMinor);
+ validator.setRequiredProperty("compilerVersionPatch", compilerVersionPatch);
+ validator.addVersionValidator("compilerVersion", compilerVersion, 3, 3);
+ validator.addRangeValidator("compilerVersionMajor", compilerVersionMajor, 1);
+ validator.addRangeValidator("compilerVersionMinor", compilerVersionMinor, 0);
+ validator.addRangeValidator("compilerVersionPatch", compilerVersionPatch, 0);
+
+ validator.setRequiredProperty("compilerIncludePaths", compilerIncludePaths);
+ validator.setRequiredProperty("compilerFrameworkPaths", compilerFrameworkPaths);
+ validator.setRequiredProperty("compilerLibraryPaths", compilerLibraryPaths);
+
+ validator.validate();
+ }
+
Rule {
id: dynamicLibraryLinker
multiplex: true
@@ -188,7 +265,6 @@ CppModule {
+ PathTools.dynamicLibraryFilePath(product),
fileTags: ["dynamiclibrary_copy"],
alwaysUpdated: false,
- cpp: { transitiveSOs: Gcc.collectTransitiveSos(inputs) }
};
var artifacts = [lib, libCopy];
@@ -392,55 +468,6 @@ CppModule {
}
}
- // TODO: Remove in 1.6
- Transformer {
- condition: cPrecompiledHeader !== undefined
- inputs: cPrecompiledHeader
- Artifact {
- filePath: product.name + "_c.gch"
- fileTags: "c_pch"
- }
- prepare: {
- return Gcc.prepareCompiler.apply(this, arguments);
- }
- }
-
- Transformer {
- condition: cxxPrecompiledHeader !== undefined
- inputs: cxxPrecompiledHeader
- Artifact {
- filePath: product.name + "_cpp.gch"
- fileTags: "cpp_pch"
- }
- prepare: {
- return Gcc.prepareCompiler.apply(this, arguments);
- }
- }
-
- Transformer {
- condition: objcPrecompiledHeader !== undefined
- inputs: objcPrecompiledHeader
- Artifact {
- filePath: product.name + "_objc.gch"
- fileTags: "objc_pch"
- }
- prepare: {
- return Gcc.prepareCompiler.apply(this, arguments);
- }
- }
-
- Transformer {
- condition: objcxxPrecompiledHeader !== undefined
- inputs: objcxxPrecompiledHeader
- Artifact {
- filePath: product.name + "_objcpp.gch"
- fileTags: "objcpp_pch"
- }
- prepare: {
- return Gcc.prepareCompiler.apply(this, arguments);
- }
- }
-
FileTagger {
patterns: "*.s"
fileTags: ["asm"]
diff --git a/share/qbs/modules/cpp/linux-gcc.qbs b/share/qbs/modules/cpp/LinuxGCC.qbs
index 2d633ae1d..84570a55c 100644
--- a/share/qbs/modules/cpp/linux-gcc.qbs
+++ b/share/qbs/modules/cpp/LinuxGCC.qbs
@@ -31,7 +31,7 @@
import qbs 1.0
UnixGCC {
- condition: qbs.targetOS.contains('linux') &&
+ condition: qbs.targetOS.contains('linux') && !qbs.targetOS.contains("android") &&
qbs.toolchain && qbs.toolchain.contains('gcc')
rpaths: ['$ORIGIN']
diff --git a/share/qbs/modules/cpp/android-gcc.qbs b/share/qbs/modules/cpp/android-gcc.qbs
new file mode 100644
index 000000000..c42f78578
--- /dev/null
+++ b/share/qbs/modules/cpp/android-gcc.qbs
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+import qbs
+import qbs.File
+import qbs.FileInfo
+import qbs.ModUtils
+import qbs.TextFile
+import "../../modules/Android/ndk/utils.js" as NdkUtils
+
+LinuxGCC {
+ Depends { name: "Android.ndk" }
+
+ condition: qbs.targetOS.contains("android") &&
+ qbs.toolchain && qbs.toolchain.contains("gcc")
+ rpaths: ['$ORIGIN']
+
+ property string toolchainDir: {
+ if (qbs.toolchain && qbs.toolchain.contains("clang"))
+ return "llvm-" + Android.ndk.toolchainVersionNumber;
+ if (["x86", "x86_64"].contains(Android.ndk.abi))
+ return Android.ndk.abi + "-" + Android.ndk.toolchainVersionNumber;
+ return toolchainPrefix + Android.ndk.toolchainVersionNumber;
+ }
+
+ property string cxxStlBaseDir: FileInfo.joinPaths(Android.ndk.ndkDir, "sources", "cxx-stl")
+ property string gabiBaseDir: FileInfo.joinPaths(cxxStlBaseDir, "gabi++")
+ property string stlPortBaseDir: FileInfo.joinPaths(cxxStlBaseDir, "stlport")
+ property string gnuStlBaseDir: FileInfo.joinPaths(cxxStlBaseDir, "gnu-libstdc++",
+ Android.ndk.toolchainVersionNumber)
+ property string llvmStlBaseDir: FileInfo.joinPaths(cxxStlBaseDir, "llvm-libc++")
+ property string stlBaseDir: {
+ if (Android.ndk.appStl.startsWith("gabi++_"))
+ return gabiBaseDir;
+ else if (Android.ndk.appStl.startsWith("stlport_"))
+ return stlPortBaseDir;
+ else if (Android.ndk.appStl.startsWith("gnustl_"))
+ return gnuStlBaseDir;
+ else if (Android.ndk.appStl.startsWith("c++_"))
+ return llvmStlBaseDir;
+ return undefined;
+ }
+
+ property string stlLibsDir: {
+ if (stlBaseDir) {
+ var infix = Android.ndk.buildProfile;
+ if (Android.ndk.armMode === "thumb")
+ infix = FileInfo.joinPaths(infix, "thumb");
+ return FileInfo.joinPaths(stlBaseDir, "libs", infix);
+ }
+ return undefined;
+ }
+
+ property string sharedStlFilePath: (stlLibsDir && Android.ndk.appStl.endsWith("_shared"))
+ ? FileInfo.joinPaths(stlLibsDir, dynamicLibraryPrefix + Android.ndk.appStl + dynamicLibrarySuffix)
+ : undefined
+ property string staticStlFilePath: (stlLibsDir && Android.ndk.appStl.endsWith("_static"))
+ ? FileInfo.joinPaths(stlLibsDir, staticLibraryPrefix + Android.ndk.appStl + staticLibrarySuffix)
+ : undefined
+
+ toolchainInstallPath: FileInfo.joinPaths(Android.ndk.ndkDir, "toolchains",
+ toolchainDir, "prebuilt",
+ Android.ndk.hostArch, "bin")
+
+ toolchainPrefix: {
+ if (qbs.toolchain && qbs.toolchain.contains("clang"))
+ return undefined;
+ return [targetAbi === "androideabi" ? "arm" : targetArch,
+ targetSystem, targetAbi].join("-") + "-";
+ }
+
+ machineType: {
+ if (Android.ndk.abi === "armeabi")
+ return "armv5te";
+ if (Android.ndk.abi === "armeabi-v7a")
+ return "armv7-a";
+ }
+
+ qbs.optimization: targetAbi === "androideabi" ? "small" : base
+
+ enableExceptions: Android.ndk.appStl !== "system"
+ enableRtti: Android.ndk.appStl !== "system"
+
+ commonCompilerFlags: NdkUtils.commonCompilerFlags(qbs.buildVariant, Android.ndk.abi,
+ Android.ndk.hardFloat, Android.ndk.armMode)
+
+ linkerFlags: NdkUtils.commonLinkerFlags(Android.ndk.abi, Android.ndk.hardFloat)
+
+ libraryPaths: {
+ var prefix = FileInfo.joinPaths(sysroot, "usr");
+ var paths = [];
+ if (Android.ndk.abi === "mips64" || Android.ndk.abi === "x86_64") // no lib64 for arm64-v8a
+ paths.push(FileInfo.joinPaths(prefix, "lib64"));
+ paths.push(FileInfo.joinPaths(prefix, "lib"));
+ return paths;
+ }
+
+ dynamicLibraries: {
+ var libs = ["c"];
+ if (!Android.ndk.hardFloat)
+ libs.push("m");
+ if (sharedStlFilePath)
+ libs.push(sharedStlFilePath);
+ return libs;
+ }
+ staticLibraries: {
+ var libs = ["gcc"];
+ if (Android.ndk.hardFloat)
+ libs.push("m_hard");
+ if (staticStlFilePath)
+ libs.push(staticStlFilePath);
+ return libs;
+ }
+ systemIncludePaths: {
+ var includes = [];
+ if (Android.ndk.appStl === "system") {
+ includes.push(FileInfo.joinPaths(cxxStlBaseDir, "system", "include"));
+ } else if (Android.ndk.appStl.startsWith("gabi++")) {
+ includes.push(FileInfo.joinPaths(gabiBaseDir, "include"));
+ } else if (Android.ndk.appStl.startsWith("stlport")) {
+ includes.push(FileInfo.joinPaths(stlPortBaseDir, "stlport"));
+ } else if (Android.ndk.appStl.startsWith("gnustl")) {
+ includes.push(FileInfo.joinPaths(gnuStlBaseDir, "include"));
+ includes.push(FileInfo.joinPaths(gnuStlBaseDir, "libs", Android.ndk.buildProfile, "include"));
+ includes.push(FileInfo.joinPaths(gnuStlBaseDir, "include", "backward"));
+ } else if (Android.ndk.appStl.startsWith("c++_")) {
+ includes.push(FileInfo.joinPaths(llvmStlBaseDir, "libcxx", "include"));
+ includes.push(FileInfo.joinPaths(llvmStlBaseDir + "abi", "libcxxabi", "include"));
+ }
+ return includes;
+ }
+ defines: {
+ var list = ["ANDROID"];
+ if (Android.ndk.hardFloat)
+ list.push("_NDK_MATH_NO_SOFTFP=1");
+ return list;
+ }
+ sysroot: FileInfo.joinPaths(Android.ndk.ndkDir, "platforms", Android.ndk.platform,
+ "arch-" + NdkUtils.abiNameToDirName(Android.ndk.abi))
+
+ targetArch: {
+ switch (qbs.architecture) {
+ case "arm64":
+ return "aarch64";
+ case "armv5":
+ case "armv5te":
+ return "armv5te";
+ case "armv7a":
+ case "x86_64":
+ return qbs.architecture;
+ case "x86":
+ return "i686";
+ case "mips":
+ case "mipsel":
+ return "mipsel";
+ case "mips64":
+ case "mips64el":
+ return "mips64el";
+ }
+ }
+
+ targetVendor: "none"
+ targetSystem: "linux"
+ targetAbi: "android" + (["armeabi", "armeabi-v7a"].contains(Android.ndk.abi) ? "eabi" : "")
+
+ Rule {
+ inputs: ["dynamiclibrary"]
+ outputFileTags: ["android.nativelibrary", "android.gdbserver-info", "android.stl-info"]
+ outputArtifacts: {
+ var artifacts = [{
+ filePath: FileInfo.joinPaths("stripped-libs",
+ inputs["dynamiclibrary"][0].fileName),
+ fileTags: ["android.nativelibrary"]
+ }];
+ if (product.moduleProperty("qbs", "buildVariant") === "debug") {
+ artifacts.push({
+ filePath: "android.gdbserver-info.txt",
+ fileTags: ["android.gdbserver-info"]
+ });
+ }
+ var stlFilePath = product.moduleProperty("cpp", "sharedStlFilePath");
+ if (stlFilePath)
+ artifacts.push({filePath: "android.stl-info.txt", fileTags: ["android.stl-info"]});
+ return artifacts;
+ }
+
+ prepare: {
+ var stlFilePath = product.moduleProperty("cpp", "sharedStlFilePath");
+ var copyCmd = new JavaScriptCommand();
+ copyCmd.silent = true;
+ copyCmd.stlFilePath = stlFilePath;
+ copyCmd.sourceCode = function() {
+ File.copy(inputs["dynamiclibrary"][0].filePath,
+ outputs["android.nativelibrary"][0].filePath);
+ var arch = product.moduleProperty("Android.ndk", "abi");
+ var destDir = FileInfo.joinPaths("lib", arch);
+ if (product.moduleProperty("qbs", "buildVariant") === "debug") {
+ arch = NdkUtils.abiNameToDirName(arch);
+ var srcPath = FileInfo.joinPaths(
+ product.moduleProperty("Android.ndk", "ndkDir"),
+ "prebuilt/android-" + arch, "gdbserver/gdbserver");
+ var targetPath = FileInfo.joinPaths(destDir,
+ product.moduleProperty("Android.ndk", "gdbserverFileName"));
+ var infoFile = new TextFile(outputs["android.gdbserver-info"][0].filePath,
+ TextFile.WriteOnly);
+ infoFile.writeLine(srcPath);
+ infoFile.writeLine(targetPath);
+ infoFile.close();
+ }
+ if (stlFilePath) {
+ var srcPath = stlFilePath;
+ var targetPath = FileInfo.joinPaths(destDir, FileInfo.fileName(srcPath));
+ var infoFile = new TextFile(outputs["android.stl-info"][0].filePath,
+ TextFile.WriteOnly);
+ infoFile.writeLine(srcPath);
+ infoFile.writeLine(targetPath);
+ infoFile.close();
+ }
+ }
+ var stripArgs = ["--strip-unneeded", outputs["android.nativelibrary"][0].filePath];
+ if (stlFilePath)
+ stripArgs.push(stlFilePath);
+ var stripCmd = new Command(product.moduleProperty("cpp", "stripPath"), stripArgs);
+ stripCmd.description = "Stripping unneeded symbols from "
+ + outputs["android.nativelibrary"][0].fileName;
+ return [copyCmd, stripCmd];
+ }
+ }
+
+ validate: {
+ var baseValidator = new ModUtils.PropertyValidator("qbs");
+ baseValidator.addCustomValidator("architecture", targetArch, function (value) {
+ return value !== undefined;
+ }, "unknown Android architecture '" + qbs.architecture + "'.");
+
+ var validator = new ModUtils.PropertyValidator("cpp");
+ validator.setRequiredProperty("targetArch", targetArch);
+
+ return baseValidator.validate() && validator.validate();
+ }
+}
diff --git a/share/qbs/modules/cpp/gcc.js b/share/qbs/modules/cpp/gcc.js
index ebe164d9c..dfecfaac2 100644
--- a/share/qbs/modules/cpp/gcc.js
+++ b/share/qbs/modules/cpp/gcc.js
@@ -77,6 +77,16 @@ function linkerFlags(product, inputs, output) {
var isDarwin = product.moduleProperty("qbs", "targetOS").contains("darwin");
var i, args = additionalCompilerAndLinkerFlags(product);
+ // ### QBS-966
+ if (product.moduleProperty("qbs", "targetOS").contains("android")) {
+ var sharedStlFilePath = product.moduleProperty("cpp", "sharedStlFilePath");
+ if (sharedStlFilePath)
+ dynamicLibraries.push(sharedStlFilePath);
+ var staticStlFilePath = product.moduleProperty("cpp", "staticStlFilePath");
+ if (staticStlFilePath)
+ staticLibraries.push(staticStlFilePath);
+ }
+
if (output.fileTags.contains("dynamiclibrary")) {
args.push(isDarwin ? "-dynamiclib" : "-shared");
@@ -134,18 +144,6 @@ function linkerFlags(product, inputs, output) {
for (i in rpaths)
args = args.concat(escapeLinkerFlags(product, ["-rpath", rpaths[i]]));
- if (product.moduleProperty("qbs", "targetOS").contains('linux')) {
- var transitiveSOs = ModUtils.modulePropertiesFromArtifacts(product,
- inputs.dynamiclibrary_copy, 'cpp', 'transitiveSOs')
- var uniqueSOs = [].uniqueConcat(transitiveSOs)
- for (i in uniqueSOs) {
- // The real library is located one level up.
- args = args.concat(escapeLinkerFlags(product, [
- "-rpath-link=" +
- FileInfo.path(FileInfo.path(uniqueSOs[i]))]));
- }
- }
-
if (product.moduleProperty("cpp", "entryPoint"))
args = args.concat(escapeLinkerFlags(product, ["-e", product.moduleProperty("cpp", "entryPoint")]));
@@ -358,6 +356,10 @@ function compilerFlags(product, input, output) {
else if (arch === 'i386')
args.push('-m32');
+ var march = product.moduleProperty("cpp", "machineType");
+ if (march)
+ args.push("-march=" + march);
+
var minimumDarwinVersion = ModUtils.moduleProperty(product, "minimumDarwinVersion");
if (minimumDarwinVersion) {
var flag = ModUtils.moduleProperty(product, "minimumDarwinVersionCompilerFlag");
@@ -468,14 +470,6 @@ function compilerFlags(product, input, output) {
args.push('-include', pchFilePath);
}
- // TODO: Remove in 1.6
- if (!pchOutput && ModUtils.moduleProperty(input, 'precompiledHeader', tag)) {
- pchFilePath = FileInfo.joinPaths(
- ModUtils.moduleProperty(product, "precompiledHeaderDir"),
- product.name + "_" + tag);
- args.push('-include', pchFilePath);
- }
-
var positionIndependentCode = input.moduleProperty('cpp', 'positionIndependentCode')
if (effectiveType === EffectiveTypeEnum.LIB) {
if (positionIndependentCode !== false && !product.moduleProperty("qbs", "toolchain").contains("mingw"))
@@ -675,19 +669,6 @@ function concatLibs(libs, deplibs) {
return r;
}
-function collectTransitiveSos(inputs)
-{
- var result = [];
- for (var i in inputs.dynamiclibrary_copy) {
- var lib = inputs.dynamiclibrary_copy[i];
- var impliedLibs = ModUtils.moduleProperties(lib, 'transitiveSOs');
- var libsToAdd = [lib.filePath].concat(impliedLibs);
- result = result.concat(libsToAdd);
- }
- result = concatLibs([], result);
- return result;
-}
-
function prepareLinker(project, product, inputs, outputs, input, output) {
var i, primaryOutput, cmd, commands = [];
@@ -895,3 +876,77 @@ function debugInfoArtifacts(product) {
function isNumericProductVersion(version) {
return version && version.match(/^([0-9]+\.){0,3}[0-9]+$/);
}
+
+function dumpMacros(compilerFilePath, args, nullDevice) {
+ var p = new Process();
+ try {
+ p.setEnv("LC_ALL", "C");
+ p.exec(compilerFilePath, (args || []).concat(["-dM", "-E", "-x", "c", nullDevice]));
+ var map = {};
+ p.readStdOut().trim().split("\n").map(function (line) {
+ var parts = line.split(" ", 3);
+ map[parts[1]] = parts[2];
+ });
+ return map;
+ } finally {
+ p.close();
+ }
+}
+
+function dumpDefaultPaths(compilerFilePath, args, nullDevice, pathListSeparator, targetOS,
+ sysroot) {
+ var p = new Process();
+ try {
+ p.setEnv("LC_ALL", "C");
+ args = args || [];
+ if (sysroot) {
+ if (targetOS.contains("darwin"))
+ args.push("-isysroot", sysroot);
+ else
+ args.push("--sysroot=" + sysroot);
+ }
+ p.exec(compilerFilePath, args.concat(["-v", "-E", "-x", "c++", nullDevice]));
+ var suffix = " (framework directory)";
+ var includePaths = [];
+ var libraryPaths = [];
+ var frameworkPaths = [];
+ var addIncludes = false;
+ var lines = p.readStdErr().trim().split("\n").map(function (line) { return line.trim(); });
+ for (var i = 0; i < lines.length; ++i) {
+ var line = lines[i];
+ var prefix = "LIBRARY_PATH=";
+ if (line.startsWith(prefix)) {
+ libraryPaths = libraryPaths.concat(line.substr(prefix.length)
+ .split(pathListSeparator));
+ } else if (line === "#include <...> search starts here:") {
+ addIncludes = true;
+ } else if (line === "End of search list.") {
+ addIncludes = false;
+ } else if (addIncludes) {
+ if (line.endsWith(suffix))
+ frameworkPaths.push(line.substr(0, line.length - suffix.length));
+ else
+ includePaths.push(line);
+ }
+ }
+
+ sysroot = sysroot || "";
+
+ if (includePaths.length === 0)
+ includePaths.push(sysroot + "/usr/include", sysroot + "/usr/local/include");
+
+ if (libraryPaths.length === 0)
+ libraryPaths.push(sysroot + "/lib", sysroot + "/usr/lib");
+
+ if (frameworkPaths.length === 0)
+ frameworkPaths.push(sysroot + "/System/Library/Frameworks");
+
+ return {
+ "includePaths": includePaths,
+ "libraryPaths": libraryPaths,
+ "frameworkPaths": frameworkPaths
+ };
+ } finally {
+ p.close();
+ }
+}
diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js
index ad4bada21..501197775 100644
--- a/share/qbs/modules/cpp/msvc.js
+++ b/share/qbs/modules/cpp/msvc.js
@@ -150,27 +150,6 @@ function prepareCompiler(project, product, inputs, outputs, input, output) {
else if (tag === "c")
args.push("/TC");
- // precompiled header file
- // TODO: Remove in 1.6
- var pch = ModUtils.moduleProperty(input, "precompiledHeader", tag);
- if (pch) {
- if (pchOutput) {
- // create PCH
- args.push("/Yc");
- args.push("/Fp" + FileInfo.toWindowsSeparators(pchOutput.filePath));
- args.push("/Fo" + FileInfo.toWindowsSeparators(objOutput.filePath));
- args.push(FileInfo.toWindowsSeparators(input.filePath));
- } else {
- // use PCH
- var pchHeaderName = FileInfo.toWindowsSeparators(pch);
- var pchName = FileInfo.toWindowsSeparators(ModUtils.moduleProperty(product, "precompiledHeaderDir")
- + "\\.obj\\" + product.name + "_" + tag + ".pch");
- args.push("/FI" + pchHeaderName);
- args.push("/Yu" + pchHeaderName);
- args.push("/Fp" + pchName);
- }
- }
-
var commands = [];
var usePch = ModUtils.moduleProperty(input, "usePrecompiledHeader", tag);
if (usePch) {
diff --git a/share/qbs/modules/cpp/windows-msvc.qbs b/share/qbs/modules/cpp/windows-msvc.qbs
index fcf8e36c0..be3d72769 100644
--- a/share/qbs/modules/cpp/windows-msvc.qbs
+++ b/share/qbs/modules/cpp/windows-msvc.qbs
@@ -73,7 +73,6 @@ CppModule {
separateDebugInformation: true
property bool generateManifestFile: true
- property bool generateManifestFiles: generateManifestFile // TODO: Remove in 1.6
property path toolchainInstallPath
architecture: qbs.architecture
staticLibraryPrefix: ""
@@ -128,48 +127,6 @@ CppModule {
}
}
- // TODO: Remove in 1.6
- Transformer {
- condition: cPrecompiledHeader !== undefined
- inputs: cPrecompiledHeader
- Artifact {
- fileTags: ['obj']
- filePath: {
- var completeBaseName = FileInfo.completeBaseName(product.moduleProperty("cpp",
- "cPrecompiledHeader"));
- return ".obj/" + Utilities.getHash(completeBaseName) + '_c.obj'
- }
- }
- Artifact {
- fileTags: ['c_pch']
- filePath: ".obj/" + product.name + '_c.pch'
- }
- prepare: {
- return MSVC.prepareCompiler.apply(this, arguments);
- }
- }
-
- Transformer {
- condition: cxxPrecompiledHeader !== undefined
- inputs: cxxPrecompiledHeader
- explicitlyDependsOn: ["c_pch"] // to prevent vc--0.pdb conflict
- Artifact {
- fileTags: ['obj']
- filePath: {
- var completeBaseName = FileInfo.completeBaseName(product.moduleProperty("cpp",
- "cxxPrecompiledHeader"));
- return ".obj/" + Utilities.getHash(completeBaseName) + '_cpp.obj'
- }
- }
- Artifact {
- fileTags: ['cpp_pch']
- filePath: ".obj/" + product.name + '_cpp.pch'
- }
- prepare: {
- return MSVC.prepareCompiler.apply(this, arguments);
- }
- }
-
Rule {
id: compiler
inputs: ["cpp", "c"]
diff --git a/share/qbs/modules/java/JavaModule.qbs b/share/qbs/modules/java/JavaModule.qbs
index 69845adc9..9fff42b09 100644
--- a/share/qbs/modules/java/JavaModule.qbs
+++ b/share/qbs/modules/java/JavaModule.qbs
@@ -180,6 +180,7 @@ Module {
JavaUtils.javacArguments(product, inputs,
JavaUtils.helperOverrideArgs(product,
"javac")));
+ cmd.ignoreDryRun = true;
cmd.silent = true;
return [cmd];
}
diff --git a/share/qbs/modules/qbs/common.qbs b/share/qbs/modules/qbs/common.qbs
index 3732b91a7..1756b8d98 100644
--- a/share/qbs/modules/qbs/common.qbs
+++ b/share/qbs/modules/qbs/common.qbs
@@ -71,7 +71,7 @@ Module {
property string nullDevice: hostOS.contains("windows") ? "NUL" : "/dev/null"
property path shellPath: hostOS.contains("windows") ? windowsShellPath : "/bin/sh"
property string profile
- property stringList toolchain
+ property stringList toolchain: []
property string architecture
property bool install: false
property path installSourceBase
@@ -115,6 +115,35 @@ Module {
}, "'" + architecture + "' is invalid. You must use the canonical name '" +
Utilities.canonicalArchitecture(architecture) + "'");
+ validator.addCustomValidator("toolchain", toolchain, function (value) {
+ if (toolchain === undefined)
+ return false; // cannot have null toolchain, empty is valid... for now
+ var canonical = Utilities.canonicalToolchain.apply(this, toolchain);
+ for (var i = 0; i < Math.max(canonical.length, toolchain.length); ++i) {
+ if (canonical[i] !== toolchain[i])
+ return false;
+ }
+ return true;
+ }, "'" + toolchain + "' is invalid. You must use the canonical list '" +
+ Utilities.canonicalToolchain.apply(this, toolchain) + "'");
+
+ validator.addCustomValidator("toolchain", toolchain, function (value) {
+ // None of the pairs listed here may appear in the same toolchain list.
+ // Note that this check is applied AFTER canonicalization, so for example
+ // {"clang", "msvc"} need not be checked, since a toolchain containing clang is
+ // guaranteed to also contain gcc.
+ var pairs = [
+ ["gcc", "msvc"],
+ ["llvm", "mingw"]
+ ];
+ var canonical = Utilities.canonicalToolchain.apply(this, value);
+ for (var i = 0; i < pairs.length; ++i) {
+ if (canonical.contains(pairs[i][0]) && canonical.contains(pairs[i][1]))
+ return false;
+ }
+ return true;
+ }, "'" + toolchain + "' contains one or more mutually exclusive toolchain types.");
+
validator.validate();
}
@@ -122,14 +151,17 @@ Module {
property string windowsRegistryKey: "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion"
property path windowsSystemRoot: FileInfo.fromWindowsSeparators(Utilities.getNativeSetting(windowsRegistryKey, "SystemRoot"))
property path windowsShellPath: FileInfo.fromWindowsSeparators(Environment.getEnv("COMSPEC")) || FileInfo.joinPaths(windowsSystemRoot, "System32", "cmd.exe")
+ property string windowsPathVariable: hostOS.contains("windows") ? "PATH" : "WINEPATH"
property var commonRunEnvironment: {
var env = Environment.currentEnv();
if (targetOS.contains("windows")) {
var newEntry = FileInfo.toWindowsSeparators(FileInfo.joinPaths(installRoot,
installPrefix));
- env["PATH"] = PathTools.prependOrSetPath(newEntry, env["PATH"], qbs.pathListSeparator);
- } else if (hostOS.contains("darwin") && targetOS.contains("darwin")) {
+ env[windowsPathVariable] = PathTools.prependOrSetPath(newEntry,
+ env[windowsPathVariable],
+ qbs.pathListSeparator);
+ } else if (hostOS.contains("osx") && targetOS.contains("osx")) {
env["DYLD_FRAMEWORK_PATH"] = PathTools.prependOrSetPath([
FileInfo.joinPaths(installRoot, installPrefix, "Library", "Frameworks"),
FileInfo.joinPaths(installRoot, installPrefix, "lib"),
@@ -140,9 +172,6 @@ Module {
FileInfo.joinPaths(installRoot, installPrefix, "Library", "Frameworks"),
FileInfo.joinPaths(installRoot, installPrefix)
].join(pathListSeparator), env["DYLD_LIBRARY_PATH"], qbs.pathListSeparator);
- if (targetOS.contains("ios-simulator") && sysroot)
- env["DYLD_ROOT_PATH"] = PathTools.prependOrSetPath(sysroot, env["DYLD_ROOT_PATH"],
- qbs.pathListSeparator);
} else if (hostOS.contains("unix") && targetOS.contains("unix")) {
env["LD_LIBRARY_PATH"] = PathTools.prependOrSetPath(
FileInfo.joinPaths(installRoot, installPrefix, "lib"), env["LD_LIBRARY_PATH"],
diff --git a/share/qbs/modules/typescript/TypeScriptModule.qbs b/share/qbs/modules/typescript/TypeScriptModule.qbs
index 732eb1f61..ece4d8653 100644
--- a/share/qbs/modules/typescript/TypeScriptModule.qbs
+++ b/share/qbs/modules/typescript/TypeScriptModule.qbs
@@ -227,6 +227,7 @@ Module {
};
var jcmd = new JavaScriptCommand();
+ jcmd.ignoreDryRun = true;
jcmd.silent = true;
jcmd.inputPaths = inputPaths.sort(sortFunc);
jcmd.outputPaths = outputPaths.sort(sortFunc);
@@ -240,6 +241,7 @@ Module {
var args = ["--module", "commonjs",
"--outDir", outDir].concat(outputPaths.filter(function (f) { return !f.endsWith(".json"); }));
var cmd = new Command(ModUtils.moduleProperty(product, "compilerPath"), args);
+ cmd.ignoreDryRun = true;
cmd.silent = true;
return [jcmd, cmd];
}
diff --git a/share/qbs/modules/xcode/xcode.qbs b/share/qbs/modules/xcode/xcode.qbs
index e9cadbf02..f6994e3be 100644
--- a/share/qbs/modules/xcode/xcode.qbs
+++ b/share/qbs/modules/xcode/xcode.qbs
@@ -144,7 +144,7 @@ Module {
}
if (!_sdkSettings) {
- throw "There is no matching SDK available for ' + sdk + '.";
+ throw "There is no matching SDK available for " + sdk + ".";
}
var validator = new ModUtils.PropertyValidator("xcode");
diff --git a/share/share.qbs b/share/share.qbs
index d78dd9a98..7c60a8784 100644
--- a/share/share.qbs
+++ b/share/share.qbs
@@ -5,12 +5,13 @@ import qbs.FileInfo
Product {
name: "qbs resources"
type: ["copied qbs resources"]
+ Depends { name: "qbsbuildconfig" }
Group {
name: "Modules and imports"
files: ["qbs/**/*"]
fileTags: ["qbs resources"]
qbs.install: true
- qbs.installDir: project.resourcesInstallDir + "/share"
+ qbs.installDir: qbsbuildconfig.resourcesInstallDir + "/share"
qbs.installSourceBase: "."
}
@@ -19,14 +20,15 @@ Product {
files: ["../examples/**/*"]
fileTags: []
qbs.install: true
- qbs.installDir: project.resourcesInstallDir + "/share/qbs"
+ qbs.installDir: qbsbuildconfig.resourcesInstallDir + "/share/qbs"
qbs.installSourceBase: ".."
}
Rule {
inputs: ["qbs resources"]
Artifact {
- filePath: FileInfo.joinPaths(project.buildDirectory, project.resourcesInstallDir,
+ filePath: FileInfo.joinPaths(project.buildDirectory,
+ product.moduleProperty("qbsbuildconfig", "resourcesInstallDir"),
"share", FileInfo.relativePath(product.sourceDirectory, input.filePath))
fileTags: ["copied qbs resources"]
}
diff --git a/src/app/config-ui/config-ui.qbs b/src/app/config-ui/config-ui.qbs
index 3f31765c1..de1de7150 100644
--- a/src/app/config-ui/config-ui.qbs
+++ b/src/app/config-ui/config-ui.qbs
@@ -15,7 +15,10 @@ QbsApp {
Group {
condition: qbs.targetOS.contains("osx")
- files: ["fgapp.mm"]
+ files: [
+ "fgapp.mm",
+ "Info.plist"
+ ]
}
Properties {
@@ -25,5 +28,4 @@ QbsApp {
Depends { name: "bundle" }
bundle.isBundle: false
- bundle.infoPlistFile: "Info.plist"
}
diff --git a/src/app/config-ui/mainwindow.cpp b/src/app/config-ui/mainwindow.cpp
index 97e04bc18..2a3627e2f 100644
--- a/src/app/config-ui/mainwindow.cpp
+++ b/src/app/config-ui/mainwindow.cpp
@@ -49,9 +49,9 @@ MainWindow::MainWindow(const QString &settingsDir, QWidget *parent)
m_model = new qbs::SettingsModel(settingsDir, this);
ui->treeView->setModel(m_model);
ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
- connect(ui->treeView, SIGNAL(expanded(QModelIndex)), SLOT(adjustColumns()));
- connect(ui->treeView, SIGNAL(customContextMenuRequested(QPoint)),
- SLOT(provideContextMenu(QPoint)));
+ connect(ui->treeView, &QTreeView::expanded, this, &MainWindow::adjustColumns);
+ connect(ui->treeView, &QWidget::customContextMenuRequested,
+ this, &MainWindow::provideContextMenu);
adjustColumns();
QMenu * const fileMenu = menuBar()->addMenu(tr("&File"));
@@ -59,20 +59,20 @@ MainWindow::MainWindow(const QString &settingsDir, QWidget *parent)
QAction * const reloadAction = new QAction(tr("&Reload"), this);
reloadAction->setShortcut(QKeySequence::Refresh);
- connect(reloadAction, SIGNAL(triggered()), SLOT(reloadSettings()));
+ connect(reloadAction, &QAction::triggered, this, &MainWindow::reloadSettings);
QAction * const saveAction = new QAction(tr("&Save"), this);
saveAction->setShortcut(QKeySequence::Save);
- connect(saveAction, SIGNAL(triggered()), SLOT(saveSettings()));
+ connect(saveAction, &QAction::triggered, this, &MainWindow::saveSettings);
QAction * const expandAllAction = new QAction(tr("&Expand All"), this);
expandAllAction->setShortcut(Qt::CTRL | Qt::Key_E);
- connect(expandAllAction, SIGNAL(triggered()), SLOT(expandAll()));
+ connect(expandAllAction, &QAction::triggered, this, &MainWindow::expandAll);
QAction * const collapseAllAction = new QAction(tr("C&ollapse All"), this);
collapseAllAction->setShortcut(Qt::CTRL | Qt::Key_O);
- connect(collapseAllAction, SIGNAL(triggered()), SLOT(collapseAll()));
+ connect(collapseAllAction, &QAction::triggered, this, &MainWindow::collapseAll);
QAction * const exitAction = new QAction(tr("E&xit"), this);
exitAction->setShortcut(QKeySequence::Quit);
exitAction->setMenuRole(QAction::QuitRole);
- connect(exitAction, SIGNAL(triggered()), SLOT(exit()));
+ connect(exitAction, &QAction::triggered, this, &MainWindow::exit);
fileMenu->addAction(reloadAction);
fileMenu->addAction(saveAction);
diff --git a/src/app/config-ui/mainwindow.h b/src/app/config-ui/mainwindow.h
index f8bba001d..8c6f1d43c 100644
--- a/src/app/config-ui/mainwindow.h
+++ b/src/app/config-ui/mainwindow.h
@@ -49,7 +49,7 @@ public:
bool eventFilter(QObject *watched, QEvent *event);
-private slots:
+private:
void adjustColumns();
void expandAll();
void collapseAll();
@@ -58,7 +58,6 @@ private slots:
void exit();
void provideContextMenu(const QPoint &pos);
-private:
Ui::MainWindow *ui;
qbs::SettingsModel *m_model;
};
diff --git a/src/app/qbs-setup-android/android-setup.cpp b/src/app/qbs-setup-android/android-setup.cpp
index 75997cf82..505d278f7 100644
--- a/src/app/qbs-setup-android/android-setup.cpp
+++ b/src/app/qbs-setup-android/android-setup.cpp
@@ -48,10 +48,10 @@ static QStringList expectedArchs()
{
return QStringList()
<< QStringLiteral("arm64")
- << QStringLiteral("armv5")
- << QStringLiteral("armv7")
- << QStringLiteral("mipsel")
- << QStringLiteral("mips64el")
+ << QStringLiteral("armv5te")
+ << QStringLiteral("armv7a")
+ << QStringLiteral("mips")
+ << QStringLiteral("mips64")
<< QStringLiteral("x86")
<< QStringLiteral("x86_64");
}
diff --git a/src/app/qbs-setup-toolchains/compilerversion.cpp b/src/app/qbs-setup-toolchains/compilerversion.cpp
index d008f20cf..8de5f3ba5 100644
--- a/src/app/qbs-setup-toolchains/compilerversion.cpp
+++ b/src/app/qbs-setup-toolchains/compilerversion.cpp
@@ -92,56 +92,6 @@ static QByteArray runProcess(const QString &exeFilePath, const QStringList &args
return process.readAllStandardOutput().trimmed();
}
-static Version getGccVersion(const QString &compilerFilePath, const QStringList &qbsToolchain)
-{
- QByteArray majorKey;
- QByteArray minorKey;
- QByteArray patchKey;
- if (qbsToolchain.contains(QLatin1String("clang"))) {
- majorKey = "__clang_major__";
- minorKey = "__clang_minor__";
- patchKey = "__clang_patchlevel__";
- } else {
- majorKey = "__GNUC__";
- minorKey = "__GNUC_MINOR__";
- patchKey = "__GNUC_PATCHLEVEL__";
- }
- QTemporaryFile dummyFile;
- if (!dummyFile.open())
- throw ErrorInfo(mkStr("Could not create temporary file (%1)").arg(dummyFile.errorString()));
- dummyFile.close();
- const QStringList compilerArgs = QStringList() << QLatin1String("-E") << QLatin1String("-dM")
- << QLatin1String("-x") << QLatin1String("c")
- << QLatin1String("-c") << dummyFile.fileName();
- const QByteArray compilerOutput = runProcess(compilerFilePath, compilerArgs);
- if (compilerOutput.isEmpty())
- throw ErrorInfo(mkStr("Could not extract version from compiler output."));
- const QList<QByteArray> lines = compilerOutput.split('\n');
- QList<QByteArray> keyParts = QList<QByteArray>() << majorKey << minorKey << patchKey;
- QStringList versionParts = QStringList() << QString() << QString() << QString();
- int partsFound = 0;
- foreach (const QByteArray &line, lines) {
- for (int i = 0; i < keyParts.count() && partsFound < keyParts.count(); ++i) {
- QString &versionPart = versionParts[i];
- if (!versionPart.isEmpty())
- continue;
- const QByteArray cleanLine = line.simplified();
- const QByteArray keyPart = "#define " + keyParts.at(i) + ' ';
- if (!cleanLine.startsWith(keyPart))
- continue;
- versionPart = QString::fromLatin1(cleanLine.mid(keyPart.count()));
- ++partsFound;
- }
- }
- if (partsFound < keyParts.count())
- throw ErrorInfo(mkStr("Failed to extract version from compiler output."));
- const Version version = Version::fromString(versionParts.at(0) + QLatin1Char('.')
- + versionParts.at(1) + QLatin1Char('.') + versionParts.at(2));
- if (!version.isValid())
- throw ErrorInfo(mkStr("Failed to extract version from compiler output."));
- return version;
-}
-
class DummyFile {
public:
DummyFile(const QString &fp) : filePath(fp) { }
@@ -205,15 +155,13 @@ void setCompilerVersion(const QString &compilerFilePath, const QStringList &qbsT
Profile &profile, const QProcessEnvironment &compilerEnv)
{
try {
- Version version;
- if (qbsToolchain.contains(QLatin1String("gcc")))
- version = getGccVersion(compilerFilePath, qbsToolchain);
- else if (qbsToolchain.contains(QLatin1String("msvc")))
- version = getMsvcVersion(compilerFilePath, compilerEnv);
- if (version.isValid()) {
- profile.setValue(QLatin1String("cpp.compilerVersionMajor"), version.majorVersion());
- profile.setValue(QLatin1String("cpp.compilerVersionMinor"), version.minorVersion());
- profile.setValue(QLatin1String("cpp.compilerVersionPatch"), version.patchLevel());
+ if (qbsToolchain.contains(QLatin1String("msvc"))) {
+ const Version version = getMsvcVersion(compilerFilePath, compilerEnv);
+ if (version.isValid()) {
+ profile.setValue(QLatin1String("cpp.compilerVersionMajor"), version.majorVersion());
+ profile.setValue(QLatin1String("cpp.compilerVersionMinor"), version.minorVersion());
+ profile.setValue(QLatin1String("cpp.compilerVersionPatch"), version.patchLevel());
+ }
}
} catch (const ErrorInfo &e) {
qDebug("Warning: Failed to retrieve compiler version: %s", qPrintable(e.toString()));
diff --git a/src/app/qbs-setup-toolchains/probe.cpp b/src/app/qbs-setup-toolchains/probe.cpp
index 728c28739..793c96997 100644
--- a/src/app/qbs-setup-toolchains/probe.cpp
+++ b/src/app/qbs-setup-toolchains/probe.cpp
@@ -40,6 +40,7 @@
#include <tools/profile.h>
#include <tools/scripttools.h>
#include <tools/settings.h>
+#include <tools/toolchains.h>
#include <QDir>
#include <QFileInfo>
@@ -97,28 +98,16 @@ static QStringList validMinGWMachines()
<< QLatin1String("i586-mingw32msvc") << QLatin1String("amd64-mingw32msvc");
}
-static QStringList completeToolchainList(const QString &toolchainName)
-{
- QStringList toolchains(toolchainName);
- if (toolchainName == QLatin1String("clang"))
- toolchains << completeToolchainList(QLatin1String("llvm"));
- else if (toolchainName == QLatin1String("llvm") ||
- toolchainName == QLatin1String("mingw")) {
- toolchains << completeToolchainList(QLatin1String("gcc"));
- }
- return toolchains;
-}
-
static QStringList toolchainTypeFromCompilerName(const QString &compilerName)
{
if (compilerName == QLatin1String("cl.exe"))
- return completeToolchainList(QLatin1String("msvc"));
+ return canonicalToolchain(QLatin1String("msvc"));
foreach (const QString &type, (QStringList() << QLatin1String("clang") << QLatin1String("llvm")
<< QLatin1String("mingw") << QLatin1String("gcc")))
if (compilerName.contains(type))
- return completeToolchainList(type);
+ return canonicalToolchain(type);
if (compilerName == QLatin1String("g++"))
- return completeToolchainList(QLatin1String("gcc"));
+ return canonicalToolchain(QLatin1String("gcc"));
return QStringList();
}
@@ -137,7 +126,7 @@ static QStringList standardCompilerFileNames()
}
static void setCommonProperties(Profile &profile, const QString &compilerFilePath,
- const QStringList &toolchainTypes, const QString &architecture)
+ const QStringList &toolchainTypes)
{
const QFileInfo cfi(compilerFilePath);
const QString compilerName = cfi.fileName();
@@ -151,7 +140,6 @@ static void setCommonProperties(Profile &profile, const QString &compilerFilePat
profile.setValue(QLatin1String("cpp.toolchainInstallPath"), cfi.absolutePath());
profile.setValue(QLatin1String("qbs.toolchain"), toolchainTypes);
- profile.setValue(QLatin1String("qbs.architecture"), canonicalArchitecture(architecture));
setCompilerVersion(compilerFilePath, toolchainTypes, profile);
const QString suffix = compilerName.right(compilerName.size() - prefix.size());
@@ -196,21 +184,17 @@ static Profile createGccProfile(const QString &compilerFilePath, Settings *setti
const QString &profileName = QString())
{
const QString machineName = gccMachineName(compilerFilePath);
- const QStringList compilerTriplet = machineName.split(QLatin1Char('-'));
if (toolchainTypes.contains(QLatin1String("mingw"))) {
if (!validMinGWMachines().contains(machineName)) {
throw ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.")
.arg(machineName));
}
- } else if (compilerTriplet.count() < 2) {
- throw qbs::ErrorInfo(Tr::tr("Architecture of compiler for platform '%1' at '%2' not understood.")
- .arg(machineName, compilerFilePath));
}
Profile profile(!profileName.isEmpty() ? profileName : machineName, settings);
profile.removeProfile();
- setCommonProperties(profile, compilerFilePath, toolchainTypes, compilerTriplet.first());
+ setCommonProperties(profile, compilerFilePath, toolchainTypes);
// Check whether auxiliary tools reside within the toolchain's install path.
// This might not be the case when using icecc or another compiler wrapper.
@@ -266,7 +250,7 @@ static void mingwProbe(Settings *settings, QList<Profile> &profiles)
= findExecutable(HostOsInfo::appendExecutableSuffix(compilerName));
if (!gccPath.isEmpty())
profiles << createGccProfile(gccPath, settings,
- completeToolchainList(QLatin1String("mingw")));
+ canonicalToolchain(QLatin1String("mingw")));
}
}
@@ -311,7 +295,7 @@ void createProfile(const QString &profileName, const QString &toolchainType,
if (toolchainType.isEmpty())
toolchainTypes = toolchainTypeFromCompilerName(compiler.fileName());
else
- toolchainTypes = completeToolchainList(toolchainType);
+ toolchainTypes = canonicalToolchain(toolchainType);
if (toolchainTypes.contains(QLatin1String("msvc")))
createMsvcProfile(profileName, compiler.absoluteFilePath(), settings);
diff --git a/src/app/qbs/commandlinefrontend.cpp b/src/app/qbs/commandlinefrontend.cpp
index 3297d7bbe..f2c0f1d1c 100644
--- a/src/app/qbs/commandlinefrontend.cpp
+++ b/src/app/qbs/commandlinefrontend.cpp
@@ -44,7 +44,6 @@
#include <QDir>
#include <QFile>
-#include <QMetaObject>
#include <QProcessEnvironment>
#include <QTimer>
@@ -190,7 +189,7 @@ void CommandLineFrontend::start()
// experimentally found to be acceptable.
// Note that this polling approach is not problematic here, since we are doing work anyway,
// so there's no danger of waking up the processor for no reason.
- connect(m_cancelTimer, SIGNAL(timeout()), SLOT(checkCancelStatus()));
+ connect(m_cancelTimer, &QTimer::timeout, this, &CommandLineFrontend::checkCancelStatus);
m_cancelTimer->start(2000);
} catch (const ErrorInfo &error) {
qbsError() << error.toString();
@@ -549,23 +548,23 @@ void CommandLineFrontend::connectBuildJob(AbstractJob *job)
if (!bjob)
return;
- connect(bjob, SIGNAL(reportCommandDescription(QString,QString)),
- this, SLOT(handleCommandDescriptionReport(QString,QString)));
- connect(bjob, SIGNAL(reportProcessResult(qbs::ProcessResult)),
- this, SLOT(handleProcessResultReport(qbs::ProcessResult)));
+ connect(bjob, &BuildJob::reportCommandDescription,
+ this, &CommandLineFrontend::handleCommandDescriptionReport);
+ connect(bjob, &BuildJob::reportProcessResult,
+ this, &CommandLineFrontend::handleProcessResultReport);
}
void CommandLineFrontend::connectJob(AbstractJob *job)
{
- connect(job, SIGNAL(finished(bool,qbs::AbstractJob*)),
- SLOT(handleJobFinished(bool,qbs::AbstractJob*)));
- connect(job, SIGNAL(taskStarted(QString,int,qbs::AbstractJob*)),
- SLOT(handleNewTaskStarted(QString,int)));
- connect(job, SIGNAL(totalEffortChanged(int,qbs::AbstractJob*)),
- SLOT(handleTotalEffortChanged(int)));
+ connect(job, &AbstractJob::finished,
+ this, &CommandLineFrontend::handleJobFinished);
+ connect(job, &AbstractJob::taskStarted,
+ this, &CommandLineFrontend::handleNewTaskStarted);
+ connect(job, &AbstractJob::totalEffortChanged,
+ this, &CommandLineFrontend::handleTotalEffortChanged);
if (m_parser.showProgress()) {
- connect(job, SIGNAL(taskProgress(int,qbs::AbstractJob*)),
- SLOT(handleTaskProgress(int,qbs::AbstractJob*)));
+ connect(job, &AbstractJob::taskProgress,
+ this, &CommandLineFrontend::handleTaskProgress);
}
}
diff --git a/src/app/qbs/commandlinefrontend.h b/src/app/qbs/commandlinefrontend.h
index 0783b189e..1b9f4d274 100644
--- a/src/app/qbs/commandlinefrontend.h
+++ b/src/app/qbs/commandlinefrontend.h
@@ -58,9 +58,9 @@ public:
~CommandLineFrontend();
void cancel();
-
-private slots:
void start();
+
+private:
void handleCommandDescriptionReport(const QString &highlight, const QString &message);
void handleJobFinished(bool success, qbs::AbstractJob *job);
void handleNewTaskStarted(const QString &description, int totalEffort);
@@ -69,7 +69,6 @@ private slots:
void handleProcessResultReport(const qbs::ProcessResult &result);
void checkCancelStatus();
-private:
typedef QHash<Project, QList<ProductData> > ProductMap;
ProductMap productsToUse() const;
diff --git a/src/app/qbs/main.cpp b/src/app/qbs/main.cpp
index d7fe21148..e981201ba 100644
--- a/src/app/qbs/main.cpp
+++ b/src/app/qbs/main.cpp
@@ -78,7 +78,7 @@ int main(int argc, char *argv[])
ConsoleLogger::instance().setSettings(&settings);
CommandLineFrontend clFrontend(parser, &settings);
app.setCommandLineFrontend(&clFrontend);
- QTimer::singleShot(0, &clFrontend, SLOT(start()));
+ QTimer::singleShot(0, &clFrontend, &CommandLineFrontend::start);
return app.exec();
} catch (const ErrorInfo &error) {
qbsError() << error.toString();
diff --git a/src/app/qbs/qbs.qbs b/src/app/qbs/qbs.qbs
index e56e97960..0f88f1ddc 100644
--- a/src/app/qbs/qbs.qbs
+++ b/src/app/qbs/qbs.qbs
@@ -7,9 +7,9 @@ QbsApp {
targetName: "qbs"
cpp.defines: base.concat([
'QBS_VERSION="' + QbsFunctions.qbsVersion() + '"',
- 'QBS_RELATIVE_LIBEXEC_PATH="' + project.relativeLibexecPath + '"',
- 'QBS_RELATIVE_SEARCH_PATH="' + project.relativeSearchPath + '"',
- 'QBS_RELATIVE_PLUGINS_PATH="' + project.relativePluginsPath + '"'
+ 'QBS_RELATIVE_LIBEXEC_PATH="' + qbsbuildconfig.relativeLibexecPath + '"',
+ 'QBS_RELATIVE_SEARCH_PATH="' + qbsbuildconfig.relativeSearchPath + '"',
+ 'QBS_RELATIVE_PLUGINS_PATH="' + qbsbuildconfig.relativePluginsPath + '"',
])
files: [
"application.cpp",
diff --git a/src/lib/corelib/api/internaljobs.cpp b/src/lib/corelib/api/internaljobs.cpp
index 87ae69617..90ed5f630 100644
--- a/src/lib/corelib/api/internaljobs.cpp
+++ b/src/lib/corelib/api/internaljobs.cpp
@@ -157,21 +157,21 @@ InternalJobThreadWrapper::InternalJobThreadWrapper(InternalJob *synchronousJob,
{
synchronousJob->shareObserverWith(this);
m_job->moveToThread(&m_thread);
- connect(m_job, SIGNAL(finished(Internal::InternalJob*)), SLOT(handleFinished()));
- connect(m_job, SIGNAL(newTaskStarted(QString,int,Internal::InternalJob*)),
- SIGNAL(newTaskStarted(QString,int,Internal::InternalJob*)));
- connect(m_job, SIGNAL(taskProgress(int,Internal::InternalJob*)),
- SIGNAL(taskProgress(int,Internal::InternalJob*)));
- connect(m_job, SIGNAL(totalEffortChanged(int,Internal::InternalJob*)),
- SIGNAL(totalEffortChanged(int,Internal::InternalJob*)));
- m_job->connect(this, SIGNAL(startRequested()), SLOT(start()));
+ connect(m_job, &InternalJob::finished, this, &InternalJobThreadWrapper::handleFinished);
+ connect(m_job, &InternalJob::newTaskStarted,
+ this, &InternalJob::newTaskStarted);
+ connect(m_job, &InternalJob::taskProgress,
+ this, &InternalJob::taskProgress);
+ connect(m_job, &InternalJob::totalEffortChanged,
+ this, &InternalJob::totalEffortChanged);
+ connect(this, &InternalJobThreadWrapper::startRequested, m_job, &InternalJob::start);
}
InternalJobThreadWrapper::~InternalJobThreadWrapper()
{
if (m_running) {
QEventLoop loop;
- loop.connect(m_job, SIGNAL(finished(Internal::InternalJob*)), SLOT(quit()));
+ connect(m_job, &InternalJob::finished, &loop, &QEventLoop::quit);
cancel();
loop.exec();
}
@@ -358,15 +358,15 @@ void InternalBuildJob::build(const TopLevelProjectPtr &project,
QThread * const executorThread = new QThread(this);
m_executor->moveToThread(executorThread);
- connect(m_executor, SIGNAL(reportCommandDescription(QString,QString)),
- this, SIGNAL(reportCommandDescription(QString,QString)));
- connect(m_executor, SIGNAL(reportProcessResult(qbs::ProcessResult)),
- this, SIGNAL(reportProcessResult(qbs::ProcessResult)));
-
- connect(executorThread, SIGNAL(started()), m_executor, SLOT(build()));
- connect(m_executor, SIGNAL(finished()), SLOT(handleFinished()));
- connect(m_executor, SIGNAL(destroyed()), executorThread, SLOT(quit()));
- connect(executorThread, SIGNAL(finished()), this, SLOT(emitFinished()));
+ connect(m_executor, &Executor::reportCommandDescription,
+ this, &BuildGraphTouchingJob::reportCommandDescription);
+ connect(m_executor, &Executor::reportProcessResult,
+ this, &BuildGraphTouchingJob::reportProcessResult);
+
+ connect(executorThread, &QThread::started, m_executor, &Executor::build);
+ connect(m_executor, &Executor::finished, this, &InternalBuildJob::handleFinished);
+ connect(m_executor, &QObject::destroyed, executorThread, &QThread::quit);
+ connect(executorThread, &QThread::finished, this, &InternalBuildJob::emitFinished);
executorThread->start();
}
diff --git a/src/lib/corelib/api/internaljobs.h b/src/lib/corelib/api/internaljobs.h
index 38dd449e6..e87bcdc92 100644
--- a/src/lib/corelib/api/internaljobs.h
+++ b/src/lib/corelib/api/internaljobs.h
@@ -62,6 +62,7 @@ public:
~InternalJob();
void cancel();
+ virtual void start() {}
ErrorInfo error() const { return m_error; }
void setError(const ErrorInfo &error) { m_error = error; }
@@ -98,16 +99,15 @@ public:
InternalJobThreadWrapper(InternalJob *synchronousJob, QObject *parent = 0);
~InternalJobThreadWrapper();
- void start();
+ void start() override;
InternalJob *synchronousJob() const { return m_job; }
signals:
void startRequested();
-private slots:
+private:
void handleFinished();
-private:
QThread m_thread;
InternalJob *m_job;
bool m_running;
@@ -125,10 +125,8 @@ public:
TopLevelProjectPtr project() const;
-private slots:
- void start();
-
private:
+ void start() override;
void resolveProjectFromScratch(Internal::ScriptEngine *engine);
void resolveBuildDataFromScratch(const RulesEvaluationContextPtr &evalContext);
BuildGraphLoadResult restoreProject(const RulesEvaluationContextPtr &evalContext);
@@ -175,11 +173,10 @@ public:
void build(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products,
const BuildOptions &buildOptions);
-private slots:
+private:
void handleFinished();
void emitFinished();
-private:
Executor *m_executor;
};
@@ -193,10 +190,9 @@ public:
void init(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products,
const CleanOptions &options);
-private slots:
- void start();
-
private:
+ void start() override;
+
CleanOptions m_options;
};
@@ -211,10 +207,9 @@ public:
void init(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products,
const InstallOptions &options);
-private slots:
- void start();
-
private:
+ void start() override;
+
TopLevelProjectPtr m_project;
QList<ResolvedProductPtr> m_products;
InstallOptions m_options;
diff --git a/src/lib/corelib/api/jobs.cpp b/src/lib/corelib/api/jobs.cpp
index 793232d92..da1629065 100644
--- a/src/lib/corelib/api/jobs.cpp
+++ b/src/lib/corelib/api/jobs.cpp
@@ -34,7 +34,7 @@
#include <language/language.h>
#include <tools/qbsassert.h>
-#include <QMetaObject>
+#include <QTimer>
namespace qbs {
using namespace Internal;
@@ -106,13 +106,13 @@ AbstractJob::AbstractJob(InternalJob *internalJob, QObject *parent)
: QObject(parent), m_internalJob(internalJob)
{
m_internalJob->setParent(this);
- connect(m_internalJob, SIGNAL(newTaskStarted(QString,int,Internal::InternalJob*)),
- SLOT(handleTaskStarted(QString,int)), Qt::QueuedConnection);
- connect(m_internalJob, SIGNAL(totalEffortChanged(int,Internal::InternalJob*)),
- SLOT(handleTotalEffortChanged(int)));
- connect(m_internalJob, SIGNAL(taskProgress(int,Internal::InternalJob*)),
- SLOT(handleTaskProgress(int)), Qt::QueuedConnection);
- connect(m_internalJob, SIGNAL(finished(Internal::InternalJob*)), SLOT(handleFinished()));
+ connect(m_internalJob, &InternalJob::newTaskStarted,
+ this, &AbstractJob::handleTaskStarted, Qt::QueuedConnection);
+ connect(m_internalJob, &InternalJob::totalEffortChanged,
+ this, &AbstractJob::handleTotalEffortChanged);
+ connect(m_internalJob, &InternalJob::taskProgress,
+ this, &AbstractJob::handleTaskProgress, Qt::QueuedConnection);
+ connect(m_internalJob, &InternalJob::finished, this, &AbstractJob::handleFinished);
m_state = StateRunning;
}
@@ -122,8 +122,7 @@ bool AbstractJob::lockProject(const TopLevelProjectPtr &project)
// synchronously.
if (project->locked) {
internalJob()->setError(tr("Cannot start a job while another one is in progress."));
- QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection, Q_ARG(bool, false),
- Q_ARG(qbs::AbstractJob *, this));
+ QTimer::singleShot(0, this, [this] { emit finished(false, this); });
return false;
}
project->locked = true;
@@ -293,10 +292,10 @@ BuildJob::BuildJob(const Logger &logger, QObject *parent)
: AbstractJob(new InternalBuildJob(logger), parent)
{
InternalBuildJob *job = static_cast<InternalBuildJob *>(internalJob());
- connect(job, SIGNAL(reportCommandDescription(QString,QString)),
- this, SIGNAL(reportCommandDescription(QString,QString)));
- connect(job, SIGNAL(reportProcessResult(qbs::ProcessResult)),
- this, SIGNAL(reportProcessResult(qbs::ProcessResult)));
+ connect(job, &BuildGraphTouchingJob::reportCommandDescription,
+ this, &BuildJob::reportCommandDescription);
+ connect(job, &BuildGraphTouchingJob::reportProcessResult,
+ this, &BuildJob::reportProcessResult);
}
void BuildJob::build(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products,
diff --git a/src/lib/corelib/api/jobs.h b/src/lib/corelib/api/jobs.h
index d61b5f722..b6892ad0c 100644
--- a/src/lib/corelib/api/jobs.h
+++ b/src/lib/corelib/api/jobs.h
@@ -79,13 +79,12 @@ signals:
void taskProgress(int newProgressValue, qbs::AbstractJob *job);
void finished(bool success, qbs::AbstractJob *job);
-private slots:
+private:
void handleTaskStarted(const QString &description, int maximumProgressValue);
void handleTotalEffortChanged(int totalEffort);
void handleTaskProgress(int newProgressValue);
void handleFinished();
-private:
void unlockProject();
virtual void finish() { }
diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp
index a12ea1086..4a9404553 100644
--- a/src/lib/corelib/api/project.cpp
+++ b/src/lib/corelib/api/project.cpp
@@ -1029,8 +1029,7 @@ QList<InstallableFile> Project::installableFilesForProduct(const ProductData &pr
}
if (internalProduct->enabled) {
QBS_CHECK(internalProduct->buildData);
- foreach (const Artifact * const artifact,
- ArtifactSet::fromNodeSet(internalProduct->buildData->nodes)) {
+ for (const Artifact *artifact : filterByType<Artifact>(internalProduct->buildData->nodes)) {
if (artifact->artifactType == Artifact::SourceFile)
continue;
try {
diff --git a/src/lib/corelib/api/runenvironment.cpp b/src/lib/corelib/api/runenvironment.cpp
index bc7091cee..179237175 100644
--- a/src/lib/corelib/api/runenvironment.cpp
+++ b/src/lib/corelib/api/runenvironment.cpp
@@ -251,6 +251,7 @@ int RunEnvironment::doRunTarget(const QString &targetBin, const QStringList &arg
} else if (QFileInfo(targetExecutable = findExecutable(QStringList()
<< QStringLiteral("ios-deploy"))).isExecutable()) {
targetArguments = QStringList()
+ << QStringLiteral("--no-wifi")
<< QStringLiteral("--noninteractive")
<< QStringLiteral("--bundle")
<< QDir::cleanPath(bundlePath);
diff --git a/src/lib/corelib/buildgraph/abstractcommandexecutor.h b/src/lib/corelib/buildgraph/abstractcommandexecutor.h
index 11df366d5..d1eb13271 100644
--- a/src/lib/corelib/buildgraph/abstractcommandexecutor.h
+++ b/src/lib/corelib/buildgraph/abstractcommandexecutor.h
@@ -57,7 +57,6 @@ public:
virtual void cancel() = 0;
-public slots:
void start(Transformer *transformer, const AbstractCommand *cmd);
signals:
diff --git a/src/lib/corelib/buildgraph/artifact.cpp b/src/lib/corelib/buildgraph/artifact.cpp
index 9ae98c640..a2d743b22 100644
--- a/src/lib/corelib/buildgraph/artifact.cpp
+++ b/src/lib/corelib/buildgraph/artifact.cpp
@@ -65,7 +65,7 @@ Artifact::Artifact()
Artifact::~Artifact()
{
- foreach (Artifact *p, parentArtifacts())
+ for (Artifact *p : parentArtifacts())
p->childrenAddedByScanner.remove(this);
}
@@ -117,14 +117,14 @@ void Artifact::initialize()
oldDataPossiblyPresent = true;
}
-ArtifactSet Artifact::parentArtifacts() const
+const TypeFilter<Artifact> Artifact::parentArtifacts() const
{
- return ArtifactSet::fromNodeSet(parents);
+ return TypeFilter<Artifact>(parents);
}
-ArtifactSet Artifact::childArtifacts() const
+const TypeFilter<Artifact> Artifact::childArtifacts() const
{
- return ArtifactSet::fromNodeSet(children);
+ return TypeFilter<Artifact>(children);
}
void Artifact::onChildDisconnected(BuildGraphNode *child)
diff --git a/src/lib/corelib/buildgraph/artifact.h b/src/lib/corelib/buildgraph/artifact.h
index d67cdceff..81dbcaf07 100644
--- a/src/lib/corelib/buildgraph/artifact.h
+++ b/src/lib/corelib/buildgraph/artifact.h
@@ -87,8 +87,8 @@ public:
bool oldDataPossiblyPresent : 1;
void initialize();
- ArtifactSet parentArtifacts() const;
- ArtifactSet childArtifacts() const;
+ const TypeFilter<Artifact> parentArtifacts() const;
+ const TypeFilter<Artifact> childArtifacts() const;
void onChildDisconnected(BuildGraphNode *child);
private:
diff --git a/src/lib/corelib/buildgraph/buildgraph.cpp b/src/lib/corelib/buildgraph/buildgraph.cpp
index 32fcdade0..3761a84d7 100644
--- a/src/lib/corelib/buildgraph/buildgraph.cpp
+++ b/src/lib/corelib/buildgraph/buildgraph.cpp
@@ -184,7 +184,7 @@ static void setupProductScriptValue(ScriptEngine *engine, QScriptValue &productS
void setupScriptEngineForFile(ScriptEngine *engine, const ResolvedFileContextConstPtr &fileContext,
QScriptValue targetObject)
{
- engine->import(fileContext, targetObject, targetObject);
+ engine->import(fileContext, targetObject);
JsExtensions::setupExtensions(fileContext->jsExtensions(), targetObject);
}
@@ -241,13 +241,14 @@ void connect(BuildGraphNode *p, BuildGraphNode *c)
{
QBS_CHECK(p != c);
if (Artifact *ac = dynamic_cast<Artifact *>(c)) {
- foreach (const Artifact * const child, ArtifactSet::fromNodeSet(p->children))
+ for (const Artifact *child : filterByType<Artifact>(p->children)) {
if (child != ac && child->filePath() == ac->filePath()) {
throw ErrorInfo(QString::fromLocal8Bit("%1 already has a child artifact %2 as "
"different object.").arg(p->toString(),
ac->filePath()),
CodeLocation(), true);
}
+ }
}
p->children.insert(c);
c->parents.insert(p);
@@ -410,40 +411,16 @@ Artifact *createArtifact(const ResolvedProductPtr &product,
return artifact;
}
-static QString productNameForErrorMessage(const ResolvedProduct *product)
-{
- return product->profile == product->topLevelProject()->profile()
- ? product->name : product->uniqueName();
-}
-
-static void checkForConflictingArtifacts(const ResolvedProduct *product, Artifact *artifact)
-{
- foreach (const ResolvedProductConstPtr &otherProduct, product->project->allProducts()) {
- if (otherProduct == product || !lookupArtifact(otherProduct, artifact->filePath()))
- continue;
- ErrorInfo error;
- 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(otherProduct.data())), otherProduct->location);
- error.append(Tr::tr("The second artifact comes from product '%1'.")
- .arg(productNameForErrorMessage(product)), product->location);
- throw error;
- }
-
-}
-
void insertArtifact(const ResolvedProductPtr &product, Artifact *artifact, const Logger &logger)
{
QBS_CHECK(!artifact->product);
QBS_CHECK(!artifact->filePath().isEmpty());
QBS_CHECK(!product->buildData->nodes.contains(artifact));
- if (artifact->artifactType == Artifact::Generated)
- checkForConflictingArtifacts(product.data(), artifact);
- product->buildData->nodes.insert(artifact);
- addArtifactToSet(artifact, product->buildData->artifactsByFileTag);
artifact->product = product;
product->topLevelProject()->buildData->insertIntoLookupTable(artifact);
product->topLevelProject()->buildData->isDirty = true;
+ product->buildData->nodes.insert(artifact);
+ addArtifactToSet(artifact, product->buildData->artifactsByFileTag);
if (logger.traceEnabled()) {
logger.qbsTrace() << QString::fromLocal8Bit("[BG] insert artifact '%1'")
@@ -504,7 +481,7 @@ static void doSanityChecksForProduct(const ResolvedProductConstPtr &product,
QBS_CHECK(output->transformer == transformer);
transformerOutputChildren.unite(ArtifactSet::fromNodeSet(output->children));
QSet<QString> childFilePaths;
- foreach (const Artifact * const a, ArtifactSet::fromNodeSet(output->children)) {
+ for (const Artifact *a : filterByType<Artifact>(output->children)) {
if (childFilePaths.contains(a->filePath())) {
throw ErrorInfo(QString::fromLocal8Bit("There is more than one artifact for "
"file '%1' in the child list for output '%2'.")
diff --git a/src/lib/corelib/buildgraph/buildgraphloader.cpp b/src/lib/corelib/buildgraph/buildgraphloader.cpp
index 0f10b6c02..bf6a12b0b 100644
--- a/src/lib/corelib/buildgraph/buildgraphloader.cpp
+++ b/src/lib/corelib/buildgraph/buildgraphloader.cpp
@@ -252,8 +252,7 @@ void BuildGraphLoader::trackProjectChanges()
// If the product gets temporarily removed, its artifacts will get disconnected
// and this structural information will no longer be directly available from them.
- foreach (const Artifact * const a,
- ArtifactSet::fromNodeSet(product->buildData->nodes)) {
+ for (const Artifact *a : filterByType<Artifact>(product->buildData->nodes)) {
childLists.insert(a, ChildrenInfo(ArtifactSet::fromNodeSet(a->children),
a->childrenAddedByScanner));
}
@@ -591,7 +590,7 @@ bool BuildGraphLoader::checkTransformersForPropertyChanges(const ResolvedProduct
{
bool transformerChanges = false;
QSet<TransformerConstPtr> seenTransformers;
- foreach (Artifact *artifact, ArtifactSet::fromNodeSet(restoredProduct->buildData->nodes)) {
+ for (Artifact *artifact : filterByType<Artifact>(restoredProduct->buildData->nodes)) {
const TransformerPtr transformer = artifact->transformer;
if (!transformer || seenTransformers.contains(transformer))
continue;
@@ -739,7 +738,7 @@ void BuildGraphLoader::replaceFileDependencyWithArtifact(const ResolvedProductPt
foreach (const ResolvedProductPtr &product, fileDepProduct->topLevelProject()->allProducts()) {
if (!product->buildData)
continue;
- foreach (Artifact *artifactInProduct, ArtifactSet::fromNodeSet(product->buildData->nodes)) {
+ for (Artifact *artifactInProduct : filterByType<Artifact>(product->buildData->nodes)) {
if (artifactInProduct->fileDependencies.contains(filedep)) {
artifactInProduct->fileDependencies.remove(filedep);
loggedConnect(artifactInProduct, artifact, m_logger);
@@ -805,8 +804,7 @@ void BuildGraphLoader::rescueOldBuildData(const ResolvedProductConstPtr &restore
// FIXME: This complete block could go away if Transformers were also to create their
// output artifacts at build time.
QList<Artifact *> oldArtifactsCreatedByTransformers;
- foreach (Artifact *artifact,
- ArtifactSet::fromNodeSet(newlyResolvedProduct->buildData->nodes)) {
+ for (Artifact *artifact : filterByType<Artifact>(newlyResolvedProduct->buildData->nodes)) {
if (!artifact->transformer)
continue;
if (m_logger.traceEnabled()) {
@@ -847,8 +845,7 @@ void BuildGraphLoader::rescueOldBuildData(const ResolvedProductConstPtr &restore
}
// This is needed for artifacts created by rules, which happens later in the executor.
- foreach (Artifact * const oldArtifact,
- ArtifactSet::fromNodeSet(restoredProduct->buildData->nodes)) {
+ for (Artifact * const oldArtifact : filterByType<Artifact>(restoredProduct->buildData->nodes)) {
if (!oldArtifact->transformer)
continue;
if (oldArtifactsCreatedByTransformers.contains(oldArtifact))
@@ -858,6 +855,12 @@ void BuildGraphLoader::rescueOldBuildData(const ResolvedProductConstPtr &restore
RescuableArtifactData rad;
rad.timeStamp = oldArtifact->timestamp();
rad.commands = oldArtifact->transformer->commands;
+ rad.propertiesRequestedInPrepareScript
+ = oldArtifact->transformer->propertiesRequestedInPrepareScript;
+ rad.propertiesRequestedInCommands
+ = oldArtifact->transformer->propertiesRequestedInCommands;
+ rad.propertiesRequestedFromArtifactInPrepareScript
+ = oldArtifact->transformer->propertiesRequestedFromArtifactInPrepareScript;
const ChildrenInfo &childrenInfo = childLists.value(oldArtifact);
foreach (Artifact * const child, childrenInfo.children) {
rad.children << RescuableArtifactData::ChildData(child->product->name,
diff --git a/src/lib/corelib/buildgraph/command.cpp b/src/lib/corelib/buildgraph/command.cpp
index 210072ef4..8a97faa70 100644
--- a/src/lib/corelib/buildgraph/command.cpp
+++ b/src/lib/corelib/buildgraph/command.cpp
@@ -46,6 +46,7 @@ AbstractCommand::AbstractCommand()
: m_description(defaultDescription()),
m_extendedDescription(defaultExtendedDescription()),
m_highlight(defaultHighLight()),
+ m_ignoreDryRun(defaultIgnoreDryRun()),
m_silent(defaultIsSilent())
{
}
@@ -60,6 +61,7 @@ bool AbstractCommand::equals(const AbstractCommand *other) const
&& m_description == other->m_description
&& m_extendedDescription == other->m_extendedDescription
&& m_highlight == other->m_highlight
+ && m_ignoreDryRun == other->m_ignoreDryRun
&& m_silent == other->m_silent
&& m_properties == other->m_properties;
}
@@ -69,6 +71,7 @@ void AbstractCommand::fillFromScriptValue(const QScriptValue *scriptValue, const
m_description = scriptValue->property(QLatin1String("description")).toString();
m_extendedDescription = scriptValue->property(QLatin1String("extendedDescription")).toString();
m_highlight = scriptValue->property(QLatin1String("highlight")).toString();
+ m_ignoreDryRun = scriptValue->property(QLatin1String("ignoreDryRun")).toBool();
m_silent = scriptValue->property(QLatin1String("silent")).toBool();
m_codeLocation = codeLocation;
@@ -76,6 +79,7 @@ void AbstractCommand::fillFromScriptValue(const QScriptValue *scriptValue, const
<< QLatin1String("description")
<< QLatin1String("extendedDescription")
<< QLatin1String("highlight")
+ << QLatin1String("ignoreDryRun")
<< QLatin1String("silent");
}
@@ -84,6 +88,7 @@ void AbstractCommand::load(PersistentPool &pool)
m_description = pool.idLoadString();
m_extendedDescription = pool.idLoadString();
m_highlight = pool.idLoadString();
+ pool.stream() >> m_ignoreDryRun;
pool.stream() >> m_silent;
m_codeLocation.load(pool);
m_properties = pool.loadVariantMap();
@@ -94,6 +99,7 @@ void AbstractCommand::store(PersistentPool &pool) const
pool.storeString(m_description);
pool.storeString(m_extendedDescription);
pool.storeString(m_highlight);
+ pool.stream() << m_ignoreDryRun;
pool.stream() << m_silent;
m_codeLocation.store(pool);
pool.store(m_properties);
@@ -120,6 +126,8 @@ static QScriptValue js_CommandBase(QScriptContext *context, QScriptEngine *engin
engine->toScriptValue(AbstractCommand::defaultExtendedDescription()));
cmd.setProperty(QLatin1String("highlight"),
engine->toScriptValue(AbstractCommand::defaultHighLight()));
+ cmd.setProperty(QLatin1String("ignoreDryRun"),
+ engine->toScriptValue(AbstractCommand::defaultIgnoreDryRun()));
cmd.setProperty(QLatin1String("silent"),
engine->toScriptValue(AbstractCommand::defaultIsSilent()));
return cmd;
@@ -163,6 +171,8 @@ static QScriptValue js_Command(QScriptContext *context, QScriptEngine *engine)
engine->toScriptValue(commandPrototype->stderrFilePath()));
cmd.setProperty(QLatin1String("environment"),
engine->toScriptValue(commandPrototype->environment().toStringList()));
+ cmd.setProperty(QLatin1String("ignoreDryRun"),
+ engine->toScriptValue(commandPrototype->ignoreDryRun()));
return cmd;
}
diff --git a/src/lib/corelib/buildgraph/command.h b/src/lib/corelib/buildgraph/command.h
index 53a98d124..f3a9f2483 100644
--- a/src/lib/corelib/buildgraph/command.h
+++ b/src/lib/corelib/buildgraph/command.h
@@ -58,6 +58,7 @@ public:
static QString defaultDescription() { return QString(); }
static QString defaultExtendedDescription() { return QString(); }
static QString defaultHighLight() { return QString(); }
+ static bool defaultIgnoreDryRun() { return false; }
static bool defaultIsSilent() { return false; }
virtual CommandType type() const = 0;
@@ -67,6 +68,7 @@ public:
const QString description() const { return m_description; }
const QString extendedDescription() const { return m_extendedDescription; }
const QString highlight() const { return m_highlight; }
+ bool ignoreDryRun() const { return m_ignoreDryRun; }
bool isSilent() const { return m_silent; }
CodeLocation codeLocation() const { return m_codeLocation; }
@@ -86,6 +88,7 @@ private:
QString m_description;
QString m_extendedDescription;
QString m_highlight;
+ bool m_ignoreDryRun;
bool m_silent;
CodeLocation m_codeLocation;
QVariantMap m_properties;
diff --git a/src/lib/corelib/buildgraph/depscanner.cpp b/src/lib/corelib/buildgraph/depscanner.cpp
index a0bf1d6ed..04f5f6323 100644
--- a/src/lib/corelib/buildgraph/depscanner.cpp
+++ b/src/lib/corelib/buildgraph/depscanner.cpp
@@ -131,6 +131,7 @@ UserDependencyScanner::UserDependencyScanner(const ResolvedScannerConstPtr &scan
{
m_engine->setProcessEventsInterval(-1); // QBS-782
m_global = m_engine->newObject();
+ m_global.setPrototype(m_engine->globalObject());
setupScriptEngineForFile(m_engine, m_scanner->scanScript->fileContext, m_global);
}
@@ -184,8 +185,7 @@ QStringList UserDependencyScanner::evaluate(Artifact *artifact, const ScriptFunc
args.append(m_global.property(QString::fromLatin1("product")));
args.append(artifactConfig);
- QScriptContext *ctx = m_engine->currentContext();
- ctx->pushScope(m_global);
+ m_engine->setGlobalObject(m_global);
QScriptValue &function = script->scriptFunction;
if (!function.isValid() || function.engine() != m_engine) {
function = m_engine->evaluate(script->sourceCode);
@@ -193,7 +193,7 @@ QStringList UserDependencyScanner::evaluate(Artifact *artifact, const ScriptFunc
throw ErrorInfo(Tr::tr("Invalid scan script."), script->location);
}
QScriptValue result = function.call(QScriptValue(), args);
- ctx->popScope();
+ m_engine->setGlobalObject(m_global.prototype());
m_engine->clearRequestedProperties();
if (Q_UNLIKELY(m_engine->hasErrorOrException(result))) {
QString msg = Tr::tr("evaluating scan script: ") + m_engine->lastErrorString(result);
diff --git a/src/lib/corelib/buildgraph/executor.cpp b/src/lib/corelib/buildgraph/executor.cpp
index b9d4cc330..dbb5225b3 100644
--- a/src/lib/corelib/buildgraph/executor.cpp
+++ b/src/lib/corelib/buildgraph/executor.cpp
@@ -82,7 +82,7 @@ Executor::Executor(const Logger &logger, QObject *parent)
m_inputArtifactScanContext = new InputArtifactScannerContext(&m_scanResultCache);
m_cancelationTimer->setSingleShot(false);
m_cancelationTimer->setInterval(1000);
- connect(m_cancelationTimer, SIGNAL(timeout()), SLOT(checkForCancellation()));
+ connect(m_cancelationTimer, &QTimer::timeout, this, &Executor::checkForCancellation);
}
Executor::~Executor()
@@ -207,7 +207,7 @@ void Executor::doBuild()
if (m_productsToBuild.isEmpty()) {
m_logger.qbsTrace() << "No products to build, finishing.";
- QTimer::singleShot(0, this, SLOT(finish())); // Don't call back on the caller.
+ QTimer::singleShot(0, this, &Executor::finish); // Don't call back on the caller.
return;
}
@@ -236,7 +236,7 @@ void Executor::doBuild()
initLeaves();
if (!scheduleJobs()) {
m_logger.qbsTrace() << "Nothing to do at all, finishing.";
- QTimer::singleShot(0, this, SLOT(finish())); // Don't call back on the caller.
+ QTimer::singleShot(0, this, &Executor::finish); // Don't call back on the caller.
}
if (m_progressObserver)
m_cancelationTimer->start();
@@ -347,7 +347,7 @@ bool Executor::isUpToDate(Artifact *artifact) const
return false;
}
- foreach (Artifact *childArtifact, ArtifactSet::fromNodeSet(artifact->children)) {
+ for (Artifact *childArtifact : filterByType<Artifact>(artifact->children)) {
QBS_CHECK(childArtifact->timestamp().isValid());
if (m_doDebug) {
m_logger.qbsDebug() << "[UTD] child timestamp "
@@ -445,8 +445,7 @@ void Executor::executeRuleNode(RuleNode *ruleNode)
if (ruleNode->rule()->acceptsAsInput(artifact))
changedInputArtifacts += artifact;
}
- foreach (Artifact *artifact,
- ArtifactSet::fromNodeSet(ruleNode->product->buildData->nodes)) {
+ for (Artifact *artifact : filterByType<Artifact>(ruleNode->product->buildData->nodes)) {
if (artifact->artifactType == Artifact::SourceFile)
continue;
if (artifact->timestampRetrieved && !isUpToDate(artifact)
@@ -513,7 +512,8 @@ void Executor::finishJob(ExecutorJob *job, bool success)
foreach (Artifact *artifact, transformer->outputs) {
if (artifact->alwaysUpdated) {
artifact->setTimestamp(FileTime::currentTime());
- if (m_buildOptions.forceOutputCheck() && !FileInfo(artifact->filePath()).exists()) {
+ if (m_buildOptions.forceOutputCheck()
+ && !m_buildOptions.dryRun() && !FileInfo(artifact->filePath()).exists()) {
if (transformer->rule) {
if (!transformer->rule->name.isEmpty()) {
throw ErrorInfo(tr("Rule '%1' declares artifact '%2', "
@@ -691,12 +691,12 @@ void Executor::addExecutorJobs()
job->setDryRun(m_buildOptions.dryRun());
job->setEchoMode(m_buildOptions.echoMode());
m_availableJobs.append(job);
- connect(job, SIGNAL(reportCommandDescription(QString,QString)),
- this, SIGNAL(reportCommandDescription(QString,QString)), Qt::QueuedConnection);
- connect(job, SIGNAL(reportProcessResult(qbs::ProcessResult)),
- this, SIGNAL(reportProcessResult(qbs::ProcessResult)), Qt::QueuedConnection);
- connect(job, SIGNAL(finished(qbs::ErrorInfo)),
- this, SLOT(onJobFinished(qbs::ErrorInfo)), Qt::QueuedConnection);
+ connect(job, &ExecutorJob::reportCommandDescription,
+ this, &Executor::reportCommandDescription, Qt::QueuedConnection);
+ connect(job, &ExecutorJob::reportProcessResult,
+ this, &Executor::reportProcessResult, Qt::QueuedConnection);
+ connect(job, &ExecutorJob::finished,
+ this, &Executor::onJobFinished, Qt::QueuedConnection);
}
}
@@ -749,8 +749,9 @@ void Executor::rescueOldBuildData(Artifact *artifact, bool *childrenAdded = 0)
}
if (canRescue) {
+ const TypeFilter<Artifact> childArtifacts(artifact->children);
const int newChildCount = childrenToConnect.count()
- + ArtifactSet::fromNodeSet(artifact->children).count();
+ + std::distance(childArtifacts.begin(), childArtifacts.end());
QBS_CHECK(newChildCount >= rad.children.count());
if (newChildCount > rad.children.count()) {
canRescue = false;
@@ -764,6 +765,12 @@ void Executor::rescueOldBuildData(Artifact *artifact, bool *childrenAdded = 0)
}
if (canRescue) {
+ artifact->transformer->propertiesRequestedInPrepareScript
+ = rad.propertiesRequestedInPrepareScript;
+ artifact->transformer->propertiesRequestedInCommands
+ = rad.propertiesRequestedInCommands;
+ artifact->transformer->propertiesRequestedFromArtifactInPrepareScript
+ = rad.propertiesRequestedFromArtifactInPrepareScript;
artifact->setTimestamp(rad.timeStamp);
if (childrenAdded && !childrenToConnect.isEmpty())
*childrenAdded = true;
@@ -918,8 +925,7 @@ void Executor::onJobFinished(const qbs::ErrorInfo &err)
if (m_evalContext->isActive()) {
m_logger.qbsDebug() << "Executor job finished while rule execution is pausing. "
"Delaying slot execution.";
- QMetaObject::invokeMethod(job, "finished", Qt::QueuedConnection,
- Q_ARG(qbs::ErrorInfo, err));
+ QTimer::singleShot(0, job, [job, err] { job->finished(err); });
return;
}
@@ -1057,7 +1063,7 @@ void Executor::prepareAllNodes()
}
foreach (const ResolvedProductPtr &product, m_productsToBuild) {
QBS_CHECK(product->buildData);
- foreach (Artifact * const artifact, ArtifactSet::fromNodeSet(product->buildData->nodes))
+ for (Artifact * const artifact : filterByType<Artifact>(product->buildData->nodes))
prepareArtifact(artifact);
}
}
diff --git a/src/lib/corelib/buildgraph/executor.h b/src/lib/corelib/buildgraph/executor.h
index b3b925475..718098367 100644
--- a/src/lib/corelib/buildgraph/executor.h
+++ b/src/lib/corelib/buildgraph/executor.h
@@ -63,10 +63,9 @@ class Executor : public QObject, private BuildGraphVisitor
{
Q_OBJECT
-public slots:
+public:
void build();
-public:
Executor(const Logger &logger, QObject *parent = 0);
~Executor();
@@ -83,12 +82,11 @@ signals:
void finished();
-private slots:
+private:
void onJobFinished(const qbs::ErrorInfo &err);
void finish();
void checkForCancellation();
-private:
// BuildGraphVisitor implementation
bool visit(Artifact *artifact);
bool visit(RuleNode *ruleNode);
diff --git a/src/lib/corelib/buildgraph/executorjob.cpp b/src/lib/corelib/buildgraph/executorjob.cpp
index 15b952373..c699c3853 100644
--- a/src/lib/corelib/buildgraph/executorjob.cpp
+++ b/src/lib/corelib/buildgraph/executorjob.cpp
@@ -49,16 +49,16 @@ ExecutorJob::ExecutorJob(const Logger &logger, QObject *parent)
, m_processCommandExecutor(new ProcessCommandExecutor(logger, this))
, m_jsCommandExecutor(new JsCommandExecutor(logger, this))
{
- connect(m_processCommandExecutor, SIGNAL(reportCommandDescription(QString,QString)),
- this, SIGNAL(reportCommandDescription(QString,QString)));
- connect(m_processCommandExecutor, SIGNAL(reportProcessResult(qbs::ProcessResult)),
- this, SIGNAL(reportProcessResult(qbs::ProcessResult)));
- connect(m_processCommandExecutor, SIGNAL(finished(qbs::ErrorInfo)),
- this, SLOT(onCommandFinished(qbs::ErrorInfo)));
- connect(m_jsCommandExecutor, SIGNAL(reportCommandDescription(QString,QString)),
- this, SIGNAL(reportCommandDescription(QString,QString)));
- connect(m_jsCommandExecutor, SIGNAL(finished(qbs::ErrorInfo)),
- this, SLOT(onCommandFinished(qbs::ErrorInfo)));
+ connect(m_processCommandExecutor, &AbstractCommandExecutor::reportCommandDescription,
+ this, &ExecutorJob::reportCommandDescription);
+ connect(m_processCommandExecutor, &ProcessCommandExecutor::reportProcessResult,
+ this, &ExecutorJob::reportProcessResult);
+ connect(m_processCommandExecutor, &AbstractCommandExecutor::finished,
+ this, &ExecutorJob::onCommandFinished);
+ connect(m_jsCommandExecutor, &AbstractCommandExecutor::reportCommandDescription,
+ this, &ExecutorJob::reportCommandDescription);
+ connect(m_jsCommandExecutor, &AbstractCommandExecutor::finished,
+ this, &ExecutorJob::onCommandFinished);
reset();
}
diff --git a/src/lib/corelib/buildgraph/executorjob.h b/src/lib/corelib/buildgraph/executorjob.h
index ea0831fee..f1f2b28ac 100644
--- a/src/lib/corelib/buildgraph/executorjob.h
+++ b/src/lib/corelib/buildgraph/executorjob.h
@@ -68,11 +68,10 @@ signals:
void reportProcessResult(const qbs::ProcessResult &result);
void finished(const qbs::ErrorInfo &error = ErrorInfo()); // !hasError() <=> command successful
-private slots:
+private:
void runNextCommand();
void onCommandFinished(const qbs::ErrorInfo &err);
-private:
void setFinished();
void reset();
diff --git a/src/lib/corelib/buildgraph/jscommandexecutor.cpp b/src/lib/corelib/buildgraph/jscommandexecutor.cpp
index 08c3e8735..14b58cf27 100644
--- a/src/lib/corelib/buildgraph/jscommandexecutor.cpp
+++ b/src/lib/corelib/buildgraph/jscommandexecutor.cpp
@@ -44,7 +44,6 @@
#include <tools/qbsassert.h>
#include <QEventLoop>
-#include <QMetaObject>
#include <QThread>
#include <QTimer>
@@ -73,7 +72,7 @@ public:
return m_result;
}
- Q_INVOKABLE void cancel()
+ void cancel()
{
QBS_ASSERT(m_scriptEngine, return);
m_scriptEngine->abortEvaluation();
@@ -82,7 +81,7 @@ public:
signals:
void finished();
-public slots:
+public:
void start(const JavaScriptCommand *cmd, Transformer *transformer)
{
try {
@@ -101,6 +100,7 @@ private:
m_result.errorMessage.clear();
ScriptEngine * const scriptEngine = provideScriptEngine();
QScriptValue scope = scriptEngine->newObject();
+ scope.setPrototype(scriptEngine->globalObject());
PrepareScriptObserver observer(scriptEngine);
setupScriptEngineForFile(scriptEngine, transformer->rule->prepareScript->fileContext, scope);
setupScriptEngineForProduct(scriptEngine, transformer->product(), transformer->rule->module, scope,
@@ -113,10 +113,9 @@ private:
scope.setProperty(it.key(), scriptEngine->toScriptValue(it.value()));
}
- QScriptContext *ctx = scriptEngine->currentContext();
- ctx->pushScope(scope);
+ scriptEngine->setGlobalObject(scope);
scriptEngine->evaluate(cmd->sourceCode());
- ctx->popScope();
+ scriptEngine->setGlobalObject(scope.prototype());
transformer->propertiesRequestedInCommands
+= scriptEngine->propertiesRequestedInScript();
scriptEngine->clearRequestedProperties();
@@ -153,9 +152,10 @@ JsCommandExecutor::JsCommandExecutor(const Logger &logger, QObject *parent)
, m_running(false)
{
m_objectInThread->moveToThread(m_thread);
- connect(m_objectInThread, SIGNAL(finished()), this, SLOT(onJavaScriptCommandFinished()));
- connect(this, SIGNAL(startRequested(const JavaScriptCommand*,Transformer*)),
- m_objectInThread, SLOT(start(const JavaScriptCommand*,Transformer*)));
+ connect(m_objectInThread, &JsCommandExecutorThreadObject::finished,
+ this, &JsCommandExecutor::onJavaScriptCommandFinished);
+ connect(this, &JsCommandExecutor::startRequested,
+ m_objectInThread, &JsCommandExecutorThreadObject::start);
}
JsCommandExecutor::~JsCommandExecutor()
@@ -168,7 +168,9 @@ JsCommandExecutor::~JsCommandExecutor()
void JsCommandExecutor::doReportCommandDescription()
{
- if (m_echoMode == CommandEchoModeCommandLine && !command()->extendedDescription().isEmpty()) {
+ if ((m_echoMode == CommandEchoModeCommandLine
+ || m_echoMode == CommandEchoModeCommandLineWithEnvironment)
+ && !command()->extendedDescription().isEmpty()) {
emit reportCommandDescription(command()->highlight(), command()->extendedDescription());
return;
}
@@ -181,7 +183,7 @@ void JsCommandExecutor::waitForFinished()
if (!m_running)
return;
QEventLoop loop;
- loop.connect(m_objectInThread, SIGNAL(finished()), SLOT(quit()));
+ connect(m_objectInThread, &JsCommandExecutorThreadObject::finished, &loop, &QEventLoop::quit);
loop.exec();
}
@@ -190,8 +192,8 @@ void JsCommandExecutor::doStart()
QBS_ASSERT(!m_running, return);
m_thread->start();
- if (dryRun()) {
- QTimer::singleShot(0, this, SIGNAL(finished())); // Don't call back on the caller.
+ if (dryRun() && !command()->ignoreDryRun()) {
+ QTimer::singleShot(0, this, [this] { emit finished(); }); // Don't call back on the caller.
return;
}
@@ -202,7 +204,7 @@ void JsCommandExecutor::doStart()
void JsCommandExecutor::cancel()
{
if (!dryRun())
- QMetaObject::invokeMethod(m_objectInThread, "cancel", Qt::QueuedConnection);
+ QTimer::singleShot(0, m_objectInThread, [this] { m_objectInThread->cancel(); });
}
void JsCommandExecutor::onJavaScriptCommandFinished()
diff --git a/src/lib/corelib/buildgraph/jscommandexecutor.h b/src/lib/corelib/buildgraph/jscommandexecutor.h
index 82084c5cd..51f239b6b 100644
--- a/src/lib/corelib/buildgraph/jscommandexecutor.h
+++ b/src/lib/corelib/buildgraph/jscommandexecutor.h
@@ -52,10 +52,9 @@ public:
signals:
void startRequested(const JavaScriptCommand *cmd, Transformer *transformer);
-private slots:
+private:
void onJavaScriptCommandFinished();
-private:
void doReportCommandDescription();
void doStart();
void cancel();
diff --git a/src/lib/corelib/buildgraph/nodeset.h b/src/lib/corelib/buildgraph/nodeset.h
index eb79b49f1..9b56567da 100644
--- a/src/lib/corelib/buildgraph/nodeset.h
+++ b/src/lib/corelib/buildgraph/nodeset.h
@@ -125,6 +125,70 @@ private:
QSharedDataPointer<NodeSetData> d;
};
+template <class T>
+class TypeFilter
+{
+ const NodeSet &m_nodes;
+public:
+ TypeFilter(const NodeSet &nodes)
+ : m_nodes(nodes)
+ {
+ }
+
+ class const_iterator : public std::iterator<std::forward_iterator_tag, T *>
+ {
+ const NodeSet &m_nodes;
+ NodeSet::const_iterator m_it;
+ public:
+ const_iterator(const NodeSet &nodes, const NodeSet::const_iterator &it)
+ : m_nodes(nodes), m_it(it)
+ {
+ while (m_it != m_nodes.constEnd() && dynamic_cast<T *>(*m_it) == 0)
+ ++m_it;
+ }
+
+ bool operator==(const const_iterator &rhs)
+ {
+ return m_it == rhs.m_it;
+ }
+
+ bool operator!=(const const_iterator &rhs)
+ {
+ return !(*this == rhs);
+ }
+
+ const_iterator &operator++()
+ {
+ for (;;) {
+ ++m_it;
+ if (m_it == m_nodes.constEnd() || dynamic_cast<T *>(*m_it))
+ return *this;
+ }
+ }
+
+ T *operator*() const
+ {
+ return static_cast<T *>(*m_it);
+ }
+ };
+
+ const_iterator begin() const
+ {
+ return const_iterator(m_nodes, m_nodes.constBegin());
+ }
+
+ const_iterator end() const
+ {
+ return const_iterator(m_nodes, m_nodes.constEnd());
+ }
+};
+
+template <class T>
+const TypeFilter<T> filterByType(const NodeSet &nodes)
+{
+ return TypeFilter<T>(nodes);
+}
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/buildgraph/processcommandexecutor.cpp b/src/lib/corelib/buildgraph/processcommandexecutor.cpp
index c109c792e..67170c0e9 100644
--- a/src/lib/corelib/buildgraph/processcommandexecutor.cpp
+++ b/src/lib/corelib/buildgraph/processcommandexecutor.cpp
@@ -61,8 +61,10 @@ namespace Internal {
ProcessCommandExecutor::ProcessCommandExecutor(const Logger &logger, QObject *parent)
: AbstractCommandExecutor(logger, parent)
{
- connect(&m_process, SIGNAL(error(QProcess::ProcessError)), SLOT(onProcessError()));
- connect(&m_process, SIGNAL(finished(int)), SLOT(onProcessFinished()));
+ connect(&m_process, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error),
+ this, &ProcessCommandExecutor::onProcessError);
+ connect(&m_process, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
+ this, &ProcessCommandExecutor::onProcessFinished);
}
void ProcessCommandExecutor::doSetup()
@@ -72,6 +74,12 @@ void ProcessCommandExecutor::doSetup()
transformer()->product()->buildEnvironment, logger())
.findExecutable(cmd->program(), cmd->workingDir());
+ QProcessEnvironment env = m_buildEnvironment;
+ const QProcessEnvironment &additionalVariables = cmd->environment();
+ foreach (const QString &key, additionalVariables.keys())
+ env.insert(key, additionalVariables.value(key));
+ m_commandEnvironment = env;
+
m_program = program;
m_arguments = cmd->arguments();
m_shellInvocation = shellQuote(QDir::toNativeSeparators(m_program), m_arguments);
@@ -83,16 +91,12 @@ void ProcessCommandExecutor::doStart()
const ProcessCommand * const cmd = processCommand();
- QProcessEnvironment env = m_buildEnvironment;
- const QProcessEnvironment &additionalVariables = cmd->environment();
- foreach (const QString &key, additionalVariables.keys())
- env.insert(key, additionalVariables.value(key));
- m_process.setProcessEnvironment(env);
+ m_process.setProcessEnvironment(m_commandEnvironment);
QStringList arguments = m_arguments;
- if (dryRun()) {
- QTimer::singleShot(0, this, SIGNAL(finished())); // Don't call back on the caller.
+ if (dryRun() && !cmd->ignoreDryRun()) {
+ QTimer::singleShot(0, this, [this] { emit finished(); }); // Don't call back on the caller.
return;
}
@@ -144,6 +148,7 @@ void ProcessCommandExecutor::doStart()
logger().qbsDebug() << "[EXEC] Running external process; full command line is: "
<< m_shellInvocation;
+ const QProcessEnvironment &additionalVariables = cmd->environment();
logger().qbsTrace() << "[EXEC] Additional environment:" << additionalVariables.toStringList();
m_process.setWorkingDirectory(workingDir);
m_process.start(m_program, arguments);
@@ -152,7 +157,7 @@ void ProcessCommandExecutor::doStart()
void ProcessCommandExecutor::cancel()
{
// We don't want this command to be reported as failing, since we explicitly terminated it.
- disconnect(this, SIGNAL(reportProcessResult(qbs::ProcessResult)), 0, 0);
+ disconnect(this, &ProcessCommandExecutor::reportProcessResult, 0, 0);
m_process.terminate();
if (!m_process.waitForFinished(1000))
@@ -167,14 +172,13 @@ QString ProcessCommandExecutor::filterProcessOutput(const QByteArray &_output,
return output;
QScriptValue scope = scriptEngine()->newObject();
+ scope.setPrototype(scriptEngine()->globalObject());
for (QVariantMap::const_iterator it = command()->properties().constBegin();
it != command()->properties().constEnd(); ++it) {
scope.setProperty(it.key(), scriptEngine()->toScriptValue(it.value()));
}
- ScriptContextScopePusher scopePusher(scriptEngine()->currentContext(), scope);
- Q_UNUSED(scopePusher);
-
+ TemporaryGlobalObjectSetter tgos(scope);
QScriptValue filterFunction = scriptEngine()->evaluate(QLatin1String("var f = ")
+ filterFunctionSource
+ QLatin1String("; f"));
@@ -304,13 +308,32 @@ void ProcessCommandExecutor::onProcessFinished()
sendProcessOutput();
}
+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');
+}
+
void ProcessCommandExecutor::doReportCommandDescription()
{
- if (m_echoMode == CommandEchoModeCommandLine) {
+ if (m_echoMode == CommandEchoModeCommandLine ||
+ m_echoMode == CommandEchoModeCommandLineWithEnvironment) {
+ QString fullInvocation;
+ if (m_echoMode == CommandEchoModeCommandLineWithEnvironment) {
+ QStringList keys = m_commandEnvironment.keys();
+ keys.sort();
+ for (const QString &key : keys)
+ fullInvocation += environmentVariableString(key, m_commandEnvironment.value(key));
+ }
+ fullInvocation += m_shellInvocation;
emit reportCommandDescription(command()->highlight(),
!command()->extendedDescription().isEmpty()
? command()->extendedDescription()
- : m_shellInvocation);
+ : fullInvocation);
return;
}
diff --git a/src/lib/corelib/buildgraph/processcommandexecutor.h b/src/lib/corelib/buildgraph/processcommandexecutor.h
index aaeb5a20b..660d38a38 100644
--- a/src/lib/corelib/buildgraph/processcommandexecutor.h
+++ b/src/lib/corelib/buildgraph/processcommandexecutor.h
@@ -56,11 +56,10 @@ public:
signals:
void reportProcessResult(const qbs::ProcessResult &result);
-private slots:
+private:
void onProcessError();
void onProcessFinished();
-private:
void doSetup();
void doReportCommandDescription();
void doStart();
@@ -81,6 +80,7 @@ private:
QProcess m_process;
QProcessEnvironment m_buildEnvironment;
+ QProcessEnvironment m_commandEnvironment;
QString m_responseFileName;
};
diff --git a/src/lib/corelib/buildgraph/productbuilddata.cpp b/src/lib/corelib/buildgraph/productbuilddata.cpp
index 5cfcb09dd..36e887b62 100644
--- a/src/lib/corelib/buildgraph/productbuilddata.cpp
+++ b/src/lib/corelib/buildgraph/productbuilddata.cpp
@@ -46,9 +46,9 @@ ProductBuildData::~ProductBuildData()
qDeleteAll(nodes);
}
-ArtifactSet ProductBuildData::rootArtifacts() const
+const TypeFilter<Artifact> ProductBuildData::rootArtifacts() const
{
- return ArtifactSet::fromNodeSet(roots);
+ return TypeFilter<Artifact>(roots);
}
static void loadArtifactSetByFileTag(PersistentPool &pool,
diff --git a/src/lib/corelib/buildgraph/productbuilddata.h b/src/lib/corelib/buildgraph/productbuilddata.h
index ee2f05359..09401acce 100644
--- a/src/lib/corelib/buildgraph/productbuilddata.h
+++ b/src/lib/corelib/buildgraph/productbuilddata.h
@@ -50,7 +50,7 @@ class ProductBuildData : public PersistentObject
public:
~ProductBuildData();
- ArtifactSet rootArtifacts() const;
+ const TypeFilter<Artifact> rootArtifacts() const;
NodeSet nodes;
NodeSet roots;
diff --git a/src/lib/corelib/buildgraph/productinstaller.cpp b/src/lib/corelib/buildgraph/productinstaller.cpp
index d462943bd..5ecb0d3de 100644
--- a/src/lib/corelib/buildgraph/productinstaller.cpp
+++ b/src/lib/corelib/buildgraph/productinstaller.cpp
@@ -88,7 +88,7 @@ void ProductInstaller::install()
QList<const Artifact *> artifactsToInstall;
foreach (const ResolvedProductConstPtr &product, m_products) {
QBS_CHECK(product->buildData);
- foreach (const Artifact *artifact, ArtifactSet::fromNodeSet(product->buildData->nodes)) {
+ for (const Artifact *artifact : filterByType<Artifact>(product->buildData->nodes)) {
if (artifact->properties->qbsPropertyValue(QLatin1String("install")).toBool())
artifactsToInstall += artifact;
}
diff --git a/src/lib/corelib/buildgraph/projectbuilddata.cpp b/src/lib/corelib/buildgraph/projectbuilddata.cpp
index 002ba1729..4482ae9a7 100644
--- a/src/lib/corelib/buildgraph/projectbuilddata.cpp
+++ b/src/lib/corelib/buildgraph/projectbuilddata.cpp
@@ -156,12 +156,36 @@ QString ProjectBuildData::deriveBuildGraphFilePath(const QString &buildDir, cons
return buildDir + QLatin1Char('/') + projectId + QLatin1String(".bg");
}
+static QString productNameForErrorMessage(const ResolvedProduct *product)
+{
+ return product->profile == product->topLevelProject()->profile()
+ ? product->name : product->uniqueName();
+}
+
void ProjectBuildData::insertIntoLookupTable(FileResourceBase *fileres)
{
QList<FileResourceBase *> &lst
= m_artifactLookupTable[fileres->fileName()][fileres->dirPath()];
- if (!lst.contains(fileres))
- lst.append(fileres);
+ const auto * const artifact = dynamic_cast<Artifact *>(fileres);
+ if (artifact && artifact->artifactType == Artifact::Generated) {
+ foreach (const auto *file, lst) {
+ const auto * const otherArtifact = dynamic_cast<const Artifact *>(file);
+ if (otherArtifact) {
+ ErrorInfo error;
+ 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())),
+ otherArtifact->product->location);
+ error.append(Tr::tr("The second artifact comes from product '%1'.")
+ .arg(productNameForErrorMessage(artifact->product.data())),
+ otherArtifact->product->location);
+ throw error;
+ }
+ }
+ }
+ QBS_CHECK(!lst.contains(fileres));
+ lst.append(fileres);
}
void ProjectBuildData::removeFromLookupTable(FileResourceBase *fileres)
@@ -243,7 +267,10 @@ void ProjectBuildData::removeArtifactAndExclusiveDependents(Artifact *artifact,
if (removedArtifacts)
removedArtifacts->insert(artifact);
- foreach (Artifact *parent, ArtifactSet::fromNodeSet(artifact->parents)) {
+ // Iterate over a copy of the artifact's parents, because we'll change
+ // artifact->parents with the disconnect call.
+ const NodeSet parentsCopy = artifact->parents;
+ for (Artifact *parent : filterByType<Artifact>(parentsCopy)) {
bool removeParent = false;
disconnect(parent, artifact, logger);
if (parent->children.isEmpty()) {
diff --git a/src/lib/corelib/buildgraph/rescuableartifactdata.cpp b/src/lib/corelib/buildgraph/rescuableartifactdata.cpp
index 85cc9a08a..464ea1135 100644
--- a/src/lib/corelib/buildgraph/rescuableartifactdata.cpp
+++ b/src/lib/corelib/buildgraph/rescuableartifactdata.cpp
@@ -56,6 +56,9 @@ void RescuableArtifactData::load(PersistentPool &pool)
children << cd;
}
+ propertiesRequestedInPrepareScript = restorePropertySet(pool);
+ propertiesRequestedInCommands = restorePropertySet(pool);
+ propertiesRequestedFromArtifactInPrepareScript = restorePropertyHash(pool);
commands = loadCommandList(pool);
}
@@ -71,6 +74,9 @@ void RescuableArtifactData::store(PersistentPool &pool) const
pool.stream() << cd.addedByScanner;
}
+ storePropertySet(pool, propertiesRequestedInPrepareScript);
+ storePropertySet(pool, propertiesRequestedInCommands);
+ storePropertyHash(pool, propertiesRequestedFromArtifactInPrepareScript);
storeCommandList(commands, pool);
}
diff --git a/src/lib/corelib/buildgraph/rescuableartifactdata.h b/src/lib/corelib/buildgraph/rescuableartifactdata.h
index 96998f77c..b04f5d073 100644
--- a/src/lib/corelib/buildgraph/rescuableartifactdata.h
+++ b/src/lib/corelib/buildgraph/rescuableartifactdata.h
@@ -33,6 +33,7 @@
#include "forward_decls.h"
+#include <language/property.h>
#include <tools/filetime.h>
#include <QHash>
@@ -64,7 +65,13 @@ public:
FileTime timeStamp;
QList<ChildData> children;
+
+ // Per-Transformer data
QList<AbstractCommandPtr> commands;
+ PropertySet propertiesRequestedInPrepareScript;
+ PropertySet propertiesRequestedInCommands;
+ PropertyHash propertiesRequestedFromArtifactInPrepareScript;
+
};
typedef QHash<QString, RescuableArtifactData> AllRescuableArtifactData;
diff --git a/src/lib/corelib/buildgraph/rulenode.cpp b/src/lib/corelib/buildgraph/rulenode.cpp
index 3a6940f88..15abb9e67 100644
--- a/src/lib/corelib/buildgraph/rulenode.cpp
+++ b/src/lib/corelib/buildgraph/rulenode.cpp
@@ -73,7 +73,8 @@ void RuleNode::apply(const Logger &logger, const ArtifactSet &changedInputs,
ArtifactSet allCompatibleInputs = currentInputArtifacts();
const ArtifactSet addedInputs = allCompatibleInputs - m_oldInputArtifacts;
const ArtifactSet removedInputs = m_oldInputArtifacts - allCompatibleInputs;
- result->upToDate = changedInputs.isEmpty() && addedInputs.isEmpty() && removedInputs.isEmpty();
+ result->upToDate = changedInputs.isEmpty() && addedInputs.isEmpty() && removedInputs.isEmpty()
+ && m_rule->requiresInputs();
if (logger.traceEnabled()) {
logger.qbsTrace()
@@ -105,7 +106,7 @@ void RuleNode::apply(const Logger &logger, const ArtifactSet &changedInputs,
if (!removedInputs.isEmpty()) {
ArtifactSet outputArtifactsToRemove;
foreach (Artifact *artifact, removedInputs) {
- foreach (Artifact *parent, ArtifactSet::fromNodeSet(artifact->parents)) {
+ for (Artifact *parent : filterByType<Artifact>(artifact->parents)) {
if (parent->transformer->rule != m_rule) {
// parent was not created by our rule.
continue;
@@ -123,7 +124,7 @@ void RuleNode::apply(const Logger &logger, const ArtifactSet &changedInputs,
}
RulesApplicator::handleRemovedRuleOutputs(inputs, outputArtifactsToRemove, logger);
}
- if (!inputs.isEmpty()) {
+ if (!inputs.isEmpty() || !m_rule->requiresInputs()) {
RulesApplicator applicator(product, logger);
applicator.applyRule(m_rule, inputs);
result->createdNodes = applicator.createdArtifacts();
@@ -165,7 +166,7 @@ ArtifactSet RuleNode::currentInputArtifacts() const
continue;
if (m_rule->inputsFromDependencies.isEmpty())
continue;
- foreach (Artifact * const a, ArtifactSet::fromNodeSet(dep->buildData->nodes)) {
+ for (Artifact * const a : filterByType<Artifact>(dep->buildData->nodes)) {
if (a->fileTags().matches(m_rule->inputsFromDependencies))
s += a;
}
diff --git a/src/lib/corelib/buildgraph/rulesapplicator.cpp b/src/lib/corelib/buildgraph/rulesapplicator.cpp
index aaab572a0..bebbe3ada 100644
--- a/src/lib/corelib/buildgraph/rulesapplicator.cpp
+++ b/src/lib/corelib/buildgraph/rulesapplicator.cpp
@@ -53,6 +53,7 @@
#include <QDir>
#include <QQueue>
+#include <QScopedPointer>
#include <QScriptValueIterator>
namespace qbs {
@@ -72,7 +73,7 @@ RulesApplicator::~RulesApplicator()
void RulesApplicator::applyRule(const RuleConstPtr &rule, const ArtifactSet &inputArtifacts)
{
- if (inputArtifacts.isEmpty())
+ if (inputArtifacts.isEmpty() && rule->requiresInputs())
return;
m_createdArtifacts.clear();
@@ -86,6 +87,7 @@ void RulesApplicator::applyRule(const RuleConstPtr &rule, const ArtifactSet &inp
m_mocScanner = new QtMocScanner(m_product, scope(), m_logger);
}
QScriptValue prepareScriptContext = engine()->newObject();
+ prepareScriptContext.setPrototype(engine()->globalObject());
PrepareScriptObserver observer(engine());
setupScriptEngineForFile(engine(), m_rule->prepareScript->fileContext, scope());
setupScriptEngineForProduct(engine(), m_product, m_rule->module, prepareScriptContext, &observer);
@@ -118,7 +120,7 @@ void RulesApplicator::handleRemovedRuleOutputs(const ArtifactSet &inputArtifacts
}
// parents of removed artifacts must update their transformers
foreach (Artifact *removedArtifact, artifactsToRemove) {
- foreach (Artifact *parent, removedArtifact->parentArtifacts())
+ for (Artifact *parent : removedArtifact->parentArtifacts())
parent->product->registerArtifactWithChangedInputs(parent);
}
EmptyDirectoriesRemover(project, logger).removeEmptyParentDirectories(artifactsToRemove);
@@ -206,7 +208,7 @@ void RulesApplicator::doApply(const ArtifactSet &inputArtifacts, QScriptValue &p
// change the transformer outputs according to the bindings in Artifact
QScriptValue scriptValue;
if (!ruleArtifactArtifactMap.isEmpty())
- engine()->currentContext()->pushScope(prepareScriptContext);
+ engine()->setGlobalObject(prepareScriptContext);
for (int i = ruleArtifactArtifactMap.count(); --i >= 0;) {
const RuleArtifact *ra = ruleArtifactArtifactMap.at(i).first;
if (ra->bindings.isEmpty())
@@ -238,7 +240,7 @@ void RulesApplicator::doApply(const ArtifactSet &inputArtifacts, QScriptValue &p
outputArtifact->properties->setValue(outputArtifactConfig);
}
if (!ruleArtifactArtifactMap.isEmpty())
- engine()->currentContext()->popScope();
+ engine()->setGlobalObject(prepareScriptContext.prototype());
m_transformer->setupOutputs(engine(), prepareScriptContext);
m_transformer->createCommands(m_rule->prepareScript, evalContext(),
@@ -252,7 +254,7 @@ ArtifactSet RulesApplicator::collectOldOutputArtifacts(const ArtifactSet &inputA
{
ArtifactSet result;
foreach (Artifact *a, inputArtifacts) {
- foreach (Artifact *p, a->parentArtifacts()) {
+ for (Artifact *p : a->parentArtifacts()) {
QBS_CHECK(p->transformer);
if (p->transformer->rule == m_rule && p->transformer->inputs.contains(a))
result += p;
@@ -294,7 +296,8 @@ Artifact *RulesApplicator::createOutputArtifact(const QString &filePath, const F
Artifact *outputArtifact = lookupArtifact(m_product, outputPath);
if (outputArtifact) {
- if (outputArtifact->transformer && outputArtifact->transformer->rule != m_rule) {
+ const Transformer * const transformer = outputArtifact->transformer.data();
+ if (transformer && transformer->rule != m_rule) {
QString e = Tr::tr("Conflicting rules for producing %1 %2 \n")
.arg(outputArtifact->filePath(),
QLatin1Char('[') +
@@ -311,21 +314,35 @@ Artifact *RulesApplicator::createOutputArtifact(const QString &filePath, const F
.arg(str);
e += QString::fromLatin1(" was already defined in: %1:%2:%3 %4\n")
- .arg(outputArtifact->transformer->rule->prepareScript->location.filePath())
- .arg(outputArtifact->transformer->rule->prepareScript->location.line())
- .arg(outputArtifact->transformer->rule->prepareScript->location.column())
+ .arg(transformer->rule->prepareScript->location.filePath())
+ .arg(transformer->rule->prepareScript->location.line())
+ .arg(transformer->rule->prepareScript->location.column())
.arg(str);
throw ErrorInfo(e);
}
- outputArtifact->clearTimestamp();
+ if (transformer && !m_rule->multiplex && transformer->inputs != inputArtifacts) {
+ QBS_CHECK(inputArtifacts.count() == 1);
+ QBS_CHECK(transformer->inputs.count() == 1);
+ ErrorInfo error(Tr::tr("Conflicting instances of rule '%1':").arg(m_rule->toString()),
+ m_rule->prepareScript->location);
+ error.append(Tr::tr("Output artifact '%1' is to be produced from input "
+ "artifacts '%2' and '%3', but the rule is not a multiplex rule.")
+ .arg(outputArtifact->filePath(),
+ (*transformer->inputs.begin())->filePath(),
+ (*inputArtifacts.begin())->filePath()));
+ throw error;
+ }
+ if (m_rule->requiresInputs())
+ outputArtifact->clearTimestamp();
m_invalidatedArtifacts += outputArtifact;
} else {
- outputArtifact = new Artifact;
- outputArtifact->artifactType = Artifact::Generated;
- outputArtifact->setFilePath(outputPath);
- insertArtifact(m_product, outputArtifact, m_logger);
- m_createdArtifacts += outputArtifact;
+ QScopedPointer<Artifact> newArtifact(new Artifact);
+ newArtifact->artifactType = Artifact::Generated;
+ newArtifact->setFilePath(outputPath);
+ insertArtifact(m_product, newArtifact.data(), m_logger);
+ m_createdArtifacts += newArtifact.data();
+ outputArtifact = newArtifact.take();
}
outputArtifact->setFileTags(
diff --git a/src/lib/corelib/buildgraph/rulesevaluationcontext.cpp b/src/lib/corelib/buildgraph/rulesevaluationcontext.cpp
index e195527d4..762016e49 100644
--- a/src/lib/corelib/buildgraph/rulesevaluationcontext.cpp
+++ b/src/lib/corelib/buildgraph/rulesevaluationcontext.cpp
@@ -49,6 +49,7 @@ RulesEvaluationContext::RulesEvaluationContext(const Logger &logger)
: m_engine(new ScriptEngine(logger)), m_observer(0), m_initScopeCalls(0)
{
m_prepareScriptScope = m_engine->newObject();
+ m_prepareScriptScope.setPrototype(m_engine->globalObject());
ProcessCommand::setupForJavaScript(m_prepareScriptScope);
JavaScriptCommand::setupForJavaScript(m_prepareScriptScope);
}
@@ -86,11 +87,9 @@ void RulesEvaluationContext::initScope()
if (m_initScopeCalls++ > 0)
return;
- m_engine->clearImportsCache();
- m_engine->pushContext();
m_scope = m_engine->newObject();
m_scope.setPrototype(m_prepareScriptScope);
- m_engine->currentContext()->pushScope(m_scope);
+ m_engine->setGlobalObject(m_scope);
}
void RulesEvaluationContext::cleanupScope()
@@ -100,8 +99,7 @@ void RulesEvaluationContext::cleanupScope()
return;
m_scope = QScriptValue();
- m_engine->currentContext()->popScope();
- m_engine->popContext();
+ m_engine->setGlobalObject(m_prepareScriptScope.prototype());
}
RulesEvaluationContext::Scope::Scope(RulesEvaluationContext *evalContext)
diff --git a/src/lib/corelib/buildgraph/transformer.cpp b/src/lib/corelib/buildgraph/transformer.cpp
index d0b58765e..6dba0ac1c 100644
--- a/src/lib/corelib/buildgraph/transformer.cpp
+++ b/src/lib/corelib/buildgraph/transformer.cpp
@@ -247,81 +247,26 @@ void Transformer::createCommands(const ScriptFunctionConstPtr &script,
}
}
-static void restorePropertyList(PersistentPool &pool, PropertySet &list)
-{
- int count;
- pool.stream() >> count;
- list.reserve(count);
- while (--count >= 0) {
- Property p;
- p.moduleName = pool.idLoadString();
- p.propertyName = pool.idLoadString();
- int k;
- pool.stream() >> p.value >> k;
- p.kind = static_cast<Property::Kind>(k);
- list += p;
- }
-}
-
void Transformer::load(PersistentPool &pool)
{
rule = pool.idLoadS<Rule>();
pool.loadContainer(inputs);
pool.loadContainer(outputs);
- restorePropertyList(pool, propertiesRequestedInPrepareScript);
- restorePropertyList(pool, propertiesRequestedInCommands);
- int count;
- pool.stream() >> count;
- propertiesRequestedFromArtifactInPrepareScript.reserve(count);
- while (--count >= 0) {
- const QString artifactName = pool.idLoadString();
- int listCount;
- pool.stream() >> listCount;
- PropertySet list;
- list.reserve(listCount);
- while (--listCount >= 0) {
- Property p;
- p.moduleName = pool.idLoadString();
- p.propertyName = pool.idLoadString();
- pool.stream() >> p.value;
- p.kind = Property::PropertyInModule;
- list += p;
- }
- propertiesRequestedFromArtifactInPrepareScript.insert(artifactName, list);
- }
+ propertiesRequestedInPrepareScript = restorePropertySet(pool);
+ propertiesRequestedInCommands = restorePropertySet(pool);
+ propertiesRequestedFromArtifactInPrepareScript = restorePropertyHash(pool);
commands = loadCommandList(pool);
pool.stream() >> alwaysRun;
}
-static void storePropertyList(PersistentPool &pool, const PropertySet &list)
-{
- pool.stream() << list.count();
- foreach (const Property &p, list) {
- pool.storeString(p.moduleName);
- pool.storeString(p.propertyName);
- pool.stream() << p.value << static_cast<int>(p.kind);
- }
-}
-
void Transformer::store(PersistentPool &pool) const
{
pool.store(rule);
pool.storeContainer(inputs);
pool.storeContainer(outputs);
- storePropertyList(pool, propertiesRequestedInPrepareScript);
- storePropertyList(pool, propertiesRequestedInCommands);
- pool.stream() << propertiesRequestedFromArtifactInPrepareScript.count();
- for (QHash<QString, PropertySet>::ConstIterator it = propertiesRequestedFromArtifactInPrepareScript.constBegin();
- it != propertiesRequestedFromArtifactInPrepareScript.constEnd(); ++it) {
- pool.storeString(it.key());
- const PropertySet &properties = it.value();
- pool.stream() << properties.count();
- foreach (const Property &p, properties) {
- pool.storeString(p.moduleName);
- pool.storeString(p.propertyName);
- pool.stream() << p.value; // kind is always PropertyInModule
- }
- }
+ storePropertySet(pool, propertiesRequestedInPrepareScript);
+ storePropertySet(pool, propertiesRequestedInCommands);
+ storePropertyHash(pool, propertiesRequestedFromArtifactInPrepareScript);
storeCommandList(commands, pool);
pool.stream() << alwaysRun;
}
diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs
index 51355a253..4c52af17b 100644
--- a/src/lib/corelib/corelib.qbs
+++ b/src/lib/corelib/corelib.qbs
@@ -4,15 +4,15 @@ import QbsFunctions
QbsLibrary {
Depends { name: "cpp" }
Depends { name: "Qt"; submodules: ["core-private", "network", "script", "xml"] }
- Depends { condition: project.enableProjectFileUpdates; name: "Qt.gui" }
- Depends { condition: project.enableUnitTests; name: "Qt.test" }
+ Depends { condition: qbsbuildconfig.enableProjectFileUpdates; name: "Qt.gui" }
+ Depends { condition: qbsbuildconfig.enableUnitTests; name: "Qt.test" }
name: "qbscore"
cpp.includePaths: base.concat([
".",
"../.." // for the plugin headers
])
property stringList projectFileUpdateDefines:
- project.enableProjectFileUpdates ? ["QBS_ENABLE_PROJECT_FILE_UPDATES"] : []
+ qbsbuildconfig.enableProjectFileUpdates ? ["QBS_ENABLE_PROJECT_FILE_UPDATES"] : []
cpp.defines: base.concat([
"QBS_VERSION=\"" + version + "\"",
"QT_CREATOR", "QML_BUILD_STATIC_LIB", // needed for QmlJS
@@ -37,12 +37,12 @@ QbsLibrary {
Group {
name: product.name
files: ["qbs.h"]
- qbs.install: project.installApiHeaders
+ qbs.install: qbsbuildconfig.installApiHeaders
qbs.installDir: headerInstallPrefix
}
Group {
name: "project file updating"
- condition: project.enableProjectFileUpdates
+ condition: qbsbuildconfig.enableProjectFileUpdates
prefix: "api/"
files: [
"changeset.cpp",
@@ -74,7 +74,7 @@ QbsLibrary {
}
Group {
name: "public api headers"
- qbs.install: project.installApiHeaders
+ qbs.install: qbsbuildconfig.installApiHeaders
qbs.installDir: headerInstallPrefix + "/api"
prefix: "api/"
files: [
@@ -159,7 +159,7 @@ QbsLibrary {
}
Group {
name: "public buildgraph headers"
- qbs.install: project.installApiHeaders
+ qbs.install: qbsbuildconfig.installApiHeaders
qbs.installDir: headerInstallPrefix + "/buildgraph"
files: "buildgraph/forward_decls.h"
}
@@ -214,8 +214,6 @@ QbsLibrary {
"asttools.h",
"builtindeclarations.cpp",
"builtindeclarations.h",
- "builtinvalue.cpp",
- "builtinvalue.h",
"deprecationinfo.h",
"evaluationdata.h",
"evaluator.cpp",
@@ -258,6 +256,7 @@ QbsLibrary {
"preparescriptobserver.h",
"projectresolver.cpp",
"projectresolver.h",
+ "property.cpp",
"property.h",
"propertydeclaration.cpp",
"propertydeclaration.h",
@@ -269,6 +268,8 @@ QbsLibrary {
"resolvedfilecontext.h",
"scriptengine.cpp",
"scriptengine.h",
+ "scriptimporter.cpp",
+ "scriptimporter.h",
"scriptpropertyobserver.h",
"value.cpp",
"value.h",
@@ -276,7 +277,7 @@ QbsLibrary {
}
Group {
name: "public language headers"
- qbs.install: project.installApiHeaders
+ qbs.install: qbsbuildconfig.installApiHeaders
qbs.installDir: headerInstallPrefix + "/language"
files: "language/forward_decls.h"
}
@@ -292,7 +293,7 @@ QbsLibrary {
}
Group {
name: "public logging headers"
- qbs.install: project.installApiHeaders
+ qbs.install: qbsbuildconfig.installApiHeaders
qbs.installDir: headerInstallPrefix + "/logging"
files: "logging/ilogsink.h"
}
@@ -371,6 +372,7 @@ QbsLibrary {
"setupprojectparameters.cpp",
"shellutils.cpp",
"shellutils.h",
+ "toolchains.cpp",
"version.cpp",
"version.h",
"visualstudioversioninfo.cpp",
@@ -398,8 +400,9 @@ QbsLibrary {
"settings.h",
"settingsmodel.h",
"setupprojectparameters.h",
+ "toolchains.h",
]
- qbs.install: project.installApiHeaders
+ qbs.install: qbsbuildconfig.installApiHeaders
qbs.installDir: headerInstallPrefix + "/tools"
}
Group {
@@ -433,11 +436,11 @@ QbsLibrary {
"use_installed_corelib.pri",
"../../../qbs_version.pri"
]
- qbs.install: project.installApiHeaders
+ qbs.install: qbsbuildconfig.installApiHeaders
qbs.installDir: headerInstallPrefix
}
Group {
- condition: project.enableUnitTests
+ condition: qbsbuildconfig.enableUnitTests
name: "tests"
cpp.defines: outer.filter(function(def) { return def !== "QT_NO_CAST_FROM_ASCII"; })
files: [
diff --git a/src/lib/corelib/jsextensions/environmentextension.cpp b/src/lib/corelib/jsextensions/environmentextension.cpp
index 8f03ec374..56c60653b 100644
--- a/src/lib/corelib/jsextensions/environmentextension.cpp
+++ b/src/lib/corelib/jsextensions/environmentextension.cpp
@@ -32,9 +32,7 @@
#include <language/scriptengine.h>
#include <logging/translator.h>
-#include <tools/error.h>
#include <tools/fileinfo.h>
-#include <tools/qbsassert.h>
#include <QDir>
#include <QFileInfo>
@@ -151,37 +149,6 @@ QScriptValue EnvironmentExtension::js_currentEnv(QScriptContext *context, QScrip
return envObject;
}
-static void printDeprecationWarning(const QString &message, const QScriptContext *context,
- QScriptEngine *engine)
-{
- ErrorInfo fullError(message, context->backtrace());
- ErrorInfo error;
- if (fullError.items().count() == 1) {
- error = fullError;
- } else {
- QBS_CHECK(fullError.items().count() >= 2);
- error.append(fullError.items().first().description(),
- fullError.items().at(1).codeLocation());
- }
- static_cast<ScriptEngine *>(engine)->logger().printWarning(error);
-}
-
-QScriptValue js_getEnvDeprecated(QScriptContext *context, QScriptEngine *qtengine)
-{
- const QString message = Tr::tr("qbs.getEnv is deprecated and will be removed in Qbs 1.6. "
- "Use Environment.getEnv instead.");
- printDeprecationWarning(message, context, qtengine);
- return EnvironmentExtension::js_getEnv(context, qtengine);
-}
-
-QScriptValue js_currentEnvDeprecated(QScriptContext *context, QScriptEngine *qtengine)
-{
- const QString message = Tr::tr("qbs.currentEnv is deprecated and will be removed in Qbs 1.6. "
- "Use Environment.currentEnv instead.");
- printDeprecationWarning(message, context, qtengine);
- return EnvironmentExtension::js_currentEnv(context, qtengine);
-}
-
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/jsextensions/environmentextension.h b/src/lib/corelib/jsextensions/environmentextension.h
index dd4b980de..4c2555a66 100644
--- a/src/lib/corelib/jsextensions/environmentextension.h
+++ b/src/lib/corelib/jsextensions/environmentextension.h
@@ -43,9 +43,6 @@ namespace Internal {
void initializeJsExtensionEnvironment(QScriptValue extensionObject);
-QScriptValue js_getEnvDeprecated(QScriptContext *context, QScriptEngine *engine);
-QScriptValue js_currentEnvDeprecated(QScriptContext *context, QScriptEngine *engine);
-
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/jsextensions/propertylist.mm b/src/lib/corelib/jsextensions/propertylist.mm
index 0306310c5..711a15b2e 100644
--- a/src/lib/corelib/jsextensions/propertylist.mm
+++ b/src/lib/corelib/jsextensions/propertylist.mm
@@ -240,7 +240,7 @@ void PropertyListPrivate::readFromData(QScriptContext *context, QByteArray data)
respondsToSelector:@selector(propertyListWithData:options:format:error:)]) {
error = nil;
errorString = nil;
- plist = [NSPropertyListSerialization propertyListWithData:QByteArray_toNSData(data)
+ plist = [NSPropertyListSerialization propertyListWithData:data.toNSData()
options:0
format:&format error:&error];
if (Q_UNLIKELY(!plist)) {
@@ -251,7 +251,7 @@ void PropertyListPrivate::readFromData(QScriptContext *context, QByteArray data)
{
error = nil;
errorString = nil;
- plist = [NSPropertyListSerialization propertyListFromData:QByteArray_toNSData(data)
+ plist = [NSPropertyListSerialization propertyListFromData:data.toNSData()
mutabilityOption:NSPropertyListImmutable
format:&format
errorDescription:&errorString];
@@ -262,7 +262,7 @@ void PropertyListPrivate::readFromData(QScriptContext *context, QByteArray data)
if (!plist && NSClassFromString(@"NSJSONSerialization")) {
error = nil;
errorString = nil;
- plist = [NSJSONSerialization JSONObjectWithData:QByteArray_toNSData(data)
+ plist = [NSJSONSerialization JSONObjectWithData:data.toNSData()
options:0
error:&error];
if (Q_UNLIKELY(!plist)) {
@@ -274,7 +274,7 @@ void PropertyListPrivate::readFromData(QScriptContext *context, QByteArray data)
#endif
if (Q_UNLIKELY(!plist)) {
- context->throwError(QString_fromNSString(errorString));
+ context->throwError(QString::fromNSString(errorString));
} else {
QVariant obj = QPropertyListUtils::fromPropertyList(plist);
if (!obj.isNull()) {
@@ -351,10 +351,10 @@ QByteArray PropertyListPrivate::writeToData(QScriptContext *context, const QStri
}
if (Q_UNLIKELY(!data)) {
- context->throwError(QString_fromNSString(errorString));
+ context->throwError(QString::fromNSString(errorString));
}
- return QByteArray_fromNSData(data);
+ return QByteArray::fromNSData(data);
}
}
diff --git a/src/lib/corelib/jsextensions/propertylistutils.h b/src/lib/corelib/jsextensions/propertylistutils.h
index 773201410..882b956e0 100644
--- a/src/lib/corelib/jsextensions/propertylistutils.h
+++ b/src/lib/corelib/jsextensions/propertylistutils.h
@@ -39,51 +39,6 @@
#error "This file must be included from Objective-C++"
#endif
-static inline QString QString_fromNSString(const NSString *string)
-{
-#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
- return QString::fromNSString(string);
-#else
- if (!string)
- return QString();
- QString qstring;
- qstring.resize([string length]);
- [string getCharacters:reinterpret_cast<unichar*>(qstring.data())
- range:NSMakeRange(0, [string length])];
- return qstring;
-#endif
-}
-
-static inline NSString *QString_toNSString(const QString &qstring)
-{
-#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
- return qstring.toNSString();
-#else
- return [NSString stringWithCharacters:reinterpret_cast<const UniChar*>(qstring.unicode())
- length:qstring.length()];
-#endif
-}
-
-static inline QByteArray QByteArray_fromNSData(const NSData *data)
-{
-#if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)
- return QByteArray::fromNSData(data);
-#else
- if (!data)
- return QByteArray();
- return QByteArray(reinterpret_cast<const char*>([data bytes]), [data length]);
-#endif
-}
-
-static inline NSData *QByteArray_toNSData(const QByteArray &qbytearray)
-{
-#if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)
- return qbytearray.toNSData();
-#else
- return [NSData dataWithBytes:qbytearray.constData() length:qbytearray.size()];
-#endif
-}
-
class QPropertyListUtils
{
Q_DISABLE_COPY(QPropertyListUtils)
diff --git a/src/lib/corelib/jsextensions/propertylistutils.mm b/src/lib/corelib/jsextensions/propertylistutils.mm
index 0f3ca9640..64ef3c06d 100644
--- a/src/lib/corelib/jsextensions/propertylistutils.mm
+++ b/src/lib/corelib/jsextensions/propertylistutils.mm
@@ -71,9 +71,9 @@ static QVariant fromObject(id obj)
} else if ([obj isKindOfClass:[NSArray class]]) {
value = fromArray(obj);
} else if ([obj isKindOfClass:[NSString class]]) {
- value = QString_fromNSString(obj);
+ value = QString::fromNSString(obj);
} else if ([obj isKindOfClass:[NSData class]]) {
- value = QByteArray_fromNSData(obj);
+ value = QByteArray::fromNSData(obj);
} else if ([obj isKindOfClass:[NSDate class]]) {
value = QDateTime_fromNSDate(obj);
} else if ([obj isKindOfClass:[NSNumber class]]) {
@@ -116,7 +116,7 @@ static QVariantMap fromDictionary(NSDictionary *dict)
{
QVariantMap map;
for (NSString *key in dict)
- map[QString_fromNSString(key)] = fromObject([dict objectForKey:key]);
+ map[QString::fromNSString(key)] = fromObject([dict objectForKey:key]);
return map;
}
@@ -146,9 +146,9 @@ static id toObject(const QVariant &variant)
} else if (variant.type() == QVariant::List) {
return toArray(variant.toList());
} else if (variant.type() == QVariant::String) {
- return QString_toNSString(variant.toString());
+ return variant.toString().toNSString();
} else if (variant.type() == QVariant::ByteArray) {
- return QByteArray_toNSData(variant.toByteArray());
+ return variant.toByteArray().toNSData();
} else if (variant.type() == QVariant::Date ||
variant.type() == QVariant::DateTime) {
return QDateTime_toNSDate(variant.toDateTime());
@@ -178,7 +178,7 @@ static NSDictionary *toDictionary(const QVariantMap &map)
QMapIterator<QString, QVariant> i(map);
while (i.hasNext()) {
i.next();
- [dict setObject:toObject(i.value()) forKey:QString_toNSString(i.key())];
+ [dict setObject:toObject(i.value()) forKey:i.key().toNSString()];
}
return [NSDictionary dictionaryWithDictionary:dict];
}
diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp
index f4ca809de..fb60da7fb 100644
--- a/src/lib/corelib/jsextensions/utilitiesextension.cpp
+++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp
@@ -34,6 +34,7 @@
#include <logging/translator.h>
#include <tools/architectures.h>
#include <tools/fileinfo.h>
+#include <tools/toolchains.h>
#ifdef Q_OS_OSX
#include <tools/applecodesignutils.h>
@@ -55,6 +56,7 @@ class UtilitiesExtension : public QObject, QScriptable
public:
static QScriptValue js_ctor(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_canonicalArchitecture(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_canonicalToolchain(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_getHash(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_getNativeSetting(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_nativeSettingGroups(QScriptContext *context, QScriptEngine *engine);
@@ -72,6 +74,8 @@ void initializeJsExtensionUtilities(QScriptValue extensionObject)
engine->newFunction(&UtilitiesExtension::js_ctor));
environmentObj.setProperty(QStringLiteral("canonicalArchitecture"),
engine->newFunction(UtilitiesExtension::js_canonicalArchitecture, 1));
+ environmentObj.setProperty(QStringLiteral("canonicalToolchain"),
+ engine->newFunction(UtilitiesExtension::js_canonicalToolchain));
environmentObj.setProperty(QStringLiteral("getHash"),
engine->newFunction(UtilitiesExtension::js_getHash, 1));
environmentObj.setProperty(QStringLiteral("getNativeSetting"),
@@ -100,11 +104,24 @@ QScriptValue UtilitiesExtension::js_ctor(QScriptContext *context, QScriptEngine
QScriptValue UtilitiesExtension::js_canonicalArchitecture(QScriptContext *context,
QScriptEngine *engine)
{
- if (Q_UNLIKELY(context->argumentCount() != 1))
- return context->throwError(QScriptContext::SyntaxError,
- QLatin1String("canonicalArchitecture expects 1 argument"));
- const QString architecture = context->argument(0).toString();
- return engine->toScriptValue(canonicalArchitecture(architecture));
+ const QScriptValue value = context->argument(0);
+ if (value.isUndefined() || value.isNull())
+ return value;
+
+ if (context->argumentCount() == 1 && value.isString())
+ return engine->toScriptValue(canonicalArchitecture(value.toString()));
+
+ return context->throwError(QScriptContext::SyntaxError,
+ QStringLiteral("canonicalArchitecture expects one argument of type string"));
+}
+
+QScriptValue UtilitiesExtension::js_canonicalToolchain(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QStringList toolchain;
+ for (int i = 0; i < context->argumentCount(); ++i)
+ toolchain << context->argument(i).toString();
+ return engine->toScriptValue(canonicalToolchain(toolchain));
}
QScriptValue UtilitiesExtension::js_getHash(QScriptContext *context, QScriptEngine *engine)
diff --git a/src/lib/corelib/language/builtindeclarations.cpp b/src/lib/corelib/language/builtindeclarations.cpp
index cbe95c0ee..7c35cc163 100644
--- a/src/lib/corelib/language/builtindeclarations.cpp
+++ b/src/lib/corelib/language/builtindeclarations.cpp
@@ -428,6 +428,7 @@ void BuiltinDeclarations::addSubprojectItem()
void BuiltinDeclarations::addTransformerItem()
{
ItemDeclaration item(ItemType::Transformer);
+ item.setDeprecationInfo(DeprecationInfo(Version(1, 7), Tr::tr("Use the 'Rule' item instead.")));
item.setAllowedChildTypes(ItemDeclaration::TypeNames()
<< ItemType::Artifact);
item << conditionProperty();
diff --git a/src/lib/corelib/language/evaluator.cpp b/src/lib/corelib/language/evaluator.cpp
index 41be0d431..b87972320 100644
--- a/src/lib/corelib/language/evaluator.cpp
+++ b/src/lib/corelib/language/evaluator.cpp
@@ -36,6 +36,7 @@
#include "filetags.h"
#include "item.h"
#include "scriptengine.h"
+#include "value.h"
#include <jsextensions/jsextensions.h>
#include <logging/translator.h>
@@ -234,7 +235,7 @@ QScriptValue Evaluator::fileScope(const FileContextConstPtr &file)
result = m_scriptEngine->newObject();
result.setProperty(QLatin1String("filePath"), file->filePath());
result.setProperty(QLatin1String("path"), file->dirPath());
- m_scriptEngine->import(file, result, result);
+ m_scriptEngine->import(file, result);
JsExtensions::setupExtensions(file->jsExtensions(), result);
return result;
}
diff --git a/src/lib/corelib/language/evaluatorscriptclass.cpp b/src/lib/corelib/language/evaluatorscriptclass.cpp
index 451658876..bbfdf56a1 100644
--- a/src/lib/corelib/language/evaluatorscriptclass.cpp
+++ b/src/lib/corelib/language/evaluatorscriptclass.cpp
@@ -36,6 +36,7 @@
#include "item.h"
#include "scriptengine.h"
#include "propertydeclaration.h"
+#include "value.h"
#include <tools/architectures.h>
#include <tools/fileinfo.h>
#include <tools/hostosinfo.h>
@@ -261,11 +262,6 @@ private:
{
*result = scriptClass->engine()->toScriptValue(variantValue->value());
}
-
- void handle(BuiltinValue *builtinValue)
- {
- *result = scriptClass->scriptValueForBuiltin(builtinValue->builtin());
- }
};
bool debugProperties = false;
@@ -281,8 +277,6 @@ EvaluatorScriptClass::EvaluatorScriptClass(ScriptEngine *scriptEngine, const Log
, m_logger(logger)
, m_valueCacheEnabled(false)
{
- m_getEnvBuiltin = scriptEngine->newFunction(js_getEnvDeprecated, 1);
- m_currentEnvBuiltin = scriptEngine->newFunction(js_currentEnvDeprecated, 0);
}
QScriptClass::QueryFlags EvaluatorScriptClass::queryProperty(const QScriptValue &object,
@@ -512,63 +506,5 @@ void EvaluatorScriptClass::setValueCacheEnabled(bool enabled)
m_valueCacheEnabled = enabled;
}
-QScriptValue EvaluatorScriptClass::scriptValueForBuiltin(BuiltinValue::Builtin builtin) const
-{
- switch (builtin) {
- case BuiltinValue::GetEnvFunction:
- return m_getEnvBuiltin;
- case BuiltinValue::CurrentEnvFunction:
- return m_currentEnvBuiltin;
- }
- QBS_ASSERT(!"unhandled builtin", ;);
- return QScriptValue();
-}
-
-QScriptValue EvaluatorScriptClass::js_consoleError(QScriptContext *context, QScriptEngine *engine,
- Logger *logger)
-{
- if (Q_UNLIKELY(context->argumentCount() != 1))
- return context->throwError(QScriptContext::SyntaxError,
- QLatin1String("error expects 1 argument"));
- logger->qbsLog(LoggerError) << context->argument(0).toString();
- return engine->undefinedValue();
-}
-
-QScriptValue EvaluatorScriptClass::js_consoleWarn(QScriptContext *context, QScriptEngine *engine,
- Logger *logger)
-{
- if (Q_UNLIKELY(context->argumentCount() != 1))
- return context->throwError(QScriptContext::SyntaxError,
- QLatin1String("error expects 1 argument"));
- logger->qbsWarning() << context->argument(0).toString();
- return engine->undefinedValue();
-}
-
-QScriptValue EvaluatorScriptClass::js_consoleInfo(QScriptContext *context, QScriptEngine *engine,
- Logger *logger)
-{
- if (Q_UNLIKELY(context->argumentCount() != 1))
- return context->throwError(QScriptContext::SyntaxError,
- QLatin1String("error expects 1 argument"));
- logger->qbsInfo() << context->argument(0).toString();
- return engine->undefinedValue();
-}
-
-QScriptValue EvaluatorScriptClass::js_consoleDebug(QScriptContext *context, QScriptEngine *engine,
- Logger *logger)
-{
- if (Q_UNLIKELY(context->argumentCount() != 1))
- return context->throwError(QScriptContext::SyntaxError,
- QLatin1String("error expects 1 argument"));
- logger->qbsDebug() << context->argument(0).toString();
- return engine->undefinedValue();
-}
-
-QScriptValue EvaluatorScriptClass::js_consoleLog(QScriptContext *context, QScriptEngine *engine,
- Logger *logger)
-{
- return js_consoleDebug(context, engine, logger);
-}
-
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/evaluatorscriptclass.h b/src/lib/corelib/language/evaluatorscriptclass.h
index 3816633b1..04cb77b81 100644
--- a/src/lib/corelib/language/evaluatorscriptclass.h
+++ b/src/lib/corelib/language/evaluatorscriptclass.h
@@ -31,13 +31,13 @@
#ifndef QBS_EVALUATORSCRIPTCLASS_H
#define QBS_EVALUATORSCRIPTCLASS_H
-#include "builtinvalue.h"
#include "forward_decls.h"
#include <logging/logger.h>
#include <QScriptClass>
#include <QStack>
+#include <QSet>
QT_BEGIN_NAMESPACE
class QScriptContext;
@@ -46,6 +46,7 @@ QT_END_NAMESPACE
namespace qbs {
namespace Internal {
class EvaluationData;
+class Item;
class ScriptEngine;
class EvaluatorScriptClass : public QScriptClass
@@ -60,18 +61,6 @@ public:
const QScriptString &name, uint id);
void setValueCacheEnabled(bool enabled);
- QScriptValue scriptValueForBuiltin(BuiltinValue::Builtin builtin) const;
-
- static QScriptValue js_consoleError(QScriptContext *context, QScriptEngine *engine,
- Logger *logger);
- static QScriptValue js_consoleWarn(QScriptContext *context, QScriptEngine *engine,
- Logger *logger);
- static QScriptValue js_consoleInfo(QScriptContext *context, QScriptEngine *engine,
- Logger *logger);
- static QScriptValue js_consoleDebug(QScriptContext *context, QScriptEngine *engine,
- Logger *logger);
- static QScriptValue js_consoleLog(QScriptContext *context, QScriptEngine *engine,
- Logger *logger);
private:
QueryFlags queryItemProperty(const EvaluationData *data,
@@ -98,8 +87,6 @@ private:
QueryResult m_queryResult;
Logger m_logger;
bool m_valueCacheEnabled;
- QScriptValue m_getEnvBuiltin;
- QScriptValue m_currentEnvBuiltin;
QStack<JSSourceValue *> m_sourceValueStack;
QSet<Value *> m_currentNextChain;
};
diff --git a/src/lib/corelib/language/forward_decls.h b/src/lib/corelib/language/forward_decls.h
index 4abedf89e..3ae74fc99 100644
--- a/src/lib/corelib/language/forward_decls.h
+++ b/src/lib/corelib/language/forward_decls.h
@@ -51,10 +51,6 @@ class VariantValue;
typedef QSharedPointer<VariantValue> VariantValuePtr;
typedef QSharedPointer<const VariantValue> VariantValueConstPtr;
-class BuiltinValue;
-typedef QSharedPointer<BuiltinValue> BuiltinValuePtr;
-typedef QSharedPointer<const BuiltinValue> BuiltinValueConstPtr;
-
class FileContext;
typedef QSharedPointer<FileContext> FileContextPtr;
typedef QSharedPointer<const FileContext> FileContextConstPtr;
diff --git a/src/lib/corelib/language/item.cpp b/src/lib/corelib/language/item.cpp
index e63ef7233..891252f48 100644
--- a/src/lib/corelib/language/item.cpp
+++ b/src/lib/corelib/language/item.cpp
@@ -241,7 +241,6 @@ static const char *valueType(const Value *v)
case Value::JSSourceValueType: return "JS source";
case Value::ItemValueType: return "Item";
case Value::VariantValueType: return "Variant";
- case Value::BuiltinValueType: return "Built-in";
}
return ""; // For dumb compilers.
}
@@ -269,8 +268,6 @@ void Item::dump(int indentation) const
qDebug("%svalue: %s", nextIndent.constData(),
qPrintable(it.value().staticCast<VariantValue>()->value().toString()));
break;
- case Value::BuiltinValueType:
- break;
}
}
if (!m_children.isEmpty())
diff --git a/src/lib/corelib/language/itemdeclaration.cpp b/src/lib/corelib/language/itemdeclaration.cpp
index 4a5837f3a..e1fa662ec 100644
--- a/src/lib/corelib/language/itemdeclaration.cpp
+++ b/src/lib/corelib/language/itemdeclaration.cpp
@@ -38,13 +38,6 @@ ItemDeclaration::ItemDeclaration(ItemType type)
{
}
-ItemDeclaration::ItemDeclaration(const qbs::Internal::ItemDeclaration &other)
- : m_type(other.m_type)
- , m_properties(other.m_properties)
- , m_allowedChildTypes(other.m_allowedChildTypes)
-{
-}
-
ItemDeclaration &ItemDeclaration::operator<<(const PropertyDeclaration &decl)
{
m_properties.append(decl);
diff --git a/src/lib/corelib/language/itemdeclaration.h b/src/lib/corelib/language/itemdeclaration.h
index 8e9ab933d..98bc583d4 100644
--- a/src/lib/corelib/language/itemdeclaration.h
+++ b/src/lib/corelib/language/itemdeclaration.h
@@ -31,6 +31,7 @@
#ifndef QBS_ITEMDECLARATION_H
#define QBS_ITEMDECLARATION_H
+#include "deprecationinfo.h"
#include "itemtype.h"
#include "propertydeclaration.h"
@@ -44,7 +45,6 @@ class ItemDeclaration
{
public:
ItemDeclaration(ItemType type = ItemType::Unknown);
- ItemDeclaration(const ItemDeclaration &other);
ItemType type() const { return m_type; }
@@ -52,6 +52,9 @@ public:
void setProperties(const Properties &props) { m_properties = props; }
const Properties &properties() const { return m_properties; }
+ void setDeprecationInfo(const DeprecationInfo &di) { m_deprecationInfo = di; }
+ DeprecationInfo deprecationInfo() const { return m_deprecationInfo; }
+
ItemDeclaration &operator<<(const PropertyDeclaration &decl);
typedef QSet<ItemType> TypeNames;
@@ -63,6 +66,7 @@ private:
ItemType m_type;
Properties m_properties;
TypeNames m_allowedChildTypes;
+ DeprecationInfo m_deprecationInfo;
};
} // namespace Internal
diff --git a/src/lib/corelib/language/itemreaderastvisitor.cpp b/src/lib/corelib/language/itemreaderastvisitor.cpp
index e68bd897b..b7b86b002 100644
--- a/src/lib/corelib/language/itemreaderastvisitor.cpp
+++ b/src/lib/corelib/language/itemreaderastvisitor.cpp
@@ -96,7 +96,10 @@ bool ItemReaderASTVisitor::visit(AST::UiObjectDefinition *ast)
QBS_CHECK(inheritorItem->type() <= ItemType::LastActualItem);
item->setType(inheritorItem->type());
} else {
- item->setType(BuiltinDeclarations::instance().typeForName(typeName, item->location()));
+ const ItemType itemType
+ = BuiltinDeclarations::instance().typeForName(typeName, item->location());
+ checkDeprecationStatus(itemType, typeName, item->location());
+ item->setType(itemType);
if (item->type() == ItemType::Properties && item->parent()
&& item->parent()->type() == ItemType::SubProject) {
item->setType(ItemType::PropertiesInSubProject);
@@ -320,5 +323,29 @@ void ItemReaderASTVisitor::inheritItem(Item *dst, const Item *src)
}
}
+void ItemReaderASTVisitor::checkDeprecationStatus(ItemType itemType, const QString &itemName,
+ const CodeLocation &itemLocation)
+{
+ const ItemDeclaration itemDecl = BuiltinDeclarations::instance().declarationsForType(itemType);
+ const DeprecationInfo &di = itemDecl.deprecationInfo();
+ if (!di.isValid())
+ return;
+ if (di.removalVersion() <= Version::qbsVersion()) {
+ QString message = Tr::tr("The item '%1' cannot be used anymore. "
+ "It was removed in qbs %2.")
+ .arg(itemName, di.removalVersion().toString());
+ ErrorInfo error(message, itemLocation);
+ if (!di.additionalUserInfo().isEmpty())
+ error.append(di.additionalUserInfo());
+ throw error;
+ }
+ QString warning = Tr::tr("The item '%1' is deprecated and will be removed in "
+ "qbs %2.").arg(itemName, di.removalVersion().toString());
+ ErrorInfo error(warning, itemLocation);
+ if (!di.additionalUserInfo().isEmpty())
+ error.append(di.additionalUserInfo());
+ m_logger.printWarning(error);
+}
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/itemreaderastvisitor.h b/src/lib/corelib/language/itemreaderastvisitor.h
index 1c32e2ee6..9c6a4fcc2 100644
--- a/src/lib/corelib/language/itemreaderastvisitor.h
+++ b/src/lib/corelib/language/itemreaderastvisitor.h
@@ -32,6 +32,7 @@
#define QBS_ITEMREADERASTVISITOR_H
#include "forward_decls.h"
+#include "itemtype.h"
#include <logging/logger.h>
#include <parser/qmljsastvisitor_p.h>
@@ -68,6 +69,8 @@ private:
const QbsQmlJS::AST::SourceLocation &sourceLocation);
Item *targetItemForBinding(const QStringList &binding, const JSSourceValueConstPtr &value);
static void inheritItem(Item *dst, const Item *src);
+ void checkDeprecationStatus(ItemType itemType, const QString &itemName,
+ const CodeLocation &itemLocation);
ItemReaderVisitorState &m_visitorState;
const FileContextPtr m_file;
diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp
index 221cb7fd7..dbb1ec694 100644
--- a/src/lib/corelib/language/language.cpp
+++ b/src/lib/corelib/language/language.cpp
@@ -48,6 +48,7 @@
#include <tools/error.h>
#include <tools/fileinfo.h>
#include <tools/persistence.h>
+#include <tools/scripttools.h>
#include <tools/qbsassert.h>
#include <QCryptographicHash>
@@ -371,6 +372,11 @@ bool Rule::isDynamic() const
return outputArtifactsScript->isValid();
}
+bool Rule::requiresInputs() const
+{
+ return !inputs.isEmpty() || !inputsFromDependencies.isEmpty();
+}
+
void Rule::load(PersistentPool &pool)
{
name = pool.idLoadString();
@@ -596,6 +602,8 @@ static QProcessEnvironment getProcessEnvironment(ScriptEngine *engine, EnvType e
}
QScriptValue scope = engine->newObject();
+ scope.setPrototype(engine->globalObject());
+ TemporaryGlobalObjectSetter tgos(scope);
QSet<QString> seenModuleNames;
QList<const ResolvedModule *> topSortedModules = topSortModules(moduleChildren, rootModules, seenModuleNames);
@@ -616,7 +624,7 @@ static QProcessEnvironment getProcessEnvironment(ScriptEngine *engine, EnvType e
}
// handle imports
- engine->import(setupScript->fileContext, scope, scope);
+ engine->import(setupScript->fileContext, scope);
JsExtensions::setupExtensions(setupScript->fileContext->jsExtensions(), scope);
// expose properties of direct module dependencies
@@ -636,10 +644,7 @@ static QProcessEnvironment getProcessEnvironment(ScriptEngine *engine, EnvType e
for (QVariantMap::const_iterator it = moduleCfg.constBegin(); it != moduleCfg.constEnd(); ++it)
scope.setProperty(it.key(), engine->toScriptValue(it.value()));
- QScriptContext *ctx = engine->currentContext();
- ctx->pushScope(scope);
scriptValue = engine->evaluate(setupScript->sourceCode + QLatin1String("()"));
- ctx->popScope();
if (Q_UNLIKELY(engine->hasErrorOrException(scriptValue))) {
QString envTypeStr = (envType == BuildEnv
? QLatin1String("build") : QLatin1String("run"));
@@ -744,7 +749,7 @@ QString ResolvedProduct::uniqueName() const
static QStringList findGeneratedFiles(const Artifact *base, bool recursive, const FileTags &tags)
{
QStringList result;
- foreach (const Artifact *parent, base->parentArtifacts()) {
+ for (const Artifact *parent : base->parentArtifacts()) {
if (tags.isEmpty() || parent->fileTags().matches(tags))
result << parent->filePath();
if (recursive)
@@ -760,7 +765,7 @@ QStringList ResolvedProduct::generatedFiles(const QString &baseFile, bool recurs
if (!data)
return QStringList();
- foreach (const Artifact *art, ArtifactSet::fromNodeSet(data->nodes)) {
+ for (const Artifact *art : filterByType<Artifact>(data->nodes)) {
if (art->filePath() == baseFile)
return findGeneratedFiles(art, recursive, tags);
}
@@ -1179,7 +1184,16 @@ template<typename T> bool listsAreEqual(const QList<T> &l1, const QList<T> &l2)
QString keyFromElem(const SourceArtifactPtr &sa) { return sa->absoluteFilePath; }
QString keyFromElem(const ResolvedTransformerPtr &t) { return t->transform->sourceCode; }
-QString keyFromElem(const RulePtr &r) { return r->toString(); }
+QString keyFromElem(const RulePtr &r) {
+ QString key = r->toString() + r->prepareScript->sourceCode;
+ if (r->outputArtifactsScript)
+ key += r->outputArtifactsScript->sourceCode;
+ foreach (const auto &a, r->artifacts) {
+ key += a->filePath;
+ }
+ return key;
+}
+
QString keyFromElem(const ArtifactPropertiesPtr &ap)
{
QStringList lst = ap->fileTagsFilter().toStringList();
diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h
index 12e3ef9e9..f909f9fa2 100644
--- a/src/lib/corelib/language/language.h
+++ b/src/lib/corelib/language/language.h
@@ -284,6 +284,7 @@ public:
FileTags staticOutputFileTags() const;
FileTags collectedOutputFileTags() const;
bool isDynamic() const;
+ bool requiresInputs() const;
private:
Rule() : multiplex(false), alwaysRun(false), ruleGraphId(-1) {}
@@ -294,6 +295,7 @@ bool operator==(const Rule &r1, const Rule &r2);
inline bool operator!=(const Rule &r1, const Rule &r2) { return !(r1 == r2); }
bool ruleListsAreEqual(const QList<RulePtr> &l1, const QList<RulePtr> &l2);
+// TODO: Remove this and all related code in 1.7.
class ResolvedTransformer : public PersistentObject
{
public:
diff --git a/src/lib/corelib/language/language.pri b/src/lib/corelib/language/language.pri
index 28da484e1..ca8fad22c 100644
--- a/src/lib/corelib/language/language.pri
+++ b/src/lib/corelib/language/language.pri
@@ -6,7 +6,6 @@ HEADERS += \
$$PWD/astpropertiesitemhandler.h \
$$PWD/asttools.h \
$$PWD/builtindeclarations.h \
- $$PWD/builtinvalue.h \
$$PWD/deprecationinfo.h \
$$PWD/evaluationdata.h \
$$PWD/evaluator.h \
@@ -38,6 +37,7 @@ HEADERS += \
$$PWD/qualifiedid.h \
$$PWD/resolvedfilecontext.h \
$$PWD/scriptengine.h \
+ $$PWD/scriptimporter.h \
$$PWD/scriptpropertyobserver.h \
$$PWD/value.h
@@ -47,7 +47,6 @@ SOURCES += \
$$PWD/astpropertiesitemhandler.cpp \
$$PWD/asttools.cpp \
$$PWD/builtindeclarations.cpp \
- $$PWD/builtinvalue.cpp \
$$PWD/evaluator.cpp \
$$PWD/evaluatorscriptclass.cpp \
$$PWD/filecontext.cpp \
@@ -66,11 +65,13 @@ SOURCES += \
$$PWD/modulemerger.cpp \
$$PWD/preparescriptobserver.cpp \
$$PWD/projectresolver.cpp \
+ $$PWD/property.cpp \
$$PWD/propertydeclaration.cpp \
$$PWD/propertymapinternal.cpp \
$$PWD/qualifiedid.cpp \
$$PWD/resolvedfilecontext.cpp \
$$PWD/scriptengine.cpp \
+ $$PWD/scriptimporter.cpp \
$$PWD/value.cpp
qbs_enable_unit_tests {
diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp
index 0febedcdf..77f88694a 100644
--- a/src/lib/corelib/language/moduleloader.cpp
+++ b/src/lib/corelib/language/moduleloader.cpp
@@ -31,7 +31,6 @@
#include "moduleloader.h"
#include "builtindeclarations.h"
-#include "builtinvalue.h"
#include "evaluator.h"
#include "filecontext.h"
#include "item.h"
@@ -301,7 +300,6 @@ private:
}
void handle(VariantValue *) { /* only created internally - no need to check */ }
- void handle(BuiltinValue *) { /* only created internally - no need to check */ }
};
void ModuleLoader::handleTopLevelProject(ModuleLoaderResult *loadResult, Item *projectItem,
@@ -1415,11 +1413,6 @@ static QStringList hostOS()
void ModuleLoader::setupBaseModulePrototype(Item *prototype)
{
- prototype->setProperty(QLatin1String("getEnv"),
- BuiltinValue::create(BuiltinValue::GetEnvFunction));
- prototype->setProperty(QLatin1String("currentEnv"),
- BuiltinValue::create(BuiltinValue::CurrentEnvFunction));
-
prototype->setProperty(QLatin1String("hostOS"), VariantValue::create(hostOS()));
prototype->setProperty(QLatin1String("libexecPath"),
VariantValue::create(m_parameters.libexecPath()));
diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp
index 27a6b9a80..927f174a0 100644
--- a/src/lib/corelib/language/projectresolver.cpp
+++ b/src/lib/corelib/language/projectresolver.cpp
@@ -712,6 +712,14 @@ 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);
+ return;
+ }
if (m_productContext)
m_productContext->product->rules += rule;
else
@@ -1125,9 +1133,6 @@ QVariantMap ProjectResolver::evaluateProperties(Item *item, Item *propertiesCont
result[it.key()] = vvp->value();
break;
}
- case Value::BuiltinValueType:
- // ignore
- break;
}
}
return lookupPrototype && propertiesContainer->prototype()
diff --git a/src/lib/corelib/language/property.cpp b/src/lib/corelib/language/property.cpp
new file mode 100644
index 000000000..a374d9d8f
--- /dev/null
+++ b/src/lib/corelib/language/property.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#include "property.h"
+
+#include <tools/persistence.h>
+
+namespace qbs {
+namespace Internal {
+
+void storePropertySet(PersistentPool &pool, const PropertySet &propertySet)
+{
+ pool.stream() << propertySet.count();
+ foreach (const Property &p, propertySet) {
+ pool.storeString(p.moduleName);
+ pool.storeString(p.propertyName);
+ pool.stream() << p.value << static_cast<int>(p.kind);
+ }
+}
+
+PropertySet restorePropertySet(PersistentPool &pool)
+{
+ int count;
+ pool.stream() >> count;
+ PropertySet propertySet;
+ propertySet.reserve(count);
+ while (--count >= 0) {
+ Property p;
+ p.moduleName = pool.idLoadString();
+ p.propertyName = pool.idLoadString();
+ int k;
+ pool.stream() >> p.value >> k;
+ p.kind = static_cast<Property::Kind>(k);
+ propertySet += p;
+ }
+ return propertySet;
+}
+
+void storePropertyHash(PersistentPool &pool, const PropertyHash &propertyHash)
+{
+ pool.stream() << propertyHash.count();
+ for (auto it = propertyHash.constBegin(); it != propertyHash.constEnd(); ++it) {
+ pool.storeString(it.key());
+ const PropertySet &properties = it.value();
+ pool.stream() << properties.count();
+ foreach (const Property &p, properties) {
+ pool.storeString(p.moduleName);
+ pool.storeString(p.propertyName);
+ pool.stream() << p.value; // kind is always PropertyInModule
+ }
+ }
+}
+
+PropertyHash restorePropertyHash(PersistentPool &pool)
+{
+ int count;
+ pool.stream() >> count;
+ PropertyHash propertyHash;
+ propertyHash.reserve(count);
+ while (--count >= 0) {
+ const QString artifactName = pool.idLoadString();
+ int listCount;
+ pool.stream() >> listCount;
+ PropertySet list;
+ list.reserve(listCount);
+ while (--listCount >= 0) {
+ Property p;
+ p.moduleName = pool.idLoadString();
+ p.propertyName = pool.idLoadString();
+ pool.stream() >> p.value;
+ p.kind = Property::PropertyInModule;
+ list += p;
+ }
+ propertyHash.insert(artifactName, list);
+ }
+ return propertyHash;
+}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/lib/corelib/language/property.h b/src/lib/corelib/language/property.h
index 8960369e9..cbdb6c6a5 100644
--- a/src/lib/corelib/language/property.h
+++ b/src/lib/corelib/language/property.h
@@ -36,6 +36,7 @@
namespace qbs {
namespace Internal {
+class PersistentPool;
class Property
{
@@ -74,6 +75,12 @@ inline uint qHash(const Property &p)
}
typedef QSet<Property> PropertySet;
+typedef QHash<QString, PropertySet> PropertyHash;
+
+void storePropertySet(PersistentPool &pool, const PropertySet &list);
+PropertySet restorePropertySet(PersistentPool &pool);
+void storePropertyHash(PersistentPool &pool, const PropertyHash &propertyHash);
+PropertyHash restorePropertyHash(PersistentPool &pool);
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/scriptengine.cpp b/src/lib/corelib/language/scriptengine.cpp
index a6a4419e3..f6ca2b116 100644
--- a/src/lib/corelib/language/scriptengine.cpp
+++ b/src/lib/corelib/language/scriptengine.cpp
@@ -30,10 +30,10 @@
#include "scriptengine.h"
-#include "evaluatorscriptclass.h"
#include "filecontextbase.h"
#include "jsimports.h"
#include "propertymapinternal.h"
+#include "scriptimporter.h"
#include "scriptpropertyobserver.h"
#include <buildgraph/artifact.h>
@@ -47,10 +47,10 @@
#include <QDirIterator>
#include <QFile>
#include <QFileInfo>
-#include <QScriptProgram>
#include <QScriptValueIterator>
#include <QSet>
#include <QTextStream>
+#include <QTimer>
namespace qbs {
namespace Internal {
@@ -81,7 +81,8 @@ uint qHash(const ScriptEngine::PropertyCacheKey &k, uint seed = 0)
}
ScriptEngine::ScriptEngine(const Logger &logger, QObject *parent)
- : QScriptEngine(parent), m_propertyCacheEnabled(true), m_logger(logger)
+ : QScriptEngine(parent), m_scriptImporter(new ScriptImporter(this)),
+ m_propertyCacheEnabled(true), m_logger(logger)
{
setProcessEventsInterval(1000); // For the cancelation mechanism to work.
m_cancelationError = currentContext()->throwValue(tr("Execution canceled"));
@@ -99,10 +100,10 @@ ScriptEngine::ScriptEngine(const Logger &logger, QObject *parent)
ScriptEngine::~ScriptEngine()
{
qDeleteAll(m_ownedVariantMaps);
+ delete (m_scriptImporter);
}
-void ScriptEngine::import(const FileContextBaseConstPtr &fileCtx, QScriptValue scope,
- QScriptValue targetObject)
+void ScriptEngine::import(const FileContextBaseConstPtr &fileCtx, QScriptValue &targetObject)
{
installImportFunctions();
m_currentDirPathStack.push(FileInfo::path(fileCtx->filePath()));
@@ -110,7 +111,7 @@ void ScriptEngine::import(const FileContextBaseConstPtr &fileCtx, QScriptValue s
const JsImports jsImports = fileCtx->jsImports();
for (JsImports::const_iterator it = jsImports.begin(); it != jsImports.end(); ++it) {
- import(*it, scope, targetObject);
+ import(*it, targetObject);
}
m_currentDirPathStack.pop();
@@ -118,9 +119,8 @@ void ScriptEngine::import(const FileContextBaseConstPtr &fileCtx, QScriptValue s
uninstallImportFunctions();
}
-void ScriptEngine::import(const JsImport &jsImport, QScriptValue scope, QScriptValue targetObject)
+void ScriptEngine::import(const JsImport &jsImport, QScriptValue &targetObject)
{
- QBS_ASSERT(!scope.isValid() || scope.isObject(), return);
QBS_ASSERT(targetObject.isObject(), return);
QBS_ASSERT(targetObject.engine() == this, return);
@@ -134,8 +134,9 @@ void ScriptEngine::import(const JsImport &jsImport, QScriptValue scope, QScriptV
} else {
if (debugJSImports)
qDebug() << "[ENGINE] " << jsImport.filePaths << " (cache miss)";
+ jsImportValue = newObject();
foreach (const QString &filePath, jsImport.filePaths)
- importFile(filePath, scope, &jsImportValue);
+ importFile(filePath, jsImportValue);
m_jsImportCache.insert(jsImport, jsImportValue);
}
targetObject.setProperty(jsImport.scopeName, jsImportValue);
@@ -235,83 +236,16 @@ void ScriptEngine::setEnvironment(const QProcessEnvironment &env)
m_environment = env;
}
-QScriptValue ScriptEngine::importFile(const QString &filePath, const QScriptValue &scope,
- QScriptValue *targetObject)
+void ScriptEngine::importFile(const QString &filePath, QScriptValue &targetObject)
{
QFile file(filePath);
if (Q_UNLIKELY(!file.open(QFile::ReadOnly)))
throw ErrorInfo(tr("Cannot open '%1'.").arg(filePath));
const QString sourceCode = QTextStream(&file).readAll();
file.close();
- QScriptProgram program(sourceCode, filePath);
- QScriptValue obj;
- if (!targetObject)
- obj = newObject();
m_currentDirPathStack.push(FileInfo::path(filePath));
- importProgram(program, scope, targetObject ? *targetObject : obj);
+ m_scriptImporter->importSourceCode(sourceCode, filePath, targetObject);
m_currentDirPathStack.pop();
- return targetObject ? *targetObject : obj;
-}
-
-void ScriptEngine::importProgram(const QScriptProgram &program, const QScriptValue &scope,
- QScriptValue &targetObject)
-{
- QSet<QString> globalPropertyNames;
- {
- QScriptValueIterator it(globalObject());
- while (it.hasNext()) {
- it.next();
- globalPropertyNames += it.name();
- }
- }
-
- pushContext();
- if (scope.isObject())
- currentContext()->pushScope(scope);
- QScriptValue result = evaluate(program);
- QScriptValue activationObject = currentContext()->activationObject();
- if (scope.isObject())
- currentContext()->popScope();
- popContext();
- if (Q_UNLIKELY(hasErrorOrException(result)))
- throw ErrorInfo(tr("Error when importing '%1': %2").arg(program.fileName(), result.toString()));
-
- // If targetObject is already an object, it doesn't get overwritten but enhanced by the
- // contents of the .js file.
- // This is necessary for library imports that consist of multiple js files.
- if (!targetObject.isObject())
- targetObject = newObject();
-
- // Copy every property of the activation object to the target object.
- // We do not just save a reference to the activation object, because QScriptEngine contains
- // special magic for activation objects that leads to unanticipated results.
- {
- QScriptValueIterator it(activationObject);
- while (it.hasNext()) {
- it.next();
- if (debugJSImports)
- qDebug() << "[ENGINE] Copying property " << it.name();
- targetObject.setProperty(it.name(), it.value());
- }
- }
-
- // Copy new global properties to the target object and remove them from
- // the global object. This is to support direct variable assignments
- // without the 'var' keyword in JavaScript files.
- QScriptValueIterator it(globalObject());
- while (it.hasNext()) {
- it.next();
- if (globalPropertyNames.contains(it.name()))
- continue;
-
- if (debugJSImports) {
- qDebug() << "[ENGINE] inserting global property "
- << it.name() << " " << it.value().toString();
- }
-
- targetObject.setProperty(it.name(), it.value());
- it.remove();
- }
}
static QString findExtensionDir(const QStringList &searchPaths, const QString &extensionPath)
@@ -396,7 +330,9 @@ QScriptValue ScriptEngine::js_loadExtension(QScriptContext *context, QScriptEngi
engine->m_logger.qbsDebug()
<< "[loadExtension] importing file " << filePath;
}
- values << engine->importFile(filePath, QScriptValue());
+ QScriptValue obj = engine->newObject();
+ engine->importFile(filePath, obj);
+ values << obj;
}
} catch (const ErrorInfo &e) {
return context->throwError(e.toString());
@@ -423,7 +359,8 @@ QScriptValue ScriptEngine::js_loadFile(QScriptContext *context, QScriptEngine *q
try {
const QString filePath = FileInfo::resolvePath(engine->m_currentDirPathStack.top(),
relativeFilePath);
- result = engine->importFile(filePath, QScriptValue());
+ result = engine->newObject();
+ engine->importFile(filePath, result);
} catch (const ErrorInfo &e) {
result = context->throwError(e.toString());
}
@@ -480,7 +417,7 @@ QScriptValueList ScriptEngine::argumentList(const QStringList &argumentNames,
void ScriptEngine::cancel()
{
- QMetaObject::invokeMethod(this, "abort", Qt::QueuedConnection);
+ QTimer::singleShot(0, this, [this] { abort(); });
}
void ScriptEngine::abort()
@@ -514,28 +451,62 @@ private:
QScriptValue m_descriptor;
};
+static QScriptValue js_consoleError(QScriptContext *context, QScriptEngine *engine, Logger *logger)
+{
+ if (Q_UNLIKELY(context->argumentCount() != 1))
+ return context->throwError(QScriptContext::SyntaxError,
+ QLatin1String("error expects 1 argument"));
+ logger->qbsLog(LoggerError) << context->argument(0).toString();
+ return engine->undefinedValue();
+}
+
+static QScriptValue js_consoleWarn(QScriptContext *context, QScriptEngine *engine, Logger *logger)
+{
+ if (Q_UNLIKELY(context->argumentCount() != 1))
+ return context->throwError(QScriptContext::SyntaxError,
+ QLatin1String("error expects 1 argument"));
+ logger->qbsWarning() << context->argument(0).toString();
+ return engine->undefinedValue();
+}
+
+static QScriptValue js_consoleInfo(QScriptContext *context, QScriptEngine *engine, Logger *logger)
+{
+ if (Q_UNLIKELY(context->argumentCount() != 1))
+ return context->throwError(QScriptContext::SyntaxError,
+ QLatin1String("error expects 1 argument"));
+ logger->qbsInfo() << context->argument(0).toString();
+ return engine->undefinedValue();
+}
+
+static QScriptValue js_consoleDebug(QScriptContext *context, QScriptEngine *engine, Logger *logger)
+{
+ if (Q_UNLIKELY(context->argumentCount() != 1))
+ return context->throwError(QScriptContext::SyntaxError,
+ QLatin1String("error expects 1 argument"));
+ logger->qbsDebug() << context->argument(0).toString();
+ return engine->undefinedValue();
+}
+
+static QScriptValue js_consoleLog(QScriptContext *context, QScriptEngine *engine, Logger *logger)
+{
+ return js_consoleDebug(context, engine, logger);
+}
+
void ScriptEngine::installQbsBuiltins()
{
globalObject().setProperty(QLatin1String("qbs"), m_qbsObject = newObject());
- installQbsFunction(QLatin1String("getEnv"), 1, js_getEnvDeprecated);
- installQbsFunction(QLatin1String("currentEnv"), 0, js_currentEnvDeprecated);
globalObject().setProperty(QLatin1String("console"), m_consoleObject = newObject());
installConsoleFunction(QLatin1String("debug"),
- reinterpret_cast<FunctionWithArgSignature>(
- EvaluatorScriptClass::js_consoleDebug));
+ reinterpret_cast<FunctionWithArgSignature>(&js_consoleDebug));
installConsoleFunction(QLatin1String("error"),
- reinterpret_cast<FunctionWithArgSignature>(
- EvaluatorScriptClass::js_consoleError));
+ reinterpret_cast<FunctionWithArgSignature>(&js_consoleError));
installConsoleFunction(QLatin1String("info"),
- reinterpret_cast<FunctionWithArgSignature>(
- EvaluatorScriptClass::js_consoleInfo));
+ reinterpret_cast<FunctionWithArgSignature>(&js_consoleInfo));
installConsoleFunction(QLatin1String("log"),
- reinterpret_cast<FunctionWithArgSignature>(
- EvaluatorScriptClass::js_consoleLog));
+ reinterpret_cast<FunctionWithArgSignature>(&js_consoleLog));
installConsoleFunction(QLatin1String("warn"),
- reinterpret_cast<FunctionWithArgSignature>(
- EvaluatorScriptClass::js_consoleWarn));
+ reinterpret_cast<FunctionWithArgSignature>(&js_consoleWarn));
}
void ScriptEngine::extendJavaScriptBuiltins()
diff --git a/src/lib/corelib/language/scriptengine.h b/src/lib/corelib/language/scriptengine.h
index 5e943f25f..acf8e8d71 100644
--- a/src/lib/corelib/language/scriptengine.h
+++ b/src/lib/corelib/language/scriptengine.h
@@ -48,6 +48,7 @@ namespace qbs {
namespace Internal {
class Artifact;
class JsImport;
+class ScriptImporter;
class ScriptPropertyObserver;
class ScriptEngine : public QScriptEngine
@@ -59,9 +60,8 @@ public:
void setLogger(const Logger &logger) { m_logger = logger; }
Logger logger() const { return m_logger; }
- void import(const FileContextBaseConstPtr &fileCtx, QScriptValue scope,
- QScriptValue targetObject);
- void import(const JsImport &jsImport, QScriptValue scope, QScriptValue targetObject);
+ void import(const FileContextBaseConstPtr &fileCtx, QScriptValue &targetObject);
+ void import(const JsImport &jsImport, QScriptValue &targetObject);
void clearImportsCache();
void addPropertyRequestedInScript(const Property &property) {
@@ -126,7 +126,7 @@ public:
void cancel();
private:
- Q_INVOKABLE void abort();
+ void abort();
void installQbsBuiltins();
void extendJavaScriptBuiltins();
@@ -136,10 +136,7 @@ private:
void installConsoleFunction(const QString &name, FunctionWithArgSignature f);
void installImportFunctions();
void uninstallImportFunctions();
- QScriptValue importFile(const QString &filePath, const QScriptValue &scope,
- QScriptValue *targetObject = nullptr);
- void importProgram(const QScriptProgram &program, const QScriptValue &scope,
- QScriptValue &targetObject);
+ void importFile(const QString &filePath, QScriptValue &targetObject);
static QScriptValue js_loadExtension(QScriptContext *context, QScriptEngine *qtengine);
static QScriptValue js_loadFile(QScriptContext *context, QScriptEngine *qtengine);
@@ -161,6 +158,7 @@ private:
friend bool operator==(const PropertyCacheKey &lhs, const PropertyCacheKey &rhs);
friend uint qHash(const ScriptEngine::PropertyCacheKey &k, uint seed);
+ ScriptImporter *m_scriptImporter;
QHash<JsImport, QScriptValue> m_jsImportCache;
bool m_propertyCacheEnabled;
QHash<PropertyCacheKey, QVariant> m_propertyCache;
diff --git a/src/lib/corelib/language/scriptimporter.cpp b/src/lib/corelib/language/scriptimporter.cpp
new file mode 100644
index 000000000..62577b343
--- /dev/null
+++ b/src/lib/corelib/language/scriptimporter.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#include "scriptimporter.h"
+
+#include <parser/qmljsastfwd_p.h>
+#include <parser/qmljsastvisitor_p.h>
+#include <parser/qmljslexer_p.h>
+#include <parser/qmljsparser_p.h>
+#include <tools/error.h>
+
+#include <QScriptValueIterator>
+
+namespace qbs {
+namespace Internal {
+
+class IdentifierExtractor : private QbsQmlJS::AST::Visitor
+{
+public:
+ void start(QbsQmlJS::AST::Node *node)
+ {
+ m_first = true;
+ m_barrier = false;
+ m_suffix += QLatin1String("\nreturn {");
+ node->accept(this);
+ m_suffix += QLatin1String("}})()");
+ }
+
+ const QString &suffix() const { return m_suffix; }
+
+private:
+ bool visit(QbsQmlJS::AST::SourceElements *) override
+ {
+ // Only consider the top level of source elements.
+ if (m_barrier)
+ return false;
+ m_barrier = true;
+ return true;
+ }
+
+ void endVisit(QbsQmlJS::AST::SourceElements *) override
+ {
+ m_barrier = false;
+ }
+
+ bool visit(QbsQmlJS::AST::FunctionSourceElement *fse) override
+ {
+ add(fse->declaration->name);
+ return false;
+ }
+
+ bool visit(QbsQmlJS::AST::VariableDeclaration *vd) override
+ {
+ add(vd->name);
+ return false;
+ }
+
+ void add(const QStringRef &name)
+ {
+ if (m_first) {
+ m_first = false;
+ m_suffix.reserve(m_suffix.length() + name.length() * 2 + 1);
+ } else {
+ m_suffix.reserve(m_suffix.length() + name.length() * 2 + 2);
+ m_suffix += QLatin1Char(',');
+ }
+ m_suffix += name;
+ m_suffix += QLatin1Char(':');
+ m_suffix += name;
+ }
+
+ bool m_first;
+ bool m_barrier;
+ QString m_suffix;
+};
+
+
+ScriptImporter::ScriptImporter(QScriptEngine *scriptEngine)
+ : m_engine(scriptEngine)
+{
+}
+
+// ### merge with Evaluator::handleEvaluationError
+static ErrorInfo errorInfoFromScriptValue(const QScriptValue &value, const QString &filePath)
+{
+ if (!value.isError())
+ return ErrorInfo(value.toString(), CodeLocation(filePath));
+
+ return ErrorInfo(value.property(QStringLiteral("message")).toString(),
+ CodeLocation(value.property(QStringLiteral("fileName")).toString(),
+ value.property(QStringLiteral("lineNumber")).toInt32(),
+ false));
+}
+
+void ScriptImporter::importSourceCode(const QString &sourceCode, const QString &filePath,
+ QScriptValue &targetObject)
+{
+ Q_ASSERT(targetObject.isObject());
+ // The targetObject doesn't get overwritten but enhanced by the contents of the .js file.
+ // This is necessary for library imports that consist of multiple js files.
+
+ QString &code = m_sourceCodeCache[filePath];
+ if (code.isEmpty()) {
+ QbsQmlJS::Engine engine;
+ QbsQmlJS::Lexer lexer(&engine);
+ lexer.setCode(sourceCode, 1, false);
+ QbsQmlJS::Parser parser(&engine);
+ if (!parser.parseProgram()) {
+ throw ErrorInfo(parser.errorMessage(), CodeLocation(filePath, parser.errorLineNumber(),
+ parser.errorColumnNumber()));
+ }
+
+ IdentifierExtractor extractor;
+ extractor.start(parser.rootNode());
+ code = QLatin1String("(function(){\n") + sourceCode + extractor.suffix();
+ }
+
+ QScriptValue result = m_engine->evaluate(code, filePath, 0);
+ if (m_engine->hasUncaughtException())
+ throw errorInfoFromScriptValue(result, filePath);
+ copyProperties(result, targetObject);
+}
+
+void ScriptImporter::copyProperties(const QScriptValue &src, QScriptValue &dst)
+{
+ QScriptValueIterator it(src);
+ while (it.hasNext()) {
+ it.next();
+ dst.setProperty(it.name(), it.value());
+ }
+}
+
+} // namespace Internal
+} // namespace qbs
diff --git a/src/lib/corelib/language/builtinvalue.h b/src/lib/corelib/language/scriptimporter.h
index fb3e470e9..e477961a2 100644
--- a/src/lib/corelib/language/builtinvalue.h
+++ b/src/lib/corelib/language/scriptimporter.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qbs.
@@ -28,38 +28,29 @@
**
****************************************************************************/
-#ifndef QBS_BUILTINVALUE_H
-#define QBS_BUILTINVALUE_H
+#ifndef SCRIPTIMPORTER_H
+#define SCRIPTIMPORTER_H
-#include "value.h"
+#include <QHash>
+#include <QScriptEngine>
namespace qbs {
namespace Internal {
-class BuiltinValue : public Value
+class ScriptImporter
{
public:
- enum Builtin
- {
- GetEnvFunction,
- CurrentEnvFunction
- };
-
- static BuiltinValuePtr create(Builtin builtin);
-
- void apply(ValueHandler *handler) { handler->handle(this); }
- ValuePtr clone() const;
-
- Builtin builtin() const { return m_builtin; }
- void setBuiltin(const Builtin &builtin) { m_builtin = builtin; }
+ ScriptImporter(QScriptEngine *scriptEngine);
+ void importSourceCode(const QString &sourceCode, const QString &filePath, QScriptValue &targetObject);
private:
- BuiltinValue(Builtin builtin);
+ static void copyProperties(const QScriptValue &src, QScriptValue &dst);
- Builtin m_builtin;
+ QScriptEngine *m_engine;
+ QHash<QString, QString> m_sourceCodeCache;
};
} // namespace Internal
} // namespace qbs
-#endif // QBS_BUILTINVALUE_H
+#endif // SCRIPTIMPORTER_H
diff --git a/src/lib/corelib/language/tst_language.cpp b/src/lib/corelib/language/tst_language.cpp
index 6ec955caf..14fe621cd 100644
--- a/src/lib/corelib/language/tst_language.cpp
+++ b/src/lib/corelib/language/tst_language.cpp
@@ -1949,7 +1949,7 @@ void TestLanguage::wildcards()
QVERIFY(product);
GroupPtr group;
if (useGroup) {
- QCOMPARE(product->groups.count(), HostOsInfo::isOsxHost() ? 4 : 3);
+ QCOMPARE(product->groups.count(), HostOsInfo::isOsxHost() ? 3 : 2);
foreach (const GroupPtr &rg, product->groups) {
if (rg->name == groupName) {
group = rg;
@@ -1957,7 +1957,7 @@ void TestLanguage::wildcards()
}
}
} else {
- QCOMPARE(product->groups.count(), HostOsInfo::isOsxHost() ? 3 : 2);
+ QCOMPARE(product->groups.count(), HostOsInfo::isOsxHost() ? 2 : 1);
group = product->groups.first();
}
QVERIFY(group);
diff --git a/src/lib/corelib/language/value.h b/src/lib/corelib/language/value.h
index 4373d595f..831e0d066 100644
--- a/src/lib/corelib/language/value.h
+++ b/src/lib/corelib/language/value.h
@@ -47,8 +47,7 @@ public:
{
JSSourceValueType,
ItemValueType,
- VariantValueType,
- BuiltinValueType
+ VariantValueType
};
Value(Type t, bool createdByPropertiesBlock);
@@ -80,7 +79,6 @@ public:
virtual void handle(JSSourceValue *value) = 0;
virtual void handle(ItemValue *value) = 0;
virtual void handle(VariantValue *value) = 0;
- virtual void handle(BuiltinValue *value) = 0;
};
class JSSourceValue : public Value
diff --git a/src/lib/corelib/qbs.h b/src/lib/corelib/qbs.h
index 2e370e5a2..4aa133fcf 100644
--- a/src/lib/corelib/qbs.h
+++ b/src/lib/corelib/qbs.h
@@ -48,5 +48,6 @@
#include "tools/settings.h"
#include "tools/settingsmodel.h"
#include "tools/setupprojectparameters.h"
+#include "tools/toolchains.h"
#endif // QBS_H
diff --git a/src/lib/corelib/tools/commandechomode.cpp b/src/lib/corelib/tools/commandechomode.cpp
index 8f09bdac8..268243af5 100644
--- a/src/lib/corelib/tools/commandechomode.cpp
+++ b/src/lib/corelib/tools/commandechomode.cpp
@@ -36,6 +36,8 @@
* \value CommandEchoModeSilent Indicates that no output will be printed.
* \value CommandEchoModeSummary Indicates that descriptions will be printed.
* \value CommandEchoModeCommandLine Indidcates that full command line invocations will be printed.
+ * \value CommandEchoModeCommandLineWithEnvironment Indidcates that full command line invocations,
+ * including environment variables, will be printed.
*/
namespace qbs {
@@ -54,6 +56,8 @@ QString commandEchoModeName(CommandEchoMode mode)
return QLatin1String("summary");
case CommandEchoModeCommandLine:
return QLatin1String("command-line");
+ case CommandEchoModeCommandLineWithEnvironment:
+ return QLatin1String("command-line-with-environment");
default:
break;
}
diff --git a/src/lib/corelib/tools/commandechomode.h b/src/lib/corelib/tools/commandechomode.h
index f38c6a9ab..e820b15a8 100644
--- a/src/lib/corelib/tools/commandechomode.h
+++ b/src/lib/corelib/tools/commandechomode.h
@@ -41,7 +41,8 @@ enum CommandEchoMode {
CommandEchoModeSilent,
CommandEchoModeSummary,
CommandEchoModeCommandLine,
- CommandEchoModeLast = CommandEchoModeCommandLine
+ CommandEchoModeCommandLineWithEnvironment,
+ CommandEchoModeLast = CommandEchoModeCommandLineWithEnvironment
};
QBS_EXPORT CommandEchoMode defaultCommandEchoMode();
diff --git a/src/lib/corelib/tools/persistence.cpp b/src/lib/corelib/tools/persistence.cpp
index 60a7ada09..b2afb89ca 100644
--- a/src/lib/corelib/tools/persistence.cpp
+++ b/src/lib/corelib/tools/persistence.cpp
@@ -41,7 +41,7 @@
namespace qbs {
namespace Internal {
-static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-85";
+static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-87";
PersistentPool::PersistentPool(const Logger &logger) : m_logger(logger)
{
diff --git a/src/lib/corelib/tools/qbsassert.h b/src/lib/corelib/tools/qbsassert.h
index 2e6afcb91..e912ffb56 100644
--- a/src/lib/corelib/tools/qbsassert.h
+++ b/src/lib/corelib/tools/qbsassert.h
@@ -33,11 +33,6 @@
#include "qbs_export.h"
-// TODO: Remove once we require 5.3.
-#ifndef Q_NORETURN
-#define Q_NORETURN
-#endif
-
namespace qbs {
namespace Internal {
diff --git a/src/lib/corelib/tools/scripttools.cpp b/src/lib/corelib/tools/scripttools.cpp
index e627bacf3..83175cd7f 100644
--- a/src/lib/corelib/tools/scripttools.cpp
+++ b/src/lib/corelib/tools/scripttools.cpp
@@ -139,5 +139,17 @@ QVariant getConfigProperty(const QVariantMap &cfg, const QStringList &name)
return getConfigProperty(cfg.value(name.first()).toMap(), name.mid(1));
}
+TemporaryGlobalObjectSetter::TemporaryGlobalObjectSetter(const QScriptValue &object)
+{
+ QScriptEngine *engine = object.engine();
+ m_oldGlobalObject = engine->globalObject();
+ engine->setGlobalObject(object);
+}
+
+TemporaryGlobalObjectSetter::~TemporaryGlobalObjectSetter()
+{
+ m_oldGlobalObject.engine()->setGlobalObject(m_oldGlobalObject);
+}
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/tools/scripttools.h b/src/lib/corelib/tools/scripttools.h
index fa6884490..774c4ac2e 100644
--- a/src/lib/corelib/tools/scripttools.h
+++ b/src/lib/corelib/tools/scripttools.h
@@ -68,27 +68,6 @@ 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);
-/**
- * @brief push/pop a scope on a QScriptContext the RAII way.
- */
-class ScriptContextScopePusher
-{
-public:
- ScriptContextScopePusher(QScriptContext *scriptContext, const QScriptValue &value)
- : m_scriptContext(scriptContext)
- {
- m_scriptContext->pushScope(value);
- }
-
- ~ScriptContextScopePusher()
- {
- m_scriptContext->popScope();
- }
-
-private:
- QScriptContext *m_scriptContext;
-};
-
template <class T>
void attachPointerTo(QScriptValue &scriptValue, T *ptr)
{
@@ -104,6 +83,16 @@ T *attachedPointer(const QScriptValue &scriptValue)
return reinterpret_cast<T *>(ptr);
}
+class TemporaryGlobalObjectSetter
+{
+public:
+ TemporaryGlobalObjectSetter(const QScriptValue &object);
+ ~TemporaryGlobalObjectSetter();
+
+private:
+ QScriptValue m_oldGlobalObject;
+};
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/tools/toolchains.cpp b/src/lib/corelib/tools/toolchains.cpp
new file mode 100644
index 000000000..e2c67f1e8
--- /dev/null
+++ b/src/lib/corelib/tools/toolchains.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#include "toolchains.h"
+#include <QMap>
+#include <QSet>
+
+namespace qbs {
+
+QStringList canonicalToolchain(const QStringList &toolchain)
+{
+ static const QStringList knownToolchains {
+ QStringLiteral("xcode"),
+ QStringLiteral("clang"),
+ QStringLiteral("llvm"),
+ QStringLiteral("mingw"),
+ QStringLiteral("gcc"),
+ QStringLiteral("msvc")
+ };
+
+ // Canonicalize each toolchain in the toolchain list,
+ // which gets us the aggregate canonicalized (unsorted) list
+ QStringList toolchains;
+ for (const QString &toolchainName : toolchain)
+ toolchains << canonicalToolchain(toolchainName);
+ toolchains.removeDuplicates();
+
+ // Find all known toolchains in the canonicalized list,
+ // removing them from the main list as we go.
+ QStringList usedKnownToolchains;
+ for (int i = 0; i < toolchains.size(); ++i) {
+ if (knownToolchains.contains(toolchains[i])) {
+ usedKnownToolchains << toolchains[i];
+ toolchains.removeAt(i--);
+ }
+ }
+
+ // Sort the list of known toolchains into their canonical order.
+ std::sort(usedKnownToolchains.begin(), usedKnownToolchains.end(), [](
+ const QString &a,
+ const QString &b) {
+ return knownToolchains.indexOf(a) < knownToolchains.indexOf(b);
+ });
+
+ // Re-add the known toolchains to the main list (the custom ones go first).
+ toolchains << usedKnownToolchains;
+
+ // The toolchain list still needs further validation as it may contain mututally exclusive
+ // toolchain types (for example, llvm and msvc).
+ return toolchains;
+}
+
+QStringList canonicalToolchain(const QString &name)
+{
+ const QString &toolchainName = name.toLower();
+ QStringList toolchains(toolchainName);
+ if (toolchainName == QLatin1String("xcode"))
+ toolchains << canonicalToolchain(QLatin1String("clang"));
+ else if (toolchainName == QLatin1String("clang"))
+ toolchains << canonicalToolchain(QLatin1String("llvm"));
+ else if (toolchainName == QLatin1String("llvm") ||
+ toolchainName == QLatin1String("mingw")) {
+ toolchains << canonicalToolchain(QLatin1String("gcc"));
+ }
+ return toolchains;
+}
+
+} // namespace qbs
diff --git a/src/lib/corelib/language/builtinvalue.cpp b/src/lib/corelib/tools/toolchains.h
index 3fe201190..d66908148 100644
--- a/src/lib/corelib/language/builtinvalue.cpp
+++ b/src/lib/corelib/tools/toolchains.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qbs.
@@ -27,27 +27,17 @@
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
+#ifndef QBS_TOOLCHAINS_H
+#define QBS_TOOLCHAINS_H
-#include "builtinvalue.h"
+#include "qbs_export.h"
+#include <QStringList>
namespace qbs {
-namespace Internal {
-BuiltinValue::BuiltinValue(Builtin builtin)
- : Value(Value::BuiltinValueType, false)
- , m_builtin(builtin)
-{
-}
+QBS_EXPORT QStringList canonicalToolchain(const QStringList &toolchain);
+QBS_EXPORT QStringList canonicalToolchain(const QString &toolchainName);
-BuiltinValuePtr BuiltinValue::create(Builtin builtin)
-{
- return BuiltinValuePtr(new BuiltinValue(builtin));
-}
-
-ValuePtr BuiltinValue::clone() const
-{
- return BuiltinValuePtr(new BuiltinValue(*this));
-}
-
-} // namespace Internal
} // namespace qbs
+
+#endif // Include guard.
diff --git a/src/lib/corelib/tools/tools.pri b/src/lib/corelib/tools/tools.pri
index 618b08bb3..915ac750b 100644
--- a/src/lib/corelib/tools/tools.pri
+++ b/src/lib/corelib/tools/tools.pri
@@ -27,6 +27,7 @@ HEADERS += \
$$PWD/projectgeneratormanager.h \
$$PWD/propertyfinder.h \
$$PWD/shellutils.h \
+ $$PWD/toolchains.h \
$$PWD/hostosinfo.h \
$$PWD/buildoptions.h \
$$PWD/installoptions.h \
@@ -71,6 +72,7 @@ SOURCES += \
$$PWD/qbsassert.cpp \
$$PWD/qttools.cpp \
$$PWD/settingscreator.cpp \
+ $$PWD/toolchains.cpp \
$$PWD/version.cpp \
$$PWD/visualstudioversioninfo.cpp
@@ -110,7 +112,8 @@ qbs_enable_unit_tests {
$$PWD/generateoptions.h \
$$PWD/generatorpluginmanager.h \
$$PWD/installoptions.h \
- $$PWD/setupprojectparameters.h
+ $$PWD/setupprojectparameters.h \
+ $$PWD/toolchains.h
tools_headers.path = $${QBS_INSTALL_PREFIX}/include/qbs/tools
INSTALLS += tools_headers
}
diff --git a/src/lib/qtprofilesetup/qtprofilesetup.qbs b/src/lib/qtprofilesetup/qtprofilesetup.qbs
index 8d340ac9a..7f739e10f 100644
--- a/src/lib/qtprofilesetup/qtprofilesetup.qbs
+++ b/src/lib/qtprofilesetup/qtprofilesetup.qbs
@@ -11,7 +11,7 @@ QbsLibrary {
"qtprofilesetup.h",
"use_installed_qtprofilesetup.pri",
]
- qbs.install: project.installApiHeaders
+ qbs.install: qbsbuildconfig.installApiHeaders
qbs.installDir: headerInstallPrefix
}
diff --git a/src/lib/qtprofilesetup/templates/QtPlugin.qbs b/src/lib/qtprofilesetup/templates/QtPlugin.qbs
index 25c30101c..9a916f695 100644
--- a/src/lib/qtprofilesetup/templates/QtPlugin.qbs
+++ b/src/lib/qtprofilesetup/templates/QtPlugin.qbs
@@ -7,8 +7,9 @@ QtModule {
property string className
- Transformer {
+ Rule {
condition: isStaticLibrary
+ multiplex: true
Artifact {
filePath: product.targetName + "_qt_plugin_import_"
+ parent.parent.qtModuleName + ".cpp"
diff --git a/src/lib/qtprofilesetup/templates/core.qbs b/src/lib/qtprofilesetup/templates/core.qbs
index 57aef089a..bdde3c77e 100644
--- a/src/lib/qtprofilesetup/templates/core.qbs
+++ b/src/lib/qtprofilesetup/templates/core.qbs
@@ -75,7 +75,6 @@ Module {
property string qdocOutputDir: FileInfo.joinPaths(generatedFilesDir, "html")
property string qmDir: product.destinationDirectory
property string qmBaseName: product.targetName
- property string qmFilesDir: qmDir // TODO: Remove in 1.6
property bool lreleaseMultiplexMode: false
cpp.defines: {
diff --git a/src/lib/qtprofilesetup/templates/moc.js b/src/lib/qtprofilesetup/templates/moc.js
index 3728d9fe0..6c4d74f27 100644
--- a/src/lib/qtprofilesetup/templates/moc.js
+++ b/src/lib/qtprofilesetup/templates/moc.js
@@ -39,9 +39,13 @@ function args(product, input, outputFileName)
var includePaths = ModUtils.modulePropertiesFromArtifacts(product, [input], 'cpp', 'includePaths');
includePaths = includePaths.uniqueConcat(ModUtils.modulePropertiesFromArtifacts(
product, [input], 'cpp', 'systemIncludePaths'));
+ includePaths = includePaths.uniqueConcat(ModUtils.modulePropertiesFromArtifacts(
+ product, [input], 'cpp', 'compilerIncludePaths'));
var frameworkPaths = product.moduleProperties("cpp", "frameworkPaths");
frameworkPaths = frameworkPaths.uniqueConcat(
product.moduleProperties("cpp", "systemFrameworkPaths"));
+ frameworkPaths = frameworkPaths.uniqueConcat(
+ product.moduleProperties("cpp", "compilerFrameworkPaths"));
var args = [];
args = args.concat(
defines.map(function(item) { return '-D' + item; }),
diff --git a/src/plugins/scanner/scannerplugin.qbs b/src/plugins/scanner/scannerplugin.qbs
index 78448a145..2b34926b6 100644
--- a/src/plugins/scanner/scannerplugin.qbs
+++ b/src/plugins/scanner/scannerplugin.qbs
@@ -3,12 +3,13 @@ import qbs 1.0
DynamicLibrary {
Depends { name: "cpp" }
Depends { name: "Qt.core" }
+ Depends { name: "qbsbuildconfig" }
cpp.cxxLanguageVersion: "c++11"
- destinationDirectory: project.libDirName + "/qbs/plugins"
+ destinationDirectory: qbsbuildconfig.libDirName + "/qbs/plugins"
Group {
fileTagsFilter: ["dynamiclibrary"]
qbs.install: true
- qbs.installDir: project.pluginsInstallDir + "/qbs/plugins"
+ qbs.installDir: qbsbuildconfig.pluginsInstallDir + "/qbs/plugins"
}
bundle.isBundle: false
}
diff --git a/tests/auto/api/api.qbs b/tests/auto/api/api.qbs
index 36ed6eb00..68e7cde46 100644
--- a/tests/auto/api/api.qbs
+++ b/tests/auto/api/api.qbs
@@ -5,10 +5,10 @@ QbsAutotest {
files: ["../shared.h", "tst_api.h", "tst_api.cpp"]
cpp.defines: base.concat([
'SRCDIR="' + path + '"',
- 'QBS_RELATIVE_LIBEXEC_PATH="' + project.relativeLibexecPath + '"',
- 'QBS_RELATIVE_SEARCH_PATH="' + project.relativeSearchPath + '"',
- 'QBS_RELATIVE_PLUGINS_PATH="' + project.relativePluginsPath + '"'
- ]).concat(project.enableProjectFileUpdates ? ["QBS_ENABLE_PROJECT_FILE_UPDATES"] : [])
+ 'QBS_RELATIVE_LIBEXEC_PATH="' + qbsbuildconfig.relativeLibexecPath + '"',
+ 'QBS_RELATIVE_SEARCH_PATH="' + qbsbuildconfig.relativeSearchPath + '"',
+ 'QBS_RELATIVE_PLUGINS_PATH="' + qbsbuildconfig.relativePluginsPath + '"'
+ ]).concat(qbsbuildconfig.enableProjectFileUpdates ? ["QBS_ENABLE_PROJECT_FILE_UPDATES"] : [])
Group {
name: "testdata"
diff --git a/tests/auto/api/testdata/explicitly-depends-on/project.qbs b/tests/auto/api/testdata/explicitly-depends-on/project.qbs
index 3db802717..eda4e27df 100644
--- a/tests/auto/api/testdata/explicitly-depends-on/project.qbs
+++ b/tests/auto/api/testdata/explicitly-depends-on/project.qbs
@@ -8,7 +8,8 @@ Product {
patterns: "*.txt"
fileTags: ["txt"]
}
- Transformer {
+ Rule {
+ multiplex: true
explicitlyDependsOn: "txt"
Artifact {
filePath: "test.mytype"
diff --git a/tests/auto/api/testdata/infinite-loop-js/infinite-loop.qbs b/tests/auto/api/testdata/infinite-loop-js/infinite-loop.qbs
index e98fda511..592c602ec 100644
--- a/tests/auto/api/testdata/infinite-loop-js/infinite-loop.qbs
+++ b/tests/auto/api/testdata/infinite-loop-js/infinite-loop.qbs
@@ -2,7 +2,8 @@ import qbs
Product {
type: "mytype"
- Transformer {
+ Rule {
+ multiplex: true
Artifact {
filePath: "output.txt"
fileTags: "mytype"
diff --git a/tests/auto/api/testdata/qt5-plugin/project.qbs b/tests/auto/api/testdata/qt5-plugin/project.qbs
index 3e0dd1c6a..834c386ad 100644
--- a/tests/auto/api/testdata/qt5-plugin/project.qbs
+++ b/tests/auto/api/testdata/qt5-plugin/project.qbs
@@ -14,19 +14,24 @@ DynamicLibrary {
files: [
"echoplugin.h",
"echoplugin.cpp",
- "echoplugin.json.source"
]
}
Group {
+ condition: Qt.core.versionMajor >= 5
+ files: ["echoplugin.json.source"]
+ fileTags: ["json_in"]
+ }
+
+ Group {
condition: Qt.core.versionMajor < 5
files: "echoplugin_dummy.cpp"
}
cpp.includePaths: buildDirectory
- Transformer {
+ Rule {
condition: Qt.core.versionMajor >= 5
- inputs: ["echoplugin.json.source"]
+ inputs: ["json_in"]
Artifact {
filePath: "echoplugin.json"
fileTags: ["qt_plugin_metadata"]
diff --git a/tests/auto/api/testdata/rule-conflict/main.cpp b/tests/auto/api/testdata/rule-conflict/main.cpp
new file mode 100644
index 000000000..237c8ce18
--- /dev/null
+++ b/tests/auto/api/testdata/rule-conflict/main.cpp
@@ -0,0 +1 @@
+int main() {}
diff --git a/tests/auto/api/testdata/rule-conflict/pch1.h b/tests/auto/api/testdata/rule-conflict/pch1.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/api/testdata/rule-conflict/pch1.h
diff --git a/tests/auto/api/testdata/rule-conflict/pch2.h b/tests/auto/api/testdata/rule-conflict/pch2.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/api/testdata/rule-conflict/pch2.h
diff --git a/tests/auto/api/testdata/rule-conflict/rule-conflict.qbs b/tests/auto/api/testdata/rule-conflict/rule-conflict.qbs
new file mode 100644
index 000000000..d2e1b9144
--- /dev/null
+++ b/tests/auto/api/testdata/rule-conflict/rule-conflict.qbs
@@ -0,0 +1,11 @@
+import qbs
+
+CppApplication {
+ cpp.useCxxPrecompiledHeader: true
+ files: "main.cpp"
+ Group {
+ name: "pch files"
+ files: ["pch1.h", "pch2.h"]
+ fileTags: "cpp_pch_src"
+ }
+}
diff --git a/tests/auto/api/testdata/transformers/transformers.qbs b/tests/auto/api/testdata/transformers/transformers.qbs
index b0884ffa6..1e5a0ec4a 100644
--- a/tests/auto/api/testdata/transformers/transformers.qbs
+++ b/tests/auto/api/testdata/transformers/transformers.qbs
@@ -9,12 +9,17 @@ Project {
name: "HelloWorld"
type: "application"
consoleApplication: true
- files: ["main.cpp"]
+
+ Group {
+ files: ["main.cpp"]
+ fileTags: ["main"]
+ }
Depends { name: "cpp" }
- Transformer {
+ Rule {
// no inputs -> just a generator
+ multiplex: true
Artifact {
filePath: "foo.txt"
fileTags: "text"
@@ -35,7 +40,8 @@ Project {
}
}
- Transformer {
+ Rule {
+ multiplex: true
// no inputs -> just a generator
Artifact {
filePath: "foo.xml"
@@ -60,8 +66,8 @@ Project {
}
}
- Transformer {
- inputs: ["main.cpp"] // will be taken from the source dir
+ Rule {
+ inputs: ["main"]
Artifact {
filePath: "bar.txt"
fileTags: "text"
diff --git a/tests/auto/api/tst_api.cpp b/tests/auto/api/tst_api.cpp
index 5ba952490..14b555b2a 100644
--- a/tests/auto/api/tst_api.cpp
+++ b/tests/auto/api/tst_api.cpp
@@ -36,6 +36,7 @@
#include <qbs.h>
#include <tools/fileinfo.h>
#include <tools/hostosinfo.h>
+#include <tools/toolchains.h>
#include <QCoreApplication>
#include <QDir>
@@ -76,7 +77,6 @@ class BuildDescriptionReceiver : public QObject
public:
QString descriptions;
-private slots:
void handleDescription(const QString &, const QString &description) {
descriptions += description;
}
@@ -89,7 +89,6 @@ public:
QString output;
QVector<qbs::ProcessResult> results;
-private slots:
void handleProcessResult(const qbs::ProcessResult &result) {
results << result;
output += result.stdErr().join(QLatin1Char('\n'));
@@ -103,7 +102,6 @@ class TaskReceiver : public QObject
public:
QString taskDescriptions;
-private slots:
void handleTaskStart(const QString &task) { taskDescriptions += task; }
};
@@ -122,10 +120,10 @@ static bool waitForFinished(qbs::AbstractJob *job, int timeout = 0)
if (job->state() == qbs::AbstractJob::StateFinished)
return true;
QEventLoop loop;
- QObject::connect(job, SIGNAL(finished(bool,qbs::AbstractJob*)), &loop, SLOT(quit()));
+ QObject::connect(job, &qbs::AbstractJob::finished, &loop, &QEventLoop::quit);
if (timeout > 0) {
QTimer timer;
- QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
+ QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
timer.setSingleShot(true);
timer.start(timeout);
loop.exec();
@@ -330,9 +328,6 @@ void TestApi::buildProject_data()
QTest::newRow("link static libs")
<< QString("link-static-lib")
<< relativeExecutableFilePath("HelloWorld");
- QTest::newRow("precompiled header") // TODO: Remove in 1.6
- << QString("precompiled-header")
- << relativeExecutableFilePath("MyApp");
QTest::newRow("precompiled header new")
<< QString("precompiled-header-new")
<< relativeExecutableFilePath("MyApp");
@@ -420,8 +415,8 @@ void TestApi::buildSingleFile()
m_logSink->setLogLevel(qbs::LoggerMaxLevel);
QScopedPointer<qbs::BuildJob> buildJob(project.buildAllProducts(options));
BuildDescriptionReceiver receiver;
- connect(buildJob.data(), SIGNAL(reportCommandDescription(QString,QString)), &receiver,
- SLOT(handleDescription(QString,QString)));
+ connect(buildJob.data(), &qbs::BuildJob::reportCommandDescription, &receiver,
+ &BuildDescriptionReceiver::handleDescription);
waitForFinished(buildJob.data());
QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString()));
QCOMPARE(receiver.descriptions.count("compiling"), 1);
@@ -429,6 +424,96 @@ void TestApi::buildSingleFile()
qPrintable(receiver.descriptions));
}
+void TestApi::canonicalToolchainList()
+{
+ // All the known toolchain lists should be equal
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"xcode", "clang", "llvm", "gcc"})),
+ QStringList({"xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"clang", "llvm", "gcc"})),
+ QStringList({"clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm", "gcc"})),
+ QStringList({"llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"mingw", "gcc"})),
+ QStringList({"mingw", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc"})),
+ QStringList({"gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"msvc"})),
+ QStringList({"msvc"}));
+
+ // Single names should canonicalize to the known lists
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"xcode"})),
+ QStringList({"xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"clang"})),
+ QStringList({"clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm"})),
+ QStringList({"llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"mingw"})),
+ QStringList({"mingw", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc"})),
+ QStringList({"gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"msvc"})),
+ QStringList({"msvc"}));
+
+ // Missing some in the middle
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"xcode", "llvm", "gcc"})),
+ QStringList({"xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"xcode", "clang", "gcc"})),
+ QStringList({"xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"xcode", "gcc"})),
+ QStringList({"xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"clang", "llvm"})),
+ QStringList({"clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"clang", "gcc"})),
+ QStringList({"clang", "llvm", "gcc"}));
+
+ // Sorted wrong, missing some in the middle
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "llvm", "clang", "xcode"})),
+ QStringList({"xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"clang", "gcc", "llvm", "xcode"})),
+ QStringList({"xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm", "clang", "xcode", "gcc"})),
+ QStringList({"xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "llvm", "clang"})),
+ QStringList({"clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "clang", "xcode"})),
+ QStringList({"xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "llvm"})),
+ QStringList({"llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "mingw"})),
+ QStringList({"mingw", "gcc"}));
+
+ // Duplicates
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "llvm", "clang", "xcode", "xcode",
+ "xcode"})),
+ QStringList({"xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"clang", "gcc", "llvm", "clang", "xcode"})),
+ QStringList({"xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm", "clang", "clang", "xcode", "xcode",
+ "gcc"})),
+ QStringList({"xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm", "clang", "gcc", "llvm", "clang"})),
+ QStringList({"clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"xcode", "gcc", "clang", "gcc", "clang",
+ "xcode"})),
+ QStringList({"xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"llvm", "gcc", "llvm", "llvm"})),
+ QStringList({"llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(QStringList({"gcc", "gcc", "gcc", "mingw"})),
+ QStringList({"mingw", "gcc"}));
+
+ // Custom insanity
+ QCOMPARE(qbs::canonicalToolchain(
+ QStringList({"crazy", "gcc", "llvm", "clang", "xcode", "insane"})),
+ QStringList({"crazy", "insane", "xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(
+ QStringList({"crazy", "gcc", "llvm", "clang", "xcode", "insane", "crazy"})),
+ QStringList({"crazy", "insane", "xcode", "clang", "llvm", "gcc"}));
+ QCOMPARE(qbs::canonicalToolchain(
+ QStringList({"crazy", "insane", "gcc", "trade", "llvm", "clang", "xcode",
+ "insane", "mark", "crazy"})),
+ QStringList({"crazy", "insane", "trade", "mark", "xcode", "clang", "llvm", "gcc"}));
+}
+
void TestApi::checkOutputs()
{
QFETCH(bool, check);
@@ -672,8 +757,8 @@ void TestApi::changeContent()
BuildDescriptionReceiver rcvr;
QScopedPointer<qbs::BuildJob> buildJob(project.buildAllProducts(buildOptions, defaultProducts(),
this));
- connect(buildJob.data(), SIGNAL(reportCommandDescription(QString,QString)), &rcvr,
- SLOT(handleDescription(QString,QString)));
+ connect(buildJob.data(), &qbs::BuildJob::reportCommandDescription,
+ &rcvr, &BuildDescriptionReceiver::handleDescription);
waitForFinished(buildJob.data());
QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString()));
QVERIFY(rcvr.descriptions.contains("compiling file.cpp"));
@@ -702,8 +787,8 @@ void TestApi::changeContent()
// Now try building again and check if the newly resolved product behaves the same way.
buildJob.reset(project.buildAllProducts(buildOptions, defaultProducts(), this));
- connect(buildJob.data(), SIGNAL(reportCommandDescription(QString,QString)), &rcvr,
- SLOT(handleDescription(QString,QString)));
+ connect(buildJob.data(), &qbs::BuildJob::reportCommandDescription,
+ &rcvr, &BuildDescriptionReceiver::handleDescription);
waitForFinished(buildJob.data());
QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString()));
QVERIFY(rcvr.descriptions.contains("compiling file.cpp"));
@@ -741,8 +826,8 @@ void TestApi::changeContent()
projectData = project.projectData();
rcvr.descriptions.clear();
buildJob.reset(project.buildAllProducts(buildOptions, defaultProducts(), this));
- connect(buildJob.data(), SIGNAL(reportCommandDescription(QString,QString)), &rcvr,
- SLOT(handleDescription(QString,QString)));
+ connect(buildJob.data(), &qbs::BuildJob::reportCommandDescription,
+ &rcvr, &BuildDescriptionReceiver::handleDescription);
waitForFinished(buildJob.data());
QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString()));
QVERIFY(rcvr.descriptions.contains("compiling main.cpp"));
@@ -1083,7 +1168,7 @@ void TestApi::infiniteLoopBuilding()
QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString()));
qbs::Project project = setupJob->project();
const QScopedPointer<qbs::BuildJob> buildJob(project.buildAllProducts(qbs::BuildOptions()));
- QTimer::singleShot(1000, buildJob.data(), SLOT(cancel()));
+ QTimer::singleShot(1000, buildJob.data(), &qbs::AbstractJob::cancel);
QVERIFY(waitForFinished(buildJob.data(), 600000));
}
@@ -1100,7 +1185,7 @@ void TestApi::infiniteLoopResolving()
= defaultSetupParameters("infinite-loop-resolving/project.qbs");
QScopedPointer<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams,
m_logSink, 0));
- QTimer::singleShot(1000, setupJob.data(), SLOT(cancel()));
+ QTimer::singleShot(1000, setupJob.data(), &qbs::AbstractJob::cancel);
QVERIFY(waitForFinished(setupJob.data(), 600000));
QVERIFY2(setupJob->error().toString().toLower().contains("cancel"),
qPrintable(setupJob->error().toString()));
@@ -1743,6 +1828,15 @@ void TestApi::resolveProjectDryRun_data()
return resolveProject_data();
}
+void TestApi::ruleConflict()
+{
+ const qbs::ErrorInfo errorInfo = doBuildProject("rule-conflict/rule-conflict.qbs");
+ QVERIFY(errorInfo.hasError());
+ const QString errorString = errorInfo.toString();
+ QVERIFY2(errorString.contains("conflict") && errorString.contains("pch1.h")
+ && errorString.contains("pch2.h"), qPrintable(errorString));
+}
+
void TestApi::softDependency()
{
const qbs::ErrorInfo errorInfo = doBuildProject("soft-dependency/project.qbs");
@@ -1893,9 +1987,10 @@ void TestApi::uic()
}
-qbs::ErrorInfo TestApi::doBuildProject(const QString &projectFilePath,
- QObject *buildDescriptionReceiver, QObject *procResultReceiver, QObject *taskReceiver,
- const qbs::BuildOptions &options, const QVariantMap overriddenValues)
+qbs::ErrorInfo TestApi::doBuildProject(
+ const QString &projectFilePath, BuildDescriptionReceiver *buildDescriptionReceiver,
+ ProcessResultReceiver *procResultReceiver, TaskReceiver *taskReceiver,
+ const qbs::BuildOptions &options, const QVariantMap overriddenValues)
{
qbs::SetupProjectParameters params = defaultSetupParameters(projectFilePath);
params.setOverriddenValues(overriddenValues);
@@ -1903,20 +1998,20 @@ qbs::ErrorInfo TestApi::doBuildProject(const QString &projectFilePath,
const QScopedPointer<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(params,
m_logSink, 0));
if (taskReceiver) {
- connect(setupJob.data(), SIGNAL(taskStarted(QString,int,qbs::AbstractJob*)), taskReceiver,
- SLOT(handleTaskStart(QString)));
+ connect(setupJob.data(), &qbs::AbstractJob::taskStarted,
+ taskReceiver, &TaskReceiver::handleTaskStart);
}
waitForFinished(setupJob.data());
if (setupJob->error().hasError())
return setupJob->error();
const QScopedPointer<qbs::BuildJob> buildJob(setupJob->project().buildAllProducts(options));
if (buildDescriptionReceiver) {
- connect(buildJob.data(), SIGNAL(reportCommandDescription(QString,QString)),
- buildDescriptionReceiver, SLOT(handleDescription(QString,QString)));
+ connect(buildJob.data(), &qbs::BuildJob::reportCommandDescription,
+ buildDescriptionReceiver, &BuildDescriptionReceiver::handleDescription);
}
if (procResultReceiver) {
- connect(buildJob.data(), SIGNAL(reportProcessResult(qbs::ProcessResult)),
- procResultReceiver, SLOT(handleProcessResult(qbs::ProcessResult)));
+ connect(buildJob.data(), &qbs::BuildJob::reportProcessResult,
+ procResultReceiver, &ProcessResultReceiver::handleProcessResult);
}
waitForFinished(buildJob.data());
return buildJob->error();
diff --git a/tests/auto/api/tst_api.h b/tests/auto/api/tst_api.h
index 1644bd9ec..24f8f6f18 100644
--- a/tests/auto/api/tst_api.h
+++ b/tests/auto/api/tst_api.h
@@ -41,7 +41,10 @@ class ErrorInfo;
class SetupProjectParameters;
}
+class BuildDescriptionReceiver;
class LogSink;
+class ProcessResultReceiver;
+class TaskReceiver;
class TestApi : public QObject
{
@@ -63,6 +66,7 @@ private slots:
void buildProjectDryRun();
void buildProjectDryRun_data();
void buildSingleFile();
+ void canonicalToolchainList();
#ifdef QBS_ENABLE_PROJECT_FILE_UPDATES
void changeContent();
#endif
@@ -116,6 +120,7 @@ private slots:
void resolveProject_data();
void resolveProjectDryRun();
void resolveProjectDryRun_data();
+ void ruleConflict();
void softDependency();
void sourceFileInBuildDir();
void subProjects();
@@ -128,9 +133,9 @@ private slots:
private:
qbs::SetupProjectParameters defaultSetupParameters(const QString &projectFilePath) const;
qbs::ErrorInfo doBuildProject(const QString &projectFilePath,
- QObject *buildDescriptionReceiver = 0,
- QObject *procResultReceiver = 0,
- QObject *taskReceiver = 0,
+ BuildDescriptionReceiver *buildDescriptionReceiver = 0,
+ ProcessResultReceiver *procResultReceiver = 0,
+ TaskReceiver *taskReceiver = 0,
const qbs::BuildOptions &options = qbs::BuildOptions(),
const QVariantMap overriddenValues = QVariantMap());
diff --git a/tests/auto/auto.qbs b/tests/auto/auto.qbs
index 5e09463f4..aa5b3ff49 100644
--- a/tests/auto/auto.qbs
+++ b/tests/auto/auto.qbs
@@ -5,12 +5,9 @@ Project {
references: [
"api/api.qbs",
"blackbox/blackbox.qbs",
- "cmdlineparser/cmdlineparser.qbs"
- ].concat(unitTests)
-
- property pathList unitTests: enableUnitTests ? [
"buildgraph/buildgraph.qbs",
+ "cmdlineparser/cmdlineparser.qbs",
"language/language.qbs",
- "tools/tools.qbs"
- ] : []
+ "tools/tools.qbs",
+ ]
}
diff --git a/tests/auto/blackbox/testdata/android/multiple-apks-per-project/product1/product1.qbs b/tests/auto/blackbox/testdata/android/multiple-apks-per-project/product1/product1.qbs
index 9dde6e174..1058b9dbf 100644
--- a/tests/auto/blackbox/testdata/android/multiple-apks-per-project/product1/product1.qbs
+++ b/tests/auto/blackbox/testdata/android/multiple-apks-per-project/product1/product1.qbs
@@ -2,14 +2,18 @@ import qbs
Project {
DynamicLibrary {
+ Depends { name: "Android.ndk" }
+ Depends { name: "cpp" }
name: "p1lib1"
files: ["src/main/jni/lib1.cpp"]
Android.ndk.appStl: "stlport_shared"
- architectures: ["mipsel", "x86"]
+ architectures: ["mips", "x86"]
cpp.useRPaths: false
}
DynamicLibrary {
+ Depends { name: "Android.ndk" }
+ Depends { name: "cpp" }
name: "p1lib2"
files: ["src/main/jni/lib2.cpp"]
Android.ndk.appStl: "stlport_shared"
diff --git a/tests/auto/blackbox/testdata/android/multiple-apks-per-project/product2/product2.qbs b/tests/auto/blackbox/testdata/android/multiple-apks-per-project/product2/product2.qbs
index ab7c4770e..f0418a425 100644
--- a/tests/auto/blackbox/testdata/android/multiple-apks-per-project/product2/product2.qbs
+++ b/tests/auto/blackbox/testdata/android/multiple-apks-per-project/product2/product2.qbs
@@ -2,12 +2,15 @@ import qbs
Project {
DynamicLibrary {
+ Depends { name: "cpp" }
name: "p2lib1"
files: ["src/main/jni/lib1.cpp"]
cpp.useRPaths: false
}
DynamicLibrary {
+ Depends { name: "Android.ndk" }
+ Depends { name: "cpp" }
name: "p2lib2"
files: ["src/main/jni/lib2.cpp"]
Android.ndk.appStl: "stlport_shared"
diff --git a/tests/auto/blackbox/testdata/android/multiple-libs-per-apk/multiple-libs-per-apk.qbs b/tests/auto/blackbox/testdata/android/multiple-libs-per-apk/multiple-libs-per-apk.qbs
index a8eb9fc8c..94eb33ce7 100644
--- a/tests/auto/blackbox/testdata/android/multiple-libs-per-apk/multiple-libs-per-apk.qbs
+++ b/tests/auto/blackbox/testdata/android/multiple-libs-per-apk/multiple-libs-per-apk.qbs
@@ -2,6 +2,8 @@ import qbs
Project {
DynamicLibrary {
+ Depends { name: "Android.ndk" }
+ Depends { name: "cpp" }
name: "lib1"
files: ["src/main/jni/lib1.cpp"]
Android.ndk.appStl: "stlport_shared"
@@ -9,6 +11,8 @@ Project {
}
DynamicLibrary {
+ Depends { name: "Android.ndk" }
+ Depends { name: "cpp" }
name: "lib2"
files: ["src/main/jni/lib2.cpp"]
Android.ndk.appStl: "stlport_shared"
diff --git a/tests/auto/blackbox/testdata/android/no-native/no-native.qbs b/tests/auto/blackbox/testdata/android/no-native/no-native.qbs
index be0b932c7..2909adc0c 100644
--- a/tests/auto/blackbox/testdata/android/no-native/no-native.qbs
+++ b/tests/auto/blackbox/testdata/android/no-native/no-native.qbs
@@ -4,5 +4,5 @@ AndroidApk {
name: "com.example.android.basicmediadecoder"
sourceSetDir: Android.sdk.sdkDir
- + "/samples/android-21/media/BasicMediaDecoder/Application/src/main"
+ + "/samples/android-BasicMediaDecoder/Application/src/main"
}
diff --git a/tests/auto/blackbox/testdata/android/teapot/teapot.qbs b/tests/auto/blackbox/testdata/android/teapot/teapot.qbs
index 6701eaa49..e9bc5b4a6 100644
--- a/tests/auto/blackbox/testdata/android/teapot/teapot.qbs
+++ b/tests/auto/blackbox/testdata/android/teapot/teapot.qbs
@@ -1,10 +1,11 @@
import qbs
Project {
- property stringList architectures: ["arm64", "armv7", "x86_64", "mipsel"]
+ property stringList architectures: ["arm64", "armv7a", "x86_64", "mips"]
StaticLibrary {
architectures: project.architectures
name: "native-glue"
+ Depends { name: "cpp" }
Group {
id: glue_sources
prefix: Android.ndk.ndkDir + "/sources/android/native_app_glue/"
@@ -21,6 +22,8 @@ Project {
StaticLibrary {
architectures: project.architectures
name: "ndk-helper"
+ Depends { name: "Android.ndk" }
+ Depends { name: "cpp" }
Depends { name: "native-glue" }
Group {
@@ -40,6 +43,7 @@ Project {
StaticLibrary {
architectures: project.architectures
name: "cpufeatures"
+ Depends { name: "cpp" }
Group {
id: cpufeatures_sources
prefix: Android.ndk.ndkDir + "/sources/android/cpufeatures/"
@@ -56,13 +60,15 @@ 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" }
Group {
name: "C++ sources"
- prefix: Android.ndk.ndkDir + "/samples/Teapot/jni/"
+ prefix: Android.ndk.ndkDir + "/samples/Teapot/app/src/main/jni/"
files: [
"TeapotNativeActivity.cpp",
"TeapotRenderer.cpp",
@@ -80,8 +86,7 @@ Project {
AndroidApk {
name: "com.sample.teapot"
- sourceSetDir: Android.sdk.ndkDir + "/samples/Teapot"
- legacyLayout: true
+ sourceSetDir: Android.sdk.ndkDir + "/samples/Teapot/app/src/main"
Depends { productTypes: ["android.nativelibrary"] }
}
}
diff --git a/tests/auto/blackbox/testdata/build-directories/project.qbs b/tests/auto/blackbox/testdata/build-directories/project.qbs
index 11cfec5c4..dd8fc6c05 100644
--- a/tests/auto/blackbox/testdata/build-directories/project.qbs
+++ b/tests/auto/blackbox/testdata/build-directories/project.qbs
@@ -4,7 +4,8 @@ Project {
Product {
name: "p1"
type: "blubb1"
- Transformer {
+ Rule {
+ multiplex: true
Artifact {
filePath: "dummy1.txt"
fileTags: product.type
diff --git a/tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs b/tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs
index d924e73ff..d2f3773ca 100644
--- a/tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs
+++ b/tests/auto/blackbox/testdata/dependenciesProperty/dependenciesProperty.qbs
@@ -7,7 +7,8 @@ Project {
type: "deps"
name: "product1"
Depends { name: "product2" }
- Transformer {
+ Rule {
+ multiplex: true
Artifact {
fileTags: ["deps"]
filePath: product.name + '.deps'
diff --git a/tests/auto/blackbox/testdata/erroneous/nonexistentWorkingDir/project.qbs b/tests/auto/blackbox/testdata/erroneous/nonexistentWorkingDir/project.qbs
index 6433d80d9..8cf1bfaad 100644
--- a/tests/auto/blackbox/testdata/erroneous/nonexistentWorkingDir/project.qbs
+++ b/tests/auto/blackbox/testdata/erroneous/nonexistentWorkingDir/project.qbs
@@ -2,7 +2,9 @@ import qbs
Application {
name: "kaputt"
- Transformer {
+ type: ["nutritious"]
+ Rule {
+ multiplex: true
Artifact {
filePath: "Stulle"
fileTags: ["nutritious"]
diff --git a/tests/auto/blackbox/testdata/installed-transformer-output/qbs668.qbs b/tests/auto/blackbox/testdata/installed-transformer-output/qbs668.qbs
index eeffe25fc..99acc5585 100644
--- a/tests/auto/blackbox/testdata/installed-transformer-output/qbs668.qbs
+++ b/tests/auto/blackbox/testdata/installed-transformer-output/qbs668.qbs
@@ -3,13 +3,15 @@ import qbs.TextFile
Product {
name: "install-test"
+ type: ["text"]
Group {
qbs.install: true
qbs.installDir: "textfiles"
fileTagsFilter: "text"
}
- Transformer {
+ Rule {
+ multiplex: true
Artifact {
filePath: "HelloWorld.txt"
fileTags: ["text"]
diff --git a/tests/auto/blackbox/testdata/jsextensions-file/file.qbs b/tests/auto/blackbox/testdata/jsextensions-file/file.qbs
index 185ee4ac8..5d6ce07ca 100644
--- a/tests/auto/blackbox/testdata/jsextensions-file/file.qbs
+++ b/tests/auto/blackbox/testdata/jsextensions-file/file.qbs
@@ -5,7 +5,8 @@ import qbs.TextFile
Product {
type: ["dummy"]
- Transformer {
+ Rule {
+ multiplex: true
Artifact {
filePath: "dummy.txt"
fileTags: ["dummy"]
diff --git a/tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs b/tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs
index 26dc5a165..c42c73129 100644
--- a/tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs
+++ b/tests/auto/blackbox/testdata/jsextensions-fileinfo/fileinfo.qbs
@@ -4,7 +4,8 @@ import qbs.TextFile
Product {
type: ["dummy"]
- Transformer {
+ Rule {
+ multiplex: true
Artifact {
filePath: "dummy.txt"
fileTags: ["dummy"]
diff --git a/tests/auto/blackbox/testdata/jsextensions-process/process.qbs b/tests/auto/blackbox/testdata/jsextensions-process/process.qbs
index 8ca6f7e69..da3a66812 100644
--- a/tests/auto/blackbox/testdata/jsextensions-process/process.qbs
+++ b/tests/auto/blackbox/testdata/jsextensions-process/process.qbs
@@ -8,7 +8,8 @@ Project {
Product {
Depends { name: "Qt.core" }
type: ["dummy"]
- Transformer {
+ Rule {
+ multiplex: true
Artifact {
filePath: "dummy.txt"
fileTags: ["dummy"]
diff --git a/tests/auto/blackbox/testdata/jsextensions-textfile/textfile.qbs b/tests/auto/blackbox/testdata/jsextensions-textfile/textfile.qbs
index 6f24d19eb..456a10f0d 100644
--- a/tests/auto/blackbox/testdata/jsextensions-textfile/textfile.qbs
+++ b/tests/auto/blackbox/testdata/jsextensions-textfile/textfile.qbs
@@ -3,7 +3,8 @@ import qbs.TextFile
Product {
type: ["dummy"]
- Transformer {
+ Rule {
+ multiplex: true
Artifact {
filePath: "dummy.txt"
fileTags: ["dummy"]
diff --git a/tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs b/tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs
index 4423d68e0..4aa7d327d 100644
--- a/tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs
+++ b/tests/auto/blackbox/testdata/linkerscripts/linkerscripts.qbs
@@ -10,7 +10,8 @@ DynamicLibrary {
fileTags: ["linkerscript"]
}
- Transformer {
+ Rule {
+ multiplex: true
outputs: ["custom"]
Artifact {
filePath: "dummy.txt"
diff --git a/tests/auto/blackbox/testdata/output-artifact-auto-tagging/output-artifact-auto-tagging.qbs b/tests/auto/blackbox/testdata/output-artifact-auto-tagging/output-artifact-auto-tagging.qbs
index e94775f1e..49a732e23 100644
--- a/tests/auto/blackbox/testdata/output-artifact-auto-tagging/output-artifact-auto-tagging.qbs
+++ b/tests/auto/blackbox/testdata/output-artifact-auto-tagging/output-artifact-auto-tagging.qbs
@@ -8,6 +8,7 @@ CppApplication {
fileTags: ["cpp.in"]
}
Rule {
+ multiplex: true
inputs: ["cpp.in"]
outputFileTags: ["cpp"]
outputArtifacts: [{ filePath: "main.cpp" }, { filePath: "broken.nomatch" }]
diff --git a/tests/auto/blackbox/testdata/productproperties/header.qbs b/tests/auto/blackbox/testdata/productproperties/header.qbs
index ee08de1e2..5c3e2db63 100644
--- a/tests/auto/blackbox/testdata/productproperties/header.qbs
+++ b/tests/auto/blackbox/testdata/productproperties/header.qbs
@@ -7,7 +7,8 @@ Product {
files: "blubb_header.h.in"
property string blubbProp: project.blubbProp
- Transformer {
+ Rule {
+ multiplex: true
Artifact {
filePath: "blubb_header.h"
fileTags: "hpp"
diff --git a/tests/auto/blackbox/testdata/propertyChanges/project.qbs b/tests/auto/blackbox/testdata/propertyChanges/project.qbs
index cd842c12e..8293d4ca7 100644
--- a/tests/auto/blackbox/testdata/propertyChanges/project.qbs
+++ b/tests/auto/blackbox/testdata/propertyChanges/project.qbs
@@ -31,10 +31,12 @@ Project {
Product {
name: "generated text file"
+ type: ["my_output"]
property string fileContentPrefix: "prefix 1"
- Transformer {
- Artifact { filePath: "nothing" }
+ Rule {
+ multiplex: true
+ Artifact { filePath: "nothing"; fileTags: ["my_output"] }
prepare: {
var cmd = new JavaScriptCommand();
cmd.silent = true;
@@ -43,8 +45,9 @@ Project {
}
}
- Transformer {
- Artifact { filePath: "generated.txt" }
+ Rule {
+ multiplex: true
+ Artifact { filePath: "generated.txt"; fileTags: ["my_output"] }
prepare: {
var cmd = new JavaScriptCommand();
cmd.description = "generating " + output.filePath;
diff --git a/tests/auto/blackbox/testdata/rule-with-no-inputs/rule-with-no-inputs.qbs b/tests/auto/blackbox/testdata/rule-with-no-inputs/rule-with-no-inputs.qbs
new file mode 100644
index 000000000..2ba97cfa6
--- /dev/null
+++ b/tests/auto/blackbox/testdata/rule-with-no-inputs/rule-with-no-inputs.qbs
@@ -0,0 +1,26 @@
+import qbs
+import qbs.TextFile
+
+Product {
+ name: "theProduct"
+ type: ["output"]
+ property int version: 1
+ Rule {
+ inputs: []
+ multiplex: true
+ Artifact {
+ filePath: "output.out"
+ fileTags: ["output"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "creating output";
+ cmd.sourceCode = function() {
+ console.info(product.version);
+ var f = new TextFile(output.filePath, TextFile.WriteOnly);
+ f.close();
+ }
+ return [cmd];
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/successive-changes/input.in b/tests/auto/blackbox/testdata/successive-changes/input.in
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/successive-changes/input.in
diff --git a/tests/auto/blackbox/testdata/successive-changes/successive-changes.qbs b/tests/auto/blackbox/testdata/successive-changes/successive-changes.qbs
new file mode 100644
index 000000000..f42ca4096
--- /dev/null
+++ b/tests/auto/blackbox/testdata/successive-changes/successive-changes.qbs
@@ -0,0 +1,30 @@
+import qbs
+import qbs.TextFile
+
+Project {
+ property string version: "1"
+ Product {
+ name: "theProduct"
+ type: ["output"]
+ Group {
+ files: ["input.in"]
+ fileTags: ["input"]
+ }
+ Rule {
+ inputs: ["input"]
+ Artifact {
+ filePath: "output.out"
+ fileTags: ["output"]
+ }
+ prepare: {
+ var cmd = new JavaScriptCommand();
+ cmd.description = "Creating output";
+ cmd.sourceCode = function() {
+ var f = new TextFile(output.filePath, TextFile.WriteOnly);
+ f.write(project.version);
+ }
+ return [cmd];
+ }
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/symlink-removal/symlink-removal.qbs b/tests/auto/blackbox/testdata/symlink-removal/symlink-removal.qbs
index 8e74149d1..fc47c450f 100644
--- a/tests/auto/blackbox/testdata/symlink-removal/symlink-removal.qbs
+++ b/tests/auto/blackbox/testdata/symlink-removal/symlink-removal.qbs
@@ -3,7 +3,8 @@ import qbs.File
Product {
type: "removal"
- Transformer {
+ Rule {
+ multiplex: true
Artifact {
filePath: "dummy"
fileTags: product.type
diff --git a/tests/auto/blackbox/testdata/versionscript/versionscript.qbs b/tests/auto/blackbox/testdata/versionscript/versionscript.qbs
index 56260a022..7dd3654a3 100644
--- a/tests/auto/blackbox/testdata/versionscript/versionscript.qbs
+++ b/tests/auto/blackbox/testdata/versionscript/versionscript.qbs
@@ -10,7 +10,8 @@ DynamicLibrary {
fileTags: ["versionscript"]
}
- Transformer {
+ Rule {
+ multiplex: true
outputs: ["custom"]
Artifact {
filePath: "dummy.txt"
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
index 6d0b024fd..0c326c628 100644
--- a/tests/auto/blackbox/tst_blackbox.cpp
+++ b/tests/auto/blackbox/tst_blackbox.cpp
@@ -431,6 +431,7 @@ void TestBlackbox::alwaysRun()
rmDirR(relativeBuildDir());
QbsRunParameters params("build", QStringList() << "-f" << projectFile);
QCOMPARE(runQbs(params), 0);
+ QVERIFY(projectFile.contains("transformer") == m_qbsStderr.contains("deprecated"));
QVERIFY(m_qbsStdout.contains("yo"));
QCOMPARE(runQbs(params), 0);
QVERIFY(!m_qbsStdout.contains("yo"));
@@ -504,7 +505,7 @@ void TestBlackbox::android_data()
QTest::addColumn<QList<int>>("apkFileCounts");
QTest::newRow("teapot") << "teapot" << QStringList("com.sample.teapot") << (QList<int>() << 25);
QTest::newRow("no native") << "no-native"
- << QStringList("com.example.android.basicmediadecoder") << (QList<int>() << 23);
+ << QStringList("com.example.android.basicmediadecoder") << (QList<int>() << 22);
QTest::newRow("multiple libs") << "multiple-libs-per-apk" << QStringList("twolibs")
<< (QList<int>() << 10);
QTest::newRow("multiple apks") << "multiple-apks-per-project"
@@ -1776,6 +1777,21 @@ void TestBlackbox::ruleCycle()
QVERIFY(m_qbsStderr.contains("Cycle detected in rule dependencies"));
}
+void TestBlackbox::ruleWithNoInputs()
+{
+ QDir::setCurrent(testDataDir + "/rule-with-no-inputs");
+ QVERIFY2(runQbs() == 0, m_qbsStderr.constData());
+ 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");
+ QVERIFY2(runQbs(params) == 0, m_qbsStderr.constData());
+ QVERIFY2(!m_qbsStdout.contains("creating output"), m_qbsStdout.constData());
+ params.arguments = QStringList() << "theProduct.version:2";
+ QVERIFY2(runQbs(params) == 0, m_qbsStderr.constData());
+ QVERIFY2(m_qbsStdout.contains("creating output"), m_qbsStdout.constData());
+}
+
void TestBlackbox::overrideProjectProperties()
{
QDir::setCurrent(testDataDir + "/overrideProjectProperties");
@@ -2557,12 +2573,10 @@ void TestBlackbox::jsExtensionsPropertyList()
QByteArray file1Contents = file1.readAll();
QCOMPARE(file3.readAll(), file1Contents);
//QCOMPARE(file1Contents, file2.readAll()); // keys don't have guaranteed order
-#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
QJsonParseError err1, err2;
QCOMPARE(QJsonDocument::fromJson(file1Contents, &err1),
QJsonDocument::fromJson(file2.readAll(), &err2));
QVERIFY(err1.error == QJsonParseError::NoError && err2.error == QJsonParseError::NoError);
-#endif
QFile file4("test.openstep.plist");
QVERIFY(file4.exists());
QFile file5("test3.json");
@@ -3107,6 +3121,7 @@ void TestBlackbox::radAfterIncompleteBuild()
// Step 1: Have a directory where a file used to be.
QbsRunParameters params(QStringList() << "-f" << projectFileName);
QCOMPARE(runQbs(params), 0);
+ QVERIFY(projectFileName.contains("transformer") == m_qbsStderr.contains("deprecated"));
WAIT_FOR_NEW_TIMESTAMP();
QFile projectFile(projectFileName);
QVERIFY(projectFile.open(QIODevice::ReadWrite));
@@ -3171,6 +3186,22 @@ void TestBlackbox::subProfileChangeTracking()
QVERIFY(m_qbsStdout.contains("main2.cpp"));
}
+void TestBlackbox::successiveChanges()
+{
+ QDir::setCurrent(testDataDir + "/successive-changes");
+ QCOMPARE(runQbs(), 0);
+
+ QbsRunParameters params(QStringList() << "theProduct.type:output,blubb");
+ QCOMPARE(runQbs(params), 0);
+
+ params.arguments << "project.version:2";
+ QCOMPARE(runQbs(params), 0);
+ QFile output(relativeProductBuildDir("theProduct") + "/output.out");
+ QVERIFY2(output.open(QIODevice::ReadOnly), qPrintable(output.errorString()));
+ const QByteArray version = output.readAll();
+ QCOMPARE(version.constData(), "2");
+}
+
void TestBlackbox::installedApp()
{
QDir::setCurrent(testDataDir + "/installed_artifact");
diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h
index 9f2461b4e..18605ec9c 100644
--- a/tests/auto/blackbox/tst_blackbox.h
+++ b/tests/auto/blackbox/tst_blackbox.h
@@ -196,7 +196,9 @@ private slots:
void responseFiles();
void ruleConditions();
void ruleCycle();
+ void ruleWithNoInputs();
void subProfileChangeTracking();
+ void successiveChanges();
void symlinkRemoval();
void renameDependency();
void separateDebugInfo();
diff --git a/tests/auto/buildgraph/buildgraph.qbs b/tests/auto/buildgraph/buildgraph.qbs
index cc5885ca2..f6c1cd1f7 100644
--- a/tests/auto/buildgraph/buildgraph.qbs
+++ b/tests/auto/buildgraph/buildgraph.qbs
@@ -2,5 +2,6 @@ import qbs
QbsAutotest {
testName: "buildgraph"
+ condition: qbsbuildconfig.enableUnitTests
files: "tst_buildgraph.cpp"
}
diff --git a/tests/auto/language/language.qbs b/tests/auto/language/language.qbs
index ff9f518f2..9fda49ce6 100644
--- a/tests/auto/language/language.qbs
+++ b/tests/auto/language/language.qbs
@@ -2,5 +2,6 @@ import qbs
QbsAutotest {
testName: "language"
+ condition: qbsbuildconfig.enableUnitTests
files: "tst_language.cpp"
}
diff --git a/tests/auto/tools/tools.qbs b/tests/auto/tools/tools.qbs
index 54a6ea485..612a70a40 100644
--- a/tests/auto/tools/tools.qbs
+++ b/tests/auto/tools/tools.qbs
@@ -2,5 +2,6 @@ import qbs
QbsAutotest {
testName: "tools"
+ condition: qbsbuildconfig.enableUnitTests
files: ["tst_tools.cpp"]
}