cmake:基础
本文主要探讨cmake语法相关知识。
cmake(GUI)安装
apt install cmake-curses-gui cmake -y
cmake语法
cmake_minimum_required(VERSION 版本号)
设置cmake最低版本
project(工程名) <==> PROGECT_NAME/CMAKE_PROJECT_NAME
设置工程名字
add_library(库名 SHARED/STATIC 源码)
编译生成库文件,默认生成静态库
add_executable(程序名 源码)
生成可执行程序
include_directories(path)
添加头文件路径
message(mode "message")
打印编译信息
FATAL_ERROR:出错停止编译和生成
SEND_ERROR:出错继续编译和生成
WARNING:告警继续编译
AUTHOR_WARNING:开发者警告继续编译
DEPRECATION:设置CMAKE_ERROR_DEPRECATED为true编译出错
(none) or NOTICE:用于打印消息
STATUS:编译状态信息,默认消息显示级别
DEBUG:调试信息
TRACE:日志级临时信息(详细)
CHECK_START:开始记录检查消息
CHECK_PASS:记录检查的成功结果
CHECK_FAIL:记录检查的失败结果
--log-level 参数用于指定消息打印最低级别
set(VAR_NAME var)/unset(VAR__NAME)
设置/删除变量
CMake给c++传递变量
add_definitions(-D PARAM)
PARAM默认值是1CMAKE_CURRENT_LIST_DIR 当前CMakeList.txt完整路径
CMAKE_CURRENT_LIST_LINE 当前所在行
CMAKE_C_FLAGS C编译参数
CMAKE_CXX_FLAGS C++编译参数
DCMAKE_BUILD_TYPE 设置Debug/Release
BUILD_SHARED_LIBS 动态启用库变量
CMAKE_SYSTEM_NAME 系统名
PROJECT_SOURCE_DIR/CMAKE_SOURCE_DIR 顶层目录
PROJECT_BINARY_DIR/CMAKE_BINARY_DIR 顶层缓存目录
CMAKE_CURRENT_SOURCE_DIR 当前源码所在路径
CMAKE_CURRENT_BINARY_DIR 当前缓存目录
CMAKE_RUNTIME_OUTPUT_DIRECTOR 执行文件输出路径
EXECUTABLE_OUTPUT_PATH 执行文件输出路径
LIBRARY_OUTPUT_PATH 动态库文件输出路径
CMAKE_LIBRARY_OUTPUT_DIRECTORY 动态库文件输出路径
CMAKE_ARCHIVE_OUTPUT_DIRECTORY 静态态库文件输出路径
ARCHIVE_OUTPUT_DIRECTORY 静态态库文件输出路径
CMAKE_C_COMPILTER C编译工具链
CMAKE_CXX_COMPILTER C++编译工具链
CMAKE_MAJOR_VERSION cmake主版本号
CMAKE_MINOR_VERSION cmake次版本号
CMAKE_VERSION cmake版本号(主次)
PROJECT_VERSION_MAJOR 工程主版本号
PROJECT_VERSION_MINOR 工程次版本号
PROJECT_VERSION 工程版本号(主次)
include(file.cmake OPTIONAL RESULT_VARIABLE ret)
导入子cmake,OPTIONAL参数使文件不存在不出错
ret为NOTFOUND不存在文件,FOUND存在文件
aux_source_directory(目录 变量)
将目录下的文件存入变量
file
file(WRITE/APPEND filename "message")
WRITE文件存在覆盖写入,文件不存在创建写入
APPEND追加吸入
file(READ filename var num offset HEX)
READ以HEX读文件从offset开始读num字节存储在var中file
file(GLOB VAR path/*.h)
读取path录下的.h文件列表存入VAR
file(GLOB_RECURSE VAR path *.c)
读取path及子目录下的.c文件列表存入VAR
逻辑比较:NOT,AND,OR
大小比较:EQUAL,LESS,LESS_EQUAL,GREATER,GREATER_EQUAL
字符串比较:STR_EQUAL...
版本比较:VERSION_EQUAL...
if(COMMAND name)name是命令,宏,函数为true
if(TEST test)add_test创建测试为true
if(DEFINED name)定义普通,缓存,环境变量为true
if(EXISTS file/directory)文件或目录(全路径)存在为true
if(file1 IS_NEWER_THAN file2)file1比file2新/两文件中一个不存在则为true
if(IS_DIRECTORY directory)是目录为true
if(IS_SYMLINK file)是符号链接为true
if(IS_ABSOLUTE path)是绝对路径为true
缓存
缓存可在构建中重新加载运行
set(VAR var CACHE BOOL "test_cache")
定义缓存变量
BOOL 存储布尔值
PATH 存储路径
STRING 存储字符串
FILEPATH 存储文件路径
INTERNAL 内部变量不在缓存显示
ccmake -B test(GUI)
cmake -S . -B test -D VAR=new_var
修改缓存变量
属性
set_property(GLOBAL|DIRECTORY|TARGET|SOURCE|INSTALL|TEST|CACHE PROPERTY name value)
get_property(var GLOBAL|DIRECTORY|TARGET|SOURCE|INSTALL|TEST|CACHE PROPERTY name)
数学运算
math(EXPR var "expression" OUTPUT_FORMAT format)
HEXADECIMAL 16进制
DECIMAL 10进制
字符串处理
string(FIND <string> <substring> <out-var> [...])
string(REPLACE <match-string> <replace-string> <out-var> <input>...)
string(REGEX MATCH <match-regex> <out-var> <input>...)
string(APPEND <string-var> [<input>...])
string(TOLOWER <string> <out-var>)
string(TOUPPER <string> <out-var>)
string(LENGTH <string> <out-var>)
string(SUBSTRING <string> <begin> <length> <out-var>)
string(STRIP <string> <out-var>)
string(ASCII <number>... <out-var>)
string(HEX <string> <out-var>)
string(TIMESTAMP <out-var> [<format string>] [UTC])
list
set(listName var1 var2 var3...)
list(APPEND listName element1 [element2 ...]) 尾部追加
list(INSERT listName index element1 [element2 ...]) 指定位插入
list(REMOVE_ITEM listName element1 [element2 ...]) 移除元素
list(REMOVE_AT listName index) 移除指定位元素
list(LENGTH listName outputVariable) 获取列表长度
list(GET listName index outputVariable) 获取列表指定位元素
list(FIND listName value outputVariable) 查找列表首次出现该值的位置
list(REVERSE listName) 反转列表
foreach
foreach(<loop_var> <items>)
foreach(<loop_var> RANGE <start> <stop> [<step>])
foreach(<loop_var> IN [LISTS [<lists>]] )
foreach(<loop_var> IN [ITEMS [<items>]])
foreach(<loop_var> IN ZIP_LISTS <lists>)
<commands>
endforeach()
while
while(<condition>)
<commands>
endwhile()
宏
名称大小写不敏感
在调用处展开类似inline
macro(foo arg1 arg2)
<commands>
endmacro()
ARGC参数个数
ARGV0/ARGV1/ARGV2参数
函数
function(func arg1 arg2)
<commands>
endfunction(func)
func(param1 param2)
表达式生成器
包含多参数时满足一个则成立
$<BOOL:string>
$<AND:{条件1}[,{条件2}]...>
$<OR:{条件1}[,{条件2}]...>
$<NOT:{条件}>
$<EQUAL:{数值1},{数值2}>
$<STREQUAL:{字符串1},{字符串2}>
$<IN_LIST:{字符串},{列表}>
$<VERSION_LESS:{版本号1},{版本号2}>
$<VERSION_LESS_EQUAL:{版本号1},{版本号2}>
$<VERSION_EQUAL:{版本号1},{版本号2}>
$<VERSION_GREATER_EQUAL:{版本号1},{版本号2}>
$<VERSION_GREATER:{版本号1},{版本号2}>
$<TARGET_EXISTS:{构建目标}>
$<CONFIG:{构建模式1}[,{构建模式2}]...>
$<PLATFORM_ID:{操作系统1}[,{操作系统2}]...>
$<C_COMPILER_ID:{编译器1}[,{编译器2}]...>
$<CXX_COMPILER_VERSION:{版本号}...>
$<COMPILE_FEATURES:{编译特性1}[,{编译特性2}]...>
$<COMPILE_LANGUAGE:{编程语言1}[,{编程语言2}]...>
$<JOIN:{列表字符串},{分隔符}>
$<JOIN:1;2;3,$<COMMA>> ==> 1,2,3
$<ANGLE-R> 为">"
$<COMMA> 为","
$<SEMICOLON> 为";"
$<LOWER_CASE:{字符串}> 转小写
$<UPPER_CASE:{字符串}> 转大写
$<TARGET_NAME_IF_EXISTS:{目标}> 文件绝对路径
$<TARGET_FILE:{目标}> 二进制文件绝对路径
$<TARGET_FILE_BASE_NAME:{目标}> 基本名称 base
$<TARGET_FILE_PREFIX:{目标}> 前缀lib
$<TARGET_FILE_SUFFIX:{目标}> 后缀.so
$<TARGET_FILE_NAME:{目标}> 文件名称 libbase.so
$<TARGET_FILE_DIR:{目标}> 目录名称
$<TARGET_PROPERTY:{目标},{目标属性}> 属性值
$<TARGET_PROPERTY:{目标属性}> 目标属性
target_include_directories
target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE>
[items2...] ...])
AFTER/BEFORE 添加目录追到头列表/尾列表
SYSTEM 添加到系统目录
INTERFACE 只有依赖者引用
PUBLIC 依赖者和自己都引用
PRIVATE 只有自己用
target_link_libraries
target_link_libraries(<target> <PRIVATE|PUBLIC|INTERFACE> <item>... )
INTERFACE 只有依赖者引用
PUBLIC 依赖者和自己都引用
PRIVATE 只有自己用
target_compile_definitions
编译传递宏
target_compile_definitions(<target> <INTERFACE|PUBLIC|PRIVATE> [items1...])
target_compile_definitions(test_cmake PUBLIC "-DPI=3.14")
target_compile_features
设置c/c++版本
target_compile_features(test_cmake PUBLIC cxx_std_11)
add_library
add_library(<name> [STATIC|SHARED|MODULE] [EXCLUDE_FROM_ALL] [source1] [source2] [...])
配置Debug/Release
set_target_properties(cmath PROPERTIES DEBUG_POSTFIX "d")
设置debug文件后缀
set(CMAKE_BUILD_TYPE Debug)
Debug: -g
Release: -O3
RelWithDebInfo: -O2 -g
MinSizeRel: -Os
cmake -S . -B test -D CMAKE_BUILD_TYPE=Release
cmake -S . -B test && ccmake -B test
install
install(DIRECTORY doc_src DESTINATION doc_dest FILES_MATCHING PATTERN "*.txt" PATTERN "*.html" EXCLUDE "dir" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ)
install(CODE [=[ string(TIMESTAMP now "%Y-%m-%d %H:%M:%S") FILE(APPEND install.log "${now}\n")]=])
install(TARGETS cmake_bin DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ)
install(TARGETS cmake_lib LIBRARY DESTINATION lib PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ)
install(FILES logo.png DESTINATION ${CMAKE_INSTALL_DOCDIR}/pic PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ)
install(SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/cmake/install_script.cmake")
demo:
语法测试
文件结构
代码示例
run.sh
#!/bin/bashcmake -S . -B test --log-level DEBUG -D CACHE_VAR=1 -D CMAKE_BUILD_TYPE=Debugcmake --build testcd test && make installcd ..$(pwd)/bin/test_cmake
clean.sh
#!/bin/bashrm -rf test install.log lib include config doc readme.txt bin
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)project(test_cmake)message("================test message=============")message(DEBUG "projetc : ${PROJECT_NAME}")
set(PARAM "hello")
message(CHECK_START "find PARMA")
if(PARAM)message(CHECK_PASS "define PARAM")
else()message(CHECK_FAIL "not define PARAM")
endif()message("================test param=============")message("CMAKE_CURRENT_LIST_DIR : ${CMAKE_CURRENT_LIST_DIR}")
message("CMAKE_CURRENT_LIST_LINE : ${CMAKE_CURRENT_LIST_LINE}")
message("CMAKE_SYSTEM_NAME : ${CMAKE_SYSTEM_NAME}")
message("PROJECT_SOURCE_DIR : ${PROJECT_SOURCE_DIR}")
message("PROJECT_BINARY_DIR : ${PROJECT_BINARY_DIR}")
message("CMAKE_VERSION : ${CMAKE_VERSION}")add_definitions(-D TEST_PARAM)add_definitions(-D TEST_NUM=27)message("================test include=============")include(${PROJECT_SOURCE_DIR}/math/test.cmake OPTIONAL RESULT_VARIABLE ret)
if(ret)message("found , ret : ${ret}")
else()message("not found , ret : ${ret}")
endif()message("================test file=============")file(WRITE readme.txt [=[
##############CMAKE TESTAUTHOR : cxb
]=])file(APPEND readme.txt [=[ TIME : 2025-06-26##############
]=])file(GLOB FILE_H ${PROJECT_SOURCE_DIR}/include/*.h)file(GLOB_RECURSE SRC_C ./ *.c)file(WRITE file.txt ${SRC_C})file(APPEND file.txt ${FILE_H})file(READ file.txt CONTEXT 1024 0)message("file.txt : ${CONTEXT}")file(REMOVE file.txt)message("================test cache=============")set(CACHE_VAR 0 CACHE BOOL "test_cache")
if(CACHE_VAR)message("CACHE_VAR : ${CACHE_VAR}")
else()message("CACHE_VAR : ${CACHE_VAR}")
endif()message("================test if=============")
if(NOT WIN32)message("system : LINUX")
endif()if(DEFINED CACHE_VAR)message("CACHE_VAR existed")
endif()if(EXISTS ./math/src/math.cpp)message("./math/src/math.cpp existed")
endif()message("================test math=============")math(EXPR test_all "1 + 1" OUTPUT_FORMAT HEXADECIMAL)message("test_all : ${test_all}")message("================test lib=============")add_subdirectory(math)include_directories(include)set(EXEC_SRC ${PROJECT_NAME}.cpp)add_executable(${PROJECT_NAME} ${EXEC_SRC})set(CMAKE_PREFIX_PATH "${PROJECT_SOURCE_DIR}/math")find_package(math)message("math_FOUND = ${math_FOUND}")if(math_FOUND)message("find math success!")endif()target_link_libraries(${PROJECT_NAME} math)message("================test property=============")set_property(GLOBAL PROPERTY TEST_GLOBAL "test1")set_property(GLOBAL APPEND PROPERTY TEST_GLOBAL "test2")get_property(test_g GLOBAL PROPERTY TEST_GLOBAL)message("test_g : ${test_g}")set_property(DIRECTORY . PROPERTY SRC_DIR "${PROJECT_SOURCE_DIR}") get_property(cur_dir DIRECTORY . PROPERTY SRC_DIR)message("cur_dir : ${cur_dir}")set_property(SOURCE math.cpp PROPERTY SRC_NAME "math.cpp")get_property(src_name SOURCE math.cpp PROPERTY SRC_NAME)message("src_name : ${src_name}")set_property(TARGET ${PROJECT_NAME} PROPERTY OBJ_VAR "test_cmake")get_property(target_name TARGET ${PROJECT_NAME} PROPERTY OBJ_VAR)message("target_name : ${target_name}")message("================test install=============")install(TARGETS ${PROJECT_NAME} DESTINATION ${PROJECT_SOURCE_DIR}/bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_WRITE WORLD_EXECUTE)install(FILES readme.txt DESTINATION ${PROJECT_SOURCE_DIR}/doc PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_WRITE WORLD_EXECUTE)string(TIMESTAMP now "%Y-%m-%d %H:%M:%S") FILE(APPEND install.log "${now} build math project\n")
test_cmake.cpp
#include <iostream>#include "math.h"int main()
{#ifdef TEST_PARAMstd::cout << "TEST_PARAM : " << TEST_PARAM << std::endl;#endif#ifdef TEST_NUMstd::cout << "TEST_NUM : " << TEST_NUM << std::endl;#endifint all = add_num(1, 1);std::cout << "all : " << all << std::endl;std::cout << "test cmake" << std::endl;return 0;
}
math/CMakeLists.txt
cmake_minimum_required(VERSION 3.0)aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src MATH_SRCS)include_directories(include)option(BUILD_SHARED_LIBS "shared lib or static lib" OFF)add_library(math $<$<CONFIG:$<BOOL:${BUILD_SHARED_LIBS}>>:SHARED> ${MATH_SRCS})set_target_properties(math PROPERTIES PUBLIC_HEADER include/math.h)target_include_directories(math PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> #install时为空,只有编译时有值$<INSTALL_INTERFACE:include> #只有install时有值
)install(TARGETS math EXPORT mathLIBRARY DESTINATION ${PROJECT_SOURCE_DIR}/libARCHIVE DESTINATION ${PROJECT_SOURCE_DIR}/libPUBLIC_HEADER DESTINATION ${PROJECT_SOURCE_DIR}/include
)install(EXPORT math FILE mathConfig.cmake DESTINATION ${PROJECT_SOURCE_DIR}/config)
math/mathConfig.cmake
set(HEADS_PATH ${PROJECT_SOURCE_DIR}/math/include)set(LIB_PATH ${PROJECT_SOURCE_DIR}/math)
math/test.cmake
message("in cmake/src")
include/math.h
#ifndef __CAMTH_H__
#define __CAMTH_H__int add_num(int num1, int num2);#endif
src/math.cpp
#include "math.h"int add_num(int num1, int num2)
{return num1 + num2;
}
编译执行结果示例
清理执行结果示例