From e405665318a7a666a945929eb6ef7829af804557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 16 Jun 2015 17:14:53 +0200 Subject: iOS: Refactor xcodebuild exclusive build logic into standalone makefile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of going to qmake to generate the makefile that we want, we write the makefile directly and include it from the generated makefile. This leaves us with a single top level makefile for handling exclusive builds through xcodebuild, and covers all the various build configurations in a unified manner. It also allows for improved test device handling. Change-Id: I66851f181ac4da2c8938645e0aa95ffa0fee33c7 Reviewed-by: Tor Arne Vestbø --- .../macx-ios-clang/features/testcase_targets.prf | 3 + mkspecs/macx-ios-clang/features/xcodebuild.prf | 90 ++++++-------------- mkspecs/macx-ios-clang/ios_destinations.sh | 55 +++++++++++++ mkspecs/macx-ios-clang/xcodebuild.mk | 96 ++++++++++++++++++++++ 4 files changed, 177 insertions(+), 67 deletions(-) create mode 100644 mkspecs/macx-ios-clang/features/testcase_targets.prf create mode 100755 mkspecs/macx-ios-clang/ios_destinations.sh create mode 100644 mkspecs/macx-ios-clang/xcodebuild.mk (limited to 'mkspecs/macx-ios-clang') diff --git a/mkspecs/macx-ios-clang/features/testcase_targets.prf b/mkspecs/macx-ios-clang/features/testcase_targets.prf new file mode 100644 index 0000000000..e0a2922c3f --- /dev/null +++ b/mkspecs/macx-ios-clang/features/testcase_targets.prf @@ -0,0 +1,3 @@ +# For the xcodebuild wrapper makefile we deal with test targets manually +!xcodebuild: \ + load(testcase_targets) diff --git a/mkspecs/macx-ios-clang/features/xcodebuild.prf b/mkspecs/macx-ios-clang/features/xcodebuild.prf index 627e1e2930..b897432a43 100644 --- a/mkspecs/macx-ios-clang/features/xcodebuild.prf +++ b/mkspecs/macx-ios-clang/features/xcodebuild.prf @@ -14,80 +14,36 @@ RESOURCES = INSTALLS = QMAKE_EXTRA_COMPILERS = -!build_pass { - # Top level makefile that aggregates all exclusive builds +!mkpath($$OUT_PWD): \ + error("Failed to create $$OUT_PWD") - !mkpath($$OUT_PWD): \ - error("Failed to create $$OUT_PWD") +args = +for(arg, QMAKE_ARGS): \ + args += $$system_quote($$arg) - args = - for(arg, QMAKE_ARGS): \ - args += $$system_quote($$arg) +cmd = "$$QMAKE_QMAKE $$args $$system_quote($$_PRO_FILE_) -spec macx-xcode" +debug(1, "Generating Xcode project in $$OUT_PWD using '$$cmd'") +system("cd $$system_quote($$OUT_PWD) && $$cmd") - cmd = "$$QMAKE_QMAKE $$args $$system_quote($$_PRO_FILE_) -spec macx-xcode" - debug(1, "Generating Xcode project in $$OUT_PWD using '$$cmd'") - system("cd $$system_quote($$OUT_PWD) && $$cmd") +# Subtargets - distclean_files += $${TARGET}.xcodeproj +for(build, BUILDS): \ + SUBTARGETS += $$eval($${build}.target) +QMAKE_EXTRA_VARIABLES += SUBTARGETS - # Pretend we have a target, even though our template is aux - CONFIG += have_target +CONFIG += no_default_goal_deps -} else { - # Leaf makefile for a single exclusive build +QMAKE_EXTRA_INCLUDES += $$shell_quote($$QMAKESPEC/xcodebuild.mk) - iphonesimulator: \ - sdk = iphonesimulator - else: \ - sdk = iphoneos +# Distclean - debug: \ - cfg = debug - else: \ - cfg = release +distfiles = $${TARGET}.xcodeproj +for(build, BUILDS): \ + distfiles += $$title($$eval($${build}.target)) +distclean_xcodebuild.commands = -$(DEL_FILE) -R $$distfiles - for(action, $$list(build install clean test)) { - equals(action, build) { - action_target_suffix = - action_target = all - } else: equals(action, test) { - action_target_suffix = -check - action_target = check - } else { - action_target_suffix = -$$action - action_target = $$action - } - - target = $${sdk}-$${cfg}$${action_target_suffix} - - xcodebuild = "xcodebuild $$action -scheme $(TARGET) -sdk $$sdk -configuration $$title($$cfg)" - - equals(action, test):equals(sdk, iphoneos) { - AVAILABLE_DEVICE_IDS = "$(shell system_profiler SPUSBDataType | sed -n -E -e '/(iPhone|iPad|iPod)/,/Serial/s/ *Serial Number: *(.+)/\1/p')" - CUSTOM_DEVICE_IDS = "$(filter $(EXPORT_AVAILABLE_DEVICE_IDS), $(IOS_TEST_DEVICE_IDS))" - TEST_DEVICE_IDS = "$(strip $(if $(EXPORT_CUSTOM_DEVICE_IDS), $(EXPORT_CUSTOM_DEVICE_IDS), $(EXPORT_AVAILABLE_DEVICE_IDS)))" - - QMAKE_EXTRA_VARIABLES += AVAILABLE_DEVICE_IDS CUSTOM_DEVICE_IDS TEST_DEVICE_IDS - - xcodebuild = "@$(if $(EXPORT_TEST_DEVICE_IDS),"\ - "echo Running tests on $(words $(EXPORT_TEST_DEVICE_IDS)) device\\(s\\): && ("\ - "$(foreach deviceid, $(EXPORT_TEST_DEVICE_IDS),"\ - "(echo Testing on device ID '$(deviceid)' ... && $${xcodebuild} -destination 'platform=iOS,id=$(deviceid)' && echo) &&"\ - ") echo Tests completed successfully on all devices"\ - "), $(error No iOS devices connected, please connect at least one device that can be used for testing.))" - } - - $${target}.commands = $$xcodebuild - QMAKE_EXTRA_TARGETS += $$target - - $${action_target}.depends += $$target - QMAKE_EXTRA_TARGETS *= $${action_target} - } - - # Remove build dir - distclean_files += $$title($$cfg)-$${sdk} -} - -distclean_xcodebuild.commands = -$(DEL_FILE) -R $$distclean_files -distclean.depends += distclean_xcodebuild +distclean.depends += clean_all distclean_xcodebuild QMAKE_EXTRA_TARGETS += distclean distclean_xcodebuild + +# Empty exclusive builds, we've set them up manually +BUILDS = diff --git a/mkspecs/macx-ios-clang/ios_destinations.sh b/mkspecs/macx-ios-clang/ios_destinations.sh new file mode 100755 index 0000000000..aebf8f6403 --- /dev/null +++ b/mkspecs/macx-ios-clang/ios_destinations.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +############################################################################# +## +## Copyright (C) 2015 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is the build configuration utility of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL21$ +## 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. +## +## 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. +## +## $QT_END_LICENSE$ +## +############################################################################# + +booted_simulator=$(xcrun simctl list devices | grep -v unavailable | grep Booted | perl -lne 'print $1 if /\((.*?)\)/') +echo "IPHONESIMULATOR_DEVICES = $booted_simulator" + +xcodebuild test -scheme $1 -destination 'id=0' -destination-timeout 1 2>&1| sed -n 's/{ \(platform:.*\) }/\1/p' | while read destination; do + id=$(echo $destination | sed -n -E 's/.*id:([^ ,]+).*/\1/p') + echo $destination | tr ',' '\n' | while read keyval; do + key=$(echo $keyval | cut -d ':' -f 1 | tr '[:lower:]' '[:upper:]') + val=$(echo $keyval | cut -d ':' -f 2) + echo "%_$id: DESTINATION_${key} = $val" + + if [ $key = 'PLATFORM' ]; then + if [ "$val" = "iOS" ]; then + echo "IPHONEOS_DEVICES += $id" + elif [ "$val" = "iOS Simulator" -a "$id" != "$booted_simulator" ]; then + echo "IPHONESIMULATOR_DEVICES += $id" + fi + fi + done + echo +done diff --git a/mkspecs/macx-ios-clang/xcodebuild.mk b/mkspecs/macx-ios-clang/xcodebuild.mk new file mode 100644 index 0000000000..f50010abc1 --- /dev/null +++ b/mkspecs/macx-ios-clang/xcodebuild.mk @@ -0,0 +1,96 @@ + +# We don't want xcodebuild to run in parallel +.NOTPARALLEL: + +# Functions +targets = $(foreach target, $(EXPORT_SUBTARGETS), $(target)-$(strip $(1))) +toupper = $(shell echo $1 | tr '[:lower:]' '[:upper:]') +tolower = $(shell echo $1 | tr '[:upper:]' '[:lower:]') +basesdk = $(shell echo $1 | sed 's/[0-9.]*$$//') + +# Explicit comma variable +, := , + +# Default targets +first: build +all: build_all + +.DEFAULT_GOAL = first + +# Top level targets +build: build_first +clean: clean_first +install: install_first +check: check_first +distclean: clean_all + +$(EXPORT_SUBTARGETS): % : %-build + +# Generic targets +%_first: $(firstword $(call targets, %)) ; +%_all: $(call targets, %) ; + +# Actions +%-build: ACTION = build +%-build: xcodebuild-% ; + +%-clean: ACTION = clean +%-clean: xcodebuild-% ; + +%-install: ACTION = install +%-install: xcodebuild-% ; + +# Limit check to a single configuration +%-iphoneos-check: check-iphoneos ; +%-iphonesimulator-check: check-iphonesimulator ; + +# SDK +%-iphoneos: SDK = iphoneos +%-iphonesimulator: SDK = iphonesimulator + +# Configuration +release-%: CONFIGURATION = Release +debug-%: CONFIGURATION = Debug + +# Test and build (device) destinations +ifneq ($(filter check%,$(MAKECMDGOALS)),) + ifeq ($(DEVICES),) + $(info Enumerating test destinations (you may override this by setting DEVICES explicitly), please wait...) + SPECDIR := $(dir $(lastword $(MAKEFILE_LIST))) + DESTINATIONS_INCLUDE = /tmp/ios_destinations.mk + $(shell $(SPECDIR)/ios_destinations.sh $(TARGET) > $(DESTINATIONS_INCLUDE)) + include $(DESTINATIONS_INCLUDE) + endif +endif + +%-iphonesimulator: DEVICES = $(firstword $(IPHONESIMULATOR_DEVICES)) +%-iphoneos: DEVICES = $(IPHONEOS_DEVICES) + +IPHONEOS_GENERIC_DESTINATION := "generic/platform=iOS" +IPHONESIMULATOR_GENERIC_DESTINATION := "id=$(shell xcrun simctl list devices | grep -v unavailable | perl -lne 'print $$1 if /\((.*?)\)/' | tail -n 1)" + +DESTINATION = $(if $(DESTINATION_ID),"id=$(DESTINATION_ID)",$(value $(call toupper,$(call basesdk,$(SDK)))_GENERIC_DESTINATION)) + +# Xcodebuild + +DESTINATION_MESSAGE = "Running $(call tolower,$(CONFIGURATION)) $(ACTION) \ + on '$(DESTINATION_NAME)' ($(DESTINATION_ID))$(if $(DESTINATION_OS),$(,) $(DESTINATION_PLATFORM) $(DESTINATION_OS),)" + +xcodebuild-%: + @$(if $(DESTINATION_NAME), echo $(DESTINATION_MESSAGE),) + xcodebuild $(ACTION) -scheme $(TARGET) $(if $(SDK), -sdk $(SDK),) $(if $(CONFIGURATION), -configuration $(CONFIGURATION),) $(if $(DESTINATION), -destination $(DESTINATION) -destination-timeout 1,) + +xcodebuild-check-device_%: DESTINATION_ID=$(lastword $(subst _, ,$@)) + +# Special check target (requires SECONDEXPANSION due to devices) +.SECONDEXPANSION: +check-%: ACTION = test +check-%: $$(foreach device, $$(DEVICES), xcodebuild-check-device_$$(device)) ; + @echo $(if $^, Ran $(call tolower,$(CONFIGURATION)) tests on $(words $^) $(SDK) destination\(s\): $(DEVICES), No compatible test devices found for \'$(SDK)\' SDK && false) + +# Determined by device +check-%: SDK = + +# Default to debug for testing +check-%: CONFIGURATION = Debug + -- cgit v1.2.3