cmake 函数相关

news2024/11/18 12:35:46

目录

cmake函数和宏基础

demo

cmake函数和宏的参数处理

cmake函数和宏的基本使用

demo

cmake函数和宏使用变量

demo

demo

cmake函数和宏需要注意的地方

demo

cmake函数和宏的关键字参数

demo

使用第二种形式cmake_parse_arguments()

demo

关键字list

demo

singleValueKeywords未传入参数

demo

cmake_parse_arguments()命令解析二级关键字

demo

函数和宏的返回值

从函数返回值

demo

 demo

从宏返回值

demo

cmake命令覆盖

demo

函数相关的的特殊变量

demo


cmake函数和宏基础

cmake里面的函数和宏,其行为和C/C++中的函数和宏很像.下面是定义函数和宏的形式:

function(name [arg1 [arg2 [...l]]])
    # function body ...

endfunction()

macro(name [arg1 [arg2 [...l]]])
    # Macro body
endmacro()

定义完函数和宏以后,这些函数和宏就能像调用cmake内置命令一样调用.

cmake函数没有返回值,如果要返回某个值,需要特殊方式.除了这个在cmake定义函数和宏的时候,对于函数和宏的名字是不区分大小写的,但是有个约定俗成的习惯,都使用小写字母加下划线的形式命名.

demo

cmake_minimum_required(VERSION 3.26)

function(print_me)
    message(STATUS "Hello from inside a function")
    message(STATUS "All done function")
endfunction()

macro(print_Macro)
    message(STATUS "macro: Hello from inside a macro")
    message(STATUS "macro: All done macro")
endmacro()


print_me()
print_Macro()

cmake函数和宏的参数处理

cmake函数和宏的参数在处理上基本相同,但是有一个非常重要的区别.

cmake函数把每个参数都当作cmake变量,并且这些参数也都有cmake变量的行为相似的.

cmake宏把参数都当作字符串,这和C/C++中的宏是一致的,宏调用就相当于把宏参数当作字符串替换到宏主体中,这些参数出现的地方.

cmake函数和宏的基本使用

demo

function(func arg)
    if (DEFINED arg)
        message("Function arg is a defined variable")
    else()
        message("Function arg is NOT a defined variable")
    endif()
endfunction()

macro(marco arg)
    if (DEFINED arg)
        message("Marco arg is a defined variable")
    else()
        message("Marco arg is NOT a defined variable")
    endif()
endmacro()

func(foobar)
marco(foobar)

 从输出我们可以看到,通过if (DEFINED ..)命令分别判断CMake函数和宏的参数是不是已经定义了的变量,cmake的宏没有,这说明cmake宏只把参数当成字符串处理.

除了上述区别.cmake函数和宏参数的处理都支持相同的特性.我们可以使用访问变量的方式在cmake函数和宏主体中访问其参数,虽然cmake宏把参数当作字符串,但也是剋通过变量的方式访问的.

cmake函数和宏使用变量

demo

function(func1 arg)
    message("arg = ${arg}")
endfunction()

macro(marco1 arg)
    message("arg = ${arg}")
endmacro()

func1(foobar)
marco1(foobar)

 从上面的两个例子,我们可以看到,调用cmake函数和宏都需要传入命名的参数,除了我们传入的命名参数,cmake还会为我们生成默认的参数:

  • ARGC
    • 这个默认参数是一个值,代表的是传递给函数或者宏的所有参数的个数.
  • ARGV
    • 这个默认参数是一个列表,其中保存的是传递给函数或者宏的所有参数.
  • ARGN
    • 这个默认参数和ARGV一样,但是它只包含命名参数之外的参数(也就是可选参数和未命名的参数).

 除了上述三个默认参数外,每个参数还可以使用ARGVx的形式引用,其中x代表参数的编号,例如ARGV0,ARGV1等等.

demo

