参考 Cmake实战指南 CMakeLists.txt 语法介绍与实例
[TOC]
- 怎么去 组织一个项目的编译框架
- 最终 输出目标 有哪些(可执行程序,动态库,静态库等等)
- 怎么为指定的输出目标指定编译参数(需要哪些源文件,需要哪些编译参数)
- 怎么为指定的输出目标指定链接参数(需要哪些外部库,需要哪些链接参数)
- 如果存在多个独立输出目标是否有执行先后顺序(比如项目有自动配置工具,用来自动生产一些源文件,那么自动配置工具输出目标就要先于其他目标比如输出可执行程序目标)
一、组织项目的编译框架
├── CMakeLists.txt // 根目录放置一个CMakeLists.txt
├── arch
│ └── CMakeLists.txt // 每个需要管理的目录下面也放置一个CMakeLists.txt
├── cfg
│ └── CMakeLists.txt
├── doc
│ └── CMakeLists.txt
├── drivers
│ └── CMakeLists.txt
├── fs
│ └── CMakeLists.txt
├── include // 头文件cmake会自动去构建不需要通过CMakeLists.txt手动添加
├── kernel
│ └── CMakeLists.txt
├── library
│ └── CMakeLists.txt
├── sample
│ └── CMakeLists.txt
└── utils
│ └── CMakeLists.txt
├── cmake // 用来放置通用的cmake源码模块(如:通用编译环境设置,编译链接的一些选项配置...)
├── build // 存放项目构建过程中所有的输出文件
#cmake最低版本要求
cmake_minimum_required(VERSION 3.10.0)
#项目名字为test
project(test NONE)
#包含通用的编译环境模块到顶层目录
include(${CMAKE_SOURCE_DIR}/cmake/base.cmake)
#下一级的编译目录
add_subdirectory(arch)
add_subdirectory(cfg)
add_subdirectory(doc)
add_subdirectory(drivers)
add_subdirectory(fs)
add_subdirectory(kernel)
add_subdirectory(library)
add_subdirectory(sample)
add_subdirectory(utils)
命令标签格式 | 说明 |
---|
cmake_minimum_required(VERSION major.minor[.patch[.tweak]] [FATAL_ERROR]) | 设置最低版本的cmake要求(一般放在第一行) |
project( [LANGUAGES] […]) | 设置项目名,版本,启用的编程语言,上面没有启用任何编程语言所以用NONE |
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL]) | 增加一个子目录到编译系统 |
include(<file|module> [OPTIONAL] [RESULT_VARIABLE ][NO_POLICY_SCOPE]) | 从给出的file文件加载和运行cmake代码 |
二、最终输出目标
- 编译器编译链接之后产生的最终结果(linux下面的elf文件,.a静态库,.so的动态库)
- 主要通过add_executable来定义输出可执行程序目标,
主要通过add_library来定义输出动态库,静态库,模块等目标。 - 定义的输出目标是全局的,比如你在根目录通过add_executable定义了一个输出目标,可以在子目录中用target_sources命令往这个输出目标里面加源文件,cmake在输出这个目标之前会在当前project中搜集所有添加到该目标的源文件再去生成一个编译链接的规则
#定义一个mytool 可执行程序输出目标,目前只有一个源文件 mytool.cpp
add_executable(mytool mytool.cpp)
#往mytool可执行程序输出目标添加源文件,现在mytool目标里面包含两个源文件
target_sources(mytool PRIVATE mytool2.cpp)
#定义一个动态库archive 输出目标,文件有三个源文件
add_library(archive SHARED archive.cpp zip.cpp lzma.cpp)
#定义一个静态库archive 输出目标,也可以不指定STATIC 因为add_library默认输出目标是#静态库
add_library(archive STATIC archive.cpp zip.cpp lzma.cpp)
#从给出的源文件直接生成object文件,比如linux下C语言的.o文件
add_library(archive OBJECT archive.cpp zip.cpp lzma.cpp)
命令标签格式 | 说明 |
---|
add_executable( [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] source1 [source2 …]) | 定义一个名字为name可执行程序输出目标,其中 source1 [source2 …]是源文件,比如C语言是.C的源文件,.H的源文件不需要指定,cmake会自动去搜索 |
add_library( [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 [source2 …]) add_library( OBJECT …) | 定义一个名字为name的库输出目标 |
target_sources(<INTERFACE|PUBLIC|PRIVATE> [items1…][<INTERFACE|PUBLIC|PRIVATE> [items2…] …]) | 往一个目标里面添加源文件,这个目标名字target是在add_executable() 或者add_library() 中定义的name |
- 如果源文件(例如CPP)中包含第三方头文件,但是头文件(例如hpp)中不包含该第三方文件头,采用PRIVATE。
- 如果源文件和头文件中都包含该第三方文件头,采用PUBLIC。
- 如果头文件中包含该第三方文件头,但是源文件(例如CPP)中不包含,采用 INTERFACE
三、指定编译参数和链接参数
- 为add_executable()或者add_library()中定义的输出目标指定编译选项可以通过下面3个命令函数;
命令标签格式 | 说明 |
---|
row 1 col 1 | row 1 col 2 |
row 2 col 1 | row 2 col 2 |
# gcc头文件查找目录,相当于-I选项,e.g -I/foo/bar
#CMAKE_SOURCE_DIR是cmake内置变量表示当前项目根目录
target_include_directories(test_elf
PRIVATE
${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/common
${CMAKE_SOURCE_DIR}/syscalls
)
# 编译的宏定义,e.g 相当于-D选项 e.g -Dmacro=defn
set(MONITOR_OMIT_BSS_INIT "0")
set(MONITOR_OMIT_DATA_INIT "0")
set(MONITOR_OMIT_T_CHECKS "0")
target_compile_definitions(test_elf
PRIVATE
MONITOR_OMIT_BSS_INIT=${MONITOR_OMIT_BSS_INIT}
MONITOR_OMIT_DATA_INIT=${MONITOR_OMIT_DATA_INIT}
MONITOR_TRAP_NT_IRQS=${MONITOR_TRAP_NT_IRQS}
)
# 其他编译选项定义,e.g -fPIC
target_compile_options(test_elf
PRIVATE
-std=c99
-Wall
-Wextra
-Werror
)