1#!/bin/sh
2#
3# Copyright (C) 2010 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17#  This shell script is a wrapper to launch the NDK build from the
18#  command-line inside an application project path.
19#
20#  Typical usage is:
21#
22#     cd $PROJECT_PATH
23#     ndk-build
24#
25#  Assuming that the Android NDK root path is in your PATH. However,
26#  you can also invoke it directly as:
27#
28#     $NDK_ROOT/ndk-build
29#
30#  This really is a tiny wrapper around GNU Make.
31#
32
33# Ensure we get the full path of this script's directory
34# this is needed if the caller uses the -C <path> GNU Make
35# option, as in:
36#
37#    cd ndk
38#    ./ndk-build -C <project-path>
39#
40PROGDIR=`dirname $0`
41PROGDIR=`cd $PROGDIR && pwd -P`
42
43# Check if absolute NDK path contain space
44#
45case $PROGDIR in
46    *\ *) echo "ERROR: NDK path cannot contain space"
47          exit 1
48        ;;
49esac
50
51# If NDK_LOG is set to 1 or true in the environment, or the command-line
52# then enable log messages below
53# Also normalize NDK_HOST_32BIT and NDK_ANALYZE to 1 or 0
54if [ -z "$NDK_LOG" ]; then
55  NDK_LOG=0
56fi
57
58if [ -z "$NDK_HOST_32BIT" ]; then
59  NDK_HOST_32BIT=0
60fi
61
62if [ -z "$NDK_ANALYZE" ]; then
63  NDK_ANALYZE=0
64fi
65
66PROJECT_PATH=
67PROJECT_PATH_NEXT=
68for opt; do
69    if [ -z "$PROJECT_PATH" -a "$PROJECT_PATH_NEXT" = "yes" ] ; then
70        PROJECT_PATH=$opt
71        PROJECT_PATH_NEXT=
72    else
73        case $opt in
74          NDK_LOG=1|NDK_LOG=true)
75            NDK_LOG=1
76            ;;
77          NDK_LOG=*)
78            NDK_LOG=0
79            ;;
80          NDK_HOST_32BIT=1|NDK_HOST_32BIT=true)
81            NDK_HOST_32BIT=1
82            ;;
83          NDK_HOST_32BIT=*)
84            NDK_HOST_32BIT=0
85            ;;
86          NDK_ANALYZE=1|NDK_ANALYZE=true)
87            NDK_ANALYZE=1
88            ;;
89          NDK_ANALYZE=*)
90            NDK_ANALYZE=0
91            ;;
92          NDK_TOOLCHAIN_VERSION=*)
93            NDK_TOOLCHAIN_VERSION=${opt#NDK_TOOLCHAIN_VERSION=}
94            ;;
95          APP_ABI=*)
96            APP_ABI=${opt#APP_ABI=}
97            ;;
98          -C)
99            PROJECT_PATH_NEXT="yes"
100            ;;
101        esac
102    fi
103done
104
105if [ "$NDK_LOG" = "true" ]; then
106  NDK_LOG=1
107fi
108
109if [ "$NDK_HOST_32BIT" = "true" ]; then
110  NDK_HOST_32BIT=1
111fi
112
113if [ "$NDK_ANALYZE" = "true" ]; then
114  NDK_ANALYZE=1
115fi
116
117if [ "$NDK_LOG" = "1" ]; then
118  log () {
119    echo "$@"
120  }
121else
122  log () {
123    : # nothing
124  }
125fi
126
127# Detect host operating system and architecture
128# The 64-bit / 32-bit distinction gets tricky on Linux and Darwin because
129# uname -m returns the kernel's bit size, and it's possible to run with
130# a 64-bit kernel and a 32-bit userland.
131#
132HOST_OS=$(uname -s)
133case $HOST_OS in
134  Darwin) HOST_OS=darwin;;
135  Linux) HOST_OS=linux;;
136  FreeBsd) HOST_OS=freebsd;;
137  CYGWIN*|*_NT-*) HOST_OS=cygwin;;
138  *) echo "ERROR: Unknown host operating system: $HOST_OS"
139     exit 1
140esac
141log "HOST_OS=$HOST_OS"
142
143HOST_ARCH=$(uname -m)
144case $HOST_ARCH in
145    i?86) HOST_ARCH=x86;;
146    x86_64|amd64) HOST_ARCH=x86_64;;
147    *) echo "ERROR: Unknown host CPU architecture: $HOST_ARCH"
148       exit 1
149esac
150log "HOST_ARCH=$HOST_ARCH"
151
152# Detect 32-bit userland on 64-bit kernels
153HOST_TAG="$HOST_OS-$HOST_ARCH"
154case $HOST_TAG in
155  linux-x86_64|darwin-x86_64)
156    # we look for x86_64 or x86-64 in the output of 'file' for our shell
157    # the -L flag is used to dereference symlinks, just in case.
158    file -L "$SHELL" | grep -q "x86[_-]64"
159    if [ $? != 0 ]; then
160      HOST_ARCH=x86
161      log "HOST_ARCH=$HOST_ARCH (32-bit userland detected)"
162    fi
163    ;;
164esac
165
166# Check that we have 64-bit binaries on 64-bit system, otherwise fallback
167# on 32-bit ones. This gives us more freedom in packaging the NDK.
168LOG_MESSAGE=
169if [ $HOST_ARCH = x86_64 ]; then
170  if [ ! -d $PROGDIR/prebuilt/$HOST_TAG ]; then
171    HOST_ARCH=x86
172    LOG_MESSAGE="(no 64-bit prebuilt binaries detected)"
173  fi
174
175  if [ "$NDK_HOST_32BIT" = "1" ]; then
176    HOST_ARCH=x86
177    LOG_MESSAGE="(force 32-bit host toolchain)"
178  fi
179fi
180
181HOST_TAG=$HOST_OS-$HOST_ARCH
182# Special case windows-x86 -> windows
183if [ $HOST_TAG = windows-x86 ]; then
184  HOST_TAG=windows
185fi
186log "HOST_TAG=$HOST_TAG $LOG_MESSAGE"
187
188# If GNUMAKE is defined, check that it points to a valid file
189if [ -n "$GNUMAKE" ] ; then
190    ABS_GNUMAKE=`which $GNUMAKE 2> /dev/null`
191    if [ $? != 0 ] ; then
192        echo "ERROR: Your GNUMAKE variable is defined to an invalid name: $GNUMAKE"
193        echo "Please fix it to point to a valid make executable (e.g. /usr/bin/make)"
194        exit 1
195    fi
196    GNUMAKE="$ABS_GNUMAKE"
197    log "GNUMAKE=$GNUMAKE (from environment variable)"
198else
199    # Otherwise use the prebuilt version for our host tag, if it exists
200    # Note: we intentionally do not provide prebuilt make binaries for Cygwin
201    # or MSys.
202    GNUMAKE=$PROGDIR/prebuilt/$HOST_TAG/bin/make
203    if [ ! -f "$GNUMAKE" ]; then
204        # Otherwise, use 'make' and check that it is available
205        GNUMAKE=`which make 2> /dev/null`
206        if [ $? != 0 ] ; then
207            echo "ERROR: Cannot find 'make' program. Please install Cygwin make package"
208            echo "or define the GNUMAKE variable to point to it."
209            exit 1
210        fi
211        log "GNUMAKE=$GNUMAKE (system path)"
212    else
213        log "GNUMAKE=$GNUMAKE (NDK prebuilt)"
214    fi
215fi
216
217# On Windows, when running under cygwin, check that we are
218# invoking a cygwin-compatible GNU Make binary. It is unfortunately
219# common for app developers to have another non cygwin-compatible
220# 'make' program in their PATH.
221#
222if [ "$OSTYPE" = "cygwin" ] ; then
223    GNUMAKE=`cygpath -u $GNUMAKE`
224    PROGDIR_MIXED=`cygpath -m $PROGDIR`
225    CYGWIN_GNUMAKE=`$GNUMAKE -f "$PROGDIR_MIXED/build/core/check-cygwin-make.mk" 2>&1`
226    if [ $? != 0 ] ; then
227        echo "ERROR: You are using a non-Cygwin compatible Make program."
228        echo "Currently using: `cygpath -m $GNUMAKE`"
229        echo ""
230        echo "To solve the issue, follow these steps:"
231        echo ""
232        echo "1. Ensure that the Cygwin 'make' package is installed."
233        echo "   NOTE: You will need GNU Make 3.81 or later!"
234        echo ""
235        echo "2. Define the GNUMAKE environment variable to point to it, as in:"
236        echo ""
237        echo "     export GNUMAKE=/usr/bin/make"
238        echo ""
239        echo "3. Call 'ndk-build' again."
240        echo ""
241        exit 1
242    fi
243    log "Cygwin-compatible GNU make detected"
244fi
245
246if [ "$NDK_ANALYZE" = 1 ]; then
247    . $PROGDIR/build/tools/dev-defaults.sh  # for DEFAULT_LLVM_VERSION
248
249    # Find perl.  If HOST_PERL is defined, check that it points to a valid file
250    HOST_PERL_LIB=
251    if [ -n "$HOST_PERL" ] ; then
252        ABS_PERL=`which $HOST_PERL 2> /dev/null`
253        if [ $? != 0 ] ; then
254            echo "ERROR: Your HOST_PERL variable is defined to an invalid name: $HOST_PERL"
255            echo "Please fix it to point to a valid perl executable (e.g. /usr/bin/perl)"
256            exit 1
257        fi
258        HOST_PERL="$ABS_PERL"
259        log "HOST_PERL=$HOST_PERL (from environment variable)"
260    else
261        # Otherwise use the prebuilt version for our host tag
262        HOST_PERL="$PROGDIR/prebuilt/$HOST_TAG/bin/perl"
263        if [ ! -f "$HOST_PERL" ]; then
264            # Otherwise, use 'perl' and check that it is available
265            HOST_PERL=`which perl 2> /dev/null`
266            if [ $? != 0 ] ; then
267                echo "ERROR: Cannot find 'perl' program. Please install perl package"
268                echo "or define the HOST_PERL variable to point to it."
269                exit 1
270            fi
271            log "HOST_PERL=$HOST_PERL (system path)"
272        else
273            HOST_PERL_LIB="$PROGDIR/prebuilt/$HOST_TAG/lib/perl5"
274            log "HOST_PERL=$HOST_PERL (NDK prebuilt)"
275        fi
276    fi
277
278    # Return flags send in env. or command line which are enough to retrive APP_ABI and TOOLCHAIN_PREFIX later
279    gen_flags ()
280    {
281        local FLAGS=
282
283        if [ -n "$PROJECT_PATH" ] ; then
284            FLAGS=$FLAGS" -C $PROJECT_PATH"
285        fi
286        if [ -n "$APP_ABI" ] ; then
287            FLAGS=$FLAGS" APP_ABI=$APP_ABI"
288        fi
289        if [ -n "$NDK_HOST_32BIT" ] ; then
290            FLAGS=$FLAGS" NDK_HOST_32BIT=$NDK_HOST_32BIT"
291        fi
292        if [ -n "$NDK_TOOLCHAIN_VERSION" ] ; then
293            FLAGS=$FLAGS" NDK_TOOLCHAIN_VERSION=$NDK_TOOLCHAIN_VERSION"
294        fi
295        echo "$FLAGS"
296    }
297
298    get_build_var ()
299    {
300        local VAR=$1
301        local FLAGS=`gen_flags`
302        $GNUMAKE --no-print-dir -f $PROGDIR/build/core/build-local.mk $FLAGS DUMP_${VAR} | tail -1
303    }
304
305    get_build_var_for_abi ()
306    {
307        local VAR=$1
308        local ABI=$2
309        local FLAGS=`gen_flags`
310        $GNUMAKE --no-print-dir -f $PROGDIR/build/core/build-local.mk $FLAGS DUMP_${VAR} APP_ABI=${ABI} | tail -1
311    }
312
313    APP_ABIS=`get_build_var APP_ABI`
314    for ABI in $APP_ABIS; do
315        TOOLCHAIN_PREFIX=`get_build_var_for_abi TOOLCHAIN_PREFIX $ABI`
316        PERL5LIB="$HOST_PERL_LIB" "$HOST_PERL" $PROGDIR/prebuilt/common/scan-build/scan-build \
317            --use-analyzer $PROGDIR/toolchains/llvm-${DEFAULT_LLVM_VERSION}/prebuilt/$HOST_TAG/bin/${ABI}/analyzer \
318            --use-cc ${TOOLCHAIN_PREFIX}gcc \
319            --use-c++ ${TOOLCHAIN_PREFIX}g++ \
320            --status-bugs \
321            $GNUMAKE -f $PROGDIR/build/core/build-local.mk "$@" APP_ABI=$ABI
322    done
323else
324    $GNUMAKE -f $PROGDIR/build/core/build-local.mk "$@"
325fi
326
327