diff options
author | Ivan Komissarov <ABBAPOH@gmail.com> | 2018-08-10 01:28:06 +0300 |
---|---|---|
committer | Ivan Komissarov <ABBAPOH@gmail.com> | 2018-11-22 11:20:38 +0000 |
commit | 68578a4bc3f1667530f674db8d01933775ebc4ff (patch) | |
tree | 99b801bdce1b955b44ea5ba8b30dddc903ccf9a0 | |
parent | 428cc6188fb4f99bca8522530ed400357cfe38ec (diff) |
Add protobuf.cpp and protobuf.objc modules
These modules implement google protobuf support for QBS for c++ and
objective-c languages
[ChangeLog] Added protobuf support for C++ and Objective-C.
Fixes: QBS-563
Change-Id: I4bb7e0bdfc1e09ea26c0cd3d3739a741ff834e5d
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
30 files changed, 1353 insertions, 6 deletions
diff --git a/doc/reference/modules/protobufcpp-module.qdoc b/doc/reference/modules/protobufcpp-module.qdoc new file mode 100644 index 000000000..d4dd36f68 --- /dev/null +++ b/doc/reference/modules/protobufcpp-module.qdoc @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \contentspage index.html + \qmltype protobuf.cpp + \inqmlmodule QbsModules + \since Qbs 1.13 + + \brief Provides support for protocol buffers for the C++ language. + + The \c protobuf.cpp module provides support for generating C++ headers and + sources from proto definition files using the \c protoc tool. + + \section2 Relevant File Tags + + \table + \header + \li Tag + \li Auto-tagged File Names + \li Since + \li Description + \row + \li \c{"protobuf.input"} + \li \c{*.proto} + \li 1.13.0 + \li Source files with this tag are considered inputs to the \c protoc compiler. + \endtable +*/ + +/*! + \qmlproperty string protobuf.cpp::protocBinary + + The command which to invoke when compiling proto definition files. + + \defaultvalue \c auto-detected +*/ + +/*! + \qmlproperty pathList protobuf.cpp::importPaths + + The list of imports that are passed to the \c protoc tool via the \c --proto_path option. + These imports should contain the proto files - they are used to determine + the relative structure of the generated files. + \note The paths are passed to \c protoc in the same order as specified in this property and + \c protoc output may differ depending on that order. + + \defaultvalue \c [] +*/ + +/*! + \qmlproperty string protobuf.cpp::includePath + + The path where protobuf C++ headers are located. Set this property to override the + default location. + + \defaultvalue \c auto-detected +*/ + +/*! + \qmlproperty string protobuf.cpp::libraryPath + + The path where the protobuf C++ library is located. Set this property to override the + default location. + + \defaultvalue \c auto-detected +*/ diff --git a/doc/reference/modules/protobufobjc-module.qdoc b/doc/reference/modules/protobufobjc-module.qdoc new file mode 100644 index 000000000..02155f492 --- /dev/null +++ b/doc/reference/modules/protobufobjc-module.qdoc @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \contentspage index.html + \qmltype protobuf.objc + \inqmlmodule QbsModules + \since Qbs 1.13 + + \brief Provides support for protocol buffers for the Objective-C language. + + The \c protobuf.objc module provides support for generating Objective-C + headers and sources from proto definition files using the \c protoc tool. + + \section2 Relevant File Tags + + \table + \header + \li Tag + \li Auto-tagged File Names + \li Since + \li Description + \row + \li \c{"protobuf.input"} + \li \c{*.proto} + \li 1.13.0 + \li Source files with this tag are considered inputs to the \c protoc compiler. + \endtable +*/ + +/*! + \qmlproperty string protobuf.objc::protocBinary + + The command which to invoke when compiling proto definition files. + + \defaultvalue \c auto-detected +*/ + +/*! + \qmlproperty pathList protobuf.cpp::importPaths + + The list of imports that are passed to the \c protoc tool via the \c --proto_path option. + These imports should contain the proto files - they are used to determine + the relative structure of the generated files. + \note The paths are passed to \c protoc in the same order as specified in this property and + \c protoc output may differ depending on that order. + + \defaultvalue \c [] +*/ + +/*! + \qmlproperty string protobuf.objc::includePath + + The path where protobuf Objective-C headers are located. Set this property + to override the default location. + + \note If a \l{protobuf.objc::frameworkPath}{framework} is present, this property + has no effect. + + \defaultvalue \c auto-detected +*/ + +/*! + \qmlproperty string protobuf.objc::libraryPath + + \note If a \l{protobuf.objc::frameworkPath}{framework} is present, this property + has no effect. + + \defaultvalue \c auto-detected +*/ + +/*! + \qmlproperty string protobuf.objc::frameworkPath + + The path where \c Protobuf.framework is located. Set this property to override the + default location. + + \defaultvalue \c auto-detected +*/ diff --git a/examples/examples.qbs b/examples/examples.qbs index 0e4e5052c..4e51bdbaf 100644 --- a/examples/examples.qbs +++ b/examples/examples.qbs @@ -62,5 +62,7 @@ Project { "helloworld-minimal/hello.qbs", "helloworld-qt/hello.qbs", "install-bundle/install-bundle.qbs", + "protobuf/cpp/addressbook.qbs", + "protobuf/objc/addressbook.qbs", ] } diff --git a/examples/protobuf/cpp/README.md b/examples/protobuf/cpp/README.md new file mode 100644 index 000000000..f0e1b1a93 --- /dev/null +++ b/examples/protobuf/cpp/README.md @@ -0,0 +1,13 @@ +### Addressbook c++ example + +This example shows how to build a cpp application that uses Google protobuf. + +In order to build this example, you'll need to have a protobuf headers and library installed in the system in locations where QBS can find them. + +On Linux, you can install a package to the system. + +On macOS, you can use brew or compile and install protobuf manually: +- to /usr/local/ +- to any folder, say /Users/<USER>/protobuf. Then you'll need to set protobuf.libraryPath: "/Users/<USER>/protobuf/lib" and protobuf.includePath: "/Users/<USER>/protobuf/include" + +On Windows, you have to compile and install protobuf manually to any folder and use libraryPath and includePath as shown above diff --git a/examples/protobuf/cpp/addressbook.qbs b/examples/protobuf/cpp/addressbook.qbs new file mode 100644 index 000000000..bd5afd377 --- /dev/null +++ b/examples/protobuf/cpp/addressbook.qbs @@ -0,0 +1,18 @@ +import qbs + +CppApplication { + name: "addressbook_cpp" + consoleApplication: true + condition: protobuf.present + + Depends { name: "cpp" } + cpp.cxxLanguageVersion: "c++11" + + Depends { id: protobuf; name: "protobuf.cpp"; required: false } + + files: [ + "../shared/addressbook.proto", + "main.cpp", + "README.md", + ] +} diff --git a/examples/protobuf/cpp/main.cpp b/examples/protobuf/cpp/main.cpp new file mode 100644 index 000000000..703a9d302 --- /dev/null +++ b/examples/protobuf/cpp/main.cpp @@ -0,0 +1,171 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <ctime> +#include <fstream> +#include <google/protobuf/util/time_util.h> +#include <iostream> +#include <string> + +#include "addressbook.pb.h" + +using google::protobuf::util::TimeUtil; + +int printUsage(char *argv0) +{ + std::cerr << "Usage: " << argv0 << "add|list ADDRESS_BOOK_FILE" << std::endl; + return -1; +} + +std::string readString(const std::string &promt) +{ + std::string result; + std::cout << promt; + std::getline(std::cin, result); + return result; +} + +// This function fills in a Person message based on user input. +void promptForAddress(tutorial::Person* person) +{ + std::cout << "Enter person ID number: "; + int id; + std::cin >> id; + person->set_id(id); + std::cin.ignore(256, '\n'); + + *person->mutable_name() = readString("Enter name: "); + + const auto email = readString("Enter email address (blank for none): "); + if (!email.empty()) + person->set_email(email); + + while (true) { + const auto number = readString("Enter a phone number (or leave blank to finish): "); + if (number.empty()) + break; + + tutorial::Person::PhoneNumber *phone_number = person->add_phones(); + phone_number->set_number(number); + + const auto type = readString("Is this a mobile, home, or work phone? "); + if (type == "mobile") + phone_number->set_type(tutorial::Person::MOBILE); + else if (type == "home") + phone_number->set_type(tutorial::Person::HOME); + else if (type == "work") + phone_number->set_type(tutorial::Person::WORK); + else + std::cout << "Unknown phone type. Using default." << std::endl; + } + *person->mutable_last_updated() = TimeUtil::SecondsToTimestamp(time(NULL)); +} + +// Iterates though all people in the AddressBook and prints info about them. +void listPeople(const tutorial::AddressBook& address_book) +{ + for (int i = 0; i < address_book.people_size(); i++) { + const tutorial::Person& person = address_book.people(i); + + std::cout << "Person ID: " << person.id() << std::endl; + std::cout << " Name: " << person.name() << std::endl; + if (person.email() != "") { + std::cout << " E-mail address: " << person.email() << std::endl; + } + + for (int j = 0; j < person.phones_size(); j++) { + const tutorial::Person::PhoneNumber& phone_number = person.phones(j); + + switch (phone_number.type()) { + case tutorial::Person::MOBILE: + std::cout << " Mobile phone #: "; + break; + case tutorial::Person::HOME: + std::cout << " Home phone #: "; + break; + case tutorial::Person::WORK: + std::cout << " Work phone #: "; + break; + default: + std::cout << " Unknown phone #: "; + break; + } + std::cout << phone_number.number() << std::endl; + } + if (person.has_last_updated()) { + std::cout << " Updated: " << TimeUtil::ToString(person.last_updated()) << std::endl; + } + } +} + +int main(int argc, char* argv[]) { + // Verify that the version of the library that we linked against is + // compatible with the version of the headers we compiled against. + GOOGLE_PROTOBUF_VERIFY_VERSION; + + if (argc != 3) + return printUsage(argv[0]); + + tutorial::AddressBook address_book; + + // Read the existing address book. + std::fstream input(argv[2], std::ios::in | std::ios::binary); + if (!input) { + std::cout << argv[2] << ": File not found." << std::endl; + } else if (!address_book.ParseFromIstream(&input)) { + std::cerr << "Failed to parse address book." << std::endl; + return -1; + } + + const std::string mode(argv[1]); + if (mode == "add") { + // Add an address. + promptForAddress(address_book.add_people()); + + if (!input) + std::cout << "Creating a new file." << std::endl; + + // Write the new address book back to disk. + std::fstream output(argv[2], std::ios::out | std::ios::trunc | std::ios::binary); + if (!address_book.SerializeToOstream(&output)) { + std::cerr << "Failed to write address book." << std::endl; + return -1; + } + } else if (mode == "list") { + listPeople(address_book); + } else { + return printUsage(argv[0]); + } + + // Optional: Delete all global objects allocated by libprotobuf. + google::protobuf::ShutdownProtobufLibrary(); + + return 0; +} diff --git a/examples/protobuf/objc/README.md b/examples/protobuf/objc/README.md new file mode 100644 index 000000000..c0fc7c0e5 --- /dev/null +++ b/examples/protobuf/objc/README.md @@ -0,0 +1,5 @@ +### Addressbook objc example + +This example shows how to build an objective-c application that uses Google protobuf. + +In order to build this example, you'll need to have a ProtocolBuffers library or framework installed in the system. diff --git a/examples/protobuf/objc/addressbook.qbs b/examples/protobuf/objc/addressbook.qbs new file mode 100644 index 000000000..f087113d9 --- /dev/null +++ b/examples/protobuf/objc/addressbook.qbs @@ -0,0 +1,15 @@ +import qbs + +CppApplication { + name: "addressbook_objc" + consoleApplication: true + condition: protobuf.present && qbs.targetOS.contains("darwin") + + Depends { name: "cpp" } + Depends { id: protobuf; name: "protobuf.objc"; required: false } + + files: [ + "../shared/addressbook.proto", + "main.m", + ] +} diff --git a/examples/protobuf/objc/main.m b/examples/protobuf/objc/main.m new file mode 100644 index 000000000..903799fca --- /dev/null +++ b/examples/protobuf/objc/main.m @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 "Addressbook.pbobjc.h" + +#import <Foundation/Foundation.h> + +int printUsage(char *argv0) +{ + NSString *programName = [[NSString alloc] initWithUTF8String:argv0]; + NSLog(@"%@", [[NSString alloc] initWithFormat:@"Usage: %@ add|list ADDRESS_BOOK_FILE", programName]); + [programName release]; + return -1; +} + +NSString *readString(NSString *promt) +{ + NSLog(@"%@", promt); + NSFileHandle *inputFile = [NSFileHandle fileHandleWithStandardInput]; + NSData *inputData = [inputFile availableData]; + NSString *result = [[[NSString alloc]initWithData:inputData encoding:NSUTF8StringEncoding] autorelease]; + result = [[result stringByTrimmingCharactersInSet: + [NSCharacterSet whitespaceAndNewlineCharacterSet]] autorelease]; + return result; +} + +// This function fills in a Person message based on user input. +void promptForAddress(Person* person) +{ + person.id_p = [readString(@"Enter person ID number:") intValue]; + person.name = readString(@"Enter name:"); + + NSString *email = readString(@"Enter email address (blank for none):"); + if ([email length] != 0) + person.email = email; + + while (true) { + NSString *number = readString(@"Enter a phone number (or leave blank to finish):"); + if ([number length] == 0) + break; + + Person_PhoneNumber* phoneNumber = [[Person_PhoneNumber alloc] init]; + phoneNumber.number = number; + + NSString *type = readString(@"Is this a mobile, home, or work phone?:"); + NSLog(@"\"%@\"", type); + if ([type compare:@"mobile"] == NSOrderedSame) + phoneNumber.type = Person_PhoneType_Mobile; + else if ([type compare:@"home"] == NSOrderedSame) + phoneNumber.type = Person_PhoneType_Home; + else if ([type compare:@"work"] == NSOrderedSame) + phoneNumber.type = Person_PhoneType_Work; + else + NSLog(@"%@", @"Unknown phone type. Using default."); + + [person.phonesArray addObject:phoneNumber]; + } +} + +// Iterates though all people in the AddressBook and prints info about them. +void listPeople(AddressBook *addressBook) +{ + NSArray *people = addressBook.peopleArray; + for (unsigned i = 0; i < [people count]; i++) { + Person *person = [people objectAtIndex:i]; + + NSLog(@"%@", [[[NSString alloc] initWithFormat:@"Person ID: %d", person.id_p] autorelease]); + NSLog(@"%@", [[[NSString alloc] initWithFormat:@"Person name: %@", person.name] autorelease]); + + if ([person.email length] != 0) { + NSLog(@"%@", [[[NSString alloc] initWithFormat:@"E-mail address: %@", person.email] autorelease]); + } + + NSArray *phones = person.phonesArray; + for (unsigned j = 0; j < [phones count]; j++) { + Person_PhoneNumber *phoneNumber = [phones objectAtIndex:j]; + NSString *phonePrefix; + + switch (phoneNumber.type) { + case Person_PhoneType_Mobile: + phonePrefix = @"Mobile phone"; + break; + case Person_PhoneType_Home: + phonePrefix = @"Home phone"; + break; + case Person_PhoneType_Work: + phonePrefix = @"Work phone"; + break; + default: + phonePrefix = @"Unknown phone"; + break; + } + + NSLog(@"%@", [[[NSString alloc] initWithFormat:@" %@ #: %@", phonePrefix, phoneNumber.number] autorelease]); + } + printf("\n"); + } +} + +int main(int argc, char *argv[]) +{ + if (argc != 3) + return printUsage(argv[0]); + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + AddressBook *addressBook;// = [AddressBook alloc]; + NSString *filePath = [[[NSString alloc] initWithUTF8String:argv[2]] autorelease]; + + // Read the existing address book. + NSData *data = [NSData dataWithContentsOfFile:filePath]; + if (!data) { + NSLog(@"%@", [[NSString alloc] initWithFormat:@"%@ : File not found.", filePath]); + addressBook = [[[AddressBook alloc] init] autorelease]; + } else { + NSError *error; + addressBook = [AddressBook parseFromData:data error:&error]; + if (!addressBook) { + NSLog(@"%@", @"Failed to parse address book."); + [pool drain]; + return -1; + } + } + + if (strcmp(argv[1], "add") == 0) { + // Add an address. + Person *person = [[Person alloc] init]; + promptForAddress(person); + [addressBook.peopleArray addObject:person]; + + if (!data) { + NSLog(@"%@", @"Creating a new file."); + } + [[addressBook data] writeToFile:filePath atomically:YES]; + } else if (strcmp(argv[1], "list") == 0) { + listPeople(addressBook); + } else { + [pool drain]; + return printUsage(argv[0]); + } + + [pool drain]; + return 0; +} diff --git a/examples/protobuf/shared/addressbook.proto b/examples/protobuf/shared/addressbook.proto new file mode 100644 index 000000000..b4b33b4c6 --- /dev/null +++ b/examples/protobuf/shared/addressbook.proto @@ -0,0 +1,51 @@ +// See README.txt for information and build instructions. +// +// Note: START and END tags are used in comments to define sections used in +// tutorials. They are not part of the syntax for Protocol Buffers. +// +// To get an in-depth walkthrough of this file and the related examples, see: +// https://developers.google.com/protocol-buffers/docs/tutorials + +// [START declaration] +syntax = "proto3"; +package tutorial; + +import "google/protobuf/timestamp.proto"; +// [END declaration] + +// [START java_declaration] +option java_package = "com.example.tutorial"; +option java_outer_classname = "AddressBookProtos"; +// [END java_declaration] + +// [START csharp_declaration] +option csharp_namespace = "Google.Protobuf.Examples.AddressBook"; +// [END csharp_declaration] + +// [START messages] +message Person { + string name = 1; + int32 id = 2; // Unique ID number for this person. + string email = 3; + + enum PhoneType { + MOBILE = 0; + HOME = 1; + WORK = 2; + } + + message PhoneNumber { + string number = 1; + PhoneType type = 2; + } + + repeated PhoneNumber phones = 4; + + google.protobuf.Timestamp last_updated = 5; +} + +// Our address book file is just one of these. +message AddressBook { + repeated Person people = 1; +} +// [END messages] diff --git a/share/qbs/imports/qbs/Probes/FrameworkProbe.qbs b/share/qbs/imports/qbs/Probes/FrameworkProbe.qbs index 544759150..da5557cc9 100644 --- a/share/qbs/imports/qbs/Probes/FrameworkProbe.qbs +++ b/share/qbs/imports/qbs/Probes/FrameworkProbe.qbs @@ -29,12 +29,12 @@ ****************************************************************************/ PathProbe { - platformPaths: [ - "~/Library/Frameworks", - "/usr/local/lib", - "/Library/Frameworks", - "/System/Library/Frameworks" - ] + platformPaths: (qbs.sysroot ? [qbs.sysroot + "/System/Library/Frameworks"] : []).concat([ + "~/Library/Frameworks", + "/usr/local/lib", + "/Library/Frameworks", + "/System/Library/Frameworks" + ]) nameFilter: { return function(name) { diff --git a/share/qbs/imports/qbs/Probes/LibraryProbe.qbs b/share/qbs/imports/qbs/Probes/LibraryProbe.qbs new file mode 100644 index 000000000..b81a15dcb --- /dev/null +++ b/share/qbs/imports/qbs/Probes/LibraryProbe.qbs @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Ivan Komissarov. +** 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. +** +****************************************************************************/ + +PathProbe { + nameSuffixes: { + if (qbs.targetOS.contains("windows")) + return [".lib"]; + if (qbs.targetOS.contains("macos")) + return [".dylib", ".a"]; + return [".so", ".a"]; + } + platformPaths: qbs.targetOS.contains("unix") ? [ + "/usr/lib", + "/usr/local/lib", + ] : [] + nameFilter: { + if (qbs.targetOS.contains("unix")) { + return function(name) { + return "lib" + name; + } + } else { + return function(name) { + return name; + } + } + } + platformEnvironmentPaths: { + if (qbs.targetOS.contains("windows")) + return [ "PATH" ]; + else + return [ "LIBRARY_PATH" ]; + } +} diff --git a/share/qbs/modules/protobuf/cpp/protobufcpp.qbs b/share/qbs/modules/protobuf/cpp/protobufcpp.qbs new file mode 100644 index 000000000..5cb3257d4 --- /dev/null +++ b/share/qbs/modules/protobuf/cpp/protobufcpp.qbs @@ -0,0 +1,48 @@ +import qbs +import qbs.File +import qbs.FileInfo +import qbs.Probes +import "../protobufbase.qbs" as ProtobufBase +import "../protobuf.js" as HelperFunctions + +ProtobufBase { + property string includePath: includeProbe.path + property string libraryPath: libraryProbe.path + + Depends { name: "cpp" } + + cpp.libraryPaths: [libraryPath] + cpp.dynamicLibraries: qbs.targetOS.contains("unix") ? ["protobuf", "pthread"] : ["protobuf"] + cpp.includePaths: [outputDir, includePath] + + Rule { + inputs: ["protobuf.input"] + 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") + ]; + } + + prepare: HelperFunctions.doPrepare(input.protobuf.cpp, product, input, outputs, "cpp") + } + + validate: { + baseValidate(); + if (!HelperFunctions.checkPath(includePath)) + 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."; + } + + Probes.IncludeProbe { + id: includeProbe + names: "google/protobuf/message.h" + } + + Probes.LibraryProbe { + id: libraryProbe + names: "protobuf" + } +} diff --git a/share/qbs/modules/protobuf/objc/protobufobjc.qbs b/share/qbs/modules/protobuf/objc/protobufobjc.qbs new file mode 100644 index 000000000..c252d9949 --- /dev/null +++ b/share/qbs/modules/protobuf/objc/protobufobjc.qbs @@ -0,0 +1,70 @@ +import qbs +import qbs.File +import qbs.FileInfo +import qbs.Probes +import "../protobufbase.qbs" as ProtobufBase +import "../protobuf.js" as HelperFunctions + +ProtobufBase { + property string includePath: includeProbe.path + property string libraryPath: libraryProbe.path + property string frameworkPath: frameworkProbe.path + + Depends { name: "cpp" } + + // library build + Properties { + condition: !frameworkPath + cpp.includePaths: [outputDir, includePath] + cpp.libraryPaths: [libraryPath] + cpp.frameworks: ["Foundation"] + cpp.dynamicLibraries: ["ProtocolBuffers"] + } + + // framework build + Properties { + condition: frameworkPath + cpp.includePaths: [outputDir] + cpp.frameworkPaths: [frameworkPath] + cpp.frameworks: ["Foundation", "Protobuf"] + cpp.defines: ["GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS"] + } + + Rule { + inputs: ["protobuf.input"] + outputFileTags: ["hpp", "objc"] + outputArtifacts: { + return [ + HelperFunctions.objcArtifact(input.protobuf.objc, product, input, "hpp", ".pbobjc.h"), + HelperFunctions.objcArtifact(input.protobuf.objc, product, input, "objc", ".pbobjc.m") + ]; + } + + prepare: HelperFunctions.doPrepare(input.protobuf.objc, product, input, outputs, "objc") + } + + validate: { + baseValidate(); + if (!HelperFunctions.checkPath(frameworkPath)) { + if (!HelperFunctions.checkPath(includePath)) + throw "Can't find objective-c protobuf include files. Please set the includePath or frameworkPath property."; + if (!HelperFunctions.checkPath(libraryPath)) + throw "Can't find objective-c protobuf library. Please set the libraryPath or frameworkPath property."; + } + } + + Probes.IncludeProbe { + id: includeProbe + names: "GPBMessage.h" + } + + Probes.LibraryProbe { + id: libraryProbe + names: "ProtocolBuffers" + } + + Probes.FrameworkProbe { + id: frameworkProbe + names: ["Protobuf"] + } +} diff --git a/share/qbs/modules/protobuf/protobuf.js b/share/qbs/modules/protobuf/protobuf.js new file mode 100644 index 000000000..576a5ec07 --- /dev/null +++ b/share/qbs/modules/protobuf/protobuf.js @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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. +** +****************************************************************************/ + +var File = require("qbs.File"); +var FileInfo = require("qbs.FileInfo"); + +var checkPath = function(path) { + return path && File.exists(path) +}; + +function toCamelCase(str){ + return str.split('_').map(function(word, index) { + // If it is the first word make sure to lowercase all the chars. + if (index === 0) { + return word.toLowerCase(); + } + // If it is not the first word only upper case the first char and lowercase the rest. + return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); + }).join(''); +} + +function getOutputDir(module, product, input) { + var outputDir = module.outputDir; + var importPaths = module.importPaths; + if (importPaths.length !== 0) { + var canonicalInput = File.canonicalFilePath(FileInfo.path(input.filePath)); + for (var i = 0; i < importPaths.length; ++i) { + path = File.canonicalFilePath(importPaths[i]); + + if (canonicalInput.startsWith(path)) { + return outputDir + "/" + FileInfo.relativePath(path, canonicalInput); + } + } + } + return outputDir; +} + +function cppArtifact(module, product, input, tag, suffix) { + var outputDir = getOutputDir(module, product, input); + return { + fileTags: [tag], + filePath: outputDir + "/" + FileInfo.baseName(input.fileName) + suffix, + cpp: { + includePaths: [].concat(input.cpp.includePaths, outputDir), + warningLevel: "none", + } + }; +} + +function objcArtifact(module, product, input, tag, suffix) { + var outputDir = getOutputDir(module, product, input); + return { + fileTags: [tag], + filePath: outputDir + "/" + toCamelCase(FileInfo.baseName(input.fileName)) + suffix, + cpp: { + includePaths: [].concat(input.cpp.includePaths, outputDir), + warningLevel: "none", + } + } +} + +function doPrepare(module, product, input, outputs, lang) +{ + var outputDir = module.outputDir; + var args = []; + + args.push("--" + lang + "_out", outputDir); + + 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/share/qbs/modules/protobuf/protobufbase.qbs b/share/qbs/modules/protobuf/protobufbase.qbs new file mode 100644 index 000000000..1c2e68800 --- /dev/null +++ b/share/qbs/modules/protobuf/protobufbase.qbs @@ -0,0 +1,30 @@ +import qbs +import qbs.File +import qbs.FileInfo +import qbs.Probes +import "protobuf.js" as HelperFunctions + +Module { + property string protocBinary: protocProbe.filePath + property pathList importPaths: [] + + property string outputDir: product.buildDirectory + "/protobuf" + readonly property string protobufRoot: FileInfo.path(FileInfo.path(protocBinary)) + + readonly property var baseValidate: { + return function() { + if (!File.exists(protocBinary)) + throw "Can't find protoc binary. Please set the protocBinary property or make sure it is found in PATH"; + } + } + + FileTagger { + patterns: ["*.proto"] + fileTags: ["protobuf.input"]; + } + + Probes.BinaryProbe { + id: protocProbe + names: ["protoc"] + } +} diff --git a/tests/auto/blackbox/testdata/protobuf/addressbook.proto b/tests/auto/blackbox/testdata/protobuf/addressbook.proto new file mode 100644 index 000000000..b4b33b4c6 --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/addressbook.proto @@ -0,0 +1,51 @@ +// See README.txt for information and build instructions. +// +// Note: START and END tags are used in comments to define sections used in +// tutorials. They are not part of the syntax for Protocol Buffers. +// +// To get an in-depth walkthrough of this file and the related examples, see: +// https://developers.google.com/protocol-buffers/docs/tutorials + +// [START declaration] +syntax = "proto3"; +package tutorial; + +import "google/protobuf/timestamp.proto"; +// [END declaration] + +// [START java_declaration] +option java_package = "com.example.tutorial"; +option java_outer_classname = "AddressBookProtos"; +// [END java_declaration] + +// [START csharp_declaration] +option csharp_namespace = "Google.Protobuf.Examples.AddressBook"; +// [END csharp_declaration] + +// [START messages] +message Person { + string name = 1; + int32 id = 2; // Unique ID number for this person. + string email = 3; + + enum PhoneType { + MOBILE = 0; + HOME = 1; + WORK = 2; + } + + message PhoneNumber { + string number = 1; + PhoneType type = 2; + } + + repeated PhoneNumber phones = 4; + + google.protobuf.Timestamp last_updated = 5; +} + +// Our address book file is just one of these. +message AddressBook { + repeated Person people = 1; +} +// [END messages] diff --git a/tests/auto/blackbox/testdata/protobuf/addressbook_cpp.qbs b/tests/auto/blackbox/testdata/protobuf/addressbook_cpp.qbs new file mode 100644 index 000000000..797d4174e --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/addressbook_cpp.qbs @@ -0,0 +1,24 @@ +import qbs + +CppApplication { + name: "addressbook_cpp" + consoleApplication: true + condition: protobuf.present + + Depends { name: "cpp" } + cpp.cxxLanguageVersion: "c++11" + + Depends { id: protobuf; name: "protobuf.cpp"; required: false } + Probe { + id: presentProbe + property bool hasModule: protobuf.present + configure: { + console.info("has protobuf: " + hasModule); + } + } + + files: [ + "addressbook.proto", + "main.cpp", + ] +} diff --git a/tests/auto/blackbox/testdata/protobuf/addressbook_objc.qbs b/tests/auto/blackbox/testdata/protobuf/addressbook_objc.qbs new file mode 100644 index 000000000..9ee82c68f --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/addressbook_objc.qbs @@ -0,0 +1,22 @@ +import qbs + +CppApplication { + name: "addressbook_objc" + consoleApplication: true + condition: protobuf.present && qbs.targetOS.contains("darwin") + + Depends { name: "cpp" } + Depends { id: protobuf; name: "protobuf.objc"; required: false } + Probe { + id: presentProbe + property bool hasModule: protobuf.present && qbs.targetOS.contains("darwin") + configure: { + console.info("has protobuf: " + hasModule); + } + } + + files: [ + "addressbook.proto", + "main.m", + ] +} diff --git a/tests/auto/blackbox/testdata/protobuf/import-main.cpp b/tests/auto/blackbox/testdata/protobuf/import-main.cpp new file mode 100644 index 000000000..6d90cdf16 --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/import-main.cpp @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <import.pb.h> + +int main() +{ + MyMessage message; + message.set_msg("msg"); + return 0; +} diff --git a/tests/auto/blackbox/testdata/protobuf/import.proto b/tests/auto/blackbox/testdata/protobuf/import.proto new file mode 100644 index 000000000..d11e83b7a --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/import.proto @@ -0,0 +1,6 @@ +syntax = "proto2"; +import "subdir/myenum.proto"; + +message MyMessage { + required string msg = 1; +} diff --git a/tests/auto/blackbox/testdata/protobuf/import.qbs b/tests/auto/blackbox/testdata/protobuf/import.qbs new file mode 100644 index 000000000..b93e03a1e --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/import.qbs @@ -0,0 +1,26 @@ +import qbs + +CppApplication { + name: "app" + consoleApplication: true + condition: protobuf.cpp.present + + protobuf.cpp.importPaths: [sourceDirectory] + + cpp.cxxLanguageVersion: "c++11" + + Depends { name: "protobuf.cpp"; required: false } + Probe { + id: presentProbe + property bool hasModule: protobuf.cpp.present + configure: { + console.info("has protobuf: " + hasModule); + } + } + + files: [ + "import.proto", + "import-main.cpp", + "subdir/myenum.proto", + ] +} diff --git a/tests/auto/blackbox/testdata/protobuf/main.cpp b/tests/auto/blackbox/testdata/protobuf/main.cpp new file mode 100644 index 000000000..c93c46717 --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/main.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <google/protobuf/util/time_util.h> +#include <string> + +#include "addressbook.pb.h" + +using google::protobuf::util::TimeUtil; + +int main(int /*argc*/, char* /*argv*/[]) { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + tutorial::AddressBook addressBook; + + auto person = addressBook.add_people(); + person->set_name("name"); + person->set_id(1); + person->set_email("email"); + + auto phone_number = person->add_phones(); + phone_number->set_number("number"); + phone_number->set_type(tutorial::Person::MOBILE); + + *person->mutable_last_updated() = TimeUtil::SecondsToTimestamp(time(nullptr)); + + google::protobuf::ShutdownProtobufLibrary(); + + return 0; +} + diff --git a/tests/auto/blackbox/testdata/protobuf/main.m b/tests/auto/blackbox/testdata/protobuf/main.m new file mode 100644 index 000000000..e9d7ce66a --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/main.m @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 "Addressbook.pbobjc.h" + +int main(int argc, char* argv[]) +{ + AddressBook *addressBook = [[AddressBook alloc] init]; + + Person *person = [[Person alloc] init]; + person.name = @"name"; + person.id_p = 1; + person.email = @"email"; + + Person_PhoneNumber *number = [[Person_PhoneNumber alloc] init]; + number.number = @"number"; + number.type = Person_PhoneType_Mobile; + + [addressBook.peopleArray addObject:person]; + [addressBook release]; + + return 0; +} diff --git a/tests/auto/blackbox/testdata/protobuf/needs-import-dir-main.cpp b/tests/auto/blackbox/testdata/protobuf/needs-import-dir-main.cpp new file mode 100644 index 000000000..d6faf9e84 --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/needs-import-dir-main.cpp @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 <needs-import-dir.pb.h> + +int main() +{ + MyMessage message; + message.set_msg("msg"); + return 0; +} diff --git a/tests/auto/blackbox/testdata/protobuf/needs-import-dir.proto b/tests/auto/blackbox/testdata/protobuf/needs-import-dir.proto new file mode 100644 index 000000000..0d0cb6578 --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/needs-import-dir.proto @@ -0,0 +1,6 @@ +syntax = "proto2"; +import "myenum.proto"; + +message MyMessage { + required string msg = 1; +} diff --git a/tests/auto/blackbox/testdata/protobuf/needs-import-dir.qbs b/tests/auto/blackbox/testdata/protobuf/needs-import-dir.qbs new file mode 100644 index 000000000..e95421a9e --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/needs-import-dir.qbs @@ -0,0 +1,27 @@ +import qbs + +CppApplication { + name: "app" + consoleApplication: true + condition: protobuf.cpp.present + + property path theImportDir + protobuf.cpp.importPaths: (theImportDir ? [theImportDir] : []).concat([sourceDirectory]) + + cpp.cxxLanguageVersion: "c++11" + + Depends { name: "protobuf.cpp"; required: false } + Probe { + id: presentProbe + property bool hasModule: protobuf.cpp.present + configure: { + console.info("has protobuf: " + hasModule); + } + } + + files: [ + "needs-import-dir.proto", + "needs-import-dir-main.cpp", + "subdir/myenum.proto", + ] +} diff --git a/tests/auto/blackbox/testdata/protobuf/subdir/myenum.proto b/tests/auto/blackbox/testdata/protobuf/subdir/myenum.proto new file mode 100644 index 000000000..0b82869fc --- /dev/null +++ b/tests/auto/blackbox/testdata/protobuf/subdir/myenum.proto @@ -0,0 +1,6 @@ +syntax = "proto2"; + +enum MyEnum { + VAL1 = 0; + VAL2 = 1; +} diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp index 0302309fb..de0e2c26d 100644 --- a/tests/auto/blackbox/tst_blackbox.cpp +++ b/tests/auto/blackbox/tst_blackbox.cpp @@ -4971,6 +4971,40 @@ void TestBlackbox::propertiesInExportItems() QVERIFY2(m_qbsStderr.isEmpty(), m_qbsStderr.constData()); } +void TestBlackbox::protobuf_data() +{ + QTest::addColumn<QString>("projectFile"); + QTest::addColumn<QStringList>("properties"); + QTest::addColumn<bool>("successExpected"); + QTest::newRow("cpp") << QString("addressbook_cpp.qbs") << QStringList() << true; + QTest::newRow("objc") << QString("addressbook_objc.qbs") << QStringList() << true; + QTest::newRow("import") << QString("import.qbs") << QStringList() << true; + QTest::newRow("missing import dir") << QString("needs-import-dir.qbs") + << QStringList() << false; + QTest::newRow("provided import dir") + << QString("needs-import-dir.qbs") + << QStringList("products.app.theImportDir:subdir") << true; +} + +void TestBlackbox::protobuf() +{ + QDir::setCurrent(testDataDir + "/protobuf"); + QFETCH(QString, projectFile); + QFETCH(QStringList, properties); + QFETCH(bool, successExpected); + rmDirR(relativeBuildDir()); + QbsRunParameters resolveParams("resolve", QStringList{"-f", projectFile} << properties); + QCOMPARE(runQbs(resolveParams), 0); + const bool withProtobuf = m_qbsStdout.contains("has protobuf: true"); + const bool withoutProtobuf = m_qbsStdout.contains("has protobuf: false"); + QVERIFY2(withProtobuf || withoutProtobuf, m_qbsStdout.constData()); + if (withoutProtobuf) + QSKIP("protobuf module not present"); + QbsRunParameters runParams("run"); + runParams.expectFailure = !successExpected; + QCOMPARE(runQbs(runParams) == 0, successExpected); +} + void TestBlackbox::pseudoMultiplexing() { // This is "pseudo-multiplexing" on all platforms that initialize qbs.architectures diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h index 3df507bdc..874690ad2 100644 --- a/tests/auto/blackbox/tst_blackbox.h +++ b/tests/auto/blackbox/tst_blackbox.h @@ -222,6 +222,8 @@ private slots: void propertyPrecedence(); void properQuoting(); void propertiesInExportItems(); + void protobuf_data(); + void protobuf(); void pseudoMultiplexing(); void qbsConfig(); void qbsVersion(); |