现代cmake--阅读笔记2

简介: 现代cmake--阅读笔记2

6. cmake编程


6.1. 控制流

if(variable)
    # If variable is `ON`, `YES`, `TRUE`, `Y`, or non zero number
else()
    # If variable is `0`, `OFF`, `NO`, `FALSE`, `N`, `IGNORE`, `NOTFOUND`, `""`, or ends in `-NOTFOUND`
endif()
# If variable does not expand to one of the above, CMake will expand it then try again


There are a variety of keywords as well, such as:


  • Unary: NOT, TARGET, EXISTS (file), DEFINED, etc.


  • Binary: STREQUAL, AND, OR, MATCHES (regular expression), VERSION_LESS, VERSION_LESS_EQUAL (CMake 3.7+), etc.


  • Parentheses can be used to group


generator-expressions

target_compile_options(MyTarget PRIVATE "$<$<CONFIG:Debug>:--my-flag>")

当使用debug编译时,加上–my-flag编译选项


That last one is very common. You'll see something like this in almost every package that supports installing:

target_include_directories(
    MyTarget
  PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)

6.2. 宏和函数


function(SIMPLE REQUIRED_ARG)
    message(STATUS "Simple arguments: ${REQUIRED_ARG}, followed by ${ARGN}")
    set(${REQUIRED_ARG} "From SIMPLE" PARENT_SCOPE)
endfunction()
simple(This Foo Bar)
message("Output: ${This}")

The output would be:


7. cmake交互


7.1. 配置文件


Version.h.in

#pragma once
#define MY_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define MY_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define MY_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define MY_VERSION_TWEAK @PROJECT_VERSION_TWEAK@
#define MY_VERSION "@PROJECT_VERSION@"
configure_file (
    "${PROJECT_SOURCE_DIR}/include/My/Version.h.in"
    "${PROJECT_BINARY_DIR}/include/My/Version.h"

7.2. 读取文件


# Assuming the canonical version is listed in a single line
# This would be in several parts if picking up from MAJOR, MINOR, etc.
set(VERSION_REGEX "#define MY_VERSION[ \t]+\"(.+)\"")
# Read in the line containing the version
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/My/Version.hpp"
VERSION_STRING REGEX ${VERSION_REGEX})
# Pick out just the version
string(REGEX REPLACE ${VERSION_REGEX} "\\1" VERSION_STRING "${VERSION_STRING}")
# Automatically getting PROJECT_VERSION_MAJOR, My_VERSION_MAJOR, etc.
project(My LANGUAGES CXX VERSION ${VERSION_STRING})

8. 如何组织工程


- project
- .gitignore
- README.md
- LICENCE.md
- CMakeLists.txt
- cmake
- FindSomeLib.cmake
- something_else.cmake
- include
- project
- lib.hpp
- src
- CMakeLists.txt
- lib.cpp
- apps
- CMakeLists.txt
- app.cpp
- tests
- CMakeLists.txt
- testlib.cpp
- docs
- CMakeLists.txt
- extern
- googletest
- scripts
- helper.py

将cmake/目录加入到工程中.

set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})

9. 运行其他程序


9.1. 在配置时运行命令

