CMake官方文档注编写CMake的文件名必须是CMakeLists.txt常用语法第一步配置所需的最低cmake版本// “3.6”可以换成所需版本cmake_minimum_required(VERSION3.6)设置项目名也可用此命令配置语言和版本号等信息这个命令不应离cmake_minimum_required太远project(name)配置c/c编译选项配置c/c编译标准可配合CMAKE_CXX_STANDARD_REQUIRED指定最小标准如果cmake不支持高标准则默认使用之前的低标准set(CMAKE_CXX_STANDARD11)// 98 11 14 17 20 23 ...配置c/c编译Flag下面一个是配置gcc的编译选项一个是配置g的编译选项set(CMAKE_C_FLAGS-Wall -Wno-unused-function -g -O3)set(CMAKE_CXX_FLAGS${CMAKE_CXX_FLAGS} -g -O3)添加源文件cmake里可用set命令配置自定义变量或是使用系统保留变量源文件如果不是特别多的话一般放在一个变量里记录就可以。若是需要把其中一些文件编译成库可单独设置一个库文件变量如LIB_SRC_FILES其余文件另存变量如SRC_FILES// 手动添加每个文件set(SRC_FILES a.cpp b.cpp...)也可以使用file命令搜索匹配的文件或用aux_source_directory直接指定文件夹下所有文件// 自动搜索当前目录及子目录下所有cpp文件file(GLOB_RECURSE SRC_FILES./*.cpp ) // 直接添加目录 aux_source_directory(dir SRC_FILES)如果搜索到的文件里有不想添加的文件可以用list进行删除// 添加需要跳过的文件file(GLOB_RECURSE SKIP_SRC_FILES// some files need to be skipped)// 从 SRC_FILES 中删除不想要的文件 SKIP_SRC_FILESlist(REMOVE_ITEM SRC_FILES ${SKIP_SRC_FILES})注因为cmake只在检测到CMakeLists.txt文件更改时才会更新当前配置所以如果有新添加的文件想要被搜索到而CMakeLists.txt文件无更改的话需要手动再cmake一下常用系统保留变量CMAKE_SOURCE_DIR// 顶层cmake目录最外层CMakeLists.txt所在目录CMAKE_BINARY_DIR// 顶层构建目录CMAKE_CURRENT_SOURCE_DIR// 当前cmake目录即当前 CMakeLists.txt 所在目录CMAKE_CURRENT_BINARY_DIR// 当前构建目录PROJECT_SOURCE_DIR// 当前项目源码根目录PROJECT_BINARY_DIR// 当前项目构建根目录CMAKE_RUNTIME_OUTPUT_DIRECTORY// 运行时(exe/dll)输出牧师CMAKE_LIBRARY_OUTPUT_DIRECTORY// 库(so/dylib)输出目录CMAKE_ARCHIVE_OUTPUT_DIRECTORY// 静态库/导入库输出目录多层项目结构上层 CMakeLists.txt 中定义的变量可直接在下层 CMakeLists.txt 文件中使用使用add_subdirectory包含子文件夹该文件夹下的 CMakeLists.txt 会自动在调用的地方运行配置头文件/外部库搜索位置分别用include_directories和link_directories添加头文件和库文件搜索目录include_directories(directoriesinclude)link_directories(directorieslib)配置库库的源文件配置可参考上一小节对静态库和动态库的编译都用add_library选项有一点小小的不同// compile library, use SHARED for shared libraryadd_library(library_nameSTATIC ${LIBXXX_SOURCE_FILES})注如果想要同时编译静态库与动态库且名称不一样则使用上面的命令编译两个库即可。但因为老版本cmake在编译库时会尝试清理其他使用这个名字的库所以如果想要编译出来的库名称相同则需按如下处理// 编译两个库两个名字先设置成不一样add_library(xxx_static STATIC ${LIBXXX_SOURCE_FILES})add_library(xxx SHARED ${LIBXXX_SOURCE_FILES})// 再重命名并配置 CLEAN_DIRECT_OUTPUTset_target_properties(xxx_static PROPERTIES OUTPUT_NAMExxx)set_target_properties(xxx PROPERTIES CLEAN_DIRECT_OUTPUT1)set_target_properties(xxx_static PROPERTIES CLEAN_DIRECT_OUTPUT1)配置可执行文件可执行文件一般添加main函数所在文件和其余不在库中的文件然后链接所需库即可add_executable(exe_namemain.cpp)链接外部库编译库或是可执行文件时用target_link_libraries链接用到的其他库注需放在add_library或add_executable后面target_link_libraries(lib/exeexternal libs)进行编译生成BuildSystem一般是在编译目录如build下cmake加上CMakeLists.txt所在目录即可如果有其余可选的编译选项可加上-D项名参数cmake[options][-B build_dir][-S source_dir]-B 指定build目录存放编译过程产生的临时文件、生成的Makefile等-S 指定source目录源代码目录必须包含一个CMakeLists.txt文件注缺省一个路径的情况下会用当前目录取代缺省的路径所以一般就在build目录下只指定source目录就行用make进行编译或安装make make install-j N 指定多线程编译检查文件/目录/库是否存在一般用于配置目录结构、定义相关宏或者编译所需库文件等// 1. 直接判断if(EXISTSfile name)message(STATUSfile exists)endif(EXISTSfile name)if(NOT EXISTdir name)execute_process(COMMAND mkdir-pdir name)// 创建目录endif(NOT EXISTdir name)// 2. 利用命令返回值execute_process(COMMAND lsfile/dirRESULT_VARIABLE find_result OUTPUT_QUIET ERROR_QUIET)if(find_result)message(STATUScheck file/dir ... no)else()message(STATUScheck file/dir ... ok)add_definitions(-DHAVE_FILE)// 定义宏endif()指定gcc/g版本想指定gcc版本可以自行创建一个xxx.cmake文件并指定好以下一些属性set(gcc_path...)set(CMAKE_C_COMPILER ${gcc_path}/bin/gcc)set(CMAKE_CXX_COMPILER ${gcc_path}/bin/g)然后在构建Buildsystem时把它作为toolchain文件指定给cmakecmake-DCMAKE_TOOLCHAIN_FILExxx.cmake...make-j8// 多线程进行编译定义函数可以像编程语言一样定义函数、传递参数、执行语句、获取返回值等普通传参方式适用于参数一一匹配的方式#Description:#Args:#out_arg:#in_arg:function(FuncName out_arg in_arg)get_filename_component(abs_path ${in_arg}ABSOLUTE)set(${out_arg}${abs_out_file}PARENT_SCOPE)endfunction()// 使用示例set(target_filefile path)FuncName(result ${target_file})注意上面调用函数的示例对于出参result调用时传入变量名对于入参target_file用${}取其值再传入函数体中out_arg不定传参方式适用于根据需求设置多个选项每个选项都能传递不定个数的参数#Description:#Args:#ARG1:#ARG2:#ARG3:#ARG4:function(FuncName)set(options ARG1)set(oneValueArgs ARG2)set(multiValueArgs ARG3)cmake_parse_arguments(Prefix${options}${oneValueArgs}${multiValueArgs}${ARGN})# 处理生成的各个变量...endfunction()使用说明FuncName自定义函数名Prefix自定义变量前缀可以换成其他任意字符串。下述所有选项都会在调用cmake_parse_arguments后生成的对应的变量变量都会以Prefix_为前缀options设置“选项”型选项无参如果在调用函数时出现那么对应变量值为TRUE否则为FALSEoneValueArgs设置“关键字”型选项有且仅有一个参数multiValueArgs设置多参数型选项参数个数1ARG1、ARG2、ARG3自定义的选项名可设置0个或多个对应的变量分别为Prefix_ARG1、Prefix_ARG2、Prefix_ARG3UNPARSED_ARGUMENTS没有对应选项的参数会统一放在这个变量中字符串处理注本质上cmake中所有变量均为字符串定义字符串set(str abc)末尾添加字符串string(APPEND str ...)字符串长度string(LENGTH str len)len变量存储字符串str的长度上述示例为3替换字符串string(REPLACE s t res_str src_str)s匹配字符串t替换字符串res_str结果src_str原字符串string(REGEX REPLACE s$ t res_str src_str)与上面类似只是匹配字符串是正则表达式获取子串string(SUBSTRING ${str} idx len result)idx子串起始索引len子串长度result结果子串字符串判断是否相同if(str STREQUAL ...)是否匹配if(str MATCHS ...)列表处理列表其实只是字符串的一种特殊解析方式字符串中的;会被解析为列表分隔符定义列表下面三种定义方式实际存储内容均相同list(lst a b c)list(lsta;b;c)list(lsta;bc)列表长度list(LENGTH lst len)len变量存储列表lst的长度元素个数注如果用set(lst ;)定义列表该列表包含一个空元素长度为1获取元素list(GET lst idx first_itemidx元素索引可选范围[0, len)末尾添加元素list(APPEND lst ...)删除元素list(REMOVE_AT lst idx)删除索引为idx的元素list(REMOVE_ITEM lst item [item2 ...])删除所有指定元素合并所有元素list(JOIN lst new_str)以指定分隔符合并列表并返回新字符串new_str不修改原列表展开当用${}展开列表时会按元素个数展开当用${}展开列表时会将整个列表作为一个字符串处理过滤元素list(FILTER lst EXCLUDE REGEX fmt)过滤列表排除符合正则fmt的元素修改原列表文件名操作对于文件名可以使用get_filename_component来将文件路径进行拆分根据需求获取各个部分get_filename_component(result_var ${file_name}opt)opt:ABSOLUTE 如果 file_name 是相对路径转为绝对路径 默认基于当前路径也可用BASE_DIR ${...}指定其他路径 DIRECTORY 获取目录部分 NAME 获取文件名包含扩展名 NAME_WE 获取文件名不含扩展名 NAME_WLE 获取文件名不包含最后一个扩展名 EXT 获取文件扩展名包含. LAST_EXT 获取最后一个扩展名 REALPATH 如果是符号链接获取真实绝对路径交叉编译想在A架构下编译B架构的程序才涉及交叉编译。否则只涉及一些代码调整工作编译选项还是与之前一样确认架构确认原版编译环境下面两个命令都可以// 查看架构lscpu arch// 或确认程序指令集fileprogram代码调整如果代码涉及用指令集优化的部分比如x86_64架构的immintrin.h等则需改成目标架构下的对应函数指令集涉及的结构及函数可以在这里粗略查询一下可以用到比如鲲鹏系列的AvxToNeon改完之后进行编译应该就能成功交叉编译以编译arm架构为例准备好交叉编译工具比如交叉编译arm工具arm-linux-gcc (arm-none-linux、arm-linux-gnueabi、arm-none-linux-gnueabihf 等应该均可)在编译目录下创建文件build_arm.cmake内容如下set(CMAKE_SYSTEM_NAME Linux)//【必须】指定目标机使用的操作系统 Generic Linux QNX WindowsCE Android 等//执行后 CMAKE_CROSSCOMPILE 被设置为 TRUEset(CMAKE_SYSTEM_PROCESSOR arm)//【可选】set(toolpath/aaa/bbb/ccc/pathname)//【必须】交叉编译工具路径set(CMAKE_C_COMPILER ${toolpath}/bin/arm-linux-gnueabihf-gcc)//【必须】设置gccset(CMAKE_CXX_COMPILER ${toolpath}/bin/arm-linux-gnueabihf-g)//【必须】设置gset(CMAKE_FIND_ROOT_PATH/usr)// CMAKE查找的根目录set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)// 设置工具程序的位置NEVER表示不查找set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)// 设置库的位置BOTH(默认)表示既可以在系统目录下也可以在CMAKE_FIND_ROOT_PATH路径下查找set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)// 设置头文件位置ONLY表示只在CMAKE_FIND_ROOT_PATH路径下查找指定toolchain编译cmake-DCMAKE_TOOLCHAIN_FILEbuild_arm.cmakepath/to/CMakeLists.txtmake-j8