aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2019-07-05 13:46:41 +0200
committerChristian Kandeler <christian.kandeler@qt.io>2019-07-05 13:46:41 +0200
commit886a98d6137692f89de80aab07278b7c6d9227d8 (patch)
tree094ee7dda5babafd7536b0e95c7ae535a62eca74
parent590a58c3702de17ba7b44c9041dfe5d3e88bea31 (diff)
parent27b78ea67f82fca051666599603273c12ecb403b (diff)
Merge 1.14 into master
-rw-r--r--doc/reference/items/probe/path-probe.qdoc60
-rw-r--r--doc/reference/modules/protobufcpp-module.qdoc87
-rw-r--r--examples/cocoa-touch-application/CocoaTouchApplication.qbs4
-rw-r--r--examples/examples.qbs1
-rw-r--r--examples/grpc/client.cpp95
-rw-r--r--examples/grpc/ping-pong-grpc.proto15
-rw-r--r--examples/grpc/ping-pong-grpc.qbs65
-rw-r--r--examples/grpc/server.cpp78
-rw-r--r--qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs16
-rwxr-xr-xscripts/build-qbs-with-qbs.sh1
-rw-r--r--share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs19
-rw-r--r--share/qbs/imports/qbs/Probes/NpmProbe.qbs18
-rw-r--r--share/qbs/imports/qbs/Probes/PathProbe.qbs17
-rw-r--r--share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs14
-rw-r--r--share/qbs/imports/qbs/Probes/path-probe.js111
-rw-r--r--share/qbs/modules/cpp/iar.js4
-rw-r--r--share/qbs/modules/cpp/ios-gcc.qbs4
-rw-r--r--share/qbs/modules/protobuf/cpp/protobufcpp.qbs84
-rw-r--r--share/qbs/modules/protobuf/protobuf.js25
-rw-r--r--src/lib/corelib/tools/launchersocket.cpp1
-rw-r--r--src/lib/corelib/tools/qttools.h2
-rw-r--r--src/lib/library.pri2
-rw-r--r--static-res.pro3
-rw-r--r--tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs26
-rw-r--r--tests/auto/blackbox/testdata/grpc/grpc.cpp49
-rw-r--r--tests/auto/blackbox/testdata/grpc/grpc.proto15
-rw-r--r--tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs26
-rw-r--r--tests/auto/blackbox/testdata/path-probe/BaseApp.qbs76
-rw-r--r--tests/auto/blackbox/testdata/path-probe/bin/super-tool.10
-rw-r--r--tests/auto/blackbox/testdata/path-probe/bin/tool0
-rw-r--r--tests/auto/blackbox/testdata/path-probe/bin/tool.10
-rw-r--r--tests/auto/blackbox/testdata/path-probe/bin/tool.20
-rw-r--r--tests/auto/blackbox/testdata/path-probe/bin/tool.30
-rw-r--r--tests/auto/blackbox/testdata/path-probe/bin/tool.40
-rw-r--r--tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs12
-rw-r--r--tests/auto/blackbox/testdata/path-probe/main.cpp1
-rw-r--r--tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs8
-rw-r--r--tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs9
-rw-r--r--tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs8
-rw-r--r--tests/auto/blackbox/testdata/path-probe/mult-files.qbs10
-rw-r--r--tests/auto/blackbox/testdata/path-probe/name-filter.qbs10
-rw-r--r--tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs8
-rw-r--r--tests/auto/blackbox/testdata/path-probe/non-existent.qbs4
-rw-r--r--tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs5
-rw-r--r--tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs5
-rw-r--r--tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs5
-rw-r--r--tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs6
-rw-r--r--tests/auto/blackbox/testdata/path-probe/single-file.qbs5
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp54
-rw-r--r--tests/auto/blackbox/tst_blackbox.h4
-rw-r--r--tests/auto/blackbox/tst_blackboxapple.cpp59
51 files changed, 1041 insertions, 90 deletions
diff --git a/doc/reference/items/probe/path-probe.qdoc b/doc/reference/items/probe/path-probe.qdoc
index 298ce9d95..eaaee9e54 100644
--- a/doc/reference/items/probe/path-probe.qdoc
+++ b/doc/reference/items/probe/path-probe.qdoc
@@ -58,6 +58,42 @@
*/
/*!
+ \qmlproperty varList PathProbe::allResults
+
+ This property contains the list of objects, each object representing a single found file:
+ \code
+ {
+ found: true,
+ candidatePaths: ["path1/to/file", "path2/to/file", ...]
+ filePath: "path/to/file"
+ fileName: "file"
+ path: "path/to"
+ }
+ \endcode
+ \sa {PathProbe::filePath}{filePath}, {PathProbe::fileName}{fileName},
+ {PathProbe::path}{path}
+*/
+
+/*!
+ \qmlproperty var PathProbe::candidateFilter
+
+ This property holds the function that can be used to filter out unsuitable candidates.
+ For example, when searching for a library, it might be necessary to check its architecture:
+ \code
+ PathProbe {
+ pathSuffixes: ["*.so", *.dll]
+ candidateFilter: {
+ function getLibraryArchitecture(file) { ... }
+ return function(file) {
+ return Utilities.isSharedLibrary(file)
+ && getLibraryArchitecture(file) == qbs.architecture;
+ }
+ }
+ }
+ \endcode
+*/
+
+/*!
\qmlproperty stringList PathProbe::names
The list of file names to search for.
@@ -69,8 +105,7 @@
\qmlproperty stringList PathProbe::nameSuffixes
The list of file suffixes to search for. These suffixes are appended to every file name passed
- via the \l names property. If \l names is empty, the probe looks for any file that ends with the
- given suffix.
+ via the \l names property.
\nodefaultvalue
*/
@@ -161,3 +196,24 @@
\nodefaultvalue
*/
+
+/*!
+ \qmlproperty varList PathProbe::selectors
+
+ This property should be used to search for multiple files. It contains the list of selectors
+ each of which describes a single file to search for. A selector can be either a string, a
+ stringList, or a dictionary.
+
+ The following example searches for three files and illustrates different ways to specify
+ selectors:
+ \code
+ selectors: [
+ // 1st file with a single name
+ "header.h",
+ // 2nd file with possible name variants
+ ["config.h", "foo-config.h", "bar-config.h"],
+ // 3rd file with possible name and suffix variants
+ {names: ["footk", "footk-version"], nameSuffixes: [".h", ".hpp"]}
+ ]
+ \endcode
+*/
diff --git a/doc/reference/modules/protobufcpp-module.qdoc b/doc/reference/modules/protobufcpp-module.qdoc
index 63c56c6ca..b82ccc9f7 100644
--- a/doc/reference/modules/protobufcpp-module.qdoc
+++ b/doc/reference/modules/protobufcpp-module.qdoc
@@ -68,10 +68,33 @@
\li \c{*.proto}
\li 1.13.0
\li Source files with this tag are considered inputs to the \c protoc compiler.
+ \row
+ \li \c{"protobuf.grpc"}
+ \li
+ \li 1.14.0
+ \li Source files with this tag are considered as gRPC files.
\endtable
*/
/*!
+ \qmlproperty string protobuf.cpp::grpcIncludePath
+
+ The path where grpc++ headers are located. Set this property to override the
+ default location.
+
+ \defaultvalue \c auto-detected
+*/
+
+/*!
+ \qmlproperty string protobuf.cpp::grpcLibraryPath
+
+ The path where the grpc++ library is located. Set this property to override the
+ default location.
+
+ \defaultvalue \c auto-detected
+*/
+
+/*!
\qmlproperty string protobuf.cpp::protocBinary
The command to invoke when compiling proto definition files.
@@ -108,3 +131,67 @@
\defaultvalue \c auto-detected
*/
+
+/*!
+ \qmlproperty bool protobuf.cpp::useGrpc
+
+ Whether to use gRPC framework.
+
+ Use this property to enable support for the modern open source high performance RPC
+ framework by Google, gRPC (\l{https://www.grpc.io}).
+
+ A simple qbs file that uses grpc can be written as follows:
+ \code
+ CppApplication {
+ Depends { name: "protobuf.cpp" }
+ protobuf.cpp.useGrpc: true
+ files: ["main.cpp"]
+ Group {
+ files: "grpc.proto"
+ fileTags: "protobuf.grpc"
+ }
+ }
+ \endcode
+
+ \note that \c protobuf.grpc tag should be assigned manually because gRPC uses same \c *.proto
+ files and \QBS can't detect whether to generate gRPC or \c protobuf.
+
+ The following \c grpc.proto file...
+ \code
+ syntax = "proto3";
+
+ package Qbs;
+
+ message Request {
+ string name = 1;
+ }
+
+ message Response {
+ string name = 1;
+ }
+
+ service Grpc {
+ rpc doWork(Request) returns (Response) {}
+ }
+ \endcode
+
+ ...can be used in the C++ sources as follows:
+ \code
+ #include <grpc.grpc.pb.h>
+
+ class Service final : public Qbs::Grpc::Service
+ {
+ grpc::Status doWork(
+ grpc::ServerContext* context,
+ const Qbs::Request* request,
+ Qbs::Response* reply) override
+ {
+ (void)context;
+ reply->set_name(request->name());
+ return grpc::Status::OK;
+ }
+ };
+ \endcode
+
+ \defaultvalue \c false
+*/
diff --git a/examples/cocoa-touch-application/CocoaTouchApplication.qbs b/examples/cocoa-touch-application/CocoaTouchApplication.qbs
index f8db6768f..cf0a273d5 100644
--- a/examples/cocoa-touch-application/CocoaTouchApplication.qbs
+++ b/examples/cocoa-touch-application/CocoaTouchApplication.qbs
@@ -52,11 +52,13 @@
import qbs 1.0
CppApplication {
+ Depends { name: "xcode"; required: false }
Depends { condition: product.condition; name: "ib" }
- condition: qbs.hostOS.contains("macos")
+ condition: qbs.hostOS.contains("macos") && xcode.present
name: "Cocoa Touch Application"
qbs.targetPlatform: "ios"
+ qbs.architecture: "arm64"
cpp.useObjcPrecompiledHeader: true
cpp.minimumIosVersion: "8.0"
diff --git a/examples/examples.qbs b/examples/examples.qbs
index c6c1f4ac3..abb6d5d9a 100644
--- a/examples/examples.qbs
+++ b/examples/examples.qbs
@@ -58,6 +58,7 @@ Project {
"code-generator/code-generator.qbs",
"collidingmice/collidingmice.qbs",
"compiled-qml/myapp.qbs",
+ "grpc/ping-pong-grpc.qbs",
"helloworld-complex/hello.qbs",
"helloworld-minimal/hello.qbs",
"helloworld-qt/hello.qbs",
diff --git a/examples/grpc/client.cpp b/examples/grpc/client.cpp
new file mode 100644
index 000000000..55bcd866d
--- /dev/null
+++ b/examples/grpc/client.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Ivan Komissarov
+** Contact: abbapoh@gmail.com
+**
+** 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.
+**
+****************************************************************************/
+
+#ifdef __GNUC__
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif // __GNUC__
+
+#include <ping-pong-grpc.grpc.pb.h>
+
+#include <grpc/grpc.h>
+#include <grpc++/channel.h>
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+
+#ifdef __GNUC__
+ #pragma GCC diagnostic pop
+#endif // __GNUC__
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+class Client
+{
+public:
+ Client(std::shared_ptr<grpc::Channel> channel)
+ : m_stub(PP::MyApi::NewStub(channel)) {}
+
+ int ping(int count) {
+ PP::Ping request;
+ request.set_count(count);
+ PP::Pong reply;
+ grpc::ClientContext context;
+
+ const auto status = m_stub->pingPong(&context, request, &reply);
+ if (status.ok()) {
+ return reply.count();
+ } else {
+ throw std::runtime_error("invalid status");
+ }
+ }
+
+private:
+ std::unique_ptr<PP::MyApi::Stub> m_stub;
+};
+
+int main(int, char**)
+{
+ Client client(
+ grpc::CreateCustomChannel(
+ "localhost:50051",
+ grpc::InsecureChannelCredentials(),
+ grpc::ChannelArguments()));
+
+ for (int i = 0; i < 1000; ++i) {
+ std::cout << "Sending ping " << i << "... ";
+ int result = client.ping(i);
+ if (result != i) {
+ std::cerr << "Invalid pong " << result << " for ping" << i << std::endl;
+ continue;
+ }
+ std::cout << "got pong " << result << std::endl;
+ }
+
+ return 0;
+}
+
diff --git a/examples/grpc/ping-pong-grpc.proto b/examples/grpc/ping-pong-grpc.proto
new file mode 100644
index 000000000..da6d9490c
--- /dev/null
+++ b/examples/grpc/ping-pong-grpc.proto
@@ -0,0 +1,15 @@
+syntax = "proto3";
+
+package PP;
+
+message Ping {
+ int32 count = 1;
+}
+
+message Pong {
+ int32 count = 1;
+}
+
+service MyApi {
+ rpc pingPong(Ping) returns (Pong) {}
+}
diff --git a/examples/grpc/ping-pong-grpc.qbs b/examples/grpc/ping-pong-grpc.qbs
new file mode 100644
index 000000000..8d8909350
--- /dev/null
+++ b/examples/grpc/ping-pong-grpc.qbs
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Ivan Komissarov
+** Contact: abbapoh@gmail.com
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.Utilities
+
+Project {
+ condition: Utilities.versionCompare(qbs.version, "1.14") >= 0
+
+ Application {
+ Depends { name: "cpp" }
+ Depends { name: "protobuf.cpp"; required: false }
+ condition: protobuf.cpp.present
+ protobuf.cpp.useGrpc: true
+ consoleApplication: true
+ cpp.cxxLanguageVersion: "c++17"
+ name: "client"
+ files: "client.cpp"
+ Group {
+ files: "ping-pong-grpc.proto"
+ fileTags: "protobuf.grpc"
+ }
+ }
+
+ Application {
+ Depends { name: "cpp" }
+ Depends { name: "protobuf.cpp"; required: false }
+ condition: protobuf.cpp.present
+ protobuf.cpp.useGrpc: true
+ consoleApplication: true
+ cpp.cxxLanguageVersion: "c++17"
+ name: "server"
+ files: "client.cpp"
+ Group {
+ files: "ping-pong-grpc.proto"
+ fileTags: "protobuf.grpc"
+ }
+ }
+}
diff --git a/examples/grpc/server.cpp b/examples/grpc/server.cpp
new file mode 100644
index 000000000..89d6f0096
--- /dev/null
+++ b/examples/grpc/server.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Ivan Komissarov
+** Contact: abbapoh@gmail.com
+**
+** 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.
+**
+****************************************************************************/
+
+#ifdef __GNUC__
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif // __GNUC__
+
+#include <ping-pong-grpc.grpc.pb.h>
+
+#include <grpc/grpc.h>
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+#include <grpc++/server_context.h>
+#include <grpc++/security/server_credentials.h>
+
+#ifdef __GNUC__
+ #pragma GCC diagnostic pop
+#endif // __GNUC__
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+class Service final : public PP::MyApi::Service
+{
+ grpc::Status pingPong(
+ grpc::ServerContext* context,
+ const PP::Ping* request,
+ PP::Pong* reply) override
+ {
+ (void)context;
+ reply->set_count(request->count());
+ return grpc::Status::OK;
+ }
+};
+
+int main(int, char**)
+{
+ std::string server_address("0.0.0.0:50051");
+ Service service;
+
+ grpc::ServerBuilder builder;
+ builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+ builder.RegisterService(&service);
+ std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
+ std::cout << "Server listening on " << server_address << std::endl;
+ server->Wait();
+ return 0;
+}
+
diff --git a/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs b/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs
index bcdf4efd2..c2db0189f 100644
--- a/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs
+++ b/qbs-resources/modules/qbsbuildconfig/qbsbuildconfig.qbs
@@ -1,5 +1,6 @@
import qbs
import qbs.FileInfo
+import qbs.Utilities
Module {
Depends {
@@ -47,8 +48,17 @@ Module {
"share/qbs/qml-type-descriptions")
Properties {
- condition: project.withCode && enableAddressSanitizer && qbs.toolchain.contains("gcc")
- cpp.cxxFlags: "-fno-omit-frame-pointer"
- cpp.driverFlags: "-fsanitize=address"
+ condition: project.withCode && qbs.toolchain.contains("gcc")
+ cpp.cxxFlags: {
+ var flags = [];
+ if (enableAddressSanitizer)
+ flags.push("-fno-omit-frame-pointer");
+ if (!qbs.toolchain.contains("clang")
+ && Utilities.versionCompare(cpp.compilerVersion, "9") >= 0) {
+ flags.push("-Wno-deprecated-copy", "-Wno-init-list-lifetime");
+ }
+ return flags;
+ }
+ cpp.driverFlags: enableAddressSanitizer ? ["-fsanitize=address"] : []
}
}
diff --git a/scripts/build-qbs-with-qbs.sh b/scripts/build-qbs-with-qbs.sh
index 15a4649b5..5956f1cff 100755
--- a/scripts/build-qbs-with-qbs.sh
+++ b/scripts/build-qbs-with-qbs.sh
@@ -53,6 +53,7 @@ BUILD_OPTIONS="\
modules.qbsbuildconfig.enableAddressSanitizer:true \
modules.qbsbuildconfig.enableProjectFileUpdates:true \
modules.qbsbuildconfig.enableUnitTests:true \
+ project.withExamples:true \
${BUILD_OPTIONS}
"
diff --git a/share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs b/share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs
index 6ebaff8be..693fb6a01 100644
--- a/share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs
@@ -47,14 +47,17 @@ BinaryProbe {
}
configure: {
- var result = PathProbeConfigure.configure(names, nameSuffixes, nameFilter, searchPaths,
- pathSuffixes, platformSearchPaths, environmentPaths,
- platformEnvironmentPaths, pathListSeparator);
- found = result.found;
- candidatePaths = result.candidatePaths;
- path = result.path;
- filePath = result.filePath;
- fileName = result.fileName;
+ var selectors;
+ var _results = PathProbeConfigure.configure(
+ selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths,
+ pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths,
+ pathListSeparator);
+ found = _results.found;
+ var resultFile = _results.files[0];
+ candidatePaths = resultFile.candidatePaths;
+ path = resultFile.path;
+ filePath = resultFile.filePath;
+ fileName = resultFile.fileName;
(nameSuffixes || [""]).forEach(function(suffix) {
var end = _compilerName + suffix;
if (fileName.endsWith(end))
diff --git a/share/qbs/imports/qbs/Probes/NpmProbe.qbs b/share/qbs/imports/qbs/Probes/NpmProbe.qbs
index 4e8124d56..f6a99e826 100644
--- a/share/qbs/imports/qbs/Probes/NpmProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/NpmProbe.qbs
@@ -47,26 +47,28 @@ NodeJsProbe {
if (!interpreterPath)
throw '"interpreterPath" must be specified';
- var result = PathProbeConfigure.configure(names, nameSuffixes, nameFilter, searchPaths,
- pathSuffixes, platformSearchPaths,
- environmentPaths, platformEnvironmentPaths,
- pathListSeparator);
+ var selectors;
+ var results = PathProbeConfigure.configure(
+ selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths,
+ pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths,
+ pathListSeparator);
var v = new ModUtils.EnvironmentVariable("PATH", pathListSeparator,
hostOS.contains("windows"));
v.prepend(interpreterPath);
- result.npmBin = result.found
+ var result = results.files[0];
+ result.npmBin = results.found
? NodeJs.findLocation(result.filePath, "bin", v.value)
: undefined;
- result.npmRoot = result.found
+ result.npmRoot = results.found
? NodeJs.findLocation(result.filePath, "root", v.value)
: undefined;
- result.npmPrefix = result.found
+ result.npmPrefix = results.found
? NodeJs.findLocation(result.filePath, "prefix", v.value)
: undefined;
- found = result.found;
+ found = results.found;
candidatePaths = result.candidatePaths;
path = result.path;
filePath = result.filePath;
diff --git a/share/qbs/imports/qbs/Probes/PathProbe.qbs b/share/qbs/imports/qbs/Probes/PathProbe.qbs
index 1235ce211..d0edea682 100644
--- a/share/qbs/imports/qbs/Probes/PathProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/PathProbe.qbs
@@ -36,6 +36,8 @@ Probe {
property stringList names
property stringList nameSuffixes
property var nameFilter
+ property var candidateFilter
+ property varList selectors
property pathList pathPrefixes
property pathList searchPaths
property stringList pathSuffixes
@@ -52,6 +54,8 @@ Probe {
property string filePath
property string fileName
+ property varList allResults
+
configure: {
if (pathPrefixes)
console.warn("PathProbe.pathPrefixes is deprecated, use searchPaths instead");
@@ -59,11 +63,14 @@ Probe {
console.warn("PathProbe.platformPaths is deprecated, use platformSearchPaths instead");
var _searchPaths = ModUtils.concatAll(pathPrefixes, searchPaths);
var _platformSearchPaths = ModUtils.concatAll(platformPaths, platformSearchPaths);
- var result = PathProbeConfigure.configure(names, nameSuffixes, nameFilter, _searchPaths,
- pathSuffixes, _platformSearchPaths,
- environmentPaths, platformEnvironmentPaths,
- pathListSeparator);
- found = result.found;
+ var results = PathProbeConfigure.configure(selectors, names, nameSuffixes, nameFilter,
+ candidateFilter, _searchPaths, pathSuffixes,
+ _platformSearchPaths, environmentPaths,
+ platformEnvironmentPaths, pathListSeparator);
+ found = results.found;
+ allResults = results.files;
+
+ var result = allResults[0];
candidatePaths = result.candidatePaths;
path = result.path;
filePath = result.filePath;
diff --git a/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs b/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs
index de28fa327..a35e555cc 100644
--- a/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs
@@ -57,16 +57,18 @@ BinaryProbe {
if (!packageManagerRootPath)
throw '"packageManagerRootPath" must be specified';
- var result = PathProbeConfigure.configure(names, nameSuffixes, nameFilter, searchPaths,
- pathSuffixes, platformSearchPaths,
- environmentPaths, platformEnvironmentPaths,
- pathListSeparator);
+ var selectors;
+ var results = PathProbeConfigure.configure(
+ selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths,
+ pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths,
+ pathListSeparator);
var v = new ModUtils.EnvironmentVariable("PATH", pathListSeparator,
hostOS.contains("windows"));
v.prepend(interpreterPath);
- result.version = result.found
+ var result = results.files[0];
+ result.version = results.found
? TypeScript.findTscVersion(result.filePath, v.value)
: undefined;
if (FileInfo.fromNativeSeparators(packageManagerBinPath) !== result.path ||
@@ -74,7 +76,7 @@ BinaryProbe {
result = { found: false };
}
- found = result.found;
+ found = results.found;
candidatePaths = result.candidatePaths;
path = result.path;
filePath = result.filePath;
diff --git a/share/qbs/imports/qbs/Probes/path-probe.js b/share/qbs/imports/qbs/Probes/path-probe.js
index a48a7e4fe..a997f77f2 100644
--- a/share/qbs/imports/qbs/Probes/path-probe.js
+++ b/share/qbs/imports/qbs/Probes/path-probe.js
@@ -33,17 +33,60 @@ var File = require("qbs.File");
var FileInfo = require("qbs.FileInfo");
var ModUtils = require("qbs.ModUtils");
-function configure(names, nameSuffixes, nameFilter, searchPaths, pathSuffixes, platformSearchPaths,
- environmentPaths, platformEnvironmentPaths, pathListSeparator) {
- var result = { found: false, candidatePaths: [] };
- if (!names)
- throw '"names" must be specified';
- var _names = ModUtils.concatAll(names);
- if (nameFilter)
- _names = _names.map(function(n) { return nameFilter(n); });
- _names = ModUtils.concatAll.apply(undefined, _names.map(function(name) {
- return (nameSuffixes || [""]).map(function(suffix) { return name + suffix; });
- }));
+function asStringList(key, value) {
+ if (typeof(value) === "string")
+ return [value];
+ if (Array.isArray(value))
+ return value;
+ throw key + " must be a string or a stringList";
+}
+
+function canonicalSelectors(selectors) {
+ var mapper = function(selector) {
+ if (typeof(selector) === "string")
+ return {names : [selector]};
+ if (Array.isArray(selector))
+ return {names : selector};
+ // dict
+ if (!selector.names)
+ throw '"names" must be specified';
+ selector.names = asStringList("names", selector.names);
+ if (selector.nameSuffixes)
+ selector.nameSuffixes = asStringList("nameSuffixes", selector.nameSuffixes);
+ return selector;
+ };
+ return selectors.map(mapper);
+}
+
+function configure(selectors, names, nameSuffixes, nameFilter, candidateFilter,
+ searchPaths, pathSuffixes, platformSearchPaths, environmentPaths,
+ platformEnvironmentPaths, pathListSeparator) {
+ var result = { found: false, files: [] };
+ if (!selectors && !names)
+ throw '"names" or "selectors" must be specified';
+
+ if (!selectors) {
+ selectors = [
+ {names: names, nameSuffixes: nameSuffixes}
+ ];
+ } else {
+ selectors = canonicalSelectors(selectors);
+ }
+
+ if (nameFilter) {
+ selectors.forEach(function(selector) {
+ selector.names = selector.names.map(nameFilter);
+ });
+ }
+
+ selectors.forEach(function(selector) {
+ selector.names = ModUtils.concatAll.apply(undefined, selector.names.map(function(name) {
+ return (selector.nameSuffixes || [""]).map(function(suffix) {
+ return name + suffix;
+ });
+ }));
+ });
+
// FIXME: Suggest how to obtain paths from system
var _paths = ModUtils.concatAll(searchPaths, platformSearchPaths);
// FIXME: Add getenv support
@@ -56,28 +99,38 @@ function configure(names, nameSuffixes, nameFilter, searchPaths, pathSuffixes, p
var _suffixes = ModUtils.concatAll('', pathSuffixes);
_paths = _paths.map(function(p) { return FileInfo.fromNativeSeparators(p); });
_suffixes = _suffixes.map(function(p) { return FileInfo.fromNativeSeparators(p); });
- for (i = 0; i < _names.length; ++i) {
- for (var j = 0; j < _paths.length; ++j) {
- for (var k = 0; k < _suffixes.length; ++k) {
- var _filePath = FileInfo.joinPaths(_paths[j], _suffixes[k], _names[i]);
- result.candidatePaths.push(_filePath);
- if (File.exists(_filePath)) {
- result.found = true;
- result.filePath = _filePath;
- // Manually specify the path components that constitute _filePath rather
- // than using the FileInfo.path and FileInfo.fileName functions because we
- // want to break _filePath into its constituent parts based on the input
- // originally given by the user. For example, the FileInfo functions would
- // produce a different result if any of the items in the names property
- // contained more than a single path component.
- result.fileName = _names[i];
- result.path = FileInfo.joinPaths(_paths[j], _suffixes[k]);
- return result;
+ var findFile = function(selector) {
+ var file = { found: false, candidatePaths: [] };
+ for (var i = 0; i < selector.names.length; ++i) {
+ for (var j = 0; j < _paths.length; ++j) {
+ for (var k = 0; k < _suffixes.length; ++k) {
+ var _filePath = FileInfo.joinPaths(_paths[j], _suffixes[k], selector.names[i]);
+ file.candidatePaths.push(_filePath);
+ if (File.exists(_filePath)
+ && (!candidateFilter || candidateFilter(_filePath))) {
+ file.found = true;
+ file.filePath = _filePath;
+
+ // Manually specify the path components that constitute _filePath rather
+ // than using the FileInfo.path and FileInfo.fileName functions because we
+ // want to break _filePath into its constituent parts based on the input
+ // originally given by the user. For example, the FileInfo functions would
+ // produce a different result if any of the items in the names property
+ // contained more than a single path component.
+ file.fileName = selector.names[i];
+ file.path = FileInfo.joinPaths(_paths[j], _suffixes[k]);
+ return file;
+ }
}
}
}
- }
+
+ return file;
+ };
+
+ result.files = selectors.map(findFile);
+ result.found = result.files.reduce(function(acc, value) { return acc && value.found }, true);
return result;
}
diff --git a/share/qbs/modules/cpp/iar.js b/share/qbs/modules/cpp/iar.js
index 646826e8a..3098c88f6 100644
--- a/share/qbs/modules/cpp/iar.js
+++ b/share/qbs/modules/cpp/iar.js
@@ -64,7 +64,7 @@ function dumpMacros(compilerFilePath, tag) {
var args = [ inFilePath, "--predef_macros", outFilePath ];
if (tag && tag === "cpp")
- args.push("--ec++");
+ args.push("--c++");
var p = new Process();
p.exec(compilerFilePath, args, true);
@@ -84,7 +84,7 @@ function dumpDefaultPaths(compilerFilePath, tag) {
var args = [ inFilePath, "--preinclude", "." ];
if (tag === "cpp")
- args.push("--ec++");
+ args.push("--c++");
var p = new Process();
// This process should return an error, don't throw
diff --git a/share/qbs/modules/cpp/ios-gcc.qbs b/share/qbs/modules/cpp/ios-gcc.qbs
index 735766650..0ff99679f 100644
--- a/share/qbs/modules/cpp/ios-gcc.qbs
+++ b/share/qbs/modules/cpp/ios-gcc.qbs
@@ -50,8 +50,8 @@ DarwinGCC {
: "-iphoneos_version_min"
libcxxAvailable: base
- && minimumDarwinVersion
- && Utilities.versionCompare(minimumDarwinVersion, "5") >= 0
+ && (!minimumDarwinVersion
+ || Utilities.versionCompare(minimumDarwinVersion, "5") >= 0)
platformObjcFlags: base.concat(simulatorObjcFlags)
platformObjcxxFlags: base.concat(simulatorObjcFlags)
diff --git a/share/qbs/modules/protobuf/cpp/protobufcpp.qbs b/share/qbs/modules/protobuf/cpp/protobufcpp.qbs
index 2b6e94e83..0c511f2aa 100644
--- a/share/qbs/modules/protobuf/cpp/protobufcpp.qbs
+++ b/share/qbs/modules/protobuf/cpp/protobufcpp.qbs
@@ -2,6 +2,7 @@ import qbs
import qbs.File
import qbs.FileInfo
import qbs.Probes
+import qbs.ModUtils
import "../protobufbase.qbs" as ProtobufBase
import "../protobuf.js" as HelperFunctions
@@ -9,23 +10,68 @@ ProtobufBase {
property string includePath: includeProbe.path
property string libraryPath: libraryProbe.path
+ property bool useGrpc: false
+
+ property string grpcIncludePath: grpcIncludeProbe.path
+ property string grpcLibraryPath: grpcLibraryProbe.path
+
Depends { name: "cpp" }
- cpp.libraryPaths: [libraryPath]
- cpp.dynamicLibraries: qbs.targetOS.contains("unix") ? ["protobuf", "pthread"] : ["protobuf"]
- cpp.includePaths: [outputDir, includePath]
+ property path grpcPluginPath: grpcPluginProbe.filePath
+
+ Probes.BinaryProbe {
+ condition: useGrpc
+ id: grpcPluginProbe
+ names: "grpc_cpp_plugin"
+ }
+
+ cpp.libraryPaths: {
+ var result = [libraryPath];
+ if (useGrpc)
+ result.push(grpcLibraryPath);
+ return result;
+ }
+ cpp.dynamicLibraries: {
+ var result = ["protobuf"];
+ if (qbs.targetOS.contains("unix"))
+ result.push("pthread");
+ if (useGrpc)
+ result.push("grpc++");
+ return result;
+ }
+ cpp.includePaths: {
+ var result = [outputDir, includePath];
+ if (useGrpc)
+ result.push("grpcIncludePath");
+ return result;
+ }
Rule {
- inputs: ["protobuf.input"]
+ inputs: ["protobuf.input", "protobuf.grpc"]
outputFileTags: ["hpp", "cpp"]
outputArtifacts: {
- return [
- HelperFunctions.cppArtifact(input.protobuf.cpp, product, input, "hpp", ".pb.h"),
- HelperFunctions.cppArtifact(input.protobuf.cpp, product, input, "cpp", ".pb.cc")
- ];
+ var result = [
+ HelperFunctions.cppArtifact(input.protobuf.cpp, product, input, "hpp", ".pb.h"),
+ HelperFunctions.cppArtifact(input.protobuf.cpp, product, input, "cpp", ".pb.cc")
+ ];
+ if (input.fileTags.contains("protobuf.grpc")) {
+ result.push(
+ HelperFunctions.cppArtifact(input.protobuf.cpp, product, input, "hpp", ".grpc.pb.h"),
+ HelperFunctions.cppArtifact(input.protobuf.cpp, product, input, "cpp", ".grpc.pb.cc"));
+ }
+
+ return result;
}
- prepare: HelperFunctions.doPrepare(input.protobuf.cpp, product, input, outputs, "cpp")
+ prepare: {
+ var result = HelperFunctions.doPrepare(
+ input.protobuf.cpp, product, input, outputs, "cpp");
+ if (input.fileTags.contains("protobuf.grpc")) {
+ result = ModUtils.concatAll(result, HelperFunctions.doPrepareGrpc(
+ input.protobuf.cpp, product, input, outputs, "cpp"));
+ }
+ return result;
+ }
}
validateFunc: {
@@ -35,6 +81,15 @@ ProtobufBase {
throw "Can't find cpp protobuf include files. Please set the includePath property.";
if (!HelperFunctions.checkPath(libraryPath))
throw "Can't find cpp protobuf library. Please set the libraryPath property.";
+
+ if (useGrpc) {
+ if (!File.exists(grpcPluginPath))
+ throw "Can't find grpc_cpp_plugin plugin. Please set the grpcPluginPath property.";
+ if (!HelperFunctions.checkPath(grpcIncludePath))
+ throw "Can't find grpc++ include files. Please set the grpcIncludePath property.";
+ if (!HelperFunctions.checkPath(grpcLibraryPath))
+ throw "Can't find grpc++ library. Please set the grpcLibraryPath property.";
+ }
}
}
@@ -47,4 +102,15 @@ ProtobufBase {
id: libraryProbe
names: "protobuf"
}
+
+ Probes.IncludeProbe {
+ id: grpcIncludeProbe
+ pathSuffixes: "grpc++"
+ names: "grpc++.h"
+ }
+
+ Probes.LibraryProbe {
+ id: grpcLibraryProbe
+ names: "grpc++"
+ }
}
diff --git a/share/qbs/modules/protobuf/protobuf.js b/share/qbs/modules/protobuf/protobuf.js
index 576a5ec07..511f5a6c6 100644
--- a/share/qbs/modules/protobuf/protobuf.js
+++ b/share/qbs/modules/protobuf/protobuf.js
@@ -109,3 +109,28 @@ function doPrepare(module, product, input, outputs, lang)
cmd.description = "generating " + lang + " files for " + input.fileName;
return [cmd];
}
+
+function doPrepareGrpc(module, product, input, outputs, lang)
+{
+ var outputDir = module.outputDir;
+ var args = [];
+
+ args.push("--grpc_out", outputDir);
+ args.push("--plugin=protoc-gen-grpc=" + module.grpcPluginPath);
+
+ var importPaths = module.importPaths;
+ if (importPaths.length === 0)
+ importPaths = [FileInfo.path(input.filePath)];
+ importPaths.forEach(function(path) {
+ if (!FileInfo.isAbsolutePath(path))
+ path = FileInfo.joinPaths(product.sourceDirectory, path);
+ args.push("--proto_path", path);
+ });
+
+ args.push(input.filePath);
+
+ var cmd = new Command(module.protocBinary, args);
+ cmd.highlight = "codegen";
+ cmd.description = "generating " + lang + " files for " + input.fileName;
+ return [cmd];
+}
diff --git a/src/lib/corelib/tools/launchersocket.cpp b/src/lib/corelib/tools/launchersocket.cpp
index 948fbca4f..4373b10b8 100644
--- a/src/lib/corelib/tools/launchersocket.cpp
+++ b/src/lib/corelib/tools/launchersocket.cpp
@@ -135,6 +135,7 @@ void LauncherSocket::handleError(const QString &error)
void LauncherSocket::handleRequests()
{
+ QBS_ASSERT(isReady(), return);
std::lock_guard<std::mutex> locker(m_requestsMutex);
for (const QByteArray &request : qAsConst(m_requests))
m_socket->write(request);
diff --git a/src/lib/corelib/tools/qttools.h b/src/lib/corelib/tools/qttools.h
index 4cb39527e..b465e3d9e 100644
--- a/src/lib/corelib/tools/qttools.h
+++ b/src/lib/corelib/tools/qttools.h
@@ -50,9 +50,11 @@ class QProcessEnvironment;
QT_END_NAMESPACE
namespace std {
+#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
template<> struct hash<QString> {
std::size_t operator()(const QString &s) const { return qHash(s); }
};
+#endif
template<typename T1, typename T2> struct hash<std::pair<T1, T2>>
{
diff --git a/src/lib/library.pri b/src/lib/library.pri
index 4ae171c93..11427b097 100644
--- a/src/lib/library.pri
+++ b/src/lib/library.pri
@@ -32,7 +32,7 @@ VERSION = $${QBS_VERSION}
linux {
# Turn off absurd qmake's soname "logic" and directly add the linker flag.
QMAKE_LFLAGS_SONAME =
- QMAKE_LFLAGS = -Wl,-soname=lib$${TARGET}.so.$${QBS_VERSION_MAJ}.$${QBS_VERSION_MIN}
+ QMAKE_LFLAGS += -Wl,-soname=lib$${TARGET}.so.$${QBS_VERSION_MAJ}.$${QBS_VERSION_MIN}
}
win32 {
diff --git a/static-res.pro b/static-res.pro
index 86816bbf0..cbf9aa9d2 100644
--- a/static-res.pro
+++ b/static-res.pro
@@ -5,8 +5,9 @@ else: qbsbindir = bin
envSpec =
unix:qbs_disable_rpath {
+ include(src/library_dirname.pri)
!isEmpty(QBS_DESTDIR): qbslibdir = $$QBS_DESTDIR
- else: qbslibdir = $$OUT_PWD/lib
+ else: qbslibdir = $$OUT_PWD/$$QBS_LIBRARY_DIRNAME
macos: envVar = DYLD_LIBRARY_PATH
else: envVar = LD_LIBRARY_PATH
oldVal = $$getenv($$envVar)
diff --git a/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs b/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs
index d7baf8c8e..fbab6d0b1 100644
--- a/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs
+++ b/tests/auto/blackbox/testdata-apple/xcode/xcode-project.qbs
@@ -1,5 +1,5 @@
Project {
- property stringList sdks: []
+ property var sdks: {}
Product {
Depends { name: "xcode" }
@@ -14,7 +14,27 @@ Project {
console.info("Latest SDK version: " + xcode.latestSdkVersion);
console.info("Available SDK names: " + xcode.availableSdkNames.join(", "));
console.info("Available SDK versions: " + xcode.availableSdkVersions.join(", "));
- console.info("Actual SDK list: " + project.sdks.join(", "));
+
+ var targetOsToKey = function(targetOS) {
+ if (targetOS.contains("ios"))
+ return "iphoneos";
+ if (targetOS.contains("ios-simulator"))
+ return "iphonesimulator";
+ if (targetOS.contains("macos"))
+ return "macosx";
+ if (targetOS.contains("tvos"))
+ return "appletvos";
+ if (targetOS.contains("tvos-simulator"))
+ return "appletvsimulator";
+ if (targetOS.contains("watchos"))
+ return "watchos";
+ if (targetOS.contains("watchos-simulator"))
+ return "watchossimulator";
+ throw "Unsupported OS" + targetOS;
+ }
+
+ var actualList = project.sdks[targetOsToKey(qbs.targetOS)];
+ console.info("Actual SDK list: " + actualList.join(", "));
var msg = "Unexpected SDK list [" + xcode.availableSdkVersions.join(", ") + "]";
var testArraysEqual = function(a, b) {
@@ -29,7 +49,7 @@ Project {
}
}
- testArraysEqual(project.sdks, xcode.availableSdkVersions);
+ testArraysEqual(actualList, xcode.availableSdkVersions);
}
}
}
diff --git a/tests/auto/blackbox/testdata/grpc/grpc.cpp b/tests/auto/blackbox/testdata/grpc/grpc.cpp
new file mode 100644
index 000000000..81995601d
--- /dev/null
+++ b/tests/auto/blackbox/testdata/grpc/grpc.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Ivan Komissarov
+** Contact: abbapoh@gmail.com
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include <grpc.grpc.pb.h>
+
+class ServiceImpl final : public Qbs::Grpc::Service
+{
+ grpc::Status doWork(
+ grpc::ServerContext* context,
+ const Qbs::Request* request,
+ Qbs::Response* reply) override
+ {
+ (void)context;
+ reply->set_name(request->name());
+ return grpc::Status::OK;
+ }
+};
+
+int main(int, char**)
+{
+ return 0;
+}
diff --git a/tests/auto/blackbox/testdata/grpc/grpc.proto b/tests/auto/blackbox/testdata/grpc/grpc.proto
new file mode 100644
index 000000000..631006bad
--- /dev/null
+++ b/tests/auto/blackbox/testdata/grpc/grpc.proto
@@ -0,0 +1,15 @@
+syntax = "proto3";
+
+package Qbs;
+
+message Request {
+ string name = 1;
+}
+
+message Response {
+ string name = 1;
+}
+
+service Grpc {
+ rpc doWork(Request) returns (Response) {}
+}
diff --git a/tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs b/tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs
new file mode 100644
index 000000000..8ee3dd9c9
--- /dev/null
+++ b/tests/auto/blackbox/testdata/grpc/grpc_cpp.qbs
@@ -0,0 +1,26 @@
+import qbs
+
+CppApplication {
+ name: "grpc_cpp"
+ consoleApplication: true
+ condition: hasDependencies
+
+ Depends { name: "cpp" }
+ cpp.cxxLanguageVersion: "c++11"
+ cpp.warningLevel: "none"
+
+ Depends { name: "protobuf.cpp"; required: false }
+ protobuf.cpp.useGrpc: true
+
+ property bool hasDependencies: {
+ console.info("has grpc: " + protobuf.cpp.present);
+ return protobuf.cpp.present;
+ }
+
+ files: "grpc.cpp"
+
+ Group {
+ files: "grpc.proto"
+ fileTags: "protobuf.grpc"
+ }
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/BaseApp.qbs b/tests/auto/blackbox/testdata/path-probe/BaseApp.qbs
new file mode 100644
index 000000000..84c00c240
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/BaseApp.qbs
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com).
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.Probes
+
+CppApplication {
+
+ property varList inputSelectors
+ property varList inputNames
+ property varList inputNameSuffixes
+ property pathList inputSearchPaths
+ property var inputNameFilter
+ property var inputCandidateFilter
+
+ property stringList outputFilePaths
+
+ Probes.PathProbe {
+ id: probe
+ selectors: inputSelectors
+ names: inputNames
+ nameSuffixes: inputNameSuffixes
+ nameFilter: inputNameFilter
+ candidateFilter: inputCandidateFilter
+ searchPaths: inputSearchPaths
+ }
+
+ property bool validate: {
+ var compareArrays = function(lhs, rhs) {
+ if (lhs.length !== rhs.length)
+ return false;
+ for (var i = 0; i < lhs.length; ++i) {
+ if (lhs[i] !== rhs[i])
+ return false;
+ }
+ return true;
+ };
+
+ if (!probe.found)
+ throw "Probe failed to find files";
+
+ if (outputFilePaths) {
+ var actual = probe.allResults.map(function(file) { return file.filePath; });
+ if (!compareArrays(actual, outputFilePaths))
+ throw "Invalid filePaths: actual = " + actual + ", expected = " + outputFilePaths;
+ }
+ }
+
+ files: ["main.cpp"]
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/bin/super-tool.1 b/tests/auto/blackbox/testdata/path-probe/bin/super-tool.1
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/bin/super-tool.1
diff --git a/tests/auto/blackbox/testdata/path-probe/bin/tool b/tests/auto/blackbox/testdata/path-probe/bin/tool
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/bin/tool
diff --git a/tests/auto/blackbox/testdata/path-probe/bin/tool.1 b/tests/auto/blackbox/testdata/path-probe/bin/tool.1
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/bin/tool.1
diff --git a/tests/auto/blackbox/testdata/path-probe/bin/tool.2 b/tests/auto/blackbox/testdata/path-probe/bin/tool.2
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/bin/tool.2
diff --git a/tests/auto/blackbox/testdata/path-probe/bin/tool.3 b/tests/auto/blackbox/testdata/path-probe/bin/tool.3
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/bin/tool.3
diff --git a/tests/auto/blackbox/testdata/path-probe/bin/tool.4 b/tests/auto/blackbox/testdata/path-probe/bin/tool.4
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/bin/tool.4
diff --git a/tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs b/tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs
new file mode 100644
index 000000000..a65256a68
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/candidate-filter.qbs
@@ -0,0 +1,12 @@
+import qbs.FileInfo
+
+BaseApp {
+ inputNames: ["tool.1", "tool.2"]
+ inputSearchPaths: "bin"
+ outputFilePaths: ["bin/tool.2"]
+ inputCandidateFilter: {
+ return function(f) {
+ return FileInfo.fileName(f) == "tool.2";
+ }
+ }
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/main.cpp b/tests/auto/blackbox/testdata/path-probe/main.cpp
new file mode 100644
index 000000000..76e819701
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/main.cpp
@@ -0,0 +1 @@
+int main() { return 0; }
diff --git a/tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs b/tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs
new file mode 100644
index 000000000..b112db44d
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/mult-files-mult-suffixes.qbs
@@ -0,0 +1,8 @@
+BaseApp {
+ inputSelectors: [
+ {names : "tool", nameSuffixes: [".1", ".2"]},
+ {names : "super-tool", nameSuffixes: [".1"]},
+ ]
+ inputSearchPaths: "bin"
+ outputFilePaths: ["bin/tool.1", "bin/super-tool.1"]
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs b/tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs
new file mode 100644
index 000000000..60c56e6b4
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/mult-files-mult-variants.qbs
@@ -0,0 +1,9 @@
+BaseApp {
+ inputSelectors: [
+ "tool",
+ ["tool.1", "tool.2"],
+ {names : ["tool.3", "tool.4"]},
+ ]
+ inputSearchPaths: "bin"
+ outputFilePaths: ["bin/tool", "bin/tool.1", "bin/tool.3"]
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs b/tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs
new file mode 100644
index 000000000..5e4fc27ca
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/mult-files-suffixes.qbs
@@ -0,0 +1,8 @@
+BaseApp {
+ inputSelectors: [
+ {names : "tool", nameSuffixes: ".2"},
+ {names : "super-tool", nameSuffixes: ".1"},
+ ]
+ inputSearchPaths: "bin"
+ outputFilePaths: ["bin/tool.2", "bin/super-tool.1"]
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/mult-files.qbs b/tests/auto/blackbox/testdata/path-probe/mult-files.qbs
new file mode 100644
index 000000000..08727ac01
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/mult-files.qbs
@@ -0,0 +1,10 @@
+BaseApp {
+ inputSelectors: [
+ "tool.1",
+ ["tool.2"],
+ {names : "tool.3"},
+ {names : ["tool.4"]}
+ ]
+ inputSearchPaths: "bin"
+ outputFilePaths: ["bin/tool.1", "bin/tool.2", "bin/tool.3", "bin/tool.4"]
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/name-filter.qbs b/tests/auto/blackbox/testdata/path-probe/name-filter.qbs
new file mode 100644
index 000000000..406988fed
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/name-filter.qbs
@@ -0,0 +1,10 @@
+BaseApp {
+ inputNames: "tool"
+ inputSearchPaths: "bin"
+ inputNameFilter: {
+ return function(n) {
+ return n + ".2"
+ };
+ }
+ outputFilePaths: ["bin/tool.2"]
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs b/tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs
new file mode 100644
index 000000000..aaa27042c
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/non-existent-selector.qbs
@@ -0,0 +1,8 @@
+BaseApp {
+ inputSelectors: [
+ "tool.1",
+ "nonexistent",
+ "tool.2",
+ ]
+ inputSearchPaths: "bin"
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/non-existent.qbs b/tests/auto/blackbox/testdata/path-probe/non-existent.qbs
new file mode 100644
index 000000000..f0c58fa6c
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/non-existent.qbs
@@ -0,0 +1,4 @@
+BaseApp {
+ inputNames: "nonexistent"
+ inputSearchPaths: "bin"
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs b/tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs
new file mode 100644
index 000000000..992a0bea4
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/single-file-mult-variants.qbs
@@ -0,0 +1,5 @@
+BaseApp {
+ inputNames: ["tool.1", "tool.2"]
+ inputSearchPaths: "bin"
+ outputFilePaths: ["bin/tool.1"]
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs b/tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs
new file mode 100644
index 000000000..697665242
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/single-file-selector-array.qbs
@@ -0,0 +1,5 @@
+BaseApp {
+ inputSelectors: ["tool"]
+ inputSearchPaths: "bin"
+ outputFilePaths: ["bin/tool"]
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs b/tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs
new file mode 100644
index 000000000..d57700baf
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/single-file-selector.qbs
@@ -0,0 +1,5 @@
+BaseApp {
+ inputSelectors: "tool"
+ inputSearchPaths: "bin"
+ outputFilePaths: ["bin/tool"]
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs b/tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs
new file mode 100644
index 000000000..4442e719a
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/single-file-suffixes.qbs
@@ -0,0 +1,6 @@
+BaseApp {
+ inputNames: "tool"
+ inputSearchPaths: "bin"
+ inputNameSuffixes: [".1", ".2"]
+ outputFilePaths: ["bin/tool.1"]
+}
diff --git a/tests/auto/blackbox/testdata/path-probe/single-file.qbs b/tests/auto/blackbox/testdata/path-probe/single-file.qbs
new file mode 100644
index 000000000..3590e7664
--- /dev/null
+++ b/tests/auto/blackbox/testdata/path-probe/single-file.qbs
@@ -0,0 +1,5 @@
+BaseApp {
+ inputNames: "tool"
+ inputSearchPaths: "bin"
+ outputFilePaths: ["bin/tool"]
+}
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
index 84322a7c7..f87889155 100644
--- a/tests/auto/blackbox/tst_blackbox.cpp
+++ b/tests/auto/blackbox/tst_blackbox.cpp
@@ -2719,6 +2719,37 @@ void TestBlackbox::overrideProjectProperties()
QCOMPARE(runQbs(params), 0);
}
+void TestBlackbox::pathProbe_data()
+{
+ QTest::addColumn<QString>("projectFile");
+ QTest::addColumn<bool>("successExpected");
+ QTest::newRow("non-existent") << QString("non-existent.qbs") << false;
+ QTest::newRow("non-existent-selector.qbs") << QString("non-existent-selector.qbs") << false;
+ QTest::newRow("single-file") << QString("single-file.qbs") << true;
+ QTest::newRow("single-file-selector") << QString("single-file-selector.qbs") << true;
+ QTest::newRow("single-file-selector-array") << QString("single-file-selector-array.qbs") << true;
+ QTest::newRow("single-file-mult-variants") << QString("single-file-mult-variants.qbs") << true;
+ QTest::newRow("mult-files") << QString("mult-files.qbs") << true;
+ QTest::newRow("mult-files-mult-variants") << QString("mult-files-mult-variants.qbs") << true;
+ QTest::newRow("single-file-suffixes") << QString("single-file-suffixes.qbs") << true;
+ QTest::newRow("mult-files-suffixes") << QString("mult-files-suffixes.qbs") << true;
+ QTest::newRow("mult-files-mult-suffixes") << QString("mult-files-mult-suffixes.qbs") << true;
+ QTest::newRow("name-filter") << QString("name-filter.qbs") << true;
+ QTest::newRow("candidate-filter") << QString("candidate-filter.qbs") << true;
+}
+
+void TestBlackbox::pathProbe()
+{
+ QDir::setCurrent(testDataDir + "/path-probe");
+ QFETCH(QString, projectFile);
+ QFETCH(bool, successExpected);
+ rmDirR(relativeBuildDir());
+
+ QbsRunParameters buildParams("build", QStringList{"-f", projectFile});
+ buildParams.expectFailure = !successExpected;
+ QCOMPARE(runQbs(buildParams) == 0, successExpected);
+}
+
void TestBlackbox::pchChangeTracking()
{
QDir::setCurrent(testDataDir + "/pch-change-tracking");
@@ -6792,6 +6823,29 @@ void TestBlackbox::groupsInModules()
QCOMPARE(output.readAll().trimmed(), QByteArray("diamond"));
}
+void TestBlackbox::grpc_data()
+{
+ QTest::addColumn<QString>("projectFile");
+ QTest::newRow("cpp") << QString("grpc_cpp.qbs");
+}
+
+void TestBlackbox::grpc()
+{
+ QDir::setCurrent(testDataDir + "/grpc");
+ QFETCH(QString, projectFile);
+ rmDirR(relativeBuildDir());
+ QbsRunParameters resolveParams("resolve", QStringList{"-f", projectFile});
+ QCOMPARE(runQbs(resolveParams), 0);
+ const bool withGrpc = m_qbsStdout.contains("has grpc: true");
+ const bool withoutGrpc = m_qbsStdout.contains("has grpc: false");
+ QVERIFY2(withGrpc || withoutGrpc, m_qbsStdout.constData());
+ if (withoutGrpc)
+ QSKIP("grpc module not present");
+
+ QbsRunParameters runParams;
+ QCOMPARE(runQbs(runParams), 0);
+}
+
void TestBlackbox::ico()
{
QDir::setCurrent(testDataDir + "/ico");
diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h
index 5b3adcbe2..0a14c418c 100644
--- a/tests/auto/blackbox/tst_blackbox.h
+++ b/tests/auto/blackbox/tst_blackbox.h
@@ -119,6 +119,8 @@ private slots:
void generator();
void generator_data();
void groupsInModules();
+ void grpc_data();
+ void grpc();
void ico();
void importAssignment();
void importChangeTracking();
@@ -205,6 +207,8 @@ private slots:
void outOfDateMarking();
void outputArtifactAutoTagging();
void overrideProjectProperties();
+ void pathProbe_data();
+ void pathProbe();
void pchChangeTracking();
void perGroupDefineInExportItem();
void pkgConfigProbe();
diff --git a/tests/auto/blackbox/tst_blackboxapple.cpp b/tests/auto/blackbox/tst_blackboxapple.cpp
index d9cabe270..96cd70b58 100644
--- a/tests/auto/blackbox/tst_blackboxapple.cpp
+++ b/tests/auto/blackbox/tst_blackboxapple.cpp
@@ -33,6 +33,7 @@
#include <tools/profile.h>
#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonobject.h>
#include <QtXml/qdom.h>
#include <regex>
@@ -718,12 +719,38 @@ void TestBlackboxApple::infoPlist()
params.arguments = QStringList() << "-f" << "infoplist.qbs";
QCOMPARE(runQbs(params), 0);
- QFile infoplist(relativeProductBuildDir("infoplist") + "/infoplist.app/Contents/Info.plist");
+ auto infoplistPath = relativeProductBuildDir("infoplist")
+ + "/infoplist.app/Contents/Info.plist";
+ if (!QFile::exists(infoplistPath))
+ infoplistPath = relativeProductBuildDir("infoplist") + "/infoplist.app/Info.plist";
+ QVERIFY(QFile::exists(infoplistPath));
+ QProcess plutil;
+ plutil.start("plutil", {
+ QStringLiteral("-convert"),
+ QStringLiteral("json"),
+ infoplistPath
+ });
+ QVERIFY2(plutil.waitForStarted(), qPrintable(plutil.errorString()));
+ QVERIFY2(plutil.waitForFinished(), qPrintable(plutil.errorString()));
+ QVERIFY2(plutil.exitCode() == 0, qPrintable(plutil.readAllStandardError().constData()));
+
+ QFile infoplist(infoplistPath);
QVERIFY(infoplist.open(QIODevice::ReadOnly));
- const QByteArray fileContents = infoplist.readAll();
- QVERIFY2(fileContents.contains("<key>LSMinimumSystemVersion</key>"), fileContents.constData());
- QVERIFY2(fileContents.contains("<string>10.7</string>"), fileContents.constData());
- QVERIFY2(fileContents.contains("<key>NSPrincipalClass</key>"), fileContents.constData());
+ QJsonParseError error;
+ const auto json = QJsonDocument::fromJson(infoplist.readAll(), &error);
+ QCOMPARE(error.error, QJsonParseError::NoError);
+ QVERIFY(json.isObject());
+ // common values
+ QCOMPARE(json.object().value(QStringLiteral("CFBundleIdentifier")),
+ QStringLiteral("org.example.infoplist"));
+ QCOMPARE(json.object().value(QStringLiteral("CFBundleName")), QStringLiteral("infoplist"));
+ QCOMPARE(json.object().value(QStringLiteral("CFBundleExecutable")),
+ QStringLiteral("infoplist"));
+
+ if (!json.object().contains(QStringLiteral("SDKROOT"))) { // macOS-specific values
+ QCOMPARE(json.object().value("LSMinimumSystemVersion"), QStringLiteral("10.7"));
+ QVERIFY(json.object().contains("NSPrincipalClass"));
+ }
}
void TestBlackboxApple::objcArc()
@@ -758,16 +785,28 @@ void TestBlackboxApple::xcode()
sdks.insert({ match[1], match[2] });
}
- auto range = sdks.equal_range("macosx");
- QStringList sdkValues;
- for (auto i = range.first; i != range.second; ++i)
- sdkValues.push_back(QString::fromStdString(i->second));
+ const auto getSdksByType = [&sdks]()
+ {
+ QStringList result;
+ std::string sdkType;
+ QStringList sdkValues;
+ for (const auto &sdk: sdks) {
+ if (!sdkType.empty() && sdkType != sdk.first) {
+ result.append(QStringLiteral("%1:['%2']")
+ .arg(QString::fromStdString(sdkType), sdkValues.join("','")));
+ sdkValues.clear();
+ }
+ sdkType = sdk.first;
+ sdkValues.append(QString::fromStdString(sdk.second));
+ }
+ return result;
+ };
QDir::setCurrent(testDataDir + "/xcode");
QbsRunParameters params;
params.arguments = (QStringList()
<< (QStringLiteral("modules.xcode.developerPath:") + developerPath)
- << (QStringLiteral("project.sdks:['") + sdkValues.join("','") + "']"));
+ << (QStringLiteral("project.sdks:{") + getSdksByType().join(",") + "}"));
QCOMPARE(runQbs(params), 0);
}