CMake基础【学习笔记(八)】

声明此博客为转载

CMake基础

文章目录

  • CMake基础
    • 一、准备知识
      • 1.1 C++的编译过程
      • 1.2 静态链接库和动态链接库
      • 1.3 为什么需要CMake
        • 1.3.1 g++ 命令行编译
        • 1.3.2 CMake简介
    • 二、CMake基础知识
      • 2.1 安装
      • 2.2 第一个CMake例子
      • 2.3 语法基础
        • 2.3.1 指定版本
        • 2.3.2 设置项目
        • 2.3.3 添加可执行文件目标
        • 2.3.4 生成静态库并链接
        • 2.3.5 生成动态库并连接
        • 2.3.6 CMake 中的 PUBLIC、PRIVATE、INTERFACE
        • 2.3.7 变量
        • 2.3.8 include引入其他代码
        • 2.3.9 条件控制
        • 2.3.10 CMake分步编译
        • 2.3.11 生成器表达式
        • 2.3.12 函数和宏
        • 2.3.13 设置安装
        • 2.3.14 寻找依赖 find_package
    • 三、opencv CMake示例

一、准备知识

1.1 C++的编译过程

使用g++等编译工具,从源码生成最终的可执行文件一般有这几步:预处理(Preprocess)、编译(Compile)、汇编(assemble)、链接(link)。

输入g++ --help可以看到对应命令:

-E                       Preprocess only; do not compile, assemble or link.
-S                       Compile only; do not assemble or link.
-c                       Compile and assemble, but do not link.
-o <file>                Place the output into <file>.

以下面程序为例:

#include <iostream>

int main() {
    std::cout << "Hello World!" << std::endl;
    return 0;
}
  • 第一步:预处理
    C++中预处理指令以 # 开头。在预处理阶段,会对#define进行宏展开,处理#if,#else等条件编译指令,递归处理#include。这一步需要我们添加所有头文件的引用路径。

    # 将xx.cpp源文件预处理成xx.i文件(文本文件)
    g++ -E main.cpp -o main.i
    
  • 第二步:编译

    检查代码的规范性和语法错误等,检查完毕后把代码翻译成汇编语言文件。

    # 将xx.i文件编译为xx.s的汇编文件(文本文件)
    g++ -S main.i -o main.s
    
  • 第三步:汇编
    基于汇编语言文件生成二进制格式的目标文件。

    # 将xx.s文件汇编成xx.o的二进制目标文件
    g++ -c main.s -o main.o
    
  • 第四步:链接

    将目标代码与所依赖的库文件进行关联或者组装,合成一个可执行文件

    # 将xx.o二进制文件进行链接,最终生成可执行程序
    g++ main.o -o main
    

1.2 静态链接库和动态链接库

所谓静态和动态,其区别是链接的阶段不一样。

  • 静态链接库名称一般是lib库名称.a.a代表archive library),其链接发生在编译环节。一个工程如果依赖一个静态链接库,其输出的库或可执行文件会将静态链接库*.a打包到该工程的输出文件中(可执行文件或库),因此生成的文件比较大,但在运行时也就不再需要库文件了。

  • 而动态链接库的链接发生在程序的执行过程中,其在编译环节仅执行链接检查,而不进行真正的链接,这样可以节省系统的开销。动态库一般后缀名为*.so.so代表shared object,Linux:lib库名称.so ,macOS:lib库名称.dylib)。动态链接库加载后,在内存中仅保存一份拷贝,多个程序依赖它时,不会重复加载和拷贝,这样也节省了内存的空间。

  • 以下图为例

    • 工程AB依赖静态链接库 static libraryAB在运行时,内存中会有多份static library

    • 工程AB依赖动态链接库 shared libraryAB在运行时,内存中只有一份 shared library(shared:共享)。

以上只是非常简单的一个解释以区分动态链接库和静态链接库。更多底层的知识需要单独进行深入讲解。

1.3 为什么需要CMake

1.3.1 g++ 命令行编译

当我们编译附件中1.hello_world时,我们可以运行

g++ main.cpp -o main

当我们需要引入外部库时,如附件中的2.external_libs,需要引入gflags(Google开源的命令行参数处理库),我们则需要运行:

# 安装gflags
sudo apt-get install libgflags-dev libgflags2.2 

// -lgflags表示链接gflags库,-o main表示输出文件名为main
g++ main.cpp -lgflags -o main 

# 或者:

# 安装pkg-config
sudo apt-get install pkg-config

// pkg-config是一个工具,用于查找和管理安装在系统上的库文件,--cflags --libs gflags表示查找gflags库的头文件和库文件的路径,-o main表示输出文件名为main

g++ main.cpp `pkg-config --cflags --libs gflags`  -o main 


# 测试输出
./main --age 31 --name alice

有些时候有一些常用库我们也不用手动添加头文件或链接库路径,通常g++能在默认查询路径中找到他们。当我们的项目文件变得多起来,引入的外部库也多起来时,命令行编译这种方式就会变得十分臃肿,也不方便调试和编辑。通常在测试单个文件时会使用命令行进行编译,但不推荐在一个实际项目中使用命令行编译。

1.3.2 CMake简介

在实际工作中推荐使用CMake构建C++项目,CMake是用于构建、测试和软件打包的开源跨平台工具;

特性:

  • 自动搜索可能需要的程序、库和头文件的能力;
  • 独立的构建目录(如build),可以安全清理
  • 支持复杂的自定义命令(下载、生成各种文件)
  • 自定义配置可选组件
  • 从简单的文本文件(CMakeLists.txt)自动生成工作区和项目的能力
  • 在主流平台上自动生成文件依赖项并支持并行构建
  • 几乎支持所有的IDE

二、CMake基础知识

2.1 安装

ubuntu上请执行,但是版本不一定是最新版,

sudo apt install cmake -y

或者编译安装:

# 以v3.25.1版本为例
git clone -b v3.25.1 https://github.com/Kitware/CMake.git 
cd CMake
# 你使用`--prefix`来指定安装路径,或者去掉`--prefix`,安装在默认路径。
./bootstrap --prefix=<安装路径> && make && sudo make install

# 验证
cmake --version

2.2 第一个CMake例子

附件位置:3.first_cmake

# 第一步:配置,-S 指定源码目录,-B 指定构建目录
cmake -S . -B build 
# 第二步:生成,--build 指定构建目录
cmake --build build
# 运行
./build/first_cmake

vs code插件:

  • 安装twxs.cmake做代码提示;
  • 安装ms-vscode.cmake-tools界面操作。

2.3 语法基础

2.3.1 指定版本

以附件:3.first_cmake/CMakeLists.txt为例:

# CMake 最低版本号要求
cmake_minimum_required(VERSION 3.10)

# first_cmake是项目名称,VERSION是版本号,DESCRIPTION是项目描述,LANGUAGES是项目语言
project(first_cmake 
        VERSION 1.0.0 
        DESCRIPTION "项目描述"
        LANGUAGES CXX) 

# 添加一个可执行程序,first_cmake是可执行程序名称,main.cpp是源文件
add_executable(first_cmake main.cpp)

命令cmake_minimum_required来指定当前工程所使用的CMake版本,不区分大小写的,通常用小写。VERSION是这个函数的一个特殊关键字,版本的值在关键字之后。CMake中的命令大多和cmake_minimum_required相似,不区分大小写,并有很多关键字来引导命令的参数输入(类似函数传参)。

2.3.2 设置项目

以附件:3.first_cmake/CMakeLists.txt为例:

project(ProjectName 
        VERSION 1.0.0 
        DESCRIPTION "项目描述"
        LANGUAGES CXX) 

CMakeLists.txt的开头,都会使用project来指定本项目的名称、版本、介绍、与使用的语言。在project中,第一个ProjectName(例子中用的是first_cmake)不需要参数,其他关键字都有参数。

2.3.3 添加可执行文件目标

以附件:3.first_cmake/CMakeLists.txt为例:

add_executable(first_cmake main.cpp)

这里我们用到add_executable,其中第一个参数是最终生成的可执行文件名以及在CMake中定义的Target名。我们可以在CMake中继续使用Target的名字为Target的编译设置新的属性和行为。命令中第一个参数后面的参数都是编译目标所使用到的源文件。

