PCL-1.9.1 for Android ndk21编译

PCL-1.9.1 for Android ndk21编译

说明

之所以记录下自己编译android版的pcl过程,主要原因是:

  1. 按照https://github.com/bashbug/pcl-for-android说明,无法完成编译,报错原因多方面,主要原因是conan的公共仓库https://conan.bintray.com已经失效,部分依赖的下载地址失效
  2. 我需要基于R21版NDK编译出来的PCL库,从而兼容其他使用了R21版的NDK模块;之前在windows下使用了别人编译好的1.8.0版本的pcl库,该版本的pcl库支持NDK16,不支持NDK21。
  3. 我的开发环境在windows下,因此,需要整理出可以在windows下使用PCL库的配置

故此,通过交叉编译,编译出基于r21版本NDK的1.9.1版本的pcl库,并在windows下使用Android studio成功编译使用pcl库的功能。

环境

操作系统:Ubantu18.04.6 LTS

Python:3.6.9

cmake:3.10.2

conan:1.44.1

GCC:8.4.0

git:2.17.1

创建虚拟环境

如果不想破坏当前的编译环境,可以使用venv创建一个虚拟环境:

mkdir pcl-1.9.1
cd pcl-1.9.1
python -m venv venv
source venv/bin/acticate

当然,也可以不创建虚拟环境,直接在当前环境下进行。虚拟环境的好处就是不会破坏当前的各项配置。

安装所需环境

sudo apt install cmake git make ninja python3-pip
sudo pip3 install conan

由于conan默认的仓库https://conan.bintray.com实效,因此,要确保conan使用的版本较新,并导入新的根证书,才可以正常使用conan仓库。

安装最新的根证书

conan config install https://github.com/conan-io/conanclientcert.git

设置conan仓库

conan remote add conan-center https://center.conan.io
conan remote list #查看设置是否成功
conan-center: https://center.conan.io [Verify SSL: True]#查询到的仓库地址

拉取项目

git clone https://github.com/bashbug/pcl-for-android.git

修改NDK版本

  1. 修改profile中的ndk版本

​ 修改conan-profile下面的文件,把[build-requires]下面的android-toolchain/r20@bashbug/stable修改为android-toolchain/r21@bashbug/stable即可。

  1. 修改android-toolchain中的ndk版本

​ 打开conanfiles/android-toolchain/conanfile.py,修改version = "r20"为version = “r21”

修改boost源码下载地址

打开conanfiles/boost/conanfile.py,修改source(self)方法的内容如下:

tools.get("https://boostorg.jfrog.io/artifactory/main/release/{}/source/{}.tar.gz".format(self.version, self.folder_name))

原本的下载地址已经失效,无法下载。原下载地址为

tools.get("https://dl.bintray.com/boostorg/release/{}/source/{}.tar.gz".format(self.version, self.folder_name))

修改lz4的版本

原本的lz4版本是1.9.1,在conan仓库中已经不支持该版本了,因此需要修改为1.9.2版本。需要修改2个文件,一个是lz4的conan文件,一个是flann的文件,因为flann中依赖lz4。

打开conanfiles/flann/conanfile.py,修改requirements部分的lz4版本号,修改后的结果如下:

self.requires("lz4/1.9.2@bashbug/stable")

打开conanfiles/lz4/conanfile.py,修改其中的version值为1.9.2,修改后的结果如下:

version = "1.9.2"

修改PCL配置文件

clone出来的pcl配置文件中,所依赖的eigen版本为"eigen/3.3.7@conan/stable",而该版本在conan仓库中不存在;通过查询conan仓库:

conan search eigen* -r=conan-center
Existing package recipes:

eigen/3.3.7
eigen/3.3.8
eigen/3.3.9
eigen/3.4.0

可以看到,仓库中的eigen版本后面没有conan/stable用户通道属性,因此,去掉用户通道参数即可,修改后的结果如下:

