1#!/bin/sh
2
3#
4# This shell-script is argument-compatible with xcrun(1) as invoked
5# by xnu's Makefiles. Additionally, it supports caching tools
6# in the local build directory. It is tightly coupled to exactly
7# the queries that MakeInc.cmd makes, in exactly the order it makes
8# them. ./tools/remote_build.sh invokes this indirectly in caching
9# mode, so '$(XCRUN) -sdk foo -find bar' copies 'bar' from wherever
10# it is on-disk into ./BUILD/BuildData, and returns that path to the
11# caller. In '-u' mode on a remote build server, cache tools
12# relative to the current build directory are returned without
13# actually calling through to xcrun(1), since the remote build
14# server may not even have Xcode installed.
15#
16
17SDKROOT=""
18FINDTOOL=""
19SDKQUERY=""
20VERBOSE=""
21OBJROOT=""
22CACHE=0
23
24# echo "Calling $0 $@" 1>&2
25
26while [ $# -gt 0 ]; do
27    case "$1" in
28	-c)
29	    CACHE=1
30	    shift
31	    OBJROOT="$1"
32	    shift
33	    ;;
34	-u)
35	    CACHE=0
36	    shift
37	    OBJROOT="$1"
38	    shift
39	    ;;
40	-sdk)
41	    shift
42	    SDKROOT="$1"
43	    shift
44	    ;;
45	-verbose)
46	    VERBOSE="$1"
47	    shift
48	    set -x
49	    ;;
50	-find)
51	    shift
52	    FINDTOOL="$1"
53	    shift
54	    ;;
55	-show-sdk-path)
56	    SDKQUERY="$1"
57	    shift
58	    ;;
59	-show-sdk-platform-path)
60	    SDKQUERY="$1"
61	    shift
62	    ;;
63	-show-sdk-version)
64	    SDKQUERY="$1"
65	    shift
66	    ;;
67	*)
68	    echo "Unrecognized argument $1" 1>&2
69	    exit 1
70    esac    
71done
72
73function CreateFile() {
74    local string="$1"
75    local filepath="$2"
76    echo "${string}" > "${filepath}.new"
77    cmp -s "${filepath}" "${filepath}.new"
78    if [ $? -eq 0 ]; then
79	rm "${filepath}.new"
80    else
81	mv "${filepath}.new" "${filepath}"
82    fi
83}
84
85if [ $CACHE -eq 1 ]; then
86
87    if [ -n "$SDKQUERY" ]; then
88	# MakeInc.cmd makes SDK queries up-front first. Generally the
89	# SDKROOT that is an input to these are one of:
90	# "macosx" => Host SDK
91	# "iphonehostXXX" => iPhone Host SDK
92	# other shortcut or full path => Target SDK
93	#
94	# Once an initial lookup is made, subsequent SDKROOTs for
95	# that same SDK may use a full path or cached path
96	SDKTYPE=""
97	case "$SDKROOT" in
98	    macosx)
99		SDKTYPE="host"
100		;;
101	    iphonehost*)
102		SDKTYPE="iphonehost"
103		;;
104	    *)
105		if [ -f "$SDKROOT/.sdktype" ]; then
106		    SDKTYPE=`cat "$SDKROOT/.sdktype"`
107		else
108		    SDKTYPE="target"
109		fi
110		;;
111	esac
112
113	# A cached SDK path can be passed to xcrun, so
114	# we need the original on-disk path
115	if [ -f "$SDKROOT/.realsdkpath" ]; then
116	    REALSDKROOT=`cat "$SDKROOT/.realsdkpath"`
117	else
118	    REALSDKROOT="$SDKROOT"
119	fi
120
121	SDKPROPERTY=`/usr/bin/xcrun $VERBOSE -sdk "$REALSDKROOT" "$SDKQUERY"`
122	if [ $? -ne 0 ]; then
123	    exit $?
124	fi
125	
126	case $SDKQUERY in
127	    -show-sdk-path)
128		# Cache the SDK locally, and transform the resulting SDKPROPERTY
129		if [ -z "$SDKPROPERTY" ]; then
130		    SDKPROPERTY="/"
131		    SDKNAME="Slash.sdk"
132		else
133		    SDKNAME=$(basename "${SDKPROPERTY}")
134		fi
135		mkdir -p "${OBJROOT}/BuildTools/${SDKNAME}"
136		mkdir -p "${OBJROOT}/BuildTools/${SDKNAME}/usr/include"
137		rsync -aq --exclude=c++ --exclude=php --exclude=soc "${SDKPROPERTY}/usr/include/" "${OBJROOT}/BuildTools/${SDKNAME}/usr/include/"
138		if [ "$SDKTYPE" = "iphonehost" ]; then
139		    mkdir -p "${OBJROOT}/BuildTools/${SDKNAME}/usr/local/lib/system"
140		    rsync -aq "${SDKPROPERTY}/usr/local/lib/system/" "${OBJROOT}/BuildTools/${SDKNAME}/usr/local/lib/system/"
141		else
142		    mkdir -p "${OBJROOT}/BuildTools/${SDKNAME}/usr/lib"
143		    rsync -aq "${SDKPROPERTY}/usr/lib/libSystem"* "${OBJROOT}/BuildTools/${SDKNAME}/usr/lib/"
144		    rsync -aq "${SDKPROPERTY}/usr/lib/libc++"* "${OBJROOT}/BuildTools/${SDKNAME}/usr/lib/"
145		    rsync -aq "${SDKPROPERTY}/usr/lib/libstdc++"* "${OBJROOT}/BuildTools/${SDKNAME}/usr/lib/"
146		    mkdir -p "${OBJROOT}/BuildTools/${SDKNAME}/usr/lib/system"
147		    rsync -aq --exclude=\*_debug.dylib --exclude=\*_profile.dylib "${SDKPROPERTY}/usr/lib/system/" "${OBJROOT}/BuildTools/${SDKNAME}/usr/lib/system/"
148		fi
149		if [ -f "${SDKPROPERTY}/usr/local/libexec/availability.pl" ]; then
150		    mkdir -p "${OBJROOT}/BuildTools/${SDKNAME}/usr/local/libexec"
151		    rsync -aq "${SDKPROPERTY}/usr/local/libexec/availability.pl" "${OBJROOT}/BuildTools/${SDKNAME}/usr/local/libexec/"
152		fi
153		CreateFile "${SDKPROPERTY}" "${OBJROOT}/BuildTools/${SDKNAME}/.realsdkpath"
154		CreateFile "${SDKTYPE}" "${OBJROOT}/BuildTools/${SDKNAME}/.sdktype"
155		CreateFile "BuildTools/${SDKNAME}" "${OBJROOT}/BuildTools/.${SDKTYPE}sdk"
156		echo "${OBJROOT}/BuildTools/${SDKNAME}"
157		exit 0
158		;;
159	    -show-sdk-platform-path)
160		PLATFORMNAME=$(basename "${SDKPROPERTY}")
161		mkdir -p "${OBJROOT}/BuildTools/${PLATFORMNAME}"
162		if [ -f "${SDKPROPERTY}/usr/local/standalone/firmware/device_map.db" ]; then
163		    mkdir -p "${OBJROOT}/BuildTools/${PLATFORMNAME}/usr/local/standalone/firmware"
164		    rsync -aq "${SDKPROPERTY}/usr/local/standalone/firmware/device_map.db" \
165			"${OBJROOT}/BuildTools/${PLATFORMNAME}/usr/local/standalone/firmware/"
166		fi
167		CreateFile "BuildTools/${PLATFORMNAME}" "${OBJROOT}/BuildTools/.targetplatform"
168		echo "${OBJROOT}/BuildTools/${PLATFORMNAME}"
169		exit 0
170		;;
171	    -show-sdk-version)
172		CreateFile "${SDKPROPERTY}" "${OBJROOT}/BuildTools/.targetsdkversion"
173		echo "${SDKPROPERTY}"
174		exit 0
175		;;
176	esac
177
178    elif [ -n "$FINDTOOL" ]; then
179
180	# We assume SDK Queries have been performed first and subsequent
181	# SDKROOTs used to find tools are all using cached SDKs in
182	# the build directory, in which case metadata is present
183
184	if [ ! -f "$SDKROOT/.realsdkpath" ]; then
185	    exit 1
186	fi
187	REALSDKROOT=`cat "$SDKROOT/.realsdkpath"`
188
189	if [ ! -f "$SDKROOT/.sdktype" ]; then
190	    exit 1
191	fi
192	SDKTYPE=`cat "$SDKROOT/.sdktype"`
193
194	TOOLPATH=`/usr/bin/xcrun $VERBOSE -sdk "$REALSDKROOT" -find "$FINDTOOL"`
195	if [ $? -ne 0 ]; then
196	    exit $?
197	fi
198
199	# Keep the parent directory when caching tools, along with Host vs. Target
200	TOOLNAME=$(basename "${TOOLPATH}")
201	TOOLDIR=$(basename $(dirname "${TOOLPATH}"))
202	if [ "$SDKTYPE" = "host" ]; then
203	    NEWTOOLPATH="${OBJROOT}/BuildTools/Host/${TOOLDIR}/${TOOLNAME}"
204	    mkdir -p "${OBJROOT}/BuildTools/Host"
205	    CreateFile "BuildTools/Host/${TOOLDIR}/${TOOLNAME}" "${OBJROOT}/BuildTools/Host/.${TOOLNAME}"
206	else
207	    NEWTOOLPATH="${OBJROOT}/BuildTools/Target/${TOOLDIR}/${TOOLNAME}"
208	    mkdir -p "${OBJROOT}/BuildTools/Target"
209	    CreateFile "BuildTools/Target/${TOOLDIR}/${TOOLNAME}" "${OBJROOT}/BuildTools/Target/.${TOOLNAME}"
210	fi
211	mkdir -p $(dirname "${NEWTOOLPATH}")
212	rsync -aq "${TOOLPATH}" "${NEWTOOLPATH}"
213	case "${TOOLNAME}" in
214	    clang)
215		mkdir -p $(dirname $(dirname "${NEWTOOLPATH}"))/lib/clang
216		rsync -aq $(dirname "${TOOLPATH}")/ld $(dirname "${NEWTOOLPATH}")/ld
217		rsync -aq $(dirname $(dirname "${TOOLPATH}"))/lib/clang/ $(dirname $(dirname "${NEWTOOLPATH}"))/lib/clang/
218		rsync -aq $(dirname $(dirname "${TOOLPATH}"))/lib/libLTO.dylib $(dirname $(dirname "${NEWTOOLPATH}"))/lib/libLTO.dylib
219		;;
220	    bison)
221		mkdir -p $(dirname $(dirname "${NEWTOOLPATH}"))/share/bison
222		rsync -aq $(dirname $(dirname "${TOOLPATH}"))/share/bison/ $(dirname $(dirname "${NEWTOOLPATH}"))/share/bison/
223		;;
224	esac
225
226	echo "${NEWTOOLPATH}"
227	exit 0
228    else
229	echo "Unrecognized option" 1>&2
230	exit 1
231    fi
232fi
233
234# When using cached SDK information, first try to do
235# an initial classification, and then read properties from
236# cached locations
237SDKTYPE=""
238case "$SDKROOT" in
239    macosx)
240	SDKTYPE="host"
241	;;
242    iphonehost*)
243	SDKTYPE="iphonehost"
244	;;
245    *)
246	if [ -f "$SDKROOT/.sdktype" ]; then
247	    SDKTYPE=`cat "$SDKROOT/.sdktype"`
248	else
249	    SDKTYPE="target"
250	fi
251	;;
252esac
253
254if [ -n "$FINDTOOL" ]; then
255    TOOLNAME=$(basename "${FINDTOOL}")
256    if [ "${SDKTYPE}" = "host" ]; then
257	RELPATH=`cat ${OBJROOT}/BuildTools/Host/.${TOOLNAME}`
258    else
259	RELPATH=`cat ${OBJROOT}/BuildTools/Target/.${TOOLNAME}`
260    fi
261    echo "${OBJROOT}/${RELPATH}"
262else	
263    case $SDKQUERY in
264	-show-sdk-path)
265	    RELPATH=`cat ${OBJROOT}/BuildTools/.${SDKTYPE}sdk`
266	    echo "${OBJROOT}/${RELPATH}"
267	    ;;
268	-show-sdk-platform-path)
269	    RELPATH=`cat ${OBJROOT}/BuildTools/.targetplatform`
270	    echo "${OBJROOT}/${RELPATH}"
271	    ;;
272	-show-sdk-version)
273	    echo `cat ${OBJROOT}/BuildTools/.targetsdkversion`
274	    ;;
275    esac
276fi
277