eew_Eu6WaC

  • 2025-02-28
  • 回复了主题帖: [树莓派Pico 2 RP2350开发板] pwm的学习

    树莓派RP2350和老版本的树莓派PR2040有什么大的区别呢?

  • 回复了主题帖: 【树莓派Pico 2 RP2350开发板】 测评 【一】 开箱 + 编译uf2 固件 + blinkLed

    详细的教程!什么时候树莓派官方这种板子的接口可以换成Tpye-C

  • 2025-02-27
  • 回复了主题帖: 自制 AirTag,支持安卓/鸿蒙/PC/Home Assistant,无需拥有 iPhone

    设备附件使用的苹果设备多,应该信号就好吧,到荒无人烟的地方估计就找不着了

  • 回复了主题帖: 《CMake构建实战》第十章-策略和向后兼容

    Jacktang 发表于 2025-2-27 07:29 渐进式重构 CMake 程序,在用的时候会提示警告,让使用者及时偿还技术债务来更好过度到新版本。 怎么理 ... "及时偿还技术债务"这个概念源自于软件开发领域,是当项目随着时间推移积累了技术上的“债务”。这些“债务”可以是代码质量不高、设计缺陷、未完成的特性或者使用了过时的技术等。如果不加以处理,这些问题可能会导致后续开发效率降低、维护成本增加、出现更多bug等

  • 2025-02-26
  • 回复了主题帖: 《CMake构建实战》- CMake在HarmomyOS中的实际使用

    蛋黄派派主 发表于 2025-2-25 21:50 感谢分享

  • 回复了主题帖: 《CMake构建实战》- CMake在HarmomyOS中的实际使用

    craigtao 发表于 2025-2-25 10:11 不错,CMake现在是主流,不管是纯应用开发还是嵌入式系统开发,cmake都占有一席之地,期待楼主可以多分享一 ... 是的对于嵌入式开发,一般厂家或者IDE那边都会提供对应的模板,对于开发使用有很大的便利

  • 回复了主题帖: 【NUCLEO-WB09KE测评】五、蓝牙数据收发实现

    板子可以接收到APP发送的数据,但为啥发送会失败呢? Fail   : aci_gatt_srv_notify TESTRESPONSE command, error code: 0x C  

  • 2025-02-25
  • 发表了主题帖: 《CMake构建实战》- CMake在HarmomyOS中的实际使用

    本帖最后由 eew_Eu6WaC 于 2025-2-25 09:17 编辑 《CMake构建实战》- CMake在HarmomyOS中的实际使用 本章只注重CMake在HarmonyOS中NDK的应用,NDK其实就是 Napi 的跨语言的调用,就先看看里面是如何使用CMake构建这一部分,有兴趣可以深入讲讲鸿蒙里面跨语言的用法和机制   下面是DevEco Studio中创建的Native C++中CMake相关的代码     可以看到在最顶层有一个CMakeLists.txt文件,这是顶层文件,下面分析一下代码 # the minimum version of CMake. cmake_minimum_required(VERSION 3.5.0) project(NDKDemo) set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) if(DEFINED PACKAGE_FIND_FILE) include(${PACKAGE_FIND_FILE}) endif() include_directories(${NATIVERENDER_ROOT_PATH} ${NATIVERENDER_ROOT_PATH}/include) add_library(entry SHARED napi_init.cpp) add_subdirectory(demo) target_link_libraries(entry PUBLIC libace_napi.z.so calc) cmake_minimum_required 设置了最低版本的要求为3.5.0 project 定义了项目名称为NDKDemo 设置了一个变量:NATIVERENDER_ROOT_PATH,为当前源目录的路径 条件判断,如果定义了PACKAGE_FIND_FILE,就包含这个路径 include_directories 添加到编译器的头文件所搜索路径中去 add_subdirectory 创建了一个共享库entry,是由源码napi_init.cpp编译而成 target_link_libraries  将库libace_napi.z.so和calc链接到目标entry   demo这个文件是自己创建的,在其中也添加了CMakeLists.txt,编译器也会找到这里进行处理,原理非常简单,要将添加的4个文件也一起打包成库以便使用 include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib) add_library(calc SHARED ${SRC_LIST}) include_directories 将当前目录和当前目录下的include包含进去,这样就将head.h添加到了编译器搜索路径中,在head.h中申明了src中所使用到的所有函数 file 可以生成一个源文件列表,在当前目录下的scr目录中下 link_directories 链接可执行文件或库时,链接器会在这个目录下查找所需的库文件 add_library 创建了一个名为calc的共享库,也就是在顶层文件中链接的   编译过后,就可以得到需要的共享库了              

  • 回复了主题帖: 这个新功能蛮不错

    哈哈哈哈哈哈这个英文界面切换功能强的,专业英语可不好翻译的

  • 2025-02-24
  • 发表了主题帖: 《CMake构建实战》第十章-策略和向后兼容

    《CMake构建实战》第十章-策略和向后兼容 CMake非常重视向后兼容性,其中策略机制是解决该问题的关键。它既能确保旧代码在新版本 CMake 中配置生成,又能针对弃用特性给出警告,还会适时清理旧特性,推动自身发展。所以本文会介绍一下相关概念、命令及程序重构方法。   CMake策略(以 CMP0115 为例) CMake 策略名称以 CMP 加四位整数命名,如 CMP0115。每个策略对应新旧两种行为,具体可以查阅官方文档进行了解详情。在官网中会依次列出CMake从新到旧的各个版本进入的策略。比如CMP0115的详情页中可以看到,在CMake 3.19及以前的版本中允许在add_executable等命令中省略源文件扩展名,而新版本则要求必须显式指定。   那么CMake文件是如何发现版本升级了呢?那就要和cmake_minimum_required命令有关了,见下小节。 指定CMake最低版本要求:cmake_minimum_required 这个命令是用于指定运行当前 CMake 程序所需的最低版本,若当前版本低于要求则报错! 这个命令不仅适用于目录程序,在CMake脚本程序、模块程序中都可以调用该命令来设置CMake的最低版本要求。 使用非常的简单:cmake_minimum_required(VERSION <最低版本>)     可以看到上面的程序和运行结果,当我把最小版本的设置改成大于当前安装的版本时,运行就会报错终止。   管理策略行为:cmake_policy cmake_policy命令中有多个子命令,可以分别用于获取和显示指定策略的行为: 按策略名称设置策略行为:cmake_policy(SET <策略名称> NEW|OLD) - 可手动设置指定策略的行为为 NEW 或 OLD,方便在代码重构后或不想看到警告时进行调整。 获取策略行为:cmake_policy(GET <策略名称> <结果变量>) - 用于获取指定策略的行为并存储到结果变量中,若策略未设置,变量为空值,否则为 NEW 或 OLD。 按 CMake 版本设置策略行为:cmake_policy(VERSION <最低版本>[...<策略兼容的最高版本>]) - 依据指定的版本范围设置相关策略行为,cmake_minimum_required命令也支持类似设置。 管理 CMake 策略栈:子目录和模块程序会创建新的策略作用域并加入策略栈,cmake_policy操作的是栈顶策略。cmake_policy(PUSH) 和 cmake_policy(POP) 分别用于策略行为的入栈和出栈,便于程序重构升级时管理策略。sudo apt-get install openssh-client   渐进式重构 CMake 程序 策略可以很好的让CMake兼容古老的代码,同时在使用的时候会提示警告,让使用者及时偿还技术债务来更好过度到新版本。 局部代码重构并启用新行为:对部分代码重构后,借助策略栈实现细粒度的策略行为设置与恢复,若某个子目录重构完成,可直接对该目录采用指定策略的 NEW 行为。 禁用警告信息:将策略行为设为 OLD 可禁用警告,局部设置可通过策略栈完成,适用于暂时不想重构但不想受警告干扰的情况。 同时兼容旧版 CMake:利用if(POLICY)判断策略是否存在,根据 CMake 版本进行不同的项目配置,以兼容新旧版本,重构后可只保留新行为。 为全部策略采用新行为:重构完成后,调整cmake_minimum_required命令的<策略兼容的最高版本>参数,使程序在不同版本下按相应设置运行,同时清理冗余代码。 完全切换到新版 CMake:修改cmake_minimum_required命令的<最低版本>参数,强制用户使用新版 CMake,删除if(POLICY)条件分支,优化代码   好的,CMake相关的基础知识到这里结束,下面会去看下鸿蒙在添加编译NAPI应用的时候如何使用CMake的                                        

  • 回复了主题帖: 《CMake构建实战》第八章-生成器表达式

    Jacktang 发表于 2025-2-22 15:04 虽然是两类表达式,布尔型生成器表达式 和 字符串生成器表达式,细分也不少 是的呢要掌握的东西确实不少,先大致了解用的时候查漏补缺就快啦

  • 2025-02-22
  • 回复了主题帖: 【Raspberry Pi 5测评】树莓派5学习笔记08(部署YOLOv5进行目标检测)

    树莓派还是挺好用的,YOLOv5模型的识别的准确度咋样呢?

  • 回复了主题帖: 【正点原子i.MX93开发板】测评 + 二、环境搭建 + 开发板连接上位机

    正点原子的这块板子对应的教程和资料丰富吗?

  • 发表了主题帖: 《CMake构建实战》第九章-模块

    《CMake构建实战》第九章-模块 这一章围绕CMake模块展开,介绍了其功能模块、查找模块的使用方法、自定义查找模块的编写步骤。并且有着大量案例,对每个用法展示运行效果。   引用功能模块 CMake 模块程序是代码复用单元,像类库一样被引用。其预置模块丰富,位于安装目录的share/…/Modules子目录,可通过include命令引用。   常用的预置功能模块 1. 调试模块:CMakePrintHelpers 的 cmake_print_properties 和 cmake_print_variables 命令分别用于输出属性和变量值。 cmake_minimum_required(VERSION 3.20) project(print-system-info) include(CMakePrintSystemInformation) cmake_minimum_required(VERSION 3.20) project(print-helpers VERSION 1.0) include(CMakePrintHelpers) cmake_print_properties(DIRECTORIES . PROPERTIES BINARY_DIR SOURCE_DIR )   2. 环境检查模块:有多个检查功能的模块,CheckSourceCompiles用于检查源程序能否编译、CheckSymbolExists用于检查符号是否存在,CheckStructHasMember 用于检查结构体/类是否存在指定的成员变量 cmake_minimum_required(VERSION 3.20) project(check-source-compiles) include(CheckSourceCompiles) check_source_compiles(C "int main() { return 0; }" res) message("${res}") # 输出:1 set(CMAKE_REQUIRED_QUIET True) check_source_compiles(C "invalid code" res2) message("${res2}") # 输出空值   cmake_minimum_required(VERSION 3.20) project(check-symbol-exists) include(CheckSymbolExists) check_symbol_exists(printf "stdio.h" res) message("${res}") # 输出:1   cmake_minimum_required(VERSION 3.20) project(check-struct-member) include(CheckStructHasMember) check_struct_has_member("std::pair<int,int>" "first" "utility" res LANGUAGE CXX)   3. 生成导出头文件模块:GenerateExportHeader模块用于生成导出头文件,定义多种宏,用于解决库开发中接口头文件编写的复杂问题 痛点: 各个编译器对导出接口所需的属性不同,隐藏符号的编译选项也不同;另外,有时需要更灵活地配置接⼝,使其能够同时⽤于静态库和动态库;⼜或者需要通过⼀些宏来标记某些过时的接⼝为弃⽤状态…… 通常会编写⼀个头⽂件,⽤宏来判断不同的编译器,再定义⼀些宏来对应不同的属性设置等,以此将不同编译器的差异隐藏起来。每次开发⼀个库时,恐怕都会这样“重复造轮⼦”。 解决: CMake提供了GenerateExportHeader模块。 //CMakeLists.txt cmake_minimum_required(VERSION 3.20) project(export-api) include(GenerateExportHeader) add_library(print SHARED print.c) generate_export_header(print # DEFINE_NO_DEPRECATED # 取消注释以定义忽略弃用接口宏 ) # 导出头文件会被生成到二进制目录中 # 将当前二进制目录加到头文件搜索目录中 target_include_directories(print PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) # 定义print_EXPORTS宏,表明正在构建该库(若不定义,则表示使用该库) target_compile_definitions(print PRIVATE print_EXPORTS) # 设置目标属性,默认隐藏符号和内联函数 set_target_properties(print PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN 1 ) # 也可以通过下面两个变量,设置上述两个目标属性的默认值 # set(CMAKE_CXX_VISIBILITY_PRESET hidden) # set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) # 主程序 add_executable(main main.c) target_link_libraries(main PRIVATE print) if(MSVC) # 为MSVC编译器启用级别3的警告 target_compile_options(main PRIVATE /W3) endif() # 静态库 add_library(print_static STATIC print.c) target_include_directories(print_static PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) target_compile_definitions(print_static PUBLIC PRINT_STATIC_DEFINE) //main.c #include "print.h" int main() { print(); old_print(); return 0; } //print.c #include "print.h" #include <stdio.h> void print() { printf("Hello\n"); } void _internal() {} #ifndef PRINT_NO_DEPRECATED void old_print() { printf("Hi\n"); } #endif // PRINT_NO_DEPRECATED //print.h #ifndef PRINT_H #define PRINT_H #include "print_export.h" PRINT_EXPORT void print(); PRINT_NO_EXPORT void _internal(); #ifndef PRINT_NO_DEPRECATED PRINT_DEPRECATED_EXPORT void old_print(); #endif // PRINT_NO_DEPRECATED #endif // PRINT_H   查找模块 查找模块(find module)是⼀系列用于搜索第三⽅依赖软件包(包括库或可执⾏⽂件)的模块。对查找模块的引用⼀般不使用include命令,⽽是使用find_package命令。   查找软件包命令(模块模式) find_package命令的模块模式用于搜索第三方依赖软件包,调用 “Find < 软件包名>.cmake” 模块,可设置多种参数,执行后会定义相关变量。 格式: find_package(<软件包名> [<版本号>] [EXACT] [QUIET] [MODULE] [REQUIRED] [[COMPONENTS] [<⼦组件>...]] [OPTIONAL_COMPONENTS <可选⼦组件>...] [NO_POLICY_SCOPE]) 用点:在开发应用的时候,经过会碰到 undefined reference to `xxxxx'。以`pthread_create'为例,就是:undefined reference to `pthread_create。可以在编译的时候添加一个编译选项来链接这个库。 难点:如何在CMake目录程序中设置链接呢? 解决:1. 可以通过判断当前的操作系统,来链接上对应的编译选项。2、可以使用CMake查找线程的模块:FindThreads。(可以针对不同的平台找到对应的线程酷) //CMakeLists.txt cmake_minimum_required(VERSION 3.20) project(find-threads) # 调用FindThreads模块,它会创建一个导入目标Threads::Threads find_package(Threads) add_executable(main main.cpp) # 如果不链接Threads::Threads,在Linux环境中构建会出错: # undefined reference to `pthread_create' target_link_libraries(main PRIVATE Threads::Threads) #include <cstdio> #include <thread> void worker(int i) { printf("worker%d\n", i); } int main() { std::thread th(worker, 0); th.join(); return 0; }      

  • 2025-02-21
  • 回复了主题帖: 颁奖:验证并选择心仪MOSFET,探寻选型奥秘!注册、体验双重好礼等你拿~

    确认个人信息无误

  • 发表了主题帖: 《CMake构建实战》第八章-生成器表达式

    本帖最后由 eew_Eu6WaC 于 2025-2-21 17:33 编辑 《CMake构建实战》第八章-生成器表达式 本章主要介绍CMake中的生成器表达式。CMake在生成阶段,能够根据具体选用的构建系统生成器生成特定的配置,常常用于获取与构建系统相关的信息。 这是CMake比较重要的特性,可以减少构建系统差异性带来的复杂度,让CMake程序更简洁易读 生成器表达式大体分为两类:布尔型生成器表达式 和 字符串生成器表达式   在介绍生成器表达式之前,先看看哪些命令支持它 创建构建目标的命令:add_executable和add_library命令的<源文件>参数可使用生成器表达式,实现根据不同构建模式选择不同源文件 属性相关命令:多数设置目录和目标属性的命令支持生成器表达式,可针对不同构建模式设置属性值 自定义构建规则和目标:add_custom_command和add_custom_target命令部分参数支持生成器表达式,还可用于调试生成器表达式 字符串生成器表达式 顾名思义,字符串生成器表达式在生成阶段会被解析为一段字符串,可以嵌套使用在其他表达式的参数中。 1. 字符转义:对构成生成器表达式语法结构的字符进行转义,如:">"  ","  ";" $<ANGLE-R> # 转义为">" $<COMMA> # 转义为"," $<SEMICOLON> # 转义为";"   2. 条件表达式:根据条件值解析为不同字符串,有完整和简化两种形式。格式:$<IF:{条件},{字符串1},{字符串2}> cmake_minimum_required(VERSION 3.20) project(condition) add_custom_target(debug-gen-exp ALL COMMAND ${CMAKE_COMMAND} -E echo "Is Debug: <$<IF:$<CONFIG:Debug>,Yes,No>$<ANGLE-R>>" VERBATIM )     3. 字符串变换 有分隔符连接、大小写转换、移除重复元素、列表筛选等多种字符串操作表达式 分隔符连接:JOIN:$<JOIN:{列表字符串},{分隔符}> ⼤⼩写转换:LOWER_CASE和UPPER_CASE:$<LOWER_CASE:{字符串}> # 转⼩写       $<UPPER_CASE:{字符串}> # 转⼤写 移除重复元素:REMOVE_DUPLICATES: $<REMOVE_DUPLICATES:{列表字符串}> 列表筛选:FILTER:$<FILTER:{列表字符串},INCLUDE|EXCLUDE,{正则表达式} ⽣成C标识符:MAKE_C_IDENTIFIER:$<MAKE_C_IDENTIFIER:{字符串}> 转换为Shell路径:SHELL_PATH:$<SHELL_PATH:{绝对路径列表字符串}> 4. ⽬标相关表达式 用于查询构建目标的名称、二进制文件路径、链接文件路径等多种属性信息 ⽬标名称:TARGET_NAME_IF_EXISTS:$<TARGET_NAME_IF_EXISTS:{⽬标}> ⽬标的⼆进制⽂件:TARGET_FILE:$<TARGET_FILE:{⽬标}> ⽬标的链接⽂件:TARGET_LINKER_FILE:$<TARGET_LINKER_FILE:{⽬标}> ⽬标的带SONAME的⽂件:TARGET_SONAME_FILE:$<TARGET_SONAME_FILE:{⽬标}> ⽬标的PDB⽂件:TARGET_PDB_FILE:$<TARGET_PDB_FILE:{⽬标}> ⽬标的BUNDLE⽬录:TARGET_BUNDLE_DIR:$<TARGET_BUNDLE_DIR:{⽬标}> ⽬标属性:TARGET_PROPERTY:$<TARGET_PROPERTY:{⽬标},{⽬标属性}> ⽬标的⽬标⽂件:TARGET_OBJECTS:$<TARGET_OBJECTS:{⽬标} 5. 解析生成器表达式 这是一个比较特殊的,其值是将参数作为生成器表达式解析后的结果 解析⼀般表达式:GENEX_EVAL:$<GENEX_EVAL:{⽣成器表达式}> 解析⽬标相关表达式:TARGET_GENEX_EVAL:$<TARGET_GENEX_EVAL:{构建⽬标},{⽣成器表达式}>  

  • 发表了主题帖: 《CMake构建实战》第七章-构建目标和属性(下)

    本帖最后由 eew_Eu6WaC 于 2025-2-21 15:44 编辑 《CMake构建实战》第七章-构建目标和属性(下) 属性相关的命令 在CMake中为了简化常用属性的操作,其提供了专门的配置命令,这些属性可以针对宏定义、编译选项等各方面进行配置,下面罗列常用的命令: 设置目标链接库:target_link_libraries:用于将库目标链接到当前目标,通过PRIVATE、INTERFACE、PUBLIC参数决定链接是作为构建要求还是使用要求。 PUBLIC、INTERFACE、PRIVATE与传递性:这三个参数决定了库目标使用要求的传递方式,影响构建目标的构建和使用要求。 设置宏定义:add_compile_definitions:对当前目录及其子目录构建目标生效,用于设置编译源文件的宏定义,不支持带参数的宏,CMake会自动转义特殊字符。 设置目标宏定义:target_compile_definitions:用于设置指定构建目标源文件的宏定义,会影响COMPILE_DEFINITIONS和INTERFACE_COMPILE_DEFINITIONS属性。 设置编译参数:add_compile_options:对当前目录及其子目录构建目标生效,用于设置编译源文件的参数,会影响目录和目标的COMPILE_OPTIONS属性。 设置目标编译参数:target_compile_options:用于设置指定构建目标源文件的编译参数,会影响COMPILE_OPTIONS和INTERFACE_COMPILE_OPTIONS属性。 设置目标编译特性:target_compile_features:用于设置指定构建目标源文件所需的编译特性,会影响COMPILE_FEATURES和INTERFACE_COMPILE_FEATURES属性,编译特性需在指定变量中存在。 设置头文件目录:include_directories:对当前目录及其子目录构建目标生效,用于设置头文件搜索目录,可控制目录添加位置,还可指定系统头文件目录。 设置目标头文件目录:target_include_directories:用于将目录加入指定构建目标的头文件搜索目录,会影响INCLUDE_DIRECTORIES和INTERFACE_INCLUDE_DIRECTORIES属性,还涉及SYSTEM参数的作用。 设置链接库:link_libraries:对当前目录及其子目录构建目标生效,用于链接库文件或库目标,但不推荐使用,建议用target_link_libraries命令。 设置链接目录:link_directories:对当前目录及其子目录构建目标生效,用于设置链接库搜索目录,可控制目录添加位置。 设置目标链接目录:target_link_directories:用于设置指定构建目标的链接库搜索目录,会影响LINK_DIRECTORIES和INTERFACE_LINK_DIRECTORIES属性,可控制目录添加位置。 设置链接参数:add_link_options:对当前目录及其子目录构建目标生效,用于设置链接构建目标的参数,会影响目录和目标的LINK_OPTIONS属性。 设置目标链接参数:target_link_options:用于设置指定构建目标的链接参数,会影响LINK_OPTIONS和INTERFACE_LINK_OPTIONS属性,可控制参数添加位置。 设置目标源文件:target_sources:用于设置指定构建目标所需的源文件,可在创建目标后设置源文件,会影响SOURCES和INTERFACE_SOURCES属性。 无须递归传递的例程:用CMake重新组织相关例程,展示了在库依赖但不暴露接口时,使用PRIVATE参数设置链接库,使库的使用要求不递归传递的方法。 存在间接引用的例程:用CMake重新组织存在间接引用的例程,展示了在库暴露接口时,使用PUBLIC参数设置链接库,使库的使用要求递归传递的方法。   自定义构建规则 上面所展示CMake定义的各类构建目标,它们的生成过程和属性过程都是由CMake掌握的,现在介绍自定义的一些规则:add_custom_command 只需要定义以下这样的构建目标,然后调用add_custom_command即可 custom_rule: <依赖⽬标>   <调⽤命令⾏⼯具>...   对构建过程的控制中,add_custom_command分别有生成文件和响应构建事件这两种形式。 1. 生成文件:通过指定输出文件、命令、依赖文件等参数定义生成文件的规则,文件不会立即生成,只有在构建过程中被引用时才执行生成命令 add_custom_command(OUTPUT <⽣成⽂件1> [<⽣成⽂件2>...] COMMAND <命令1> [ARGS] [<命令⾏参数>...] [COMMAND <命令2> [ARGS] [<命令⾏参数>...] ...] [BYPRODUCTS [<副产品⽂件>...]] [MAIN_DEPENDENCY <主依赖⽂件>] [DEPENDS [<依赖⽂件>...]] [IMPLICIT_DEPENDS <编程语⾔1> <隐式依赖⽂件> [<编程语⾔2> <隐式依赖⽂件>] ...] [DEPFILE <依赖清单⽂件>] [WORKING_DIRECTORY <⼯作⽬录>] [COMMENT <注释>] [VERBATIM] [APPEND] [COMMAND_EXPAND_LISTS] [JOB_POOL <Ninja构建⼯具的Job Pool>] [USES_TERMINAL] ) 2. 响应构建事件:用于声明当构建目标的指定构建事件(PRE_BUILD、PRE_LINK、POST_BUILD)触发时执行的自定义构建规则。 add_custom_command(TARGET <构建⽬标> PRE_BUILD | PRE_LINK | POST_BUILD COMMAND <命令1> [ARGS] [<命令⾏参数>...] [COMMAND <命令2> [ARGS] [<命令⾏参数>...] ...] [BYPRODUCTS [<副产品⽂件>...]] [WORKING_DIRECTORY <⼯作⽬录>] [COMMENT <注释>] [VERBATIM] [COMMAND_EXPAND_LISTS] [USES_TERMINAL] ) 自定义构建目标 可以创建一个真正的构建目标,其构建规则为指定的一系列命令,默认不在构建全部时构建,可通过`ALL`参数指定是否包含在`all`目标内,还可指定源文件便于在IDE中使用。 命令形式: add_custom_target(<构建⽬标名称> [ALL] [<命令1> [<命令⾏参数>...]] [COMMAND <命令2> [<命令⾏参数>...] ...] [DEPENDS [<依赖⽂件>...]] [BYPRODUCTS [<副产品⽂件>...]] [WORKING_DIRECTORY <⼯作⽬录>] [COMMENT <注释>] [JOB_POOL <Ninja构建⼯具的Job Pool>] [VERBATIM] [COMMAND_EXPAND_LISTS] [USES_TERMINAL] [SOURCES <源⽂件>...] ) 使用:   设置依赖关系 用于显式指定构建目标间的依赖关系,使一个构建目标在另一个构建目标之后构建。与自定义构建规则及目标中的 DEPENDS 参数作用不同, DEPENDS 参数主要用于设置对文件的依赖关系。 命令格式: add_dependencies(<构建⽬标> [<依赖的构建⽬标>]...)   第7章上和下小结 因为这张内容比较重要而且知识点多,所以分成两个章节,在其中涵盖创建构建目标、添加子目录、声明项目的方法,介绍了常用属性及相关命令,强调了面向目标的属性设置在现代CMake中的重要性,还介绍了自定义构建规则和目标,展示了CMake在组织项目结构方面的功能特性及优势。  

  • 2025-02-19
  • 回复了主题帖: 【deepseek】01预热贴:gpt回帖,得积分小礼

    通义千文  

  • 回复了主题帖: DigiKey应用探索站重磅上线!潮流应用,硬核技术探秘,N多干货,一站get!

    DigiKey应用探索站干货满满当当啊,学习潮流技术

  • 2025-02-17
  • 发表了主题帖: 《CMake构建实战》第七章-构建目标和属性(上)

    本帖最后由 eew_Eu6WaC 于 2025-2-19 14:17 编辑 《CMake构建实战》第七章-构建目标和属性(上) “毫不夸张地说,如果学习CMake的目标就是组织简单的C和C++小项目的构建流程,那么阅读掌握本章的内容就足够了”,那我应该在本书的开头提示一下,看完第一章介绍就可以直接跳到本章了哈哈。在本章中和第一章呼应,介绍在CMake的目录程序中定义各种类型的构建目标,包括可执行文件、静态库、动态库、接口库和目标等等。 二进制构建目标 定义:是构建过程中生成的可执行文件、库文件或目标文件,并且全局可见 下面介绍一些二进制构建目标的定义方法: 可执行文件目标:使用add_executable命令创建,参数包括目标名称、源文件等,还有WIN32、MACOSX_BUNDLE、EXCLUDE_FROM_ALL等特殊的参数 格式如下: add_executable(<目标名称>     [WIN32][MACOSX_BUNDLE][EXCLUDE_FROM_ALL]     [<源文件>……] ) cmake_minimum_required(VERSION 3.20) project(myProgram) add_executable(myProgram main.c) add_executable(myProgramExcludedFromAll EXCLUDE_FROM_ALL main.c ) #include <stdio.h> int main() { printf("Hello\n"); } 一般库目标:用add_library命令创建,库类型有STATIC、SHARED、MODULE,可通过BUILD_SHARED_LIBS变量决定库类型 格式: add_library(<目标名称><库类型>     [EXCLUDE_FROM_ALL]     [<源文件>] ) cmake_minimum_required(VERSION 3.20) project(myLib) add_library(myLib lib.c) int add(int a, int b) { return a + b; }   目标文件库目标:用add_library命令创建目标文件集合,可在其他构建目标中通过特定表达式链接其目标文件 格式: add_library(<⽬标名称> OBJECT     [<源⽂件>...] )     cmake_minimum_required(VERSION 3.20) project(myObjLib) add_library(myObjLib OBJECT a.c b.c) add_executable(main main.c $<TARGET_OBJECTS:myObjLib>) int fa(int a, int b) { return a + b; } int fb(int a, int b) { return a - b; } #include <stdio.h> int fa(int a, int b); int fb(int a, int b); int main() { printf("%d %d\n", fa(1, 2), fb(3, 1)); return 0; }   指定源文件的方式:简答省事的方式-使用手动罗列比较好哈哈,但是当文件数量较多那怎么办?可以使用开源项目或者用file和aux_source_directory命令来获取源文件,当然它们存在一定的缺点,比如CMake如何知道构建目标添加了新的源文件呢??有一条命令:aux_source_directory(<⽬录> <结果变量>) 可以遍历目录中的源文件 伪构建目标 定义:那些不会被构建二进制文件的目标,通常用于表明仅具有使用要求的可链接的对象。 分为以下三种类型: 接口库目标 导入目标 别名目标 接口库目标:用add_library命令创建。作用:头文件库的抽象 格式: add_library(<⽬标名称> INTERFACE) cmake_minimum_required(VERSION 3.20) project(myInterfaceLib) add_library(myInterfaceLib INTERFACE) # 声明myInterfaceLib的使用要求:头文件搜索目录应为include target_include_directories(myInterfaceLib INTERFACE include) add_executable(main main.c) # 声明main的构建要求:链接myInterfaceLib库,也就是说 # 将myInterfaceLib接口库的使用要求作为main的构建要求 target_link_libraries(main myInterfaceLib) #include <a.h> #include <stdio.h> int main() { printf("%d\n", add(1, 2)); return 0; } static int add(int a, int b) { return a + b; }   导入目标:包括可执行文件导入目标和库导入目标,但不会构建它,可使用add_executable和add_library命令创建 格式: add_executable(<⽬标名称> IMPORTED [GLOBAL]) 因为要运行一个可执行文件,所以就自己新建一个main.c通过gcc编译出可执行文件,代码如下: cmake_minimum_required(VERSION 3.20) project(import-main) add_executable(main main.c) add_custom_target(run-main COMMAND ./main DEPENDS main WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) #include <stdio.h> void main(void){ printf("Hello CMake\r\n"); } 别名目标:是另一个构建目标的别名,使用add_executable或add_library命令创建 格式: add_executable(<⽬标名称> ALIAS <指向的实际⽬标名称>) add_library(<⽬标名称> ALIAS <指向的实际⽬标名称>) 创建一个静态库 my_liba,其源文件为 a.c。 根据 USE_EXTERNAL_LIBA 的值进行判断: 若 USE_EXTERNAL_LIBA 为真,引入一个外部的静态库 liba,并将其位置设置为 liba.lib。 若 USE_EXTERNAL_LIBA 为假,创建一个别名目标 liba,它指向之前创建的 my_liba 库。 cmake_minimum_required(VERSION 3.20) project(alias-target) add_library(my_liba STATIC "a.c") if(USE_EXTERNAL_LIBA) add_library(liba STATIC IMPORTED) set_target_properties(liba PROPERTIES IMPORTED_LOCATION "liba.lib") else() add_library(liba ALIAS my_liba) endif() add_executable(main "main.c") target_link_libraries(main liba) #include <stdio.h> void liba_function() { printf("This is a function from liba.\n"); } extern void liba_function(); int main() { liba_function(); return 0; }   子目录 CMak可以为每一个目录设置独立的目录属性,这样可以方便地针对不同子目录分别进行构建配置。 用处:使一些子目录结构更加清晰 使用:调用add_subdirectory命令将子目录加入项目,子目录需要包含CMakeLists.txt文件 格式: add_subdirectory(< 源⽂件⽬录 > [< ⼆进制⽬录 >] [EXCLUDE_FROM_ALL]) 项目:project 项目使CMake中组织项目的一个逻辑概念,在CMake目录程序中,可以有若干个项目,顶层目录程序中的第一个我呢见叫-顶层项目。 可声明项目名称、编程语言、版本号等属性,通过变量可获取项目相关属性。并且支持代码注入,通过设置特定变量可在项目定义前后注入代码。 project(< 项⽬名称 > [< 编程语⾔ >...]) project(< 项⽬名称 > [VERSION < 主版本号 >[.< 次版本号 >[.< 补丁版本号 >[.< 修订版本号 >]]]] [DESCRIPTION < 项⽬描述 >] [HOMEPAGE_URL < 项⽬主⻚ URL>] [LANGUAGES < 编程语⾔ >...]) 属性 在CMake中属性根据作用域可以分为以下7中类型: 全局属性:CMake进程所具有的属性,通常用于获取一些全局状态。get_cmake_property和get_property命令来获取状态,set_property命令来设置状态 cmake_minimum_required(VERSION 3.20) project(global_property) get_cmake_property(res GENERATOR_IS_MULTI_CONFIG) message("GENERATOR_IS_MULTI_CONFIG: ${res}") get_property(res GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG SET) message("GENERATOR_IS_MULTI_CONFIG is SET: ${res}")     目录属性:作用于目录(包括子目录),通常用于为目录中的构建目标统一设置编译选项或获取目录信息。get_directory_property和get_property命令来获取,set_directory_properties和set_property命令来设置 cmake_minimum_required(VERSION 3.20) project(directory_property) add_subdirectory(a) add_subdirectory(b) # 获取目录属性SUBDIRECTORIES的值到res get_directory_property(res SUBDIRECTORIES) message("SUBDIRECTORIES: ${res}") #include <stdio.h> int main() { printf("DIR: %s\n", DIR); return 0; } # 设置目录属性COMPILE_DEFINITIONS的值为DIR="a" set_directory_properties(PROPERTIES COMPILE_DEFINITIONS DIR="a") add_executable(a ../main.c) # 设置目录属性COMPILE_DEFINITIONS的值为DIR="b" set_directory_properties(PROPERTIES COMPILE_DEFINITIONS DIR="b") add_executable(b ../main.c)   目标属性:用于构建目标、设置构建和使用要求,通过get_target_property和get_property命令来获取,set_target_properties和set_property命令来设置 //CmakeLists.tet cmake_minimum_required(VERSION 3.20) project(target_property) add_executable(main main.c) # 设置main的目标属性 set_target_properties(main PROPERTIES # 构建要求:将include加入头文件搜索目录 INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/include # 构建要求:链接a库(即传递a库的使用要求到main中作为main的构建要求) LINK_LIBRARIES a ) add_subdirectory(liba)   //main.c #include <f.h> #include <liba.h> #include <stdio.h> int main() { printf("fa: %s\n", fa()); printf("f: %s\n", f()); return 0; } //include.f.h const char *f() { return "main"; }   源文件属性:作用于源文件,用于配置源文件构建和获取信息,通过get_source_file_property和get_property命令来获取,set_source_files_properties和set_property命令来设置 //CMakeLists.txt cmake_minimum_required(VERSION 3.20) project(source_file_property) add_subdirectory(a) add_subdirectory(b) set_source_files_properties(main.c DIRECTORY a PROPERTIES COMPILE_DEFINITIONS VERSION="0.1") set_source_files_properties(main.c DIRECTORY b PROPERTIES COMPILE_DEFINITIONS VERSION="0.2") //main.c #include <stdio.h> int main() { printf("VERSION: %s\n", VERSION); return 0; } //b/CMakeLists.txt add_executable(b ../main.c) //a/CMakeLists.txt add_executable(a ../main.c)   缓存变量属性:作用于缓存变量,用于获取相关信息,通过get_property命令来获取,set_property命令来设置 自定义属性(define_property):使用define_property命令可以自定义属性并添加文档说明,并且指定属性作用域和是否继承上层作用域属性值    

最近访客

< 1/2 >

统计信息

已有26人来访过

  • 芯积分:184
  • 好友:--
  • 主题:20
  • 回复:31

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言