CMake指令:file()

发布于:2025-05-28 ⋅ 阅读:(19) ⋅ 点赞:(0)

目录

1.简介

2.常用子命令(COMMAND)

2.1.COPY - 复制文件或目录

2.2.RENAME - 重命名文件或目录

2.3.REMOVE - 删除文件或目录

2.4.MAKE_DIRECTORY - 创建目录

2.5.READ - 读取文件内容

2.6.WRITE - 写入文件内容

2.7.GLOB - 按模式匹配文件

2.8.GET_FILENAME_COMPONENT - 获取文件路径组件

2.9.TOUCH - 更新文件时间戳或创建空文件

2.10.MD5/SHA1/SHA256 - 计算文件哈希值

2.11.GET_RUNTIME_DEPENDENCIES - 获取运行时依赖

2.12.SIZE - 获取文件大小

2.13.DOWNLOAD - 下载文件

2.14.UPLOAD - 上传文件

2.15.归档压缩

3.注意事项

4.总结


1.简介

        在 CMake 中,file 命令用于需要访问文件系统的文件和路径操作,执行文件系统相关的操作,例如复制、移动、删除文件或目录,创建目录,写入文件内容,获取文件属性等。它是 CMake 中处理文件系统操作的核心命令之一,功能丰富且灵活。

        基本语法:

file(<COMMAND> [ARG1] [ARG2] ...)

其中 <COMMAND> 是具体的操作类型,不同的命令对应不同的参数和功能。

2.常用子命令(COMMAND)

2.1.COPY - 复制文件或目录

复制文件或目录到目标路径。

file(COPY <source>... DESTINATION <dir> [FILE_PERMISSIONS <permissions>...] [DIRECTORY_PERMISSIONS <permissions>...] [USE_SOURCE_PERMISSIONS] [NO_SOURCE_PERMISSIONS] [RENAME <name>] [SYMBOLIC_LINK_DESTINATION] [LINK_ONLY] [EXCLUDE_FROM_ALL])

示例代码:

# 复制单个文件到目标目录(覆盖已存在文件)
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/config.ini" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/bin")

# 复制整个目录(包含子文件和目录)
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/resources/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/resources")

# 复制时重命名文件
file(COPY "logo.png" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" RENAME "app_logo.png")

2.2.RENAME - 重命名文件或目录

重命名文件或目录(可跨路径移动)

file(RENAME <old_path> <new_path>)

示例代码:

# 重命名文件
file(RENAME "temp.txt" "final_data.txt")

# 移动并重命名目录
file(RENAME "${CMAKE_CURRENT_BINARY_DIR}/build_temp" "${CMAKE_CURRENT_BINARY_DIR}/build_release")

2.3.REMOVE - 删除文件或目录

删除文件、目录或符号链接。

file(REMOVE [FORCE] <file>...)          # 删除文件或符号链接
file(REMOVE_RECURSE [FORCE] <dir>...)   # 递归删除目录及内容(谨慎使用!)
  • FORCE:强制删除(忽略权限问题,跨平台兼容)。

示例代码:

# 删除单个文件
file(REMOVE "debug.log")

# 递归删除构建目录(常用于清理)
file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/build")

2.4.MAKE_DIRECTORY - 创建目录

创建单个或多个目录(若不存在)。

file(MAKE_DIRECTORY <dir>...)

示例代码:

# 创建输出目录
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}")

2.5.READ - 读取文件内容

读取文件内容到变量。

file(READ <file> <variable> [LIMIT <num_bytes>] [OFFSET <offset>] [HEX])

示例代码: 

# 读取配置文件内容
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/config.ini" CONFIG_CONTENT)
message("Config content: ${CONFIG_CONTENT}")

file(READ example.txt res)
message("${res}")  # 输出: 你好,CMake!

file(READ example.txt res LIMIT 6)
message("${res}")  # 输出: 你好

