零基础CMake学习笔记

零基础CMake学习笔记

    • 1. 名词解释
      • make cmake Makefile CMakeLists.txt
    • 2. CMake语法介绍
      • 2.1 常用指令
        • 2.1.1 project
        • 2.1.2 set
        • 2.1.3 message
        • 2.1.4 add_executable
        • 2.1.5 aux_source_directory
        • 2.1.6 include_directories
        • 2.1.7 add_definitions
        • 2.1.8 add_subdirectory
        • 2.1.9 add_library
        • 2.1.10 link_directories
        • 2.1.11 target_link_libraries
      • 2.2 指令编写时的注意事项
    • 3. CMakeLists.txt外部构建
    • 4. 源码结构工程化
      • 4.1 工程化思路
      • 4.2 将目标文件放入构建目录的 bin 子目录
      • 4.3 更改二进制的保存路径
    • 5. 安装
      • 5.1 两种安装方法
      • 5.2 如何安装 HelloWord
      • 5.3 安装文件 COPYRIGHT 和 README
      • 5.4 安装脚本 runhello.sh
      • 5.5 安装 doc 中的 hello.txt
      • 5.6 安装指令
    • 6. 静态库(lib)和动态库(dll)
      • 6.1 lib 和 dll必知
      • 6.2 dll 和 lib 的区别
      • 6.3 lib 和 dll 实例构建(含例子和问题)
        • 6.3.1 ADD_LIBRARY
        • 6.3.2 同时构建静态和动态库
        • 6.3.3 SET_TARGET_PROPERTIES
        • 6.3.4 动态库的版本号
        • 6.3.5 安装共享库和头文件
        • 6.3.6 使用外部共享库和头文件
        • 6.3.7 CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH(特殊的环境变量)
        • 6.3.8 生产debug版本的方法:
        • 解决:make后头文件找不到的问题
        • 解决:找到引用的函数问题



来自B站的一个大佬,有几年了,找不到了作者了,他的视频讲的不错的!


1. 名词解释

make cmake Makefile CMakeLists.txt

  • make

    注意: 依赖 Makefile(makefile) 文件

    make命令结果: 产生可执行文件

    • 自动化编译工具。当需要编译的文件较多时,使用make工具会大大提高效率

    • make 会在当前的目录下搜寻 Makefile文件,按照文件中的编译规则进行批处理编译

    • make 会自动的判别原始码是否经过变动,进而自动更新执行档

  • cmake

    注意: 依赖 CMakeLists.txt 文件

    cmake命令结果: 产生一大堆文件,包括make需要用到的Makefile文件

    • 高级编译配置工具。当n个人使用不同的编程语言或者编译器开发同一个项目时,最终完成只要求输出一个可执行文件或者共享库(dll,so等等),这时候就需要使用CMake

    • CMake所有操作都是通过编译 CMakeLists.txt 来完成

  • Makefile(makefile)文件

    • 由cmake执行之后生成
    • 在Linux/Windows下编译c/c++/java代码时用到的一种脚本文件,该文件包含了工程文件的编译规则
    • 每一个功能都要写一个Makefile文件,如果工程很大,并且相关性比较强的话,makefile的书写就会变得相对繁琐,更要命的是如果以后需要添加新的功能或者是新人需要修改功能的话,看起来就会特别麻烦
  • CMakeLists.txt

    • 该文件包含了所需要编译的源文件(c/cpp/java)的编译器、名称、依赖、路径等信息

    大体结构编写流程:

    cmake_minimum_required(VERSION 版本)  #必须
    project(工程名称) #必须add_subdirectory(子文件夹名称) #父目录必须,子目录不必
    add_library(库文件名称 STATIC 文件) #通常子目录(二选一)
    add_executable(可执行文件名称 文件) #通常父目录(二选一)include_directories(路径) #必须
    link_directories(路径) #必须
    target_link_libraries(库文件名称/可执行文件名称 链接的库文件名称) #必须
    

    后面根据需求补充set语句、message语句和判断语句等


