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
53if [ -z "$NDK_LOG" ]; then
54  NDK_LOG=0
55fi
56
57if [ -z "$NDK_ANALYZE" ]; then
58  NDK_ANALYZE=0
59fi
60
61PROJECT_PATH=
62PROJECT_PATH_NEXT=
63for opt; do
64    if [ -z "$PROJECT_PATH" -a "$PROJECT_PATH_NEXT" = "yes" ] ; then
65        PROJECT_PATH=$opt
66        PROJECT_PATH_NEXT=
67    else
68        case $opt in
69          NDK_LOG=1|NDK_LOG=true)
70            NDK_LOG=1
71            ;;
72          NDK_LOG=*)
73            NDK_LOG=0
74            ;;
75          NDK_ANALYZE=1|NDK_ANALYZE=true)
76            NDK_ANALYZE=1
77            ;;
78          NDK_ANALYZE=*)
79            NDK_ANALYZE=0
80            ;;
81          NDK_TOOLCHAIN_VERSION=*)
82            NDK_TOOLCHAIN_VERSION=${opt#NDK_TOOLCHAIN_VERSION=}
83            ;;
84          APP_ABI=*)
85            APP_ABI=${opt#APP_ABI=}
86            ;;
87          -C)
88            PROJECT_PATH_NEXT="yes"
89            ;;
90        esac
91    fi
92done
93
94if [ "$NDK_LOG" = "true" ]; then
95  NDK_LOG=1
96fi
97
98if [ "$NDK_ANALYZE" = "true" ]; then
99  NDK_ANALYZE=1
100fi
101
102if [ "$NDK_LOG" = "1" ]; then
103  log () {
104    echo "$@"
105  }
106else
107  log () {
108    : # nothing
109  }
110fi
111
112# Detect host operating system and architecture
113# The 64-bit / 32-bit distinction gets tricky on Linux and Darwin because
114# uname -m returns the kernel's bit size, and it's possible to run with
115# a 64-bit kernel and a 32-bit userland.
116#
117HOST_OS=$(uname -s)
118case $HOST_OS in
119  Darwin) HOST_OS=darwin;;
120  Linux) HOST_OS=linux;;
121  FreeBsd) HOST_OS=freebsd;;
122  CYGWIN*|*_NT-*) HOST_OS=cygwin;;
123  *) echo "ERROR: Unknown host operating system: $HOST_OS"
124     exit 1
125esac
126log "HOST_OS=$HOST_OS"
127
128HOST_ARCH=$(uname -m)
129case $HOST_ARCH in
130    i?86) HOST_ARCH=x86;;
131    x86_64|amd64) HOST_ARCH=x86_64;;
132    *) echo "ERROR: Unknown host CPU architecture: $HOST_ARCH"
133       exit 1
134esac
135log "HOST_ARCH=$HOST_ARCH"
136
137# Detect 32-bit userland on 64-bit kernels
138HOST_TAG="$HOST_OS-$HOST_ARCH"
139case $HOST_TAG in
140  linux-x86_64|darwin-x86_64)
141    # we look for x86_64 or x86-64 in the output of 'file' for our shell
142    # the -L flag is used to dereference symlinks, just in case.
143    file -L "$SHELL" | grep -q "x86[_-]64"
144    if [ $? != 0 ]; then
145      HOST_ARCH=x86
146      log "HOST_ARCH=$HOST_ARCH (32-bit userland detected)"
147    fi
148    ;;
149esac
150
151# Check that we have 64-bit binaries on 64-bit system, otherwise fallback
152# on 32-bit ones. This gives us more freedom in packaging the NDK.
153LOG_MESSAGE=
154if [ $HOST_ARCH = x86_64 ]; then
155  if [ ! -d $PROGDIR/prebuilt/$HOST_TAG ]; then
156    HOST_ARCH=x86
157    LOG_MESSAGE="(no 64-bit prebuilt binaries detected)"
158  fi
159fi
160
161HOST_TAG=$HOST_OS-$HOST_ARCH
162# Special case windows-x86 -> windows
163if [ $HOST_TAG = windows-x86 ]; then
164  HOST_TAG=windows
165fi
166log "HOST_TAG=$HOST_TAG $LOG_MESSAGE"
167
168# If GNUMAKE is defined, check that it points to a valid file
169if [ -n "$GNUMAKE" ] ; then
170    ABS_GNUMAKE=`which $GNUMAKE 2> /dev/null`
171    if [ $? != 0 ] ; then
172        echo "ERROR: Your GNUMAKE variable is defined to an invalid name: $GNUMAKE"
173        echo "Please fix it to point to a valid make executable (e.g. /usr/bin/make)"
174        exit 1
175    fi
176    GNUMAKE="$ABS_GNUMAKE"
177    log "GNUMAKE=$GNUMAKE (from environment variable)"
178else
179    # Otherwise use the prebuilt version for our host tag, if it exists
180    # Note: we intentionally do not provide prebuilt make binaries for Cygwin
181    # or MSys.
182    GNUMAKE=$PROGDIR/prebuilt/$HOST_TAG/bin/make
183    if [ ! -f "$GNUMAKE" ]; then
184        # Otherwise, use 'make' and check that it is available
185        GNUMAKE=`which make 2> /dev/null`
186        if [ $? != 0 ] ; then
187            echo "ERROR: Cannot find 'make' program. Please install Cygwin make package"
188            echo "or define the GNUMAKE variable to point to it."
189            exit 1
190        fi
191        log "GNUMAKE=$GNUMAKE (system path)"
192    else
193        log "GNUMAKE=$GNUMAKE (NDK prebuilt)"
194    fi
195fi
196
197# On Windows, when running under cygwin, check that we are
198# invoking a cygwin-compatible GNU Make binary. It is unfortunately
199# common for app developers to have another non cygwin-compatible
200# 'make' program in their PATH.
201#
202if [ "$OSTYPE" = "cygwin" ] ; then
203    GNUMAKE=`cygpath -u $GNUMAKE`
204    PROGDIR_MIXED=`cygpath -m $PROGDIR`
205    CYGWIN_GNUMAKE=`$GNUMAKE -f "$PROGDIR_MIXED/core/check-cygwin-make.mk" 2>&1`
206    if [ $? != 0 ] ; then
207        echo "ERROR: You are using a non-Cygwin compatible Make program."
208        echo "Currently using: `cygpath -m $GNUMAKE`"
209        echo ""
210        echo "To solve the issue, follow these steps:"
211        echo ""
212        echo "1. Ensure that the Cygwin 'make' package is installed."
213        echo "   NOTE: You will need GNU Make 3.81 or later!"
214        echo ""
215        echo "2. Define the GNUMAKE environment variable to point to it, as in:"
216        echo ""
217        echo "     export GNUMAKE=/usr/bin/make"
218        echo ""
219        echo "3. Call 'ndk-build' again."
220        echo ""
221        exit 1
222    fi
223    log "Cygwin-compatible GNU make detected"
224fi
225
226if [ "$NDK_ANALYZE" = 1 ]; then
227    . $PROGDIR/build/tools/dev-defaults.sh  # for DEFAULT_LLVM_VERSION
228
229    # Return flags send in env. or command line which are enough to retrive APP_ABI and TOOLCHAIN_PREFIX later
230    gen_flags ()
231    {
232        local FLAGS=
233
234        if [ -n "$PROJECT_PATH" ] ; then
235            FLAGS=$FLAGS" -C $PROJECT_PATH"
236        fi
237        if [ -n "$APP_ABI" ] ; then
238            FLAGS=$FLAGS" APP_ABI=$APP_ABI"
239        fi
240        if [ -n "$NDK_TOOLCHAIN_VERSION" ] ; then
241            FLAGS=$FLAGS" NDK_TOOLCHAIN_VERSION=$NDK_TOOLCHAIN_VERSION"
242        fi
243        echo "$FLAGS"
244    }
245
246    get_build_var ()
247    {
248        local VAR=$1
249        local FLAGS=`gen_flags`
250        $GNUMAKE --no-print-dir -f $PROGDIR/core/build-local.mk $FLAGS DUMP_${VAR} | tail -1
251    }
252
253    get_build_var_for_abi ()
254    {
255        local VAR=$1
256        local ABI=$2
257        local FLAGS=`gen_flags`
258        $GNUMAKE --no-print-dir -f $PROGDIR/core/build-local.mk $FLAGS DUMP_${VAR} APP_ABI=${ABI} | tail -1
259    }
260
261    APP_ABIS=`get_build_var APP_ABI`
262    for ABI in $APP_ABIS; do
263        TOOLCHAIN_PREFIX=`get_build_var_for_abi TOOLCHAIN_PREFIX $ABI`
264        LLVM_PATH=$PROGDIR/toolchains/llvm-${DEFAULT_LLVM_VERSION}/prebuilt
265        perl $LLVM_PATH/tools/scan-build/scan-build \
266            --use-analyzer $LLVM_PATH/bin/${ABI}/analyzer \
267            --use-cc ${TOOLCHAIN_PREFIX}gcc \
268            --use-c++ ${TOOLCHAIN_PREFIX}g++ \
269            --status-bugs \
270            $GNUMAKE -f $PROGDIR/core/build-local.mk "$@" APP_ABI=$ABI
271    done
272else
273    $GNUMAKE -f $PROGDIR/core/build-local.mk "$@"
274fi
275
276