file(READ example.txt res OFFSET 9)
message("${res}")  # 输出: CMake

file(READ example.txt res OFFSET 9 HEX)
message("${res}")  # 输出: 434d616b65efbc81

<OFFSET(偏移量)>和<LIMIT(最大长度)>均按照字节计算,因此UTF-8编码的中文等特殊字符的长度并不能视为1。

file(STRING)

命令用于读取文件内容到字符串变量将字符串写入文件,支持灵活处理换行符、编码等细节。

# 读取文件内容到变量
file(STRING <filename> <variable> [NEWLINE_STYLE <style>] [ENCODING <encoding>] [RESULT_VARIABLE <result_var>])

# 将字符串写入文件
file(STRING WRITE <filename> <content> [NEWLINE_STYLE <style>] [ENCODING <encoding>] [RESULT_VARIABLE <result_var>])

1. 读取文件相关参数

  • <filename>:目标文件路径(支持绝对路径或相对路径)。
  • <variable>:存储文件内容的变量名。
  • NEWLINE_STYLE:控制读取时如何处理换行符,可选值:
    • UNIX:转换为 \n(默认)。
    • DOS:转换为 \r\n
    • MAC:转换为 \r
    • KEEP:保留原始换行符(不转换)。
  • ENCODING:指定文件编码(如 UTF-8ASCIIGBK 等,需 CMake 3.16+)。
  • RESULT_VARIABLE:存储命令执行结果(成功为 0,失败为非零值)。

2. 写入文件相关参数

  • <content>:要写入文件的字符串内容。
  • 其他参数与读取文件类似,NEWLINE_STYLE 可控制写入时的换行符风格。

示例 1:读取文件并转换换行符(默认 UNIX 风格)

file(STRING "${CMAKE_CURRENT_SOURCE_DIR}/version.txt" VERSION_STR)
message(STATUS "Version: ${VERSION_STR}")
  • 若 version.txt 内容为 1.0.0\r\n(Windows 换行),读取后 VERSION_STR 会转换为 1.0.0\n

示例 2:保留原始换行符(KEEP 模式)

file(STRING "${CMAKE_CURRENT_SOURCE_DIR}/log.txt" LOG_CONTENT NEWLINE_STYLE KEEP)
# 适用于需要保留 Windows/macOS 原始换行格式的场景

示例 3:处理文件不存在的情况

file(STRING "non_existent_file.txt" DATA RESULT_VARIABLE RESULT)
if(NOT RESULT EQUAL 0)
    message(WARNING "文件不存在,使用默认值")
    set(DATA "default content")
endif()

file(STRING)与 file(READ)/file(WRITE) 的区别

  • file(STRING) 更适合处理文本文件,自动处理换行符和编码;
  • file(READ)/file(WRITE) 用于二进制文件或原始字节流,不做任何转换。

2.6.WRITE - 写入文件内容

将内容写入文件(覆盖或创建新文件)。

file(WRITE <file> <content> [APPEND])
  • APPEND:追加内容到文件末尾,而非覆盖。

示例代码:

# 写入版本信息到文件
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/version.txt" "Version: ${PROJECT_VERSION}\nBuild Date: ${CMAKE_CURRENT_DATE}")

# 追加日志信息
file(WRITE "build.log" "Compilation started...\n" APPEND)

2.7.GLOB - 按模式匹配文件

根据通配符模式搜索文件路径。

file(GLOB <variable> [RELATIVE <path>] [FOLLOW_SYMLINKS] <globbing_pattern>...)

示例代码:

# 搜索所有 .cpp 文件(递归)
file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/**/*.cpp")

