CMake多工程最小实现

2023-05-16

背景:

最近团队的新项目开始基于CMake作为工程管理,结合VSCode作为IDE进行开发,一个原因当然是为了可支持跨平台。原来我们的开发环境是使用VS系列IDE进行开发,在底层框架完全改为CMake支持后,后续的项目开发也开始完全用CMake组织工程,虽然说的是使用VSCode开发,不过对于今天要总结的内容暂时不必要,所以,这次介绍使用CMake生成VS2015的工程,重点在CMakeLists.txt怎么写

由于真正用于项目开发的CMakeLists.txt已经非常庞大和复杂,所以这里我将简化一版自己的练习工程作为总结。


需要环境:

  • 演示操作系统:Windows
  • CMake工具:这里我用的是cmake-3.19.8-win64-x64
  • VS系列IDE:作为代码开发
  • VSCode:可选,如果有CMake-GUI,完全可以替代,无非就是配置后Configuration和Generation,只是我最近发现VSCode安装CMake相关插件后,可以修改后直接在根CMakeLists.txt里保存一下,就能生成工程了,非常方便。
  • 开发语言:C++
  • 引入三方框架:Qt (这里只介绍Qt,其它三方库同理)

达到结果:

既然是CMake多工程的最小实现,那么,一是多个工程,或者说必要的几类工程例子:动态库、静态库、可执行程序、Qt界面库,这些如何组织起来;二是最小实现,在满足如上库的工程能够组件起来的情况下,能够将CMake精简,首先理解最基础的命令即可。
所以,例子工程将实现在main中,调用简单动态库导出的一个接口并打印内容、调用静态库中一个计算函数并打印结果,调用界面库中的一个Qt界面类,并show出来。

在这里插入图片描述


实现步骤:

  1. 目录构建
  • 目录树:
Training
└─SourceCode
    ├─Product
    │  ├─Bin
    │  ├─Config
    │  └─Data
    └─Source
        ├─SampleLib
        │  ├─Include
        │  └─Src
        ├─SampleWidget
        │  ├─Include
        │  └─Src
        ├─TrainingApp
        │  ├─Include
        │  └─Src
        └─TrainingCore
            ├─Include
            └─Src
  • 以上是我所习惯的工程项目组织路径,具体介绍如下
  1. Training代码工程名;
  2. Training下的SourceCode则包含了工程代码(Source)和产物(Product)
  3. 产物Product内Bin是产物生成路径,所以工程编译生成的exe、dll等,会有一个拷贝的动作,拷贝到Bin下面的Release(或者Debug、MinSizeRel、RelWithDebInfo)子目录内;
  4. Product内的Config是软件启动所需要的如网络、数据库等的配置文件存放目录;
  5. Product内的Data是软件启动所需要的必要数据初始化,比如地图预加载数据之类的;
  6. Source内就是各自的工程了:
  • TrainingApp是main.cpp所在工程,是可执行程序例子工程,会依赖下面的三个例子工程,调用里面的接口或类;
  • SampleLib是静态库例子工程;
  • TrainingCore是动态库例子工程;
  • SampleWidget是带Qt界面的动态库例子工程;

SourceCode下
在这里插入图片描述
Source下
在这里插入图片描述
一个工程下,以TrainingApp为例
在这里插入图片描述


  1. CMakeLists.txt的组织
    接下来主要关心Source下的工程结构,首先是根CMakeLists.txt
    在这里插入图片描述
cmake_minimum_required(VERSION 3.9)

project(AlgorithmTraining VERSION 1.0.0)

# 避免find_package 设置_ROOT的警告
cmake_policy(SET CMP0074 OLD)

#--------------------------------------------------------------------
# 系统变量初始化
#--------------------------------------------------------------------
# 支持的Configuration
message("Generated with config types: ${CMAKE_CONFIGURATION_TYPES}")

#设置Product生成目录
SET(PRODUCT_EXECUTABLE_DIR ${CMAKE_SOURCE_DIR}/../Product/Bin/
                            ${PRODUCT_EXECUTABLE_DIR})
message(STATUS "PRODUCT_EXECUTABLE_DIR: " ${PRODUCT_EXECUTABLE_DIR})

# 设置Qt环境变量路径 or $ENV{QTDIR}
SET(CMAKE_PREFIX_PATH D:\\Qt\\Qt5.10.1\\5.10.1\\msvc2015_64)
message(STATUS "CMAKE_PREFIX_PATH: " ${CMAKE_PREFIX_PATH})