self.requires("eigen/3.3.7")

根据需要,修改PCL功能模块开关,默认以下模块被关闭,也就是不会被编译到pcl库中:

cmake.definitions["PCL_SHARED_LIBS"] = "OFF"
cmake.definitions["PCL_BINARIES"] = "OFF"
cmake.definitions["WITH_CUDA"] = "OFF"
cmake.definitions["WITH_OPENGL"] = "OFF"
cmake.definitions["WITH_PCAP"] = "OFF"
cmake.definitions["WITH_PNG"] = "OFF"
cmake.definitions["WITH_QHULL"] = "OFF"
cmake.definitions["WITH_VTK"] = "OFF"

PCL_SHARED_LIBS是控制编译共享库,我们要交叉编译,因此不打开该项;

PCL_BINARIES控制是否编译可执行文件,也就是可以命令行运行的pcl命令。pcl_binaries.patch补丁实现了该配置打开情况下编译的支持。

WITH_VTK模块不适用于Android平台,Android平台使用VES,在PCL的源码CMakeLists.txt中有这样的表述:

if(ANDROID)
  set(build FALSE)
  message("VTK was found, but cannot be compiled for Android. Please use VES instead.")
endif()

其他模块打开,需要增加对应的配置参数,而且模块间有依赖关系,如VTK依赖OPENG;具体如何配置,还不熟悉,有空再研究。

编译

armeabi-v7a
./pcl-build-for-android.sh armeabi-v7a
arm64-v8a
./pcl-build-for-android.sh arm64-v8a

如果编译有错,仔细看错误信息,对应修改即可。

导出PCL库和头文件

编译出来的pcl库和头文件以及相关依赖,按照模块分别存放,主要输出在./conan/data下面,类似以下结构:

├── android-toolchain
├── boost
├── eigen
├── flann
├── lz4
├── pcl

android-toolchain是自动下载的r21版本的NDK,适用于Linux平台,没有包含windows平台的有关文件,因此不能直接拉到windows下使用。

lz4是flann依赖的模块,编译后,已经包含在flann中,因此不需要单独拉取;

boost、eigen、flann、pcl这4个模块是需要拉取出来的,形成一个pcl库和头文件的集合,供其他Android项目使用。要注意:我们所需要拉取的不是./conan/data下的内容全部,而是每个模块对应版本下面的bashbug/stable/××××下面的lib和include2个文件夹,具体各个模块要拉取的目录如下:

.conan/data/boost/1.70.0/bashbug/stable/package/4e65a98fd5c197b6539ce5c3062c84123c059f0c/lib
.conan/data/boost/1.70.0/bashbug/stable/package/4e65a98fd5c197b6539ce5c3062c84123c059f0c/include
.conan/data/eigen/3.3.7/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/eigen3/
.conan/data/flann/1.9.1/bashbug/stable/package/42aed23ccd4c3006a79a880ba523d6d45486ac63/lib
.conan/data/flann/1.9.1/bashbug/stable/package/42aed23ccd4c3006a79a880ba523d6d45486ac63/include
.conan/data/pcl/1.9.1/bashbug/stable/package/edf8fc3f2f92012e3ef85012b21cfa3182a52d47/lib
.conan/data/pcl/1.9.1/bashbug/stable/package/edf8fc3f2f92012e3ef85012b21cfa3182a52d47/include

package后面的文件夹名称时编译时自动生成的,因此,每次编译都不相同。

在windows下创建pcl文件夹,比如:pcl-android-191-build/build,在build下面分别创建boost-android、flann-android、pcl-android,把上述对应的内容拉取到对应模块的文件夹下面;eigen3拉取下来后,修改eigen3为eigen即可;可能需要qhull模块,我是直接复制了原来1.8.0版qhull,目前暂时没有使用到,所以在配置pcl功能模块时没有开打qhull,因此,编译结果也就没有qhull的库和头文件。如果编译android应用需要qhull头文件和库,可以试试直接使用1.8.0版qhull。后面有时间再研究如何编译出qhull。

