参考文章:
http://stackoverflow.com/questions/14810135/erro-while-cross-compile-opencv-program-for-arm
http://blog.csdn.net/pangdegui/article/details/42716829
http://www.cnblogs.com/rickyk/p/3875334.html
https://cmake.org/cmake-tutorial/
https://cmake.org/Wiki/CMake_Cross_Compiling
一、交叉编译opencv3.1.0
1、修改cmake文件
在源码的platforms下已经有对各平台的交叉编译支持,我们只需要做一些简单的修改。
[zzz@localhost platforms]$ pwd
/home/zzz/software/opencv-3.1.0/platforms
[zzz@localhost platforms]$ ll
total 28
drwxr-xr-x. 4 zzz zzz 4096 Dec 18 23:02 android
drwxr-xr-x. 3 zzz zzz 4096 Dec 18 23:02 ios
drwxr-xr-x. 4 zzz zzz 4096 Jan 22 17:24 linux
drwxr-xr-x. 2 zzz zzz 4096 Dec 18 23:02 osx
-rw-r--r--. 1 zzz zzz 323 Dec 18 23:02 readme.txt
drwxr-xr-x. 2 zzz zzz 4096 Dec 18 23:02 scripts
drwxr-xr-x. 2 zzz zzz 4096 Dec 18 23:02 winrt
我们的目标是交叉编译到arm上,那么就进入到linux下:
[zzz@localhost linux]$ pwd
/home/zzz/software/opencv-3.1.0/platforms/linux
[zzz@localhost linux]$ ll
total 20
-rw-r--r--. 1 zzz zzz 4196 Jan 22 16:35 arm-gnueabi.toolchain.cmake
...
arm-gnueabi.toolchain.cmake指明了交叉编译的一些路径等设置,我们根据实际情况对其进行适当修改:
set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_VERSION 1) set(CMAKE_SYSTEM_PROCESSOR arm-hisiv300-linux-gnueabi) set(GCC_COMPILER_VERSION "4.6" CACHE STRING "GCC Compiler version") set(FLOAT_ABI_SUFFIX "") if (NOT SOFTFP) set(FLOAT_ABI_SUFFIX "hf") endif() #CROSS COMPILE SETTING set(TOOLCHAIN_DIR "/opt/hisi-linux/x86-arm/arm-hisiv300-linux/") set(CMAKE_C_COMPILER "/opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc") set(CMAKE_CXX_COMPILER "/opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-g++") set(CMAKE_FIND_ROOT_PATH /opt/hisi-linux/ /opt/hisi-linux/x86-arm/arm-hisiv300-linux/) set(ARM_LINUX_SYSROOT /opt/hisi-linux/x86-arm/arm-hisiv300-linux/ CACHE PATH "ARM cross compile system root") MESSAGE(STATUS "This is cross compile dir --->"$(CMAKE_C_COMPILER)) #find_program(CMAKE_C_COMPILER NAMES arm-linux-gnueabi${FLOAT_ABI_SUFFIX}-gcc-${GCC_COMPILER_VERSION}) #find_program(CMAKE_CXX_COMPILER NAMES arm-linux-gnueabi${FLOAT_ABI_SUFFIX}-g++-${GCC_COMPILER_VERSION}) #set(ARM_LINUX_SYSROOT /usr/arm-linux-gnueabi${FLOAT_ABI_SUFFIX} CACHE PATH "ARM cross compilation system root") #set(CMAKE_CXX_FLAGS "" CACHE STRING "c++ flags") #set(CMAKE_C_FLAGS "" CACHE STRING "c flags") #set(CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "shared linker flags") #set(CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "module linker flags") #set(CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc" CACHE STRING "executable linker flags") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi") set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now ${CMAKE_SHARED_LINKER_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now ${CMAKE_MODULE_LINKER_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "-Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now ${CMAKE_EXE_LINKER_FLAGS}") if(USE_NEON) message(WARNING "You use obsolete variable USE_NEON to enable NEON instruction set. Use -DENABLE_NEON=ON instead." ) set(ENABLE_NEON TRUE) elseif(USE_VFPV3) message(WARNING "You use obsolete variable USE_VFPV3 to enable VFPV3 instruction set. Use -DENABLE_VFPV3=ON instead." ) set(ENABLE_VFPV3 TRUE) endif() #set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${ARM_LINUX_SYSROOT}) if(EXISTS ${CUDA_TOOLKIT_ROOT_DIR}) set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${CUDA_TOOLKIT_ROOT_DIR}) endif() set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." ) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) # macro to find programs on the host OS macro( find_host_program ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) if( CMAKE_HOST_WIN32 ) SET( WIN32 1 ) SET( UNIX ) elseif( CMAKE_HOST_APPLE ) SET( APPLE 1 ) SET( UNIX ) endif() find_program( ${ARGN} ) SET( WIN32 ) SET( APPLE ) SET( UNIX 1 ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) endmacro() # macro to find packages on the host OS macro( find_host_package ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) if( CMAKE_HOST_WIN32 ) SET( WIN32 1 ) SET( UNIX ) elseif( CMAKE_HOST_APPLE ) SET( APPLE 1 ) SET( UNIX ) endif() find_package( ${ARGN} ) SET( WIN32 ) SET( APPLE ) SET( UNIX 1 ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) endmacro()
2、交叉编译
设置好了以后,开始进行交叉编译:
建立好执行cmake的路径:build_softfp,建立好编译后的安装路径:install_dir
[zzz@localhost linux]$ ll
total 20
-rw-r--r--. 1 zzz zzz 4196 Jan 22 16:35 arm-gnueabi.toolchain.cmake
drwxrwxr-x. 15 zzz zzz 4096 Jan 22 16:38 build_softfp
drwxrwxr-x. 6 zzz zzz 4096 Jan 22 15:51 install_dir
执行:
[zzz@localhost build_softfp]$ pwd
/home/zzz/software/opencv-3.1.0/platforms/linux/build_softfp
[zzz@localhost build_softfp]$ cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=../install_dir/ -D SOFTFP=ON -D ENABLE_NEON=ON -D CMAKE_TOOLCHAIN_FILE=../arm-gnueabi.toolchain.cmake ../../../
等待10几分钟。
二、编写测试程序
1、程序内容
简单测试对图片的加载:
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc,char* argv[]){
string path="/home/zzz/facedata/lena.jpg";
Mat image = imread( path, 1 );
if(image.isContinuous()){
cout<<"read picture successfully!"<<endl;
}else{
cout<<"fail to read picture!"<<endl;
}
return 0;
}
2、编译
CMakeLists.txt:
# this is required
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_FIND_ROOT_PATH /opt/hisi-linux/ /opt/hisi-linux/x86-arm/arm-hisiv300-linux/)
set(ARM_LINUX_SYSROOT /opt/hisi-linux/x86-arm/arm-hisiv300-linux/ CACHE PATH "ARM cross compile system root")
# search for programs in the build host directories (not necessary)
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(TOOLCHAIN_DIR "/opt/hisi-linux/x86-arm/arm-hisiv300-linux/")
set(CMAKE_C_COMPILER "/opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc")
set(CMAKE_CXX_COMPILER "/opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-g++")
set(CMAKE_VERBOSE_MAKEFILE ON)
cmake_minimum_required(VERSION 2.8)
project( LoadImage )
set(OpenCV_DIR /home/zzz/software/opencv-3.1.0/platforms/linux/build_softfp/)
include_directories(/home/zzz/software/opencv-3.1.0/platforms/linux/install_dir/include)
#set(OpenCV_DIR /home/zzz/software/opencv-2.4.9/release)
#include_directories(/home/zzz/software/opencv-2.4.9/build/include)
find_package( OpenCV REQUIRED )
add_executable( LoadImage LoadImage.cpp )
target_link_libraries( LoadImage ${OpenCV_LIBS} )
可以把上半部分的内容抽取出来,作为交叉编译的指示文件:
# this is required
set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_FIND_ROOT_PATH /opt/hisi-linux/ /opt/hisi-linux/x86-arm/arm-hisiv300-linux/) set(ARM_LINUX_SYSROOT /opt/hisi-linux/x86-arm/arm-hisiv300-linux/ CACHE PATH "ARM cross compile system root") # search for programs in the build host directories (not necessary) SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # for libraries and headers in the target directories SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(TOOLCHAIN_DIR "/opt/hisi-linux/x86-arm/arm-hisiv300-linux/") set(CMAKE_C_COMPILER "/opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc") set(CMAKE_CXX_COMPILER "/opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-g++") set(CMAKE_VERBOSE_MAKEFILE ON)
执行如下:
[zzz@localhost basictest]$ cmake .
-- The C compiler identification is GNU 4.8.3 -- The CXX compiler identification is GNU 4.8.3 -- Check for working C compiler: /opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc -- Check for working C compiler: /opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working CXX compiler: /opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-g++ -- Check for working CXX compiler: /opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-g++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Configuring done -- Generating done -- Build files have been written to: /home/zzz/workspace/arm-opencv3.1.0/src/basictest [zzz@localhost basictest]$ make
Scanning dependencies of target LoadImage
[100%] Building CXX object CMakeFiles/LoadImage.dir/LoadImage.cpp.o
Linking CXX executable LoadImage
[100%] Built target LoadImage
[zzz@localhost basictest]$
三、在板上运行
需要设置好LD_LIBRARY_PATH,使其也指向一开始生成的opencv的库文件路径,或者直接将这些库拷贝到LD_LIBRARY_PATH指定的当前路径中。
四、问题
一开始没有设定好cmake的交叉编译设置,导致在编译测试程序的时候,使用的是系统的c++编译器在编译链接,结果提示无法读取opencv的so的符号等。所以对cmake的设置要在实践中慢慢掌握全面一些。
后记(2016-1-28):
由于使用的板子有浮点运算单元以及neon,但是上面的编译脚本没有使用相关的参数,包括编译opencv的库以及编译自己的执行程序时都没有用上。因此,编译出来的程序没有用上硬件浮点单元的特性。需要进行修改:
1、修改opencv的交叉编译脚本
主要是设置:
27
28 set(CMAKE_CXX_FLAGS "-mthumb -mcpu=cortex-a7 -mfloat-abi=softfp -mfpu=neon-vfpv4 -mno-unaligned-access -fno-aggressi ve-loop-optimizations" CACHE STRING "c++ flags")
29 set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "c flags")
30 set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "shared linker flags")
31 set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "module linker flags")
32 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-z,nocopyreloc" CACHE STRING "executable linker flags")
33
34 #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi")
35 #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi")
36
37 #set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,- z,now ${CMAKE_SHARED_LINKER_FLAGS}")
38 #set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,- z,now ${CMAKE_MODULE_LINKER_FLAGS}")
39 #set(CMAKE_EXE_LINKER_FLAGS "-Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,- z,now ${CMAKE_EXE_LINKER_FLAGS}")
40
我这里只需要生成so,是否只需要设置CMAKE_SHARED_LINKER_FLAGS这个就可以了?
2、编译出来的so的情况:
[zzz@localhost build_softfp]$ cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=../install_dir/ -D SOFTFP=ON -DENABLE_NEON=ON -D CMAKE_TOOLCHAIN_FILE=../arm-gnueabi.toolchain.cmake ../../../
[zzz@localhost build_softfp]$ readelf -a lib/libopencv_imgproc.so.2.4.9
...
Attribute Section: aeabi
File Attributes
Tag_CPU_name: "Cortex-A7"
Tag_CPU_arch: v7
Tag_CPU_arch_profile: Application
Tag_ARM_ISA_use: Yes
Tag_THUMB_ISA_use: Thumb-2
Tag_FP_arch: VFPv4
Tag_Advanced_SIMD_arch: NEONv1 with Fused-MAC
Tag_ABI_PCS_wchar_t: 4
Tag_ABI_FP_denormal: Needed
Tag_ABI_FP_exceptions: Needed
Tag_ABI_FP_number_model: IEEE 754
Tag_ABI_align_needed: 8-byte
Tag_ABI_enum_size: int
Tag_ABI_HardFP_use: SP and DP
Tag_CPU_unaligned_access: v6
Tag_MPextension_use: Allowed
Tag_DIV_use: Allowed in v7-A with integer division extension
Tag_Virtualization_use: TrustZone and Virtualization Extensions
[zzz@localhost build_softfp]$
我加了一个-DENABLE_NEON=ON,不加也可以。
3、修改执行程序的脚本
在toolchainfile里增加:
set(CMAKE_CXX_FLAGS "-mthumb -mcpu=cortex-a7 -mfloat-abi=softfp -mfpu=neon-vfpv4 -mno-unaligned-access -fno-aggressive-loop-optimizations" CACHE STRING "c++ flags")
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "c flags")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "shared linker flags")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "module linker flags")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-z,nocopyreloc" CACHE STRING "executable linker flags")
经过测试,其实不设置CMAEK_CXX_FLAGS,CMAKE_C_FLAGS及其他,只设置CMAKE_EXE_LINKER_FLAGS,都能达到目标。
产生的exe的情况:
Attribute Section: aeabi
File Attributes
Tag_CPU_name: "Cortex-A7"
Tag_CPU_arch: v7
Tag_CPU_arch_profile: Application
Tag_ARM_ISA_use: Yes
Tag_THUMB_ISA_use: Thumb-2
Tag_FP_arch: VFPv4
Tag_Advanced_SIMD_arch: NEONv1 with Fused-MAC
Tag_ABI_PCS_wchar_t: 4
Tag_ABI_FP_denormal: Needed
Tag_ABI_FP_exceptions: Needed
Tag_ABI_FP_number_model: IEEE 754
Tag_ABI_align_needed: 8-byte
Tag_ABI_enum_size: int
Tag_ABI_HardFP_use: SP and DP
Tag_CPU_unaligned_access: v6
Tag_MPextension_use: Allowed
Tag_DIV_use: Allowed in v7-A with integer division extension
Tag_Virtualization_use: TrustZone and Virtualization Extensions
4、弄明白cmake的几个变量的含义