CMake 教程

2024-01-04

这篇文章主要介绍 CMake 的使用,看完这篇文章后,CMake 的绝大多数使用方法你都能掌握。本篇文章采用循序渐进的方法带你一步步逐渐进阶 CMake,通过多个示例,告诉你如何使用 CMake 解决常见的构建系统问题。

各位爱学习的朋友,收藏的同时点个赞行不,点赞的人多,这篇文章才能帮助到更多的人。

step0:环境配置

开始前说明一下,我的环境是 Windows10 + CMake + MinGW,MinGW 就是 GCC 的 Windows 移植版本。

环境安装我就不介绍了,不是这篇文章的重点,知乎有很多相关教程,这里提供相关工具下载链接:

  • 构建工具: Download | CMake
  • 编译工具: Downloads - MinGW-w64

需要注意的是,CMake 和 MinGW 安装好后,要手动添加到环境变量。

step 1:构建最小项目

最基本的项目是将一个源代码文件生成可执行文件。对于这么简单的项目,只需要一个三行的 CMakeLists.txt 文件即可,这是本篇教程的起点。在 step1 目录中创建一个 CMakeLists.txt 文件,如下所示:

cmake_minimum_required(VERSION 3.15) # set the project name project(Tutorial) # add the executable add_executable(Tutorial tutorial.cpp)

cmake_minimum_required 指定使用 CMake 的最低版本号, project 指定项目名称, add_executable 用来生成可执行文件,需要指定生成可执行文件的名称和相关源文件。

注意,此示例在 CMakeLists.txt 文件中使用小写命令。CMake 支持大写、小写和混合大小写命令。tutorial.cpp 文件在 step1 目录中,可用于计算数字的平方根。

// tutorial.cpp #include <cmath> #include <cstdlib> #include <iostream> #include <string> int main(int argc, char* argv[]) { if (argc < 2) { std::cout << "Usage: " << argv[0] << " number" << std::endl; return 1; } // convert input to double const double inputValue = atof(argv[1]); // calculate square root const double outputValue = sqrt(inputValue); std::cout << "The square root of " << inputValue << " is " << outputValue << std::endl; return 0; }

构建、编译和运行

现在就可以构建和运行我们的项目了,就是先运行 cmake 命令来构建项目,然后使用你选择的编译工具进行编译。

先从命令行进入到 step1 目录,并创建一个构建目录 build,接下来,进入 build 目录并运行 CMake 来配置项目,并生成构建系统:

mkdir build cd build cmake -G"MinGW Makefiles" ..

构建系统是需要指定 CMakeLists.txt 所在路径,此时在 build 目录下,所以用 .. 表示 CMakeLists.txt 在上一级目录。

Windows 下,CMake 默认使用微软的 MSVC 作为编译器,我想使用 MinGW 编译器,可以通过 -G 参数来进行指定,只有第一次构建项目时需要指定。

此时在 build 目录下会生成 Makefile 文件,然后调用编译器来实际编译和链接项目:

--build 指定编译生成的文件存放目录,其中就包括可执行文件, . 表示存放到当前目录,

在 build 目录下生成了一个 Tutorial.exe 可执行文件,试着执行它:

> Tutorial.exe 5 The square root of 5 is 2.23607

该程序计算 5 的平方根,从输出结果看已经得到了正确的结果。

此时目录结构为:

step1/ build/ CMakeLists.txt tutorial.cpp

外部构建与内部构建

这里创建了一个 build 目录存放编译产物,可以避免编译产物与代码文件混在一起,这种叫做外部构建。

还有一种内部构建,即直接在项目根目录下进行构建系统与编译,这时构建和编译命令就更改为:

cmake -G"MinGW Makefiles" . cmake --build .

内部构建会使得项目文件很混乱,一般直接用外部构建即可。

step 2:优化 CMakeLists.txt 文件

set 与 PROJECT_NAME

这是之前见过的 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.15) # set the project name project(Tutorial) # add the executable add_executable(Tutorial tutorial.cpp)

指定了项目名后,后面可能会有多个地方用到这个项目名,如果更改了这个名字,就要改多个地方,比较麻烦,那么可以使用 PROJECT_NAME 来表示项目名。

add_executable(${PROJECT_NAME} tutorial.cpp)

生成可执行文件需要指定相关的源文件,如果有多个,那么就用空格隔开,比如:

add_executable(${PROJECT_NAME} a.cpp b.cpp c.cpp)