find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_SUBMOD_RESULT)
if(NOT GIT_SUBMOD_RESULT EQUAL "0")
message(FATAL_ERROR "git submodule update --init --recursive failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
endif()
endif()

9.2. 在编译时运行命令

find_package(PythonInterp REQUIRED)
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include/Generated.hpp"
COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/GenerateHeader.py" --argument
DEPENDS some_target)
add_custom_target(generate_header ALL
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/include/Generated.hpp")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/Generated.hpp DESTINATION  include)



10. 一个简单示例


# Almost all CMake files should start with this
# You should always specify a range with the newest
# and oldest tested versions of CMake. This will ensure
# you pick up the best policies.
cmake_minimum_required(VERSION 3.1...3.22)
# This is your project statement. You should always list languages;
# Listing the version is nice here since it sets lots of useful variables
project(
ModernCMakeExample
VERSION 1.0
LANGUAGES CXX)
# If you set any CMAKE_ variables, that can go here.
# (But usually don't do this, except maybe for C++ standard)
# Find packages go here.
# You should usually split this into folders, but this is a simple example
# This is a "default" library, and will match the *** variable setting.
# Other common choices are STATIC, SHARED, and MODULE
# Including header files here helps IDEs but is not required.
# Output libname matches target name, with the usual extensions on your system
add_library(MyLibExample simple_lib.cpp simple_lib.hpp)
# Link each target with other targets or add options, etc.
# Adding something we can run - Output name matches target name
add_executable(MyExample simple_example.cpp)
# Make sure you link your targets with this command. It can also link libraries and
# even flags, so linking a target that does not exist will not give a configure-time error.
target_link_libraries(MyExample PRIVATE MyLibExample)

11. 使用技巧


选择c++标准

set_target_properties(myTarget PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS NO
)

启用pisition independent code

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

集成ccache

find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
set(CMAKE_CUDA_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") # CMake 3.9+
endif()

集成clang-tidy

~/package # cmake -S . -B build-tidy -DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);-fix"

打印变量

message(STATUS "MY_VARIABLE=${MY_VARIABLE}")
include(CMakePrintHelpers)
cmake_print_variables(MY_VARIABLE)
cmake_print_properties(
TARGETS my_target
PROPERTIES POSITION_INDEPENDENT_CODE
)

trace cmake

cmake -S . -B build --trace-source=CMakeLists.txt

debug编译


-DCMAKE_BUILD_TYPE=Debug



12. 测试


add_test(
NAME
ExampleCMakeBuild
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${My_SOURCE_DIR}/examples/simple"
"${CMAKE_CURRENT_BINARY_DIR}/simple"
--build-generator "${CMAKE_GENERATOR}"
--test-command "${CMAKE_CTEST_COMMAND}"
相关文章
|
27天前
|
存储 弹性计算 固态存储
阿里云服务器按量付费与包年包月收费标准,云服务器最新活动价格参考
阿里云的价格一直是用户最为关注的,阿里云这两年也多次做了降价策略,阿里云根据用户的实际需求,针对云服务器收费模式推出按量付费与包年包月两种收费模式,云服务器价格表2025最新版,轻量应用服务器38元一年起,ECS云服务器2核2G3M带宽99元1年、2核4G5M带宽199元一年,新品通用算力型u2i实例4核4G1120.44元/1年起、4核8G1170.26元/1年起,九代云服务器计算型c9i实例8核16G6037.01元/1年起、通用型g9i实例8核32G7551.94元/1年起、内存型r9i实例8核64G9937.12元/1年起。叠加阿里云推出的各种优惠券还可享受满减优惠。
|
4月前
|
缓存 安全 网络安全
0x80070002错误代码怎么解决?
以下是解决Windows系统错误代码0x80070002的多种方法,综合了高可信度来源的解决方案:
|
JSON 小程序 JavaScript
|
API Windows
恶意代码分析入门--初次接触加壳的程序(chapter1_Lab01-02)
实验分析了Lab01-02.exe文件,包括上传至VirusTotal检测、使用PEiD识别壳、FreeUPX脱壳、分析导入函数及字符串。结果显示文件被UPX壳包裹,脱壳后发现其可能通过创建服务和网络连接来实现恶意行为。
243 2
恶意代码分析入门--初次接触加壳的程序(chapter1_Lab01-02)
|
Web App开发 前端开发 安全
前端研发链路之测试
本文由前端徐徐撰写,介绍了前端测试的重要性及其主要类型,包括单元测试、E2E测试、覆盖率测试、安全扫描和自动化测试。文章详细讲解了每种测试的工具和应用场景,并提供了选择合适测试策略的建议,帮助开发者提高代码质量和用户体验。
327 3
前端研发链路之测试
|
监控 安全 数据安全/隐私保护
系统监控软件有哪些
【10月更文挑战第17天】
623 10
|
编解码 安全 Linux
网络空间安全之一个WH的超前沿全栈技术深入学习之路(10-2):保姆级别教会你如何搭建白帽黑客渗透测试系统环境Kali——Liinux-Debian:就怕你学成黑客啦!)作者——LJS
保姆级别教会你如何搭建白帽黑客渗透测试系统环境Kali以及常见的报错及对应解决方案、常用Kali功能简便化以及详解如何具体实现
|
存储 运维 算法
服务器数据恢复—raid6阵列硬盘重组raid5阵列如何恢复raid6阵列数据?
服务器存储数据恢复环境: 存储中有一组由12块硬盘组建的RAID6阵列,上层linux操作系统+EXT3文件系统,该存储划分3个LUN。 服务器存储故障&分析: 存储中RAID6阵列不可用。为了抢救数据,运维人员使用原始RAID中的部分硬盘重新组建RAID并进行了初始化。 初始化开始一段时间后,运维人员察觉到情况有异后强制终止初始化,这个时候初始化已经完成一半以上。数据部分已被不可逆的破坏。
|
人工智能 计算机视觉 C++
AI计算机视觉笔记七:基于mediapipe的虚拟鼠标控制
该项目旨在通过摄像头识别手指动作以实现鼠标控制。利用mediapipe检测手指关键点,并通过食指移动鼠标,当食指与中指距离小于阈值时触发点击事件。环境基于miniconda3,需创建虚拟环境并安装mediapipe、numpy、autopy和opencv等依赖。代码分为`AiVirtualMouse.py`和`HandTrackingModule.py`两个部分,前者用于实现鼠标控制逻辑,后者提供手势检测功能。运行时可能出现`PacketInvoked`错误,需修改`solution_base.py`文件第595行以解决。
|
数据中心
配置案例 | CE交换机如何配置堆叠?
配置案例 | CE交换机如何配置堆叠?
396 2