cmake交叉编译配置
很多时候,我们在开发的时候是面对嵌入式平台,因此由于资源的限制需要用到相关的交叉编译。即在你host宿主机上要生成target目标机的程序。里面牵扯到相关头文件的切换和编译器的选择以及环境变量的改变等,我今天仅仅简单介绍下相关CMake在面对交叉编译的时候,需要做的一些准备工作。
CMake给交叉编译预留了一个很好的变量CMAKE_TOOLCHAIN_FILE,它定义了一个文件的路径,这个文件即toolChain,里面set了一系列你需要改变的变量和属性,包括C_COMPILER,CXX_COMPILER,如果用Qt的话需要更改QT_QMAKE_EXECUTABLE以及如果用BOOST的话需要更改的BOOST_ROOT(具体查看相关Findxxx.cmake里面指定的路径)。CMake为了不让用户每次交叉编译都要重新输入这些命令,因此它带来toolChain机制,简而言之就是一个cmake脚本,内嵌了你需要改变以及需要set的所有交叉环境的设置。
toolChain脚本中设置的几个重要变量
1.CMAKE_SYSTEM_NAME:
即你目标机target所在的操作系统名称,比如ARM或者Linux你就需要写"Linux",如果Windows平台你就写"Windows",如果你的嵌入式平台没有相关OS你即需要写成"Generic",只有当CMAKE_SYSTEM_NAME这个变量被设置了,CMake才认为此时正在交叉编译,它会额外设置一个变量CMAKE_CROSSCOMPILING为TRUE.
2. CMAKE_C_COMPILER:
顾名思义,即C语言编译器,这里可以将变量设置成完整路径或者文件名,设置成完整路径有一个好处就是CMake会去这个路径下去寻找编译相关的其他工具比如linker,binutils等,如果你写的文件名带有arm-elf等等前缀,CMake会识别到并且去寻找相关的交叉编译器。
3. CMAKE_CXX_COMPILER:
同上,此时代表的是C++编译器。
4. 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将会在那里查找。
5. CMAKE_FIND_ROOT_PATH_MODE_PROGRAM:
对FIND_PROGRAM()起作用,有三种取值,NEVER,ONLY,BOTH,第一个表示不在你CMAKE_FIND_ROOT_PATH下进行查找,第二个表示只在这个路径下查找,第三个表示先查找这个路径,再查找全局路径,对于这个变量来说,一般都是调用宿主机的程序,所以一般都设置成NEVER
6. CMAKE_FIND_ROOT_PATH_MODE_LIBRARY:
对FIND_LIBRARY()起作用,表示在链接的时候的库的相关选项,因此这里需要设置成ONLY来保证我们的库是在交叉环境中找的.
7. 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
8. BOOST_ROOT:
对于需要boost库的用户来说,相关的boost库路径配置也需要设置,因此这里的路径即ARM下的boost路径,里面有include和lib。
9. QT_QMAKE_EXECUTABLE:
对于Qt用户来说,需要更改相关的qmake命令切换成嵌入式版本,因此这里需要指定成相应的qmake路径(指定到qmake本身)
toolChain demo
# 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)
# configure Boost and Qt
SET(QT_QMAKE_EXECUTABLE /opt/qt-embedded/qmake)
SET(BOOST_ROOT /opt/boost_arm)
这样就完成了相关toolChain的编写,之后,你可以灵活的选择到底采用宿主机版本还是开发机版本,之间的区别仅仅是一条-DCMAKE_TOOLCHAIN_FILE=./toolChain.cmake,更爽的是,如果你有很多程序需要做转移,但目标平台是同一个,你仅仅需要写一份toolChain放在一个地方,就可以给所有工程使用。
CMake交叉编译配置就介绍到这,转移之间我来博客园也2个多月了,感受颇多,希望你会喜欢这篇文章 : ) 并且给我一点鼓励。
CMake Cross Compiling
Cross compiling is supported by CMake starting with version 2.6.0.
Cross compiling means that the software is built for a different system than the one which does the build. This means
- CMake cannot autodetect the target system
- Usually the executables don't run on the build host
- The build process has to use a different set of include files and libraries for building, i.e. not the native ones
Contents
[hide]
- 1 Setting up the system and toolchain
- 2 Searching and finding external software
- 3 The toolchain file
- 4 System introspection
- 5 Using executables in the build created during the build
- 6 Cross compilation for Windows CE
- 7 Information how to set up various cross compiling toolchains
- 8 How to cross compile specific projects
- 9 FAQ/Potential Problems
Setting up the system and toolchain
When cross compiling, CMake cannot guess the target system, so you have to preset some CMake variables, e.g. using a toolchain file. The following variables have to be preset:
this one is mandatory, it is the name of the target system, i.e. the same as CMAKE_SYSTEM_NAME would have if CMake would run on the target system. Typical examples are "Linux" and "Windows". This variable is used for constructing the file names of the platform files like Linux.cmake or Windows-gcc.cmake. If your target is an embedded system without OS set CMAKE_SYSTEM_NAME to "Generic". If CMAKE_SYSTEM_NAME is preset, the CMake variable CMAKE_CROSSCOMPILING is automatically set to TRUE, so this can be used for testing in the CMake files.
CMAKE_SYSTEM_VERSION
optional, version of your target system, not used very much.
CMAKE_SYSTEM_PROCESSOR
optional, processor (or hardware) of the target system. This variable is not used very much except for one purpose, it is used to load a CMAKE_SYSTEM_NAME-compiler-CMAKE_SYSTEM_PROCESSOR.cmake file, which can be used to modify settings like compiler flags etc. for the target. You probably only have to set this one if you are using a cross compiler where every target hardware needs special build settings.
Since CMake cannot guess the target system, it also cannot guess which compiler it should use, so you have to preset this too:
the C compiler executable, may be the full path or just the filename. If it is specified with full path, then this path will be prefered when searching the C++ compiler and the other tools (binutils, linker, etc.). If this compiler is a gcc-cross compiler with a prefixed name (e.g. "arm-elf-gcc") CMake will detect this and automatically find the corresponding C++ compiler (i.e. "arm-elf-c++"). The compiler can also be preset via the CC environment variables.
CMAKE_CXX_COMPILER
the C++ compiler executable, may be the full path or just the filename. It is handled the same way as CMAKE_C_COMPILER. If the toolchain is a GNU toolchain, you only need to set one of both.
Once the system and the compiler are determined by CMake, it loads the corresponding files in the following order:
- Platform/${CMAKE_SYSTEM_NAME}.cmake (optional, but issues a stern warning)
- Platform/${CMAKE_SYSTEM_NAME}-<compiler>.cmake (optional)
- Platform/${CMAKE_SYSTEM_NAME}-<compiler>-${CMAKE_SYSTEM_PROCESSOR}.cmake (optional)
<compiler> is either the basename of the compiler executable, e.g. "gcc" (this is also used if gcc has a different name) or "cl", or by a compiler id, which is detected by compiling a test source file.
For testing the host system, there is a corresponding set of variables, which is set automatically by CMake:
- CMAKE_HOST_SYSTEM_NAME
- CMAKE_HOST_SYSTEM_VERSION
- CMAKE_HOST_SYSTEM_PROCESSOR
- CMAKE_HOST_SYSTEM
Without cross compiling the variables for the host system and the target system are identical. In most cases you will want to testfor the target system, then the same way as without cross compiling use the CMAKE_SYSTEM_xxx variables,this will work both for cross compiling and for native building.
With these variables correctly set, CMake will now use the cross compiling toolchain for building and in the CMakeLists.txt you can still use theCMAKE_SYSTEM_XXX variables for testing for which system you are building. This is already enough to use CMake for cross compiling simple (buildsystem-wise) projects.
Searching and finding external software
Most non-trivial projects will depend on external libraries or tools. CMake offers the FIND_PROGRAM(), FIND_LIBRARY(), FIND_FILE(), FIND_PATH() and FIND_PACKAGE() commands for this purpose. They search the file system in common places for files and return the results. FIND_PACKAGE() is a bit different in that it actually doesn't search itself, but "only" executes FindXXX.cmake modules, which usually call the FIND_PROGRAM(), FIND_LIBRARY(), FIND_FILE() and FIND_PATH() commands then.
When cross compiling e.g. for a target with an ARM processor getting /usr/lib/libjpeg.so as the result of a FIND_PACKAGE(JPEG) wouldn't be much of a help, since this would be the JPEG library for the host system, e.g. an x86 Linux box. So you need to tell CMake to search in other locations. This can be done by setting the following variables:
this is a list of directories, each of the directories listed there will be prepended to each of the search directories of every FIND_XXX() command. So e.g. if your target environment is installed under /opt/eldk/ppc_74xx, set CMAKE_FIND_ROOT_PATH to this directory. Then e.g. FIND_LIBRARY(BZ2_LIB bz2) will search in /opt/eldk/ppc_74xx/lib, /opt/eldk/ppc_74xx/usr/lib, /lib, /usr/lib and so give /opt/eldk/ppc_74xx/usr/lib/libbz2.so as result. By default CMAKE_FIND_ROOT_PATH is empty. If set, at first the directories prefixed with the directories given in CMAKE_FIND_ROOT_PATH will be searched and after that the unprefixed versions of the search directories will be searched. This behaviour can be modified individually for every FIND_XXX() call with the NO_CMAKE_FIND_ROOT_PATH, ONLY_CMAKE_FIND_ROOT_PATH and CMAKE_FIND_ROOT_PATH_BOTH options or the default for all FIND_XXX() commands can be adjusted with the CMAKE_FIND_ROOT_PATH_MODE_PROGRAM, CMAKE_FIND_ROOT_PATH_MODE_LIBRARY and CMAKE_FIND_ROOT_PATH_MODE_INCLUDE variables. If you don't want to use only libraries that come with the toolchain but also build and use additional libraries for your target platform, you should create an install directory for these packages, e.g. $HOME/eldk-ppc_74xx-inst/ and add this to CMAKE_FIND_ROOT_PATH, so the FIND_XXX() commands will search there too. If you then build packages for your target platform, they should be installed into this directory.
CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
This sets the default behaviour for the FIND_PROGRAM() command. It can be set to NEVER, ONLY or BOTH (default). If set to NEVER, CMAKE_FIND_ROOT_PATH will not be used for FIND_PROGRAM() calls (except where it is enabled explicitely). If set to ONLY, only the search directories with the prefixes coming from CMAKE_FIND_ROOT_PATH will be used in FIND_PROGRAM(). The default is BOTH, which means that at first the prefixed directories and after that the unprefixed directories will be searched. In most cases FIND_PROGRAM() is used to search for an executable which will then be executed e.g. using EXECUTE_PROCESS() or ADD_CUSTOM_COMMAND(). So in most cases an executable from the build host is required, so usually set CMAKE_FIND_ROOT_PATH_MODE_PROGRAM to NEVER.
CMAKE_FIND_ROOT_PATH_MODE_LIBRARY
This is the same as above, but for the FIND_LIBRARY() command. In most cases this is used to find a library which will then be used for linking, so a library for the target is required. So in the common case, set it to ONLY.
CMAKE_FIND_ROOT_PATH_MODE_INCLUDE
This is the same as above and used for both FIND_PATH() and FIND_FILE(). In many cases this is used for finding include directories, so the target environment should be searched. So in the common case, set it to ONLY. You may have to adjust this behaviour for some of the FIND_PATH() or FIND_FILE() calls using the NO_CMAKE_FIND_ROOT_PATH, ONLY_CMAKE_FIND_ROOT_PATH and CMAKE_FIND_ROOT_PATH_BOTH options.
The toolchain file
-DCMAKE_SYSTEM_NAME
absolute or relative path to a cmake script which sets up all the toolchain related variables mentioned above
toolchain Demo File
For instance for crosscompiling from Linux to Embedded Linux on PowerPC this file could look like this:
# 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)
If this file is named Toolchain-eldk-ppc74xx.cmake and is located in your home directory and you are building in the subdirectory build then you can do:
~/src$ cd build ~/src/build$ cmake -DCMAKE_TOOLCHAIN_FILE=~/Toolchain-eldk-ppc74xx.cmake .. ...
You don't have to write a toolchain file for every piece of software you want to build, the toolchain files are per target platform, i.e. if you are building several software packages all for the same target platform, you have to write only one toolchain file and you can use this for all packages.
If your compiler is not able to build a simple program by default without special flags or files (e.g. linker scripts or memory layout files), the toolchain file as shown above doesn't work. Then you have to force the compiler:
INCLUDE(CMakeForceCompiler) # this one is important SET(CMAKE_SYSTEM_NAME eCos) # specify the cross compiler CMAKE_FORCE_C_COMPILER(arm-elf-gcc GNU) CMAKE_FORCE_CXX_COMPILER(arm-elf-g++ GNU) # where is the target environment SET(CMAKE_FIND_ROOT_PATH /home/alex/src/ecos/install ) # 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)
This is done using the CMAKE_FORCE_XXX_COMPILER() macros. The second argument is the compiler id, which is used by CMake to recognize the compiler.
A toolchain for crosscompiling for Win32 using mingw32 might look like this:
# the name of the target operating system SET(CMAKE_SYSTEM_NAME Windows) # which compilers to use for C and C++ SET(CMAKE_C_COMPILER i486-mingw32-gcc) SET(CMAKE_CXX_COMPILER i486-mingw32-g++) SET(CMAKE_RC_COMPILER i486-mingw32-windres) # here is the target environment located SET(CMAKE_FIND_ROOT_PATH /usr/i486-mingw32) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
System introspection
Many non-trivial software projects have a set of system introspection tests for finding out properties of the (target) system. In CMake there are macros provided for this purpose like e.g. CHECK_INCLUDE_FILES() or CHECK_C_SOURCE_RUNS(). Most of these tests will internally use either the TRY_COMPILE() or the TRY_RUN() CMake commands. The TRY_COMPILE() commands work as expected also when cross compiling, they will try to compile the piece of code with the cross compiling toolchain, which will give the expected result. All tests using TRY_RUN() internally cannot work, since the created executables cannot run on the build host system. At first TRY_RUN() tries to compile the software, which will work the same way when cross compiling. If this succeeded, it will check the variable CMAKE_CROSSCOMPILING whether the resulting executable is runnable or not. If not, it will create two cache variables, which then have to be set by the user or via the CMake cache. Let's say the command looks like this:
TRY_RUN(SHARED_LIBRARY_PATH_TYPE SHARED_LIBRARY_PATH_INFO_COMPILED ${PROJECT_BINARY_DIR}/CMakeTmp ${PROJECT_SOURCE_DIR}/CMake/SharedLibraryPathInfo.cxx OUTPUT_VARIABLE OUTPUT ARGS "LDPATH")
The variable SHARED_LIBRARY_PATH_INFO_COMPILED will be set to the result of the build (i.e. TRUE or FALSE). CMake will create a cache variable SHARED_LIBRARY_PATH_TYPE and preset it to PLEASE_FILL_OUT-FAILED_TO_RUN. This one has to be set to the exit code of the executable if it would have been executed on the target. It will also create a cache variable SHARED_LIBRARY_PATH_TYPE__TRYRUN_OUTPUT and preset it to PLEASE_FILL_OUT-NOTFOUND. This one has to be set to the output the executable prints to stdout and stderr if it is executed on the target. This variable is only created if the TRY_RUN() command was used with the RUN_OUTPUT_VARIABLE or the OUTPUT_VARIABLE argument. You have to fill in appropriate values for these variables. To help you with this CMake tries its best to give you useful information.
To do so CMake creates a file ${CMAKE_BINARY_DIR}/TryRunResults.cmake. There you will find all variables which CMake could not determine, from which CMake file they were called, the source file, the arguments for the executable and the path to the executable. CMake will also copy the executables in the build directory, they have the names cmTryCompileExec-<name of the variable>, e.g. cmTryCompileExec-SHARED_LIBRARY_PATH_TYPE. You can then try to run this executable manually on the actual target platform and check the results.
Once you have these results, they have to get in the CMake cache. You can either use ccmake/CMakeSetup/"make edit_cache" and edit the variables directly in the cache. Then you won't be able to reuse your changes in another build directory or if you remove CMakeCache.txt. The second option is to use the TryRunResults.cmake file. Copy it to a safe location (i.e. where it is not deleted if you delete the build dir) and give it a useful name, e.g. MyProjectTryRunResults-eldk-ppc.cmake. Then edit it so that the SET() commands set the required values. You can the use this file to preload the CMake cache by using the -C option of cmake:
src/build/ $ cmake -C ~/MyProjectTryRunResults-eldk-ppc.cmake .
You don't have to use the other CMake options again, they are now already in the cache. This way you can use MyProjectTryRunResults-eldk-ppc.cmake in multiple build trees and it could also be distributed with your project so it gets easier for other users who want to compile it.
This script may be helpful to automatically populate the TRY_RUN results with those placed in a CMakeCache.txt that were created on the target.
Using executables in the build created during the build
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)
Cross compilation for Windows CE
Building for Windows CE requires Visual Studio 2005 or 2008 (No Express Edition!) with at least one installed SDK. If you don't have a specific installation file for your target device it is possible to use the Windows CE 5.0 Standard SDK from http://www.microsoft.com/downloads/details.aspx?familyid=fa1a3d66-3f61-4ddc-9510-ae450e2318c3.
NMake Makefiles generator. To use it you first need the corresponding environment variables set, for which the CMake command env_vs8_wince
"%VS80COMNTOOLS%vsvars32.bat" cmake -E env_vs8_wince "STANDARDSDK_500 (ARMV4I)" > env.bat env.bat
Then the Makefiles can be generated and built with the following commands:
cmake -G "NMake Makefiles" -DCMAKE_SYSTEM_NAME=WindowsCE -DCMAKE_SYSTEM_PROCESSOR=ARMV4I \path\to\source cmake --build .
Starting with CMake 2.8.11 it is also possible to create Visual Studio solution for Windows CE targets. Depending on the installed SDKs CMake will accept additional generators. The following command will create Visual Studio 2005 files for the WinCE standard SDK:
cmake -G "Visual Studio 8 2005 STANDARDSDK_500 (ARMV4I)" \path\to\source
To use VS2008 instead of VS2005 simple replace "VS80COMNTOOLS" with "VS90COMNTOOLS", "vs8" with "vs9" and "8 2005" with "9 2008".
Information how to set up various cross compiling toolchains
- [1], detailed instructions for using CMake for the iPhone (external, thirdparty website).
- eldk, embedded Linux cross compiling toolchain from Denx
- mingw - gcc for cross compiling from Linux to Windows
- SDCC - the small devices C compiler
- eCos - the embedded Configurable operating system
- ADSP - the Analog Devices toolchain for their DSPs
- IBM BlueGene/L
- Cray XT3 / Catamount
- Crosstool NG - may be used to easily build various cross compiler toolchain. The produced toolchain seems to work well with CMake cross-compiling.
- MXE - Builds compiler and libraries for cross compiling from Linux to Windows. Comes with CMake toolchain file!
How to cross compile specific projects
FAQ/Potential Problems
- On mixed 32/64 bit Linux installations cross compilation cannot be used to build for 32/64 bit only.
- FindXXX.cmake modules, which rely on executing a binary tool like pkg-config may have problems, since the pkg-config of the target platform cannot be executed on the host. Tools like pkg-config should be used only optional in FindXXX.cmake files.
- What about Scratchbox ? CMake should work without problems in scratchbox, then it will just work in native mode.
- Can it build software for PS3 ? If you build software for PS3, you build software for two architectures, for the PowerPC and for the cells. This is done using two different toolchains. Currently CMake doesn't support using multiple toolchains in one buildtree or building for multiple target architectures in one build tree. So building for PS3 doesn't work out-of-the-box. It should work using ADD_CUSTOM_COMMAND() or by using two buildtrees.
参考链接:http://www.cmake.org/Wiki/CMake_Cross_Compiling
CMakeForceCompiler
This module defines macros intended for use by cross-compiling toolchain files when CMake is not able to automatically detect the compiler identification.
Macro CMAKE_FORCE_C_COMPILER has the following signature:
CMAKE_FORCE_C_COMPILER(<compiler> <compiler-id>)
It sets CMAKE_C_COMPILER to the given compiler and the cmake internal variable CMAKE_C_COMPILER_ID to the given compiler-id. It also bypasses the check for working compiler and basic compiler information tests.
Macro CMAKE_FORCE_CXX_COMPILER has the following signature:
CMAKE_FORCE_CXX_COMPILER(<compiler> <compiler-id>)
It sets CMAKE_CXX_COMPILER to the given compiler and the cmake internal variable CMAKE_CXX_COMPILER_ID to the given compiler-id. It also bypasses the check for working compiler and basic compiler information tests.
Macro CMAKE_FORCE_Fortran_COMPILER has the following signature:
CMAKE_FORCE_Fortran_COMPILER(<compiler> <compiler-id>)
It sets CMAKE_Fortran_COMPILER to the given compiler and the cmake internal variable CMAKE_Fortran_COMPILER_ID to the given compiler-id. It also bypasses the check for working compiler and basic compiler information tests.
So a simple toolchain file could look like this:
include (CMakeForceCompiler) set(CMAKE_SYSTEM_NAME Generic) CMAKE_FORCE_C_COMPILER (chc12 MetrowerksHicross) CMAKE_FORCE_CXX_COMPILER (chc12 MetrowerksHicross)