cmake 教程
cmake 教程
1. 创建CMakeLists.txt
在工程中,需要创建很多的CMakeLists.txt,在运行 cmake
时,cmake会根据这些文件,对我们构建的依赖关系创建makefile。
这里以一个最小的工程为例,来实现cmake编译管理工程。
常用的工程目录结构如下:
[duapple@duapple-pc test]$ tree -N -L 3 -I 'build|bin'
.
├── CMakeLists.txt
├── include
│ └── play.h
├── lib
│ ├── CMakeLists.txt
│ └── mylib
│ ├── CMakeLists.txt
│ ├── mylib.c
│ └── mylib.h
└── src
├── CMakeLists.txt
├── main.c
└── play.c
4 directories, 9 files
[duapple@duapple-pc test]$
一般将 .c
文件放到src中,.h
文件放到include
中,然后lib
目录存放我们自己的库。main.c
可以放顶层目录,也可以放src中。
这里有两个思路构建CMakeLists.txt。一种是:由于工程比较简单,在顶层目录下编写CMakeLists.txt即可,通过这一个文件来生成makefile。第二种是:在每一个目录下都编写CMakeLists.txt,没一个目录下的文件只负责自己目录下的文件依赖关系。
这里我采用第二种方式。
- 先主目录编写CMakeLists.txt。
# CMake 最低版本号要求
cmake_minimum_required(VERSION 3.1)
# 项目信息
project(test_project)
# 添加 子目录
add_subdirectory(lib)
add_subdirectory(src)
- 在
lib
中编写CMakeLists.txt。(按理来说这里,应该也是可以跳过这个目录在lib/mylib
中直接编写一个就行了,在顶层路径下指定子目录为lib/mylib
)
add_subdirectory(mylib)
- 在
lib/mylib
中编写CMakeLists.txt。
aux_source_directory(. SRC_LIST)
include_directories(../include ../lib/mylib)
add_library(mylib STATIC ${SRC_LIST})
- 在
src
中编写CMakeLists.txt。
aux_source_directory(. SRC_LIST)
# 添加头文件搜索路径
include_directories(../include ../lib/mylib)
add_executable(test ${SRC_LIST})
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
# 链接库的搜索路径
link_directories("../lib/mylib")
# 添加链接库
target_link_libraries(test m mylib)
至此,CMakeLists.txt文件编写完成,非常的简单明了。如果是在顶层路径下编写一个CMakeLists.txt,那么将更加的简单。cmake的语法是易读的,看一些例子就知道这些语句的作用是什么了。
2. 编译
开始生成makefile。
$ mkdir build & cd build
$ cmake ../
编译。(这里可能会遇到链接先后的顺序的问题,链接顺序不对导致出现函数未定义的情况。将需要的库先链接即可。还有可能出现库的相互依赖问题。暂时没有遇到。)
[duapple@duapple-pc build]$ make
-- Configuring done
-- Generating done
-- Build files have been written to: /home/duapple/work/cmake/test/build
[ 20%] Building C object lib/mylib/CMakeFiles/mylib.dir/mylib.c.o
[ 40%] Linking C static library libmylib.a
[ 40%] Built target mylib
[ 60%] Building C object src/CMakeFiles/test.dir/main.c.o
[ 80%] Building C object src/CMakeFiles/test.dir/play.c.o
[100%] Linking C executable ../../bin/test
[100%] Built target test
运行。
[duapple@duapple-pc build]$ ../bin/test
play_1 called.
mylib_1 called.
3^4 = 81.000000
3. 快捷生成
每次都需要自己手动编写CMakeLists.txt,比较麻烦。写一个脚本来快捷生成模板。
- 编写模板文件
gen_cmake.conf
.
# 支持的最低版本
cmake_minimum_required(VERSION 3.0)
# 项目名称
project(project_name)
# 可执行文件名称
set(OUT_EXEC "out")
# 源文件目录
aux_source_directory(. SRC_LIST)
# 头文件路径
include_directories(./)
# 添加编译参数
add_compile_options(-Os -g -std=gnu99)
# 设置可执行文件输出路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
# 链接库的路径
link_directories(./)
# 生成可执行文件
add_executable(${OUT_EXEC} ${SRC_LIST})
# 添加链接库
target_link_libraries(${OUT_EXEC} )
- 编写生成脚本
gen_make.sh
。
#!/bin/bash
cp /usr/local/sbin/gen_cmake.conf ./CMakeLists.txt
- 设置权限,并放到可执行系统路径下。
$ sudo chmod 777 gen_cmake.sh
$ sudo chmod 777 gen_cmake.conf
$ sudo chmod +x gen_cmake.sh
$ sudo cp gen_cmake.sh gen_cmake.conf /bin/
$ gen_cmake.sh
效果如下:
交叉编译模板 gen_cross_cmake.conf
# 支持的最低版本
cmake_minimum_required(VERSION 3.0)
# 项目名称
project(project_name)
# 可执行文件名称
set(OUT_EXEC "main")
# 指定交叉编译器路径
set(TOOLSCHAIN_PATH "/opt/arm-2014.05/")
set(TOOLCHAIN_HOST "${TOOLSCHAIN_PATH}/bin/arm-none-linux-gnueabi")
# 设置工具链编译器
set(TOOLCHAIN_CC "${TOOLCHAIN_HOST}-gcc")
set(TOOLCHAIN_CXX "${TOOLCHAIN_HOST}-g++")
#告诉cmake是进行交叉编译
set(CMAKE_CROSSCOMPILING TRUE)
set(CMAKE_SYSTEM_NAME "Linux")
# Define the compiler
set(CMAKE_C_COMPILER ${TOOLCHAIN_CC})
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_CXX})
# 源文件目录
aux_source_directory(. SRC_LIST)
# 头文件路径
include_directories(./)
# 添加编译参数
add_compile_options(-Os -g -std=gnu99)
# 设置可执行文件输出路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
# 链接库的路径
link_directories(./)
# 生成可执行文件
add_executable(${OUT_EXEC} ${SRC_LIST})
# 添加链接库
target_link_libraries(${OUT_EXEC} )
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了