2. CMake语法介绍

注意是写在 CMakeLists.txt 文件中

2.1 常用指令

2.1.1 project

作用: 可以用来指定工程的名字和支持的语言,默认支持所有语言

基本语法:

project (工程名称) #指定了工程的名字,并且支持所有语言——建议
project (工程名称 CXX) #指定了工程的名字,并且支持语言是C++
project (工程名称 C CXX) #指定了工程的名字,并且支持语言是C和C++
project (工程名称 C CXX JAVA) #指定了工程的名字,并且支持语言是C、C++和JAVA

注意:
编写了"PROJECT命令"之后,该命令会隐式定义两个make变量,如下:

<projectname>_BINARY_DIR
<projectname>_SOURCE_DIR

message命令 就可以直接使用者两个变量,当前都指向当前的工作目录

问题: 如果改了工程名,隐式定义两个 make变量 也会改变

解决方法: 使用预定义变量:PROJECT_BINARY_DIRPROJECT_SOURCE_DIR,去替代 project命令 隐式定义的两个 make变量

2.1.2 set

作用: 给文件名、路径名或其他字符串起别名,用 ${变量} 即可获取变量中的内容

基本语法: set(变量 文件名/路径/...)

# 举例 SRC_LIST变量包含了多个cpp文件 
set(SRC_LIST xxx.cpp xxx1.cpp xxx2.cpp ...)
2.1.3 message

作用: 向终端输出用户自定义的信息

主要包含三种信息:

  1. SEND_ERROR: 产生错误,生成过程被跳过
  2. SATUS: 输出前缀为—的信息
  3. FATAL_ERROR: 立即终止所有 cmake 过程
2.1.4 add_executable

作用:.cpp/.c/.cc文件生成可执行文件

基本语法:

  • add_executable(可执行文件名称 文件1 文件2 ...)
  • add_executable(可执行文件名称 ${变量}) ,这里获取 set命令 设置的变量
2.1.5 aux_source_directory

作用: 获取路径下所有的.cpp/.c/.cc文件,并赋值给某个变量

基本语法: aux_source_directory(路径 变量)

2.1.6 include_directories

作用: 向工程添加多个特定.h头文件搜索路径。相当于g++编译器的 -I 参数

基本语法: include_directories(dir1 dir2 ...)

2.1.7 add_definitions

作用: 添加编译选项

基本语法: add_definitions(编译选项)

2.1.8 add_subdirectory

作用: 向当前工程添加存放源文件的子目录,并可以指定 中间bin(二进制)文件 和 目标bin文件 存放的位置

注意: 子文件夹中也需要包含并编写 CMakeLists.txt 文件

基本语法:

  • add_subdirectory(子文件夹)
  • add_subdirectory(子文件夹 中间bin文件夹)
  • add_subdirectory(子文件夹 中间bin文件夹 目标bin文件夹)
  • |==》如果不进行 bin 目录的指定,那么编译结果(包括中间结果)都将存放在 子文件夹中
2.1.9 add_library

作用:cpp/.c/.cc文件生成.a静态库

注意: 库文件名称通常为libxxx.so,在这里只要写xxx即可

基本语法: add_library(库文件名称 STATIC ${变量})

2.1.10 link_directories

作用:向工程添加多个特定的.so/.a库文件搜索路径,相当于指定g++编译器的 -L 参数

基本语法: link_directories(dir1 dir2 ...)

2.1.11 target_link_libraries

作用:add_libraryadd_executable生成的文件进行链接操作

基本语法:target_link_libraries(库文件名称/可执行文件名称 链接的库文件名称)