我们也可以用一个变量来表示这多个源文件:

set(SRC_LIST a.cpp b.cpp c.cpp) add_executable(${PROJECT_NAME} ${SRC_LIST})

set 命令指定 SRC_LIST 变量来表示多个源文件,用 ${var_name} 获取变量的值。

于是原来的 CMakeLists.txt 文件就可以变成如下所示:

cmake_minimum_required(VERSION 3.15) # set the project name project(Tutorial) SET(SRC_LIST tutorial.cpp) # add the executable add_executable(${PROJECT_NAME} ${SRC_LIST})

这样看起来就很简洁。

添加版本号和配置头文件

我们可以在 CMakeLists.txt 为可执行文件和项目提供一个版本号。首先,修改 CMakeLists.txt 文件,使用 project 命令设置项目名称和版本号。

cmake_minimum_required(VERSION 3.15) # set the project name and version project(Tutorial VERSION 1.0.2) configure_file(TutorialConfig.h.in TutorialConfig.h)

然后,配置头文件将版本号传递给源代码:

configure_file(TutorialConfig.h.in TutorialConfig.h)

由于 TutorialConfig.h 文件这里被设置为自动写入 build 目录,因此需要将该目录添加到搜索头文件的路径列表中,也可以修改为写到其它目录。

将以下行添加到 CMakeLists.txt 文件的末尾:

target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_BINARY_DIR} )

PROJECT_BINARY_DIR 表示当前工程的二进制路径,即编译产物会存放到该路径,此时 PROJECT_BINARY_DIR 就是 build 所在路径。

然后手动创建 http://TutorialConfig.h.in 文件,包含以下内容:

// the configured options and settings for Tutorial #define Tutorial_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ #define Tutorial_VERSION_MINOR @PROJECT_VERSION_MINOR@ #define Tutorial_VERSION_PATCH @PROJECT_VERSION_PATCH@

当使用 CMake 构建项目后,会在 build 中生成一个 TutorialConfig.h 文件,内容如下:

// the configured options and settings for Tutorial #define Tutorial_VERSION_MAJOR 1 #define Tutorial_VERSION_MINOR 0 #define Tutorial_VERSION_PATCH 2

下一步在 tutorial.cpp 包含头文件 TutorialConfig.h,最后通过以下代码打印出可执行文件的名称和版本号。