#--------------------------------------------------------------------
# 添加需要包含的模块
#--------------------------------------------------------------------
# install时需要的目录变量的module
include(GNUInstallDirs)
# 打包导出配置所需要的module
include(CMakePackageConfigHelpers)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

#--------------------------------------------------------------------
# 添加子目录
#--------------------------------------------------------------------
add_subdirectory(TrainingApp)
add_subdirectory(TrainingCore)
add_subdirectory(SampleLib)
add_subdirectory(SampleWidget)

#--------------------------------------------------------------------
# 添加自定义配置
#--------------------------------------------------------------------
# 生成后事件:创建<Configuration>目录
add_custom_target(TARGET ALL
    COMMAND ${CMAKE_COMMAND} -E make_directory ${PRODUCT_EXECUTABLE_DIR}/$<CONFIGURATION>)

接下来依次是子CMakeLists.txt:
可执行程序TrainingApp
在这里插入图片描述

# 工程名称
set(PROJECT_NAME TrainingApp)
project(${PROJECT_NAME}
    VERSION ${CMAKE_PROJECT_VERSION})

#------------------------------------------------
# 依赖库/框架
#------------------------------------------------

#--------------------------------------------------------------------
# 源代码文件
#--------------------------------------------------------------------
set(_Enter
    "${CMAKE_CURRENT_LIST_DIR}/Src/main.cpp"
 )
source_group(入口 FILES ${_Enter})

# 生成target
add_executable(${PROJECT_NAME}
    ${_Enter}
) 

#--------------------------------------------------------------------
# 工程依赖
#--------------------------------------------------------------------

# 路径寻址
target_include_directories(${PROJECT_NAME}
    PRIVATE
        ./Include
)

# 依赖库
target_link_libraries(${PROJECT_NAME} 
    PUBLIC
        TrainingCore
        SampleLib
        SampleWidget
)

#--------------------------------------------------------------------
# 事件
#--------------------------------------------------------------------

# 拷贝
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 
  COMMAND "${CMAKE_COMMAND}" -E copy 
     "$<TARGET_FILE:${PROJECT_NAME}>"
     "${PRODUCT_EXECUTABLE_DIR}/$<CONFIGURATION>/$<TARGET_FILE_NAME:${PROJECT_NAME}>" 
  COMMENT "Copying to product directory")

动态库TrainingCore
在这里插入图片描述

# 工程名称
set(PROJECT_NAME TrainingCore)
project(${PROJECT_NAME}
    VERSION ${CMAKE_PROJECT_VERSION})

#------------------------------------------------
# 依赖库/框架
#------------------------------------------------

#--------------------------------------------------------------------
# 源代码文件
#--------------------------------------------------------------------
set(_Export
    "${CMAKE_CURRENT_LIST_DIR}/Include/TrainingCoreExport.h"
)
source_group(导出 FILES ${_Export})

set(_Public
   "${CMAKE_CURRENT_LIST_DIR}/Include/TrainingCoreApplication.h"
   "${CMAKE_CURRENT_LIST_DIR}/Src/TrainingCoreApplication.cpp"
 )
source_group(公用方法 FILES ${_Public})

add_library(${PROJECT_NAME} SHARED 
    ${_Export}
    ${_Public}
) 

#--------------------------------------------------------------------
# 工程依赖
#--------------------------------------------------------------------

# 导出宏
target_compile_definitions(${PROJECT_NAME} PRIVATE TRAININGCORE_EXPORTS)

# 路径寻址
target_include_directories(${PROJECT_NAME}
    PRIVATE
        ./Include
)

#--------------------------------------------------------------------
# 事件
#--------------------------------------------------------------------

# 拷贝
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 
  COMMAND "${CMAKE_COMMAND}" -E copy 
     "$<TARGET_FILE:${PROJECT_NAME}>"
     "${PRODUCT_EXECUTABLE_DIR}/$<CONFIGURATION>/$<TARGET_FILE_NAME:${PROJECT_NAME}>" 
  COMMENT "Copying to product directory")

静态库SampleLib
在这里插入图片描述

# 工程名称
set(PROJECT_NAME SampleLib)
project(${PROJECT_NAME}
    VERSION ${CMAKE_PROJECT_VERSION})

#------------------------------------------------
# 依赖库/框架
#------------------------------------------------

#--------------------------------------------------------------------
# 源代码文件
#--------------------------------------------------------------------

# 生成target
add_library(${PROJECT_NAME} STATIC)

