cmake工具构建工程
1. CMake简介
嵌入式多文件编程CMake工具,
cmake 是一个跨平台的自动构建工具
cmake 的诞生主要是为了解决直接使用 make+Makefile 这种方式无法实现跨平台的问题,所以 cmake 是可以实现跨平台的编译工具
详细参考正点原子imax6u嵌入式linux C应用编程指南。
cmake 生成 Makefile 在执行make编译得到执行程序。
Linux 应用编程能力,本部内容将会使用 cmake+vscode 进行开发,其实 cmake 在实际的项目当中用的还是比较多的,譬如很多的开源软件都会选择使用 cmake 来构建、 配置工程源码,
除了 cmake 之外, 还有一些其它的自动构建工具,常用的譬如 automake、 autoconf 等,
开放源代码。我们可以直接从 cmake 官网 https://cmake.org/下载到它的源代码;
跨平台。 cmake 并不直接编译、构建出最终的可执行文件或库文件, 它允许开发者编写一种与平台无关的 CMakeLists.txt 文件来制定整个工程的编译流程,cmake 工具会解析 CMakeLists.txt 文件语法规则,再根据当前的编译平台,生成本地化的 Makefile 和工程文件,最后通过 make 工具来编译整个工程;cmake 仅仅只是根据不同平台生成对应的 Makefile,最终还是通过 make工具来编译工程源码,但是 cmake 却是跨平台的。
语法规则简单。 Makefile 语法规则比较复杂, cmake 工具通过解析 CMakeLists.txt 自动帮我们生成 Makefile,这样就不需要我们自己手动编写 Makefile 了。
https://cmake.org/documentation/ //文档总链接地址
https://cmake.org/cmake/help/latest/guide/tutorial/index.html //培训教程
2. Cmake流程图
3. Cmake安装
cmake 就是一个工具命令,在 Ubuntu 系统下通过 apt-get 命令可以在线安装
sudo apt-get install cmake //安装完成之后可以通过
cmake --version //命令查看 cmake的版本号
4. Cmake构建项目(单文件版本)
新建 HelloWrod 项目为例:
新建项目目录 mkdir HelloWrod
vi main.c //新建代码文件 内容如下:
vi CMakeLists.txt //新建CMakeLists.txt CMakeLists.txt文件会被cmake工具解析
cmake ./ // 执行cmake cmake 后面携带的路径指定了 CMakeLists.txt 文件的所在路径生成了很多其它的文件或文件夹,包括: CMakeCache.txt、 CmakeFiles、 cmake_install.cmake、 Makefile,重点是生成了这个Makefile 文件, 有了 Makefile 之后,接着我们使用 make 工具编译我们的工程,make 编译之后得到了一个可执行文件 hello,通过 file 命令可以查看到 hello 是一个 x86-64 架构下的可执行文件,所以只能在我们的 UbuntuPC 上运行:
CMakeLists.txt 文件内容如下
project(HELLO)
add_executable(hello ./main.c)
main.c 如下内容:
#include <stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}
5. Cmake构建项目(使用 out-of-source 方式构建)
cmake 生成的文件以及最终的可执行文件 hello 与工程的源码文件 main.c 混在了一起,这使得工程看起来非常乱,当我们需要清理 cmake 产生的文件时将变得非常麻烦,这不是我们想看到的;我们需要将构建过程生成的文件与源文件分离开来, 不让它们混杂在一起,也就是使用 out-of-source 方式构建。
对上面项目做调整:
新建 HelloWrod 项目为例:
新建项目目录 mkdir HelloWrod
cd HelloWrod
mkdir build
vi main.c //新建代码文件 内容如下:
vi CMakeLists.txt //新建CMakeLists.txt CMakeLists.txt文件会被cmake工具解析
cd build //进去build 目录下执行 cmake ../ cmake 就会在build目录下生成中间文件 如果要清理工程,直接删除 build 目录即可,这样就方便多了
cmake ../ // 执行cmake cmake 后面携带的路径指定了 CMakeLists.txt 文件的所在路径生成了很多其它的文件或文件夹,包括: CMakeCache.txt、 CmakeFiles、 cmake_install.cmake、 Makefile,重点是生成了这个Makefile 文件, 有了 Makefile 之后,接着我们使用 make 工具编译我们的工程,make 编译之后得到了一个可执行文件 hello,通过 file 命令可以查看到 hello 是一个 x86-64 架构下的可执行文件,所以只能在我们的 UbuntuPC 上运行:
如果要清理工程,直接删除 build 目录即可,这样就方便多了
6. Cmake构建项目(多文件版本)
多文件构建
修改CMakeLists.txt 文件 添加如下:
project(HELLO)
set(SRC_LIST main.c hello.c)
add_executable(hello ${SRC_LIST})
进入到 build 目录下,执行 cmake、再执行 make 编译工程,最终就会得到可执行文件 hello。在本例子中, CMakeLists.txt 文件中使用到了 set 命令, set 命令用于设置变量,如果变量不存在则创建该变量并设置它;在本例中,我们定义了一个 SRC_LIST 变量, SRC_LIST 变量是一个源文件列表, 记录生成可执行文件 hello 所需的源文件 main.c 和 hello.c,而在 add_executable 命令引用了该变量; 当然我们也可以不去定义 SRC_LIST 变量,直接将源文件列表写在 add_executable 命令中,如下:add_executable(hello main.c hello.c)
7. Cmake构建项目(多目录版本)
我们已经加入了多个源文件,但是这些源文件都是放在同一个目录下,这样还是不太正规,我们应该将这些源文件按照类型、功能、模块给它们放置到不同的目录下。
⚫ 顶层 CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(HELLO)
add_subdirectory(libhello)
add_subdirectory(src)
⚫ src 目录下的 CMakeLists.txt
include_directories(${PROJECT_SOURCE_DIR}/libhello)
add_executable(hello main.c)
target_link_libraries(hello libhello)
⚫ libhello 目录下的 CMakeLists.txt
add_library(libhello hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME “hello”)
add_subdirectory 命令, 该命令告诉 cmake 去子目录中寻找新的CMakeLists.txt 文件并解析它;
include_directories 命令用来指明头文件所在的路径,并且使用到了 PROJECT_SOURCE_DIR 变量,该变量指向了一个路径,
进入到 build 目录下进行构建、编译,最终会得到可执行文件 hello(build/src/hello)和库文件 libhello.a(build/libhello/libhello.a):
上面也存在问题:生成的可执行文件和库文件放置不同目录下。
8. Cmake构建项目(将生成的可执行文件和库文件放置到单独的目录下)
如果我想让可执行文件单独放置在 bin 目录下,而库文件单独放置在 lib 目录下,就像下面这样:
将 src 目录下的 CMakeList.txt 文件进行修改,如下所示:
include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(hello main.c)
target_link_libraries(hello libhello)
然后再对 libhello 目录下的 CMakeList.txt 文件进行修改,如下所示:
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
add_library(libhello hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
修改完成之后,再次按照步骤对工程进行构建、编译,
9. Cmake生成库文件
除了生成可执行文件 hello 之外,我们还需要将 hello.c 编译为静态库文件或者动态库文件,
CMakeLists.txt 文件进行修改,如下所示:
project(HELLO)
add_library(libhello hello.c)
add_executable(hello main.c)
target_link_libraries(hello libhello)
进入到 build 目录下,执行 cmake、再执行 make 编译工程,编译完成之后,在 build 目录下就会生成可执行文件 hello 和库文件,如下所示:
add_library(libhello SHARED hello.c) #生成动态库文件
add_library(libhello STATIC hello.c) #生成静态库文件
不难发现 上面 生成的库为 liblibhello.a,名字非常不好看;如果想生成 libhello.a 该怎么办?
直接 add_library(hello hello.c) 答案是不行的
因为 hello 这个目标已经存在了(add_executable(hello main.c)),目标名对于整个工程来说是唯一的,不可出现相同名字的目标,所以这种方法肯定是不行的,实际上我们只需要在 CMakeLists.txt文件中添加下面这条命令即可:set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
set_target_properties 用于设置目标的属性,这里通过 set_target_properties 命令对 libhello 目标的OUTPUT_NAME 属性进行了设置,将其设置为 hello。
编译完成之后会发现,生成的库文件为 libhello.a,而不是 liblibhello.a。
10. CMakeLists.txt 文件
第一行 project(HELLO) project 命令用于设置工程的名称 设置工程名称并不是强制性的,但是最好加上。
第二行 add_executable(hello ./main.c) 用于生成一个可执行文件, 在本例中传入了两个参数,第一个参数表示生成的可执行文件对应的文件名,第二个参数表示对应的源文件; 所以 add_executable(hello ./main.c)表示需要生成一个名为 hello 的可执行文件,所需源文件为当前目录下的 main.c。
11. CMakeLists.txt 语法规则
参考详细参考正点原子imax6u嵌入式linux C应用编程指南。 第三十二章 CMake 入门与进阶。