2.3.4 生成静态库并链接

附件位置:4.static_lib_test

A.生成静态库

#account_dir/CMakeLists.txt

# 最低版本要求
cmake_minimum_required(VERSION 3.10)

# 项目信息
project(Account)

# 添加静态库,Linux下会生成libAccount.a
add_library(Account STATIC Account.cpp Account.h)
# 编译静态库后,会在build下生成 build/libAccount.a 静态库文件
account_dir/
├── Account.cpp
├── Account.h
├── build
│   └── libAccount.a
└── CMakeLists.txt

这里我们用到add_library, 和add_executable一样,Account为最终生成的库文件名(lib库名称.a),第二个参数是用于指定链接库为动态链接库(SHARED)还是静态链接库(STATIC),后面的参数是需要用到的源文件。

B.链接

# test_account/CMakeLists.txt

# 最低版本要求
cmake_minimum_required(VERSION 3.10)

# 项目名称
project(test_account)

# 添加执行文件
add_executable(test_account test_account.cpp)

# 添加头文件目录,如果不添加,找不到头文件
target_include_directories(test_account PUBLIC "../account_dir")
# 添加库文件目录,如果不添加,找不到库文件
target_link_directories(test_account PUBLIC "../account_dir/build")
# 添加目标链接库
target_link_libraries(test_account PRIVATE Account)
# 编译后目录如下
4.static_lib_test/
├── account_dir
│   ├── Account.cpp
│   ├── Account.h
│   ├── build
│   │   └── libAccount.a
│   └── CMakeLists.txt
└── test_account 
    ├── build
    │   └── test_account
    ├── CMakeLists.txt
    └── test_account.cpp

我们通过add_libraryadd_executable定义了Target,我们可以通过Target的名称为其添加属性,例如:

# 指定目标包含的头文件目录
target_include_directories(test_account PUBLIC "../account_dir")
# 添加库文件目录,如果不添加,找不到库文件
target_link_directories(test_account PUBLIC "../account_dir/build")
# 指定目标链接的库
target_link_libraries(test_account PRIVATE Account)
  • 通过target_include_directories,我们给test_account添加了头文件引用路径"../account_dir"。上面的关键词PUBLIC,PRIVATE用于说明目标属性的作用范围,更多介绍参考下节。
  • 通过target_link_libraries,将前面生成的静态库libAccount.a链接给对象test_account,但此时还没指定库文件的目录,CMake无法定位库文件
  • 再通过target_link_directories,添加库文件的目录即可。
2.3.5 生成动态库并连接

附件位置:5.dynamic_lib_test

A.生成动态库

#account_dir/CMakeLists.txt

# 添加动态库,Linux下会生成libAccount.so
add_library(Account SHARED Account.cpp Account.h)
# 编译动态库后,会在build下生成 build/libAccount.so 动态库文件
account_dir/
├── Account.cpp
├── Account.h
├── build
│   └── libAccount.so
└── CMakeLists.txt

B.链接

操作不变。

# ldd查看依赖的动态库
libAccount.so => /home/enpei/Documents/course_cpp_tensorrt/course_5/src/5.dynamic_lib_test/test_account/../account_dir/build/libAccount.so (0x00007fb692cf1000)

当然,也可以用一个CMakeLists.txt来一次性编译,参考附件6.build_together

#6.build_together/CMakeLists.txt`

# 最低版本要求
cmake_minimum_required(VERSION 3.10)

# 项目信息
project(test_account)

# 添加动态库
add_library(Account SHARED "./account_dir/Account.cpp" "./account_dir/Account.h")

# 添加可执行文件
add_executable(test_account "./test_account/test_account.cpp")

# 添加头文件
target_include_directories(test_account PUBLIC "./account_dir")
# 添加链接库
target_link_libraries(test_account Account)
2.3.6 CMake 中的 PUBLIC、PRIVATE、INTERFACE

CMake中经常使用target_...()类似的命令,一般这样的命令支持通过PUBLICPRIVATEINTERFACE关键字来控制传播。

target_link_libraries(A B)为例,从理解的角度来看

  • PRIVATE :依赖项B仅链接到目标 A,如果有C 链接了AC不会链接B
  • INTERFACE :依赖项B并不链接到目标A,如果有C 链接了AC会链接B
  • PUBLIC :依赖项B链接到目标 A,如果有C 链接了AC也会链接B

其实就是对象属性的传递,打个散烟的比方:

  • PRIVATE: 就是自己抽,不给别人抽
  • INTERFACE :就是自己不抽,给别人抽
  • PUBLIC :就是自己抽,也给别人抽

从使用的角度来说,如果有C链接了目标A

  • 如果B仅用于A的实现,且不在头文件中提供给C使用,使用PRIVATE
  • 如果B不用于A的实现,仅在头文件中作为借口给C使用,使用INTERFACE
  • 如果B既用于A的实现,也在头文件中提供给C使用,使用PUBLIC

举例:

# 创建库
add_library(C c.cpp)
add_library(D d.cpp)
add_library(B b.cpp)

# C是B的PUBLIC依赖项
target_link_libraries(B PUBLIC C)
# D是B的PRIVATE依赖项
target_link_libraries(B PRIVATE D)

# 添加可执行文件
add_executable(A a.cpp)

# 将B链接到A
target_link_libraries(A B)
  • 因为CBPUBLIC依赖项,所以C会传播到A
  • 因为DBPRIVATE依赖性,所以D不会传播到A
2.3.7 变量

附件位置:7.message_var_demo

像其他编程语言一样,我们应该将CMake理解为一门编程语言。我们也需要设定变量来储存我们的选项,信息。有时候我们通过变量来判断我们在什么平台上,通过变量来判断我们需要编译哪些Target,也通过变量来决定添加哪些依赖。

2.3.8 include引入其他代码

附件位置:8.include_demo

2.3.9 条件控制

附件位置:9.if_demo

正如前面所讲,应该把CMake当成编程语言,除了可以设置变量以外,CMake还可以写条件控制。

if(variable)
    # 为true的常量:ON、YES、TRUE、Y、1、非0数字
else()
    # 为false的常量:OFF、NO、FALSE、N、0、空字符串、NOTFOUND
endif()

可以和条件一起使用的关键词有

NOT, TARGET, EXISTS (file), DEFINED等
STREQUAL, AND, OR, MATCHES (regular expression), VERSION_LESS, VERSION_LESS_EQUAL等
2.3.10 CMake分步编译

附件位置:10.steps_demo

# 查看所有目标
$ cmake -S . -B build
$ cd build
$ cmake --build . --target help

The following are some of the valid targets for this Makefile:
... all (the default if no target is provided)
... clean
... depend
... rebuild_cache
... edit_cache
... steps_demo
... main.o
... main.i
... main.s



# 1.预处理
$ cmake --build . --target main.i
# 输出:Preprocessing CXX source to CMakeFiles/steps_demo.dir/main.cpp.i
# 可以打开滑到底部

# 2.编译
$ cmake --build . --target main.s
# 输出汇编代码:Compiling CXX source to assembly CMakeFiles/steps_demo.dir/main.cpp.s

# 3.汇编
$ cmake --build . --target main.o
# 输出二进制文件:Building CXX object CMakeFiles/steps_demo.dir/main.cpp.o

# 链接
$ cmake --build .
Scanning dependencies of target steps_demo
[ 50%] Linking CXX executable steps_demo
[100%] Built target steps_demo

# 运行
./steps_demo
2.3.11 生成器表达式

附件位置:11.generator_expression

生成器表达式简单来说就是在CMake生成构建系统的时候根据不同配置动态生成特定的内容。有时用它可以让代码更加精简,我们介绍几种常用的。

需要注意的是,生成表达式被展开是在生成构建系统的时候,所以不能通过解析配置CMakeLists.txt阶段的message命令打印,可以用类似file(GENERATE OUTPUT "./generator_test.txt" CONTENT "$<$<BOOL:TRUE>:TEST>")生成文件的方式间接测试。

在其最一般的形式中,生成器表达式是$<...>,尖括号中间可以是如下几种类型:

  • 条件表达式
  • 变量查询(Variable-Query)
  • 目标查询(Target-Query)
  • 输出相关的表达式
# 1.条件表达式:$<condition:true_string>,当condition为真时,返回true_string,否则返回空字符串
$<0:TEST>  
$<1:TEST>  
$<$<BOOL:TRUE>:TEST>

# 2.变量查询(Variable-Query)
$<TARGET_EXISTS:target>:判断目标是否存在
$<CONFIG:Debug>:判断当前构建类型是否为Debug

# 3.目标查询(Target-Query)
$<TARGET_FILE:target>:获取编译目标的文件路径
$<TARGET_FILE_NAME:target>:获取编译目标的文件名

4.输出相关表达式:用于在不同的环节使用不同参数,比如需要在installbuild环节分别用不同的参数,我们可以这样写:

add_library(Foo ...)
target_include_directories(Foo
    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)

其中$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>仅在build环节生效;而$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>仅在install环节生效。通过设定不同阶段不同的参数,我们可以避免路径混乱的问题。

2.3.12 函数和宏

附件位置:12.function_macro

# 定义一个宏,宏名为my_macro,没有参数
macro(my_macro)
    message("宏内部的信息")
    set(macro_var "宏内部变量test")
endmacro(my_macro)

# 定义一个函数,函数名为second_func,有两个参数
function(second_func arg1 arg2)
    message("第一个参数:${arg1}, 第二个参数:${arg2}")
endfunction(second_func)
2.3.13 设置安装

附件位置:13.install_demo

当需要发布项目时你需要指定项目文件的安装路径。下面的代码片段中,使用install安装demo_test,并分别将可执行文件安装在bin中,动态链接库和静态链接库都安装在lib,公共头文件安装在include。这里的路径都将添加${CMAKE_INSTALL_PREFIX}作为前缀(如果不设置CMAKE_INSTALL_PREFIX,则会安装到/usr/local 目录下)。实现安装的功能在你需要发布你项目给其他人使用时,非常有用。

# 设置安装
install(TARGETS demo_test
        RUNTIME DESTINATION bin # 可执行文件
        LIBRARY DESTINATION lib # 动态库
        ARCHIVE DESTINATION lib # 静态库
        PUBLIC_HEADER DESTINATION include # 公共头文件
)
2.3.14 寻找依赖 find_package

对于大部分支持了CMake的项目来说,均可以通过find_package找到对应的依赖库,参考附件:14.find_demo

# 使用find_package寻找<LibaryName>库,如果找到,一般都会有以下变量(库作者设置)
<LibaryName>_FOUND:表示是否找到
<LibaryName>_INCLUDE_DIR:表示头文件目录
<LibaryName>_LIBRARIES:表示库文件目录

假设我们编写了一个新的函数库,我们希望别的项目可以通过find_package对它进行引用,我们有两种办法:

  • 编写一个Find<LibraryName>.cmake,适用于导入非cmake安装的项目,参考附件:15.custom_find
  • 使用install安装,生成<LibraryName>Config.cmake文件,适用于导入自己开发的cmake项目,参考附件:16.custom_install_demo

三、opencv CMake示例

附件位置:17.demo_opencv/

安装OpenCV:sudo apt install libopencv-dev

依赖和链接OpenCV与常规的添加依赖并没有太多不同,同时OpenCV提供了cmake find package的功能,因此我们可以通过find_package方便的定位opencv在系统中的位置和需要添加的依赖。

find_package(OpenCV REQUIRED)

message("OPENCV INCLUDE DIRS: ${OpenCV_INCLUDE_DIRS}")
message("OPENCV LINK LIBRARIES: ${OpenCV_LIBS}")

如果cmake找到了OpenCV,配置cmake后,命令行会有如下输出:

OPENCV INCLUDE DIRS: /usr/include/opencv4
OPENCV LINK LIBRARIES: opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_stitching;opencv_video;opencv_videoio;opencv_aruco;opencv_bgsegm;opencv_bioinspired;opencv_ccalib;opencv_datasets;opencv_dnn_objdetect;opencv_dnn_superres;opencv_dpm;opencv_face;opencv_freetype;opencv_fuzzy;opencv_hdf;opencv_hfs;opencv_img_hash;opencv_line_descriptor;opencv_optflow;opencv_phase_unwrapping;opencv_plot;opencv_quality;opencv_reg;opencv_rgbd;opencv_saliency;opencv_shape;opencv_stereo;opencv_structured_light;opencv_superres;opencv_surface_matching;opencv_text;opencv_tracking;opencv_videostab;opencv_viz;opencv_ximgproc;opencv_xobjdetect;opencv_xphoto

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从入门到大牛,JMeter接口测试+接口自动化测试(超细整理)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 在进行接口测试、…

符号执行初识

一、符号执行概念 符号执行&#xff08;Symbolic Execution&#xff09;是一种程序分析技术&#xff0c;它 可以通过分析程序来得到让特定代码区域执行的输入。 符号执行的 目的 是在给定的时间内&#xff0c; 生成一组输入&#xff0c;并通过这些输入尽可能多的探索执行路径。…

C++ Qt 学习(一):Qt 入门

Qt6 安装教程 0. 基础知识 0.1 qmake 和 cmake 对比 qmake&#xff1a;qt 独有的代码构建工具cmake&#xff1a;C 通用的代码构建工具&#xff0c;绝大部分 C 开源项目都使用 cmake 管理代码qt 项目&#xff0c;没有特殊要求&#xff0c;使用 qmake 即可 0.2 Qt 3 个窗口类的…

MATLAB野外观测站生态气象数据处理分析实践应用

1.基于MATLAB语言 2.以实践案例为主&#xff0c;提供所有代码 3.原理与操作结合 4.布置作业&#xff0c;答疑与拓展 示意图&#xff1a; 以野外观测站高频时序生态气象数据为例&#xff0c;基于MATLAB开展上机操作&#xff1a; 1.不同生态气象要素文件的数据读写与批处理实现 …

微信小程序自定义弹窗阻止滑动冒泡catchtouchmove之后弹窗内部内容无法滑动

自定义弹窗 如图所示&#xff1a; 自定义弹窗内部有带滚动条的盒子区域 问题&#xff1a; 在盒子上滑动&#xff0c;页面如果超出一屏的话&#xff0c;也会跟着一起上下滚动 解决方案&#xff1a;给自定义弹窗 添加 catchtouchmove 事件&#xff0c;阻止冒泡即可 网上不少…

Linux 安装 Redis7.x

Linux 安装 Redis7.x 下载redis7检查linux版本检查是否有 gcc什么是 gcc查看 gcc 是否有安装 安装 redis7查看默认安装目录启动服务连接服务服务关闭Redis的删除卸载Redis数据类型 下载redis7 下载地址&#xff1a;https://download.redis.io/releases/ 检查linux版本 [root…

Oracle JDK 和OpenJDK两者有什么异同点

Oracle JDK 和 OpenJDK 是两种不同版本的 Java Development Kit&#xff08;Java 开发工具包&#xff09;&#xff0c;它们都提供了用于开发 Java 程序的一系列工具和库。以下是它们之间的一些主要异同点&#xff1a; 相同点&#xff1a; 功能&#xff1a;在大多数情况下&…

【C++入门 三】学习C++缺省参数 | 函数重载 | 引用

C入门 三 1.缺省参数1.1 缺省参数概念1.2 缺省参数分类 2. 函数重载2.1 函数重载概念2.2 C支持函数重载的原理--名字修饰(name Mangling) 3.引用3.1引用概念3.2引用特性3.3 常引用3.4 使用场景1. 做参数2. 做返回值 3.5 传值、传引用效率比较3.6引用和指针的区别 4.引用和指针的…

2023最新ChatGPT商业运营系统源码+支持GPT4/支持ai绘画+支持Midjourney绘画

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

Linux进程基础

文章目录 1.进程概念2.进程描述3.进程操作&#xff08;一&#xff09;3.1.进程查看3.2.进程获取3.3.进程终止3.4.进程创建 4.进程状态4.1.进程状态理论4.1.1.粗略理解4.1.2.深入理解 4.2.进程状态实现4.2.1.运行状态和浅度/深度睡眠4.2.2.暂停状态和停止并跟踪状态4.2.3.终止状…