file(GLOB INC_FILES Include/*.h)
file(GLOB INC_FILES1 Src/*.h)
set(${PROJECT_NAME}_Includes
   ${INC_FILES}
   ${INC_FILES1}
)

aux_source_directory(Src CPP_FILES)
set(${PROJECT_NAME}_SRCS 
    ${CPP_FILES}
)

target_sources(${PROJECT_NAME}
    PRIVATE 
		${${PROJECT_NAME}_Includes}
        ${${PROJECT_NAME}_SRCS}
)

#--------------------------------------------------------------------
# 工程依赖
#--------------------------------------------------------------------

# 路径寻址
target_include_directories(${PROJECT_NAME}
    PRIVATE
        ./Include
)

#--------------------------------------------------------------------
# 事件
#--------------------------------------------------------------------

Qt界面库SampleWidget
在这里插入图片描述

# 工程名称
set(PROJECT_NAME SampleWidget)
project(${PROJECT_NAME}
    VERSION ${CMAKE_PROJECT_VERSION})

#------------------------------------------------
# 依赖库/框架
#------------------------------------------------

# Qt
find_package(Qt5
    COMPONENTS
        Core
        Gui
        Widgets
        LinguistTools
    REQUIRED
)
set(CMAKE_AUTOMOC ON)   # 自动处理moc文件
set(CMAKE_AUTORCC ON)   # 自动处理资源文件
set(CMAKE_AUTOUIC ON)   # 自动处理UI文件

#--------------------------------------------------------------------
# 源代码文件
#--------------------------------------------------------------------
set(_Export
    "${CMAKE_CURRENT_LIST_DIR}/Include/SampleWidgetExport.h"
)
source_group(导出 FILES ${_Export})

set(_UI
    "${CMAKE_CURRENT_LIST_DIR}/Include/SampleWidget.h"
    "${CMAKE_CURRENT_LIST_DIR}/Src/SampleWidget.cpp"
    "${CMAKE_CURRENT_LIST_DIR}/Src/SampleWidget.ui"
 )
source_group(界面 FILES ${_UI})

# 生成target
add_library(${PROJECT_NAME} SHARED 
    ${_Export}
    ${_UI}
) 

#--------------------------------------------------------------------
# 工程依赖
#--------------------------------------------------------------------

# 导出宏
target_compile_definitions(${PROJECT_NAME} PRIVATE SAMPLEWIDGET_EXPORTS)

# 路径寻址
target_include_directories(${PROJECT_NAME}
    PRIVATE
        ./Include
)

# 链接库
target_link_libraries(${PROJECT_NAME}  Qt5::Core Qt5::Gui Qt5::Widgets)

#--------------------------------------------------------------------
# 事件
#--------------------------------------------------------------------

# 拷贝
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 
  COMMAND "${CMAKE_COMMAND}" -E copy 
     "$<TARGET_FILE:${PROJECT_NAME}>"
     "${PRODUCT_EXECUTABLE_DIR}/$<CONFIGURATION>/$<TARGET_FILE_NAME:${PROJECT_NAME}>" 
  COMMENT "Copying to product directory")

  1. 通过VSCode执行CMake,build出最终的VS2015工程
  • 刚才说VSCode可选,是因为CMake的GUI完全可以满足,把根CMakeLists.txt拖进去,然后设置必要参数,Configure->Generate后,就在指定的build目录下生成了。
    在这里插入图片描述
  • 然后说下VSCode如何“爽快”地生成:
    需要安装CMake需要的插件:CMake、CMake Tools
  • 在VSCode中点击“打开文件夹”,选到Source目录(即根CMakeLists.txt的目录)
    在这里插入图片描述
    这个时候VSCode把目录树都加载好了
  • 需要选择指定生成的工程
    在这里插入图片描述
  • VSCode会弹出这个,选择VS14.0(或者按需选择)即可
    在这里插入图片描述
  • 然后每次修改了任意CMakeLists.txt后,只需在根的CMakeLists.txt内Ctrl+s保存下,它就自动给生成build目录,生成工程了:
    在这里插入图片描述
  • 然后查看目录就会发现Source下有“build”文件夹,里面就是生成的VS工程了:
    在这里插入图片描述

这里是用VS2015作为例子,现在就可以打开sln,进入熟悉的VS-IDE开发了


  1. 配置到直接F5启动调试
  • 进入熟悉的界面,先编译一下,看生成的产物有没有拷贝到指定目录。
    在这里插入图片描述
    在Product/Bin下面确实生成了Debug目录,里面有2个库和1个exe
    在这里插入图片描述
  • 这时候双击exe会提示缺Qt库,这很正常,使用Qt的Bin内的windeployqt.exe执行一下,就会获得所需要的Qt基础依赖库
    在这里插入图片描述
  • 如果想F5直接启动,那么就把TrainingApp设置为启动项目,然后配置下属性内的调试
    在这里插入图片描述
    然后“应用”,就可以愉快地F5启动了。

分享

最后分享这个练习工程的CMakeLists.txt必要的演示源码,放在网盘链接内,目录组织形式根据例子介绍的放入了,还包括一个CMake 3.19的Window安装包
大家可以基于这个安装包,结合上面的步骤,自己跑一遍,就基本熟悉CMake如何组建工程的了,然后就可以用这样的方法写自己的工程了,进而学习更复杂的CMake指令,以及更多的工程构建,包括跨平台如何支持的配置。

链接:https://pan.baidu.com/s/1Tta_s__yCCfGmeefMALzZA 提取码:lcc6

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

CMake多工程最小实现 的相关文章

  • 安卓串口调试记录(包括串口通信底层知识点)

    一 有关串口通信基本知识 有关波特率计算 xff08 参考链接 xff09 第一个字节的10位 xff08 1位起始位 0 xff0c 8位数据位和1位停止位 1 xff09 共占约1 05ms xff0c 这样可计算出其波特率约为 xff
  • Android通过jni调用本地c/c++接口方法总结

    网上有网友问android的原生应用 xff0c 上层java代码如何通过jni调用本地的c c 43 43 接口或第三方动态库 xff1f 之前搞过android应用开发和底层c c 43 43 接口开发都是一个人搞定 xff0c 觉得还
  • fastadmin使用fast\Http 发送post/get/patch等请求,参数为二维数组时候报错,怎么解决?

    之前受邀回答了这么一个问题 xff1a 在后端发请求时 xff0c 如果参数里面是数组 xff0c 就会报错 34 Array to string conversion 34 xff0c 大概意思就是数组转字符串的时候出错了 先说解决方法
  • 【单片机笔记】PWM信号与PPM信号简单理解

    PPM信号是航模遥控器输出的一种标准信号 xff0c 从PPM信号中可以获取7 9个通道的遥控指令数据 PPM看起来很像PWM xff0c 很多模型爱好者对于它们产生了误解 xff0c 有些朋友认为PPM和PWM就是一回事 xff0c 其实
  • /etc/init.d/rcS 导致无法进入系统

    使用putty 和 pscp 自制了一个生产脚本 xff0c 脚本中从windows复制程序和启动文件至linux系统中 xff0c 系统重启后 xff0c 提示如下信息 xff0c 找不到 etc init d rcS文件 can spa
  • C语言实现linux环境UDP协议接收发送数据

    C语言实现linux环境UDP协议接收发送数据 说明上代码运行结果 说明 闲来无事 xff0c 写了个C语言的UDP小程序 xff0c 程序新建了两个线程 xff0c 分别用来实现UDP数据到发送和接收 需要的直接拿去用 上代码 inclu
  • 【随问】网址中的www是什么意思?HTTPS和HTTP的区别是什么?

    一旦某个单位拥有了一个域名 xff0c 它就可以自己决定是否要进一步划分其下属的子域而不需要上级结构批准 所以 xff0c 当一个单位申请到一个域名后 xff0c 如腾讯申请了一个qq com xff0c 他就可以自己划分子域 这里就出现了
  • HTTP身份认证

    文章目录 HTTP身份认证概述BASIC认证DIGEST认证SSL客户端认证基于表单认证 HTTP身份认证 概述 某些Web页面只想让特定的人浏览 xff0c 或者仅本人可见 xff0c 未达到这个目标 xff0c 必不可少的就是认证功能
  • 不应该不知道C++的常用库

    非常惭愧 xff0c 我过去也仅仅了解boost STLport这样的库 xff0c 以及一些GUI库 xff0c 但是居然有如此众多的C xff0b xff0b 库 xff0c 其实令我惊讶 当然 xff0c 这个问题应该辩证的看 xff
  • Nginx配置完毕后不准发请求头header的解决办法

    目前项目架构是vue 43 springboot前后端分离的 xff0c 前端部署在nginx上 xff0c 后端启动接口服务 xff0c 并用nginx进行反向代理 部署完毕后 xff0c 后端就是怎么收取不到shiro的header中的
  • Win10问题篇:解决AMD家CPU机械,固态硬盘混用导致的卡顿(爆音)问题。

    有的朋友使用AMD Cpu机械固态混用会有的卡顿问题 xff0c 卡顿包括 爆音 xff0c 硬盘占用突然100 xff0c 游戏卡屏 我冷静分析加百度 xff0c 是IDE ATA ATAPI控制器驱动不一致导致 xff0c 换成一样的驱
  • ARM 搭建开源NAS平台

    最近用闲置的电脑配件装了台黑群晖 xff0c 从使用角度以及省电方面考虑 xff0c 个人认为ARM架构的NAS平台相较于X86更加省电 xff0c 正好手里有一块之前调试全志T3平台闲置下来的开发板 xff0c 开发板上正好有个SATA接
  • BMP085气压传感器驱动 &MS5611经验

    BMP085是新一代的小封装气压传感器 主要用于气压温度检测 在四轴飞行器上可以用作定高检测 该传感器属于IIC总线接口 依然沿用标准IIC驱动程序 使用该传感器需要注意的是我们不能直接读出转换好的二进制温度数据或者气压数据 必须先读出一整
  • PotPlayer下载与使用

    下载安装 说起来 xff0c Potplayer的下载其实并不轻松 xff0c 它在国内是没有自己的官网 xff1b 虽然你简单百度下 xff0c 总能找到下载网站 xff0c 但是并不能保证其安全和纯净 xff0c 个人建议从这个官网下载
  • QT多界面切换(登录跳转)

    多界面切换 xff08 QT登录跳转 xff09 应用程序中经常需要在多个界面中跳转切换 xff0c 最常见的就是登录跳转 xff0c 下面是简单过程实现 程序运行时 xff0c 显示登录界面 xff0c 点击登录后跳转至界面2执行具体业务
  • STM32 GPIO简单使用

    STM32 GPIO简单使用 IO初使化配置 GPIO Init xff08 xff09 span class token punctuation span GPIO InitTypeDef GPIO InitStructure span
  • L298电机驱动模块STM32程序封装

    L298电机驱动模块STM32程序封装 程序可以控制电机驱动模块实现 前进 后退 左右转 停止 PWM速度调节 适用于多种电机奁动模块 1 适用模块 xff1a L298N电机驱动模块 TB6612F电机驱动模块 L293D电机驱动模块 2
  • C#,生成字符串整数校验码(Checksum)的谷歌(Google)算法与源代码

    如题 校验码系统是产生校验码并校验包括校验码在内的字符串的一套规则 它可以防止在抄录和键入字符串时产生的错误 一般生成 MD5 校验 xff0c 也可以生成 进行简单 快速的 整数 校验 谷歌开源 xff0c 很实用的整数校验码生成代码 u
  • AD常用快捷键(自用)

    走线角度切换 xff1a shift 43 空格 走线线宽切换 xff1a shift 43 W 快速查找元件 xff1a J 43 C 快速对齐 xff1a a 查看相同网络连接 xff1a Alt 43 单击网络 切换单层显示和多层显示
  • stm32软件仿真调试

    下面是一个单片机STM32RCT6的PA8 xff0c PA9 xff0c PA10引脚输出PWM波形的仿真步骤 xff0c 此外还展示了软件运行过程 xff0c 如何查看全局变量的实时数据 每一步我都做了截图 xff0c 大家照着一步步来

随机推荐

  • 电容种类特性

  • STM32F103 PB3,PB4,PA15,IO不可控问题

    STM32默认启动时PB4 PB3 PA15三个引脚不是普通IO xff0c 而是JTAG的复用功能 xff0c 分别为JNTRST JTDI JTDO 由上可以知要使PB3可以用 须关闭JTAG DP SW DP 可以不管 添加以下配置即
  • STM32CubeMX | STM32使用HAL库串口收发

    一 串口实现printf 1 hal配置 2 重定向代码 span class token comment USER CODE BEGIN Includes span span class token macro property span
  • 继电器开关阿里云IOT上云设置操作

    阿里云IOT继电器开关产品 阿里云IOT设备接入的入口有两个 一是物联网平台 xff0c 二是生活物联网平台 飞燕平台 xff09 飞燕平台主要是为生成APP用 xff0c 它创建的产品也会出现在物联网平台下 物联网平台下创建更方便配置相对
  • STM32定时器使用计算

    STM32F103ZE有8个定时器 xff0c 其中2个高级定时器 TIM1 TIM8 xff08 带死区控制 xff09 xff0c 4个通用定时器 xff08 TIM2 TIM3 TIM4 TIM5 xff09 xff0c 2个基本定时
  • lwip select函数分析和优化

    我的设备有两个网卡 xff0c 我需要开两路socket xff0c 一路UDP xff0c 一路TCP xff0c lwip的版本是1 4 1的 xff0c 实际运行发现 xff0c UDP 运行一段时间以后挂了 xff0c 通信挂了 x
  • curl并发 c++

    QQ技术交流群 xff1a 386476712
  • ROS组网

    参考ROS实战之ROS组网的搭建 ROS ROS命令 xff08 三 xff09 ROS 信息命令 其实整个过程比想象中简单的多 首先保证所有运行 ROS 的机器 xff08 no matter it is a raspberry or a
  • Ubuntu16.04下完美切换Python版本

    转载自http blog csdn net u013894834 article details 75305752 Ubuntu16 04下完美切换Python版本 xff08 亲测 xff09 对于ubuntu 16 04 xff0c 由
  • ArduPilot-sitl中的一些操作记录

    ArduPilot 这么优秀的代码 提供了一套很方便的SITL仿真开发模式 在git clone代码的时候 已经将相关的东西下载下来了 问题是如何进行使用 首先要安装mavproxy 这个软件 pymavlink mavlink封装的pyt
  • 烧写自定义ArduPilot到自定义的开发板

    写在前面的话 xff1a 本篇章内容参看 怒飞垂云 的资料 将APM固件移植到自制硬件 实际操作过程中 xff0c 需要如下几个步骤 xff1a 先在ardupilot中的 waf distclean 完成清理 xff0c 主要删除了bui
  • 跨域资源共享CORS的那些事(二)

    跨域资源共享CORS的那些事 xff08 二 xff09 最近在为高性能开源API网关apisix写跨域插件 xff0c 发现该功能对协议要求要比较熟悉 xff0c 借此机会重新复习下跨域协议 xff0c 以及简要写下跨域功能的设计 文章目
  • 宅家学习,如何进行Kubernetes Ingress控制器的技术选型?

    导语 xff1a 在Kubernetes的实践 部署中 xff0c 为了解决 Pod 迁移 Node Pod 端口 域名动态分配等问题 xff0c 需要开发人员选择合适的 Ingress 解决方案 面对市场上众多Ingress产品 xff0
  • Linux下connect()函数的错误代码对应含义

    Linux下connect 函数的错误代码对应含义 windows和linux下的connect系统接口有自己的一套返回码以及返回含义 Linux EBADF xff1a 参数socket未指定一个合法的描述符ENOTSOCK 参数sock
  • git设置用户名密码

    git设置用户名密码 设置git用户名 xff0f 邮箱 span class hljs comment git span span class hljs comment config span span class hljs litera
  • 'python' 不是内部或外部命令,也不是可运行的程序或批处理文件。

    python 不是内部或外部命令 xff0c 也不是可运行的程序或批处理文件 我将python安装在D盘之后 xff0c 输入python xff0c 显示如下问题 span class hljs keyword D span gt pyt
  • git pull时遇到error: cannot lock ref 'xxx': ref xxx is at (一个commitID) but expected的解决办法

    git pull时遇到error cannot lock ref xxx ref xxx is at xff08 一个commitID xff09 but expected的解决办法 在执行git pull时遇到如下错误 xff1a spa
  • tar.gz和tar.bz2解压命令

    tar gz和tar bz2解压命令 网络上下载到linux源码包主要是tar gz和tar bz2压缩格式的 xff0c 有一部分是zip 解压tar gz命令是 tar zxvf xx tar gz 解压tar bz2的命令是 tar
  • 使用VS CODE+PlantUML高效画图

    使用VS CODE 43 PlantUML高效画图 自从发现了plantuml写脚本画图的方式之后 xff0c 爱上了画图 环境 xff1a MAC 前言 本文多数内容引用自官网文档和其他人的教程 xff0c 并非本人原创 xff0c 也谈
  • CMake多工程最小实现

    背景 xff1a 最近团队的新项目开始基于CMake作为工程管理 xff0c 结合VSCode作为IDE进行开发 xff0c 一个原因当然是为了可支持跨平台 原来我们的开发环境是使用VS系列IDE进行开发 xff0c 在底层框架完全改为CM