function(add_mytest targetName)
    add_executable(${targetName} ${ARGN})
    target_link_libraries(${targetName} PRIVATE foobar)
    add_test(NAME ${targetName}
        COMMAND ${targetName})
endfunction()

add_test(smallTest small.cpp)
add_test(bifTest big.cpp alog.cpp net.cpp)

这个例子,我们定义了一个叫做add_test的函数,这个函数有一个命名参数,第一个参数代表添加单元测试的名字,后续的未命名参数是编译这个单元测试需要的源文件,可以是一个也可以多个.

cmake宏在使用ARGN的时候,需要特别注意,

cmake函数和宏需要注意的地方

一个特别容易出错的例子:

demo

macro(dangerous)
    foreach(arg IN LISTS ARGN)
        message("Argument: ${arg}")
    endforeach()
endmacro()

function(func)
    dangerous(1 2)
endfunction()

func(3)

结果:

我们希望调用func()函数然后通过宏传入 1 2两个未命名参数,通过foreach打印两个message,但实际上只打印了一个.参数还是3.

其实宏的本质就是字符串替换,如果把宏替换成字符串就好理解了.

替换后的代码:

function(func)
    foreach(arg IN LISTS ARGN)
        message("Argument: ${arg}")
    endforeach()
endfunction()

 如果非要用第一种形式,建议使用函数代替宏,函数不会有上面的问题.

cmake函数和宏的关键字参数

如何写出类似于target_link_libraries()这样的函数?

target_link_libraries(targetName
    <PRIVATE|PUBLIC|INTERFACE> item1 [item2 ...]
    [<PRIVATE|PUBLIC|INTERFACE> itme3 [item4 ..]]
    ...
)

对于cmake内置的target_link_libraries()命令,他的作用就是在链接阶段,将某个target连接上.比如我们的一个可执行程序依赖一个库,这时候就需要用到这个命令.

从这个命令(函数)的签名可以看出,它是有关键字参数的,这些关键字是<PRIVATE|PUBLIC|INTERFACE>

如果我们需要编写这样的函数或者宏,cmake给我们提供了另外一个内置的命令:cmake_parse_arguments(),在这个内置命令的帮助下,我们也能写出target_link_libraries()这样的函数或者宏.

cmake_parse_arguments()命令有两种形式,第一种形式所有的cmake版本都支持.

include(CMakeParseArguments)

cmake_parse_arguments(
    prefix        //前缀
    valuelessKeywords singleValueKeywords multiValueKeywords    //关键字参数
    argsToparse...    
)

在cmake3.5版本以前cmake_parse_atguments()命令是CMakeParseArguments这个模板提供的命令,如果想用其中的功能就要先include它.

在cmake3.5版本开始,cmake_parse_atguments()命令已经是一个默认的命令了,不需要再include(CMakeParseArguments)了.

cmake_parse_arguments(
    prefix
    valuelessKeywords singleValueKeywords multiValueKeywords
    argsToparse...
)

第二种形式再cmake3.7版本中引入的,而且只有cmake函数可以使用,cmake宏是不支持这种形式的.

cmake_parse_arguments(
    PARSE_ARGV startIndex
    prefix
    valuelessKeywords singleValueKeywords multiValueKeywords
)
  •  valuelessKeywords
    • 这种关键字参数没有额外的参数,只是一个独立的关键字,再调用函数的时候,有这个关键字和没有这个关键字代表着两种不同的情况,功能类似于传递了一个BOOL类型的命名参数.
  • singleValueKeywords
    • 这种关键字参数需要一个额外的参数,而且只能有一个.
  • multiValueKeywords
    • 这种关键字参数后面可以有零个或者多个额外的参数.

以上三个关键字参数在命名方面,虽然没有约定,但是建议都使用大写字母加下划线的形式,另外关键字的参数的名字不要太长,否则可能带来意想不到的后果.

demo

