Android基于ndk和cmake开发C++命令行程序
Creating a simple Hello World application Using Android NDK with C++ · GitHubandroid Ndk学习笔记01之Hello World! - 简书https://developer.android.com/ndk/samples/sample_hellojni
https://gist.github.com/gnuanu/252fd406f48f7da2c1c7
Android NDK编译C/C++为so共享对象_wkw1125的博客-CSDN博客_ndk编译so
https://developer.android.com/ndk/guides/build?hl=zh-cn
Building an Android command-line application using the NDK build tools
opencl
Android with OpenCL tutorial | aplacetogeek
使用 NDK 编译代码主要有三种方法:
ndk, sdk下载
sdk manager命令行工具下载:
https://developer.android.com/studio?hl=zh-cn#command-tools
https://developer.android.com/studio/command-line/sdkmanager
安装java
sudo apt install -y default-jre default-jdk
列出可以安装的包
./bin/sdkmanager --list --channel=0 --sdk_root=./sdk
例如:
build-tools;33.0.0
cmake;3.18.1
cmdline-tools;latest
emulator
ndk;20.1.5948944
platform-tools
platforms;android-30
sources;android-32
安装sdk ndk等一系列包
./bin/sdkmanager \
"platform-tools" \
"platforms;android-30" \
"sources;android-30" \
"cmake;3.18.1" \
"build-tools;33.0.0" \
"cmdline-tools;latest" \
"ndk;24.0.8215888" \
--channel=0 --sdk_root=./sdk
sdk:java开发; ndk:C++开发; 应用通常使用java通过jni方式调用C++。java函数生成C++头文件,然后使用C++进行实现。
基于ndk-build开发命令行程序
jni目录里面3个文件:
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello_world
LOCAL_SRC_FILES := hello_world.cpp
# LOCAL_C_INCLUDES += ../jni/
# include $(BUILD_SHARED_LIBRARY)
include $(BUILD_EXECUTABLE)
Application.mk
# APP_ABI := all
# APP_ABI := armeabi-v7a arm64-v8a x86
APP_ABI := arm64-v8a
APP_PLATFORM := android-21
# APP_STL := c++_shared
APP_STL := c++_static
hello_world.cpp
#include <iostream>
int main() {
std::cout << "hello world c++" << std::endl;
return 0;
}
然后在当前目录执行ndk-build,会在libs/arm64-v8a/生成可执行文件。
最后拷贝文件到手机端执行:
export DEV_DIR=/data/local/tmp/
adb push ./libs/arm64-v8a/hello_world ${DEV_DIR}
adb shell #进入shell命令行执行环境
cd ${DEV_DIR}
chmod 755 ./hello_world
./hello_world
基于CMake命令行开发
仍然是三个文件
build.sh
#!/bin/bash
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd ${SCRIPT_DIR}
# rm -rf build
mkdir build
cd build
# please set SDK_PATH, NDK_PATH first
# SDK_PATH=/root/codes/my_sdk/sdk/
# NDK_PATH=/root/codes/my_sdk/sdk/ndk/24.0.8215888/
ANDROID_ABI=arm64-v8a
MINSDKVERSION=29
# please ref https://developer.android.com/ndk/guides/cmake?hl=zh-cn#command-line
# /root/codes/my_sdk/sdk/cmake/3.18.1/bin/cmake \
# -DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake \
# -DANDROID_ABI=${ANDROID_ABI} \
# -DANDROID_PLATFORM=android-${MINSDKVERSION} \
# -DANDROID_STL=c++_static \
# ..
# make
${SDK_PATH}/cmake/3.18.1/bin/cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=${ANDROID_ABI} \
-DANDROID_NDK=${NDK_PATH} \
-DANDROID_PLATFORM=android-${MINSDKVERSION} \
-DCMAKE_ANDROID_ARCH_ABI=${ANDROID_ABI} \
-DCMAKE_ANDROID_NDK=${NDK_PATH} \
-DCMAKE_MAKE_PROGRAM=${SDK_PATH}/cmake/3.18.1/bin/ninja \
-DCMAKE_SYSTEM_NAME=Android \
-DCMAKE_SYSTEM_VERSION=${MINSDKVERSION} \
-DANDROID_STL=c++_static \
-GNinja \
..
if [ $? -ne 0 ]; then
echo "ERROR: cmake failed"
exit 1
fi
${SDK_PATH}/cmake/3.18.1/bin/ninja
if [ $? -ne 0 ]; then
echo "ERROR: build failed"
exit 1
fi
# DANDROID_ABI:
# armeabi-v7a
# armeabi-v7a with NEON
# arm64-v8a
# x86
# x86_64
# ANDROID_STL:
# c++_shared libc++ 的共享库变体。
# c++_static libc++ 的静态库变体。
# none 不支持 C++ 标准库。
# system 系统 STL
其他cmake方式
cmake .. \
-DCMAKE_TOOLCHAIN_FILE=$NDK_ROOT/build/cmake/android.toolchain.cmake \
-DANDROID_ABI="arm64-v8a" -DANDROID_NATIVE_API_LEVEL=android-21 \
-DANDROID_STL=c++_shared \
-DWITH_TESTING=OFF \
-DWITH_PYTHON=OFF \
-DANDROID_TOOLCHAIN=clang \
-DWITH_ICU_LITE=ON
make \
-j8
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(cmake_study LANGUAGES CXX)
# set(CMAKE_CXX_STANDARD 11)
# without these flags, the cmake generated binary file is much bigger than ndk-build
# you can also pass -DCMAKE_C_FLAGS="-s" to the CMake call.
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")
# 编译源码生成目标
add_executable(
main
jni/hello_world.cpp
)
# target_include_directories(
# main
# PUBLIC
# inc
# )
# target_link_libraries(
# main
# PUBLIC
# libxx.so
# )
这里面如果不加FLAGS则会导致CMake生成的二进制明显比ndk-build生成的更大,ref:
c++ - How to config cmake for strip file - Stack Overflow
Android CMake and ndk-build produce different sized files - Stack Overflow
hello_world.cpp
#include <iostream>
int main() {
std::cout << "hello world c++ with cmake" << std::endl;
return 0;
}
执行build.sh即可构建并生成二进制文件
PaddleNLP/how_to_build_android.md at develop · PaddlePaddle/PaddleNLP · GitHub
编译后的 C++ 库在当前目录下的 cpp
目录下。可以选择使用 strip 减少库体积:
$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/aarch64-linux-android/bin/strip libcore_tokenizers.so
错误处理
ndk/20.1.5948944/toolchains/llvm/prebuilt/linux-x86_64/bin/../lib/gcc/aarch64-linux-android/4.9.x/../../../../aarch64-linux-android/bin/ld: jni/../lib64/libOpenCL.so: don't know how to handle section `.relr.dyn' [0x 13]
解决方法:换一个高版本的ndk
sh脚本运行:
sh开头: #!/system/bin/sh
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)