这段时间一直在做代码移植代码的工作,即将c/c++
代码编译成Android平台的so库,于是写一篇文章记录下。
预备知识: GCC命令
如果有Android Studio
可以直接在下载即可,如果没有则需要NDK
,我用的是23
版本的。下载好不要安装,直接解压到制定目录即可。
在安装路径+ndk/23.1.7779620/toolchains/llvm/prebuilt/darwin-x86_64/bin
下,有四个命令组:
aarch64-linux-android
arm-linux-androideabi
i686-linux-android
x86_64-linux-android
由cpu架构-系统版本-Android版本-编译器
。如果你想编译32的就选arm-linux-androideabi
组的命令,如果编译64位,就选aarch64-linux-android
组的命令。命令列表如下:
如aarch64-linux-android21-clang++
,表示cpu
架构为64,Linux
系统,最低适配Android
版本21
,采用的是clang++
编译进行编译。
目前Android
支持ABI
有下面这些,和上面的命令是对应的。
ABI | 支持的指令集 | 备注 |
---|---|---|
armeabi-v7a |
| 与 ARMv5/v6 设备不兼容。 |
arm64-v8a | ● AArch64 | |
x86 |
| 不支持 MOVBE 或 SSE4。 |
x86_64 |
|
通过下面命令配置工具链环境:
打开terminal输入
export PATH$PATH=安装路径+/ndk/23.1.7779620/toolchains/llvm/prebuilt/darwin-x86_64/bin
输入aarch64-linux-android21-clang++ -v
Android (7714059, based on r416183c1) clang version 12.0.8 (https://android.googlesource.com/toolchain/llvm-project c935d99d7cf2016289302412d708641d52d2f7ee)
Target: aarch64-unknown-linux-android23
Thread model: posix
InstalledDir: /Users/*/Library/Android/sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/darwin-x86_64/bin
Found candidate GCC installation: /Users/*/Library/Android/sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/darwin-x86_64/bin/../lib/gcc/aarch64-linux-android/4.9.x
Selected GCC installation: /Users/*/Library/Android/sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/darwin-x86_64/bin/../lib/gcc/aarch64-linux-android/4.9.x
Candidate multilib: .;@m64
Selected multilib: .;@m64
如果得到上面的信息说明配置环境成功,接下来就是进入编译的过程。
如果你想查看so文件的信息可以用readelf命令,
命令存放在/Users/*/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/arm-linux-androideabi/bin
再次使用export PATH=$PATH:/Users/banma-2643/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/arm-linux-androideabi/bin
Asr.h
文件#include
class Asr
{
public:
int China;
int Usa;
int Japan;
Asr();
~Asr();
public:
void start();
std::string getTest();
int printCountry();
};
Asr.cpp
文件#include
#include "Asr.h"
Asr::Asr() : China(1), Japan(2), Usa(3)
{
}
Asr::~Asr()
{
}
void Asr::start()
{
std::cout << "this is static lib!";
}
std::string Asr::getTest()
{
return "test";
}
int Asr::printCountry()
{
return China + Japan + Usa;
}
Main.cpp
文件#include
#include "Asr.h"
using namespace std;
int main()
{
std::cout << "gcc Demo";
cout << endl;
Asr *a = new Asr();
a->start();
std::cout << a->getTest() << std::endl;
std::cout << a->printCountry();
}
执行clang++ Asr.cpp Main.cpp
命令得到a.out,然后执行./a.out
得到下面结果:
gcc Demo
this is static lib!test
6
如果不会使用命令,可以参考: GCC命令。
接下来我们将Asr.cpp
编译成so库,并在Android
中使用Asr.h
来访问它。
● 编译64 so库
执行 aarch64-linux-android21-clang++ -fPIC -shared C++/src/Asr.cpp -o libAsr.so
备注:so库的文件名一定要以lib开头,Android平台库默认是lib开头。
新建一个Android
工程,添加C++ module
,并新建jniLibs
,工程目录如下:
将libAsr.so
放在arm64-v8a
目录下,将Asr.h
放在main/cpp
目录下。现在配置CmakeLists.txt
和build.gradle
cmake_minimum_required(VERSION 3.18.1)
project("ndkdemo")
include_directories(../cpp/)
add_library( # Sets the name of the library.
ndkdemo
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
ndkdemo.cpp)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
ndkdemo
Asr
# Links the target library to the log library
# included in the NDK.
${log-lib})
include_directories(../cpp/)
用于设置头文件,set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")
设置so文件。
由于我只编译了arm64-v8a
,所以我必须设置 abiFilters "arm64-v8a"
,如果你编译了所有的arm版本,这样就不用设置了。
android {
……
defaultConfig {
……
externalNativeBuild {
cmake {
arguments '-DANDROID_STL=c++_static'
cppFlags ""
abiFilters "arm64-v8a"/*,"arm64-v8a"*/ /*todo 缺少对应的64位so ,需要解决64位兼容问题*/
}
}
ndk {
abiFilters "arm64-v8a"
}
}
}
在实际的过程中,发现缺失libc++_shared.so
,找到对应arm下libc++_shared.so
复制到对应的文件夹下就行了。还有一种缺失libc++_shared.so
,需要设置arguments '-DANDROID_STL=c++_shared'