function(funqwer)
    set(prefix ARG)
    set(noValue ENABLE_NET COOL_STUFF)
    set(singleValues TARGET)
    set(multiValue SOURCES IMAGES)

    include(CMakeParseArguments)
    cmake_parse_arguments(
        ${prefix}
        "${noValue}" "${singleValues}" "${multiValue}"
        ${ARGN}
    )

    message("Option summary: ")

    foreach(arg IN LISTS noValue)
        if (${prefix}_${arg})
            message(" ${arg} enabled")
        else()
            message(" ${arg} disabled")
        endif()
    endforeach()

    foreach(arg IN LISTS singleValues multiValue)
        message( "${arg} = ${${prefix}_${arg}}")
    endforeach()
endfunction()


funqwer(
    SOURCES foo.cpp bar.cpp
    TARGET MyApp
    ENABLE_NET
)

funqwer(
    COOL_STUFF
    TARGET dummy
    IMAGES here.png gone.png
)

使用第二种形式cmake_parse_arguments()

第二种cmake_parse_arguments()命令形式如下:

cmake_parse_arguments(
    PARSE_ARGV 0
    ${prefix}
    "${noValues}" "${singleValues}" "${multiValues}"
)

demo

function(funzxc)
    set(prefix ARG)
    set(noValue ENABLE_NET COOL_STUFF)
    set(singleValues TARGET)
    set(multiValue SOURCES IMAGES)

    # include(CMakeParseArguments)
    # cmake_parse_arguments(
    #     ${prefix}
    #     "${noValue}" "${singleValues}" "${multiValue}"
    #     ${ARGN}
    # )
    cmake_parse_arguments(
        PARSE_ARGV 0
        ${prefix}
        "${noValue}" "${singleValues}" "${multiValue}"
    )
    message("Option summary: ")

    foreach(arg IN LISTS noValue)
        if (${prefix}_${arg})
            message(" ${arg} enabled")
        else()
            message(" ${arg} disabled")
        endif()
    endforeach()

    foreach(arg IN LISTS singleValues multiValue)
        message( "${arg} = ${${prefix}_${arg}}")
    endforeach()
endfunction()
  message("-------------------------------------")
funzxc(
    SOURCES foo.cpp bar.cpp
    TARGET MyApp
    ENABLE_NET
)

funzxc(
    COOL_STUFF
    TARGET dummy
    IMAGES here.png gone.png
)

 结果是一样的.

关键字list

 如果传入的valuelessKeywords singleValueKeywords multiValueKeywords三种关键字参数都不能解析,那就会保存一个叫做<prefix>_UNPARSED_ARGUMENTS的变量中,这个变量是个列表.

demo

message("-------------------------------------")
function(funArges)
    set(noValue "")
    set(singleValues SPECIAL)
    set(multiValue EXTRAS)

    cmake_parse_arguments(
        PARSE_ARGV 0
        ARG
        "${noValue}" "${singleValues}" "${multiValue}"
    )

    message("Left-over args: ${ARG_UNPARSED_ARGUMENTS}")

    foreach(arg IN LISTS ARG_UNPARSED_ARGUMENTS)
        message("${arg}")
    endforeach()
endfunction()


funArges(burger fries "chinese;tomato" SPECIAL secretSauce)

上面例子我们特意传入一个包含分号的参数"chinese;tomato",我们使用的是cmake_parese_arguments()命令的第二种形式去解析参数,所有它有效地识别出"chinese;tomato"是一个参数,而不是两个.如果使用cmake_parse_argument()命令的第一种形式,就会不一样.

singleValueKeywords未传入参数

 从cmake3.15开始如果没有给singleValueKeywords关键字需要一个额外的参数,就会给一个默认的变量:

<prefix>_KEYWORDS_MISSING_VALUES将会保存这个关键字.

demo


message("-------------------------------------")

