1#!/usr/bin/env bash
2
3# ====================================================================
4# Sets the cross compile environment for Xcode/iOS
5#
6# Based upon OpenSSL's setenv-ios.sh  by TH, JW, and SM.
7# Heavily modified by JWW for Crypto++.
8# Modified by JWW for Unbound.
9# ====================================================================
10
11#########################################
12#####        Some validation        #####
13#########################################
14
15# In the past we could mostly infer arch or cpu from the SDK (and
16# mostly vice-versa). Nowadays we need it set for us because Apple
17# platforms can be either 32-bit or 64-bit.
18
19if [ -z "$IOS_SDK" ]; then
20    echo "IOS_SDK is not set. Please set it"
21    [[ "$0" = "${BASH_SOURCE[0]}" ]] && exit 1 || return 1
22fi
23
24if [ -z "$IOS_CPU" ]; then
25    echo "IOS_CPU is not set. Please set it"
26    [[ "$0" = "${BASH_SOURCE[0]}" ]] && exit 1 || return 1
27fi
28
29# cryptest-ios.sh may run this script without sourcing.
30if [ "$0" = "${BASH_SOURCE[0]}" ]; then
31    echo "setenv-ios.sh is usually sourced, but not this time."
32fi
33
34#########################################
35#####    Small Fixups, if needed    #####
36#########################################
37
38if [[ "$IOS_SDK" == "iPhone" ]]; then
39    IOS_SDK=iPhoneOS
40fi
41
42if [[ "$IOS_SDK" == "iPhoneOSSimulator" ]]; then
43    IOS_SDK=iPhoneSimulator
44fi
45
46if [[ "$IOS_SDK" == "TV" || "$IOS_SDK" == "AppleTV" ]]; then
47    IOS_SDK=AppleTVOS
48fi
49
50if [[ "$IOS_SDK" == "Watch" || "$IOS_SDK" == "AppleWatch" ]]; then
51    IOS_SDK=WatchOS
52fi
53
54if [[ "$IOS_CPU" == "aarch64" || "$IOS_CPU" == "armv8"* ]] ; then
55    IOS_CPU=arm64
56fi
57
58########################################
59#####         Environment          #####
60########################################
61
62# The flags below were tested with Xcode 8 on Travis. If
63# you use downlevel versions of Xcode, then you can push
64# xxx-version-min=n lower. For example, Xcode 6 can use
65# -miphoneos-version-min=5.
66
67# iPhones can be either 32-bit or 64-bit
68if [[ "$IOS_SDK" == "iPhoneOS" && "$IOS_CPU" == "armv7"* ]]; then
69    MIN_VER=-miphoneos-version-min=6
70elif [[ "$IOS_SDK" == "iPhoneOS" && "$IOS_CPU" == "arm64" ]]; then
71    MIN_VER=-miphoneos-version-min=6
72
73# Fixups for convenience
74elif [[ "$IOS_SDK" == "iPhoneOS" && "$IOS_CPU" == "i386" ]]; then
75    IOS_SDK=iPhoneSimulator
76    # MIN_VER=-miphoneos-version-min=6
77    MIN_VER=-miphonesimulator-version-min=6
78elif [[ "$IOS_SDK" == "iPhoneOS" && "$IOS_CPU" == "x86_64" ]]; then
79    IOS_SDK=iPhoneSimulator
80    # MIN_VER=-miphoneos-version-min=6
81    MIN_VER=-miphonesimulator-version-min=6
82
83# Simulator builds
84elif [[ "$IOS_SDK" == "iPhoneSimulator" && "$IOS_CPU" == "i386" ]]; then
85    MIN_VER=-miphonesimulator-version-min=6
86elif [[ "$IOS_SDK" == "iPhoneSimulator" && "$IOS_CPU" == "x86_64" ]]; then
87    MIN_VER=-miphonesimulator-version-min=6
88
89# Apple TV can be 32-bit Intel (1st gen), 32-bit ARM (2nd, 3rd gen) or 64-bit ARM (4th gen)
90elif [[ "$IOS_SDK" == "AppleTVOS" && "$IOS_CPU" == "i386" ]]; then
91    MIN_VER=-mappletvos-version-min=6
92elif [[ "$IOS_SDK" == "AppleTVOS" && "$IOS_CPU" == "armv7"* ]]; then
93    MIN_VER=-mappletvos-version-min=6
94elif [[ "$IOS_SDK" == "AppleTVOS" && "$IOS_CPU" == "arm64" ]]; then
95    MIN_VER=-mappletvos-version-min=6
96
97# Simulator builds
98elif [[ "$IOS_SDK" == "AppleTVSimulator" && "$IOS_CPU" == "i386" ]]; then
99    MIN_VER=-mappletvsimulator-version-min=6
100elif [[ "$IOS_SDK" == "AppleTVSimulator" && "$IOS_CPU" == "x86_64" ]]; then
101    MIN_VER=-mappletvsimulator-version-min=6
102
103# Watch can be either 32-bit or 64-bit ARM. TODO: figure out which
104# -mwatchos-version-min=n is needed for arm64. 9 is not enough.
105elif [[ "$IOS_SDK" == "WatchOS" && "$IOS_CPU" == "armv7"* ]]; then
106    MIN_VER=-mwatchos-version-min=6
107elif [[ "$IOS_SDK" == "WatchOS" && "$IOS_CPU" == "arm64" ]]; then
108    MIN_VER=-mwatchos-version-min=10
109
110# Simulator builds. TODO: figure out which -watchos-version-min=n
111# is needed for arm64. 6 compiles and links, but is it correct?
112elif [[ "$IOS_SDK" == "WatchSimulator" && "$IOS_CPU" == "i386" ]]; then
113    MIN_VER=-mwatchsimulator-version-min=6
114elif [[ "$IOS_SDK" == "WatchSimulator" && "$IOS_CPU" == "x86_64" ]]; then
115    MIN_VER=-mwatchsimulator-version-min=6
116
117# And the final catch-all
118else
119    echo "IOS_SDK and IOS_CPU are not valid. Please fix them"
120    [[ "$0" = "${BASH_SOURCE[0]}" ]] && exit 1 || return 1
121fi
122
123#####################################################################
124
125# Xcode 6 and below cannot handle -miphonesimulator-version-min
126# Fix it so the simulator will compile as expected. This trick
127# may work on other SDKs, but it was not tested.
128
129if [ -n "$(command -v xcodebuild 2>/dev/null)" ]; then
130    # Output of xcodebuild is similar to "Xcode 6.2". The first cut gets
131    # the dotted decimal value. The second cut gets the major version.
132    XCODE_VERSION=$(xcodebuild -version 2>/dev/null | head -n 1 | cut -f2 -d" " | cut -f1 -d".")
133    if [ -z "$XCODE_VERSION" ]; then XCODE_VERSION=100; fi
134
135    if [ "$XCODE_VERSION" -le 6 ]; then
136        MIN_VER="${MIN_VER//iphonesimulator/iphoneos}"
137    fi
138fi
139
140#####################################################################
141
142# Allow a user override? I think we should be doing this. The use case is,
143# move /Applications/Xcode somewhere else for a side-by-side installation.
144if [ -z "${XCODE_DEVELOPER-}" ]; then
145  XCODE_DEVELOPER=$(xcode-select -print-path 2>/dev/null)
146fi
147
148if [ ! -d "$XCODE_DEVELOPER" ]; then
149  echo "ERROR: unable to find XCODE_DEVELOPER directory."
150  [ "$0" = "${BASH_SOURCE[0]}" ] && exit 1 || return 1
151fi
152
153# XCODE_DEVELOPER_SDK is the SDK location.
154XCODE_DEVELOPER_SDK="$XCODE_DEVELOPER/Platforms/$IOS_SDK.platform"
155
156if [ ! -d "$XCODE_DEVELOPER_SDK" ]; then
157  echo "ERROR: unable to find XCODE_DEVELOPER_SDK directory."
158  echo "       Is the SDK supported by Xcode and installed?"
159  [ "$0" = "${BASH_SOURCE[0]}" ] && exit 1 || return 1
160fi
161
162# XCODE_TOOLCHAIN is the location of the actual compiler tools.
163if [ -d "$XCODE_DEVELOPER/Toolchains/XcodeDefault.xctoolchain/usr/bin/" ]; then
164  XCODE_TOOLCHAIN="$XCODE_DEVELOPER/Toolchains/XcodeDefault.xctoolchain/usr/bin/"
165elif [ -d "$XCODE_DEVELOPER_SDK/Developer/usr/bin/" ]; then
166  XCODE_TOOLCHAIN="$XCODE_DEVELOPER_SDK/Developer/usr/bin/"
167fi
168
169if [ -z "$XCODE_TOOLCHAIN" ] || [ ! -d "$XCODE_TOOLCHAIN" ]; then
170  echo "ERROR: unable to find Xcode cross-compiler tools."
171  [ "$0" = "${BASH_SOURCE[0]}" ] && exit 1 || return 1
172fi
173
174# XCODE_SDK is the SDK name/version being used - adjust the list as appropriate.
175# For example, remove 4.3, 6.2, and 6.1 if they are not installed. We go back to
176# the 1.0 SDKs because Apple WatchOS uses low numbers, like 2.0 and 2.1.
177XCODE_SDK=
178for i in $(seq -f "%.1f" 30.0 -0.1 1.0)
179do
180    if [ -d "$XCODE_DEVELOPER_SDK/Developer/SDKs/$IOS_SDK$i.sdk" ]; then
181        XCODE_SDK="$IOS_SDK$i.sdk"
182        break
183    fi
184done
185
186# Error checking
187if [ -z "$XCODE_SDK" ]; then
188    echo "ERROR: unable to find a SDK."
189    [ "$0" = "${BASH_SOURCE[0]}" ] && exit 1 || return 1
190fi
191
192IOS_SYSROOT="$XCODE_DEVELOPER_SDK/Developer/SDKs/$XCODE_SDK"
193
194if [ -z "$IOS_SYSROOT" ] || [ ! -d "$IOS_SYSROOT" ]; then
195  echo "ERROR: unable to find IOS_SYSROOT directory."
196  [ "$0" = "${BASH_SOURCE[0]}" ] && exit 1 || return 1
197fi
198
199#####################################################################
200
201# We want to set AR=libtool and ARFLAGS="-static -o",
202# but I am not sure Autotools can handle it.
203CPP=cpp; CC=clang; CXX=clang++; LD=ld
204AS=as; AR=ar; RANLIB=ranlib; STRIP=strip
205
206# Error checking
207if [ ! -e "$XCODE_TOOLCHAIN/$CC" ]; then
208    echo "ERROR: Failed to find iOS clang. Please edit this script."
209    [ "$0" = "${BASH_SOURCE[0]}" ] && exit 1 || return 1
210fi
211
212# Error checking
213if [ ! -e "$XCODE_TOOLCHAIN/$CXX" ]; then
214    echo "ERROR: Failed to find iOS clang++. Please edit this script."
215    [ "$0" = "${BASH_SOURCE[0]}" ] && exit 1 || return 1
216fi
217
218# Error checking
219if [ ! -e "$XCODE_TOOLCHAIN/$RANLIB" ]; then
220    echo "ERROR: Failed to find iOS ranlib. Please edit this script."
221    [ "$0" = "${BASH_SOURCE[0]}" ] && exit 1 || return 1
222fi
223
224# Error checking
225if [ ! -e "$XCODE_TOOLCHAIN/$AR" ]; then
226    echo "ERROR: Failed to find iOS ar. Please edit this script."
227    [ "$0" = "${BASH_SOURCE[0]}" ] && exit 1 || return 1
228fi
229
230# Error checking
231if [ ! -e "$XCODE_TOOLCHAIN/$AS" ]; then
232    echo "ERROR: Failed to find iOS as. Please edit this script."
233    [ "$0" = "${BASH_SOURCE[0]}" ] && exit 1 || return 1
234fi
235
236# Error checking
237if [ ! -e "$XCODE_TOOLCHAIN/$LD" ]; then
238    echo "ERROR: Failed to find iOS ld. Please edit this script."
239    [ "$0" = "${BASH_SOURCE[0]}" ] && exit 1 || return 1
240fi
241
242#####################################################################
243
244LENGTH=${#XCODE_TOOLCHAIN}
245SUBSTR=${PATH:0:$LENGTH}
246if [ "$SUBSTR" != "$XCODE_TOOLCHAIN" ]; then
247    export PATH="$XCODE_TOOLCHAIN":"$PATH"
248fi
249
250#####################################################################
251
252export CPP CC CXX LD AS AR RANLIB STRIP
253export IOS_SYSROOT
254export CFLAGS="-arch $IOS_CPU $MIN_VER --sysroot=$IOS_SYSROOT"
255export CXXFLAGS="-arch $IOS_CPU $MIN_VER -stdlib-libc++ --sysroot=$IOS_SYSROOT"
256
257#####################################################################
258
259echo "XCODE_TOOLCHAIN: $XCODE_TOOLCHAIN"
260
261echo "CPP: $(command -v "$CPP")"
262echo "CC: $(command -v "$CC")"
263echo "CXX: $(command -v "$CXX")"
264echo "LD: $(command -v "$LD")"
265echo "AS: $(command -v "$AS")"
266echo "AR: $(command -v "$AR")"
267
268echo "IOS_SYSROOT: $IOS_SYSROOT"
269
270echo "CPPFLAGS: $CPPFLAGS"
271echo "CFLAGS: $CFLAGS"
272echo "CXXFLAGS: $CXXFLAGS"
273
274[ "$0" = "${BASH_SOURCE[0]}" ] && exit 0 || return 0
275