不管是 *.pro
,*.vcxproj
还是说 CMakeLists.txt
文件其实都是项目配置的文件
他们的编写虽然语法存在很大差异,但是在项目配置的内容上基本都是互通的
如果可以了解项目配置的条目,而具体语法是可以随便搜到的
基本配置项
一个项目只要知道 项目名称
,编译输入对象(*.h,*.cpp等)
, 编译输出对象(库/可执行程序)
就能写个最简单的项目管理的 CMakeLists.txt
文件
# cmake最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 设置PROJECT_NAME变量
set(PROJECT_NAME CMakeDemo)
# 设置工程名
project (${PROJECT_NAME})
# 查找当前目录下(src)的所有源文件并存入 PROJECT_SOURCES 变量
aux_source_directory(src PROJECT_SOURCES)
# 添加一个可编译的目标到工程
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
项目名称
project()
是设置项目名称的方法
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[DESCRIPTION <project-description-string>]
[HOMEPAGE_URL <url-string>]
[LANGUAGES <language-name>...])
project()
命令用于指定 cmake
工程的名称,实际上,它还可以指定 cmake
工程的版本号(VERSION
关键字)、简短的描述(DESCRIPTION
关键字)、主页URL(HOMEPAGE_URL
关键字)和编译工程使用的语言(LANGUAGES
关键字)。
详细语法可以参考这篇博客 https://www.jianshu.com/p/cdd6e56c2422
源文件
方法一:
aux_source_directory(<dir> <variable>)
收集指定 <dir> 目录中所有源文件的名称,并将列表存储在提供的 <variable>变量中。
方法二:
file(GLOB_RECURSE PROJECT_SOURCES "*.h" "*.cpp")
获取所有 *.h
和 *.cpp
文件作为源文件(PROJECT_SOURCES
)
编译输出
动态库,静态库都是使用 add_library()
, 只是通过该方法设置第二个变量是 SHARED
STATIC
来改变库类型,一般缺省情况下因为 BUILD_SHARED_LIBS
这个系统全局变量是 ON
, 所以默认生成是动态库
add_library(${PROJECT_NAME} SHARED/STATIC ${PROJECT_SOURCES})
可执行程序使用 add_executable
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
产物导出位置
CMAKE_ARCHIVE_OUTPUT_DIRECTORY
:默认存放静态库的文件夹位置;CMAKE_LIBRARY_OUTPUT_DIRECTORY
:默认存放动态库的文件夹位置;LIBRARY_OUTPUT_PATH
:默认存放库文件的位置,如果产生的是静态库并且没有指定CMAKE_ARCHIVE_OUTPUT_DIRECTORY
则存放在该目录下,动态库也类似;CMAKE_RUNTIME_OUTPUT_DIRECTORY
:存放可执行软件的目录;
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/archive)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/library)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/runtime)
set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin)
编译参数
方法一:
add_compile_options(<option> ...)
add_definitions(-DFOO -DBAR ...) // 函数可以添加任意选项,但主要是用来添加 `-D` 选项。
可以给当前目录以及当前目录以下的目录的 sources
添加编译选项。
add_compile_options(-std=c++11)
方法二:
target_compile_options(<target> [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
是给给定的 <target>
添加编译选项
<target>
指的是由add_executable()
产生的可执行文件或add_library()
添加进来的库。<INTERFACE|PUBLIC|PRIVATE>
指的是[items...]
选项可以传播的范围PUBLIC
和INTERFACE
会传播<target>
的INTERFACE_COMPILE_DEFINITIONS
属性PRIVATE
和PUBLIC
会传播<target>
的COMPILE_DEFINITIONS
属性。
这个方法需要在 add_executable()
和 add_library()
方法后调用
方法三:
通过 set
命令修改 CMAKE_CXX_FLAGS
或 CMAKE_C_FLAGS
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
第三方库的使用
第三库的使用主要就是设置第三方库头文件查找地址,以及需要链接的库信息
第一类
include_directories(${PROJECT_BINARY_DIR})
link_directories(${PROJECT_BINARY_DIR})
link_libraries(MathFunctions)
第二类
target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}")
target_link_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}")
target_link_libraries(Tutorial PUBLIC MathFunctions)
这 2 组和 add_compile_options()
+ target_compile_options()
一样
- 作用域存在区别
- 出现在
add_executable()
和add_library()
方法的位置区别
target_*
因为需要 <target>
目标,所以必须要在 add_executable()
它们后面
include_directories()
是生效于这行命令后面的命令,所以应该在 add_executable()
前面
额外的配置项
注意事项
cmake
变量使用${}
方式取值,但是在if
控制语句中是直接使用变量名- 环境变量使用
$ENV{}
方式取值,使用SET(ENV{VAR} VALUE)
赋值 CMake
支持 大写、小写 和 混合大小写 命令。- 参数和变量是大小写相关的。
message
可以在屏幕上打印信息- 在
CMakeLists.txt
所在目录下先创建类似build
这样的构建目录,然后在build
文件夹内运行cmake ..
,这样就不会污染源代码, 如果不想要这些自动生成的文件了,只要简单的删除build
文件夹就可以
常用全局变量
CMAKE_SOURCE_DIR
:顶层CMakeLists.txt
所在位置CMAKE_CURRENT_SOURCE_DIR
: 正在编译模块的CMakeLists.txt
所在位置CMAKE_BINARY_DIR
: 顶层的构建目录CMAKE_CURRENT_BINARY_DIR
: 正在编译模块的构建目录
以上四个是比较经常用到的,相对于 PROJECT_SOURCE_DIR
这些,个人觉得这几个在多模块下不容易出错
CMAKE_BUILD_TYPE
: 区分debug
和release
版本
if(CMAKE_BUILD_TYPE AND (CMAKE_BUILD_TYPE STREQUAL "Debug"))
message("Debug mode:${CMAKE_C_FLAGS_DEBUG}")
...
elseif(CMAKE_BUILD_TYPE AND (CMAKE_BUILD_TYPE STREQUAL "Release"))
message("Release mode:${CMAKE_C_FLAGS_RELEASE}")
...
else()
message("else:${CMAKE_BUILD_TYPE}")
...
endif()
区分编译平台
cmake
中判断操作系统平台有两种方法:
第一种
message(STATUS "operation system is ${CMAKE_SYSTEM}")
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
message(STATUS "current platform: Linux ")
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
message(STATUS "current platform: Windows")
elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
message(STATUS "current platform: FreeBSD")
else ()
message(STATUS "other platform: ${CMAKE_SYSTEM_NAME}")
endif (CMAKE_SYSTEM_NAME MATCHES "Linux")
message(STSTUS "###################################")
第二种
if (WIN32)
MESSAGE(STATUS "Now is windows")
elseif (APPLE)
MESSAGE(STATUS "Now is Apple systens.")
elseif (UNIX)
MESSAGE(STATUS "Now is UNIX-like OS's.")
endif ()
自定义编译选项
如果项目中存在一些类似开关的选项,可以使用 option()
来定义
option(<variable> "<help_text>" [value])
variable
选项名help_text
描述、解释、备注value
选项初始化值(不初始化或赋为非ON
的值,全部视为OFF
)
详细用法可参照 https://www.cnblogs.com/Braveliu/p/15665143.html
option(BUILD_EXEC "option for build exec" OFF)
if (BUILD_EXEC)
message(STATUS "编译成可执行程序")
add_executable(${project_name} ${DIR_SRCS})
else()
message(STATUS "编译成动态库")
add_library(${project_name} SHARED ${DIR_SRCS})
endif()
cmake
语句的用法:
cmake .. -DBUILD_EXEC=ON