function(demoArgs)
    set(noValue "")
    set(singleValues SPECIAL)
    set(multiValue ORDINARY EXTRAS)

    cmake_parse_arguments(
        PARSE_ARGV 0
        ARG
        "${noValue}" "${singleValues}" "${multiValue}"
    )
    message("Keywords missing values: ${ARG_KEYWORDS_MISSING_VALUES}")
endfunction()

demoArgs(burger fries SPECIAL ORDINARY EXTRAS high low)

在这个例子中,因为SPECIAL关键字参数明确需要一个额外的参数,如果没有传递,可能会导致错误.但是cmake不会报错,所以我们需要特别注意.

cmake_parse_arguments()命令解析二级关键字

cmake_parse_arguments()命令解析二级关键字

demo

function(libWithTest)
    set(groups LIB TEST)
    cmake_parse_arguments(GRP "" "" "${groups}" "${ARGN}")

    set(args SOURCES PRIVATE_LIBS PUBLIC_LIBS)
    cmake_parse_arguments(LIB "" "TARGET" "${args}" ${GRP_LIB})
    cmake_parse_arguments(TEST "" "TARGET" "${args}" ${GRP_TEST})

    add_library(${LIB_TARGET} ${LIB_SOURCES})
    target_link_libraries(${TEST_TARGET}
        PUBLIC ${LIB_PUBLIC_LIBS}
        PRIVATE ${LIB_PRIVATE_LIBS}
    )

    add_executable(${TEST_TARGET} ${TEST_SOURCES})
    target_link_libraries(${TEST_TARGET}
        PUBLIC ${TEST_PUBLIC_LIBS}
        PRIVATE ${LIB_TARGET} ${TEST_PRIVATE_LIBS}
    )
endfunction()
message("-------------------------------------")
libWithTest(
    LIB
        TARGET Algo
        SOURCE algo.cpp algo.h
        PUBLIC_LIBS SomeMathHelpers
    TEST
        TARGET AlgoTest
        SOURCE algo.cpp algo.h
        PRIVATE_LIBS gtest_main
)

 这个例子很好的展示通过cmake_parse_arguments()命令解析多级参数的方式.

虽然这些功能相当强大,但是该命令任然有些限制.内置命令能够支持重复关键字.例如像target_link_libraries()这样的命令允许在同一个命令中多次使用PRIVATE PUBLIC INTERFACE关键字,cmake_parse_arguments()命令不支持这一点.它只会返回与关键字最后一次出现相关的值,并丢弃较早的值.只有当使用多级关键字集并且关键字在任何给定的正在处理的参数集中只出现一次时,关键字才能重复使用.

函数和宏的返回值

cmake函数和宏的主要区别,函数会创建一个新的作用域,而宏不会.函数内部定义或修改的变量对函数外部同名的变量没有影响,除非明确需要传播出去,宏和其调用者共享作用域,因此在宏内部定义变量或者修改变量都会影响到外部同名的变量.

从函数返回值

从cmake3.25开始,我们可以在return()命令中使用关键字PROPAGATE关键字来轻松返回值,所以要使用这个语法我们必须将CMP0140这个策略设置为NEW.

cmake_minimum_requierd(VERSION 3.25 FATAL_ERROR)命令最小cmake版本,这条命令会自动为我们将CMP0140这个策略设置为NEW.

demo

message("-------------------------------------")
function(doSomething outVar)
    set(${outVar} 42)
    return(PROPAGATE ${outVar})
endfunction()

doSomething(result)
message("result = ${result}")

上面的例子,函数调用者希望通过outVar这个变量返回一个值.所以我们只需要在函数内部对这个变量赋值后通过return()命令的PROPAGATE关键字返回就行.

这里有个技巧,为了不让函数中自己定义的变量覆盖调用者作用域内部的变量,通常在return()命令中使用PROPAGATE关键字传播出去的变量都要求定义成函数的命名变量,这样变量的名字和作用完全由调用者决定,函数只是对其值做操作.

如果函数内部还有新的作用域,return()命令时从函数内部型的作用域调用的.

 demo

