交叉编译,在我们的host宿主机器上需要生成target目标机器的程序, 使用CMake的Toolchain管理这里的各种环境变量和配置,就很好.
CMake给交叉编译预留了一个变量--CMAKE_TOOLCHAIN_FILE
, 它定义了一个文件的路径, 这个文件就是toolchain
,我们可以在里面配置C_COMPILER
,CXX_COMPILER
,如果用Qt的话需要更改QT_QMAKE_EXECUTABLE
以及如果用BOOST
的话需要更改的BOOST_ROOT
(具体查看相关Findxxx.cmake
里面指定的路径), 因此,这个toolchain
内嵌了一系列需要改变并且需要set的交叉环境的设置.
下面归纳一些比较重要的:
-
CMAKE_SYSTEM_NAME
: 即你目标机target所在的操作系统名称,比如ARM或者Linux你就需要写Linux
,如果Windows平台你就写Windows
,如果你的嵌入式平台没有相关OS你即需要写成Generic
,只有当CMAKE_SYSTEM_NAME
这个变量被设置了,CMake才认为此时正在交叉编译,它会额外设置一个变量CMAKE_CROSSCOMPILING
为TRUE. -
CMAKE_C_COMPILER
: 顾名思义,即C语言编译器,这里可以将变量设置成完整路径或者文件名,设置成完整路径有一个好处就是CMake会去这个路径下去寻找编译相关的其他工具比如linker,binutils等,如果你写的文件名带有arm-elf等等前缀,CMake会识别到并且去寻找相关的交叉编译器。 -
CMAKE_CXX_COMPILER
: 同上,此时代表的是C++编译器。 -
CMAKE_FIND_ROOT_PATH
: 代表了一系列的相关文件夹路径的根路径的变更,比如你设置了/opt/arm/
,所有的Find_xxx.cmake
都会优先根据这个路径下的/usr/lib
,/lib
等进行查找,然后才会去你自己的/usr/lib
和/lib
进行查找,如果你有一些库是不被包含在/opt/arm
里面的,你也可以显示指定多个值给CMAKE_FIND_ROOT_PATH
,比如:
set(CMAKE_FIND_ROOT_PATH /opt/arm /opt/inst)
-
CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
: 对FIND_PROGRAM()
起作用,有三种取值,NEVER
,ONLY
,BOTH
,第一个表示不在你CMAKE_FIND_ROOT_PATH
下进行查找,第二个表示只在这个路径下查找,第三个表示先查找这个路径,再查找全局路径,对于这个变量来说,一般都是调用宿主机的程序,所以一般都设置成NEVER
-
CMAKE_FIND_ROOT_PATH_MODE_LIBRARY
: 对FIND_LIBRARY()
起作用,表示在链接的时候的库的相关选项,因此这里需要设置成ONLY
来保证我们的库是在交叉环境中找的. -
CMAKE_FIND_ROOT_PATH_MODE_INCLUDE
: 对FIND_PATH()
和FIND_FILE()
起作用,一般来说也是ONLY
,如果你想改变,一般也是在相关的FIND
命令中增加option
来改变局部设置,有NO_CMAKE_FIND_ROOT_PATH
,ONLY_CMAKE_FIND_ROOT_PATH
,BOTH_CMAKE_FIND_ROOT_PATH
-
BOOST_ROOT
: 对于需要boost库的用户来说,相关的boost库路径配置也需要设置,因此这里的路径即ARM下的boost路径,里面有include和lib。 -
QT_QMAKE_EXECUTABLE
: 对于Qt用户来说,需要更改相关的qmake命令切换成嵌入式版本,因此这里需要指定成相应的qmake路径(指定到qmake本身)
下面是一个常规的配置
# cross.toolchain.cmake
# this is required
SET(CMAKE_SYSTEM_NAME Linux)
# specify the cross compiler
SET(CMAKE_C_COMPILER /opt/arm/usr/bin/ppc_74xx-gcc)
SET(CMAKE_CXX_COMPILER /opt/arm/usr/bin/ppc_74xx-g++)
# where is the target environment
SET(CMAKE_FIND_ROOT_PATH /opt/arm/ppc_74xx /home/rickk/arm_inst)
# 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(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# configure Boost and Qt
SET(QT_QMAKE_EXECUTABLE /opt/qt-embedded/qmake)
SET(BOOST_ROOT /opt/boost_arm)
# OPENSSL_FOUND OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES
SET(OPENSSL_ROOT_DIR /home/brownfeng/haisi/openssl)
SET(OPENSSL_USE_STATIC_LIBS TRUE)
# CURL_FOUND CURL_INCLUDE_DIRS CURL_LIBRARIES
这样就完成了相关toolChain的编写,之后,你可以灵活的选择到底采用宿主机版本还是开发机版本,之间的区别仅仅是一条-DCMAKE_TOOLCHAIN_FILE=./cross.toolChain.cmake
,更爽的是,如果你有很多程序需要做转移,但目标平台是同一个,你仅仅需要写一份toolChain放在一个地方,就可以给所有工程使用。
搜索查找外部依赖
稍微大一点的项目都会用到一些外部依赖库或者tool,CMake提供了FIND_PROGRAM()
, FIND_LIBRARY()
, FIND_FILE()
, FIND_PATH()
and FIND_PACKAGE()
等命令来进行外部依赖的搜索查找。
但是有个问题,假如我们在给一个ARM处理器的移动设备做交叉编译,其中需要寻找libjpeg.so
,假如FIND_PACKAGE(JPEG)
返回的是/usr/lib/libjpeg.so
,那么这就会有问题,因为找到的这个so
库只是给你的宿主机系统(例如一个x86的Ubuntu主机)服务的,不能用于Arm系统。所以你需要告诉CMake去其它地方去查找,这个时候你就需要配置以下的变量了:
CMAKE_FIND_ROOT_PATH
CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
CMAKE_FIND_ROOT_PATH_MODE_LIBRARY
CMAKE_FIND_ROOT_PATH_MODE_INCLUDE
CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
我的toolchain文件的命名和编译过程
在工程中一般通过如下步骤, 进入工程文件, 创建arm-himix200-linux.cmake
文件, 内容是:
#cmake -DCMAKE_MAKE_PROGRAM=/usr/bin/make -DCMAKE_TOOLCHAIN_FILE=../arm-himix200-linux.cmake ..
# this is required
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_MAKE_PROGRAM /usr/bin/make)
# specify the cross compiler
SET(CMAKE_C_COMPILER /opt/hisi-linux/x86-arm/arm-himix200-linux/bin/arm-himix200-linux-gcc)
SET(CMAKE_CXX_COMPILER /opt/hisi-linux/x86-arm/arm-himix200-linux/bin/arm-himix200-linux-g++)
#指定交叉编译环境中 FindXXX 搜索的目录...
SET(CMAKE_FIND_ROOT_PATH
/opt/hisi-linux/x86-arm/arm-himix200-linux/
/home/brownfeng/haisi/openssl
/home/brownfeng/haisi/curl
)
#从来不在指定目录下查找工具程序
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
#只在指定目录下查找库文件
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
#只在指定目录下查找头文件
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# configure Boost and Qt
#SET(QT_QMAKE_EXECUTABLE /opt/qt-embedded/qmake)
#SET(BOOST_ROOT /opt/boost_arm)
# OPENSSL_FOUND OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES
#SET(OPENSSL_ROOT_DIR /home/brownfeng/haisi/openssl)
#SET(OPENSSL_USE_STATIC_LIBS TRUE)
# CURL_FOUND CURL_INCLUDE_DIRS CURL_LIBRARIES
然后创建build文件夹, 进行编译(注意, 需要指定CMAKE_MAKE_PROGRAM
, 不指定的话好像编译有问题...):
mkdir build
cd build
cmake -DCMAKE_MAKE_PROGRAM=/usr/bin/make -DCMAKE_TOOLCHAIN_FILE=../arm-himix200-linux.cmake ..
在我的toolchain
文件中,我指定:
SET(CMAKE_FIND_ROOT_PATH
/opt/hisi-linux/x86-arm/arm-himix200-linux/
/home/brownfeng/haisi/openssl
/home/brownfeng/haisi/curl
)
因为我项目中CMakeLists.txt
中需要查找OpenSSL
和curl
, 因此会用到CMake自带的FindOpenSSL.cmake
和FindCurl.cmake
两个脚本, 他们会用到Findxxx
命令, 会去我指定的目录去搜索对应的库
参考
https://www.cnblogs.com/rickyk/p/3875334.html
http://www.cmake.org/Wiki/CMake_Cross_Compiling
网友评论