├── 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 | 
44 |
45 |
46 | - Enter a dedicated shell where can run android gcc related commands easily
47 |
48 | 
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 |
--------------------------------------------------------------------------------