if (argc < 2) { // report version std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "." << Tutorial_VERSION_MINOR << std::endl; std::cout << "Usage: " << argv[0] << " number" << std::endl; return 1; }

添加编译时间戳

有时候我们需要知道编译时的时间戳,并在程序运行时打印出来。

那就需要在 CMakeLists.txt 中添加如下这句:

string(TIMESTAMP COMPILE_TIME %Y%m%d-%H%M%S)

这表示将时间戳已指定格式保存到 COMPILE_TIME 变量中。

然后修改上面的 http://TutorialConfig.h.in 文件:

// the configured options and settings for Tutorial #define Tutorial_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ #define Tutorial_VERSION_MINOR @PROJECT_VERSION_MINOR@ #define Tutorial_VERSION_PATCH @PROJECT_VERSION_PATCH@ #define TIMESTAMP @COMPILE_TIME@

在构建项目后,TutorialConfig.h 文件就会自动增加一句:

#define TIMESTAMP 20230220-203532

这样就可以在源码中打印出 TIMESTAMP 的值了。

指定 C++ 标准

接下来将 step1/tutorial.cpp 源码中的 atof 替换为 std::stod ,这是 C++11 的特性,并删除 #include<cstdlib>

const double inputValue = std::stod(argv[1]);

在 CMake 中支持特定 C++标准的最简单方法是使用 CMAKE_CXX_STANDARD 标准变量。在 CMakeLists.txt 中设置 CMAKE_CXX_STANDARD 为11, CMAKE_CXX_STANDARD_REQUIRED 设置为True。确保在 add_executable 命令之前添加 CMAKE_CXX_STANDARD_REQUIRED 命令。

cmake_minimum_required(VERSION 3.15) # set the project name and version project(${PROJECT_NAME} VERSION 1.0) # specify the C++ standard set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True)

需要注意的是,如果你的gcc编译器版本够高,也可以不用指定 C++ 版本为 11。从 GCC 6.1 开始,当不指定任何版本 C++ 标准时,默认版本是 C++ 14,如果你想用 C++17 的语言,还是需要指定的。

修改完成后,需要对代码进行重新编译 cmake --build . ,此时可以不用进行项目构建。

此时目录结构为:

step2/ build/ CMakeLists.txt tutorial.cpp TutorialConfig.h.in

step 3:添加库

现在我们将向项目中添加一个库,这个库包含计算数字平方根的实现,可执行文件使用这个库,而不是编译器提供的标准平方根函数。

我们把库放在名为 MathFunctions 的子目录中。此目录包含头文件 MathFunctions.h 和源文件 mysqrt.cpp。源文件有一个名为 mysqrt 的函数,它提供了与编译器的 sqrt 函数类似的功能,MathFunctions.h 则是该函数的声明。

在 MathFunctions 目录下创建一个 CMakeLists.txt 文件,并添加以下一行:

# MathFunctions/CMakeLists.txt add_library(MathFunctions mysqrt.cpp)

表示添加一个叫 MathFunctions 的库文件。

CMake 中的 target 有可执行文件和库文件,分别使用 add_executable add_library 命令生成,除了指定生成的可执行文件名/库文件名,还需要指定相关的源文件。

此时文件结构为:

step3/ build/ MathFunctions/ CMakeLists.txt MathFunctions.h mysqrt.cpp CMakeLists.txt tutorial.cpp TutorialConfig.h.in

为了使用 MathFunctions 这个库,我们将在顶级 CMakeLists.txt 文件中添加一个 add_subdirectory(MathFunctions) 命令指定库所在子目录,该子目录下应包含 CMakeLists.txt 文件和代码文件。

可执行文件要使用库文件,需要能够找到库文件和对应的头文件,可以分别通过 target_link_libraries target_include_directories 来指定。

使用 target_link_libraries 将新的库文件添加到可执行文件中,使用 target_include_directories 将 MathFunctions 添加为头文件目录,添加到 Tutorial 目标上,以便 mysqrt.h 可以被找到。

顶级 CMakeLists.txt 的最后几行如下所示:

# add the MathFunctions library add_subdirectory(MathFunctions) # add the executable add_executable(${PROJECT_NAME} tutorial.cpp) target_link_libraries(${PROJECT_NAME} PUBLIC MathFunctions) # add the binary tree to the search path for include files # so that we will find TutorialConfig.h target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/MathFunctions )

MathFunctions 库就算添加完成了,接下来就是在主函数使用该库中的函数,先在 tutorial.cpp 文件中添加头文件:

#include "MathFunctions.h"

然后使用 mysqrt 函数即可:

const double outputValue = mysqrt(inputValue);

step 4:将库设置为可选项

现在将 MathFunctions 库设为可选的,虽然对于本教程来说,没有必要这样做,但对于较大的项目来说,这种情况很常见。

第一步是向顶级 CMakeLists.txt 文件添加一个选项。

option(USE_MYMATH "Use tutorial provided math implementation" ON)

option 表示提供用户可以选择的选项。命令格式为: option(<variable> "description [initial value])

USE_MYMATH 这个选项缺省值为 ON,用户可以更改这个值。此设置将存储在缓存中,以便用户不需要在每次构建项目时设置该值。

下一个更改是使 MathFunctions 库的构建和链接成为条件。于是创建一个 if 语句,该语句检查选项 USE_MYMATH 的值。

if(USE_MYMATH) add_subdirectory(MathFunctions) list(APPEND EXTRA_LIBS MathFunctions) list(APPEND EXTRA_INCLUDES ${PROJECT_SOURCE_DIR}/MathFunctions) endif() # add the executable add_executable(${PROJECT_NAME} tutorial.cpp) target_link_libraries(${PROJECT_NAME} PUBLIC ${EXTRA_LIBS}) # add the binary tree to the search path for include files # so that we will find TutorialConfig.h target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_BINARY_DIR} ${EXTRA_INCLUDES} )

在 if 块中,有 add_subdirectory 命令和 list 命令, APPEND 表示将元素 MathFunctions 追加到列表 EXTRA_LIBS 中,将元素 ${PROJECT_SOURCE_DIR}/MathFunctions 追加到列表 EXTRA_INCLUDES 中。 EXTRA_LIBS 存储 MathFunctions 库, EXTRA_INCLUDES 存储 MathFunctions 头文件。

变量 EXTRA_LIBS 用来保存需要链接到可执行程序的可选库,变量 EXTRA_INCLUDES 用来保存可选的头文件搜索路径。这是处理可选组件的经典方法,我将在下一步介绍现代方法。

接下来对源代码的进行修改。首先,在 tutorial.cpp 中包含 MathFunctions.h 头文件:

#ifdef USE_MYMATH #include "MathFunctions.h" #endif

然后,还在 tutorial.cpp 中,使用 USE_MYMATH 选择使用哪个平方根函数:

#ifdef USE_MYMATH const double outputValue = mysqrt(inputValue); #else const double outputValue = sqrt(inputValue); #endif

因为源代码使用了 USE_MYMATH 宏,可以用下面的行添加到 tutorialconfig.h.in 文档中:

// TutorialConfig.h.in #cmakedefine USE_MYMATH

现在使用 cmake 命令构建项目,并运行生成的 Tutorial 可执行文件。

build> cmake -G"MinGW Makefiles" .. build> cmake --build . build> Tutorial.exe 8 Computing sqrt of 8 to be 4.5 Computing sqrt of 8 to be 3.13889 Computing sqrt of 8 to be 2.84378 Computing sqrt of 8 to be 2.82847 Computing sqrt of 8 to be 2.82843 Computing sqrt of 8 to be 2.82843 Computing sqrt of 8 to be 2.82843 Computing sqrt of 8 to be 2.82843 Computing sqrt of 8 to be 2.82843 Computing sqrt of 8 to be 2.82843 The square root of 8 is 2.82843

默认调用 mysqrt 函数,也可以在构建项目时指定 USE_MYMATH 的值为 OFF:

> cmake -DUSE_MYMATH=OFF .. > cmake --build .

此时会调用自带的 sqrt 函数。

step 5:添加库的使用要求

使用要求会对库或可执行程序的链接、头文件包含命令行提供了更好的控制,也使 CMake 中目标的传递目标属性更加可控。利用使用要求的主要命令是:

  • target_compile_definitions()
  • target_compile_options()
  • target_include_directories()
  • target_link_libraries()

现在重构一下 step4 中的代码,使用更加现代的 CMake 方法来包含 MathFunctions 库的头文件。

首先声明,链接 MathFunctions 库的任何可执行文件/库文件都需要包含 MathFunctions 目录作为头文件路径,而 MathFunctions 本身不需要包含,这被称为 INTERFACE 使用要求。

INTERFACE 是指消费者需要、但生产者不需要的那些东西。在 MathFunctions/CMakeLists.txt 最后添加:

# MathFunctions/CMakeLists.txt target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} )

CMAKE_CURRENT_SOURCE_DIR 表示 MathFunctions 库所在目录。

现在我们已经为 MathFunctions 指定了使用要求 INTERFACE ,那么可以从顶级 CMakeLists.txt 中删除 EXTRA_INCLUDES 变量的相关使用:

if(USE_MYMATH) add_subdirectory(MathFunctions) list(APPEND EXTRA_LIBS MathFunctions) list(APPEND EXTRA_INCLUDES ${PROJECT_SOURCE_DIR}/MathFunctions) # 删除此行 endif() ... # add the binary tree to the search path for include files # so that we will find TutorialConfig.h target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_BINARY_DIR} ${EXTRA_INCLUDES} # 删除此行 )

现在只要是链接了 MathFunctions 库,就会自动包含 MathFunctions 所在目录的头文件,简洁而优雅。

这里补充两个知识点:

1、使用要求除了 INTERFACE ,还有 PRIVATE PUBLIC INTERFACE 表示消费者需要生产者不需要, PRIVATE 表示消费者不需要生产者需要, PUBLIC 表示消费者和生产者都需要。

2、这里使用 add_library 命令生成的 MathFunctions 库其实是静态链接库。动态库和静态库的区别是:静态库在 链接阶段 会被链接到最终目标中(比如可执行程序),缺点是同一个静态库如果被不同的程序引用,那么内存中会存在这个静态库函数的多份拷贝。动态库在链接阶段不会被拷贝最终目标中,程序在 运行阶段 才会加载这个动态库。所以多个程序就算引用了同一个动态库,内存中也只存在一份动态库函数的拷贝。

step 6:build 目录介绍

在文本中,我都是创建了一个 build 用来存放 cmake 构建和编译的产物,这里简单说下里面有些什么东西。

build/ CMakeCache.txt CMakeFiles/ cmake_install.cmake Makefile Tutorial.exe TutorialConfig.h MathFunctions/

其中 Makefile 是 cmake 根据顶级 CMakeLists.txt 生成的构建文件,通过该文件可以对整个项目进行编译。

Tutorial.exe 就是生成的可执行文件,通过该文件运行程序。

TutorialConfig.h 是用于配置信息的头文件,是 cmake 根据 TutorialConfig.h.in 文件自动生成的。

还有个 MathFunctions 文件夹:

MathFunctions/ CMakeFiles/ cmake_install.cmake Makefile libMathFunctions.a

其中 Makefile 是 cmake 根据 MathFunctions 目录下的 CMakeLists.txt 生成的构建文件。

libMathFunctions.a 则是 MathFunctions 静态链接库,可执行文件会通过这个库调用 mysqrt 函数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CMake 教程 的相关文章

  • 为什么使用abs()或fabs()而不是条件否定?

    在 C C 中 为什么要使用abs or fabs 不使用以下代码即可查找变量的绝对值 int absoluteValue value lt 0 value value 这与较低级别的指令较少有关吗 您提出的 有条件的abs 并不等于std
  • 在 C++ 中分割大文件

    我正在尝试编写一个程序 该程序接受一个大文件 任何类型 并将其分成许多较小的 块 我想我已经有了基本的想法 但由于某种原因我无法创建超过 12 kb 的块大小 我知道谷歌等上有一些解决方案 但我更感兴趣的是了解这个限制的根源是什么 然后实际
  • 为什么基类必须有一个带有 0 个参数的构造函数?

    这不会编译 namespace Constructor0Args class Base public Base int x class Derived Base class Program static void Main string a
  • 处理 fanart.tv Web 服务响应 JSON 和 C#

    我正在尝试使用 fanart tv Webservice API 但有几个问题 我正在使用 Json Net Newtonsoft Json 并通过其他 Web 服务将 JSON 响应直接反序列化为 C 对象 这里的问题是元素名称正在更改
  • 有什么工具可以说明每种方法运行需要多长时间?

    我的程序的某些部分速度很慢 我想知道是否有我可以使用的工具 例如它可以告诉我可以运行 methodA 花了 100ms 等等 或者类似的有用信息 如果您使用的是 Visual Studio Team System 性能工具 中有一个内置分析
  • Guid 应包含 32 位数字和 4 个破折号

    我有一个包含 createuserwizard 控件的网站 创建帐户后 验证电子邮件及其验证 URL 将发送到用户的电子邮件地址 但是 当我进行测试运行时 单击电子邮件中的 URL 时 会出现以下错误 Guid should contain
  • 获取从属性构造函数内部应用到哪个属性的成员?

    我有一个自定义属性 在自定义属性的构造函数内 我想将属性的属性值设置为属性所应用到的属性的类型 是否有某种方式可以访问该属性所应用到的成员从我的属性类内部 可以从 NET 4 5 using CallerMemberName Somethi
  • 为什么 BOOST_FOREACH 不完全等同于手工编码的?

    From 增强文档 http www boost org doc libs 1 48 0 doc html foreach html foreach introduction what is literal boost foreach li
  • 如何在 VS 中键入时显示方法的完整文档?

    标题非常具有描述性 是否有任何扩展可以让我看到我正在输入的方法的完整文档 我想查看文档 因为我可以在对象浏览器中看到它 其中包含参数的描述和所有内容 而不仅仅是一些 摘要 当然可以选择查看所有覆盖 它可能是智能感知的一部分 或者我不知道它并
  • 为什么 std::allocator 在 C++17 中丢失成员类型/函数?

    一边看着std 分配器 http en cppreference com w cpp memory allocator 我看到成员 value type pointer const pointer reference const refer
  • 单元测试失败,异常代码为 c0000005

    我正在尝试使用本机单元测试项目在 Visual Studios 2012 中创建单元测试 这是我的测试 TEST METHOD CalculationsRoundTests int result Calculations Round 1 0
  • “MyClass”的类型初始值设定项引发异常

    以下是我的Windows服务代码 当我调试代码时 我收到错误 异常 CSMessageUtility CSDetails 的类型初始值设定项引发异常 using System using System Collections Generic
  • std::bind 重载解析

    下面的代码工作正常 include
  • C# using 语句、SQL 和 SqlConnection

    使用 using 语句 C SQL 可以吗 private static void CreateCommand string queryString string connectionString using SqlConnection c
  • UWP 无法在两个应用程序之间创建本地主机连接

    我正在尝试在两个 UWP 应用程序之间设置 TCP 连接 当服务器和客户端在同一个应用程序中运行时 它可以正常工作 但是 当我将服务器部分移动到一个应用程序并将客户端部分移动到另一个应用程序时 ConnectAsync 会引发异常 服务器未
  • Qt - 设置不可编辑的QComboBox的显示文本

    我想将 QComboBox 的文本设置为某些自定义文本 不在 QComboBox 的列表中 而不将此文本添加为 QComboBox 的项目 此行为可以在可编辑的 QComboBox 上实现QComboBox setEditText cons
  • 通过等待任务或访问其 Exception 属性都没有观察到任务的异常

    这些是我的任务 我应该如何修改它们以防止出现此错误 我检查了其他类似的线程 但我正在使用等待并继续 那么这个错误是怎么发生的呢 通过等待任务或访问其 Exception 属性都没有观察到任务的异常 结果 未观察到的异常被终结器线程重新抛出
  • C# 搜索目录中包含字符串的所有文件,然后返回该字符串

    使用用户在文本框中输入的内容 我想搜索目录中的哪个文件包含该文本 然后我想解析出信息 但我似乎找不到该字符串或至少返回信息 任何帮助将不胜感激 我当前的代码 private void btnSearchSerial Click object
  • 如何在 GCC 5 中处理双 ABI?

    我尝试了解如何克服 GCC 5 中引入的双重 ABI 的问题 但是 我没能做到 这是一个重现错误的非常简单的示例 我使用的GCC版本是5 2 如您所见 我的主要函数 在 main cpp 文件中 非常简单 main cpp include
  • 以编程方式使用自定义元素创建网格

    我正在尝试以编程方式创建一个网格 并将自定义控件作为子项附加到网格中 作为 2x2 矩阵中的第 0 行第 0 列 为了让事情变得更棘手 我使用了 MVVM 设计模式 下面是一些代码可以帮助大家理解这个想法 应用程序 xaml cs base

随机推荐

  • [每周一更]-(第56期):不能不懂的网络知识

    作为程序员 在网络方面具备一定的知识和技能是非常重要的 以下是一些程序员需要熟练掌握的网络知识 基础网络概念 IP地址 了解IPv4和IPv6地址的格式和分配方式 以及常见的IP地址分类 子网掩码 理解子网掩码的作用 以及如何计算子网的大小
  • Win7系统提示找不到KBDUR1.DLL文件的解决办法

    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题 如果是新手第一时间会认为是软件或游戏出错了 其实并不是这样 其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库 这时你可以下载这个KBDUR1
  • Java版直播商城免 费 搭 建:平台规划与常见营销模式,电商源码、小程序、三级分销及详解

    saas云平台 打造全行业全渠道全场景的saas产品 为经营场景提供一体化解决方案 门店经营区域化 网店经营一体化 本地化 全方位 一站式服务 为多门店提供统一运营解决方案 提供丰富多样的营销玩法覆盖所有经营场景 助力商家成功 系统稳定压倒
  • 对 pcl::StatisticalOutlierRemoval 滤波器的理解

    对 pcl StatisticalOutlierRemoval 滤波器的理解 注 以下内容基于与 GPT 4 的交流并结合个人理解整理而成 若有描述不准确或模糊之处 欢迎指正 参数配置 setMeanK int meanK 此参数设置每个点
  • Win7系统提示找不到KBDUSA.DLL文件的解决办法

    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题 如果是新手第一时间会认为是软件或游戏出错了 其实并不是这样 其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库 这时你可以下载这个KBDUSA
  • Docker无法启动Postgresql容器

    目录 问题描述 解决问题 问题描述 拉取了一个Postgresql14 2的镜像 在 docker run 创建并运行容器之后使用 docker ps 发现容器没有跑起来 再次使用 docker start 也没跑起来 docker run
  • 太强了!利用 Python 连接 ES 查询索引某个字段命中数的脚本!

    当我们在工作中 如果频繁查询 Elasticsearch 某个索引中的某个字段命中的记录数量时 可以通过 Python 的 Elasticsearch 库来查询 从而提升工作效率 代码大致思路如下 第一步 从 elasticsearch 模
  • Java版企业电子招标采购系统源码——鸿鹄电子招投标系统的技术特点

    在数字化时代 采购管理也正经历着前所未有的变革 全过程数字化采购管理成为了企业追求高效 透明和规范的关键 该系统通过Spring Cloud Spring Boot2 Mybatis等先进技术 打造了从供应商管理到采购招投标 采购合同 采购
  • 德思特应用 | 革新MIMO无线电测试,精准测量10 MHz-8 GHz复杂射频信号!(二)

    来源 德思特测量测试 德思特应用 革新MIMO无线电测试 精准测量10 MHz 8 GHz复杂射频信号 二 原文链接 https mp weixin qq com s ScYnA3 09XT3Gp6SRg1n4Q 欢迎关注虹科 为您提供最新
  • NetCore Webapi XSRF/CSRF 跨站请求伪造过滤中间件

    XSRF Cross Site Request Forgery 和CSRF Cross Site Request Forgery 是一种常见的网络攻击方式 攻击者通过伪造请求将恶意操作发送到用户正在访问的网站 为了防止这种攻击 可以采取以下
  • 移植useradd到嵌入式Linux设备

    友情提示 前面一大段描述的是在老版本Ubuntu14 4交叉编译新版本shadow 过程曲折 没有结果 分割线后面一段是重新换了一个较老版本shadow 4 4 过程丝滑 结果喜人 诸君如耐心有限可直接划拉至分割线后部分内容 对于其他程序的
  • 如何查看电脑使用记录?分享4个可行方法!

    我在使用电脑时突然想查看一下电脑之前的使用记录 但是不知道应该怎么操作 有没有朋友知道应该怎么做呢 在日常生活和工作中 我们经常需要查看电脑的使用记录 例如访问过的网站 运行过的程序 文档编辑历史等 如何查看电脑使用记录呢 本文将给大家分享
  • Win7系统提示找不到KBDUGHR1.DLL文件的解决办法

    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题 如果是新手第一时间会认为是软件或游戏出错了 其实并不是这样 其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库 这时你可以下载这个KBDUGHR
  • 如何无需公网IP实现远程访问Windows本地WebDAV服务中存储文件

    文章目录 1 安装IIS必要WebDav组件 2 客户端测试 3 cpolar内网穿透 3 1 打开Web UI管理界面 3 2 创建隧道 3 3 查看在线隧道列表
  • BMS开发之面向对象思想(adbms1818)

    借鉴adbms1818的底层驱动代码 前言 adbms1818的主要用途就是不同种类的寄存器里面存储不同的数据 程序员需要通过特定的协议往寄存器里面写入或者读出数据 1 定义一个结构体 里面存储了adbms1818的所有寄存器的信息 然后我
  • SpringCloud之Eureka组件工作原理详解

    Eureka是一种服务注册与发现组件 最初由Netflix开发并开源出来 它主要用于构建分布式系统中的微服务架构 并提供了服务注册 服务发现 负载均衡等功能 在本文中 我们将详细解释Eureka的工作原理 一 Eureka概述 Eureka
  • 《知识扫盲》ROS和ROS2对比

    文章摘选自 ROS与ROS2对比 1 ROS问题举例 ROS的设计目标是简化机器人的开发 如何简化呢 ROS为此设计了一整套通信机制 话题 服务 参数 动作 通过这些通信机制 ROS实现了将机器人的各个组件给的连接起来 在设计这套通信机制的
  • Vue3.4的新变化

    解析器 3 4版本解析器速度提升2倍 提高了 SFC 构建性能 之前版本Vue 使用递归下降解析器 该解析器依赖于许多正则表达式和前瞻搜索 新的解析器使用基于htmlparser2中的标记生成器的状态机标记生成器 它仅迭代整个模板字符串一次
  • mybatis:使用SQL类的函数LIMIT、OFFSET指定从哪行开始查询、最多返回多少行

    org apache ibatis jdbc SQL类的OFFSET函数指定从哪行 行索引的位置 开始查询 LIMIT函数指定最多返回多少行 注意 第一行的行索引是0 而不是1 示例 mysql数据库user表的记录 mapper接口文件
  • CMake 教程

    这篇文章主要介绍 CMake 的使用 看完这篇文章后 CMake 的绝大多数使用方法你都能掌握 本篇文章采用循序渐进的方法带你一步步逐渐进阶 CMake 通过多个示例 告诉你如何使用 CMake 解决常见的构建系统问题 各位爱学习的朋友 收