CMake: (三) 交叉編譯



CMAKE_TOOLCHAIN_FILE

#toolchain cmake file
 
SET(CMAKE_SYSTEM_NAME Linux)
SET(TOOLCHAIN_DIR "/home/xx/softwares/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux")
SET(3RDPART_LIBS_DIR "/home/xx/install")
 
#specify the cross compiler
SET(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}/bin/arm-linux-gnueabihf-gcc CACHE FILEPATH "Archiver")
SET(CMAKE_CXX_COMPILER ${TOOLCHAIN_DIR}/bin/arm-linux-gnueabihf-g++ CACHE FILEPATH "Archiver")
#SET(CMAKE_GFORTRAN  ${TOOLCHAIN_DIR}/bin/arm-linux-gnueabihf-gfortran)
SET(CMAKE_AR ${TOOLCHAIN_DIR}/bin/arm-linux-gnueabihf-ar CACHE FILEPATH "Archiver")
SET(CMAKE_AS ${TOOLCHAIN_DIR}/bin/arm-linux-gnueabihf-as CACHE FILEPATH "Archiver")
SET(CMAKE_LD  ${TOOLCHAIN_DIR}/bin/arm-linux-gnueabihf-ld CACHE FILEPATH "Archiver")
SET(CMAKE_NM ${TOOLCHAIN_DIR}/bin/arm-linux-gnueabihf-nm CACHE FILEPATH "Archiver")
SET(CMAKE_STRIP  ${TOOLCHAIN_DIR}/bin/arm-linux-gnueabihf-strip CACHE FILEPATH "Archiver")
 
# where is the target environment
SET(CMAKE_FIND_ROOT_PATH  ${TOOLCHAIN_DIR} ${3RDPART_LIBS_DIR})
 
# 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)

上面是一個在x86_64的Linux上編譯arm32程序的toolchain.cmake,編譯時候,可以使用如下指令

cd ./build
cmake -DCMAKE_TOOLCHAIN_FILE=~/toolchain.camke ../

參數說明

CMAKE_SYSTEM_NAME

這個參數是利用cmake進行交叉編譯必須設置的,通常都是Linux或者Windows,聲明要利用cmake創建運行在目標系統上的文件。如果要創建運行在沒有操作系統的嵌入式環境,該參數要設置成Generic.如果CMAKE_SYSTEM_NAME進行了預先設置,CMAKE_CROSSCOMPLING經會被自動置位為True.所以可以被用來測試時候在交叉編譯環境進行編譯。

CMAKE_SYSTEM_VERSION

可選項,目標系統的版本,用的不多。

CMAKE_SYSTEM_PROCESS

可選項,目標系統的處理器,只有在目標程序要運行在不同硬件平台時候才需要進行設置針對不同的對象。它可以被用來做一些編譯器編譯選項的快速設定。

CMAKE_C_COMPLIER

C語言編譯器,例如在shell中修改變量CC指向交叉編譯的C編譯器export CC=arm-linux-guneabihf-gcc, 或者在CMakeLists.txt內設置 SET(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}/bin/arm-linux-gnueabihf-gcc),但是這句話只有寫到PROJECT( project_name)之前才會起作用,或者將一系列設置寫在toolchain.cmake文件中,如上所述。

CMAKE_CXX_COMPLIER:CXX

CXX編譯器,如果其是交叉編譯工具,二者只需要聲明一個。

主機環境

CMAKE_HOST_SYSTEM_NAME,CMAKE_HOST_SYSTEM_VERSION,CMAKE_HOST_SYSTEM_PROCESSOR,CMAKE_HOST_SYSTEM除了交叉環境編譯情況下,主機和目標機器的變量值一樣。

查找外部軟件