# 相对路径模式
file(GLOB HEADERS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h")

在 CMake 中查找当前目录及其子目录中的所有文件夹的方法有几种。以下是三种常见的方法:

方法一:使用 file(GLOB ...) 命令

cmake_minimum_required(VERSION 3.22.1)
project(MyProject)

# 使用 GLOB 获取所有文件夹
file(GLOB_RECURSE ALL_SUBDIRECTORIES LIST_DIRECTORIES true "*")

# 输出所有文件夹
message("All subdirectories:")
foreach(subdir ${ALL_SUBDIRECTORIES})
    if(IS_DIRECTORY ${subdir})
        message("  ${subdir}")
    endif()
endforeach()
  • GLOB_RECURSE
    • 这是 file 命令的一种模式,用于递归地获取匹配指定通配符模式的文件。
  • ALL_SUBDIRECTORIES
    • 这是一个自定义的变量名,用于存储匹配的文件列表。
  • LIST_DIRECTORIES
    • 这是 file 命令的选项,设置为 true 表示匹配的文件列表中包含目录。
  • true
    • 这是通配符模式,用于匹配所有文件和文件夹。

方法二:使用 file(GLOB ...) 结合 LIST_DIRECTORIES 选项

cmake_minimum_required(VERSION 3.22.1)
project(MyProject)

# 使用 GLOB 获取所有文件夹
file(GLOB ALL_SUBDIRECTORIES LIST_DIRECTORIES true "*")

# 输出所有文件夹
message("All subdirectories:")
foreach(subdir ${ALL_SUBDIRECTORIES})
    message("  ${subdir}")
endforeach()
  • GLOB
    • 这是 file 命令的一种模式,用于获取匹配指定通配符模式的文件。
  • ALL_SUBDIRECTORIES
    • 这是一个自定义的变量名,用于存储匹配的文件列表。
  • LIST_DIRECTORIES
    • 这是 file 命令的选项,设置为 true 表示匹配的文件列表中包含目录。
  • true
    • 这是通配符模式,用于匹配所有文件和文件夹。

方法三:使用 file(GLOB ...) 结合 DIRECTORY 选项

cmake_minimum_required(VERSION 3.22.1)
project(MyProject)

# 使用 GLOB 获取所有文件夹
file(GLOB ALL_SUBDIRECTORIES DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} "*")

# 输出所有文件夹
message("All subdirectories:")
foreach(subdir ${ALL_SUBDIRECTORIES})
    message("  ${subdir}")
endforeach()
  • GLOB
    • 这是 file 命令的一种模式,用于获取匹配指定通配符模式的文件。
  • ALL_SUBDIRECTORIES
    • 这是一个自定义的变量名,用于存储匹配的文件列表。
  • DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    • 这是 file 命令的选项,指定要搜索的目录。${CMAKE_CURRENT_SOURCE_DIR} 是当前源码目录的路径。
  • "\*"
    • 这是通配符模式,用于匹配所有文件和文件夹。

假设当前目录结构如下:

.
├── Subdir1
│   ├── Subsubdir1
│   └── Subsubdir2
├── Subdir2
├── Subdir3
└── CMakeLists.txt

在这个例子中,以上三种方法都会输出所有子目录的路径:

All subdirectories:
  /path/to/your/project/Subdir1
  /path/to/your/project/Subdir1/Subsubdir1
  /path/to/your/project/Subdir1/Subsubdir2
  /path/to/your/project/Subdir2
  /path/to/your/project/Subdir3

这样你就可以根据实际需求使用其中的一种方法来获取当前目录及其子目录中的所有文件夹。

2.8.GET_FILENAME_COMPONENT - 获取文件路径组件

解析文件路径,提取目录、文件名、后缀等组件。

file(GET_FILENAME_COMPONENT <variable> <file> <component> [CACHE])
  • component 可选值
    • PATH:目录路径(去掉文件名)。
    • NAME:文件名(包含后缀)。
    • NAME_WE:文件名(不含后缀)。
    • EXT:文件后缀(带 .)。
    • ABSOLUTE:绝对路径。

示例代码:

set(SOURCE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp")
file(GET_FILENAME_COMPONENT(SOURCE_DIR ${SOURCE_FILE} PATH)       # SOURCE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}/src
file(GET_FILENAME_COMPONENT(SOURCE_NAME ${SOURCE_FILE} NAME)     # SOURCE_NAME = main.cpp
file(GET_FILENAME_COMPONENT(SOURCE_NAME_WE ${SOURCE_FILE} NAME_WE) # SOURCE_NAME_WE = main

2.9.TOUCH - 更新文件时间戳或创建空文件

创建空文件或更新现有文件的时间戳。

file(TOUCH <file>...)

示例代码:

# 创建空的编译标记文件
file(TOUCH "${CMAKE_CURRENT_BINARY_DIR}/compiled.success")

2.10.MD5/SHA1/SHA256 - 计算文件哈希值

计算文件的哈希值(用于校验文件完整性)。

file(MD5 <file> <variable>)
file(SHA1 <file> <variable>)
file(SHA256 <file> <variable>)

示例代码:

file(SHA256 "${CMAKE_CURRENT_SOURCE_DIR}/data.zip" DATA_HASH)
message("SHA256 of data.zip: ${DATA_HASH}")

2.11.GET_RUNTIME_DEPENDENCIES - 获取运行时依赖

用于自动收集可执行文件或共享库的运行时依赖(如动态链接库 .dll/.so/.dylib)。这在打包应用程序、部署到其他环境时非常有用。

file(GET_RUNTIME_DEPENDENCIES
    [EXECUTABLES <exe1> <exe2> ...]  # 可执行文件列表
    [LIBRARIES <lib1> <lib2> ...]    # 库文件列表
    [RESOLVED_DEPENDENCIES_VAR <resolved_var>]  # 已解析的依赖
    [UNRESOLVED_DEPENDENCIES_VAR <unresolved_var>]  # 未解析的依赖
    [DIRECTORIES <dir1> <dir2> ...]  # 额外搜索路径
    [PRE_EXECUTE]  # 预执行模式(在文件实际生成前运行)
    [POST_EXECUTE]  # 后执行模式(在文件生成后运行,默认)
)
  1. 输入参数

    • EXECUTABLES/LIBRARIES:指定要分析的目标文件(可执行文件或库)。
    • DIRECTORIES:指定额外的搜索路径(如第三方库目录)。
  2. 输出参数

    • RESOLVED_DEPENDENCIES_VAR:存储已成功解析的依赖路径。
    • UNRESOLVED_DEPENDENCIES_VAR:存储无法解析的依赖(需手动处理)。
  3. 执行模式

    • PRE_EXECUTE:在文件实际生成前分析依赖(适用于生成过程中需要依赖的场景)。
    • POST_EXECUTE:在文件生成后分析(默认,更常用)。

典型应用场景

场景 1:收集应用程序的所有依赖库

# 分析可执行文件的依赖
file(GET_RUNTIME_DEPENDENCIES
    EXECUTABLES "${CMAKE_CURRENT_BINARY_DIR}/my_app"
    RESOLVED_DEPENDENCIES_VAR _resolved_deps
    UNRESOLVED_DEPENDENCIES_VAR _unresolved_deps
    DIRECTORIES "${QT_LIB_DIR}"  # 额外搜索路径(如 Qt 库目录)
)

# 打印结果
message(STATUS "Resolved dependencies: ${_resolved_deps}")
if(_unresolved_deps)
    message(WARNING "Unresolved dependencies: ${_unresolved_deps}")
endif()

# 将依赖库复制到输出目录
foreach(_dep ${_resolved_deps})
    file(COPY "${_dep}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/bin")
endforeach()

场景 2:在安装阶段收集依赖

# 在安装时执行依赖分析
install(CODE "
    file(GET_RUNTIME_DEPENDENCIES
        EXECUTABLES \"\$<TARGET_FILE:my_app>\"
        RESOLVED_DEPENDENCIES_VAR _r_deps
        UNRESOLVED_DEPENDENCIES_VAR _u_deps
        DIRECTORIES \"${QT_LIB_DIR}\"
    )
    
    # 安装依赖库到指定目录
    foreach(_dep \${_r_deps})
        install(FILES \"\${_dep}\" DESTINATION \"\${CMAKE_INSTALL_PREFIX}/lib\")
    endforeach()
    
    # 处理未解析的依赖
    if(_u_deps)
        message(WARNING \"Unresolved dependencies: \${_u_deps}\")
    endif()
")

场景 3:跨平台处理(Windows/macOS/Linux)

# 通用依赖收集函数
function(copy_runtime_dependencies TARGET)
    set(_output_dir "${CMAKE_CURRENT_BINARY_DIR}/bin")
    
    file(GET_RUNTIME_DEPENDENCIES
        EXECUTABLES "$<TARGET_FILE:${TARGET}>"
        RESOLVED_DEPENDENCIES_VAR _deps
        POST_EXECUTE  # 在目标文件生成后执行
    )
    
    # 复制依赖到输出目录
    foreach(_dep ${_deps})
        # 过滤系统库(可选)
        if(NOT _dep MATCHES "/libc\\.|/libstdc\\+\\+|/libgcc_s|/System/Library")
            file(COPY "${_dep}" DESTINATION "${_output_dir}")
        endif()
    endforeach()
endfunction()

# 使用示例
copy_runtime_dependencies(my_app)

2.12.SIZE - 获取文件大小

file(SIZE) 命令用于获取文件的大小(以字节为单位),这在检查文件是否正确生成、处理二进制资源或执行条件编译时非常有用。

file(SIZE <filename> <variable>)
  • <filename>:目标文件的路径(绝对路径或相对路径)。
  • <variable>:存储文件大小的变量名(若文件不存在,变量将被设为空)。

示例代码:

file(SIZE "${CMAKE_CURRENT_BINARY_DIR}/output.lib" LIB_SIZE)

if(LIB_SIZE GREATER 0)
    message(STATUS "库文件生成成功,大小: ${LIB_SIZE} 字节")
else()
    message(FATAL_ERROR "库文件生成失败或为空")
endif()

2.13.DOWNLOAD - 下载文件

用于从网络下载文件,支持 HTTP、HTTPS、FTP 等协议。这在获取第三方依赖、更新资源文件或集成 CI/CD 流程时非常有用。

file(DOWNLOAD <url> <output_file>
    [INACTIVITY_TIMEOUT <seconds>]  # 无活动超时时间
    [TIMEOUT <seconds>]            # 总超时时间
    [SHOW_PROGRESS]                # 显示下载进度
    [EXPECTED_MD5 <md5>]           # 预期 MD5 校验和
    [EXPECTED_SHA256 <sha256>]     # 预期 SHA256 校验和
    [STATUS <status_var>]          # 存储状态码
    [LOG <log_var>]                # 存储详细日志
    [TLS_VERIFY ON|OFF]            # 启用/禁用 TLS 验证(默认 ON)
    [USERPWD <username>:<password>] # 认证信息
)
  1. 必选参数

    • <url>:文件下载地址(如 https://example.com/file.zip)。
    • <output_file>:保存路径(需包含文件名,如 ./downloads/file.zip)。
  2. 超时控制

    • INACTIVITY_TIMEOUT:连续无数据传输的超时时间(秒)。
    • TIMEOUT:整个下载过程的最大超时时间(秒)。
  3. 校验机制

    • EXPECTED_MD5/EXPECTED_SHA256:验证下载文件的哈希值,不匹配时报错。
  4. 状态反馈

    • STATUS:存储下载状态(格式:[<error_code>, <error_message>])。
    • LOG:存储详细的下载日志(如网络响应信息)。
  5. 高级选项

    • TLS_VERIFY OFF:禁用 HTTPS 证书验证(不推荐,仅用于测试)。
    • USERPWD:用于认证的用户名和密码(格式:user:pass)。

典型应用场景

场景 1:下载第三方库

set(DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/downloads")
set(ZLIB_URL "https://zlib.net/zlib-1.2.13.tar.gz")
set(ZLIB_FILE "${DOWNLOAD_DIR}/zlib-1.2.13.tar.gz")
set(ZLIB_MD5 "4ff941449631ace0d4d203e3483be9")

# 创建下载目录
file(MAKE_DIRECTORY "${DOWNLOAD_DIR}")

# 下载文件并验证 MD5
file(DOWNLOAD "${ZLIB_URL}" "${ZLIB_FILE}"
    EXPECTED_MD5 "${ZLIB_MD5}"
    TIMEOUT 300  # 5 分钟超时
    SHOW_PROGRESS
    STATUS DOWNLOAD_STATUS
    LOG DOWNLOAD_LOG
)

# 检查下载状态
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
list(GET DOWNLOAD_STATUS 1 STATUS_MESSAGE)

if(NOT STATUS_CODE EQUAL 0)
    message(FATAL_ERROR "下载失败: ${STATUS_MESSAGE}\n日志: ${DOWNLOAD_LOG}")
else()
    message(STATUS "Zlib 下载成功,MD5 校验通过")
    # 后续可添加解压和编译逻辑
endif()

场景 2:下载资源文件(带进度显示)

set(RESOURCE_URL "https://assets.example.com/textures.zip")
set(RESOURCE_FILE "${CMAKE_CURRENT_BINARY_DIR}/textures.zip")

file(DOWNLOAD "${RESOURCE_URL}" "${RESOURCE_FILE}"
    TIMEOUT 600  # 10 分钟超时
    SHOW_PROGRESS  # 显示下载进度
    TLS_VERIFY ON  # 启用 HTTPS 验证
)

message(STATUS "资源文件下载完成")

场景 3:条件下载(仅当文件不存在或校验失败时)

set(TOOL_URL "https://tools.example.com/tool.exe")
set(TOOL_FILE "${CMAKE_BINARY_DIR}/bin/tool.exe")
set(TOOL_SHA256 "1234567890abcdef...")  # 实际 SHA256 值

# 检查文件是否存在且校验和匹配
if(NOT EXISTS "${TOOL_FILE}" OR NOT "${TOOL_FILE}" IS_NEWER_THAN "${CMAKE_BINARY_DIR}/.tool_downloaded")
    message(STATUS "下载工具: ${TOOL_URL}")
    
    file(DOWNLOAD "${TOOL_URL}" "${TOOL_FILE}"
        EXPECTED_SHA256 "${TOOL_SHA256}"
        STATUS DOWNLOAD_STATUS
    )
    
    list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
    if(NOT STATUS_CODE EQUAL 0)
        message(FATAL_ERROR "工具下载失败")
    endif()
    
    # 创建标记文件,记录下载时间
    file(WRITE "${CMAKE_BINARY_DIR}/.tool_downloaded" "Downloaded at ${CMAKE_CURRENT_DATE}")
else()
    message(STATUS "工具已存在,跳过下载")
endif()

2.14.UPLOAD - 上传文件

用于将本地文件上传到远程服务器,支持 HTTP 和 HTTPS 协议。这在自动化部署、测试报告上传或持续集成流程中非常有用。

file(UPLOAD <input_file> <url>
    [INACTIVITY_TIMEOUT <seconds>]  # 无活动超时时间
    [TIMEOUT <seconds>]            # 总超时时间
    [HTTPHEADER <header_name> <header_value> ...]  # HTTP 请求头
    [STATUS <status_var>]          # 存储状态码
    [LOG <log_var>]                # 存储详细日志
    [TLS_VERIFY ON|OFF]            # 启用/禁用 TLS 验证(默认 ON)
    [USERPWD <username>:<password>] # 认证信息
)
  1. 必选参数

    • <input_file>:本地要上传的文件路径(如 ./build/report.txt)。
    • <url>:远程服务器接收地址(如 https://api.example.com/upload)。
  2. 超时控制

    • INACTIVITY_TIMEOUT:连续无数据传输的超时时间(秒)。
    • TIMEOUT:整个上传过程的最大超时时间(秒)。
  3. HTTP 头设置

    • HTTPHEADER:添加自定义 HTTP 请求头(如 Content-TypeAuthorization)。
  4. 状态反馈

    • STATUS:存储上传状态(格式:[<http_code>, <error_message>])。
    • LOG:存储详细的上传日志(如服务器响应信息)。
  5. 高级选项

    • TLS_VERIFY OFF:禁用 HTTPS 证书验证(不推荐,仅用于测试)。
    • USERPWD:用于认证的用户名和密码(格式:user:pass)。

典型应用场景

场景 1:上传测试报告到服务器

set(REPORT_FILE "${CMAKE_BINARY_DIR}/test_report.xml")
set(UPLOAD_URL "https://ci.example.com/upload/report")
set(AUTH_TOKEN "your_api_token")

file(UPLOAD "${REPORT_FILE}" "${UPLOAD_URL}"
    HTTPHEADER "Authorization" "Bearer ${AUTH_TOKEN}"
    HTTPHEADER "Content-Type" "application/xml"
    TIMEOUT 300  # 5 分钟超时
    STATUS UPLOAD_STATUS
    LOG UPLOAD_LOG
)

# 检查上传状态
list(GET UPLOAD_STATUS 0 HTTP_CODE)
list(GET UPLOAD_STATUS 1 ERROR_MSG)

if(NOT HTTP_CODE EQUAL 200)
    message(FATAL_ERROR "上传失败 (HTTP ${HTTP_CODE}): ${ERROR_MSG}\n日志: ${UPLOAD_LOG}")
else()
    message(STATUS "测试报告上传成功")
endif()

场景 2:上传构建产物到远程存储

set(BUILD_ARTIFACT "${CMAKE_BINARY_DIR}/release/my_app_v1.0.0.zip")
set(STORAGE_URL "https://storage.example.com/releases/")
set(CREDENTIALS "deploy_user:${DEPLOY_PASSWORD}")  # 从环境变量获取密码

file(UPLOAD "${BUILD_ARTIFACT}" "${STORAGE_URL}"
    USERPWD "${CREDENTIALS}"
    TIMEOUT 1800  # 30 分钟超时(大文件)
    SHOW_PROGRESS  # 显示上传进度(CMake 3.24+ 支持)
    STATUS UPLOAD_STATUS
)

list(GET UPLOAD_STATUS 0 HTTP_CODE)
if(NOT HTTP_CODE EQUAL 201)  # 201 Created 表示上传成功
    message(FATAL_ERROR "构建产物上传失败: ${UPLOAD_STATUS}")
else()
    message(STATUS "构建产物上传成功")
endif()

场景 3:条件上传(仅发布版本)

if(CMAKE_BUILD_TYPE STREQUAL "Release")
    set(PACKAGE_FILE "${CMAKE_BINARY_DIR}/dist/package.tar.gz")
    set(UPLOAD_URL "https://releases.example.com/${PROJECT_NAME}/")
    
    file(UPLOAD "${PACKAGE_FILE}" "${UPLOAD_URL}"
        HTTPHEADER "X-Release-Version" "${PROJECT_VERSION}"
        TIMEOUT 600
        STATUS UPLOAD_STATUS
    )
    
    list(GET UPLOAD_STATUS 0 HTTP_CODE)
    if(HTTP_CODE EQUAL 200)
        message(STATUS "发布版本 ${PROJECT_VERSION} 已上传")
    else()
        message(WARNING "发布上传失败,HTTP 状态码: ${HTTP_CODE}")
    endif()
else()
    message(STATUS "跳过上传(非发布版本)")
endif()

2.15.归档压缩

file(ARCHIVE_CREATE) 和 file(ARCHIVE_EXTRACT) 命令分别用于创建归档文件(压缩)和解压归档文件,支持 ZIP、TGZ(tar.gz)、TBZ2(tar.bz2)等格式。

1.创建归档文件(file(ARCHIVE_CREATE)

file(ARCHIVE_CREATE
    OUTPUT <output_file>       # 输出归档文件路径
    PATHS <path1> <path2> ...  # 要归档的文件或目录
    [FORMAT <format>]          # 归档格式(zip、tar、tar.gz 等)
    [COMPRESSION_LEVEL <0-9>]  # 压缩级别(0=无压缩,9=最高压缩)
    [EXCLUDE_PATTERNS <pattern> ...]  # 排除匹配的文件/目录
    [PRESET <preset>]          # 预设选项(如 "deflate" 用于 ZIP)
)

示例代码:创建 ZIP 归档

# 将 build/bin 目录下的所有文件打包为 release.zip
file(ARCHIVE_CREATE
    OUTPUT "${CMAKE_BINARY_DIR}/release.zip"
    PATHS "${CMAKE_BINARY_DIR}/bin/"
    FORMAT zip
    COMPRESSION_LEVEL 9  # 最高压缩比
    EXCLUDE_PATTERNS "*.log" "debug/*"  # 排除日志文件和 debug 目录
)

2.解压归档文件(file(ARCHIVE_EXTRACT)

file(ARCHIVE_EXTRACT
    INPUT <archive_file>       # 要解压的归档文件
    DESTINATION <destination>  # 解压目标目录
    [PATTERNS <pattern> ...]   # 只提取匹配的文件/目录
    [EXCLUDE_PATTERNS <pattern> ...]  # 排除匹配的文件/目录
    [VERBOSE]                  # 显示详细解压过程
)

示例代码:解压第三方依赖

# 解压下载的 Boost 库
set(BOOST_ARCHIVE "${CMAKE_BINARY_DIR}/downloads/boost_1_82_0.tar.gz")
set(BOOST_DIR "${CMAKE_BINARY_DIR}/external/boost")

file(ARCHIVE_EXTRACT
    INPUT "${BOOST_ARCHIVE}"
    DESTINATION "${BOOST_DIR}"
    # 只提取需要的组件,减少解压时间
    PATTERNS "boost/algorithm" "boost/container" "boost/LICENSE_1_0.txt"
    VERBOSE
)

3.注意事项

1.路径处理

  • 始终使用绝对路径或 CMake 预定义变量(如 ${CMAKE_CURRENT_SOURCE_DIR}${CMAKE_BINARY_DIR}),避免相对路径歧义。
  • 跨平台路径需使用正斜杠(/),CMake 会自动适配操作系统。

2.权限问题

  • 删除或修改系统文件时需谨慎,建议在构建目录内操作。
  • 使用 FORCE 参数时需注意可能绕过权限检查,导致不可预期的后果。

3.缓存影响

  • 某些命令(如 GLOB)的结果不会自动更新,若文件结构变化,需手动清理缓存或重启 CMake 生成。

4.跨平台兼容性

  • 部分命令(如符号链接操作)在不同系统上行为可能不同,需通过 IF(WIN32) 等条件语句适配。

4.总结

  • 资源管理:复制配置文件、静态资源到输出目录。
  • 构建清理:删除临时文件或旧版本构建产物。
  • 动态生成文件:根据项目配置生成头文件或脚本。
  • 依赖跟踪:通过哈希值校验第三方库文件完整性。
  • 目录结构初始化:自动创建输出目录或缓存路径。

合理使用 file 命令可以简化项目的文件管理流程,提升 CMake 脚本的自动化能力。

相关链接


网站公告

今日签到

点亮在社区的每一天
去签到