我拉取后的结构如下:

├── pcl-android-191-build
│   └── build
│       └── boost-android
│       	└── include
│       	└── lib
│       └── eigen
│       	└── Eigen
│       	└── unsupported
│       └── flann-android
│       	└── include
│       	└── lib
│       └── pcl-android
│       	└── include
│       	└── lib
│       └── qhull-android
│       	└── include
│       	└── lib

build.gradle中,做对应的配置:

externalNativeBuild {
    cmake {
        cppFlags "-std=c++11 -frtti -fexceptions -fopenmp -DANDROID_STL=gnustl_static"
    }
}

ndk {
	abiFilters "armeabi-v7a"
}

编写cpp文件,使用pcl功能。pcl-180库cpp对应的CMakeLists.txt类似如下:

cmake_minimum_required(VERSION 3.4.1)

set(PCL_BUILD "F:/pcl-android-180-build/build")

set(PCL_INCLUDE "${PCL_BUILD}/pcl-android")
set(BOOST_INCLUDE "${PCL_BUILD}/boost-android")
set(FLANN_INCLUDE "${PCL_BUILD}/flann-android")
set(EIGEN_INCLUDE "${PCL_BUILD}/eigen")
set(QHULL_INCLUDE "${PCL_BUILD}/qhull-android")

set(PCL_STATIC_LIB_DIR "${PCL_INCLUDE}/lib")
set(BOOST_STATIC_LIB_DIR "${BOOST_INCLUDE}/lib")
set(FLANN_STATIC_LIB_DIR "${FLANN_INCLUDE}/lib")
set(QHULL_STATIC_LIB_DIR "${QHULL_INCLUDE}/lib")

include_directories(${PCL_INCLUDE}/include)
include_directories(${BOOST_INCLUDE}/include)
include_directories(${FLANN_INCLUDE}/include)
include_directories(${QHULL_INCLUDE}/include)
include_directories(${EIGEN_INCLUDE})

function(importLib dirName libName)
    add_library(${libName} STATIC IMPORTED)
    set_target_properties(${libName}
            PROPERTIES
            IMPORTED_LOCATION
            "${dirName}/${libName}.a")
endfunction(importLib)

set(libFlannNames
        libflann_cpp_s
        libflann_s
        )

set(libBoostNames
        libboost_thread
        libboost_signals
        libboost_program_options
        libboost_filesystem
        libboost_system
        libboost_regex
        libboost_iostreams
        libboost_date_time
        )

set(libQhullNames
        libqhullstatic
        )

set(libPclNames
        libpcl_stereo
        libpcl_2d
        libpcl_segmentation
        libpcl_recognition
        libpcl_ml
        libpcl_io
        libpcl_io_ply
        libpcl_filters
        libpcl_tracking
        libpcl_search
        libpcl_registration
        libpcl_keypoints
        libpcl_features
        libpcl_surface
        libpcl_sample_consensus
        libpcl_octree
        libpcl_kdtree
        libpcl_common
        )

foreach(lib ${libPclNames})
    importLib(${PCL_STATIC_LIB_DIR} ${lib})
endforeach(lib)

foreach(lib ${libFlannNames})
    importLib(${FLANN_STATIC_LIB_DIR} ${lib})
endforeach(lib)

foreach(lib ${libBoostNames})
    importLib(${BOOST_STATIC_LIB_DIR} ${lib})
endforeach(lib)

foreach(lib ${libQhullNames})
    importLib(${QHULL_STATIC_LIB_DIR} ${lib})
endforeach(lib)

add_library(native-jni SHARED
        native-jni.cpp
        )


target_link_libraries(
        native-jni
        ${libPclNames}
        ${libFlannNames}
        ${libBoostNames}
        ${libQhullNames}
        android
        log)

