一、cmake简介1.1 为什么要用cmake平时,我们写的一些示例程序,只有一个.c文件,编译起来也比较容易,直接使用GCC编译即可。但是,实际项目中,一个工程可能包含成百上千个源文件,分布在各个目录。这样的工程通常使用makefile编译,makefile可以实现自动化编译,极大地提高效率。但是Makefile也有不足之处,譬如当使用qt编译时,需要用到qmake;qmake的语法和linux上的GNU make的规范完全不同,造成不便。cmake就是为了解决这种问题,用户可以通过一个CMakeLists.txt文件指定编译流程,生成Makefile,再执行make编译。
cmake的诞生主要是为了解决直接使用make+Makefile这种方式无法实现跨平台的问题,所以cmake是可以实现跨平台的编译工具,这是它最大的特点,当然除了这个之外,cmake还包含以下优点: 开放源代码。我们可以直接从cmake官网https://cmake.org/下载到它的源代码; 跨平台。cmake并不直接编译、构建出最终的可执行文件或库文件,它允许开发者编写一种与平台无关的CMakeLists.txt文件来制定整个工程的编译流程,cmake工具会解析CMakeLists.txt文件语法规则,再根据当前的编译平台,生成本地化的Makefile和工程文件,最后通过make工具来编译整个工程;所以由此可知,cmake仅仅只是根据不同平台生成对应的Makefile,最终还是通过make工具来编译工程源码,但是cmake却是跨平台的。 语法规则简单。Makefile语法规则比较复杂,对于一个初学者来说,通常并不那么友好,并且Makefile语法规则在不同平台下往往是不一样的;而cmake依赖的是CMakeLists.txt文件,该文件的语法规则与平台无关,并且语法规则简单、容易理解!cmake工具通过解析CMakeLists.txt自动帮我们生成Makefile,这样就不需要我们自己手动编写Makefile了。
1.2 cmake和Makefile直观上理解,cmake就是用来产生Makefile的工具,解析CMakeLists.txt自动生成Makefile: 
二、cmake的使用2.1 安装方法直接apt-get即可安装
sudo apt-get install cmake
查看cmake版本
cmake -version 2.2 cmake编译单个源文件先从编译helloworld开始,写一个main.c文件: #include <stdio.h> int main() { printf("Hello World!\n"); return 0; } 在当前路径下新建一个CMakeLists.txt文件,CMakeLists.txt文件会被cmake工具解析。CMakeLists.txt文件内容如下: project(HELLO) add_executable(hello ./main.c) 
执行cmake命令 cmake ./
执行完cmake之后,除了源文件main.c和CMakeLists.txt之外,可以看到当前目录下生成了很多其它的文件或文件夹,包括:CMakeCache.txt、CmakeFiles、cmake_install.cmake、Makefile,重点是生成了这个Makefile文件,有了Makefile之后,接着我们使用make工具编译我们的工程,make编译后的目录如下所示:

因为我们没有配置交叉编译,所以编译出的可执行文件是X86架构的。 2.3 CMakeLists.txt文件第一行project(HELLO)
project是一个命令,命令的使用方式有点类似于C语言中的函数,因为命令后面需要提供一对括号,并且通常需要我们提供参数,多个参数使用空格分隔而不是逗号“,”。
project命令用于设置工程的名称,括号中的参数HELLO便是我们要设置的工程名称;设置工程名称并不是强制性的,但是最好加上。 第二行add_executable(hello ./main.c)
add_executable同样也是一个命令,用于生成一个可执行文件,在本例中传入了两个参数,第一个参数表示生成的可执行文件对应的文件名,第二个参数表示对应的源文件;所以add_executable(hello ./main.c)表示需要生成一个名为hello的可执行文件,所需源文件为当前目录下的main.c。
2.4 使用out-of-source方式构建在上面的例子中,cmake生成的文件以及最终的可执行文件hello与工程的源码文件main.c混在了一起,这使得工程看起来非常乱,当我们需要清理cmake产生的文件时将变得非常麻烦,这不是我们想看到的;我们需要将构建过程生成的文件与源文件分离开来,不让它们混杂在一起,也就是使用out-of-source方式构建。
将cmake编译生成的文件清理下,然后在工程目录下创建一个build目录,如下所示: 
然后进入到build目录下执行cmake: cd build/ cmake ../ make 这样cmake生成的中间文件以及make编译生成的可执行文件就全部在build目录下了,如果要清理工程,直接删除build目录即可,这样就方便多了。 
2.5 多个源文件在工程中加入多个源文件,分别为hello.c hello.h main.c,在hello.c当中有一个打印hello word的函数,在 main.c当中调用函数,内容如下:
hello.c #include <stdio.h> #include "hello.h" void hello(const char *name) { printf("Hello %s!\n", name); } hello.h #ifndef __HELLO_H #define __HELLO_H void hello(const char *name); #endif main.c #include "hello.h" int main() { hello("world"); return 0; } CMakeLists.txt文件内容: project(HELLO) set(SRC_LIST main.c hello.c) add_executable(hello ${SRC_LIST}) 这里设置了一个SRC_LIST变量,也可以不使用这个变量,直接写成add_executable(hello main.c hello.c)。需要注意,引用变量使用的是{},跟shell的变量有区别。 此时,工程目录结构为: ├── build //文件夹 ├── CMakeLists.txt ├── hello.c ├── hello.h └── main.c 同理,进入build路径下,执行cmake ../即可生成makefile,可以直接make编译。编译后效果如下: 
2.6 设置交叉编译如果不设置交叉编译,默认情况下,cmake会选择主机系统的编译器编译工程,在虚拟机上们就是gcc。而我们的开发板上使用的交叉编译工具为: arm-poky-linux-gnueabi-gcc #C编译器 arm-poky-linux-gnueabi-g++ #C++编译器 在我们每次编译应用之前,都需要执行一个环境变量,以下是部分环境变量内容: export SDKTARGETSYSROOT=/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/cortexa7hf-neon-poky-linux-gnueabi export PATH=/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/x86_64-pokysdk-linux/usr/bin:/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/x86_64-pokysdk-linux/usr/sbin:/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/x86_64-pokysdk-linux/bin:/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/x86_64-pokysdk-linux/sbin:/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/x86_64-pokysdk-linux/usr/bin/../x86_64-pokysdk-linux/bin:/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi:/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-uclibc:/opt/fsl-imx-x11/4.1.15-2.0.0/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-musl:$PATH export CC="arm-poky-linux-gnueabi-gcc -march=armv7ve -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=$SDKTARGETSYSROOT" export CXX="arm-poky-linux-gnueabi-g++ -march=armv7ve -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=$SDKTARGETSYSROOT" export AS="arm-poky-linux-gnueabi-as " export LD="arm-poky-linux-gnueabi-ld --sysroot=$SDKTARGETSYSROOT" export GDB=arm-poky-linux-gnueabi-gdb export TARGET_PREFIX=arm-poky-linux-gnueabi- export CONFIGURE_FLAGS="--target=arm-poky-linux-gnueabi --host=arm-poky-linux-gnueabi --build=x86_64-linux --with-libtool-sysroot=$SDKTARGETSYSROOT" export CFLAGS=" -O2 -pipe -g -feliminate-unused-debug-types -fdebug-prefix-map=/home/diskc/home/liyue/poky/fsl-arm-yocto-bsp/build-fb/tmp/work/x86_64-nativesdk-pokysdk-linux/meta-environment-imx6ulevk/1.0-r8=/usr/src/debug/meta-environment-imx6ulevk/1.0-r8 -fdebug-prefix-map=/home/diskc/home/liyue/poky/fsl-arm-yocto-bsp/build-fb/tmp/sysroots/x86_64-linux= -fdebug-prefix-map=/home/diskc/home/liyue/poky/fsl-arm-yocto-bsp/build-fb/tmp/sysroots/x86_64-nativesdk-pokysdk-linux= " export CXXFLAGS=" -O2 -pipe -g -feliminate-unused-debug-types -fdebug-prefix-map=/home/diskc/home/liyue/poky/fsl-arm-yocto-bsp/build-fb/tmp/work/x86_64-nativesdk-pokysdk-linux/meta-environment-imx6ulevk/1.0-r8=/usr/src/debug/meta-environment-imx6ulevk/1.0-r8 -fdebug-prefix-map=/home/diskc/home/liyue/poky/fsl-arm-yocto-bsp/build-fb/tmp/sysroots/x86_64-linux= -fdebug-prefix-map=/home/diskc/home/liyue/poky/fsl-arm-yocto-bsp/build-fb/tmp/sysroots/x86_64-nativesdk-pokysdk-linux= " export LDFLAGS="-Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed" #export LDFLAGS="-Wl,--copy-dt-needed-entries -lA" export CPPFLAGS="" export KCFLAGS="--sysroot=$SDKTARGETSYSROOT" export OECORE_DISTRO_VERSION="4.1.15-2.0.0" export OECORE_SDK_VERSION="4.1.15-2.0.0" export ARCH=arm export CROSS_COMPILE=arm-poky-linux-gnueabi- 故配置交叉编译只需要配置几个变量,如下: # 配置ARM交叉编译 set(CMAKE_SYSTEM_NAME Linux) #设置目标系统名字 set(CMAKE_SYSTEM_PROCESSOR arm) #设置目标处理器架构 # 指定编译器的sysroot路径 set(TOOLCHAIN_DIR /opt/fsl-imx-x11/4.1.15-2.0.0/sysroots) set(CMAKE_SYSROOT ${TOOLCHAIN_DIR}/cortexa7hf-neon-poky-linux-gnueabi) 指定交叉编译器arm-gcc和arm-g++ set(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-gcc) set(CMAKE_CXX_COMPILER ${TOOLCHAIN_DIR}/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-g++) # 为编译器添加编译选项 set(CMAKE_C_FLAGS "-march=armv7ve -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7") set(CMAKE_CXX_FLAGS "-march=armv7ve -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|