2.2 指令编写时的注意事项

  1. 变量使用 ${变量} 方式取值,但是在 if控制语句 中是直接使用变量名
  2. 指令() 中的参数之间使用空格或分号分开。
  3. CMake命令与大小写无关,但其参数和变量是大小写相关的
  4. 如果源文件名中含有空格,就必须要加双引号("含有空格的文件名"
  5. add_executable(可执行文件名称 xxx)中,xxx的后缀名可省略,它会自动去找xxx.c和xxx.cpp,最好不要这样写,可能会出现同名的源文件和文件夹

3. CMakeLists.txt外部构建

  1. 在与源码文件同一个文件夹下创建 build 文件夹,并进入

    命令:mkdir build && cd build (或 先mkdir build,再 cd build),文件夹名称并不一定使用build,但一般都用build

  2. 使用cmake编译上级目录的CMakeLists

    命令:cmake .. (或 cmake CMakeLists.txt的绝对路径),执行完成之后生成Makefile和其他文件(在build文件夹中)

  3. 使用make生成可执行文件

    命令:make

  4. 执行可执行文件

    命令:./可执行文件名称


4. 源码结构工程化

4.1 工程化思路

  • 添加子目录

    1. 添加一个子目录 src,用来放置工程源代码
    2. 添加一个子目录 doc,用来放置这个工程的文档
  • 在工程目录添加文本文件

    1. COPYRIGHT:版权信息
    2. README
  • 在工程目录添加一个runhello.sh 脚本,用来调用 hello 二进制

  • 将构建后的目标文件放入构建目录的 bin子目录

  • 将 doc 目录的内容以及COPYRIGHT/README安装到/usr/share/doc/cmake/

4.2 将目标文件放入构建目录的 bin 子目录

每个目录下都要有一个CMakeLists.txt说明

[root@localhost cmake]# tree
.
├── build
├── CMakeLists.txt
└── src├── CMakeLists.txt└── main.cpp

外层CMakeLists.txt

PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)

src下的CMakeLists.txt

ADD_EXECUTABLE(hello main.cpp)

4.3 更改二进制的保存路径

使用set 命令重新定义EXECUTABLE_OUTPUT_PATHLIBRARY_OUTPUT_PATH变量,以此来指定最终的 目标bin文件 的位置

  • SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
  • SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

问题: 应该加载哪个目录下的CMakeLists.txt文件

解决方法: 哪里要改变目标存放路径,就在哪里加入上述的定义,所以应该在 src文件夹 中的 CMakeLists.txt 下写


5. 安装

5.1 两种安装方法

  1. 从代码编译后直接 make install 安装
  2. 打包时的指定目录安装
# 简单指定目录
make install DESTDIR=/tmp/test
# 复杂指定目录
./configure –prefix=/usr

5.2 如何安装 HelloWord

使用CMake一个新的指令:INSTALL

INSTALL的安装可以包括:二进制、动态库、静态库以及文件、目录、脚本等

使用CMake一个新的变量:CMAKE_INSTALL_PREFIX

// 目录树结构
[root@localhost cmake]# tree
.
├── build
├── CMakeLists.txt
├── COPYRIGHT
├── doc
│   └── hello.txt
├── README
├── runhello.sh
└── src├── CMakeLists.txt└── main.cpp3 directories, 7 files

5.3 安装文件 COPYRIGHT 和 README

基本语法:INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)

参数解释:

  • FILES:文件

  • DESTINATION:

    1. 写绝对路径
    2. 可以写相对路径,相对路径实际路径是:${CMAKE_INSTALL_PREFIX}/<DESTINATION 定义的路径>

    CMAKE_INSTALL_PREFIX 默认是在 /usr/local/

    cmake -DCMAKE_INSTALL_PREFIX=/usr 在cmake的时候指定CMAKE_INSTALL_PREFIX变量的路径

5.4 安装脚本 runhello.sh

基本语法:INSTALL(PROGRAMS runhello.sh DESTINATION bin)

参数解释:

  • PROGRAMS:非目标文件的可执行程序安装(比如脚本之类)

说明: 实际安装到的是 /usr/bin

5.5 安装 doc 中的 hello.txt