一般工程都包含一些外部依賴的庫或者工具,cmake提供給我們一些變量可以進行查找FIND_PROGRAM(), FIND_LIBRARY(), FIND_FILE(), FIND_PATH() and FIND_PACKAGE() 查找文件和返回結果。FIND_PACKAGE()其實並不進行查找,而是通過執行FindXXX.cmake模塊,進而調用FIND_PROGRAM(), FIND_LIBRARY(), FIND_FILE(), FIND_PATH()去查找文件。例如當你編譯軟件時候,希望程序鏈接文件 /usr/lib/libjpeg.soFIND_PACKAGE(JPEG)會直接在主機的相對位置查找此鏈接文件,所以我們必須設定CMake在指定的位置查找需要的文件。

下面的設置可以幫助我們完成相應的操作

CMAKE_FIND_ROOT_PATH

這是一個文件夾列表,如果你的目標環境安裝在/opt/eldk/ppc_74xx,配置CMAKE_FIND_ROOT_PATH指向此處,然后FIND_LIBRARY(BZ2_LIB bz2)將會搜索/opt/eldk/ppc_74xx/lib, /opt/eldk/ppc_74xx/usr/lib, /lib, /usr/lib 之后會將 /opt/eldk/ppc_74xx/usr/lib/libbz2.so 作為結果返回。

CMAKE_FIND_ROOT_PATH默認設置為空。如果設置之后,cmake默認會首先搜索具有這個前綴的位置下文件,之后去其他位置查找。

  • 每個FIND_XXX()可以通過參數NO_CMAKE_FIND_ROOT_PATH, ONLY_CMAKE_FIND_ROOT_PATHCMAKE_FIND_ROOT_PATH_BOTH設置查找范圍
  • 或者采用對所有的FIND_XXX()都起作用的的參數CMAKE_FIND_ROOT_PATH_MODE_PROGRAM, CMAKE_FIND_ROOT_PATH_MODE_LIBRARYCMAKE_FIND_ROOT_PATH_MODE_INCLUDE進行設置。

如果你的工程不僅需要toolchain里面的工具,還有目標平台的附加庫。我們還需要為這些依賴包建立一個安裝文件夾,例如/home/ke/install,同時需要添加這個位置進去CMAKE_FIND_ROOT_PATH,之后FIND_XXX()才可以在這些位置進行查找。

如果之后你build packages在你的目標平台上面,也要安裝在這個文件夾內。

CMKAE_FIND_ROOT_PATH_MODE_PROGRAM

這個變量為FIND_PROGRAM命令設置默認選項,可以是NEVER,ONLY,BOTH(默認).

  1. NEVER:CMAKE_ROOT_PATH將會被FIND_PROGRAM()忽略,除非顯示使能。
  2. ONLY:FIND_PROGRAM只在CMAKE_FIND_ROOT_PATH為前綴的目錄下查找需要的文件;
  3. BOTH,先在CMAKE_FIND_ROOT_PATH查找之后再去其他位置。

在大多數情形下,FIND_PROGRAM()用來查找可以被EXECUTABLE_PROCESS() 或者 ADD_CUSTOM_COMMAND()執行的程序。所以在大多數情況下,主機的可執行程序是必須的,所以CMAKE_FIND_ROOT_PATH_MODE_PROGRAM通常被設置成為NEVER。

CMAKE_FIND_ROOT_PATH_MODE_LIBRARY

FIND_LIBRARY()命令的默認設置,設置鏈接需要的文件目錄,通常都位於目標系統內,所以一般設置成為ONLY;

CMAKE_FIND_ROOT_PATH_MODE_INCLUDE

FIND_FILE()和FIND_PATH()的默認設置,用來查找include文件目錄,文件通常位於目標機器中,所以一般設置為ONLY,我們也可以通過設置NO_CMAKE_FIND_ROOT_PATH, ONLY_CMAKE_FIND_ROOT_PATHCMAKE_FIND_ROOT_PATH_BOTH為FIND_FILE()和FIND_PATH()限定文件的查找位置。


使用其他可執行程序

