• 如何将c/c++代码通过NDK交叉工具链移植到Android平台上?


    这段时间一直在做代码移植代码的工作,即将c/c++代码编译成Android平台的so库,于是写一篇文章记录下。

    预备知识: GCC命令

    一、下载NDK

    如果有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
    • armeabi
    • Thumb-2
    • VFPv3-D16
    与 ARMv5/v6 设备不兼容。
    arm64-v8a● AArch64
    x86
    • x86 (IA-32)
    • MMX
    • SSE/2/3
    • SSSE3
    不支持 MOVBE 或 SSE4。
    x86_64
    • x86-64
    • MMX
    • SSE/2/3
    • SSSE3
    • SSE4.1、4.2
    • POPCNT6

    通过下面命令配置工具链环境:

    • 打开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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    如果得到上面的信息说明配置环境成功,接下来就是进入编译的过程。

    如果你想查看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

    三、编译C++代码

    • Asr.h文件
    #include 
    class Asr
    {
    public:
        int China;
        int Usa;
        int Japan;
        Asr();
        ~Asr();
    
    public:
        void start();
        std::string getTest();
        int printCountry();
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    执行clang++ Asr.cpp Main.cpp 命令得到a.out,然后执行./a.out得到下面结果:

    gcc Demo
    this is static lib!test
    6
    
    • 1
    • 2
    • 3

    如果不会使用命令,可以参考: 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中集成

    新建项目

    新建一个Android 工程,添加C++ module,并新建jniLibs,工程目录如下:
    在这里插入图片描述
    libAsr.so放在arm64-v8a目录下,将Asr.h放在main/cpp目录下。现在配置CmakeLists.txtbuild.gradle

    配置CmakeLists.txt

    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})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    include_directories(../cpp/)用于设置头文件,set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")设置so文件。

    配置 build.gradle

    由于我只编译了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"
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在实际的过程中,发现缺失libc++_shared.so,找到对应arm下libc++_shared.so复制到对应的文件夹下就行了。还有一种缺失libc++_shared.so,需要设置arguments '-DANDROID_STL=c++_shared'

    参考:

  • 相关阅读:
    Java拷贝之深拷贝与浅拷贝
    SpringBoot日志文件
    设计模式定义
    注意!全国九大系列职称都已设专利要求!
    微信小程序(基础语法)
    ASP.NET Core框架探索之Authentication
    【Linux】—— Linux 环境搭建
    KMP算法详解以及Java代码实现
    前端报错的时候提示必须为表达式
    RabbitMQ介绍及下载安装详解
  • 原文地址:https://blog.csdn.net/c_he_n/article/details/125870085