message("-------------------------------------")
function(doSomething1 outVar)
    set(${outVar} 42)
    block()
        set(${outVar} 27)
        return(PROPAGATE ${outVar})
    endblock()
endfunction()

doSomething1(result1)
message("result1 = ${result1}")

上面使用的return()命令在cmake 3.25及其以后的版本才支持,如果在小于3.25版本可以使用set()命令的PARENT_SCOPE关键字.

function(doSomthing2 re2 re3)
    set(${re2} "first result" PARENT_SCOPE)
    set(${re3} "second result" PARENT_SCOPE)
endfunction()
message("-------------------------------------")
doSomthing2(re2 re3)
message("re2 = ${re2}")
message("re3 = ${re3}")

  

从宏返回值

宏可以像函数那样return()特定的变量,通过将他们作为参数传入,来指定要设置的变量名称.唯一的区别是在调用set()命令时不应该在宏中使用PARENT_SCOPE关键字.因为宏已经修改了调用者范围内的变量.

demo


message("-------------------------------------")
macro(mFunc1 mre1 mre2)
    set(${mre1} "qwer")
    set(${mre2} "asdf")
endmacro()
mFunc1(mre1 mre2)
message("mre1 = ${mre1}")
message("mre2 = ${mre2}")

在宏中使用return()命令一定要小心,因为宏相当于直接将宏主体粘贴到调用的地方,所以return()命令在宏中使用产生的效果与在地方有很大关系. 

cmake命令覆盖

cmake命令覆盖就是我们定义新的函数或者宏与已经存在的函数或者宏重名的情况.

在C/C++中,我们可以是使用作用域来区分,在cmake中我们是完全允许这样的操作的,因为我们可能会有这样的操作的需求: 我们需要包装已有的函数或者宏.但是在使用的时候会有一些坑,需要注意.

demo

function(someFunc)
    # dosomething
endfunction()

function(someFunc)
    if(...)
        # ...
    else()
        _someFunc()
    endif()
endfunction()

 在这个例子中,我们先定义了someFunc()这个函数,然后紧接着又定义了一个同名的函数,这时候,第二个定义的地方就会覆盖之前定义的地方.

cmake内部实现在遇到这种情况会将第一处定义的someFunc()函数改成_someFunc()函数.这样,新的someFunc()函数就覆盖了旧的someFunc()函数,然后要访问旧的someFunc()函数就可以通过_someFunc()函数来访问.如上面例子所示.

只在覆盖一次的情况下,没什么大问题,但是当覆盖次数多的时候就会陷入死循环.

在有需要覆盖已有命令的情况下,一定要记得只能覆盖一次,千万不要覆盖多次.最佳实践就是不要试图覆盖已有的命令.

函数相关的的特殊变量

这些变量在cmake3.17版本以后才开始支持.所以使用这些变量保证cmake最小版本是3.17.

  • CMAKE_CURRENT_FUNCTION
    • 这个变量会保存当前正在执行的函数名字
  • CMAKE_CURRENT_FUNCTION_LIST_FILE
    • 这个变量会保存当前正在执行的函数所在文件的绝对路径
  • CMAKE_CURRENT_FUNCTION_LIST_DIR
    • 这个变量会保存当前正在执行的函数所在文件的目录的绝对路径
  • CMAKE_CURRENT_FUNCTION_LIST_LINE
    • 这个变量会保存当前正在执行的函数的行号

除了在调试的时候用到这些变量,我们在调用函数的时候,如果在函数内部需要使用路径的时候,这些变量也是非常有用的,

demo

function(writeSomeFile toWhere)
        configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/template.cpp.in ${toWhere} @ONLY)
endfunction()

这里的config_file()命令的作用是把${CMAKE_CURRENT_FUNCTION_LIST_DIR}/template.cpp.in文件通过一些规则转换成另一个文件:${toWhere}.这个例子中能够通过CMAKE_CURRENT_FUNCTION_LIST_DIR这个变量准确的定位template.cpp.in的路径,如果没有这个变量是支持,还有中一种实现:

