• 跨平台编译ceres for Android


    折腾了几乎一天,记录一下。

    最大的坑是官网给出的

       1.进入ceres源代码目录下的jni目录

       2.EIGEN_PATH="指向eigen库目录,即包含EIGEN文件夹的那个文件夹” ndk-build

    这方法的确编译出了一个近700M的静态库,但使用时总是未定义链接错误。现在想想跟以前编译OpenCV时遇到的错误相似,

    解决的办法也相似,通过cmake调用ndk的工具链编译。

    我编译动态库的命令

    /home/hk/Android/Sdk/cmake/3.10.2.4988404/bin/cmake -DCMAKE_TOOLCHAIN_FILE=/home/hk/Android/Sdk/ndk/20.0.5594570/build/cmake/android.toolchain.cmake -DEIGEN_INCLUDE_DIR=/home/hk/ndk/eigen-git-mirror-3.3.6 -DANDROID_ABI=arm64-v8a -DANDROID_STL=c++_shared -DANDROID_NATIVE_API_LEVEL=android-27 -DBUILD_SHARED_LIBS=ON -DBUILD_TESTING=OFF -DBUILD_EXAMPLES=OFF -DMINIGLOG=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-s" /home/hk/ndk/ceres-solver-master

    注意一定要在一行,否则可能配置错误,生成Lunix格式的库。可先在文本文档里写好,然后复制到终端。这里用到的cmake是android studio安装的

    ,本来装的是3.5版本,这里要求高版本。

    详细的解释下

    #这部分是指定工具链,工具链在ndk里

    -DCMAKE_TOOLCHAIN_FILE=/home/hk/Android/Sdk/ndk/20.0.5594570/build/cmake/android.toolchain.cmake

    #这部分指定Eigen库路径,要求3.3.4以上

    -DEIGEN_INCLUDE_DIR=/home/hk/ndk/eigen-git-mirror-3.3.6

    #这部分指定abi,我是arm64-v8a

    -DANDROID_ABI=arm64-v8a

    #这部分指定STL,这里可能要跟项目用的一致,就是要跟项目编译c++文件的那个STL一致,若选择c++_static应该也可以,一致就行,项目选择STL在

    #gradle里设置,这在下面介绍

    -DANDROID_STL=c++_shared

    #指定android版本27对应android 8.1.0

    -DANDROID_NATIVE_API_LEVEL=android-27

    #ON就是动态库,OFF就是静态库

    -DBUILD_SHARED_LIBS=ON

    #不编译测试,没意义,不可能在LINUX上运行的,库是android的格式

    -DBUILD_TESTING=OFF

    #不编译列子

    -DBUILD_EXAMPLES=OFF

    #不依赖glog源码了,这里是重点,这里选择ON会使用ceres目录下/ceres-solver-master/internal/ceres/miniglog里的代码代替glog

    #当库放入android项目时需要将这个目录里的头文件也加入项目,比如可直接将这个目录加入项目的头文件路径

    -DMINIGLOG=ON

    #非调试版本

    -DCMAKE_BUILD_TYPE=Release

    #不懂

    -DCMAKE_C_FLAGS="-s"

    #指定ceres目录,即CMakeLists.txt所在的目录路径

    /home/hk/ndk/ceres-solver-master

    配置成功的特点是

    .........

    -- Check for working C compiler: /home/hk/Android/Sdk/ndk/20.0.5594570/toolchains/llvm/prebuilt/linux-x86_64/bin/clang
    -- Check for working C compiler: /home/hk/Android/Sdk/ndk/20.0.5594570/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Detecting C compile features
    -- Detecting C compile features - done
    -- Check for working CXX compiler: /home/hk/Android/Sdk/ndk/20.0.5594570/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++
    -- Check for working CXX compiler: /home/hk/Android/Sdk/ndk/20.0.5594570/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ -- works

    .........
    即cmake选择的默认编译器是clang和clang++

    配置好后sudo make

    生成好后将.so库放入app下的libs里,我是新建arm64-v8a文件夹,然后放在里面的。

    libs里新建include,头文件都放在这里。重点是,差个 config.h,cmake生成库的那个目录里搜索下,有个新生成的config.h,将其放到指定地方即可。指定的地方错误提示会指出。

    注意,这个libs文件夹没有跟jniLibs相关联,里面的.so不会放入.apk,关联在gradle里设置,下面会给出完整的配置。

    看看libs文件夹的内容

    gradle配置

    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 29
        buildToolsVersion "29.0.2"
        defaultConfig {
            applicationId "com.example.myapplication"
            minSdkVersion 27
            targetSdkVersion 29
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
            //项目的ndk配置需和使用的库一致,项目的配置在这里设置
            externalNativeBuild {
                cmake {
                    cppFlags "-std=c++11"
                    //arguments '-DANDROID_STL=c++_static'
                    arguments '-DANDROID_STL=c++_shared'
                    abiFilters "arm64-v8a"
                }
            }
            //指定jniLibs目录只有这个目录里的.so动态库会被加载到.apk
            sourceSets {
                main {
                    jniLibs.srcDirs = ['libs']
                }
            }
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
        externalNativeBuild {
            cmake {
                path "src/main/cpp/CMakeLists.txt"
                version "3.10.2"
            }
        }
    }
    
    
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'androidx.appcompat:appcompat:1.0.2'
        implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'androidx.test:runner:1.1.1'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
    }

    cmake配置

    # Sets the minimum version of CMake required to build the native library.
    cmake_minimum_required(VERSION 3.4.1)
    
    #要求支持c++11
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
    #设置第三方库目录路径参数
    set(libs_path ${CMAKE_SOURCE_DIR}/../../../libs)
    
    #引入glog头文件
    include_directories( ${libs_path}/include )
    
    ##########添加Ceres静态库 begin#########
    add_library(
            ceres       #库名字 去掉了 lib 与 .a
            SHARED      #必须的
            IMPORTED    #必须的
    )
    #指定Ceres静态库位置
    set_target_properties(
            ceres
            PROPERTIES IMPORTED_LOCATION
            ${libs_path}/arm64-v8a/libceres.so
    )
    #引入Ceres的头文件
    include_directories( ${libs_path}/include )
    ##########添加Ceres静态库 end#########
    
    ##########添加Eigen库 begin#########
    #引入Eigen的头文件
    include_directories( ${libs_path}/include )
    ##########添加Eigen库 begin#########
    
    ##########添加添加native-lib动态库 begin#########
    add_library(
            native-lib
            SHARED
            native-lib.cpp
    )
    #查找要链接的android log库
    find_library(
            log-lib
            log )
    #链接库
    target_link_libraries(
            native-lib
            ${log-lib}
            ceres
            #openmap库
            #若编译Ceres时使用了 -DCERES_USE_OPENMP
            #则在使用Ceres时必须链接上OpenMap库
            #omp
    )
    ##########添加添加native-lib动态库 end#########

    测试代码就是ceres的hello ceres示列,将其放入jni函数里

    #include <jni.h>
    #include <string>
    
    #include "ceres/ceres.h"
    #include "glog/logging.h"
    
    using ceres::AutoDiffCostFunction;
    using ceres::CostFunction;
    using ceres::Problem;
    using ceres::Solver;
    using ceres::Solve;
    
    // A templated cost functor that implements the residual r = 10 -
    // x. The method operator() is templated so that we can then use an
    // automatic differentiation wrapper around it to generate its
    // derivatives.
    struct CostFunctor {
        template <typename T> bool operator()(const T* const x, T* residual) const {
            residual[0] = 10.0 - x[0];
            return true;
        }
    };
    
    extern "C" JNIEXPORT jstring JNICALL
    Java_com_example_myapplication_MainActivity_stringFromJNI(
            JNIEnv* env,
            jobject /* this */) {
        std::string hello = "Hello Ceres";
    
        // The variable to solve for with its initial value. It will be
        // mutated in place by the solver.
        double x = 0.5;
        const double initial_x = x;
    
        // Build the problem.
        Problem problem;
    
        // Set up the only cost function (also known as residual). This uses
        // auto-differentiation to obtain the derivative (jacobian).
        CostFunction* cost_function =
                new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
        problem.AddResidualBlock(cost_function, NULL, &x);
    
        // Run the solver!
        Solver::Options options;
        options.minimizer_progress_to_stdout = true;
        Solver::Summary summary;
        Solve(options, &problem, &summary);
    
        std::cout << summary.BriefReport() << "
    ";
        std::cout << "x : " << initial_x
                  << " -> " << x << "
    ";
    
        return env->NewStringUTF(summary.BriefReport().c_str());
    }
  • 相关阅读:
    论工作动力的来源是什么?答案是来自于实现自己的梦想
    向梦想者致敬
    内置函数,递归函数,模块与包,开发目录规范
    迭代器,生成器
    闭包函数,装饰器,语法糖
    函数对象,名称空间及查找,作用域
    函数调用与参数
    字符编码
    文件处理
    python 11.5数据类型及常用方法
  • 原文地址:https://www.cnblogs.com/qq2523984508/p/11470716.html
Copyright © 2020-2023  润新知