Linux——CMake的快速入门上手和保姆级使用介绍、一键执行shell脚本
目录
一、前言
二、CMake简介
三、CMake与其他常见的构建、编译工具的联系
四、CMake入门
1、CMake的使用注意事项
2、基本的概念和术语
3、CMake常用的预定义变量
4、CMakeLists.txt文件的基本结构
五、上手实操
1、示例
编辑
2、一个正式的工程构建
2.1基本构建
2.2静态库和动态库的编译控制
六、shell脚本一键自动化方式
一、前言
在我们刚开始学习Linux系统编程的时候,我们就接触到了 Makefile ,它是用于自动化构建软件项目的工具,主要用于编译源代码文件、管理项目依赖关系。
Makefile 是一个文件。它是一个工程文件的编译规则,它记录了原始码如何编译的详细信息、描述了整个工程的编译链接等规则。
Makefile 存在的意义就是为了构建依赖关系和依赖原理。
Makefile 带来的好处是“自动化编译”,一旦写好的话,只需要一个make命令,整个工程的完全自动编译,极大的提高了软件开发的效率。
且大多数的IDE软件都是集成了make,例如Visual C++的 nmake,Linux下的 GNU make,Qt的 qmake等等,不同的IDE所集成的make工具所遵循的规范和标准都不同,也就导致其语法、格式不同,也就不能很好的跨平台编译,如果软件想跨平台,必须要保证能够在不同的平台上编译,如果使用上面的make工具的话,就得为每一个标准写一个Makefile文件,会再次使得工作繁琐起来。
所以CMake的出现允许开发者指定整个工程的编译流程,再跟据编译平台,生成本地化的Makefile和工程文件,最后只需要make编译即可。
二、CMake简介
CMake是“Cross Platform Make”的缩写,CMake是开源的、跨平台的构建工具,可以让我们通过简单的配置文件去生成本地的 Makefile ,这个配置文件时独立于运行平台和编译器的,这样就不用亲自去编写Makefile了,而且配置文件可以直接拿到其他平台上去使用,不用修改,非常的奈斯。
CMake的安装我们就直接跳过了,在网上随便可以找到。
安装好之后,我们可以使用 cmake -version 命令查看安装成功的cmake的版本
三、CMake与其他常见的构建、编译工具的联系
CMake有着跨平台自动化构建系统的特性,其不直接调用编译器进行构建,而是生成适用于目标平台的构建文件。通过 CMake,开发者可以编写一套与平台无关的配置文件(CMakeLists.txt)然后根据目标平台的不同,生成相应的构建文件。如Makefile或者Visual Studio工程文件等,从而简化了构建过程。
在这个构建生态系统中,GCC作为编译器,负责将源代码转换为可执行文件或库;Make工具根据Makefile中的指令执行编译和链接;而CMake则作为构建配置的中心,生成Makefile或其他构建脚本。此外,Ninja作为注重速度的构建工具,与CMake结合使用,进一步提高了构建的效率。
下面的表格清晰地展示了这些工具之间的相互关系及其在整个构建过程中地作用,表中还添加了其他相关工具的介绍。
工具名称 | 定义 | 使用场景 | 系统支持 | 使用实例 |
---|---|---|---|---|
CMake | 跨平台的自动化构建系统 | 多平台项目构建,生成 Makefile 等构建文件 | 跨平台 | cmake . 或 cmake --build . |
CMakeLists | CMake 项目配置文件 | 定义项目的构建规则和依赖关系 | 跨平台 | add_executable(myapp main.cpp) |
Make | 构建自动化工具 | 根据 Makefile 自动编译源代码 | Unix/Linux | make 或 make all |
Makefile | 构建规则文件 | 自定义编译指令和依赖关系 | Unix/Linux | all: main.o foo.o |
Ninja | 高效的构建系统 | 快速构建项目,支持并行编译 | 跨平台 | ninja 或 ninja -j 4 |
Autotools* | 包含 Autoconf、Automake 等工具 | 自动生成配置脚本和 Makefile | Unix/Linux | ./configure 然后 make |
configure | 配置脚本生成工具 | 检测系统环境,生成适合当前系统的构建脚本 | Unix/Linux | ./configure --prefix=/usr/local |
Autoconf | 配置脚本生成工具 | 检测系统特性,生成配置脚本 | Unix/Linux | autoconf 生成 configure 脚本 |
Automake | Makefile 生成工具 | 根据规则生成 Makefile | Unix/Linux | automake --add-missing |
GCC | GNU 编译器集合 | C、C++ 等多种语言的编译 | 跨平台 | gcc -o myapp main.c |
g++ | C/C++ 编译器 | 编译 C 或 C++ 源代码文件 | Unix/Linux | g++ -o myapp main.cpp |
c++ | C++ 编译器 | 编译 C++ 源代码文件 | Unix/Linux | c++ -o myapp main.cpp |
Clang | LLVM 项目的一部分 | C 语言家族的编译器前端,代码分析转换 | 跨平台 | clang -o myapp main.c |
GDB | GNU 调试器 | 调试 C/C++ 程序,提供断点、单步执行等功能 | Unix/Linux | gdb myapp |
ar | 静态库管理工具 | 创建、修改和提取静态库文件 | Unix/Linux | ar rcs libmyapp.a main.o |
ld | 链接器 | 将多个目标文件或库文件链接成可执行文件或库 | Unix/Linux | ld -o myapp main.o -L. -lmyib |
strip | 移除符号信息工具 | 减小可执行文件或库的大小 | Unix/Linux | strip myapp |
pkg-config | 库依赖管理工具 | 提供库的编译和链接参数 | Unix/Linux | pkg-config --cflags --libs gtk+-3.0 |
四、CMake入门
接下来我们将学习CMake地基本概念,其中包括项目定义、目标创建及如何通过CMakeLists.txt文件来控制整个的构建过程。
1、CMake的使用注意事项
- CMake构建专用定义文件,文件名严格区分大小写。在工程中使用 CMake 时,通常会在项目的根目录放置一个 CMakeLists.txt 文件来描述如何构建项目。这个文件名是固定的,不能随意更改。
- 工程存在多个目录的情况下,可以在每个目录下都放一个CMakeLists.txt文件,这有助于分层管理复杂的项目结构。通过这种方式,可以更方便地组织代码,并且可以对不同部分的源代码进行独立配置。
- 工程存在多个目录的情况下,也可以只使用一个CMakeLists.txt文件管理,这适用于较为简单的项目或者当开发者希望将所有构建逻辑集中在一个地方时。
- 严格区分大小写,在某些操作系统(如 Linux)上,文件系统是区分大小写的。这意味着 CMakeLists.txt和 cmakeLists.txt 会被视为两个不同的文件。因此,在这些平台上,必须确保文件名的大小写正确无误。然而,这条规则并不适用于文件内容中的变量命名或其他定义。
CMake支持大写、小写、混合大小写的命令。如果在编写CMakeLists.txt文件时使用的工具有对应的命令提示,那么大小写随缘即可,不要太过在意。
- 严格大小写相关,名称只能用字母、数字、下划线
- 使用 ${} 来引用变量
- 参数之间使用空格进行间隔
2、基本的概念和术语
- Project: 一个逻辑概念,定义了项目的名称和属性。
- Target: 构建系统中的一个目标,如可执行文件、库文件等。
- Source Files: 需要编译的源代码文件。
- Binary Directory: 存放编译生成的二进制文件的目录。
- Source Directory: 存放源代码的目录。
- Generator: 用于生成特定构建系统的程序,如Unix Makefiles。
- Variable: CMake中的变量,用于存储和传递配置信息。
- Command: CMake中的命令,用于执行构建配置的操作。
3、CMake常用的预定义变量
变量名 | 描述 | 示例值(取决于项目) |
---|---|---|
CMAKE_SOURCE_DIR | 顶层 CMakeLists.txt 所在的目录,即项目的根源代码目录。 | /home/user/myproject |
CMAKE_BINARY_DIR | 构建目录(运行 cmake 的目录)。 | /home/user/myproject/build |
CMAKE_CURRENT_SOURCE_DIR | 当前处理的 CMakeLists.txt 所在的源代码目录。 | /home/user/myproject/src/module |
CMAKE_CURRENT_BINARY_DIR | 当前处理的 CMakeLists.txt 对应的构建目录。 | /home/user/myproject/build/src/module |
CMAKE_CURRENT_LIST_FILE | 当前正在处理的 CMakeLists.txt 文件的完整路径。 | /home/user/myproject/src/CMakeLists.txt |
CMAKE_CURRENT_LIST_LINE | 当前执行的 CMake 命令在文件中的行号。 | 15 |
CMAKE_PROJECT_NAME | 通过project() 命令设置的项目名称。 | MyProject |
PROJECT_NAME | 同CMAKE_PROJECT_NAME ,但在子项目中可能不同(由project() 设置)。 | MyProject |
CMAKE_VERSION | 当前 CMake 的版本号。 | 3.25.1 |
CMAKE_SYSTEM | 目标系统的名称和版本。 | Linux-5.15.0 |
CMAKE_SYSTEM_NAME | 目标系统的名称(如 Linux、Windows、Darwin)。 | Linux |
CMAKE_SYSTEM_VERSION | 目标系统的版本号。 | 5.15.0 |
CMAKE_SYSTEM_PROCESSOR | 目标处理器架构(如 x86_64、arm64)。 | x86_64 |
CMAKE_C_COMPILER | C 编译器的完整路径。 | /usr/bin/gcc |
CMAKE_CXX_COMPILER | C++ 编译器的完整路径。 | /usr/bin/g++ |
CMAKE_BUILD_TYPE | 构建类型(如 Debug、Release、RelWithDebInfo)。 | Debug |
CMAKE_INSTALL_PREFIX | make install 安装文件的默认前缀路径。 | /usr/local |
CMAKE_MODULE_PATH | CMake 模块文件(如 Find*.cmake)的搜索路径列表。 | ["/home/user/myproject/cmake/Modules"] |
EXECUTABLE_OUTPUT_PATH | 可执行文件的输出目录。 | /home/user/myproject/build/bin |
LIBRARY_OUTPUT_PATH | 库文件的输出目录。 | /home/user/myproject/build/lib |
CMAKE_INCLUDE_PATH | 查找头文件的附加路径(类似 CFLAGS 中的 - I)。 | ["/usr/include/mylib"] |
CMAKE_LIBRARY_PATH | 查找库文件的附加路径(类似 LDFLAGS 中的 - L)。 | ["/usr/lib/mylib"] |
CMAKE_PREFIX_PATH | 查找依赖项的前缀路径列表(用于find_package 等)。 | ["/opt/myframework", "/usr/local"] |
CMAKE_AR | 归档工具(如 ar)的完整路径。 | /usr/bin/ar |
CMAKE_RANLIB | ranlib 工具的完整路径。 | /usr/bin/ranlib |
CMAKE_BUILD_PARALLEL_LEVEL | 并行构建的线程数(由-j 选项或环境变量设置)。 | 8 |
4、CMakeLists.txt文件的基本结构
CMakeLists.txt 是 CMake 的配置文件,用于定义项目的构建规则,下面是一个简单的示例
# 指定 CMake 的最低版本要求(不是必须的,这个version需要比本地使用的低就行)
cmake_minimum_required(VERSION 3.10)# 定义项目名称和使用的编程语言(不写默认情况支持所有语言) project(<PROJECT-NAME> [<language-name>...])
project(MyProject CXX)# 添加可执行文件目标 add_executable(可执行程序名 所有源文件名称.cpp)
add_executable(MyProgram main.cpp utils.cpp)# 添加编译选项
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O2")# 添加库文件(如果需要)
target_link_libraries(MyProgram some_library)# 注释单行行(# ) 注释多行CMake 使用 #[[ ]] 形式进行块注释
#[[ 这是一个 CMakeLists.txt 文件。
这是一个 CMakeLists.txt 文件
这是一个 CMakeLists.txt 文件]]
下面是对基本结构的解释
1、cmake_minimum_required(VERSION 3.10):指定CMake的最低版本要求,确保项目的构建依赖于特定版本的CMake特性
2、 project(MyProject CXX):指定项目名称为“MyProject”,并指定项目所使用的编程语言为C++
3、添加可执行文件
add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [source1] [source2 ...])
用于定义一个可执行文件目标(Executable Target),即告诉 CMake 如何编译并链接一组源文件以生成最终的可执行程序。
参数 含义 <name>
可执行文件的目标名称(输出文件名由 CMake 决定,如 myapp
,在 Windows 上会生成myapp.exe
)WIN32
有此参数时, WIN32_EXECUTABLE属性会被置为true, 此时在windows环境下创建的可执行文件将以WinMain函数代替main函数作为程序入口, 构建而成的可执行文件为GUI应用程序而不是控制台应用程序 MACOSX_BUNDLE
有此参数时, MACOSX_BUNDLE属性会被置为true, 此时在macOS或者iOS上构建可执行文件目标时, 目标会成为一个从Finder启动的GUI可执行程序 EXCLUDE_FROM_ALL
有此参数时, 此目标就会被排除在all target列表之外, 即在执行默认的make时, 不会构造此目标, 需要构造此目标的时候, 需要手动构建 source1 source2 ...
编译所需的源文件列表(C/C++/ObjC/ASM 等) 4、set的使用:
4.1定义变量
4.1.1一般变量
假设我们在工程中存在着许多的源文件(.cpp),这些源文件需要被反复使用,每次在使用的时候都需要将它们的名字写出来是很麻烦的,此时我们可以定义一个变量,将文件名对应的字符串存储起来。例如将生成可执行文件的源文件全都定义为一个变量,在后面使用时候直接使用该变量即可,就不用再输入一长串文件名了。
<variable>:要设置的变量名; <value1> <value2> ...:一个或多个值,会被合并成一个列表(空格分隔); [PARENT_SCOPE]:可选参数,表示将变量设置到父作用域中。
作用域说明:
CMake 的变量作用域是 函数/目录层级的。也就是说:
- 在某个
CMakeLists.txt
或函数中定义的变量,默认只在当前作用域可见;- 使用
PARENT_SCOPE
可以让变量“提升”一级,在父级作用域中可见。例如
set(SRC_LIST add.c div.c main.c mult.c sub.c)
4.1.2缓存变量
缓存变量是指那些被存储在
CMakeCache.txt
文件中的变量。这些变量不仅影响当前的配置和构建过程,而且在后续运行 CMake 配置命令时也会被记住和重用。因此,它们被称为“缓存”变量,因为它们就像是保存在项目根目录下的一个持久化存储(缓存),供未来的 CMake 配置会话使用。set(<variable> <value>... CACHE <type> <docstring> [FORCE]) //是用于**设置一个缓存变量(Cache Variable)**的标准语法。这类变量在 CMake 配置过程中会持久化 //保存到 CMakeCache.txt 文件中,非常适合用于配置选项、用户可修改的构建参数等。# variable:只能有一个 # value:可以有0个,1个或多个,当value值为空时,方法同unset,用于取消设置的值 # CACHE:关键字,说明是缓存变量设置## type(类型):必须为以下中的一种:## BOOL:有ON/OFF,两种取值## FILEPATH:文件的全路径## PATH:目录路径## STRING:字符串## INTERNAL:字符串## docstring:总结性文字(字符串) # [FORCE]:变量名相同,第二次调用set方法时,第一次的value将会被覆盖
例如
强制覆盖已有的缓存变量
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries" FORCE)
4.1.3环境变量
用于设置或清除环境变量(Environment Variables)
set(ENV{<variable>} [<value>])# variable:只能有一个 # value:一般来说,只有一个,为空时,将清除之前设置的变量值,多个时,取值最近的一个,之后的值将被忽略
4.2指定使用C++标准
我们在编写程序的时候,可能会用到C++11、C++14、C++17、C++20等新特性,所以就需要在编译的时候指出来。
#增加-std=c++11 set(CMAKE_CXX_STANDARD 11) #增加-std=c++14 set(CMAKE_CXX_STANDARD 14) #增加-std=c++17 set(CMAKE_CXX_STANDARD 17)
4.3指定输出的路径
set还可以定义一个变量用于存储一个绝对路径,设置文件的输出路径
# 定义一个变量用于存储一个绝对路径 set(HOME /home/robin/Linux/Sort) # 拼接好的路径值设置给CMAKE_RUNTIME_OUTPUT_DIRECTORY 宏,设置可执行程序输出目录 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${HOME}/bin)# 设置库文件的输出目录 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "D:/learn/C++/test/code/lib")# 设置静态库文件的输出目录 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "D:/learn/C++/test/code/lib")# 定义可执行文件 add_executable(MyProgram main.cpp) # 为特定目标设置输出目录 set_target_properties(MyProgram PROPERTIESRUNTIME_OUTPUT_DIRECTORY "D:/learn/C++/test/code/bin" )
5、搜索文件
如果在一个项目里的源文件很多,在编写CMakeLists.txt文件的时候不可能将项目目录中的各个文件一一列举出来,这样太过于麻烦,所以在CMake中为我们提供了搜索文件的命令:file
# GLOB: 将指定目录下搜索到的满足条件的所有文件名生成一个列表,并将其存储到变量中。 # GLOB_RECURSE:递归搜索指定目录,将搜索到的满足条件的文件名生成一个列表,并将其存储到变量中file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径和文件类型) file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) # CMAKE_CURRENT_SOURCE_DIR 这个存储路径就是cmakefile.txt所在的路径 # file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) # file(GLOB MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
6、指定头文件的搜索路径
当使用 CMake 管理 C++ 项目时,如果头文件所在的目录发生了变化,你不需要手动修改每一个引用该头文件的 .cpp 文件。相反,你只需要调整 CMake 的配置文件(通常是 CMakeLists.txt),就可以更新头文件的搜索路径。这种方法极大地简化了维护工作,并减少了出错的可能性。
set(headpath ${PROJECT_SOURCE_DIR}/include) include_directories(${headpath}) //告诉CMake是在${headpath}这个路径下寻找头文件,而不需要修改源代码中的 #include 指令。
但是这个是全局作用域,容易引起混乱,更推荐使用
target_include_directories(mytargetPRIVATE src/PUBLIC include/INTERFACE ../third_party/include )
7、CMake制作库文件
add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 [source2 ...]) set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)//设置库文件生成路径(放在哪里)
例子:
参数 含义 <name>
库名,是你为这个库指定的名称,比如 mylib
STATIC
表示这是一个静态库(.a 文件,在 Linux/macOS 上)或 (.lib 文件,在 Windows 上) SHARED
表示这是一个动态库(共享库,.so 文件在 Linux,.dll 在 Windows) MODULE
通常用于插件模块(不参与链接,仅加载),较少使用 EXCLUDE_FROM_ALL
可选参数,表示该库不会被默认构建,需要显式调用构建 source1 source2 ...
构建该库所需的源文件列表,如 .cpp
,.c
,.cc
等add_library(mylib STATIC src/mylib.cpp src/utils.cpp)
- 创建了一个名为
mylib
的静态库;- 使用了两个源文件
mylib.cpp
和utils.cpp
;- 编译完成后会生成类似
libmylib.a
(Linux/macOS) 或mylib.lib
(Windows)的静态库文件。add_library(mylib SHARED src/mylib.cpp src/utils.cpp)
- 创建的是一个动态库;
- 编译后生成
libmylib.so
(Linux)、libmylib.dylib
(macOS)或mylib.dll
(Windows)。8、链接库
target_link_libraries(<target> [PRIVATE|PUBLIC|INTERFACE] <item>...)
<target>
:你的目标名称,比如通过add_executable()
或add_library()
定义的名称。PRIVATE
:仅当前目标需要这个库;PUBLIC
:当前目标和依赖它的目标都需要这个库;INTERFACE
:仅依赖它的目标需要这个库。使用示例:
add_executable(myapp main.cpp) target_link_libraries(myapp PRIVATE mylib)
这样就只让
myapp
链接mylib
,不影响其他目标。9、在目录下查找所有的源文件
aux_source_directory(<dir> <varname>)
是一个用于自动收集目录中所有源文件路径的命令,常用于简化源码列表的定义。
参数 含义 <dir>
要扫描的目录(相对于当前 CMakeLists.txt
所在目录)<varname>
用于存储找到的所有源文件路径的变量名 功能说明
- 自动查找源文件:会递归查找指定目录下的所有
.c
,.cpp
,.cxx
,.m
,.mm
,.rc
,.inl
,.txx
等常见源代码文件;- 不包括子目录中的文件:只查找指定目录中的文件,不会进入其子目录;
- 生成一个包含所有源文件路径的列表:结果以相对路径形式保存在
<varname>
中;- 适用于小型项目或模块:对于结构简单、源文件数量不多的情况非常方便。
10、向当前工程添加存放源文件的子目录
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_BUILD])
用于将一个子目录添加到构建系统中,并处理该目录下的
CMakeLists.txt
文件。它是组织多模块、多层次项目的常用方式。
参数 含义 source_dir
必须参数,指定包含 CMakeLists.txt
的子目录路径(相对于当前CMakeLists.txt
所在目录)binary_dir
可选参数,指定该子目录构建输出的目标路径(默认与源路径一致) EXCLUDE_FROM_BUILD
可选参数,表示该子目录中的目标不会被默认构建(仅当被依赖时才会构建) 示例:
add_subdirectory(src) add_subdirectory(libs/utils)
这会依次进入
src/
和libs/utils/
目录,并执行其中的CMakeLists.txt
文件。11、打印输出信息
message(mode "message text" )
<mode>
:可选参数,指定消息的类型;"message text"
:要输出的消息内容(支持变量替换);
消息类型 行为说明 无模式(默认) 输出消息到标准输出(stdout),不带任何前缀 STATUS
输出状态信息(通常以 --
开头,用于显示进度或状态)WARNING
输出黄色警告信息(不影响配置继续执行) AUTHOR_WARNING
类似 WARNING
,但仅在启用CMAKE_SUPPRESS_DEVELOPER_WARNINGS
时生效SEND_ERROR
输出红色错误信息,配置继续,但会提示问题 FATAL_ERROR
输出红色严重错误信息,并立即终止配置过程 DEPRECATION
输出弃用警告(仅当 CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION
等相关设置启用时显示)12、搜索外部库
find_package(<PackageName> [version] [EXACT] [QUIET] [REQUIRED] [COMPONENTS <components...>])
是用于查找和加载外部依赖包(库、工具等)的配置信息,在使用第三方库(如 Boost、OpenCV、Qt 等)时非常关键。采用两种模式(FindXXX.cmake和XXXConfig.cmake)搜索外部库。
参数 含义 <PackageName>
要查找的包名(如 Boost
,OpenCV
,Threads
等)[version]
可选,指定所需版本号(如 3.4.1
)[EXACT]
可选,要求精确匹配版本号 [QUIET]
可选,禁止输出警告信息(即使未找到也不报错) [REQUIRED]
可选,表示该包必须存在,否则终止配置 [COMPONENTS ...]
可选,指定需要查找的子模块或组件
示例: find_package( OpenCV 3.4 REQUIRED )
搜索有两种模式
Module模式:搜索 CMAKE_MODULE_PATH 指定路径下的 FindXXX.cmake 文件,执行该文件从而找到XXX库。其中,具体查找库并给XXX_INCLUDE_DIRS和XXX_LIBRARIES两个变量赋值的操作由FindXXX.cmake模块完成。
Config模式:搜索XXX_DIR指定路径下的XXXConfig.cmake文件从而找到XXX库。其中具体查找库并给XXX_INCLUDE_DIRS和XXX_LIBRARIES两个变量赋值的操作由XXXConfig.cmake模块完成。
两种模式看起来似乎差不多,不过cmake默认采取Module模式,如果Module模式未找到库,才会采取Config模式。
如果XXX_DIR路径下找不到XXXConfig.cmake文件,则会找/usr/local/lib/cmake/XXX/中的XXXConfig.cmake文件。总之,Config模式是一个备选策略。通常,库安装时会拷贝一份XXXConfig.cmake到系统目录中,因此在没有显式指定搜索路径时也可以顺利找到。
若XXX安装时没有安装到系统目录,则无法自动找到XXXConfig.cmake,需要在CMakeLists.txt最前面添加XXX的搜索路径。
13、列表操作
LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules) list(LENGTH <list><output variable>) list(GET <list> <elementindex> [<element index> ...]<output variable>) list(APPEND <list><element> [<element> ...]) list(FIND <list> <value><output variable>) list(INSERT <list><element_index> <element> [<element> ...]) list(REMOVE_ITEM <list> <value>[<value> ...]) list(REMOVE_AT <list><index> [<index> ...]) list(REMOVE_DUPLICATES <list>) list(REVERSE <list>) list(SORT <list>)
- LENGTH: 返回list的长度
- GET: 返回list中index的element到value中
- APPEND: 添加新element到list中
- FIND: 返回list中element的index,没有找到返回-1
- INSERT: 将新element插入到list中index的位置
- REMOVE_ITEM: 从list中删除某个element
- REMOVE_AT: 从list中删除指定index的element
- REMOVE_DUPLICATES: 从list中删除重复的element
- REVERSE: 将list的内容反转
- SORT: 将list按字母顺序排序
五、上手实操
学习了cmake的基本用法,我们知道cmake命令会执行目录下的 CMakeLists.txt 配置文件里面的配置项,我们在实际的工程项目中的一个基本的CMakeLists.txt的配置文件内容如下:
cmake_minimum_required (VERSION 2.8) #要求cmake最低的版本号
project (demo) # 定义当前工程名字#用于配置构建类型为 Debug 模式,以便在编译时生成带有调试信息的可执行文件,
#方便使用调试器(如 GDB)进行断点调试。
set(CMAKE_BUILD_TYPE "Debug")#设置当前项目的构建类型为 Debug
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -g)#手动将 -g 添加到 C++ 编译选项中add_executable(main main.c)
#进入子目录下执行 CMakeLists.txt文件 这里的lib和tests里面都有可编译的代码文件
add_subdirectory(lib)
add_subdirectory(tests)
注:set(CMAKE_BUILD_TYPE "Debug")
- 效果:
- 编译器会生成带有调试信息的二进制文件(例如 GCC 的
-g
参数); - 不会进行优化(或仅进行极低程度的优化),便于调试;
- 常见构建类型包括:
Debug
:带调试信息;Release
:优化级别高,不带调试信息;RelWithDebInfo
:优化后的调试信息;MinSizeRel
:最小体积优化。
- 编译器会生成带有调试信息的二进制文件(例如 GCC 的
1、示例
在项目目录下创建了 main.cpp 再在同级目录下创建一个 CMakeLists.txt 文件
#CMakeLists.txt文件cmake_minimum_required(VERSION 3.0)#要求的cmake的最低版本号
project(demo) #定义当前工程的名字
set(CMAKE_BUILD_TYPE "Debug") #设置DEBUG模式
add_executable(main main.cpp)
#include<iostream>
int main()
{std::cout<<"This is a cmake test!"<<std::endl;return 0;
}
执行 cmake .
使用 ls 查看当前目录下的文件 ,可以看到目录下多出了很多文件,除了CMake生成的中间文件,还生成了Makefile文件
接着我们再使用 make 进行编译 ,可以看到生成了可执行文件 main
运行文件如下
Makefile中也实现了clean,使用make clean命令清除生成的文件如下
但是如果需要编译的有多个源文件的话,可以都添加到 add_executable(main main.cpp test.cpp) 列表当中,但是如果源文件太多,一个个添加到 add_executable(main main.cpp test.cpp) 的源文件列表中,就太过于麻烦了,此时可以用 aux_source_directory(dir var) 来定义源文件列表,使用如下
cmake_minimum_required (VERSION 2.8) project (demo) aux_source_directory(. SRC_LIST) # 定义变量SRC_LIST,存储当前目录下(.)的所有源文件 add_executable(main ${SRC_LIST})
但是同样 aux_source_directory() 也存在着弊端,它会把指定目录下的所有源文件都加进来,可能会加入一些我们不需要的文件,此时我们可以使用 set 命令去新建变量来存放需要的源文件,如下
cmake_minimum_required (VERSION 2.8) project (demo) set( SRC_LIST ./main.cpp ./test.cpp) add_executable(main ${SRC_LIST})
2、一个正式的工程构建
2.1基本构建
一个正式的源码工程应该有这几个目录
- bin:存放最终的可执行文件
- bulid:放的是构建该项目cmake编译什么的中间文件
- include:存放该项目的头文件
- src:存放该项目的源代码文件
CMakeLists.txt如下:
cmake_minimum_required (VERSION 2.8)project (math)# 设置二进制可执行文件的输出位置为${PROJECT_SOURCE_DIR}/bin
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)#添加头文件路径,相当于makefile里面的-I,这样编译器就能找到在 #include "xxx.h" 中引用的头文件。
include_directories(${PROJECT_SOURCE_DIR}/include)#将 src/ 目录下的所有 .cpp 文件收集到变量 SRC_LIST 中。不包括子目录中的源文件;
#如果以后加入其他语言文件(如 .c)也不会包含;
aux_source_directory (src SRC_LIST)add_executable (main main.cpp ${SRC_LIST})
然后在build目录里面执行cmake .. 命令,其中 .. 表示上一级目录,使用 cmake .. 表示cmake需要使用上一层目录下的CMakeLists.txt文件来配置项目,并生成Makefile文件。这样所有的编译中间文件都会在build目录下,最终的可执行文件会在bin目录里面
2.2静态库和动态库的编译控制
我们假设将上面的sum和minor源文件直接生成静态库或者动态库,让外部程序进行链接使用,结构如下
- lib:里面存放编译生成的库文件
- test:项目的测试代码
最外层的CMakeLists.txt是总控制编译,内容如下:
cmake_minimum_required (VERSION 2.8)
project (math)#进入到src和test目录下去执行CMakeLists.txt
add_subdirectory (test)
add_subdirectory (src)
src里面的源代码要生成静态库和动态库,CMakeLists.txt的內容如下
#设置库文件的生成路径
set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)# 生成库,动态库是SHARED,静态库是STATIC
add_library (sum SHARED sum.cpp)
add_library (minor SHARED minor.cpp)# set_target_properties用途是修改目标(target)在构建时生成的库文件名。修改库的名字
#set_target_properties (sum PROPERTIES OUTPUT_NAME "libsum")
#set_target_properties (minor PROPERTIES OUTPUT_NAME "libminor")
test 里面的 CMakeLists.txt 內容如下
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)include_directories (../include) # 头文件搜索路径link_directories (${PROJECT_SOURCE_DIR}/lib) # 库文件搜索路径add_executable (main main.cpp) # 指定生成的可执行文件target_link_libraries (main sum minor) # 执行可执行文件需要依赖的库
然后在bulid目录下执行cmake ..命令,接着执行make,可以查看生成的可执行文件了。
检验可执行文件其链接的库有哪些
六、shell脚本一键自动化方式
有了上面的手动构建项目方式,我们还有shell脚本的一件自动方式
我们还是拿示例一来举例子,在示例一的基础上在同级目录下新增一个 一键执行shell脚本文件 ,如下:
#cmake_build.sh#!/bin/bash
export LC_ALL=C# 获取脚本所在目录的绝对路径
curDIR=$(cd $(dirname $0); pwd)
projectMainDir="${curDIR}/build"
product_main_exe_name="product_cmake_test"function printResultBanner()
{echo -e "\n=========================================================>"echo -e "$1!!!"echo -e "=========================================================<"
}# 检查并创建构建目录
if [ ! -d ${projectMainDir} ];thenmkdir -p ${projectMainDir}
fi# 生成可执行文件并检查构建是否成功
cd ${projectMainDir}
rm -rf * && cmake .. && cmake .. && make clean && make
if [ $? -ne 0 ];thenprintResultBanner "FAILED : make compile errors and not continue !"exit 1
fi# 运行可执行程序
printResultBanner "INFO : Start To Run The Executable!!!"
${projectMainDir}/${product_main_exe_name}
if [ $? -ne 0 ];thenprintResultBanner "FAILED : run [${projectMainDir}/${product_main_exe_name}] errors and not continue !"exit 1
fi# 给出成功提示
printResultBanner "SUCCESS : Congratulations, all test cases have passed successfully!!!"
exit 0
执行shell脚本后就可以直接运行啦!
感谢阅读!
相关文章:
Linux——CMake的快速入门上手和保姆级使用介绍、一键执行shell脚本
目录 一、前言 二、CMake简介 三、CMake与其他常见的构建、编译工具的联系 四、CMake入门 1、CMake的使用注意事项 2、基本的概念和术语 3、CMake常用的预定义变量 4、CMakeLists.txt文件的基本结构 五、上手实操 1、示例 编辑 2、一个正式的工程构建 2.1基本构…...
GAN简读
Abstract 我们提出了一个通过同时训练两个模型的对抗过程来评估生成模型的新框架:一个生成模型 G G G用来捕捉数据特征,还有一个用于估计这个样本是来自训练样本还是 G G G的概率的判别模型 D D D, G G G的训练过程是最大化 D D D犯错的概率。这个框架就相当于一个minimax tw…...
Jsp技术入门指南【十四】实现基于MySQL+JDBC+JSP数据库验证的登录界面与登录跳转功能
Jsp技术入门指南【十四】实现基于MySQLJDBCJSP数据库验证的登录界面与登录跳转功能 前言第一步:加入驱动包与Maven第二步、创建并导入web库第三步、连接本地数据库的java代码核心代码讲解 第四步、创建数据库第五步、导入并修改JSP登录文件 前言 在之前的博客中&am…...
【漫话机器学习系列】259.神经网络参数的初始化(Initialization Of Neural Network Parameters)
神经网络参数初始化详解 在构建神经网络时,参数的初始化虽然只是一个开端步骤,但它对网络最终的训练效果和收敛速度有着至关重要的影响。本文将结合一张手绘风格图,深入浅出地讲解神经网络初始化的背景、方法及其数学依据,帮助大…...
如何设置FFmpeg实现对高分辨率视频进行转码
使用FFmpeg进行高分辨率视频转码的步骤如下:首先,确保FFmpeg支持GPU加速,通过命令ffmpeg -hwaccels检查CUDA支持。接着,下载样本视频进行测试,例如使用wget命令获取Blender基金会的样本视频。然后,使用FFmp…...
2025tg最新免费社工库机器人
中情局社工库 https://t.me/ZhongQingJuSGKBOT?start07c662145624d195aa098f0d39e6451d 小孩哥社工库 http://t.me/xiaohaigeSGK1_bot?startWGGVVrMgQiBslNE 冰墩墩个户机器人 t.me/bingdundung… 维基百科社工库 https://t.me/WikiSGKBot?start0b9d27c2e91b AI社工库…...
ps向pl传数据axi-4-lite
定义一个axi-4-lite ip,引出管脚 可以看到,ip的地址是这个 因为在定义axi-4-lite ip的时候定义了4个寄存器,其中只把第2个引出来,所以只需要往第2个写数据就可 即只有 (u32)(0x800000004) angle; 这个是有效的 这时pl就可以收到angle的值…...
scikit-learn在无监督学习算法的应用
哈喽,我是我不是小upper~ 前几天,写了一篇对scikit-learn在监督学习算法的应用详解,今天来说说关于sklearn在无监督算法方面的案例。 稍微接触过机器学习的朋友就知道,无监督学习是在没有标签的数据上进行训练的。其主要目的可能…...
聊聊JetCache的缓存构建
序 本文主要研究一下JetCache的缓存构建 invokeWithCached com/alicp/jetcache/anno/method/CacheHandler.java private static Object invokeWithCached(CacheInvokeContext context)throws Throwable {CacheInvokeConfig cic context.getCacheInvokeConfig();CachedAnnoC…...
【ios越狱包安装失败?uniapp导出ipa文件如何安装到苹果手机】苹果IOS直接安装IPA文件
问题场景: 提示:ipa是用于苹果设备安装的软件包资源 设备:iphone 13(未越狱) 安装包类型:ipa包 调试工具:hbuilderx 问题描述 提要:ios包无法安装 uniapp导出ios包无法安装 相信有小伙伴跟我一样&…...
浅析 Golang 内存管理
文章目录 浅析 Golang 内存管理栈(Stack)堆(Heap)堆 vs. 栈内存逃逸分析内存逃逸产生的原因避免内存逃逸的手段 内存泄露常见的内存泄露场景如何避免内存泄露?总结 浅析 Golang 内存管理 在 Golang 当中,堆…...
仿射变换 与 透视变换
仿射变换 与 透视变换 几种变换之间的关系 1、缩放 Rescale 1)变换矩阵 缩放变换矩阵,形为 : , 其中: 、 为 x轴 和 y轴的缩放因子,即 宽高的缩放因子 图像中的每一个像素点 (x, y),经过矩阵…...
Vue.js---嵌套的effect与effect栈
4.3嵌套的effect与effect栈 1、嵌套的effect effect是可以发生嵌套的 01 effect(function effectFn1() { 02 effect(function effectFn2() { /* ... */ }) 03 /* ... */ 04 })有这么一段代码: 01 // 原始数据 02 const data { foo: true, bar: true } 03 /…...
jQuery知识框架
一、jQuery 基础 核心概念 $ 或 jQuery:全局函数,用于选择元素或创建DOM对象。 链式调用:多数方法返回jQuery对象,支持连续操作。 文档就绪事件: $(document).ready(function() { /* 代码 */ }); // 简写 $(function…...
【Java学习笔记】hashCode方法
hashCode方法 注意:C要大写 作用:返回对象的哈希码值(可以当作是地址,真实的地址在 Java 虚拟机上),支持此方法是为了提高哈希表的性能 底层实现:实际上,由Object类定义的hashCod…...
[思维模式-37]:什么是事?什么是物?什么事物?如何通过数学的方法阐述事物?
一、基本概念 1、事(Event) “事”通常指的是人类在社会生活中的各种活动、行为、事件或情况,具有动态性和过程性,强调的是一种变化、发展或相互作用的流程。 特点 动态性:“事”往往涉及一系列的动作、变化和发展过程。例如&a…...
STM32-USART串口通信(9)
一、通信接口介绍 通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统。 当STM32想要实现一些功能,但是需要外挂一些其他模块才能实现,这就需要在两个设备之间连接上一根或多跟通信线,通过通信线路发送或者接…...
【内网渗透】——NTML以及Hash Relay
【内网渗透】——NTLM以及Hash Relay 文章目录 【内网渗透】——NTLM以及Hash Relay[toc]前情提要1.NTML网络认证机制1.1NTML协议1.2NET NTMLv21.3NTML的认证方式1.4NTLM hash的生成方法: 2.PTH(pass the hash)2.1原理2.2漏洞原理2.3实验环境2.4攻击过程…...
速查 Linux 常用指令 II
目录 一、网络管理命令1. 查看和配置网络设备:ifconfig1)重启网络命令2)重启网卡命令 2. 查看与设置路由:route3. 追踪网络路由:traceroute4. 查看端口信息和使用情况1)netstat 命令2)lsof 命令…...
基于 GPUGEEK平台进行vLLM环境部署DeepSeek-R1-70B
选择 GPUGEEK 平台的原因 算力资源丰富:GPUGEEK 提供多样且高性能的 GPU 资源,像英伟达高端 GPU 。DeepSeek - R1 - 70B 模型推理计算量巨大,需要强大算力支持,该平台能满足其对计算资源的高要求,保障推理高效运行。便…...
深入理解ThingsBoard的Actor模型
1、ThingsBoard系统中定义了哪些Actor ✅ ThingsBoard Actor 创建机制与作用对照表: Actor 类型 何时创建 由谁创建 是否缓存 作用描述 SystemActor 系统启动时 DefaultActorService / ActorSystem ✅ 是 ★ ThingsBoard 平台服务级别管理器:负责创建所有的Actor AppActor...
虚幻引擎5-Unreal Engine笔记之Qt与UE中的Meta和Property
虚幻引擎5-Unreal Engine笔记之Qt与UE中的Meta和Property code review! 文章目录 虚幻引擎5-Unreal Engine笔记之Qt与UE中的Meta和Property1.Qt 中的 Meta(元对象系统)1.1 主要功能1.2 如何实现1.2.1 例子1.2.2 访问 meta 信息 2.UE5 中的 Metaÿ…...
技术中台-核心技术介绍(微服务、云原生、DevOps等)
在企业数字化中台建设中,技术中台是支撑业务中台、数据中台及其他上层应用的底层技术基础设施,其核心目标是提供标准化、可复用的技术能力,降低业务开发门槛,提升系统稳定性与扩展性。技术中台的技术栈需覆盖从开发、运维到治理的…...
attention_weights = torch.ones_like(prompt_embedding[:, :, 0]):切片操作获取第二维度,第三维度
attention_weights = torch.ones_like(prompt_embedding[:, :, 0]):切片操作获取第1 维度,第二维度 attention_weights = torch.ones_like(prompt_embedding[:, :, 0]) 这行代码的作用是创建一个与 prompt_embedding[:, :, 0] 形状相同且所有元素都为 1 的张量,它用于初始化…...
2025年中国DevOps工具选型指南:主流平台能力横向对比
在数字化转型纵深发展的2025年,中国企业的DevOps工具选型呈现多元化态势。本文从技术架构、合规适配、生态整合三个维度,对Gitee、阿里云效(云效DevOps)、GitLab CE(中国版)三大主流平台进行客观对比分析&a…...
国产ETL数据集成软件和Informatica 相比如何
数据集成领域Informatica名号可谓无人不知无人不晓。作为国际知名的ETL工具,凭借其强大的功能和多年的市场积累,赢得了众多企业的信赖。然而,随着国内企业数字化转型的加速以及对数据安全、成本控制和本地化服务的需求日益增长,国…...
FFMPEG 与 mp4
1. FFmpeg 中的 start_time 与 time_base start_time 流的起始时间戳(单位:time_base),表示第一帧的呈现时间(Presentation Time)。通常用于同步多个流(如音频和视频)。 time_base …...
在RAG中 如何提高向量搜索的准确性?
在RAG(Retrieval-Augmented Generation)系统中,提高向量搜索的准确性需要从数据预处理、模型选择、算法优化和后处理等多个维度进行综合改进。以下是具体策略的详细分析: 一、优化数据质量与预处理 1. 数据清洗与结构化 去噪与规范化:去除停用词、拼写纠错、统一大小写和…...
Python调用SQLite及pandas相关API详解
前言 SQLite是一个轻量级的嵌入式关系数据库,它不需要独立的服务器进程,将数据存储在单一的磁盘文件中。Python内置了sqlite3模块,使得我们可以非常方便地操作SQLite数据库。同时,pandas作为Python数据分析的重要工具,…...
【Java学习笔记】finalize方法
finalize 方法 说明:实际开发中很少或者几乎不会重写finalize方法,更多的是应对面试考点 说明 (1)当对象被回收时,系统会自动调用该对象的 finalize 方法。子类可以重写该方法,做一些额外的资源释放操作&…...
MySQL之基础索引
目录 引言 1、创建索引 2、索引的原理 2、索引的类型 3、索引的使用 1.添加索引 2.删除索引 3.删除主键索引 4.修改索引 5.查询索引 引言 当一个数据库里面的数据特别多,比如800万,光是创建插入数据就要十几分钟,我们查询一条信息也…...
MCU程序加密保护(二)ID 验证法 加密与解密
STM32 微控制器内部具有一个 96 位全球唯一的 CPU ID,不可更改。开发者可利用此 ID 实现芯片绑定和程序加密,增强软件安全性。 ID 验证法就是利用这个 UID,对每颗芯片的身份进行识别和绑定,从而防止程序被复制。 实现方式…...
SparkSQL的基本使用
SparkSQL 是 Apache Spark 的一个模块,用于处理结构化数据。它提供了一个高性能、分布式的 SQL 查询引擎,可以轻松处理各种数据源,包括结构化数据、半结构化数据和非结构化数据12。 SparkSQL 的特点 易整合:SparkSQL 无缝整合了…...
QListWedget控件使用指南
QListWedget公共函数 函数签名功能描述QListWidget(QWidget *parent nullptr)构造函数,创建一个QListWidget对象,可指定父部件(默认为nullptr)。virtual ~QListWidget()虚析构函数,释放QListWidget对象及其资源。voi…...
primitive创建图像物体
本节我们学习使用entity来创建物体 我们以矩形为例,在输入矩形的四个点后运行程序 //使用entity创建矩形var rectangle viewer.entities.add({rectangle: {coordinates:Cesium.Rectangle.fromDegrees(//西边的经度90,//南边维度20,//东边经度110,//北边维度30 ),material:Ces…...
MySQL 服务器配置和管理(上)
MySQL 服务器简介 通常所说的 MySQL 服务器指的是mysqld(daemon 守护进程)程序,当运⾏mysqld后对外提供MySQL 服务,这个专题的内容涵盖了以下关于MySQL 服务器以及相关配置的内容,包括: • 服务器⽀持的启动选项。可以在命令⾏和…...
跨区域智能电网负荷预测:基于 PaddleFL 的创新探索
跨区域智能电网负荷预测:基于 PaddleFL 的创新探索 摘要: 本文聚焦跨区域智能电网负荷预测,提出基于 PaddleFL 框架的联邦学习方法,整合多地区智能电网数据,实现数据隐私保护下的高精度预测,为电网调度优化提供依据,推动智能电网发展。 一、引言 在当今社会,电力作为经…...
Java 重试机制详解
文章目录 1. 重试机制基础1.1 什么是重试机制1.2 重试机制的关键要素1.3 适合重试的场景2. 基础重试实现2.1 简单循环重试2.2 带延迟的重试2.3 指数退避策略2.4 添加随机抖动2.5 使用递归实现重试2.6 可重试异常过滤3. 常用重试库介绍3.1 Spring Retry3.1.1 依赖配置3.1.2 编程…...
Spark缓存---cache方法
在Spark 中,cache() 是用于优化计算性能的核心方法之一,但它有许多细节需要深入理解。以下是关于 cache() 的详细技术解析: 1. cache() 的本质 简化的 persist():cache() 是 persist(StorageLevel.MEMORY_ONLY) 的快捷方式&#…...
一分钟了解大语言模型(LLMs)
一分钟了解大语言模型(LLMs) A Minute to Know about Large Language Models (LLMs) By JacksonML 自从ChatGPT上线发布以来,在短短的两年多时间里,全球ChatBot(聊天机器人)发展异常迅猛,更为…...
当数控编程“联姻”AI:制造工厂的“智能大脑”如何炼成?
随着DeepSeek乃至AI人工智能技术在企业中得到了广泛的关注和使用,多数企业开始了AI探索之旅,迅易科技也不例外,且在不断地实践中强化了AI智能应用创新的强大能力。许多制造企业面临着工艺知识传承困难、编程效率低下等诸多挑战, 今…...
鸿蒙OSUniApp 实现的二维码扫描与生成组件#三方框架 #Uniapp
UniApp 实现的二维码扫描与生成组件 前言 最近在做一个电商小程序时,遇到了需要扫描和生成二维码的需求。在移动应用开发中,二维码功能已经成为标配,特别是在电商、社交和支付等场景下。UniApp作为一个跨平台开发框架,为我们提供…...
【Python 内置函数】
Python 内置函数是语言核心功能的直接体现,无需导入即可使用。以下是精选的 10 大类、50 核心内置函数详解,涵盖日常开发高频场景: 一、数据类型转换 函数示例说明int()int("123") → 123字符串/浮点数转整数float()float("3…...
鸿蒙OSUniApp开发支持多语言的国际化组件#三方框架 #Uniapp
使用UniApp开发支持多语言的国际化组件 在全球化的今天,一个优秀的应用往往需要支持多种语言以满足不同地区用户的需求。本文将详细讲解如何在UniApp框架中实现一套完整的国际化解决方案,从而轻松实现多语言切换功能。 前言 去年接手了一个面向国际市场…...
MySQL之基础事务
目录 引言: 什么是事务? 事务和锁 mysql数据库控制台事务的几个重要操作指令(transaction.sql) 1、事物操作示意图: 2.事务的隔离级别 四种隔离级别: 总结一下隔离指令 1. 查看当前隔离级别 …...
OpenHarmony系统HDF驱动开发介绍(补充)
一、HDF驱动简介 HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理、驱动消息机制和配置管理。 简单来说:HDF框架的驱动和Linux的驱动比较相似都是由配置文件和驱动…...
深度学习中的查全率与查准率:如何实现有效权衡
📌 友情提示: 本文内容由银河易创AI(https://ai.eaigx.com)创作平台的gpt-4-turbo模型辅助生成,旨在提供技术参考与灵感启发。文中观点或代码示例需结合实际情况验证,建议读者通过官方文档或实践进一步确认…...
文件名是 E:\20250512_191204.mp4, EV软件录屏,未保存直接关机损坏, 如何修复?
去github上下载untrunc 工具就能修复 https://github.com/anthwlock/untrunc/releases 如果访问不了 本机的 hosts文件设置 140.82.112.3 github.com 199.232.69.194 github.global.ssl.fastly.net 就能访问了 实在不行,从这里下载,传上去了 https://do…...
界面控件DevExpress WinForms v24.2 - 数据处理功能增强
DevExpress WinForms拥有180组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜…...
Web UI测试效率低?来试Parasoft Selenic的智能修复与分析!
如果你正在使用Selenium进行Web UI测试,但被测试维护的繁琐、测试不稳定以及测试执行缓慢等问题困扰,不妨试试Parasoft Selenic! Parasoft Selenic能够通过智能修复与分析功能,帮你自动检测并修复测试中的不稳定因素,…...