set(__writeSomeFile_DIR ${CMAKE_CURRENT_LIST_DIR})

function(writeSomeFile toWhere)
    configure_file(__writeSomeFile_DIR/template.cpp.in ${toWhere} @ONLY)
endfunction()

这种实现就严重依赖与__writeSomeFile_DIR变量,使用起来灵活度有所下降.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/756557.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GDB 调试代码

目录 一、其他调试代码的工具 二、GDB调试 1、调试准备 2、开始调试 3、调试命令 1.运行程序 2.退出gdb 3.传参 4.查看代码 5.设置或删除断点及相关操作 6.继续运行 7.运行中打印某些值及其类型 8.自动的打印某些值和信息及其相关操作 9.单步调试 10.设置变量的…

http-server 的安装与使用

文章目录 问题背景http-server简介安装nodejs安装http-server开启http服务http-server参数 问题背景 打开一个文档默认使用file协议打开&#xff0c;不能发送ajax请求&#xff0c;只能使用http协议才能请求资源&#xff0c;所以此时我们需要在本地建立一个http服务&#xff0c…

基于java的智能停车场管理系统

背景 智能停车场管理系统的主要使用者分为管理员和用户&#xff0c;实现功能包括管理员&#xff1a;个人中心、用户管理、车位信息管理、车位租用管理、车位退租管理、违规举报管理、论坛交流、系统管理&#xff0c;用户&#xff1a;个人中心、车位租用管理、车位退租管理、违…

MySQL每日一练——MySQL多表查询进阶挑战

目录 1、首先创建表 t_dept: t_emp: 2、插入数据 t_dept表&#xff1a; t_tmp表: 3、修改表 4、按条件查找 1、首先创建表 t_dept: CREATE TABLE t_dept (id INT(11) NOT NULL AUTO_INCREMENT,deptName VARCHAR(30) DEFAULT NULL,address VARCHAR(40) DEFAULT NULL,P…

为什么单片机可以直接烧录程序的原因是什么?

单片机&#xff08;Microcontroller&#xff09;可以直接烧录程序的原因主要有以下几点&#xff1a; 集成性&#xff1a;单片机是一种高度集成的芯片&#xff0c;内部包含了处理器核心&#xff08;CPU&#xff09;、存储器&#xff08;如闪存、EEPROM、RAM等&#xff09;、输入…

JavaScript 使用URL跳转传递数组对象数据类型的方法

文章目录 首先了解一下正常传递基本数据类型JavaScript 跳转页面方法JavaScript 路由传递参数JavaScript 路由接收参数传递对象、数组效果&#xff1a; 在前端有的时候会需要用链接进行传递参数&#xff0c;基本数据类型的传递还是比较简单的&#xff0c;但是如果要传递引用数据…

AWS 解决方案架构师「免费考」

周五晚&#xff0c;AWS 推出了的训练营活动&#xff0c;这对于正在准备 Cloud Practitioner 的我来说&#xff0c;简直不要太开心。官方文章原文链接《限定&#xff01;直冲「云」霄训练营开营啦》。 PART-01 训练营简介 看到推送后第一时间点了进去&#xff0c;活动的情况简…

Socket API使用——模拟http协议

Socket API使用——模拟http协议 简单的c/s程序——服务端实例 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; import java.nio.char…

Python np.unique()函数详解

np.unique()函数详解&#xff1a;返回数组的唯一值唯一值默认已进行从小到大的排序 一些重要参数 return_index&#xff1a;bool, optional。如果设置为True,返回数组中唯一值的索引号&#xff1b;否则不返回。 注意&#xff1a;返回的数组和输入的数组的大小不相同&#xf…

第十五章——友元、异常

