Skip to content

Commit 799bbc6

Browse files
committed
script: build llama.cpp on Linux for Android
1 parent 901e20b commit 799bbc6

File tree

2 files changed

+277
-0
lines changed

2 files changed

+277
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,5 @@ poetry.toml
146146
# Local scripts
147147
/run-vim.sh
148148
/run-chat.sh
149+
150+
/prebuilts

scripts/build-run-android.sh

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
#!/usr/bin/env bash
2+
#
3+
# build llama.cpp on Linux for Android phone
4+
#
5+
set -e
6+
7+
######## part-1 ########
8+
9+
PWD=`pwd`
10+
PROJECT_HOME_PATH=`pwd`
11+
PROJECT_ROOT_PATH=${PROJECT_HOME_PATH}
12+
HOST_CPU_COUNTS=`cat /proc/cpuinfo | grep "processor" | wc | awk '{print int($1)}'`
13+
14+
#running path on Android phone
15+
REMOTE_PATH=/data/local/tmp
16+
17+
#Android NDK can be found at:
18+
#https://developer.android.com/ndk/downloads
19+
ANDROID_PLATFORM=android-34
20+
ANDROID_NDK_VERSION=r28
21+
ANDROID_NDK_NAME=android-ndk-${ANDROID_NDK_VERSION}
22+
ANDROID_NDK_FULLNAME=${ANDROID_NDK_NAME}-linux.zip
23+
ANDROID_NDK=${PROJECT_ROOT_PATH}/prebuilts/${ANDROID_NDK_NAME}
24+
25+
######## part-2 ########
26+
OPT_FLAGS="-march=armv8.2-a+dotprod+fp16"
27+
28+
RUNNING_PARAMS=" -ngl 99 -t 8 -n 256 --no-warmup "
29+
30+
PROMPT_STRING="introduce the movie Once Upon a Time in America briefly.\n"
31+
32+
#for llama-cli & llama-bench, 1.12 GiB, will be downloaded automatically via this script
33+
TEST_MODEL_NAME=/sdcard/qwen1_5-1_8b-chat-q4_0.gguf
34+
35+
######## part-3: utilities and functions ########
36+
37+
function dump_vars()
38+
{
39+
echo -e "ANDROID_NDK: ${ANDROID_NDK}"
40+
}
41+
42+
function show_pwd()
43+
{
44+
echo -e "current working path:$(pwd)\n"
45+
}
46+
47+
function check_command_in_host()
48+
{
49+
set +e
50+
cmd=$1
51+
ls /usr/bin/${cmd}
52+
if [ $? -eq 0 ]; then
53+
#printf "${cmd} already exist on host machine\n"
54+
echo ""
55+
else
56+
printf "${cmd} not exist on host machine, pls install command line utility ${cmd} firstly and accordingly\n"
57+
exit 1
58+
fi
59+
set -e
60+
}
61+
62+
function check_commands_in_host()
63+
{
64+
check_command_in_host wget
65+
}
66+
67+
function check_and_download_ndk()
68+
{
69+
mkdir -p ${PROJECT_ROOT_PATH}/prebuilts
70+
71+
is_android_ndk_exist=1
72+
73+
if [ ! -d ${ANDROID_NDK} ]; then
74+
is_android_ndk_exist=0
75+
fi
76+
77+
if [ ! -f ${ANDROID_NDK}/build/cmake/android.toolchain.cmake ]; then
78+
is_android_ndk_exist=0
79+
fi
80+
81+
if [ ${is_android_ndk_exist} -eq 0 ]; then
82+
83+
if [ ! -f ${PROJECT_ROOT_PATH}/prebuilts/${ANDROID_NDK_FULLNAME} ]; then
84+
wget --no-config --quiet --show-progress -O ${PROJECT_ROOT_PATH}/prebuilts/${ANDROID_NDK_FULLNAME} https://dl.google.com/android/repository/${ANDROID_NDK_FULLNAME}
85+
fi
86+
87+
cd ${PROJECT_ROOT_PATH}/prebuilts/
88+
unzip ${ANDROID_NDK_FULLNAME}
89+
90+
if [ $? -ne 0 ]; then
91+
printf "failed to download Android NDK to %s \n" "${ANDROID_NDK}"
92+
exit 1
93+
fi
94+
cd ${PROJECT_ROOT_PATH}
95+
96+
printf "Android NDK saved to ${ANDROID_NDK} \n\n"
97+
else
98+
printf "Android NDK already exist: ${ANDROID_NDK} \n\n"
99+
fi
100+
}
101+
102+
function build_arm64
103+
{
104+
cmake -H. -B./out/android -DCMAKE_BUILD_TYPE=Release -DGGML_OPENMP=OFF -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=latest -DLLAMA_CURL=OFF -DCMAKE_C_FLAGS=${OPT_FLAGS} -DCMAKE_CXX_FLAGS=${OPT_FLAGS}
105+
cd out/android
106+
make -j${HOST_CPU_COUNTS}
107+
show_pwd
108+
109+
cd -
110+
}
111+
112+
function build_arm64_debug
113+
{
114+
cmake -H. -B./out/android -DCMAKE_BUILD_TYPE=Debug -DGGML_OPENMP=OFF -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=latest -DLLAMA_CURL=OFF -DCMAKE_C_FLAGS=${OPT_FLAGS} -DCMAKE_CXX_FLAGS=${OPT_FLAGS}
115+
cd out/android
116+
make -j${HOST_CPU_COUNTS}
117+
show_pwd
118+
119+
cd -
120+
}
121+
122+
function remove_temp_dir()
123+
{
124+
if [ -d out/android ]; then
125+
echo "remove out/android directory in `pwd`"
126+
rm -rf out/android
127+
fi
128+
}
129+
130+
function build_llamacpp()
131+
{
132+
show_pwd
133+
check_and_download_ndk
134+
dump_vars
135+
remove_temp_dir
136+
build_arm64
137+
}
138+
139+
function build_llamacpp_debug()
140+
{
141+
show_pwd
142+
check_and_download_ndk
143+
dump_vars
144+
remove_temp_dir
145+
build_arm64_debug
146+
}
147+
148+
function check_and_download_model()
149+
{
150+
set +e
151+
152+
model_name=$1
153+
model_url=$2
154+
155+
adb shell ls /sdcard/${model_name}
156+
if [ $? -eq 0 ]; then
157+
printf "the prebuild LLM model ${model_name} already exist on Android phone\n"
158+
else
159+
printf "the prebuild LLM model ${model_name} not exist on Android phone\n"
160+
wget --no-config --quiet --show-progress -O ${PROJECT_ROOT_PATH}/models/${model_name} ${model_url}
161+
adb push ${PROJECT_ROOT_PATH}/models/${model_name} /sdcard/
162+
fi
163+
164+
set -e
165+
}
166+
167+
function check_prebuilt_models()
168+
{
169+
#https://huggingface.co/ggml-org/gemma-3-4b-it-GGUF/blob/main/gemma-3-4b-it-Q8_0.gguf, size 4.13 GiB
170+
#https://huggingface.co/Qwen/Qwen1.5-1.8B-Chat-GGUF/blob/main/qwen1_5-1_8b-chat-q4_0.gguf, size 1.12 GiB
171+
172+
set +e
173+
174+
check_and_download_model qwen1_5-1_8b-chat-q4_0.gguf https://huggingface.co/Qwen/Qwen1.5-1.8B-Chat-GGUF/resolve/main/qwen1_5-1_8b-chat-q4_0.gguf
175+
set -e
176+
}
177+
178+
function prepare_run_on_phone()
179+
{
180+
if [ $# != 1 ]; then
181+
print "invalid param"
182+
return
183+
fi
184+
program=$1
185+
186+
check_prebuilt_models
187+
188+
all_libs=`find ./out/android/bin -name "*.so" -print`
189+
#echo ${all_libs}
190+
for lib in ${all_libs};do
191+
adb push ${lib} ${REMOTE_PATH}/
192+
done
193+
194+
adb push ./out/android/bin/${program} ${REMOTE_PATH}/
195+
196+
adb shell chmod +x ${REMOTE_PATH}/${program}
197+
}
198+
199+
function run_llamacli()
200+
{
201+
prepare_run_on_phone llama-cli
202+
203+
echo "${REMOTE_PATH}/llama-cli ${RUNNING_PARAMS} -m ${TEST_MODEL_NAME} -p \"${PROMPT_STRING}\""
204+
adb shell "cd ${REMOTE_PATH} \
205+
&& export LD_LIBRARY_PATH=${REMOTE_PATH} \
206+
&& ${REMOTE_PATH}/llama-cli ${RUNNING_PARAMS} -no-cnv -m ${TEST_MODEL_NAME} -p \"${PROMPT_STRING}\""
207+
208+
}
209+
210+
function run_llamabench()
211+
{
212+
prepare_run_on_phone llama-bench
213+
214+
echo "adb shell \"cd ${REMOTE_PATH} \
215+
&& export LD_LIBRARY_PATH=${REMOTE_PATH} \
216+
&& ${REMOTE_PATH}/llama-bench ${RUNNING_PARAMS} -m ${TEST_MODEL_NAME}\""
217+
echo "${REMOTE_PATH}/llama-bench ${RUNNING_PARAMS} -m ${TEST_MODEL_NAME}"
218+
219+
adb shell "cd ${REMOTE_PATH} \
220+
&& export LD_LIBRARY_PATH=${REMOTE_PATH} \
221+
&& ${REMOTE_PATH}/llama-bench ${RUNNING_PARAMS} -m ${TEST_MODEL_NAME}"
222+
223+
}
224+
225+
function show_usage()
226+
{
227+
echo -e "\n\n\n"
228+
echo "Usage:"
229+
echo " $0 help"
230+
echo " $0 build"
231+
echo " $0 build_debug"
232+
echo " $0 run_llamacli"
233+
echo " $0 run_llamabench"
234+
235+
echo -e "\n\n\n"
236+
}
237+
238+
######## part-4: entry point ########
239+
240+
show_pwd
241+
242+
check_commands_in_host
243+
check_and_download_ndk
244+
check_prebuilt_models
245+
246+
if [ $# == 0 ]; then
247+
show_usage
248+
exit 1
249+
elif [ $# == 1 ]; then
250+
if [ "$1" == "-h" ]; then
251+
show_usage
252+
exit 1
253+
elif [ "$1" == "help" ]; then
254+
show_usage
255+
exit 1
256+
elif [ "$1" == "build" ]; then
257+
build_llamacpp
258+
exit 0
259+
elif [ "$1" == "build_debug" ]; then
260+
build_llamacpp_debug
261+
exit 0
262+
elif [ "$1" == "run_llamacli" ]; then
263+
run_llamacli
264+
exit 0
265+
elif [ "$1" == "run_llamabench" ]; then
266+
run_llamabench
267+
exit 0
268+
else
269+
show_usage
270+
exit 1
271+
fi
272+
else
273+
show_usage
274+
exit 1
275+
fi

0 commit comments

Comments
 (0)