CMake基础:条件判断详解

目录

1.简介

2.核心判断类型及示例

2.1.变量相关判断

2.2.数值判断

[2.3.文件 / 路径判断](#2.3.文件 / 路径判断)

[2.4. 目标 / 组件判断](#2.4. 目标 / 组件判断)

[2.5. 系统与编译器判断](#2.5. 系统与编译器判断)

[2.6.逻辑组合(与 / 或 / 非)](#2.6.逻辑组合(与 / 或 / 非))

2.7.括号分组(优先级控制)

2.8.判断某个元素是否在列表中

3.常见实用场景

4.注意事项

相关链接


1.简介

CMake 的条件判断是通过 if()/elseif()/else()/endif() 结构实现流程控制的核心,常用于根据环境、配置、依赖等动态调整构建逻辑。

基本语法:

cpp 复制代码
if(<条件>)
  # 条件为真时执行
elseif(<另一条件>)  # 可选,可多个
  # 另一条件为真时执行
else()  # 可选
  # 所有条件为假时执行
endif()  # 必须闭合(推荐加注释:endif(<条件>) 增强可读性)

如果是基本表达式,条件(expression)有以下三种情况:常量、变量、字符串

  • 如果是1, ON, YES, TRUE, Y, 非零值非空字符串时,条件判断返回True
  • 如果是0, OFF, NO, FALSE, N, IGNORE, NOTFOUND空字符串时,条件判断返回False

2.核心判断类型及示例

2.1.变量相关判断

1)if(<var>) :变量存在且值为 "真"(1/ON/YES/TRUE/Y,不区分大小写)。

cpp 复制代码
set(ENABLE_FEATURE ON)
if(ENABLE_FEATURE)  # 成立
  message("Feature enabled")
endif()

2)if(NOT <var>) :变量不存在或值为 "假"(0/OFF/NO/FALSE/N/ 空值)。

3)if(DEFINED <var>):仅判断变量是否被定义(无论值是否为空)。

cpp 复制代码
set(EMPTY_VAR "")
if(DEFINED EMPTY_VAR)  # 成立(变量已定义)
  message("变量已定义")
endif()

4)字符串比较STREQUAL(全等,区分大小写)、STRLESS(小于)、STRGREATER(大于)。

if(string1 STREQUAL string2):字符串相等(区分大小写)。

if(string1 MATCHES regex):正则匹配。

cpp 复制代码
# 1
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")  # 字符串完全匹配, 编译Debug版本
  ...
endif()

# 2
set(OS_TYPE "Linux")
if(OS_TYPE STREQUAL "macOS")  # 注意大小写
    message("macOS detected") # 不会执行(L != l)
endif()

2.2.数值判断

支持整数比较,使用 EQUAL(等于)、LESS(小于)、GREATER(大于)、LESS_EQUAL(小于等于)、GREATER_EQUAL(大于等于):

cpp 复制代码
set(NUM 5)
if(NUM GREATER 3)  # 成立(5 > 3)
    message(STATUS "NUM 大于 3")
endif()

2.3.文件 / 路径判断

  • if(EXISTS <路径>):路径存在(文件或目录均可)。
cpp 复制代码
if(EXISTS "src/main.cpp")  # 若文件存在则成立
    message(STATUS "找到源文件")
endif()
  • if(IS_DIRECTORY <路径>):路径为目录则成立。
cpp 复制代码
if(IS_DIRECTORY "include")  # 若 include 是目录则成立
    message(STATUS "找到 include 目录")
endif()
  • if(IS_FILE <路径>):路径为文件则成立(CMake 3.14+ 支持)。

  • if(IS_SYMLINK file-name) : 判断是不是软链接, 此处的file-name必须是绝对路径

  • if(IS_ABSOLUTE path) : 判断是不是绝对路径

2.4. 目标 / 组件判断

  • if(TARGET <目标名>) :检查是否存在指定名称的构建目标(如通过 add_executable/add_library 定义的目标)。
cpp 复制代码
add_executable(my_app main.cpp)
if(TARGET my_app)  # 成立(目标存在)
    message(STATUS "目标 my_app 已定义")
endif()
  • if(<包名>_FOUND) :检查通过 find_package() 查找的包是否成功(通常包会定义 <包名>_FOUND 变量)。
cpp 复制代码
find_package(OpenSSL)
if(OpenSSL_FOUND)  # 找到 OpenSSL 则成立
    message(STATUS "OpenSSL 已找到")
endif()

2.5. 系统与编译器判断

条件 含义
if(WIN32) Windows 系统(含 32/64 位)
if(UNIX) 类 Unix 系统(Linux/macOS 等)
if(APPLE) macOS/iOS 系统
if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 精确匹配 Linux 系统
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 编译器为 GCC
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 编译器为 Clang(含 AppleClang)
cpp 复制代码
if(WIN32)
    message(STATUS "当前系统:Windows")
elseif(APPLE)
    message(STATUS "当前系统:macOS")