native-jni.cpp为使用PCL功能库JNI本地化文件,可以根据自己的实际情况修改为自己的实现文件名。

191版本默认编译出来的pcl库中是没有libpcl_2d库的,可以复制180版本的库文件,也可以修改上面的txt文件,去掉libpcl_2d即可;同样,该本本没有编译出libboost_signals库,去掉即可,也可以复制180版本的同名库文件即可;flann模块也也没有编译出libflann_s.a文件,同样可以去掉,也可以复制180版本的文件过来。

去掉上面3个库文件后,191版的PCL库对应CMakeLists.txt类似如下:

cmake_minimum_required(VERSION 3.4.1)

set(PCL_BUILD "F:/pcl-android-180-build/build")

set(PCL_INCLUDE "${PCL_BUILD}/pcl-android")
set(BOOST_INCLUDE "${PCL_BUILD}/boost-android")
set(FLANN_INCLUDE "${PCL_BUILD}/flann-android")
set(EIGEN_INCLUDE "${PCL_BUILD}/eigen")
set(QHULL_INCLUDE "${PCL_BUILD}/qhull-android")

set(PCL_STATIC_LIB_DIR "${PCL_INCLUDE}/lib")
set(BOOST_STATIC_LIB_DIR "${BOOST_INCLUDE}/lib")
set(FLANN_STATIC_LIB_DIR "${FLANN_INCLUDE}/lib")
set(QHULL_STATIC_LIB_DIR "${QHULL_INCLUDE}/lib")

include_directories(${PCL_INCLUDE}/include)
include_directories(${BOOST_INCLUDE}/include)
include_directories(${FLANN_INCLUDE}/include)
include_directories(${QHULL_INCLUDE}/include)
include_directories(${EIGEN_INCLUDE})

function(importLib dirName libName)
    add_library(${libName} STATIC IMPORTED)
    set_target_properties(${libName}
            PROPERTIES
            IMPORTED_LOCATION
            "${dirName}/${libName}.a")
endfunction(importLib)

set(libFlannNames
        libflann_cpp_s
        )

set(libBoostNames
        libboost_thread
        libboost_program_options
        libboost_filesystem
        libboost_system
        libboost_regex
        libboost_iostreams
        libboost_date_time
        )

set(libQhullNames
        libqhullstatic
        )

set(libPclNames
        libpcl_stereo
        libpcl_segmentation
        libpcl_recognition
        libpcl_ml
        libpcl_io
        libpcl_io_ply
        libpcl_filters
        libpcl_tracking
        libpcl_search
        libpcl_registration
        libpcl_keypoints
        libpcl_features
        libpcl_surface
        libpcl_sample_consensus
        libpcl_octree
        libpcl_kdtree
        libpcl_common
        )

foreach(lib ${libPclNames})
    importLib(${PCL_STATIC_LIB_DIR} ${lib})
endforeach(lib)

foreach(lib ${libFlannNames})
    importLib(${FLANN_STATIC_LIB_DIR} ${lib})
endforeach(lib)

foreach(lib ${libBoostNames})
    importLib(${BOOST_STATIC_LIB_DIR} ${lib})
endforeach(lib)

foreach(lib ${libQhullNames})
    importLib(${QHULL_STATIC_LIB_DIR} ${lib})
endforeach(lib)

add_library(native-jni SHARED
        native-jni.cpp
        )


target_link_libraries(
        native-jni
        ${libPclNames}
        ${libFlannNames}
        ${libBoostNames}
        ${libQhullNames}
        android
        log)

Android studio会自动识别CMakeList.txt。如果项目中原本有CMakeList.txt,可以把上面的CMakeList.txt当作已有项目的子模块,在项目根目录下的CMakeList.txt中通过以下语句添加子模块即可:

add_subdirectory(src/main/cpp/xxx/)

xxx为存放cpp文件和对应CMakeList.txt文件的文件夹。

你可能感兴趣的:(Linux,android,PCL,NDK,1.9.1)