In some cases during a build executables are created which are then used in ADD_CUSTOM_COMMAND() or ADD_CUSTOM_TARGET() during the same build process.When cross compiling this won't work without modifications because the executables cannot run on the build host. Starting with CMake 2.6 it is possible to "import" executable targets into a CMake project. When cross compiling this has to be used to import executables built in a native build into the cross-build. This can be done like this:

# when crosscompiling import the executable targets from a file
IF(CMAKE_CROSSCOMPILING)
  SET(IMPORT_EXECUTABLES "IMPORTFILE-NOTFOUND" CACHE FILEPATH "Point it to the export file from a native build")
  INCLUDE(${IMPORT_EXECUTABLES})
ENDIF(CMAKE_CROSSCOMPILING)

...

# only build the generator if not crosscompiling
IF(NOT CMAKE_CROSSCOMPILING)
   ADD_EXECUTABLE(mygenerator mygen.cpp)
   TARGET_LINK_LIBRARIES(mygenerator ${SOME_LIBS})
ENDIF(NOT CMAKE_CROSSCOMPILING)

# then use the target name as COMMAND, CMake >= 2.6 knows how to handle this
ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated.c
                   COMMAND mygenerator foo.dat -o ${CMAKE_CURRENT_BINARY_DIR}/generated.c
                   DEPENDS foo.dat )


...
# export the generator target to a file, so it can be imported (see above) by another build
# the IF() is not necessary, but makes the intention clearer
IF(NOT CMAKE_CROSSCOMPILING) 
  EXPORT(TARGETS mygenerator FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake )
ENDIF(NOT CMAKE_CROSSCOMPILING)

So during the native build the target "mygenerator" will be built and used in ADD_CUSTOM_COMMAND(). As command only the target name is used. CMake >= 2.6.0 recognizes this and creates the dependencies and will use the path to the created executable when executing the command. At the end the EXPORT() function (since CMake 2.6.0) is called, which "exports" the listed targets to the file ${CMAKE_BINARY_DIR}/ImportExecutables.cmake, which will look like this:

ADD_EXECUTABLE(mygenerator IMPORT)
SET_TARGET_PROPERTIES(mygenerator PROPERTIES 
                      LOCATION /home/alex/build-native/bin/mygenerator )

This file is then included when cross compiling, it either has to be specified using -D or via the cmake GUI. Then later on the command for actually building mygenerator is excluded. In ADD_CUSTOM_COMMAND() mygenerator will be recognized as an imported target and it will be used when executing the command.

If the executable mygenerator also has to be built when cross compiling, then some more logic needs to be added, e.g. like this:

# when crosscompiling import the executable targets from a file
IF(CMAKE_CROSSCOMPILING)
  SET(IMPORT_EXECUTABLES "IMPORTFILE-NOTFOUND" CACHE FILEPATH "Point it to the export file from a native build")
  INCLUDE(${IMPORT_EXECUTABLES})
ENDIF(CMAKE_CROSSCOMPILING)

...

# always build the executable
ADD_EXECUTABLE(mygenerator mygen.cpp)
TARGET_LINK_LIBRARIES(mygenerator ${SOME_LIBS})

# but use different names for the command
IF(CMAKE_CROSSCOMPILING)
   SET(mygenerator_EXE native-mygenerator)
ELSE(CMAKE_CROSSCOMPILING)
   SET(mygenerator_EXE mygenerator)
ENDIF(CMAKE_CROSSCOMPILING)

# then use the target name as COMMAND, CMake >= 2.6 knows how to handle this
ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/generated.c
                   COMMAND ${mygenerator_EXE} foo.dat -o ${CMAKE_CURRENT_BINARY_DIR}/generated.c
                   DEPENDS foo.dat )


...
# export the generator target to a file, so it can be imported (see above) by another build
# the IF() is not necessary, but makes the intention clearer
# use the NAMESPACE option of EXPORT() to get a different target name for mygenerator when exporting
IF(NOT CMAKE_CROSSCOMPILING) 
  EXPORT(TARGETS mygenerator FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake NAMESPACE native- )
ENDIF(NOT CMAKE_CROSSCOMPILING)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM