天空大作战
94.86M · 2026-02-04
cmake_minimum_required(VERSION <版本号>)
cmake_minimum_required(VERSION 3.10) # Abseil项目最低版本
cmake_minimum_required(VERSION 3.22.1) # nativesdk项目最低版本
cmake_minimum_required(VERSION 3.5) # utf8_range项目最低版本
指定运行当前CMake脚本所需的最低CMake版本,低于该版本会直接报错,确保脚本兼容性。
project(<项目名> [LANGUAGES <语言列表>] [VERSION <版本号>])
project(absl LANGUAGES CXX VERSION 20230802) # 仅C++,指定版本
project(nativesdk) # 默认语言(C/C++),无版本
project(utf8_range C CXX) # 同时支持C和C++
LANGUAGES:指定项目支持的编译语言(CXX=C++,C=C,不写则默认C/C++);VERSION:给项目标注版本号(仅发布库时有用);${PROJECT_NAME}:当前项目名(如absl、nativesdk);${PROJECT_SOURCE_DIR}:项目源码根目录。# 基础赋值
set(<变量名> <变量值>)
# 缓存变量(强制覆盖默认值)
set(<变量名> <值> CACHE <类型> "<描述>" FORCE)
# 基础变量:编译标准、平台配置
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_ANDROID_STL_TYPE c++_static)
# 缓存变量:关闭第三方库测试/示例
set(ABSL_BUILD_TESTING OFF CACHE BOOL "" FORCE)
set(protobuf_USE_LITE_RUNTIME ON CACHE BOOL "" FORCE)
# 路径变量:拼接路径
set(UTF8_RANGE_SRC_DIR "${protobuf_SOURCE_DIR}/third_party/utf8_range")
${变量名}(如${CMAKE_CXX_STANDARD});BOOL(布尔值,值为ON/OFF,非true/false);FORCE:强制覆盖CMake默认的变量值(比如关闭Abseil的测试编译);"${A}/${B}"),避免路径含空格时出错。add_libraryadd_library(<库名> <库类型> <源码文件列表>)
# 静态库(STATIC):生成.a/.lib文件
add_library(utf8_range STATIC naive.c range2-neon.c)
# 动态库(SHARED):生成.so/.dll文件
add_library(nativesdk SHARED ${ALL_SRC})
STATIC:静态库,编译时打包进可执行文件,不依赖外部库;SHARED:动态库,运行时加载,需配套发布.so/.dll;INTERFACE:仅头文件库(无源码,仅提供头文件);naive.c),也可引用变量(如${ALL_SRC})。add_executableadd_executable(<程序名> <源码文件列表>)
add_executable(tests utf8_validity_test.cc) # 编译测试程序
生成可运行的程序(如测试程序、工具程序),仅在需要可执行文件时使用。
# 全局头文件(所有目标生效)
include_directories(<目录列表>)
# 目标专属头文件(推荐,精准)
target_include_directories(<目标名> <作用域> <目录列表>)
# 全局头文件
include_directories(${UTF8_RANGE_SRC_DIR})
# 目标专属头文件(PRIVATE仅当前目标可用)
target_include_directories(nativesdk PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${abseil-cpp_SOURCE_DIR}
)
PRIVATE:仅当前目标可用(如nativesdk自己的头文件);PUBLIC:当前目标 + 依赖该目标的其他目标可用;INTERFACE:仅依赖该目标的其他目标可用;target_link_libraries(<目标名> <作用域> <库名列表>)
target_link_libraries(nativesdk PRIVATE
absl::base absl::strings
protobuf::libprotobuf-lite
utf8_range
log z atomic m
)
target_link_libraries(utf8_validity PUBLIC absl::strings)
utf8_range);absl::base、protobuf::libprotobuf-lite);log、z、atomic);target_include_directories(PRIVATE/PUBLIC/INTERFACE)。if(<条件>)
# 满足条件执行的命令
elseif(<其他条件>)
# 其他条件执行的命令
else()
# 都不满足执行的命令
endif()
# 检查是否存在目标
if (NOT TARGET absl::strings)
if (NOT ABSL_ROOT_DIR)
find_package(absl REQUIRED CONFIG)
else ()
add_subdirectory(${ABSL_ROOT_DIR} third_party/abseil-cpp)
endif ()
endif ()
# 检查编译开关
if (${ABSL_BUILD_DLL})
absl_make_dll()
endif ()
NOT:取反(如NOT TARGET absl::strings = 不存在absl::strings目标);MATCHES:字符串匹配(如"${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang");${ABSL_BUILD_DLL} = ON时执行);实现「跨平台编译」「按需编译」(比如Android和Linux编译逻辑不同、是否编译测试代码)。
FetchContent(自动下载/编译)# 声明要拉取的库
FetchContent_Declare(
<库名>
GIT_REPOSITORY <Git仓库地址>
GIT_TAG <版本标签/分支>
GIT_SHALLOW <ON/OFF>
)
# 初始化并编译库
FetchContent_MakeAvailable(<库名1> <库名2>)
FetchContent_Declare(
abseil-cpp
GIT_REPOSITORY
GIT_TAG 20240116.0
GIT_SHALLOW OFF
)
FetchContent_MakeAvailable(abseil-cpp protobuf)
GIT_TAG:必须指定(如版本号、标签),避免拉取最新代码导致兼容问题;_deps子目录下。find_package(找已安装的库)find_package(<库名> [REQUIRED] [CONFIG])
find_package(Threads REQUIRED) # 查找线程库,找不到则报错
find_package(GTest REQUIRED) # 查找GoogleTest库
find_package(absl REQUIRED CONFIG) # 按配置文件查找Abseil
REQUIRED:标记为必选依赖,找不到库则直接报错;CONFIG:按库的CMake配置文件查找(而非系统默认路径);FetchContent是「下载并编译」,find_package是「找已安装的库」。add_subdirectoryadd_subdirectory(<子目录路径> [编译输出目录])
add_subdirectory(absl) # 编译Abseil主目录
add_subdirectory(base) # 编译Abseil的base子模块
add_subdirectory(${ABSL_ROOT_DIR} third_party/abseil-cpp) # 指定输出目录
进入子目录,执行该目录下的CMakeLists.txt,适合拆分大型项目(如Abseil按模块拆分编译)。
target_compile_definitionstarget_compile_definitions(<目标名> <作用域> <宏名1> <宏名2=值>)
target_compile_definitions(nativesdk PRIVATE
PROTOBUF_USE_LITE_RUNTIME
GOOGLE_PROTOBUF_NO_RTTI
PROTOBUF_DISABLE_JSON=1
)
给编译器传递宏定义,代码中可通过#ifdef判断(如PROTOBUF_USE_LITE_RUNTIME启用Protobuf Lite版本)。
file(GLOB)file(GLOB <变量名> <文件匹配规则>)
file(GLOB ALL_SRC
${CMAKE_CURRENT_SOURCE_DIR}/core/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/proto/*.pb.cc
)
.cpp、.pb.cc),避免手动罗列所有源码;*.cpp(所有cpp文件)、core/*.cpp(core目录下的cpp文件);cmake ..才能识别。cmake_policycmake_policy(SET <策略ID> <NEW/OLD>)
cmake_policy(SET CMP0025 NEW) # Apple Clang编译器标识修正
cmake_policy(SET CMP0077 NEW) # option命令尊重变量值
兼容不同CMake版本的行为差异(如旧版本CMake的某些命令逻辑和新版本不同,通过策略统一)。
核心命令流程:
# 1. 基础配置
cmake_minimum_required(VERSION 3.22.1)
project(nativesdk)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_ANDROID_STL_TYPE c++_static)
# 2. 拉取第三方依赖
FetchContent_Declare(abseil-cpp ...)
FetchContent_Declare(protobuf ...)
FetchContent_MakeAvailable(abseil-cpp protobuf)
# 3. 收集源码
file(GLOB ALL_SRC core/*.cpp jni/*.cpp proto/*.pb.cc)
# 4. 编译动态库
add_library(nativesdk SHARED ${ALL_SRC})
# 5. 配置头文件
target_include_directories(nativesdk PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${abseil-cpp_SOURCE_DIR})
# 6. 定义编译宏
target_compile_definitions(nativesdk PRIVATE PROTOBUF_USE_LITE_RUNTIME)
# 7. 链接依赖库
target_link_libraries(nativesdk PRIVATE absl::base protobuf::libprotobuf-lite)
核心命令流程:
# 1. 基础配置
cmake_minimum_required(VERSION 3.5)
project(utf8_range C CXX)
# 2. 编译静态库
add_library(utf8_range STATIC naive.c range2-neon.c)
# 3. 查找/编译Abseil依赖
if (NOT TARGET absl::strings)
find_package(absl REQUIRED CONFIG)
endif()
# 4. 链接Abseil
target_link_libraries(utf8_validity PUBLIC absl::strings)
${}包裹,拼接时加双引号(如"${A}/${B}");ON/OFF,而非true/false;PRIVATE(仅当前目标生效),避免PUBLIC导致的全局污染;FetchContent指定GIT_TAG,避免拉取最新代码引发兼容问题;target_include_directories;target_link_libraries(库名是否正确、顺序是否合理)。