友元 类并非只能拥有友元函数&#xff0c;也可以将类作为友元。在这种情况下&#xff0c;友元类的所有方法都可以访问原始类的私有成员和保护成员。因此尽管友元被授予从外部访问类的私有部分的权限&#xff0c;但它们并不与面向对象的编程思想相悖&#xff0c;相反提高了共有…

《C++程序设计原理与实践》笔记 第20章 容器和迭代器

本章和下一章将介绍STL&#xff0c;即C标准库的容器和算法部分。关键概念序列和迭代器用于将容器&#xff08;数据&#xff09;和算法&#xff08;处理&#xff09;联系在一起。 20.1 存储和处理数据 首先考虑一个简单的例子&#xff1a;Jack和Jill各自在测量车速&#xff0c…

echarts x轴文字过长 文字换行显示

xAxis: {type: "category",data: [四美休闲娱乐文化场馆, 资讯, 大咖分享],axisLabel: {show: true,fontSize: 10,interval: 0,color: "#CAE8EA",formatter: function (params) {var newParamsName "";var paramsNameNumber params.length;var…

MySQL数据库基础 18

第18章_MySQL8其它新特性 1. MySQL8新特性概述1.1 MySQL8.0 新增特性1.2 MySQL8.0移除的旧特性 2. 新特性1&#xff1a;窗口函数2.1 使用窗口函数前后对比2.2 窗口函数分类2.3 语法结构2.4 分类讲解1. 序号函数2. 分布函数3. 前后函数4. 首尾函数5. 其他函数 2.5 小 结 3. 新特…

【讲座笔记】Continual Learning and Memory Augmentation with Deep Neural Networks

20230607【开放世界的感知&#xff1a;探索可迁移与可持续学习之路】巩东&#xff1a;Continual Learning and Memory Augmentation……_哔哩哔哩_bilibili 游荡……游荡……找个talk看一下 讲的是continuous learning&#xff08;好家伙缩写也是CL&#xff09; 1.continual l…

error: ‘CV_LOAD_IMAGE_UNCHANGED’ was not declared in this scope

1-错误 2-错误原因 opencv4.x以上&#xff0c;有些宏&#xff0c;API名字改了&#xff0c;需要改为新的 3-解决方案 CV_LOAD_IMAGE_UNCHANGED 改为 cv::IMREAD_UNCHANGEDCV_LOAD_IMAGE_GRAYSCALE 改为 cv::IMREAD_GRAYSCALECV_LOAD_IMAGE_COLOR 改为 cv::IMREAD_COLORCV_LO…

Win10,WinServer16,DNS,Web ,域 环境配置 周总结 (温故而知新 可以为师矣 第十五课)

Win10,WinServer16,DNS,Web ,域 环境安装 (第十五课) 创建虚拟机安装windowserver2016服务器(NETBASE第二课)_星辰镜的博客-CSDN博客 创建台虚拟机并安装上window10系统&#xff08;NETBASE 第一课&#xff09;_window 虚拟机_星辰镜的博客-CSDN博客配置通过域名访问网站(NET…

【5G PHY】5G 调制与编码策略(MCS)介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

实验:如何在YOLO8中添加PnP算法来实现Head Pose Estimation

目录 前言一、步骤二、PnP估计Head Pose&#xff0c;并显示1.引入库2.结果展示 总结 前言 YOLO&#xff18;的集成度比较高&#xff0c;如何在简洁的代码中加入Head Pose的东西&#xff0c;不是一件简单的事情&#xff0e;这里介绍如何插入PnP算法实现头部姿态估计的代码&…

【岛屿最大面积】BJ某IT厂笔试题

该题在LeetCode上能找到原题&#xff0c;大致意思是&#xff0c;给你一个大小为 m x n 的二进制矩阵 grid 。岛屿 是由一些相邻的 1 (代表土地) 构成的组合&#xff0c;这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0&…

【雕爷学编程】Arduino动手做(06)---KY-038声音传感器模块2

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…