elseif(UNIX)
    message(STATUS "当前系统:Linux 或其他类 Unix 系统")
endif()

2.6.逻辑组合(与 / 或 / 非)

  • if(<条件1> AND <条件2>):两个条件都为真则成立。
  • if(<条件1> OR <条件2>):至少一个条件为真则成立。
  • if(NOT <条件>):条件为假则成立(前面已提)。
cpp 复制代码
set(A 1)
set(B 0)
if(A AND NOT B)  # 成立(A 为真,B 为假)
    message(STATUS "条件成立")
endif()

2.7.括号分组(优先级控制)

() 调整逻辑优先级:

cpp 复制代码
if((A OR B) AND C)  # 先判断 A 或 B,再与 C 组合
    ...
endif()

2.8.判断某个元素是否在列表中

CMake版本要求 > 3.3

cpp 复制代码
if(<variable|string> IN_LIST <variable>)

3.常见实用场景

1.根据构建类型(Debug/Release)配置:

cpp 复制代码
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
  add_definitions(-DDEBUG_MODE)  # Debug 模式定义宏
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0")  # 关闭优化
else()
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")  # Release 模式开优化
endif()

2.条件添加源文件 / 宏:

cpp 复制代码
add_executable(myapp main.cpp)
if(ENABLE_FEATURE_X)  # 若启用 Feature X,添加对应源文件
  target_sources(myapp PRIVATE feature_x.cpp)
  target_compile_definitions(myapp PRIVATE ENABLE_X)
endif()

3.检查 CMake 版本是否满足要求:

cpp 复制代码
cmake_minimum_required(VERSION 3.10)  # 最低版本要求
if(CMAKE_VERSION VERSION_LESS "3.18")  # 低于 3.18 时提示
  message(WARNING "CMake 版本过低,部分功能可能受限")
endif()

4.根据用户选项(option())开启/关闭功能

cpp 复制代码
option(ENABLE_FOO "Enable feature FOO" ON)
option(ENABLE_BAR "Enable feature BAR (requires FOO)" OFF)

if(ENABLE_BAR AND NOT ENABLE_FOO)
    message(FATAL_ERROR "ENABLE_BAR requires ENABLE_FOO to be ON")
endif()

if(ENABLE_FOO)
    target_compile_definitions(my_app PRIVATE HAVE_FOO)
    if(ENABLE_BAR)
        target_compile_definitions(my_app PRIVATE HAVE_BAR)
    endif()
endif()

更多内容可参考:CMake指令:option_cmake option-CSDN博客

5.依赖项检查(如 find_package() 结果)

cpp 复制代码
find_package(Protobuf 3.14 QUIET)  # 优先找 3.14+
if(NOT Protobuf_FOUND)
    find_package(Protobuf 3.0 REQUIRED)  # 找不到则降级到 3.0+
endif()

target_link_libraries(my_app PRIVATE ${Protobuf_LIBRARIES})

更多内容可参考:CMake指令:find_package_cmake find package-CSDN博客

4.注意事项

1.变量引用无需 ${}if(MY_VAR) 直接用变量名,而非 if(${MY_VAR})(后者会解析为变量值,易出错)。

2.空变量视为假 :未定义的变量或值为空时,if(<var>) 结果为假。

3.字符串比较大小写敏感STREQUAL 严格区分大小写,如需忽略可先统一大小写(如 string(TOLOWER ${A} A_LOW))。

4.路径用绝对路径更可靠 :结合 CMAKE_SOURCE_DIR(源码根目录)等内置变量:

cpp 复制代码
if(EXISTS "${CMAKE_SOURCE_DIR}/third_party")  # 绝对路径检查
  ...
endif()

相关链接

相关推荐
山登绝顶我为峰 3(^v^)31 小时前
如何录制带备注的演示文稿(LaTex Beamer + Pympress)
c++·线性代数·算法·计算机·密码学·音视频·latex
QuantumStack6 小时前
【C++ 真题】P1104 生日
开发语言·c++·算法
天若有情6736 小时前
01_软件卓越之道:功能性与需求满足
c++·软件工程·软件
whoarethenext6 小时前
使用 C++/OpenCV 和 MFCC 构建双重认证智能门禁系统
开发语言·c++·opencv·mfcc
Jay_5157 小时前
C++多态与虚函数详解:从入门到精通
开发语言·c++
xiaolang_8616_wjl8 小时前
c++文字游戏_闯关打怪
开发语言·数据结构·c++·算法·c++20
FrostedLotus·霜莲9 小时前
C++主流编辑器特点比较
开发语言·c++·编辑器
liulilittle13 小时前
深度剖析:OPENPPP2 libtcpip 实现原理与架构设计
开发语言·网络·c++·tcp/ip·智能路由器·tcp·通信
十年编程老舅14 小时前
跨越十年的C++演进:C++20新特性全解析
c++·c++11·c++20·c++14·c++23·c++17·c++新特性