├── host ├── gcc-m32 │ ├── cc │ ├── c++ │ ├── clang │ ├── clang++ │ ├── g++ │ └── gcc ├── -compilers │ ├── ar │ ├── as │ ├── c++ │ ├── cc │ ├── g++ │ ├── ld │ ├── nm │ ├── clang │ ├── clang++ │ ├── ranlib │ ├── strip │ └── gcc ├── gcc-lpthread │ ├── cc │ ├── c++ │ ├── clang │ ├── clang++ │ ├── g++ │ └── gcc ├── gcc-no-lrt │ ├── c++ │ ├── cc │ ├── g++ │ ├── clang │ ├── clang++ │ └── gcc └── ar-dual-os │ └── ar ├── img ├── android-gcc.png └── android-gcc-enter.png ├── LICENSE ├── android └── compiler-wrapper ├── Dockerfile ├── lib └── fast-copy.py ├── test └── basic.sh ├── README.md └── android-gcc-toolchain /host/gcc-m32/cc: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/-compilers/ar: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/-compilers/as: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/-compilers/c++: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/-compilers/cc: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/-compilers/g++: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/-compilers/ld: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/-compilers/nm: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-lpthread/cc: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-m32/c++: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-m32/clang: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-m32/clang++: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-m32/g++: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-no-lrt/c++: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-no-lrt/cc: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-no-lrt/g++: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/-compilers/clang: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/-compilers/clang++: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/-compilers/ranlib: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/-compilers/strip: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-lpthread/c++: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-lpthread/clang: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-lpthread/clang++: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-lpthread/g++: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-no-lrt/clang: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /host/gcc-no-lrt/clang++: -------------------------------------------------------------------------------- 1 | gcc -------------------------------------------------------------------------------- /img/android-gcc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sjitech/android-gcc-toolchain/HEAD/img/android-gcc.png -------------------------------------------------------------------------------- /img/android-gcc-enter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sjitech/android-gcc-toolchain/HEAD/img/android-gcc-enter.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 QianJin2013 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /android/compiler-wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | EXE_NAME=${0##*/} 3 | function _msg { echo "[final-wrapper-$EXE_NAME]" "$@" >&2; } 4 | function _dbg { [[ $AGCC_DBG == 1 ]] && _msg "$@"; } 5 | 6 | _EXE=""; case $OSTYPE in msys|cygwin) _EXE=.exe;; esac 7 | 8 | EXE_PATH=${0%/*}/$ARCH_PREFIX$EXE_NAME$_EXE 9 | 10 | ############################################################################### 11 | #output command line 12 | 13 | CCACHE=""; [[ $USE_CCACHE == 1 ]] && case $EXE_NAME in gcc|g++|cc|c++|clang|clang++) CCACHE=ccache;; esac 14 | 15 | if [[ $AGCC_VERBOSE == 1 || $AGCC_DBG == 1 ]]; then 16 | function _raw_msg { echo "$@" >&2; } 17 | 18 | _raw_msg '$___' $CCACHE "'$EXE_PATH'" \\ 19 | 20 | spaces='$___ ' 21 | 22 | i=0 23 | for arg in "$@"; do 24 | ((i++)) 25 | arg=${arg//\'/\\\'} #replace ' with \' 26 | if [[ $i == $# ]]; then 27 | _raw_msg "$spaces" "'$arg'" 28 | else 29 | _raw_msg "$spaces" "'$arg'" \\ 30 | fi 31 | done 32 | 33 | [[ $# == 0 ]] && _raw_msg "" 34 | fi 35 | 36 | ############################################################################### 37 | #run command via ccache 38 | 39 | exec $CCACHE "$EXE_PATH" "$@" 40 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #https://github.com/sjitech/ubuntu-non-root-with-utils/blob/master/Dockerfile 2 | FROM osexp2000/ubuntu-non-root-with-utils 3 | 4 | RUN sudo apt-get update && sudo DEBIAN_FRONTEND=noninteractive apt-get -y install \ 5 | ccache 6 | 7 | ENV PATH=$PATH:/home/devuser/ndk/prebuilt/linux-x86_64/bin:/home/devuser/ndk:/home/devuser/android-gcc-toolchain 8 | ENV NDK=/home/devuser/ndk 9 | ENV USE_CCACHE=1 10 | 11 | RUN ccache -M 50G && \ 12 | echo "Downloading NDK" >&2 && \ 13 | wget https://dl.google.com/android/repository/android-ndk-r12b-linux-x86_64.zip --no-verbose && \ 14 | echo "Decompressing NDK" >&2 && \ 15 | bash -c "7z x android-ndk-r12b-linux-x86_64.zip | grep -vE '^Extracting|^$'; exit \${PIPESTATUS[0]}" && \ 16 | rm android-ndk-r12b-linux-x86_64.zip && \ 17 | mv android-ndk-r12b ndk && \ 18 | git clone https://github.com/sjitech/android-gcc-toolchain -b master --single-branch && \ 19 | android-gcc-toolchain which gcc && \ 20 | echo "Compressing platforms/android-*/arch-*/usr/* of \$NDK to \$NDK/platforms.7z" >&2 && \ 21 | bash -c "cd $NDK && 7z a platforms.7z platforms/android-*/arch-*/usr/ | grep -vE '^Compressing|^$'; exit \${PIPESTATUS[0]}" && \ 22 | echo "Removing platforms/android-*/arch-*/usr/* of \$NDK" >&2 && \ 23 | (cd $NDK/platforms && rm -fr android-*/arch-*/usr/) 24 | 25 | ENTRYPOINT ["android-gcc-toolchain"] 26 | -------------------------------------------------------------------------------- /host/gcc-m32/gcc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | EXE_NAME=${0##*/} 3 | function _msg { echo "[$EXE_NAME-m32]" "$@" >&2; } 4 | function _dbg { [[ $AGCC_DBG == 1 ]] && _msg "$@"; } 5 | 6 | ############################################################################### 7 | #Search the exe behind me in $PATH. Even faster than {for f in `type -ap name`} 8 | 9 | case $EXE_NAME in 10 | cc) ALT_EXE_NAME="gcc";; 11 | gcc) ALT_EXE_NAME="cc";; 12 | c++) ALT_EXE_NAME="g++";; 13 | g++) ALT_EXE_NAME="c++";; 14 | *) unset ALT_EXE_NAME;; 15 | esac 16 | 17 | IFS=: pathList=($PATH); unset IFS #split $PATH by :, save to array 18 | 19 | for name in $EXE_NAME $ALT_EXE_NAME; do 20 | EXE_PATH=""; foundMyself="" 21 | for d in "${pathList[@]}"; do 22 | if [[ -f $d/$name && -x $d/$name ]]; then 23 | if [[ $d/$name -ef "$0" ]]; then #is it actually myself? (symbol link also works) 24 | foundMyself=YES 25 | elif [[ $foundMyself ]]; then 26 | EXE_PATH=$d/$name 27 | break 28 | fi 29 | fi 30 | done 31 | [[ $EXE_PATH ]] && break; 32 | done 33 | 34 | if [[ ! $EXE_PATH ]]; then 35 | _msg "$EXE_NAME${ALT_EXE_NAME+ or }$ALT_EXE_NAME not found." 36 | exit 127 37 | fi 38 | 39 | ############################################################################### 40 | #if already have -m32 option then run command without change. 41 | 42 | for arg in "$@"; do 43 | if [[ $arg == -m32 ]]; then 44 | _dbg "call '$EXE_PATH' (already specified -m32 option)" 45 | exec "$EXE_PATH" "$@" 46 | exit 47 | fi 48 | done 49 | 50 | ############################################################################### 51 | #otherwise run command with -m32 52 | 53 | _msg "call '$EXE_PATH' with -m32 option" 54 | exec "$EXE_PATH" -m32 "$@" 55 | -------------------------------------------------------------------------------- /lib/fast-copy.py: -------------------------------------------------------------------------------- 1 | def copy2(src, dst): 2 | if os.path.isdir(dst): 3 | dst = os.path.join(dst, os.path.basename(src)) 4 | try: 5 | if os.environ['VERBOSE'] == "--verbose": 6 | sys.stderr.write(" %s\n-> %s\n" % (src.replace(NDK_DIR, "$NDK"), dst.replace(NDK_DIR, "$NDK"))) 7 | if os.name == "nt": 8 | import ctypes 9 | if not ctypes.windll.kernel32.CreateHardLinkA(dst, src, 0): 10 | raise ctypes.WinError() 11 | else: 12 | os.link(src, dst) 13 | except OSError as e: 14 | if not ((dst.endswith("NOTICE") or dst.endswith("repo.prop"))): 15 | import filecmp 16 | if not filecmp.cmp(src, dst): 17 | if os.environ['VERBOSE'] != "--verbose": 18 | sys.stderr.write(" %s\n-> %s\n" % (src.replace(NDK_DIR, "$NDK"), dst.replace(NDK_DIR, "$NDK"))) 19 | import errno 20 | if e.errno == errno.EEXIST: 21 | sys.stderr.write("Warning: failed to copy above files due to target already exists\n") 22 | else: 23 | raise 24 | 25 | def copytree(src, dst): 26 | """Recursively copy a directory tree. 27 | 28 | The destination directory must not already exist. 29 | If exception(s) occur, an Error is raised with a list of reasons. 30 | 31 | """ 32 | names = os.listdir(src) 33 | os.makedirs(dst) 34 | for name in names: 35 | srcname = os.path.join(src, name) 36 | dstname = os.path.join(dst, name) 37 | if os.path.islink(srcname): 38 | linkto = os.readlink(srcname) 39 | copy2(linkto, dstname) 40 | elif os.path.isdir(srcname): 41 | copytree(srcname, dstname) 42 | else: 43 | copy2(srcname, dstname) 44 | 45 | 46 | -------------------------------------------------------------------------------- /test/basic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | function _msg { echo "$@" >&2; } 3 | function _dbg { [[ $AGCC_DBG == 1 ]] && echo "$@" >&2; } 4 | function _guide { echo "" "$@" >&2; } 5 | 6 | thisDir=${0%/*}; [[ $0 != */* ]] && thisDir=. 7 | if target=`readlink "$0"`; then if [[ $target == /* ]]; then thisDir=${target%/*}; elif [[ $target == */* ]]; then thisDir+=/${target%/*}; fi; fi 8 | _dbg "thisDir: '$thisDir'" 9 | hackDir=$thisDir/../host 10 | 11 | PATH=$thisDir/..:$PATH 12 | 13 | [[ `android-gcc-toolchain sh -c 'echo $BIN/' 2>&1 <<<"echo hi"` == */std-toolchains/android-9-arm/bin/ ]] && echo OK || echo $LINENO 14 | [[ `android-gcc-toolchain arm 2>&1 <<<"echo hi"` == hi ]] && echo OK || echo $LINENO 15 | [[ `android-gcc-toolchain arm --host ar-dual-os,gcc-no-lrt,gcc-m32 -C 2>&1 <<<"echo hi"` == hi ]] && echo OK || echo $LINENO 16 | [[ `android-gcc-toolchain arm -c 2>&1 <<<"echo hi"` == hi ]] && echo OK || echo $LINENO 17 | [[ `android-gcc-toolchain arm -C 2>&1 <<<"echo hi"` == hi ]] && echo OK || echo $LINENO 18 | #[[ `android-gcc-toolchain --host a 2>&1 <<<"echo hi"` == *"--host option must be used with -C|-c option"* ]] && echo OK || echo $LINENO 19 | [[ `android-gcc-toolchain --host a -C 2>&1 <<<"echo hi"` == *"invalid host compiler rule"* ]] && echo OK || echo $LINENO 20 | [[ `android-gcc-toolchain --host ar-dual-os,-compilers -C 2>&1 <<<"echo hi"` == *"invalid host compiler rule"* ]] && echo OK || echo $LINENO 21 | 22 | rm -fr $hackDir/xxx 23 | [[ `android-gcc-toolchain --host xxx -C 2>&1 <<<"echo hi"` == *"invalid host compiler rule"* ]] && echo OK || echo $LINENO 24 | mkdir $hackDir/xxx 25 | [[ `android-gcc-toolchain --host xxx -C 2>&1 <<<"echo hi"` == "hi" ]] && echo OK || echo $LINENO 26 | rm -fr $hackDir/xxx 27 | 28 | [[ `android-gcc-toolchain --host ,, -C 2>&1 <<<"echo hi"` == *"invalid host compiler rule"* ]] && echo OK || echo $LINENO 29 | [[ `android-gcc-toolchain --host ,, -C --list-host-rules 2>&1 <<<"echo hi"` == *"Available host compiler rules"*gcc-m32* ]] && echo OK || echo $LINENO 30 | -------------------------------------------------------------------------------- /host/gcc-lpthread/gcc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | EXE_NAME=${0##*/} 3 | function _msg { echo "[$EXE_NAME-lpthread]" "$@" >&2; } 4 | function _dbg { [[ $AGCC_DBG == 1 ]] && _msg "$@"; } 5 | 6 | ############################################################################### 7 | #Search the exe behind me in $PATH. Even faster than {for f in `type -ap name`} 8 | 9 | case $EXE_NAME in 10 | cc) ALT_EXE_NAME="gcc";; 11 | gcc) ALT_EXE_NAME="cc";; 12 | c++) ALT_EXE_NAME="g++";; 13 | g++) ALT_EXE_NAME="c++";; 14 | *) unset ALT_EXE_NAME;; 15 | esac 16 | 17 | IFS=: pathList=($PATH); unset IFS #split $PATH by :, save to array 18 | 19 | for name in $EXE_NAME $ALT_EXE_NAME; do 20 | EXE_PATH=""; foundMyself="" 21 | for d in "${pathList[@]}"; do 22 | if [[ -f $d/$name && -x $d/$name ]]; then 23 | if [[ $d/$name -ef "$0" ]]; then #is it actually myself? (symbol link also works) 24 | foundMyself=YES 25 | elif [[ $foundMyself ]]; then 26 | EXE_PATH=$d/$name 27 | break 28 | fi 29 | fi 30 | done 31 | [[ $EXE_PATH ]] && break; 32 | done 33 | 34 | if [[ ! $EXE_PATH ]]; then 35 | _msg "$EXE_NAME${ALT_EXE_NAME+ or }$ALT_EXE_NAME not found." 36 | exit 127 37 | fi 38 | 39 | ############################################################################### 40 | #if already have -lpthread option then run command without change. 41 | 42 | has_lLIB="" 43 | for arg in "$@"; do 44 | if [[ $arg == -lpthread ]]; then 45 | _dbg "call '$EXE_PATH' (already specified -lpthread option)" 46 | exec "$EXE_PATH" "$@" 47 | exit 48 | elif [[ $arg == -l* ]]; then 49 | has_lLIB=1 50 | fi 51 | done 52 | 53 | #if not sure whether need append -lpthread option then run command without change. 54 | if [[ ! $has_lLIB ]]; then 55 | _dbg "call '$EXE_PATH' (no any -lLIB option)" 56 | exec "$EXE_PATH" "$@" 57 | exit 58 | fi 59 | 60 | ############################################################################### 61 | #otherwise run command with -lpthread 62 | 63 | _msg "call '$EXE_PATH' with -lpthread" 64 | exec "$EXE_PATH" "$@" -lpthread 65 | -------------------------------------------------------------------------------- /host/-compilers/gcc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | EXE_NAME=${0##*/} 3 | function _msg { echo "[final-wrapper-$EXE_NAME]" "$@" >&2; } 4 | function _dbg { [[ $AGCC_DBG == 1 ]] && _msg "$@"; } 5 | 6 | ############################################################################### 7 | #Search the exe behind me in $PATH. Even faster than {for f in `type -ap name`} 8 | 9 | case $EXE_NAME in 10 | cc) ALT_EXE_NAME="gcc";; 11 | gcc) ALT_EXE_NAME="cc";; 12 | c++) ALT_EXE_NAME="g++";; 13 | g++) ALT_EXE_NAME="c++";; 14 | *) unset ALT_EXE_NAME;; 15 | esac 16 | 17 | IFS=: pathList=($PATH); unset IFS #split $PATH by :, save to array 18 | 19 | for name in $EXE_NAME $ALT_EXE_NAME; do 20 | EXE_PATH=""; foundMyself="" 21 | for d in "${pathList[@]}"; do 22 | if [[ -f $d/$name && -x $d/$name ]]; then 23 | if [[ $d/$name -ef "$0" ]]; then #is it actually myself? (symbol link also works) 24 | foundMyself=YES 25 | elif [[ $foundMyself ]]; then 26 | EXE_PATH=$d/$name 27 | break 28 | fi 29 | fi 30 | done 31 | [[ $EXE_PATH ]] && break; 32 | done 33 | 34 | if [[ ! $EXE_PATH ]]; then 35 | _msg "$EXE_NAME${ALT_EXE_NAME+ or }$ALT_EXE_NAME not found." 36 | exit 127 37 | fi 38 | 39 | ############################################################################### 40 | #output command line 41 | 42 | CCACHE=""; [[ $USE_CCACHE == 1 ]] && case $EXE_NAME in gcc|g++|cc|c++|clang|clang++) CCACHE=ccache;; esac 43 | 44 | if [[ $AGCC_VERBOSE == 1 || $AGCC_DBG == 1 ]]; then 45 | function _raw_msg { echo "$@" >&2; } 46 | 47 | _raw_msg '$___' $CCACHE "'$EXE_PATH'" \\ 48 | 49 | spaces='$___ ' 50 | 51 | i=0 52 | for arg in "$@"; do 53 | ((i++)) 54 | arg=${arg//\'/\\\'} #replace ' with \' 55 | if [[ $i == $# ]]; then 56 | _raw_msg "$spaces" "'$arg'" 57 | else 58 | _raw_msg "$spaces" "'$arg'" \\ 59 | fi 60 | done 61 | 62 | [[ $# == 0 ]] && _raw_msg "" 63 | fi 64 | 65 | ############################################################################### 66 | #run command via ccache 67 | 68 | exec $CCACHE "$EXE_PATH" "$@" 69 | -------------------------------------------------------------------------------- /host/ar-dual-os/ar: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | EXE_NAME=ar 3 | function _msg { echo "[ar-dual-os]" "$@" >&2; } 4 | function _dbg { [[ $AGCC_DBG == 1 ]] && _msg "$@"; } 5 | 6 | ############################################################################### 7 | #Search the exe behind me in $PATH. Even faster than {for f in `type -ap name`} 8 | 9 | IFS=: pathList=($PATH); unset IFS #split $PATH by :, save to array 10 | 11 | EXE_PATH=""; foundMyself="" 12 | for d in "${pathList[@]}"; do 13 | if [[ -f $d/$EXE_NAME && -x $d/$EXE_NAME ]]; then 14 | if [[ $d/$EXE_NAME -ef "$0" ]]; then #is it actually myself? (symbol link also works) 15 | foundMyself=YES 16 | elif [[ $foundMyself ]]; then 17 | EXE_PATH=$d/$EXE_NAME 18 | break 19 | fi 20 | fi 21 | done 22 | 23 | if [[ ! $EXE_PATH ]]; then 24 | _msg "$EXE_NAME not found." 25 | exit 127 26 | fi 27 | 28 | ############################################################################### 29 | #get path of target-side ar and objdump from \$AR_target 30 | 31 | if [[ ! $AR_target ]]; then 32 | _msg "AR_target not defined." 33 | exit 1 34 | fi 35 | 36 | #AR_target maybe contains quot itself, so remove it first 37 | AR_target="${AR_target//\"}" 38 | #replace last "ar" with "objdump" 39 | objdump=${AR_target/%ar/objdump} 40 | 41 | ############################################################################### 42 | #get non-zero a *.o file from arguments 43 | 44 | OBJ_FILE="" 45 | for f in "$@"; do 46 | if [[ ${f/*.} == o && -s $f ]]; then 47 | OBJ_FILE=$f 48 | break 49 | fi 50 | done 51 | 52 | ############################################################################### 53 | #use target objdump to test .o file, if OK, then run target ar 54 | 55 | if [[ $OBJ_FILE ]]; then 56 | _dbg "check '$OBJ_FILE' by run '$objdump' -a on it" 57 | if "$objdump" -a "$OBJ_FILE" >/dev/null 2>/dev/null; then 58 | _msg "call '$AR_target'" 59 | exec "$AR_target" "$@" 60 | exit 61 | fi 62 | else 63 | _msg "no any non-empty *.o file provided for type check." 64 | fi 65 | 66 | ############################################################################### 67 | #otherwise call host ar 68 | 69 | _msg "call '$EXE_PATH'" 70 | exec "$EXE_PATH" "$@" 71 | -------------------------------------------------------------------------------- /host/gcc-no-lrt/gcc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | EXE_NAME=${0##*/} 3 | function _msg { echo "[$EXE_NAME-no-lrt]" "$@" >&2; } 4 | function _dbg { [[ $AGCC_DBG == 1 ]] && _msg "$@"; } 5 | 6 | ############################################################################### 7 | #Search the exe behind me in $PATH. Even faster than {for f in `type -ap name`} 8 | 9 | case $EXE_NAME in 10 | cc) ALT_EXE_NAME="gcc";; 11 | gcc) ALT_EXE_NAME="cc";; 12 | c++) ALT_EXE_NAME="g++";; 13 | g++) ALT_EXE_NAME="c++";; 14 | *) unset ALT_EXE_NAME;; 15 | esac 16 | 17 | IFS=: pathList=($PATH); unset IFS #split $PATH by :, save to array 18 | 19 | for name in $EXE_NAME $ALT_EXE_NAME; do 20 | EXE_PATH=""; foundMyself="" 21 | for d in "${pathList[@]}"; do 22 | if [[ -f $d/$name && -x $d/$name ]]; then 23 | if [[ $d/$name -ef "$0" ]]; then #is it actually myself? (symbol link also works) 24 | foundMyself=YES 25 | elif [[ $foundMyself ]]; then 26 | EXE_PATH=$d/$name 27 | break 28 | fi 29 | fi 30 | done 31 | [[ $EXE_PATH ]] && break; 32 | done 33 | 34 | if [[ ! $EXE_PATH ]]; then 35 | _msg "$EXE_NAME${ALT_EXE_NAME+ or }$ALT_EXE_NAME not found." 36 | exit 127 37 | fi 38 | 39 | ############################################################################### 40 | #if already have no -lrt option then run command without change. 41 | 42 | ind=""; count=0; i=0 43 | for arg in "$@"; do 44 | if [[ $arg == -lrt ]]; then 45 | if [[ $count == 0 ]]; then 46 | ind=$i 47 | count=1 48 | elif [[ $count == 1 ]]; then 49 | count=">=2" 50 | break 51 | fi 52 | fi 53 | ((i++)) 54 | done 55 | 56 | if [[ ! $ind ]]; then 57 | _dbg "call '$EXE_PATH' (no -lrt option yet)" 58 | exec "$EXE_PATH" "$@" 59 | exit 60 | fi 61 | 62 | _dbg found count: $count, first ind: $ind 63 | 64 | ############################################################################### 65 | #otherwise run command without -lrt 66 | 67 | _msg "call '$EXE_PATH' without -lrt option" 68 | if [[ $count == 1 ]]; then 69 | exec "$EXE_PATH" "${@:1:$ind}" "${@:$((ind+2))}" 70 | else 71 | ARGS=() 72 | for arg in "$@"; do 73 | [[ $arg != -lrt ]] && ARGS[${#ARGS[@]}]=$arg 74 | done 75 | exec "$EXE_PATH" "${ARGS[@]}" 76 | fi 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # android-gcc-toolchain 2 | Enable you to use NDK's standalone toolchain easily, quickly and magically for cross-compile. 3 | 4 | As an example, see [Build NodeJS for Android perfectly](https://github.com/sjitech/build-nodejs-for-android-perfectly). 5 | 6 | Tested OS: 7 | - **Mac**: OS X 10.11.5/10.11.6 EI Capitan (64bit) 8 | - **Linux**: Ubuntu 16.04 (64bit) 9 | - **Windows**: Windows Pro 7 (64bit). With [GIT Bash for Windows](https://git-for-windows.github.io/) installed. 10 | 11 | Also tested in Docker (Docker image id: `osexp2000/android-gcc-toolchain`) 12 | via [Docker-Toolbox](https://www.docker.com/products/docker-toolbox). 13 | See [Features-9: Use this tool in Docker](#docker). 14 | 15 | ## Prerequisite 16 | 17 | NDK: tested on 18 | - [NDK 12.1.29](https://developer.android.com/ndk/downloads/index.html) 19 | 20 | Install Android NDK and set env var `NDK` to the dir: `export NDK=__the_top_dir_of_installed_NDK__`. 21 | 22 | Otherwise, it will guess NDK dir from env vars: ANDROID_NDK_ROOT ANDROID_NDK_HOME NDK_ROOT NDKROOT ANDROID_NDK ANDROID_SDK_HOME 23 | ANDROID_SDK_ROOT ANDROID_SDK ANDROID_HOME ANDROID_ROOT. 24 | 25 | *With NDK, you do not need to install python, make, awk* 26 | 27 | ## Install 28 | 29 | Nothing. Just use the `android-gcc-toolchain` with full path, 30 | otherwise link it to /usr/local/bin/ or add the path to the $PATH. 31 | 32 | 33 | If you clean & compile repeatedly, **you'd better setup [CCACHE](https://ccache.samba.org/) to speed up repeating compilation**. 34 | - Run `brew install ccache` on Mac or `sudo apt-get install ccache` on Linux 35 | - `export USE_CCACHE=1` to tell android-gcc-toolchain to use CCACHE. 36 | - optional: `export CCACHE_DIR=some_dir_in_fast_disk`(default is ~/.ccache). 37 | - optional: run `ccache -M 50G` once to set max cache size(default is 5G). 38 | 39 | ## Screenshot 40 | 41 | - Run android gcc related commands easily 42 | 43 | ![android-gcc](img/android-gcc.png) 44 | 45 | 46 | - Enter a dedicated shell where can run android gcc related commands easily 47 | 48 | ![android-gcc-enter](img/android-gcc-enter.png) 49 | 50 | ## Usage 51 | 52 | Run commands in an android-oriented cross-compile environment. 53 | 54 | *Note: words in `[ ]` means may be omitted. "|" means "or". {...} means selection. (default) means can be omitted* 55 | 56 | ``` 57 | Usage: android-gcc-toolchain [OPTIONS] [CMD [ARGS...]] 58 | -------------------------------------------------------------------------------- 59 | OPTIONS: for toolchain, env mode, host compiler,... 60 | 61 | Toolchain options: specify which toolchain to use or create 62 | [--arch] ARCH Android architecture: 63 | {arm(default)|arm64|x86|x86_64|mips|mips64} or aliases: 64 | i386,ia32(=x86), x64(=x86_64), mipsel, mipsel64 65 | --api APIL Android API level: 66 | {min(default)|max|an integer} 67 | --stl STL C++ STL to use: 68 | {gnustl(default)|libc++|stlport} 69 | --force Delete existing toolchain dir then create 70 | --copy Force copy files instead of create hard link of files when 71 | create toolchain first time 72 | 73 | Env mode options: Specify whether set $PATH or $CC... or $CC_target... 74 | omitted This is the Redirect mode. 75 | Set $PATH to redirect gcc... to the toolchain's gcc... 76 | e.g. export PATH=$NDK/std-toolchains/.../bin:$PATH 77 | -c Set $CC,$CXX,$LINK,$AR,$AS,$RANLIB,$LD,$STRIP,$NM 78 | e.g. export CC=$NDK/std-toolchains/.../bin/gcc 79 | -C Set $CC_target,$CXX_target,$LINK_target,...,$NM_target 80 | e.g. export CC_target=$NDK/std-toolchains/.../bin/gcc 81 | 82 | Host compiler option: Add/remove options to host compiler forcibly 83 | --host RULES Mandatory host compiler rules. Must be a comma joined 84 | combination of available rules(Use --list-host-rules to show). 85 | This is done by supersede host compiler in $PATH by some 86 | wrapper scripts to add/remove option then transfer to original. 87 | 88 | Other options: 89 | -v, --verbose Show verbose information, include compiler arguments 90 | --version Show version of this tool 91 | -------------------------------------------------------------------------------- 92 | CMD and ARGS: The external command to be run 93 | 94 | CMD Any command. Default is /bin/bash. 95 | To avoid ambiguous with other option, place - or -- before CMD 96 | ARGS... The arguments for the CMD 97 | -------------------------------------------------------------------------------- 98 | Environment variables affecting this tool 99 | 100 | USE_CCACHE=1 Compilers(gcc/g++/cc/c++/clang/clang++) will run via ccache 101 | AGCC_VERBOSE=1 Compilers(include ar as ranlib ld strip nm) will show arguments 102 | ``` 103 | ---- 104 | 105 | ## Features 106 | 107 | ### 1. Run android gcc related commands easily. 108 | 109 | - Just prepend `android-gcc-toolchain` to your gcc related command. 110 | 111 | ``` 112 | android-gcc-toolchain gcc a.c 113 | android-gcc-toolchain arm64 gcc a.c 114 | ``` 115 | 116 | 117 | ### 2. Start a dedicated shell where can run android gcc related commands easily ([Screenshot](#dedicated-shell-screenshot)). 118 | 119 | - start an interactive shell with gcc... ready 120 | 121 | ``` 122 | android-gcc-toolchain arm64 #bash 123 | android-gcc-toolchain arm64 zsh #zsh 124 | ``` 125 | 126 | See also: [About Redirect Mode](#about-redirect-mode) 127 | 128 | - start an interactive bash with $CC... predefined 129 | 130 | ``` 131 | android-gcc-toolchain arm64 -c 132 | ``` 133 | 134 | See also: [About env vars passed to CMD](#about-env-vars-passed-to-cmd) 135 | 136 | - start an interactive bash with $CC_target... predefined 137 | 138 | ``` 139 | android-gcc-toolchain arm64 -C 140 | ``` 141 | 142 | See also: [About env vars passed to CMD](#about-env-vars-passed-to-cmd). 143 | 144 | 145 | - *Notes* 146 | 147 | To feed multiple commands to the shell non-interactively, 148 | you can use `< 241 | ### 9. Use this tool in Docker (Docker image id: `osexp2000/android-gcc-toolchain`) 242 | 243 | Assume in current dir($PWD) there are some files to be compiled by android compiler, then you can 244 | use following ways to compile it with the docker image. As a result, you will get result_exe in current dir. 245 | 246 | - Run docker to enter a interactive [dedicated shell](#dedicated-shell). e.g. 247 | 248 | ``` 249 | $ docker run -it -v $PWD:/work osexp2000/android-gcc-toolchain arm64 250 | [android-21-arm64] cd /work && gcc a.cc -o result_exe 251 | ``` 252 | 253 | - Run docker and specify single command directly 254 | 255 | ``` 256 | docker run -v $PWD:/work osexp2000/android-gcc-toolchain arm64 g++ /work/a.cc -o /work/result_exe 257 | ``` 258 | 259 | - Run docker and feed multiple commands to it with Here String 260 | 261 | ``` 262 | docker run -i -v $PWD:/work osexp2000/android-gcc-toolchain arm64 <<< "cd /work && g++ a.cc -o result_exe" 263 | ``` 264 | 265 | - Run docker and feed multiple commands to it with Here Document 266 | 267 | ``` 268 | docker run -i -v $PWD:/work osexp2000/android-gcc-toolchain arm64 < 280 | ### 10. Show compiler command line in verbose mode 281 | 282 | - Triggered by env var `AGCC_VERBOSE=1` or specifying `-v` or `--verbose` option to `android-gcc-toolchain`, 283 | when any compiler(gcc g++ cc c++ clang clang++ ar as ranlib ld strip nm) process 284 | started from android-gcc-toolchain, its command line will be output. 285 | 286 | The output command line example: 287 | ``` 288 | $___ ccache '/Users/q/Library/Android/sdk/ndk-bundle/std-toolchains/android-9-arm/bin/arm-linux-androideabi-c++' \ 289 | $___ '-D_GLIBCXX_USE_C99_MATH' \ 290 | $___ '-I../deps/gtest' \ 291 | $___ '-I../deps/gtest/include' \ 292 | $___ '-Wall' \ 293 | $___ '-Wextra' \ 294 | $___ '-Wno-unused-parameter' \ 295 | $___ '-Wno-missing-field-initializers' \ 296 | $___ '-O3' \ 297 | $___ '-fno-omit-frame-pointer' \ 298 | $___ '-fPIE' \ 299 | $___ '-fno-rtti' \ 300 | $___ '-fno-exceptions' \ 301 | $___ '-std=gnu++0x' \ 302 | $___ '-MMD' \ 303 | $___ '-MF' \ 304 | $___ '/Users/q/Downloads/node/out/Release/.deps//Users/q/Downloads/node/out/Release/obj.target/gtest/deps/gtest/src/gtest-filepath.o.d.raw' \ 305 | $___ '-c' \ 306 | $___ '-o' \ 307 | $___ '/Users/q/Downloads/node/out/Release/obj.target/gtest/deps/gtest/src/gtest-filepath.o' \ 308 | $___ '../deps/gtest/src/gtest-filepath.cc' 309 | ``` 310 | Each line is prefixed by $___ which is just for grep easily. Because $___ is empty string, you can copy paste lines to 311 | other place to run without modifying. 312 | 313 | ### 11. (TODO) Support brew install, bash_autocomplete 314 | 315 | ---- 316 | 317 | ## About where the toolchain created and what's in it 318 | 319 | - This tool create dir in your NDK dir, in following format: 320 | `$NDK/std-toolchains/android-APIL-ARCH[STL_TAG]` 321 | 322 | - If NDK is upgraded, please specify `--force` to recreate toolchains 323 | 324 | - Basically, the toolchain is created by on-fly modified version of `$NDK/build/tools/make_standalone_toolchain.py`, 325 | Use hard link by default instead of copy 326 | 327 | - Some extra works: 328 | - Removed NDK's python,make,awk,yasm,gdb,ndk-depends... (prebuilt common utilities) from toolchain bin dir. 329 | As a fallback, append $NDK/prebuilt/*/bin/ to PATH so these utilities are available if no existing one. 330 | - For default gnustl C++ STL only: enable use of `std::snprintf` 331 | by `#inlcude ` or `#include ` like libc++ 332 | - Insert definition of `std::snprintf` to "$BIN"/../include/c++/?.?.?/cstdio 333 | - Append `#include ` to "$BIN"/../include/c++/?.?.?/string 334 | - For mipsel gnustl only: ln -f "$BIN"/../include/c++/?.?.?/*/bits/*.h "$BIN"/../include/c++/?.?.?/bits/ 335 | to avoid error of `bits/c++config.h not found` when specified `-mips32r2` to gcc/g++. 336 | - For CCACHE in Redirect Mode: created wrapper scripts in $BIN/../ccache/. 337 | - For CCACHE compiler hash: if use non default Android API level or non default C++ stl, then to let CCACHE know 338 | compiler's include files changes, this tool set different timestamp to compiler commands gcc g++ cc c++ clang clang++. 339 | 340 | *?.?.? means gcc version such as 4.9.x* 341 | 342 | ### About NDK python,make,awk,yasm,gdb,ndk-depends... (prebuilt common utilities) 343 | 344 | - The \$NDK/prebuilt/*/bin/ are always appended to \$PATH. so these utilities are 345 | always available, but not the first choice in \$PATH 346 | 347 | ## About Redirect mode 348 | 349 | In this mode(means without -c|-C), the following commands are redirected to the toolchain's one. 350 | 351 | - gcc g++ cc c++ clang clang++ ar as ranlib ld strip nm ... 352 | - readelf objdump c++filt elfedit objcopy strings size ... 353 | 354 | *cc is just a link to gcc* 355 | 356 | *gdb is also available from $NDK/prebuilt/*/bin/ which already appended to $PATH* 357 | 358 | ## About env vars passed to CMD 359 | 360 | - PATH: will be changed under certain conditions: 361 | use [Redirect mode](#about-redirect-mode) 362 | or use [Mandatory host compiler rules](#host-compiler-rules)) 363 | or use CCACHE([About how CCACHE are used](#about-how-ccache-are-used)). 364 | When called recursively, it will be restored first 365 | - GYP_DEFINES: will be set to "host_os=" to specify host_os for gyp. 366 | - Following vars will be set for $CC mode(-c) or $CC_target mode(-C), otherwise cleared: 367 | - CC CXX LINK AR CC_target CXX_target LINK_target AR_target 368 | - AS RANLIB LD STRIP NM AS_target RANLIB_target LD_target STRIP_target NM_target 369 | - BIN: will be set as mnemonics, means the toolchain's bin dir 370 | - AGCC_BIN AGCC_HOST_COMPILERS_DIR: will be set for internal cleaner 371 | - AGCC_VERBOSE=1 if -v(--verbose) is specified 372 | 373 | ## About how CCACHE is used 374 | 375 | - Triggered by env var `USE_CCACHE=1` 376 | - gcc g++ cc c++ clang clang++ will run via ccache 377 | - Android compilers in $BIN dir are created as wrapper scripts which call ccache 378 | - Host compilers are superseded in $PATH by wrapper scripts which call ccache 379 | 380 | 381 | 382 | ## About Mandatory host compiler rules (--host RULES): 383 | 384 | This tool provide wrapper scripts to supersede compiler commands(gcc|g++|cc|c++|clang|clang++) via $PATH, optionally. 385 | These wrapper scripts 386 | - smartly find original compiler command in $PATH behind itself, 387 | - add or remove options then transfer to original compiler command. 388 | - can be chained. The first specified, the first run. 389 | 390 | The mandatory host compiler rules solves some common cross-compile problems on Mac or Linux: 391 | 392 | - [Mac] **ar**: Some projects does not honor `$AR_target` when make android static 393 | lib(*.a). Instead, they call Mac ar command, so cause link error. 394 | 395 | `--host ar-dual-os` detect input \*.o file format, Mac or android, then call correct one. 396 | 397 | - [Mac] **-lrt**: Some projects use link option `-lrt` (librt) comes from linux, but 398 | Mac have no librt, so cause link error "library not found for -lrt". 399 | 400 | `--host gcc-no-lrt` remove -lrt option. 401 | 402 | - [Mac/Linux] **-m32**: On 64bit OS, some projects added `-m32` option to gcc to produce 403 | 32bit codes, but some forgot, cause link error of mixing 64 and 32bit codes. 404 | 405 | `--host gcc-m32` prepend -m32 option if not specified. 406 | 407 | - [Linux] **-lpthread**: Some projects forgot to add this option so cause strange link error: 408 | `...libpthread.so.0: error adding symbols: DSO missing from command line`. 409 | 410 | `--host gcc-lpthread` append -lpthread option, only when found any other -l option. 411 | 412 | ---- 413 | Good luck. 414 | -------------------------------------------------------------------------------- /android-gcc-toolchain: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | function _msg { echo "$@" >&2; } 3 | function _dbg { [[ $AGCC_DBG == 1 ]] && echo "$@" >&2; } 4 | function _guide { echo "" "$@" >&2; } 5 | 6 | VERSION=2.2 7 | 8 | _EXE=""; case $OSTYPE in msys|cygwin) _EXE=.exe;; esac 9 | 10 | thisDir=${0%/*}; [[ $0 != */* ]] && thisDir=. 11 | if target=`readlink "$0"`; then if [[ $target == /* ]]; then thisDir=${target%/*}; elif [[ $target == */* ]]; then thisDir+=/${target%/*}; fi; fi 12 | _dbg "thisDir: '$thisDir'" 13 | hackDir=$thisDir/host 14 | 15 | [[ ! $NDK ]] && for d in "$ANDROID_NDK_ROOT" "$ANDROID_NDK_HOME" "$NDK_ROOT" "$NDKROOT" "$ANDROID_NDK"; do 16 | [[ $d ]] && export NDK=$d && break 17 | done 18 | [[ ! $NDK ]] && for d in "$ANDROID_SDK_HOME" "$ANDROID_SDK_ROOT" "$ANDROID_SDK" "$ANDROID_HOME" "$ANDROID_ROOT"; do 19 | [[ $d ]] && export NDK=$d/ndk-bundle && break 20 | done 21 | 22 | ARCH=""; APIL=""; STL=""; FORCE=""; ENV_MODE=""; CMD=""; HACK=""; HACK_LIST=(); VERBOSE=""; COPY=""; 23 | 24 | while [[ $# -gt 0 ]]; do 25 | _dbg "'$1'" 26 | case $1 in 27 | --arch) case $2 in arm|arm64|x86|x86_64|mips|mips64|i386|ia32|x64|mipsel|mipsel64) ARCH=$2; _dbg " ARCH='$2'"; shift;; 28 | ""|-*) _msg "expect arch behind $1. Must be arm(default)|arm64|x86|x86_64|mips|mips64 or aliases i386|ia32|x64|mipsel|mipsel64"; exit 1;; 29 | *) _msg "invalid arch '$2'. Must be arm(default)|arm64|x86|x86_64|mips|mips64 or aliases i386|ia32|x64|mipsel|mipsel64"; exit 1;; 30 | esac 31 | ;; 32 | --api) case $2 in min|max) APIL=$2; _dbg " APIL='$2'"; shift;; 33 | ""|-*) _msg "expect Android API level behind $1. Must be min(default)|max|an integer"; exit 1;; 34 | *[!0-9]*) _msg "invalid Android API level '$2'. Must be min(default)|max|an integer"; exit 1;; 35 | *) APIL=$2; _dbg " APIL='$2'"; shift;; 36 | esac 37 | ;; 38 | --stl) case $2 in gnustl|libc++|stlport) STL=$2; _dbg " STL='$2'"; shift;; 39 | ""|-*) _msg "expect C++ STL behind $1. Must be gnustl(default)|libc++|stlport"; exit 1;; 40 | *) _msg "invalid C++ STL '$2'. Must be gnustl(default)|libc++|stlport"; exit 1;; 41 | esac 42 | ;; 43 | --host) case $2 in 44 | ""|-*) _msg "expect host compiler rules behind $1. Must be combination of available rules(use --list-host-rules to show), joined by comma"; exit 1;; 45 | *) HACK=$2; _dbg " HACK='$2'"; shift;; 46 | esac 47 | ;; 48 | --force) 49 | FORCE=$1; _dbg " ->FORCE" 50 | ;; 51 | -v|--verbose) 52 | VERBOSE=--verbose; _dbg " ->VERBOSE" 53 | ;; 54 | --copy) 55 | COPY=$1; _dbg " ->COPY" 56 | ;; 57 | arm|arm64|x86|x86_64|mips|mips64|i386|ia32|x64|mipsel|mipsel64) 58 | ARCH=$1; _dbg " ->ARCH" 59 | ;; 60 | -c|-C) 61 | ENV_MODE=$1; _dbg " ->ENV_MODE" 62 | ;; 63 | -|--) case $2 in ""|-*) _msg "expect external command behind $1"; exit 1;; esac 64 | CMD=$2; _dbg " CMD='$2'" 65 | shift; shift 66 | break 67 | ;; 68 | --help|--version|--list-host-rules) 69 | break 70 | ;; 71 | --*) 72 | _msg "invalid long option '$1'. Must be --arch|--api|--stl|--force|--verbose|--copy|--host|--version|--help|--list-host-rules" 73 | exit 1 74 | ;; 75 | -*) 76 | _msg "invalid short option '$1'. Must be -c(set \$CC...) or -C(set \$CC_target...), or -v(verbose)" 77 | exit 1 78 | ;; 79 | "") 80 | _dbg " :skip isolated empty arg" 81 | ;; 82 | *) 83 | CMD=$1; _dbg " ->CMD" 84 | shift 85 | break 86 | ;; 87 | esac 88 | 89 | shift 90 | done 91 | 92 | [[ ! $CMD ]] && \ 93 | case $1 in 94 | --help) 95 | _msg "android-gcc-toolchain $VERSION" 96 | _msg "Run commands in an android-oriented cross-compile environment." 97 | _msg "" 98 | _msg "Usage: android-gcc-toolchain [OPTIONS] [CMD [ARGS...]]" 99 | _msg "--------------------------------------------------------------------------------" 100 | _msg "OPTIONS: for toolchain, env mode, host compiler,..." 101 | _msg "" 102 | _msg "Toolchain options: specify which toolchain to use or create" 103 | _msg " [--arch] ARCH Android architecture:" 104 | _msg " {arm(default)|arm64|x86|x86_64|mips|mips64} or aliases:" 105 | _msg " i386,ia32(=x86), x64(=x86_64), mipsel, mipsel64" 106 | _msg " --api APIL Android API level:" 107 | _msg " {min(default)|max|an integer}" 108 | _msg " --stl STL C++ STL to use:" 109 | _msg " {gnustl(default)|libc++|stlport}" 110 | _msg " --force Delete existing toolchain dir then create" 111 | _msg " --copy Force copy files instead of create hard link of files when" 112 | _msg " create toolchain first time" 113 | _msg "" 114 | _msg "Env mode options: Specify whether set \$PATH or \$CC... or \$CC_target..." 115 | _msg " omitted This is the Redirect mode." 116 | _msg " Set \$PATH to redirect gcc... to the toolchain's gcc..." 117 | _msg " e.g. export PATH=\$NDK/std-toolchains/.../bin:\$PATH" 118 | _msg " -c Set \$CC,\$CXX,\$LINK,\$AR,\$AS,\$RANLIB,\$LD,\$STRIP,\$NM" 119 | _msg " e.g. export CC=\$NDK/std-toolchains/.../bin/gcc" 120 | _msg " -C Set \$CC_target,\$CXX_target,\$LINK_target,...,\$NM_target" 121 | _msg " e.g. export CC_target=\$NDK/std-toolchains/.../bin/gcc" 122 | _msg "" 123 | _msg "Host compiler option: Add/remove options to host compiler forcibly" 124 | _msg " --host RULES Mandatory host compiler rules. Must be a comma joined " 125 | _msg " combination of available rules(Use --list-host-rules to show)." 126 | _msg " This is done by supersede host compiler in \$PATH by some" 127 | _msg " wrapper scripts to add/remove option then transfer to original." 128 | _msg "" 129 | _msg "Other options:" 130 | _msg " -v, --verbose Show verbose information, include compiler arguments" 131 | _msg " --version Show version of this tool" 132 | _msg "--------------------------------------------------------------------------------" 133 | _msg "CMD and ARGS: The external command to be run" 134 | _msg "" 135 | _msg " CMD Any command. Default is /bin/bash." 136 | _msg " To avoid ambiguous with other option, place - or -- before CMD" 137 | _msg " ARGS... The arguments for the CMD" 138 | _msg "--------------------------------------------------------------------------------" 139 | _msg "Environment variables affecting this tool" 140 | _msg "" 141 | _msg " USE_CCACHE=1 Compilers(gcc/g++/cc/c++/clang/clang++) will run via ccache" 142 | _msg " AGCC_VERBOSE=1 Compilers(include ar as ranlib ld strip nm) will show arguments" 143 | _msg "--------------------------------------------------------------------------------" 144 | _msg "Quick examples" 145 | _msg "" 146 | _msg "#### compile a.c with android's gcc" 147 | _msg "android-gcc-toolchain arm64 gcc a.c" 148 | _msg "" 149 | _msg "#### start an interactive shell with gcc... ready" 150 | _msg "android-gcc-toolchain arm64 #bash" 151 | _msg "android-gcc-toolchain arm64 zsh #zsh" 152 | _msg "" 153 | _msg "#### start an interactive bash with \$CC... predefined" 154 | _msg "android-gcc-toolchain arm64 -c" 155 | _msg "" 156 | _msg "#### start an interactive bash with \$CC_target... predefined" 157 | _msg "android-gcc-toolchain arm64 -C" 158 | _msg "" 159 | _msg "#### cross-compile ffmpeg" 160 | _msg "android-gcc-toolchain arm64 <<<\"./configure --enable-cross-compile --arch=arm64 --target-os=linux \$OTHER_OPTIONS && make\"" 161 | _msg "" 162 | _msg "#### cross-compile nodejs with \$CC_target... ready and host compiler rules applied forcibly (on Mac)" 163 | _msg "android-gcc-toolchain arm64 --host ar-dual-os,gcc-no-librt -C <<<\"./configure --dest-cpu=arm64 --dest-os=android && make\"" 164 | _msg "" 165 | _msg "See README.md, https://github.com/sjitech/android-gcc-toolchain" 166 | exit 0 167 | ;; 168 | --list-host-rules) 169 | _msg "Available host compiler rules:" 170 | for d in "$hackDir"/*; do 171 | [[ $d == *\** ]] && break 172 | [[ $d == */-* ]] && continue; 173 | _msg " ${d##$hackDir/}" 174 | done 175 | _msg "See README.md, https://github.com/sjitech/android-gcc-toolchain#host-option" 176 | exit 0 177 | ;; 178 | --version) 179 | _msg $VERSION 180 | exit 0 181 | ;; 182 | esac 183 | 184 | if [[ $AGCC_DBG == 1 ]]; then 185 | _dbg "args {" 186 | _dbg " ARCH $ARCH" 187 | _dbg " APIL $APIL" 188 | _dbg " STL $STL" 189 | _dbg " FORCE $FORCE" 190 | _dbg " VERBOSE $VERBOSE" 191 | _dbg " COPY $COPY" 192 | _dbg " HACK $HACK" 193 | _dbg " ENV_MODE $ENV_MODE" 194 | _dbg " CMD $CMD" 195 | _dbg " #ARGS $#" 196 | _dbg "}" 197 | fi 198 | 199 | ################################################################################ 200 | #check arch and cross-compile executable's name prefix 201 | case ${ARCH:=arm} in 202 | arm) ARCH_PREFIX=arm-linux-androideabi- ;; 203 | arm64) ARCH_PREFIX=aarch64-linux-android- ;; 204 | x86|i386|ia32) ARCH=x86; ARCH_PREFIX=i686-linux-android- ;; 205 | x86_64|x64) ARCH=x86_64; ARCH_PREFIX=x86_64-linux-android- ;; 206 | mips|mipsel) ARCH=mips; ARCH_PREFIX=mipsel-linux-android- ;; 207 | mips64|mipsel64) ARCH=mips64; ARCH_PREFIX=mips64el-linux-android- ;; 208 | *) _msg "invalid arch '$ARCH'. Must be arm(default)|arm64|x86|x86_64|mips|mips64 or aliases i386|ia32|x64|mipsel|mipsel64"; exit 1 ;; 209 | esac 210 | 211 | ################################################################################ 212 | #check Android API level 213 | minAPIL="" 214 | case ${APIL:=min} in 215 | min|max) 216 | [[ ! $NDK ]] && { _msg "\$NDK not set. Can not guess from \$ANDROID_NDK_ROOT, \$ANDROID_SDK_HOME,... Please run: export NDK=dir_of_NDK"; exit 1; } 217 | dirPrefix=$NDK/platforms/android- 218 | dirSuffix=/arch-$ARCH 219 | dirList=() #save ordered dir list 220 | 221 | #glob dir list, add to dirList if globed. 222 | tmpList=("$dirPrefix"?$dirSuffix) 223 | [[ ${tmpList[0]} != *\?* ]] && dirList+=("${tmpList[@]}") 224 | tmpList=("$dirPrefix"??$dirSuffix) 225 | [[ ${tmpList[0]} != *\?* ]] && dirList+=("${tmpList[@]}") 226 | tmpList=("$dirPrefix"???$dirSuffix) 227 | [[ ${tmpList[0]} != *\?* ]] && dirList+=("${tmpList[@]}") 228 | 229 | #get first or last dir name, e.x. ...android-9/arch-... or ...android-24/arch-... 230 | if [[ $APIL == min ]]; then 231 | APIL=${dirList[0]} 232 | minAPIL=$APIL 233 | else 234 | APIL=${dirList[${#dirList[@]}-1]} 235 | fi 236 | 237 | #remove prefix and suffix to get pure number 238 | APIL=${APIL#$dirPrefix} 239 | APIL=${APIL%$dirSuffix} 240 | 241 | [[ ! $APIL ]] && { _msg "invalid NDK. The platforms/android-*/arch-$ARCH not found at \$NDK($NDK)"; exit 1; } 242 | [[ $minAPIL ]] && minAPIL=$APIL 243 | ;; 244 | *[!0-9]*) 245 | _msg "invalid Android API level '$APIL'. Must be min(default)|max|an integer"; exit 1 246 | ;; 247 | esac 248 | 249 | ################################################################################ 250 | #check C++ STL 251 | case ${STL:=gnustl} in 252 | gnustl ) STL_TAG="" ;; 253 | libc++ ) STL_TAG=-libc++ ;; 254 | stlport) STL_TAG=-stlport ;; 255 | *) _msg "invalid C++ STL '$STL'. Must be gnustl(default)|libc++|stlport"; exit 1 ;; 256 | esac 257 | 258 | ################################################################################ 259 | #check USE_CCACHE 260 | if [[ $USE_CCACHE == 1 ]]; then 261 | type -p ccache > /dev/null || { unset USE_CCACHE; _msg "\$USE_CCACHE=1 but ccache is not found in \$PATH"; } 262 | fi 263 | 264 | ################################################################################ 265 | #check host compiler rules 266 | if [[ $HACK || $ENV_MODE ]]; then 267 | 268 | hoList=() 269 | if [[ $HACK ]]; then 270 | #replace comma with space, then convert to array, then remote empty items 271 | hoList=(${HACK//,/ }); hoList=(${hoList[@]}) 272 | [[ ! ${hoList[0]} ]] && { _msg "invalid host compiler rules '$HACK'. Use --list-host-rules to show available rules"; exit 1; } 273 | fi 274 | 275 | function already_checked { local ho; for ho in "${HACK_LIST[@]}"; do [[ $1 == $ho ]] && return 0; done; return 1; } 276 | 277 | #append internal host compiler rule "-compilers" to list. 278 | #check each item of the combined list 279 | for ho in "${hoList[@]}"; do 280 | [[ $ho == -* || $ho == */* || $ho == . || $ho == .. || ! -d $hackDir/$ho ]] && { _msg "invalid host compiler rule '$ho'. Use --list-host-rules to show available rules"; exit 1; } 281 | already_checked "$ho" || HACK_LIST+=($ho) 282 | done 283 | 284 | [[ $ENV_MODE ]] && HACK_LIST+=(-compilers) 285 | fi 286 | 287 | ################################################################################ 288 | if [[ $AGCC_DBG == 1 ]]; then 289 | _dbg "args {" 290 | _dbg " ARCH $ARCH" 291 | _dbg " APIL $APIL" 292 | _dbg " STL $STL" 293 | _dbg " FORCE $FORCE" 294 | _dbg " VERBOSE $VERBOSE" 295 | _dbg " COPY $COPY" 296 | _dbg " HACK $HACK" 297 | _dbg " HACK_LIST(${HACK_LIST[@]})" 298 | _dbg " ENV_MODE $ENV_MODE" 299 | _dbg " CMD $CMD" 300 | _dbg " #ARGS $#" 301 | _dbg "}" 302 | fi 303 | 304 | ################################################################################ 305 | #create or check standalone toolchain 306 | [[ ! $NDK ]] && { _msg "\$NDK is not set. Can not guess from \$ANDROID_NDK_ROOT, \$ANDROID_SDK_HOME,... Please run: export NDK=dir_of_NDK"; exit 1; } 307 | TC_NAME=android-$APIL-$ARCH$STL_TAG 308 | TC_TOP=$NDK/std-toolchains/$TC_NAME 309 | BIN=$TC_TOP/bin 310 | BIN_ARCH_PREFIX=$BIN/$ARCH_PREFIX 311 | 312 | #the $NDK/prebuilt/*/bin contains python make awk, 313 | # append it to $PATH to ensure python can be found even if no existing one 314 | fileList=("$NDK"/prebuilt/*/bin/python) 315 | [[ ${fileList[0]} == *\** ]] && { _msg "invalid NDK. The prebuilt/*/bin/python not found at \$NDK($NDK)"; exit 1; } 316 | PREBUILT_BIN=${fileList[0]%/*}; _dbg "NDK prebuilt bin dir confirmed: $PREBUILT_BIN" 317 | case $PATH in *:$PREBUILT_BIN:*|*:$PREBUILT_BIN|$PREBUILT_BIN:*) _dbg "already in \$PATH";; 318 | *) export PATH=$PATH:$PREBUILT_BIN; _dbg "appended to \$PATH" 319 | esac 320 | 321 | if [[ ! -d $TC_TOP || $FORCE ]]; then 322 | _msg "Make std-toolchains/$TC_NAME at \$NDK($NDK)" 323 | 324 | #try to extract platform files from compressed file. 325 | extracted="" 326 | if [[ ! -d $NDK/platforms/android-$APIL/arch-$ARCH/usr && -f $NDK/platforms.7z ]]; then 327 | if type -p 7z >/dev/null; then 328 | _msg "Extract platforms/android-$APIL/arch-$ARCH/usr/* from \$NDK/platforms.7z" 329 | ( \ 330 | cd "$NDK" \ 331 | && { [[ -d tmp ]] || mkdir tmp; } \ 332 | && cd tmp \ 333 | && 7z x -y ../platforms.7z platforms/android-$APIL/arch-$ARCH/usr \ 334 | | grep -vE '^Extracting|^Skipping|^$'; \ 335 | exit ${PIPESTATUS[0]} \ 336 | ) \ 337 | && mv -f "$NDK"/tmp/platforms/android-$APIL/arch-$ARCH/usr "$NDK"/platforms/android-$APIL/arch-$ARCH/ \ 338 | && extracted=YES 339 | else 340 | _msg "The platform files(\$NDK/platforms/android-$APIL/arch-$ARCH/usr/) does not exists," \ 341 | _msg "so trying to extract files from \$NDK/platforms.7z with 7z." 342 | _msg "Unfortunately 7z not found. Please install 7z." 343 | fi 344 | fi 345 | 346 | [[ $FORCE ]] && { rm -fr "$TC_TOP" || mv -f "$TC_TOP" "$TC_TOP".old; } 347 | 348 | PY_FILE=$NDK/build/tools/make_standalone_toolchain.py 349 | if [[ $COPY ]]; then 350 | "$PY_FILE" --arch $ARCH --api $APIL --stl $STL --install-dir "$TC_TOP" $VERBOSE 351 | results=($? 0) 352 | else 353 | #use hard link as possible. Use customized copy2 and copytree to replace shutil.copy2 and shutil.copytree 354 | { cat "$thisDir"/lib/fast-copy.py \ 355 | && sed "s/__file__/os.environ['PY_FILE']/g;s/shutil\.copy2/copy2/g;s/shutil\.copytree/copytree/g" "$PY_FILE" \ 356 | ; } | VERBOSE=$VERBOSE PY_FILE=$PY_FILE python - --arch $ARCH --api $APIL --stl $STL --install-dir "$TC_TOP" $VERBOSE 357 | results=("${PIPESTATUS[@]}") 358 | fi 359 | 360 | [[ $extracted ]] && rm -fr "$NDK"/platforms/android-$APIL/arch-$ARCH/usr 361 | 362 | [[ ${results[0]} != 0 ]] && exit ${results[0]}; 363 | [[ ${results[1]} != 0 ]] && exit ${results[1]}; 364 | 365 | if [[ -f "$BIN_ARCH_PREFIX"gcc$_EXE && -x "$BIN_ARCH_PREFIX"gcc$_EXE ]]; then 366 | _msg "Done" 367 | else 368 | _msg "Failed to create toolchain." 369 | _msg "Please use --force --verbose to recreate toolchain." 370 | exit 1 371 | fi 372 | elif [[ ! -f "$BIN_ARCH_PREFIX"gcc$_EXE && -x "$BIN_ARCH_PREFIX"gcc$_EXE ]]; then 373 | _msg "invalid toolchain. The ${BIN_ARCH_PREFIX/#$NDK/}gcc$_EXE not found at \$NDK($NDK) or not executable." 374 | _msg "Please use --force --verbose to recreate toolchain." 375 | exit 1 376 | fi 377 | 378 | #create symbol links or wrapper scripts such as gcc for arm-linux-androideabi-gcc 379 | if [[ ! -f "$BIN"/.final-wrapper-created ]]; then 380 | 381 | #copy *-gcc as *-cc 382 | ln -f "$BIN_ARCH_PREFIX"gcc$_EXE "$BIN_ARCH_PREFIX"cc$_EXE || exit 383 | 384 | #create gcc wrapper 385 | s=gcc 386 | sed "s/\$ARCH_PREFIX/$ARCH_PREFIX/g" "$thisDir"/android/compiler-wrapper > "$BIN"/$s.tmp || exit 387 | chmod a+x "$BIN"/$s.tmp || exit 388 | mv -f "$BIN"/$s.tmp "$BIN"/$s || exit 389 | 390 | for f in "$BIN_ARCH_PREFIX"*$_EXE; do 391 | [[ $f == *\** ]] && break 392 | s=${f#$BIN_ARCH_PREFIX} #$BIN/arm-linux-androideabi-gcc.exe -> gcc.exe 393 | s=${s%$_EXE} #remove trailing ".exe" 394 | 395 | case $s in 396 | gcc) 397 | ;; 398 | g++|cc|c++|clang|clang++|ar|as|ranlib|ld|strip|nm) 399 | ln -sf gcc "$BIN"/$s || exit 400 | ;; 401 | *) 402 | ln -sf $ARCH_PREFIX$s$_EXE "$BIN"/$s || exit 403 | ;; 404 | esac 405 | done 406 | 407 | #get min Android API level 408 | if [[ $STL == gnustl && ! $minAPIL ]]; then 409 | dirPrefix=$NDK/platforms/android- 410 | dirSuffix=/arch-$ARCH 411 | dirList=() #save ordered dir list 412 | #glob dir list, add to dirList if globed. 413 | tmpList=("$dirPrefix"?$dirSuffix) 414 | [[ ${tmpList[0]} != *\?* ]] && dirList+=("${tmpList[@]}") 415 | tmpList=("$dirPrefix"??$dirSuffix) 416 | [[ ${tmpList[0]} != *\?* ]] && dirList+=("${tmpList[@]}") 417 | tmpList=("$dirPrefix"???$dirSuffix) 418 | [[ ${tmpList[0]} != *\?* ]] && dirList+=("${tmpList[@]}") 419 | #get first or last dir name, e.x. ...android-9/arch-... or ...android-24/arch-... 420 | minAPIL=${dirList[0]} 421 | #remove prefix and suffix to get pure number 422 | minAPIL=${minAPIL#$dirPrefix} 423 | minAPIL=${minAPIL%$dirSuffix} 424 | fi 425 | 426 | if [[ $STL != gnustl || $APIL != $minAPIL ]]; then 427 | 428 | #try to calculate a consistent timestamp based on STL and APIL and minAPIL 429 | year=2000; [[ ! $minAPIL || $APIL -lt $minAPIL ]] && { minAPIL=0; year=1999; } 430 | case $STL in gnustl) month=01;; libc++) month=03;; *) month=05;; esac 431 | ((day=(APIL-minAPIL)%30+1)); [[ ${#day} == 1 ]] && day=0$day 432 | ((almostZero=(APIL-minAPIL)/30)); 433 | ((hour=almostZero%60)); [[ ${#hour} == 1 ]] && hour=0$hour 434 | ((almostZero=almostZero/60)); 435 | ((minute=almostZero%60)); [[ ${#minute} == 1 ]] && minute=0$minute 436 | timestamp=$year$month$day$hour$minute 437 | _dbg set gcc $timestamp 438 | 439 | # By default CCACHE does not cache hash of system include files, while for toolchains with 440 | # same arch but different C++ STL or Android API level, the system include files changes, but 441 | # the compilers are still same, so CCACHE will be confused about compile result from different toolchains. 442 | # To avoid this problem, i have to make the compilers of each toolchain have a unique timestamp, e.g. 443 | # 2000/01/01/STL:APIL:00 444 | for s in gcc g++ cc c++ clang clang++; do 445 | f=$ARCH_PREFIX$s$_EXE 446 | cp -pf "$BIN"/$f "$BIN"/$f.tmp \ 447 | && touch -t $timestamp "$BIN"/$f.tmp \ 448 | && mv -f "$BIN"/$f.tmp "$BIN"/$f 449 | done 450 | else 451 | #clang/clang++ are wrapper script created by make_standalone_toolchain.py at calling time, 452 | # so the timestamp need be keep being same (as gcc), no matter when create toolchain 453 | touch -r "$BIN_ARCH_PREFIX"gcc$_EXE "$BIN_ARCH_PREFIX"clang$_EXE "$BIN_ARCH_PREFIX"clang++$_EXE 454 | fi 455 | 456 | touch "$BIN"/.final-wrapper-created 457 | fi 458 | 459 | #do not want toolchain's python make awk take precedence of existing one. 460 | # So remove them. They are provided at $NDK/prebuilt/*/bin which are already appended to $PATH 461 | if [[ ! -f $BIN/.python_make_awk_removed ]]; then 462 | for f in "$PREBUILT_BIN"/*; do 463 | [[ $f == *\** ]] && break 464 | f=$BIN/${f##*/} # "$PREBUILT_BIN"/file -> "$BIN"/file 465 | [[ -f $f ]] && { rm -f "$f" || mv -f "$f" "$f"_; } 466 | done 467 | touch "$BIN"/.python_make_awk_removed 468 | fi 469 | 470 | #fix possible bug of android-mips: g++ -mips32r2 option cause error "bits/c++config.h" not found. 471 | #so merge .../*/bits/*.h to standard place .../bits/ 472 | if [[ $ARCH == mips && $STL == gnustl && ! -f $BIN/../.bits_h_merged ]]; then 473 | ln -f "$BIN"/../include/c++/?.?.?/*/bits/*.h "$BIN"/../include/c++/?.?.?/bits/ \ 474 | && touch "$BIN"/../.bits_h_merged 475 | fi 476 | 477 | #add std::snprintf to so make it compatible with libc++ 478 | if [[ $STL == gnustl && ! -f $BIN/../.std_snprintf_added_to_cstdio ]]; then 479 | "$BIN_ARCH_PREFIX"g++$_EXE -E -x c++ - <<< "#include " | grep -q 'using ::snprintf' 480 | results=("${PIPESTATUS[@]}") 481 | if [[ ${results[0]} == 0 ]]; then 482 | if [[ ${results[1]} == 0 ]]; then 483 | touch "$BIN"/../.std_snprintf_added_to_cstdio 484 | else 485 | f=("$BIN"/../include/c++/?.?.?/cstdio) 486 | awk '/using ::printf;/{print $0 RS "#undef snprintf" RS "using ::snprintf;"; next}1' "$f" > "$f".tmp \ 487 | && mv -f "$f".tmp "$f" \ 488 | && touch "$BIN"/../.std_snprintf_added_to_cstdio 489 | fi 490 | fi 491 | fi 492 | 493 | #add std::snprintf to so make it compatible with libc++ 494 | if [[ $STL == gnustl && ! -f $BIN/../.cstdio_added_to_string ]]; then 495 | "$BIN_ARCH_PREFIX"g++$_EXE -E -x c++ - <<< "#include " | grep -q 'using ::snprintf' 496 | results=("${PIPESTATUS[@]}") 497 | if [[ ${results[0]} == 0 ]]; then 498 | if [[ ${results[1]} == 0 ]]; then 499 | touch "$BIN"/../.cstdio_added_to_string 500 | else 501 | f=("$BIN"/../include/c++/?.?.?/string) 502 | { cat "$f" && echo && echo '#include '; } > "$f".tmp \ 503 | && mv -f "$f".tmp "$f" \ 504 | && touch "$BIN"/../.cstdio_added_to_string 505 | fi 506 | fi 507 | fi 508 | 509 | ################################################################################ 510 | #otherwise, prepare env then run command 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | ################################################################################ 520 | #check verbose mode or interactive bash just for show guide and prompt 521 | INTER_BASH=""; [[ ! $CMD && -t 0 && -t 2 ]] && INTER_BASH=YES 522 | GUIDE=""; [[ $VERBOSE || $INTER_BASH ]] && GUIDE=YES 523 | _dbg "GUIDE: ${GUIDE:-NO} INTER_BASH: ${INTER_BASH:-NO}" 524 | 525 | ################################################################################ 526 | #remove previous bin path from $PATH 527 | if [[ $AGCC_BIN ]]; then 528 | 529 | [[ $GUIDE ]] && oldStr=$PATH 530 | 531 | d=$AGCC_BIN 532 | PATH=${PATH//:$d:/:} #replace :dir: with : 533 | PATH=${PATH#$d:} #remove dir: from head 534 | PATH=${PATH%:$d} #remove :dir from tail 535 | 536 | [[ $GUIDE && $oldStr != $PATH ]] && _guide "PATH -= ${AGCC_BIN/#$NDK/\$NDK}" 537 | fi 538 | unset AGCC_BIN 539 | 540 | ################################################################################ 541 | #remove previous hack dir from $PATH 542 | if [[ $AGCC_HOST_COMPILERS_DIR ]]; then 543 | 544 | for d in "$AGCC_HOST_COMPILERS_DIR"/*; do 545 | [[ $d == *\** ]] && break; #means dir not expanded 546 | 547 | [[ $GUIDE ]] && oldStr=$PATH 548 | 549 | PATH=${PATH//:$d:/:} #replace :dir: with : 550 | PATH=${PATH#$d:} #remove dir: from head 551 | PATH=${PATH%:$d} #remove :dir from tail 552 | 553 | [[ $GUIDE && $oldStr != $PATH ]] && _guide "PATH -= $d" 554 | done 555 | fi 556 | unset AGCC_HOST_COMPILERS_DIR 557 | 558 | ################################################################################ 559 | #clear some maybe-inherited var 560 | unset CC CXX LINK AR AS RANLIB LD STRIP NM 561 | unset CC_target CXX_target LINK_target AR_target AS_target RANLIB_target LD_target STRIP_target NM_target 562 | unset GYP_DEFINES PS1 563 | 564 | ################################################################################ 565 | #save bin dir for cleaner and as mnemonics 566 | export AGCC_BIN=$BIN 567 | export BIN 568 | 569 | if [[ $GUIDE ]]; then 570 | tmpStr="$TC_NAME toolchain is ready! The bin dir(\$BIN) is:" 571 | _guide "${tmpStr//?/-}" #replace each char with - 572 | _guide "$tmpStr" 573 | _guide " ${BIN/#$NDK/\$NDK}" 574 | _guide "" 575 | fi 576 | 577 | ################################################################################ 578 | 579 | #set verbose output for host -compilers/* and android $BIN/gcc... which print arguments 580 | [[ $VERBOSE ]] && export AGCC_VERBOSE=1 581 | 582 | #set gyp host_os to explicitly set it so correctly choose source files 583 | case $OSTYPE in 584 | darwin*) export GYP_DEFINES="host_os=mac" ;; 585 | linux*) export GYP_DEFINES="host_os=linux" ;; 586 | msys|cygwin) export GYP_DEFINES="host_os=$OSTYPE" ;; 587 | *) export GYP_DEFINES="host_os=$OSTYPE" 588 | _dbg "unsupported OSTYPE '$OSTYPE', so just set GYP_DEFINES=\"host_os=$OSTYPE\"" ;; 589 | esac 590 | 591 | #if $NDK contains spaces, then should be quoted in $CC... $CC_target... 592 | q=""; Q=""; [[ $NDK == *\ * ]] && q=\" && Q=\\\" 593 | 594 | case $ENV_MODE in 595 | ################################################################################ 596 | "") #$PATH mode(redirect mode) 597 | export PATH=$BIN:$PATH 598 | 599 | if [[ $GUIDE ]]; then 600 | _guide "PATH=\$BIN:\$PATH. Toolchain commands can be used directly:" 601 | _guide " gcc g++ cc c++ clang clang++ ar as ranlib ld strip nm ..." 602 | _guide " readelf objdump c++filt elfedit objcopy strings size ..." 603 | _guide "" 604 | 605 | #change prompt 606 | PS1="[$TC_NAME] "; 607 | fi 608 | ;; 609 | ################################################################################ 610 | -c) #$CC mode 611 | export CC=$q$BIN/gcc$q 612 | export CXX=$q$BIN/g++$q 613 | export LINK=$q$BIN/g++$q 614 | export AR=$q$BIN/ar$q 615 | export AS=$q$BIN/as$q 616 | export RANLIB=$q$BIN/ranlib$q 617 | export LD=$q$BIN/ld$q 618 | export STRIP=$q$BIN/strip$q 619 | export NM=$q$BIN/nm$q 620 | 621 | if [[ $GUIDE ]]; then 622 | _guide "Following env vars have been exported:" 623 | _guide " export CC=$Q\$BIN/gcc$Q" 624 | _guide " export CXX=$Q\$BIN/g++$Q" 625 | _guide " export LINK=$Q\$BIN/g++$Q" 626 | _guide " export AR=$Q\$BIN/ar$Q" 627 | _guide " export AS=$Q\$BIN/as$Q" 628 | _guide " export RANLIB=$Q\$BIN/ranlib$Q" 629 | _guide " export LD=$Q\$BIN/ld$Q" 630 | _guide " export STRIP=$Q\$BIN/strip$Q" 631 | _guide " export NM=$Q\$BIN/nm$Q" 632 | _guide "" 633 | 634 | #change prompt 635 | PS1="[$TC_NAME \\\$CC] "; 636 | fi 637 | ;; 638 | ################################################################################ 639 | -C) #$CC_target mode 640 | export CC_target=$q$BIN/gcc$q 641 | export CXX_target=$q$BIN/g++$q 642 | export LINK_target=$q$BIN/g++$q 643 | export AR_target=$q$BIN/ar$q 644 | export AS_target=$q$BIN/as$q 645 | export RANLIB_target=$q$BIN/ranlib$q 646 | export LD_target=$q$BIN/ld$q 647 | export STRIP_target=$q$BIN/strip$q 648 | export NM_target=$q$BIN/nm$q 649 | 650 | if [[ $GUIDE ]]; then 651 | _guide "Following env vars have been exported:" 652 | _guide " export CC_target=$Q\$BIN/gcc$Q" 653 | _guide " export CXX_target=$Q\$BIN/g++$Q" 654 | _guide " export LINK_target=$Q\$BIN/g++$Q" 655 | _guide " export AR_target=$Q\$BIN/ar$Q" 656 | _guide " export AS_target=$Q\$BIN/as$Q" 657 | _guide " export RANLIB_target=$Q\$BIN/ranlib$Q" 658 | _guide " export LD_target=$Q\$BIN/ld$Q" 659 | _guide " export STRIP_target=$Q\$BIN/strip$Q" 660 | _guide " export NM_target=$Q\$BIN/nm$Q" 661 | _guide "" 662 | 663 | #change prompt 664 | PS1="[$TC_NAME \\\$CC_target] " 665 | fi 666 | esac 667 | 668 | ################################################################################ 669 | #Supersede host compiler by prioritized wrappers in $PATH 670 | if [[ ${#HACK_LIST[@]} -gt 0 ]]; then 671 | #save hack dir for cleaner 672 | export AGCC_HOST_COMPILERS_DIR=$hackDir 673 | 674 | ((i=${#HACK_LIST[@]}-1)) 675 | while ((i>=0)); do 676 | ho=${HACK_LIST[$i]} 677 | export PATH=$hackDir/$ho:$PATH 678 | [[ $GUIDE ]] && _guide "PATH=$hackDir/$ho:\$PATH" 679 | ((i--)) 680 | done 681 | [[ $GUIDE ]] && _guide "" 682 | 683 | #change prompt, replace "]" with "+]" 684 | [[ $GUIDE ]] && PS1="${PS1/#]/+]}" 685 | fi #end of HACK_LIST 686 | 687 | ################################################################################ 688 | #finally, call CMD or bash. "exec" is to overwrite current process 689 | if [[ $INTER_BASH ]]; then 690 | #forcibly set my prompt ($PS1) via an on-fly init-file yet simulate interactive non-login bash 691 | exec /bin/bash --init-file <( 692 | echo '[[ -f /etc/bash.bashrc ]] && source /etc/bash.bashrc' 693 | echo '[[ -f ~/.bashrc ]] && source ~/.bashrc' 694 | echo "PS1='$PS1'" 695 | ) 696 | else 697 | if [[ $CMD ]]; then 698 | exec "$CMD" "$@" 699 | else 700 | exec /bin/bash 701 | fi 702 | fi 703 | --------------------------------------------------------------------------------