简述电子商务网站建设的主要步骤,做网站投资多少钱,龙海市城乡规划建设局网站,本地企业网站建设目录
1.include
1.1.简介
1.2.核心作用
1.3.工作流程
1.4.常见使用场景
1.5.与 add_subdirectory 的区别
1.6.注意事项
2.include_guard
2.1.简介
2.2.核心作用
2.3.工作原理
2.4.常见使用场景
2.5.include_guard() 优势
2.6.注意事项
3.include_directories
3…目录
1.include
1.1.简介
1.2.核心作用
1.3.工作流程
1.4.常见使用场景
1.5.与 add_subdirectory 的区别
1.6.注意事项
2.include_guard
2.1.简介
2.2.核心作用
2.3.工作原理
2.4.常见使用场景
2.5.include_guard() 优势
2.6.注意事项
3.include_directories
3.1.简介
3.2.常见使用场景
3.3.注意事项
4.target_include_directories
4.1.简介
4.2.核心作用
4.3.常见使用场景
4.4.与其他命令的对比
4.5.注意事项
5.总结
相关链接 1.include
1.1.简介 在 CMake 中include() 是一个用于导入外部 CMake 脚本或模块的命令类似于编程语言中的 import 或 #include。 基本语法
include(file|module [OPTIONAL] [RESULT_VARIABLE var] [NO_POLICY_SCOPE])
file|module要导入的文件路径或模块名。 若为文件路径如 cmake/Utils.cmake直接加载该文件。若为模块名如 FetchContent在 CMake 模块路径中查找并加载。 OPTIONAL可选参数若文件不存在则忽略错误。RESULT_VARIABLE var将加载结果存储到变量中成功为 TRUE失败为 FALSE。NO_POLICY_SCOPE不创建新的策略作用域CMake 3.20。 如果include的是模块名该命令会依次将 CAMAKE_MODULE_PATH 列表变量中的路径作为父目录来搜索CMake模块若任未能搜索到则从CMake预置模块目录搜索指定的CMake模块。 引用的外部程序与该命令所在的调用上下文共享相同的作用域也就是说引用的程序内创建的变量在include命令之后仍然存在。
1.2.核心作用
模块化 CMake 代码将通用逻辑如工具链配置、依赖管理封装到独立文件中避免重复代码。导入标准模块加载 CMake 内置模块如 ExternalProject、CPack扩展功能。跨平台工具链通过导入工具链文件如 arm-gcc-toolchain.cmake支持交叉编译。
1.3.工作流程
1.路径搜索
若参数是绝对路径如 /path/to/script.cmake直接加载该文件。若为相对路径如 cmake/Utils.cmake在当前目录及其父目录中查找。若为模块名如 FindOpenCV在 CMAKE_MODULE_PATH 中查找通常位于 $CMAKE_ROOT/Modules。
2.脚本执行
被导入的脚本在当前 CMake 作用域中执行定义的变量、函数、宏等直接生效。若使用 NO_POLICY_SCOPE则不创建新的策略作用域避免策略版本冲突。
3.变量继承
导入脚本可访问当前作用域的变量也可通过 set(... PARENT_SCOPE) 修改父作用域变量。
1.4.常见使用场景
1.导入自定义 CMake 脚本
项目结构
project/
├─ CMakeLists.txt
└─ cmake/└─ Utils.cmake # 自定义工具函数
Utils.cmake
# 定义通用函数
# Turn on warnings on the given target
function(enable_warnings target)if(SPDLOG_BUILD_WARNINGS)if(CMAKE_CXX_COMPILER_ID STREQUAL MSVC)list(APPEND MSVC_OPTIONS /W3)if(MSVC_VERSION GREATER 1900) # Allow non fatal security warnings for msvc 2015list(APPEND MSVC_OPTIONS /WX)endif()endif()target_compile_options(${target_name}PRIVATE $$OR:$CXX_COMPILER_ID:Clang,$CXX_COMPILER_ID:AppleClang,$CXX_COMPILER_ID:GNU:-Wall-Wextra-Wconversion-pedantic-Werror-Wfatal-errors$$CXX_COMPILER_ID:MSVC:${MSVC_OPTIONS})endif()
endfunction()
CMakeLists.txt
# 导入自定义脚本
include(cmake/Utils.cmake)# 使用脚本中定义的函数
add_executable(my_app src/main.cpp)
enable_warnings(my_app) # 应用警告选项
2.导入 CMake 标准模块
# 导入 FetchContent 模块用于依赖管理
include(FetchContent)# 使用模块功能
FetchContent_Declare(fmtGIT_REPOSITORY https://github.com/fmtlib/fmt.gitGIT_TAG 10.1.1
)
FetchContent_MakeAvailable(fmt)# 链接依赖
target_link_libraries(my_app PRIVATE fmt::fmt)
3.导入工具链文件交叉编译
# 项目根目录 CMakeLists.txt
if(CROSS_COMPILE)include(cmake/arm-gcc-toolchain.cmake) # 导入工具链
endif()
arm-gcc-toolchain.cmake
# 配置交叉编译工具链
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g)
1.5.与 add_subdirectory 的区别
特性include()add_subdirectory()作用域共享当前作用域创建新的子作用域文件类型纯 CMake 脚本完整的子项目构建目标不生成目标可定义目标如 add_library典型场景导入工具函数、模块管理子项目、源代码目录
1.6.注意事项
1.脚本组织
将通用逻辑封装到 cmake/ 目录下的脚本中
project/
├─ CMakeLists.txt
└─ cmake/├─ CompilerOptions.cmake # 编译选项├─ CodeCoverage.cmake # 代码覆盖率└─ FindMyLib.cmake # 自定义 Find 模块
2.模块导入
使用 list(APPEND CMAKE_MODULE_PATH ...) 添加自定义模块路径
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
include(FindMyLib) # 从 cmake/ 目录加载自定义模块
3.条件导入
根据平台或选项选择性导入脚本
if(WIN32)include(cmake/WindowsUtils.cmake)
else()include(cmake/UnixUtils.cmake)
endif()
4.变量作用域
导入脚本中的变量默认在当前作用域生效可能覆盖已有变量。建议使用函数封装逻辑避免全局变量污染
# 推荐写法
function(my_function arg)# 函数内的变量是局部的set(result ${arg}_processed PARENT_SCOPE)
endfunction()
5.循环导入
避免脚本之间的循环导入如 A.cmake 导入 B.cmake而 B.cmake 又导入 A.cmake会导致无限递归。
6.模块版本兼容性
某些模块如 CPack依赖 CMake 版本需确保版本兼容
cmake_minimum_required(VERSION 3.16) # 确保支持 FetchContent
include(FetchContent)
2.include_guard
2.1.简介 include_guard() 是 CMake 3.10 引入的一个命令用于防止 CMake 脚本被重复包含类似于 C/C 头文件中的 #pragma once 或头文件保护宏#ifndef ... #define ... #endif。 基本语法
include_guard([GLOBAL|DIRECTORY])
GLOBAL在全局范围内检查重复包含默认行为。DIRECTORY仅在当前目录及其子目录的 CMake 脚本中检查重复包含。
2.2.核心作用
防止重复定义避免在多次包含同一脚本时重复定义函数、宏或设置变量。提高性能减少不必要的脚本执行加速 CMake 配置过程。避免循环依赖防止脚本间的循环包含如 A.cmake 包含 B.cmake而 B.cmake 又包含 A.cmake。
2.3.工作原理
1.唯一标识符生成
include_guard() 会根据当前脚本的绝对路径生成一个唯一标识符如 CMAKE_INCLUDE_GUARD_/path/to/script.cmake。该标识符存储在 CMake 的缓存变量中CMAKE_INCLUDE_GUARD_*。
2.重复检查
每次执行 include_guard() 时检查该标识符是否已存在。若存在则立即返回跳过脚本剩余部分否则继续执行并标记为已包含。
3.作用域选项
GLOBAL在整个 CMake 项目中检查重复默认。DIRECTORY仅在当前目录及其子目录的 CMake 脚本中检查重复适用于模块化项目。
2.4.常见使用场景
1.通用工具函数脚本
cmake/Utils.cmake
include_guard() # 防止重复包含# 定义函数
function(enable_warnings target)target_compile_options(${target} PRIVATE-Wall -Wextra -Wpedantic)
endfunction()# 定义宏
macro(add_example name)add_executable(${name} examples/${name}.cpp)target_link_libraries(${name} PRIVATE my_lib)
endmacro()
CMakeLists.txt
# 多次包含同一脚本实际项目中可能因条件分支导致
if(DEBUG)include(cmake/Utils.cmake)
endif()# 其他条件也可能包含
if(BUILD_TESTS)include(cmake/Utils.cmake) # 第二次包含被 include_guard 阻止
endif()# 正常包含仅执行一次
include(cmake/Utils.cmake)# 使用脚本中定义的函数
add_executable(my_app src/main.cpp)
enable_warnings(my_app)
2.第三方依赖模块
cmake/FindMyLib.cmake
include_guard()# 查找库
find_library(MYLIB_LIBRARY NAMES mylib)
find_path(MYLIB_INCLUDE_DIR NAMES mylib.h)# 设置结果
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MyLib DEFAULT_MSGMYLIB_LIBRARY MYLIB_INCLUDE_DIR
)
2.5.include_guard() 优势
自动生成标识符无需手动命名变量避免命名冲突。简洁只需一行代码提高可读性。兼容性在 CMake 3.10 版本中稳定支持。
2.6.注意事项
1.在所有共享脚本中使用
所有被多个地方包含的脚本如工具函数、Find 模块都应添加 include_guard()。
2.放在脚本顶部
确保 include_guard() 是脚本中的第一个命令避免在检查前执行不必要的代码。
# 正确位置
include_guard()# 脚本内容
function(my_function)# ...
endfunction()
3.选择合适的作用域
默认 GLOBAL适用于全局工具函数或依赖模块。DIRECTORY适用于特定目录下的模块化脚本避免与其他目录的脚本冲突。
4.版本兼容性
include_guard() 仅在 CMake 3.10 版本中可用。若需兼容旧版本需手动实现保护逻辑。
5.条件包含
若脚本中的部分内容需要在每次包含时执行如更新变量需将这些内容放在 include_guard() 之后但可能导致重复定义需谨慎处理。
3.include_directories
3.1.简介 include_directories 是 CMake 中用于指定头文件搜索路径的命令允许编译器在编译时找到项目依赖的头文件。 基本语法
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
FTER|BEFORE指定路径添加到搜索列表的位置默认 AFTER。SYSTEM将目录标记为系统目录减少编译警告。dir1 [dir2 ...]要添加的头文件搜索路径相对路径或绝对路径。
3.2.常见使用场景
1.简单项目
# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyApp)# 添加项目头文件目录
include_directories(include)# 添加源文件
add_executable(my_app src/main.cpp)
2. 多目录项目
# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyApp)# 添加多个头文件目录
include_directories(includesrc/coresrc/gui
)# 添加源文件
add_executable(my_app src/main.cpp)
3.外部依赖
# 查找并链接 OpenCV
find_package(OpenCV REQUIRED)# 添加 OpenCV 头文件目录通常由 find_package 设置
include_directories(${OpenCV_INCLUDE_DIRS})# 链接 OpenCV 库
target_link_libraries(my_app ${OpenCV_LIBS})
3.3.注意事项
1.全局作用域
include_directories 设置的路径对当前 CMakeLists.txt 及所有子目录有效。替代方案使用 target_include_directories 为特定目标设置路径
target_include_directories(my_app PRIVATE include)
2.相对路径与绝对路径
相对路径基于当前 CMakeLists.txt 的位置。建议使用绝对路径如 ${CMAKE_SOURCE_DIR}/include提高可移植性。
3.路径顺序
多个目录按添加顺序搜索先找到的头文件优先使用。使用 BEFORE/AFTER 控制路径优先级
include_directories(BEFORE src/override) # 优先搜索
4.优先使用 target_include_directories
提高代码隔离性避免不同目标的路径冲突。支持 PRIVATE/PUBLIC/INTERFACE 作用域控制。
5.区分项目内与第三方路径
# 项目内头文件
target_include_directories(my_app PRIVATE include)# 第三方库头文件标记为 SYSTEM 减少警告
target_include_directories(my_app SYSTEM PRIVATE third_party/include)
4.target_include_directories
4.1.简介 target_include_directories 是 CMake 中用于精确控制目标如可执行文件、库头文件搜索路径的命令相比全局的 include_directories它提供了更细粒度的作用域控制。 基本语法
target_include_directories(target # 目标名称如 add_executable 或 add_library 创建的[SYSTEM] # 将目录标记为系统目录减少编译警告[BEFORE] # 优先搜索这些目录而非追加到末尾INTERFACE|PUBLIC|PRIVATE # 作用域[items1...][INTERFACE|PUBLIC|PRIVATE [items2...]] ...
)
作用域选项 PRIVATE仅目标自身使用这些路径。PUBLIC目标和依赖该目标的其他目标都使用这些路径。INTERFACE仅依赖该目标的其他目标使用这些路径目标自身不使用。
4.2.核心作用
1.模块化头文件路径
为特定目标设置头文件搜索路径避免全局污染。例如库 libA 的公开头文件路径对依赖它的项目可见私有头文件仅内部使用。
2.构建依赖传递
通过 PUBLIC/INTERFACE 作用域自动将头文件路径传递给依赖链上的其他目标。例如app → libB → libA若 libB 以 PUBLIC 方式链接 libA则 app 也能找到 libA 的头文件。
3.系统目录标记
使用 SYSTEM 标记第三方库目录减少编译器警告如 -isystem 选项。
4.3.常见使用场景
1.库项目的公开 / 私有头文件
项目结构
mylib/
├─ include/ # 公开头文件供外部使用
│ └─ mylib/api.h
├─ src/ # 源代码和私有头文件
│ ├─ impl.cpp
│ └─ detail/impl.h # 私有头文件不暴露给外部
└─ CMakeLists.txt
CMakeLists.txt
add_library(mylib STATIC src/impl.cpp)# 公开头文件路径供依赖 mylib 的目标使用
target_include_directories(mylibPUBLIC$BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include # 构建时$INSTALL_INTERFACE:include # 安装后
)# 私有头文件路径仅 mylib 自身使用
target_include_directories(mylibPRIVATE${CMAKE_CURRENT_SOURCE_DIR}/src
)
2.第三方依赖的系统目录标记
add_executable(my_app src/main.cpp)# 将 fmt 库的头文件标记为系统目录减少警告
target_include_directories(my_appSYSTEM PRIVATE${FMT_INCLUDE_DIRS}
)
3.传递性依赖多级项目
# libA 项目
add_library(libA STATIC src/libA.cpp)
target_include_directories(libAPUBLIC${CMAKE_CURRENT_SOURCE_DIR}/include # 公开头文件
)# libB 项目依赖 libA
add_library(libB STATIC src/libB.cpp)
target_link_libraries(libB PUBLIC libA) # PUBLIC 确保 libA 的头文件路径传递给依赖 libB 的目标# app 项目依赖 libB
add_executable(app src/main.cpp)
target_link_libraries(app PRIVATE libB) # app 自动获得 libA 的头文件路径
4.4.与其他命令的对比
命令作用域目标针对性传递性推荐场景include_directories全局否否简单项目、临时测试target_include_directories目标级是是模块化项目、库开发set_target_properties目标级是否特殊属性如 CXX_STANDARD
4.5.注意事项
1.分离公开 / 私有头文件
库项目中将公开 API 放在 include/ 目录私有实现放在 src/ 目录。使用 PUBLIC 暴露公开头文件PRIVATE 隐藏私有头文件。
2.使用生成器表达式Generator Expressions
处理构建时与安装后的路径差异
target_include_directories(mylibPUBLIC$BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include # 构建时$INSTALL_INTERFACE:include # 安装后
)
3.避免重复路径
同一目标的相同路径只需设置一次PUBLIC 已包含 PRIVATE 的效果。
4.路径顺序
多个 PRIVATE/PUBLIC/INTERFACE 块按添加顺序处理先添加的路径优先级更高。使用 BEFORE 参数可将路径插入到搜索列表的前面
target_include_directories(my_appBEFORE PRIVATE${CMAKE_CURRENT_SOURCE_DIR}/override # 优先搜索此目录
)
5.目标必须先存在
target_include_directories 必须在目标如 add_executable创建后调用。
5.总结
命令核心功能作用域使用场景include(file)导入并执行外部 CMake 脚本或模块全局模块化 CMake 代码、导入工具函数include_guard()防止 CMake 脚本被重复包含文件级所有共享脚本的顶部include_directories(...)设置全局头文件搜索路径全局简单项目、快速原型开发target_include_directories()为特定目标设置头文件搜索路径支持传递性依赖目标级库开发、模块化项目
相关链接
CMake 官网 CMake - Upgrade Your Software Build SystemCMake 官方文档CMake Tutorial — CMake 4.0.2 DocumentationCMake 源码https://github.com/Kitware/CMakeCMake 源码CMake · GitLab中文版基础介绍: CMake 入门实战 | HaHackwiki: Home · Wiki · CMake / Community · GitLab