option() 必须在 project() 后调用、显式指定 bool 类型、设字面量默认值(on/off),同名变量已存在时不会覆盖旧值,子目录重复定义会报错,推荐写法为 option(enable_tests "build test executables" off bool)。

直接写 option() 就行,但必须配默认值、类型要明确、变量名不能和已有缓存项冲突——否则 CMake 会静默忽略或报错。
option() 的基本写法和参数顺序
option() 是 CMake 提供的缓存布尔开关,语法固定为四参数(CMake 3.20+ 支持三参数,但建议写全):
- 第一个是变量名(
ENABLE_FOO),会被写入缓存,后续可用${ENABLE_FOO}引用 - 第二个是描述字符串(
"Enable Foo feature"),只在cmake-gui或ccmake中显示 - 第三个是默认值(
ON或OFF),注意:必须是字面量,不能是变量或表达式 - 第四个是可选的“类型”(
BOOL),CMake 3.20+ 才支持显式指定;不写时默认为BOOL,但显式写上更安全
正确示例:
option(ENABLE_TESTS "Build test executables" OFF)
推荐写法(显式类型 + 注释说明):
# 缓存变量名: ENABLE_TESTS # 类型: BOOL(强制约束用户只能输 ON/OFF) # 默认: OFF(避免意外启用测试影响构建速度) option(ENABLE_TESTS "Build test executables" OFF BOOL)
为什么 option() 不生效?常见陷阱
最常踩的坑不是语法错,而是缓存机制和作用域问题:
-
option()必须在project()之后调用,否则 CMake 可能不识别缓存变量 - 如果同名变量已在缓存中存在(比如上次运行时设过),
option()不会覆盖默认值,只保留旧值 —— 这是设计行为,不是 bug - 在子目录(
add_subdirectory())里重复定义同名option(),会导致 CMake 报错:CMake Error: option called with unknown type(类型不一致)或静默失败 - 误把
set(ENABLE_FOO ON CACHE BOOL ...)当成option()替代 —— 虽然效果类似,但缺少描述字段,GUI 工具里看不到说明
怎么在代码里用这个选项?别直接 if(ENABLE_FOO)
option() 定义的是缓存变量,但它在 CMake 脚本中就是普通变量,可以直接判断。但要注意:
- 用
if(ENABLE_FOO)没问题,但等价于if(ENABLE_FOO STREQUAL "ON"),CMake 会自动转换 - 如果变量未定义(比如漏写
option()),if(ENABLE_FOO)会返回 false,不会报错 —— 容易掩盖配置遗漏 - 更健壮的做法是加一层存在性检查(尤其跨项目复用时):
if(DEFINED ENABLE_TESTS AND ENABLE_TESTS) add_subdirectory(tests) endif()
另外,别在 option() 前就引用该变量,例如:
# ❌ 错误:ENABLE_TESTS 还没声明,这里读到的是空字符串
message(STATUS "Tests enabled: ${ENABLE_TESTS}")
option(ENABLE_TESTS "..." OFF)
和 set(... CACHE ...) 的区别在哪?
两者都写缓存,但语义和约束不同:
-
option()只支持BOOL类型,且默认值只能是ON/OFF,CMake GUI 里显示为勾选框 -
set(VAR value CACHE STRING "desc")支持STRING/PATH/FILEPATH等类型,GUI 里显示为输入框或路径选择器 -
option()更适合开关类配置(如USE_OPENMP、BUILD_SHARED_LIBS);需要填路径或字符串时,必须用set(... CACHE ...) - 混用时注意:如果先
set(FOO ON CACHE BOOL ...),再option(FOO "..." OFF),CMake 会报错,因为缓存项类型已定,不能二次声明
复杂项目里经常同时用两者:用 option() 控制功能开闭,用 set(... CACHE ...) 配置路径或编译器标志。