两种方法安装

  1. 通过在 doc 目录建立 CMakeLists.txt ,通过 install 下的 file
  2. 直接在工程目录通过

基本语法: INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake)

注意:

  • DIRECTORY 后面连接的是所在 Source 目录的相对路径

  • / 加与不加有很大的区别

    目录名不以 / 结尾:目录将被安装到目标路径下

    目录名以 / 结尾:目录中的内容安装到目标路径下

5.6 安装指令

cmake ..
#...
make
#...
make install

6. 静态库(lib)和动态库(dll)

6.1 lib 和 dll必知

  • 两者的概念

    • 动态链接库(Dynamic Link Library)
      1. Windows应用程序中,实行了模块化设计,也就是说并不是每个应用程序都编写完所有的功能代码,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,我们称之为dll文件,DLL是一个包含可由多个程序同时使用的代码和数据的库,类似于一个函数库
      2. 动态链接提供了一种方法,使某个进程可以调用不属于它的可执行代码的函数。函数的可执行代码位于一个DLL中,该DLL包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。
      3. 分割成许多dll有助于促进代码重用和内存的有效使用,通过使用 DLL,程序可以实现模块化,由相对独立的组件组成。
      4. 一般来说,DLL 是一种磁盘文件,以.dll.DRV.FON.SYS 和许多以 .exe 为扩展名的系统文件都可以是DLL。一个 DLL 在内存中只有一个实例,并且动态链接库通常都不能直接运行,也不能接收消息,它们是一些独立的文件
    • 静态链接库(Static Link Library)
    1. 静态编译将导出声明和实现都放在lib中,编译后是将所有代码嵌套在程序中,直接可以当成程序的一部分来使用。
  • 调用时两者的区别--------------------------------------------------------------------------------------------------------------

    • 动态链接库

      某个程序在运行中要调用某个DLL函数时,操作系统首先会查看所有正在运行的程序,看看在内存中是否已有此库函数的拷贝,如果有,则让其共享那一个拷贝,如果没有,则去链接载入DLL函数。
      ​ 在程序运行的时候,被调用的DLL函数被安置在内存的某个地方,所有调用它的程序将指向这个代码段。因此,这些代码必须使用相对地址,而不是绝对地址。在编译的时候,我们需要告诉编译器,这些对象文件是用来做动态链接库的,所以要用地址无关代码 (Position Independent Code (PIC) )

    • 静态链接库

      当要使用时,链接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库就不再需要。

6.2 dll 和 lib 的区别

静态库动态库
拓展名一般为.a.lib一般为.so.dll
区别静态库在编译时会直接整合到目标程序中,
编译成功的可执行文件可独立运行
态库在编译时不会放到连接的目标程序中,
编译成功的可执行文件无法单独运行

6.3 lib 和 dll 实例构建(含例子和问题)

任务:

1,建立一个静态库和动态库,提供 HelloFunc 函数供其他程序编程使用,HelloFunc 向终端输出 Hello World 字符串。

2,安装头文件与共享库。

[root@localhost cmake2]# tree
.
├── build
├── CMakeLists.txt
└── lib├── CMakeLists.txt├── hello.cpp└── hello.h

hello.h中的内容

#ifndef HELLO_H
#define Hello_Hvoid HelloFunc();#endif

hello.cpp中的内容

#include "hello.h"
#include <iostream>
void HelloFunc(){std::cout << "Hello World" << std::endl;
}

项目中的cmake内容

PROJECT(HELLO)
ADD_SUBDIRECTORY(lib bin)

lib中CMakeLists.txt中的内容

SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
6.3.1 ADD_LIBRARY

ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

  • hello:就是正常的库名,生成的名字前面会加上lib,最终产生的文件是libhello.so
  • SHARED,动态库 STATIC,静态库
  • ${LIBHELLO_SRC} :源文件
