CMake 个人心得

不管是 *.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...] 选项可以传播的范围
    • PUBLICINTERFACE 会传播 <target>INTERFACE_COMPILE_DEFINITIONS 属性
    • PRIVATEPUBLIC 会传播 <target>COMPILE_DEFINITIONS 属性。

这个方法需要在 add_executable()add_library() 方法后调用

方法三:

通过 set 命令修改 CMAKE_CXX_FLAGSCMAKE_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 : 区分 debugrelease 版本
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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会偷懒的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值