Cmake 交叉编译
轉載自 http://zhixinliu.com/2016/02/01/2016-02-01-cmake-cross-compile/
CMake交叉編譯
CMake的使用,以及如何將一個項目移植到Android。
CMake的用法
先讓我們簡單學習回顧一下cmake的基本知識:
基本流程
以linux平臺為例,使用 CMake 生成 Makefile 并編譯的流程如下:
編寫 CMake 配置文件 CMakeLists.txt 。
執行命令 cmake Path-to-Cmakelist/CMakeLists.txt 生成 Makefile。
使用 make 命令進行編譯。
語法
CMakeLists文件可以包含comments,commands,以及 空行。
注釋以#開頭
command:包含命令名字,括號,用空格分開的參數 comand(arg1 arg2 …)
所有的空白行都會被忽略。
基本的命令
project
project:用來聲明項目的名字,也可以指定項目的開發語言
project(projectname [cxx] [c] [java] [none])
如果沒有指定語言,那么CMake默認指定為c和c++
在每一個project出現的CMakeLists.txt,CMake都會創建一個top level的IDE project文件。這個project會包括出現在該CMakeLists.txt中的所有的targets,以及它所有的subdirecotry, 用add_subdirectory命令來指定。
set
set命令用來定義或者修改變量或者lists
和set對應的remove命令
add_executable / add_library
用來定義what executable/libs to build, 并且指定source 文件。
另外一些命令可以從這里找到:
https://cmake.org/cmake/help/v3.0/manual/cmake-variables.7.html
https://cmake.org/Wiki/CMake_Useful_Variables
關于cmake在普通項目中的用法,請參考這篇文章:cmake入門實踐
交叉編譯
現在移動開發越老越火,我們免不了會將一些項目porting到Android/iOS平臺,這個時候就要用到交叉編譯:即在你host宿主機上(例如你用的Ubuntu電腦)要生成target目標機(例如Android手機)的程序。在編譯的過程中會涉及到相關頭文件的切換和編譯器的選擇以及環境變量的改變等,今天就來看看CMake是如何來做交叉編譯的。
首先需要明確以下幾點:
CMake不能自動判斷出目標機系統,需要我們指定。
一般情況下Build出來的可執行文件是不能直接運行在宿主機上。
編譯過程中不能用宿主機上的原聲頭文件和庫,而是需要用到一套不同的頭文件和庫。
CMAKE_TOOLCHIAIN_FILE
這個應該是CMake交叉編譯中最重要的概念。正如前面提到過的,CMake不知道你的目標平臺是什么、用什么編譯起、如何編譯等等,所以你需要提供預設一些變量到CMake,其中最為方便的一個方法就是將相關的變量設置都放進一個文件(cmake腳本)中去,然后將該文件通過CMAKE_TOOLCHIAIN_FILE傳遞給CMake, 例如:
cmake -D CMAKE_TOOLCHIAIN_FILE="/path/to/my-cmake-toolchain-file" …
此處我們假設要執行的CMakeLists file在上一級目錄中。
下面將要在這個文件中需要設置的幾個重要的變量分兩大類依次介紹一下。
設置目標系統以及Toolchain
CMAKE_SYSTEM_NAME:
在toolchain腳本中必須要設置的變量,只有當CMAKE_SYSTEM_NAME這個變量被設置了,CMake才認為此時正在交叉編譯,它會額外設置一個變量CMAKE_CROSSCOMPILING為TRUE。
CMAKE_SYSTEM_NAME即目標機target所在的操作系統名稱,比如ARM或者Linux你就需要寫”Linux”,如果Android平臺你就寫”Android”,如果你的嵌入式平臺沒有相關OS你即需要寫成”Generic”.
CMAKE_SYSTEM_PROCESSOR:
這個是可選項,但是在移動開發中很重要,代表目標系統的硬件或者CPU型號,例如ARM,X86 etc。
CMAKE_C_COMPILER:
即C語言編譯器,這里可以將變量設置成完整路徑或者文件名
CMAKE_CXX_COMPILER:
C++編譯器。
搜索查找外部依賴
稍微大一點的項目都會用到一些外部依賴庫或者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:
代表了一系列的相關文件夾路徑的根路徑的變更,比如你設置了/opt/arm/,所有的Find_xxx.cmake都會優先根據這個路徑下的/usr/lib,/lib等進行查找,然后才會去你自己的/usr/lib和/lib進行查找.
CMAKE_FIND_ROOT_PATH_MODE_PROGRAM:
對FIND_PROGRAM()起作用,有三種取值,NEVER,ONLY,BOTH,第一個表示不在你CMAKE_FIND_ROOT_PATH設置的目錄下進行查找,第二個表示只在這個路徑下查找,第三個表示先查找這個路徑,再查找全局路徑
CMAKE_FIND_ROOT_PATH_MODE_LIBRARY
對FIND_LIBRARY()起作用,表示在鏈接的時候的庫的相關選項,因此這里需要設置成ONLY來保證我們的庫是在交叉環境中找的.
一個小例子
附上一個CMake官方文檔中的toolchian file的小例子,這樣我們就會對如何寫toolchain文件有了感性認識:
# this one is important
SET(CMAKE_SYSTEM_NAME Linux)
#this one not so much
SET(CMAKE_SYSTEM_VERSION 1)# specify the cross compiler
SET(CMAKE_C_COMPILER /opt/eldk-2007-01-19/usr/bin/ppc_74xx-gcc)
SET(CMAKE_CXX_COMPILER /opt/eldk-2007-01-19/usr/bin/ppc_74xx-g++)# where is the target environment
SET(CMAKE_FIND_ROOT_PATH /opt/eldk-2007-01-19/ppc_74xx /home/alex/eldk-ppc74xx-inst)# search for programs in the build host directories
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)
執行起來也很簡單,如下:
~/src$ cd build
~/src/build$ cmake -DCMAKE_TOOLCHAIN_FILE=~/Toolchain-eldk-ppc74xx.cmake …
總結
以上是生活随笔為你收集整理的Cmake 交叉编译的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 求助高人解梦啊啊啊啊啊啊啊啊啊啊啊啊啊,
- 下一篇: 求一个浪漫qq个性签名。