19.4 Boost Asio 远程命令执行

命令执行机制的实现与原生套接字通信一致&#xff0c;仅仅只是在调用时采用了Boost通用接口&#xff0c;在服务端中我们通过封装实现一个run_command函数&#xff0c;该函数用于发送一个字符串命令&#xff0c;并循环等待接收客户端返回的字符串&#xff0c;当接收到结束标志go…

工作中的小tips:如何快速提取图片或者pdf上的文字,进行编辑?

工作中经常会碰到需要的材料是图片或者不能拷贝的pdf之类的情况&#xff0c;那么有没有办法快速从上面提取文字呢&#xff1f; 最近发现一个很好用的网站&#xff0c;百度翻译。首先说明一下&#xff0c;接下来的方法比较适合短一点的文字&#xff0c;像是大篇幅的那种不太适合…

Linux学习第30天:Linux 自带的 LED 灯驱动实验:驱动开发思维方式的转变势在必行

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 学习嵌入式Linux驱动开发整整30天了。今天简单做一个小结。因为之前的主要工作是做ARM的裸机开发&#xff0c;所以接触Linux以后感觉很多东西都变了。不仅仅包括…

如何选择安全又可靠的文件数据同步软件?

数据实时同步价值体现在它能够确保数据在多个设备或系统之间实时更新和保持一致。这种技术可以应用于许多领域&#xff0c;如电子商务、社交媒体、金融服务等。在这些领域中&#xff0c;数据实时同步可以带来很多好处&#xff0c;如提高工作效率、减少数据不一致、提高用户体验…

【Verilog 教程】7.3 Verilog 串行 FIR 滤波器设计

串行 FIR 滤波器设计 设计说明 设计参数不变&#xff0c;与并行 FIR 滤波器参数一致。即&#xff0c;输入频率为 7.5 MHz 和 250 KHz 的正弦波混合信号&#xff0c;经过 FIR 滤波器后&#xff0c;高频信号 7.5MHz 被滤除&#xff0c;只保留 250KMHz 的信号。 输入频率&#x…

uniapp 省市区三级联动选择器

还有半个小时下班&#xff0c;总想着发点光亮照耀他人。IT技术这东西&#xff0c;尤其是UI方面的东西&#xff0c;于用户体验至关重要&#xff0c;想想最近使用uni-data-picker的丑陋页面&#xff0c;自己重构了这个功能&#xff0c;新加实现&#xff0c;效果图如下&#xff0c…

使用 Curl 和 DomCrawler 下载抖音视频链接并存储到指定文件夹

项目需求 假设我们需要从抖音平台上下载一些特定的视频&#xff0c;以便进行分析、编辑或其他用途。为了实现这个目标&#xff0c;我们需要编写一个爬虫程序来获取抖音视频的链接&#xff0c;并将其保存到本地文件夹中。 目标分析 在开始编写爬虫之前&#xff0c;我们需要了…

【Linux】配置JDKTomcat开发环境及MySQL安装和后端项目部署

目录 一、jdk安装配置 1. 传入资源 2. 解压 3. 配置 二、Tomcat安装 1. 解压开启 2. 开放端口 三、MySQL安装 1. 解压安装 2. 登入配置 四、后端部署 1. 数据库 2. 导入.war包 3. 修改端口 4.开启访问 一、jdk安装配置 打开虚拟机 Centos 登入账号&#xff…

MySQL -- 内置函数

MySQL – 内置函数 文章目录 MySQL -- 内置函数一、日期函数1.current_date()获取年月日2.current_time()获取时分秒3.current_timestamp() / now()获得时间戳4.date_add()在日期的基础上加日期5.date_sub()在日期的基础上减去日期6. datediff()计算两个日期之间相差多少天7.案…

inquirer.js——交互式命令行用户界面

一、什么是inquirer.js 1、inquirer.js是一个开源的交互式命令行用户界面&#xff08;CLI&#xff09;库&#xff0c;可以让你轻松地与用户进行交互&#xff0c;获取用户输入并做出相应的处理。它的主要功能是提供了一系列常用的命令行交互界面组件&#xff0c;例如input、con…
最新文章