6.3.2 同时构建静态和动态库
// 如果用这种方式,只会构建一个动态库,不会构建出静态库,虽然静态库的后缀是.a
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})// 修改静态库的名字,这样是可以的,但是我们往往希望他们的名字是相同的,只是后缀不同而已
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
6.3.3 SET_TARGET_PROPERTIES

这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和 API 版本

同时构建静态和动态库

SET(LIBHELLO_SRC hello.cpp)ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})//对hello_static的重名为hello
SET_TARGET_PROPERTIES(hello_static PROPERTIES  OUTPUT_NAME "hello")
//cmake 在构建一个新的target 时,会尝试清理掉其他使用这个名字的库,因为,在构建 libhello.so 时, 就会清理掉 libhello.a
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})SET_TARGET_PROPERTIES(hello PROPERTIES  OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
6.3.4 动态库的版本号

一般动态库都有一个版本号的关联

libhello.so.1.2
libhello.so ->libhello.so.1
libhello.so.1->libhello.so.1.2

CMakeLists.txt 插入如下

SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)

VERSION 指代动态库版本,SOVERSION 指代 API 版本。

6.3.5 安装共享库和头文件

本例中我们将 hello 的共享库安装到/lib目录,

将 hello.h 安装到/include/hello 目录

//文件放到该目录下
INSTALL(FILES hello.h DESTINATION include/hello)//二进制,静态库,动态库安装都用TARGETS
//ARCHIVE 特指静态库,LIBRARY 特指动态库,RUNTIME 特指可执行目标二进制。
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)

注意:

安装的时候,指定一下路径,放到系统下

cmake -DCMAKE_INSTALL_PREFIX=/usr ..

6.3.6 使用外部共享库和头文件

准备工作,新建一个目录来使用外部共享库和头文件

[root@MiWiFi-R4CM-srv cmake3]# tree
.
├── build
├── CMakeLists.txt
└── src├── CMakeLists.txt└── main.cpp

main.cpp

#include <hello.h>int main(){HelloFunc();
}
6.3.7 CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH(特殊的环境变量)

注意:这两个是环境变量而不是 cmake 变量,可以在linux的bash中进行设置

我们上面例子中使用了绝对路径INCLUDE_DIRECTORIES(/usr/include/hello)来指明include路径的位置

我们还可以使用另外一种方式,使用环境变量export CMAKE_INCLUDE_PATH=/usr/include/hello

6.3.8 生产debug版本的方法:

cmake .. -DCMAKE_BUILD_TYPE=debug

解决:make后头文件找不到的问题

PS:include <hello/hello.h> 这样include是可以,这么做的话,就没啥好讲的了,

关键字:INCLUDE_DIRECTORIES,这条指令可以用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割,

在CMakeLists.txt中加入头文件搜索路径:INCLUDE_DIRECTORIES(/usr/include/hello)

解决:找到引用的函数问题

报错信息:undefined reference to `HelloFunc()’

关键字:LINK_DIRECTORIES ,添加非标准的共享库搜索路径

指定第三方库所在路径,LINK_DIRECTORIES(/home/myproject/libs)

关键字:TARGET_LINK_LIBRARIES ,添加需要链接的共享库

TARGET_LINK_LIBRARIES的时候,只需要给出动态链接库的名字就行了。

在CMakeLists.txt中插入链接共享库,主要要插在executable的后面

查看main的链接情况

[root@MiWiFi-R4CM-srv bin]# ldd main linux-vdso.so.1 =>  (0x00007ffedfda4000)libhello.so => /lib64/libhello.so (0x00007f41c0d8f000)libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f41c0874000)libm.so.6 => /lib64/libm.so.6 (0x00007f41c0572000)libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f41c035c000)libc.so.6 => /lib64/libc.so.6 (0x00007f41bff8e000)/lib64/ld-linux-x86-64.so.2 (0x00007f41c0b7c000)

链接静态库

TARGET_LINK_LIBRARIES(main libhello.a)



end.

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

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

相关文章

针对AIGC检测的鲁棒性测试——常见攻击手段汇总

前言&#xff1a;这篇文章来总结一下针对AIGC检测的常见攻击手段&#xff0c;选取的研究工作均出自近5年AIGC检测相关文章。&#xff08;论文被拒了需要补实验&#xff0c;先来看看别人怎么做的……&#xff09; 2019 WIFS Detecting and Simulating Artifacts in GAN Fake Ima…

JavaScript的学习之事件的简介

目录 一、事件是什么 二、如何处理事件 一、事件是什么 定义&#xff1a;事件就是浏览器和用户之间的交互行为。 例如&#xff1a;点击按钮、鼠标移动、关闭窗口等。 二、如何处理事件 我们可以在对应的事件属性中设置一些JS行为&#xff0c;当事件触发的时候会将这些代码执行…

关于Pandas的数据填充

前言 在数据分析与预处理过程中&#xff0c;脏数据几乎不可避免&#xff0c;这直接影响到后续分析的准确性和可靠性。清洗数据中最常见的就是处理空值。Pandas DF的数据填充功能非常强大。本文介绍Pandas中常用的几种数据填充&#xff08;也称为缺失值处理&#xff09;方法&am…

35岁,是终点?还是拐点?

35岁&#xff0c;是终点还是拐点&#xff0c;取决于我们对生活和事业的态度、目标以及行动。这个年龄可以看作是一个重要的转折点&#xff0c;具有多重意义和可能性。 很多人在35岁时&#xff0c;已经在自己的职业生涯中建立了一定的基础&#xff0c;可能达到了管理层或专家级别…

Python量化交易学习——Part8:带有技术因子指标的多因子策略

技术面分析又称技术分析(Technical Analysis ),是股票投资分析的专业术语。技术分析研究以往价格和交易量数据,进而预测未来的价格走向。此类型分析侧重于图表与公式的构成,以捕获主要和次要的趋势,并通过估测市场周期长短,识别买入 / 卖出机会。根据您选择的时间跨度,…

Charles抓包工具系列文章(二)-- Repeat 回放http请求

一、什么是http请求回放 当我们对客户端进行抓包&#xff0c;经常会想要重试http请求&#xff0c;或者改写原有部分进行重新请求&#xff0c;都需要用到回放http请求。 还有一种场景是压力测试&#xff0c;对一个请求进行重复请求多少次&#xff0c;并加上适当的并发度。 这里…

【PythonWeb开发】Flask视图函数传递数据到前端模版的方法总结。

在Flask框架中&#xff0c;视图函数返回响应有四种常见方式&#xff0c;都得掌握。 一、返回文本内容 可以直接返回字符串&#xff0c;Flask会自动将其转换为一个响应对象&#xff0c;具有默认的text/html内容类型。 app.route(/return_text) def return_text():return "…

力扣第211题“添加与搜索单词 - 数据结构设计”

关注微信公众号 数据分析螺丝钉 免费领取价值万元的python/java/商业分析/数据结构与算法学习资料 在本篇文章中&#xff0c;我们将详细解读力扣第211题“添加与搜索单词 - 数据结构设计”。通过学习本篇文章&#xff0c;读者将掌握如何实现一个支持通配符搜索的字典数据结构&…

WebStorm 配置 PlantUML

1. 安装 PlantUML 插件 在 WebStorm 插件市场搜索 PlantUML Integration 并安装&#xff0c;重启 WebStorm 使插件生效。 2. 安装 Graphviz PlantUML 需要 Graphviz 来生成图形。使用 Homebrew 安装 Graphviz&#xff1a; 打开终端&#xff08;Terminal&#xff09;。确保你…

java的Nio演进

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 java的Nio演进 前言简介正文总结 前言 在JDK1.4推出JavaNIO之前,基于Java的所有Socket通信都采用了同步阻塞模式 (BIO),这种一请求一应答的通信模型简化了上层的应用开发,但…

C语言小例程28/100

题目&#xff1a;利用递归方法求5!。 程序分析&#xff1a;递归公式&#xff1a;fnfn_1*4! #include <stdio.h>int main() {int i;int fact(int);for(i0;i<6;i){printf("%d!%d\n",i,fact(i));} } int fact(int j) {int sum;if(j0){sum1;} else {sumj*fac…

消防认证-防火门

一、消防认证 消防认证是指消防产品符合国家相关技术要求和标准&#xff0c;且通过了国家认证认可监督管理委员会审批&#xff0c;获得消防认证资质的认证机构颁发的证书&#xff0c;消防产品具有完好的防火功能&#xff0c;是住房和城乡建设领域验收的重要指标。 二、认证依…

嵌入式系统中串口通信粘包问题的解决方案(C语言)

文章目录 0. 引言1. 什么是粘包问题&#xff1f;2. 粘包问题的影响3. 处理粘包问题的思路4. 不同处理方法的优缺点分析5. 实现方案5.1 数据包格式5.2 代码实现 0. 引言 在嵌入式系统中&#xff0c;串口通信是一种常见且重要的数据传输方式。然而&#xff0c;由于硬件和软件的限…

闪迪sd卡视频格式化数据恢复方法,你了解吗

咨询&#xff1a;“我不小心将闪迪SD卡格式化了&#xff0c;里面的重要视频文件全都不见了。我感到非常焦虑&#xff0c;因为这些视频对我来说意义非凡。现在急需找到方法来恢复&#xff01;&#xff01;” 在数字时代&#xff0c;SD卡已成为我们日常生活中不可或缺的数据存储设…

python中数据的作用域

一、命名空间 在 Python 中&#xff0c;命名空间是一个系统&#xff0c;它用于确保名字的唯一性&#xff0c;并防止命名冲突。命名空间是一个存储变量名称&#xff08;或者更广泛地说&#xff0c;标识符&#xff09;与对象之间映射的抽象概念。每个变量名你在程序中创建&#x…

本篇内容:ArkTS开发系列之事件(2.8.1触屏、键鼠、焦点事件)

上篇回顾&#xff1a; ArkTS开发系列之导航 (2.7动画&#xff09; 本篇内容&#xff1a;ArkTS开发系列之事件&#xff08;2.8.1触屏、键鼠、焦点事件&#xff09; 一、知识储备 1. 触屏事件&#xff1a;包括点击事件、拖拽事件、触摸事件。 点击事件 Button()....onClick(…

msvcp120.dll丢失怎么办,找不到msvcp120.dll的多种解决方法

最近&#xff0c;我在运行一个程序时遇到了一个错误&#xff0c;系统提示找不到msvcp120.dll文件&#xff0c;无法继续执行代码。这让我感到非常困扰&#xff0c;因为这个问题导致我无法正常运行这个程序。经过一番搜索和尝试&#xff0c;我找到了几种修复这个问题的方法&#…

如何开发、使用 Starter

开发 第一步&#xff1a;创建starter工程hello-spring-boot-starter并配置pom.xml文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchem…

SpringBoot优点达项目实战:项目初始化(一)

SpringBoot优点达项目实战&#xff1a;项目初始化&#xff08;一&#xff09; 文章目录 SpringBoot优点达项目实战&#xff1a;项目初始化&#xff08;一&#xff09;1、项目介绍2、项目搭建3、依赖导入4、数据准备 1、项目介绍 技术框架 SpringbootmybatisPlusvueknife 2、项目…

什么是生成式AI?

生成式AI&#xff08;Generative AI&#xff09;是一类利用机器学习和人工智能技术来生成内容的系统。这些系统可以创建文本、图像、音乐、视频等各种类型的内容。生成式AI通过学习大量的数据来理解和模仿人类的创作过程&#xff0c;从而生成新的、原创的内容。以下是生成式AI的…