升级构建工具,从Makefile到CMake

2023-05-16

更多博文,请看音视频系统学习的浪漫马车之总目录

C/C++编译
浅析C/C++编译本质
一篇文章入门C/C++自动构建利器之Makefile
升级构建工具,从Makefile到CMake

上一篇文章一篇文章入门C/C++自动构建利器之Makefile介绍了构建项目的脚本工具Makefile,相比于手动执行gcc命令来说,已经方便了太多了。不过如果只用Makefile构建项目,会有一个问题,那就是不支持跨平台的问题,因为Makefile脚本中的命令是和具体平台绑定的,比如上篇文章就是用GNU的gcc命令,那如果项目要移植到其他不能使用gcc命令的平台,那又要重新写一套Makefile,这可不符合懒惰的程序员群体,所以支持跨平台语法又更简洁的CMake就应运而生了。

本文算是CMake的入门,阅读本文前建议先将前面2篇文章看完,至少也要看完一篇文章入门C/C++自动构建利器之Makefile,不然就会因为缺少对项目构建的整体认识而容易感到雾里看花。

CMake介绍

CMake官网开头已经把CMake的作用说得很清楚了:

CMake is an open-source, cross-platform family of tools designed to build, test and package software. CMake is used to control the software compilation process using simple platform and compiler independent configuration files, and generate native makefiles and workspaces that can be used in the compiler environment of your choice. The suite of CMake tools were created by Kitware in response to the need for a powerful, cross-platform build environment for open-source projects such as ITK and VTK.

上面有一段文字,一句话概括就是CMake是一段跨平台的构建脚本,可以根据具体平台上生成对应的makefile,所以CMake的本质还是生成makefile,然后还是通过makefile来构建项目,CMake本身不构建项目。

以下就从简单到复杂项目来谈一谈CMake如何使用,所用平台依旧是Ubuntu。

单目录单文件

首先在Demo1目录下创建源文件main.cpp:

#include <iostream>
  
int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

然后创建CMakeLists文件(根据规范,CMakeLists.txt这个名字是固定的):

ubuntu@VM-20-7-ubuntu:~/study/projects/CmakeDemo$ cd Demo1/
ubuntu@VM-20-7-ubuntu:~/study/projects/CmakeDemo/Demo1$ ls
main.cpp
#创建CMakeLists文件(名字固定)
ubuntu@VM-20-7-ubuntu:~/study/projects/CmakeDemo/Demo1$ vim CMakeLists.txt

编写CMakeLists.txt:

#指定cmake的版本号
cmake_minimum_required(VERSION 3.16)
#工程名称
project(CmakeDemo)
#指定C++版本
set(CMAKE_CXX_STANDARD 14)
#指定生成可执行文件名称和依赖的源文件(可以多个)
add_executable(CmakeDemo main.cpp)

可以看到,cmake脚本相比Makefile更加简洁,直接指定源文件和最终可执行文件即可(终于不用为那些gcc命令和中间的汇编、目标文件什么的操碎心了)。通过一句“add_executable”,仿佛就是一句“我用main.cpp生成可执行文件CmakeDemo ”,然后cmake命令就把对应的Makfile生成了。

cmake 命令格式:

cmake [选项] <现有构建路径>

ubuntu@VM-20-7-ubuntu:~/study/projects/CmakeDemo/Demo1$ cmake .
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ubuntu/study/projects/CmakeDemo/Demo1

此时cmake指令生成了很多文件,注意到熟悉的Makefile文件已经生成:
在这里插入图片描述
对于Makefile,那当然就是执行make指令去构建项目:

ubuntu@VM-20-7-ubuntu:~/study/projects/CmakeDemo/Demo1$ make 
Scanning dependencies of target CmakeDemo
[ 50%] Building CXX object CMakeFiles/CmakeDemo.dir/main.cpp.o
[100%] Linking CXX executable CmakeDemo
[100%] Built target CmakeDemo

可以很开心地看到可执行文件已经生成:
在这里插入图片描述
运行下:

ubuntu@VM-20-7-ubuntu:~/study/projects/CmakeDemo/Demo1$ ./CmakeDemo 
Hello, World!

没问题~~

单目录多文件

现在在原来的基础上进行调整,增加了Dog类:

ubuntu@VM-20-7-ubuntu:~/study/projects/CmakeDemo/Demo2$ ls
CMakeLists.txt  Dog.cpp  Dog.h  main.cpp

Dog.h:

#ifndef CMAKEDEMO_DOG_H
#define CMAKEDEMO_DOG_H


class Dog {
public:
    void shut();

};


#endif //CMAKEDEMO_DOG_H

Dog.cpp:

#include "Dog.h"
#include <iostream>

void Dog::shut() {
    std::cout << "I am dog!" << std::endl;
}

main.cpp:

#include "Dog.h"

int main() {
    Dog dog;
    dog.shut();
    return 0;
}

对应的CMakeLists.txt改动很小,只需要在add_executable中增加Dog类相关文件即可:

#指定cmake的版本号
cmake_minimum_required(VERSION 3.16)
#工程可执行文件名称
project(CmakeDemo1:)
#指定C++版本
set(CMAKE_CXX_STANDARD 14)
#指定生成可执行文件的源文件
add_executable(CmakeDemo main.cpp Dog.cpp Dog.h)

这样每次增加类都要修改CMakeLists.txt,想起Makefile有变量和通配符,那CMake有没有呢?

答案是肯定的。

#指定cmake的版本号
cmake_minimum_required(VERSION 3.16)
#工程可执行文件名称
project(CmakeDemo1:)
#指定C++版本
set(CMAKE_CXX_STANDARD 14)


# 查找目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
#指定生成可执行文件的源文件
add_executable(CmakeDemo ${DIT_SRCS})

只要增加aux_source_directory就可以得到目录下的所有文件,然后将所有文件赋值给一个变量DIR_SRCS,传给add_executable即可。

cmake有大量内置变量,有些是用来获取当前环境信息的,比如获取系统版本的CMAKE_SYSTEM_VERSION,有些用来获取当前工程信息的,比如获取工程目录的PROJECT_SOURCE_DIR,有些是用来改变构建过程的,比如编译 C++ 文件时的选项CMAKE_CXX_FLAGS。

官方变量文档就介绍了这些内置变量:cmake-variables

多目录多文件

还是刚才的工程源文件,不过将Dog类放到lib目录下,lib目录下创建一个CMakeLists.txt文件,用将Dog类打包为一个动态链接库,然后交给main.cpp链接为一个可执行文件。
在这里插入图片描述
lib中的CMakeLists.txt:

# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)

# 指定生成 Animal链接库,SHARED 表示生成动态链接库
add_library (Animal SHARED ${DIR_LIB_SRCS})

其实非常简单,用add_library 生成一个动态链接库libAnimal.so(前缀lib和后缀.so是系统自动会加上去的)

Demo3中的CMakeLists.txt:

#指定cmake的版本号
cmake_minimum_required(VERSION 3.16)
#工程可执行文件名称
project(Demo)
#指定C++版本
set(CMAKE_CXX_STANDARD 14)
# 添加一个子目录并构建该子目录。
add_subdirectory(lib)
#添加头文件目录,因为当前根目录的main.cpp需要引用到Dog.h头文件
include_directories(lib)
# 查找目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
#打印出DIR_SRCS变量用于调试
Message("DIR_SRCS = ${DIR_SRCS}")
#指定生成可执行文件的源文件
add_executable(Demo ${DIR_SRCS})
# 添加链接库
target_link_libraries(Demo Animal)

多目录这里重点有三个:

1.添加头文件目录:
因为当前根目录的main.cpp需要引用到Dog.h头文件,所以需要通过include_directories引用头文件目录,注意CMakeLists的目录是相对于当前CMakeLists文件而言的。

2.add_subdirectory,官方的说明是

Add a subdirectory to the build.

就是要让当前的CMakeLists可以执行到执指定子目录的CMakeLists进而构建子目录中的源文件,在这里就是通过子目录构建处对应的动态链接库libAnimal.so。

3.链接操作:

target_link_libraries(Demo Animal)

将生成的Demo可执行文件和动态链接库进行链接(当然这里还不是真正的链接,因为动态链接库是在运行时链接的)

多目录多文件标准化

上面的工程结构不太规范,比如CMake产生的文件和源文件放在一起,导致这一部分文件不方便统一处理,现在一般标准的工程结构是这样的:

在这里插入图片描述
一个build目录专门用于存放CMake产生的文件,工程源文件和库源文件分开存放在src和lib目录,工程根目录有个CMakeLists.txt用于管理全局的CMakeLists文件。

根目录的CMakeLists.txt:

CMAKE_MINIMUM_REQUIRED(VERSION 3.16)
  
PROJECT(Demo)
#引入2个子目录
ADD_SUBDIRECTORY(lib)
ADD_SUBDIRECTORY(src)

非常简单,将src和lib目录加入构建就好。

src的CMakeLists.txt:

#指定可执行文件输出路径为执行CMake的目录下的/scr/bin(/home/ubuntu/study/projects/CmakeDemo/Demo4/build/src/bin)
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
# 添加 lib 子目录
include_directories(../lib)
#添加头文件目录
include_directories(../lib)
# 查找目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
Message("DIR_SRCS = ${DIR_SRCS}")
Message("PROJECT_SOURCE_DIR = ${PROJECT_SOURCE_DIR}")
Message("PROJECT_BINARY_DIR = ${PROJECT_BINARY_DIR}")

#指定生成可执行文件的源文件
add_executable(Demo ${DIR_SRCS})
# 添加链接库
target_link_libraries(Demo Animal)

lib的CMakeLists.txt:

# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
#指定库的输出路径为lib(/home/ubuntu/study/projects/CmakeDemo/Demo4/build/lib)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
# 指定生成 Animal链接库
add_library (Animal SHARED ${DIR_LIB_SRCS})

由于需要在build下生成构建文件,所以需要在build中执行CMake:

ubuntu@VM-20-7-ubuntu:~/study/projects/CmakeDemo/Demo4/build$ cmake ..
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
DIR_SRCS = ./main.cpp
PROJECT_SOURCE_DIR = /home/ubuntu/study/projects/CmakeDemo/Demo4/src
PROJECT_BINARY_DIR = /home/ubuntu/study/projects/CmakeDemo/Demo4/build/src
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ubuntu/study/projects/CmakeDemo/Demo4/build

此时build文件已经生成构建文件Makefile和对应的构建结果文件lib和src,并且lib和src已经分别生成了各自对应的Makefile文件。
在这里插入图片描述
在build下执行make:
在这里插入图片描述
此时可执行文件和动态链接库已经生成,执行可执行文件:
在这里插入图片描述
完美~~

总结下,这里主要就是创建了一个根目录作为统领的CMakeLists.txt,并且修改原来src和lib的CMakeLists.txt一些产出路径,使得它们CMake产生的文件放在build下对应的目录,即工程的放在build目录,src和lib的分别放在build/src和build/lib目录。

最后的目录结构为:

ubuntu@VM-20-7-ubuntu:~/study/projects/CmakeDemo/Demo4$ tree
.
├── build
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   │   ├── 3.16.3
│   │   │   ├── CMakeCCompiler.cmake
│   │   │   ├── CMakeCXXCompiler.cmake
│   │   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   │   ├── CMakeSystem.cmake
│   │   │   ├── CompilerIdC
│   │   │   │   ├── a.out
│   │   │   │   ├── CMakeCCompilerId.c
│   │   │   │   └── tmp
│   │   │   └── CompilerIdCXX
│   │   │       ├── a.out
│   │   │       ├── CMakeCXXCompilerId.cpp
│   │   │       └── tmp
│   │   ├── cmake.check_cache
│   │   ├── CMakeDirectoryInformation.cmake
│   │   ├── CMakeOutput.log
│   │   ├── CMakeTmp
│   │   ├── Makefile2
│   │   ├── Makefile.cmake
│   │   ├── progress.marks
│   │   └── TargetDirectories.txt
│   ├── cmake_install.cmake
│   ├── lib
│   │   ├── CMakeFiles
│   │   │   ├── Animal.dir
│   │   │   │   ├── build.make
│   │   │   │   ├── cmake_clean.cmake
│   │   │   │   ├── CXX.includecache
│   │   │   │   ├── DependInfo.cmake
│   │   │   │   ├── depend.internal
│   │   │   │   ├── depend.make
│   │   │   │   ├── Dog.cpp.o
│   │   │   │   ├── flags.make
│   │   │   │   ├── link.txt
│   │   │   │   └── progress.make
│   │   │   ├── CMakeDirectoryInformation.cmake
│   │   │   └── progress.marks
│   │   ├── cmake_install.cmake
│   │   ├── libAnimal.so
│   │   └── Makefile
│   ├── Makefile
│   └── src
│       ├── bin
│       │   └── Demo
│       ├── CMakeFiles
│       │   ├── CMakeDirectoryInformation.cmake
│       │   ├── Demo.dir
│       │   │   ├── build.make
│       │   │   ├── cmake_clean.cmake
│       │   │   ├── CXX.includecache
│       │   │   ├── DependInfo.cmake
│       │   │   ├── depend.internal
│       │   │   ├── depend.make
│       │   │   ├── flags.make
│       │   │   ├── link.txt
│       │   │   ├── main.cpp.o
│       │   │   └── progress.make
│       │   └── progress.marks
│       ├── cmake_install.cmake
│       └── Makefile
├── CMakeLists.txt
├── lib
│   ├── CMakeLists.txt
│   ├── Dog.cpp
│   └── Dog.h
└── src
    ├── CMakeLists.txt
    └── main.cpp

总结

本文算是对CMake的入门,就作为一种抛砖引玉的作用吧,CMake本身也比较简单,详细的用法一般可以通过查CMake官方文档或者百度谷歌解决,有了CMake的基础,那么下一步就可以稳步向ndk进军啦(初探ndk的世界(一))。

如果觉得本文有帮助,别忘了点赞关注哦~

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

升级构建工具,从Makefile到CMake 的相关文章

  • gloox 获取花名册和联系人出席信息

    gloox 之 RosterManager 此类实现了jabber iq roster名空间中的Jabber XMPP花名册操作 它继承了 IqHandler PresenceHandler SubscriptionHandler 和 Pr
  • TCP/IP网络编程笔记--套接字和标准I/O

    一 定义 xff1a 标准I O是标准C库提供的对文件操作的函数接口 二 常见的标准I O函数 xff1a 1 fopen xff08 xff09 函数原型 xff1a FILE fopen xff08 const char path xf
  • C语言位运算符:与、或、异或、取反、左移和右移

    文章转载于 博客园 博主 夜真寒 链接地址 xff1a http www cnblogs com yezhenhan archive 2011 11 06 2238452 html 语言位运算符 xff1a 与 或 异或 取反 左移和右移
  • Linux系统之常用命令

    这几天在看教学视频 xff0c 里面在讲一些linux系统常用的命令 xff0c 虽然有一部分都很熟悉了 xff0c 但也有一些不太熟悉 xff0c 因此来总结一下 注 xff1a 本文并非介绍了linux下所有常用的命令 xff0c 而是
  • C++学习笔记--尽量以const,enum,inline替换#define

    本文内容整理自 Effective C 43 43 中文版 xff0c 主要讲述 C 43 43 中在一些场合使用 const enum inline 来替换 define 所带来的好处 1 const 当我们编写这样一条代码 xff1a
  • ROS分布式通信(可以查看话题但主机接受不到从机传输的消息)

    提示 xff1a 想要将nano上的传感器数据发回pc端从机进行计算 xff0c 但是pc端计算完后发布话题 xff0c nano上的主机可以查看到这个话题但却收不到消息 xff08 已经在主机配置好相应的消息类型 xff09 前言 提示
  • 用户身份认证

    0 背景 计算机本身无法判断坐在显示器前的使用者的身份 xff0c 也无法确认网络的另一端的是谁 为了明确是谁在访问服务器 xff0c 必须让客户端自报家门 通常核对一些登录者本人的信息 xff1a 密码 xff1a 只有本人知道的字符串信
  • 一款用过就舍不得换的播放器-potplayer(中文绿色版)/win64

    PotPlayer 是 KMPlayer 的原制作者姜龙喜先生 xff08 韩国 xff09 进入 Daum 公司后的新一代网络播放器 PotPlayer 的优势在于强大的内置解码器 xff1b 而 KMPlayer 的优势在于强大的定制能
  • (一) odroid-xu4交叉编译过程

    目录 文章目录 目录前言Toolchain安装过程总结 前言 现在转到ODROID xu4的平台 xff0c 需要安装ODROID xu4的交叉编译环境 xff0c 特此记录 xff01 本文参照ODROID Wiki Toolchain安
  • 使用OPENMV控制云台自动追踪Apriltag,测出与Apriltag距离并且通过串口发送给单片机。

    使用openmv控制云台自动跟踪Apriltag xff0c 并且将openmv与Apriltag距离通过串口发送到单片机 如果有openmv的同学直接将main py和pid py复制到flash中就可以了 注意 xff01 Aprilt
  • ubuntu 配置http

    1 去服务器上购买免费https服务并配置域名等 2 根据自己的网站服务器来选择下载不同的ssl证书 apache证书包括 1 root bundle crt 证书文件 2 xxx xxx xxx crt 证书文件 3 xxx xxx xx
  • C++中istringstream、ostringstream、stringstream详细介绍和使用

    C 43 43 中istringstream ostringstream stringstream介绍和使用 1 基于控制台的I O 注意 xff1a 提取符 34 gt gt 从流中提取数据时跳过输入流中的空格 tab键 换行符等空白字符
  • java httpClient Digest Auth 认证

    技术交流QQ群 933925017 java httpClient Digest Auth 认证 因为项目需要 请求海康摄像头 进行抓图以及云台控制等功能 海康有http协议 但是需要进行请求头认证 因为海康给的资料已经过时 所以找了很久
  • 锂电池充电过程及电路设计

    通常为了提高电池充电时的可靠性和稳定性 xff0c 我们会用电源管理芯片来控制电池充电的电压与电流 xff0c 但是在使用电源管理芯片设计充电电路时 xff0c 我们往往对充电电路每个时间段的工作状态及电路设计注意事项存在一些困惑 1 电池
  • 0Ω电阻到底能过多大电流

    0 电阻到底能过多大电流 xff1f 这个问题想必每位硬件工程师都查过 而与之相关的还有一个问题 xff0c 那就是0 电阻的阻值到底有多大 xff1f 这两个问题本来是很简单的 xff0c 答案应该也是很明确的 xff0c 但网上网友却给
  • linux进程控制函数--fork,exec,exit,wait,sleep

    1 fork 在linux系统中 xff0c 用户创建进程的唯一方法就是使用系统调用fork xff0c 大概要进行下面的操作 lt 1 gt 分配表项 xff0c 一个用户的进程项是有限的 xff1b lt 2 gt 创建子进程的进程标识
  • linux的用户模式和内核模式

    MS DOS等操作系统在单一的CPU模式下运行 xff0c 但是一些类Unix的操作系统则使用了双模式 xff0c 可以有效地实现时间共享 在Linux机器上 xff0c CPU要么处于受信任的内核模式 xff0c 要么处于受限制的用户模式
  • 阿里内推面试经历

    写在最前 其实主观上并不是很想写 xff0c 但坚持写完是希望能分享给准备进互联网实习或工作的同学或朋友一些经验和收获
  • 关于利用Openmp中使用的时间函数

    Openmp是一项并行化技术 xff0c 是可以提高串行化程序的运行效率的 xff0c 但需要使用正确的时间函数来进行衡量 首先 xff0c 先提出一个unix linux下的内核时间获取函数和一个omp h的一个库函数 1 clock 函
  • mybatis之映射文件

    mybatis框架如何实现java语句与数据库语句的分离 映射文件 通过在映射文件中写入动态sql语句 xff0c 完成增删改查操作 映射文件中的元素都包含在根节点 lt mapper gt lt mapper gt 下 xff0c map

随机推荐

  • mybatis之高级查询

    Mybatis中的高级查询主要通过关联查询 xff0c 集合查询或鉴别器来完成 其核心就是之前提到的通过resultMap标记来完成 1 关联查询 关联查询一般有三种方式 xff1a a 联合查询 利用resultMap的map xml中的
  • mybaits之动态sql

    mybaits除了提供连接数据库 xff0c 使java和数据库语句分离之外 xff0c 还有一个显著的特点就是使用动态sql语句 这些sql语句均写在map映射文件中 xff0c 并通过一系列标记来完成 1 if标记 常用形式 xff1a
  • 平衡二叉树-的四种旋转调整(代码,图解)

    平衡二叉树 的四种旋转调整 xff08 代码 xff0c 图解 xff09 1 右单旋 xff1a 新插入节点插入在较高左子树的左侧 xff08 左左右 xff09 xff0c 插入新节点二十 xff1a 1 修改parent和curLR的
  • 头文件里一般会加入的宏定义,为了避免一个头文件被重复调用

    华清视频里讲的 xff0c 写代码的时候 xff0c 头文件一般地都会加上一个类似这样的宏 xff0c 希望你从此以后再写头文件 xff0c 加上一个宏 加了这个有一个好处 xff0c 当你第一次包含tree h的时候 xff0c 如果没定
  • 自己组装Pixhawk F450无人机的一些细节

    首先参考文档为 xff1a 1 https mp weixin qq com s VXKU kIB v i0AX3zgtLig 2 https mp weixin qq com s Qzzl dQ6Tz2pXNp7Oj0lTg 3 http
  • 电机和桨叶要搭配选择

    拍自 四旋翼无人机的制作与飞行
  • 接收机PPM与SBUS

    最开始是自己弄ACfly的飞控时发现插接收机有两个位置 xff0c 一个PPM一个SBUS xff0c 我想直接移植Pixhawk的接收机或者无名的接收机到ACfly模块上 我最后发现Pixhawk和无名的也是留了两个给接收机 xff08
  • 现在发现如果无人机的电机不同,浆可能是不能混用的。

    现在发现如果无人机的电机不同 xff0c 浆可能是不能混用的 孔位不同 xff0c 我之前在无名那里买了很多浆 xff0c 觉得这次F330的浆没了可以用那个替 xff0c 我刚刚试了下发现插不进去 xff0c 不能通用 包括我刚才在店家那
  • 无人机电池似乎可以并联,串联组合

    之前总是见到这种奇怪的线 xff0c 一直不知道作什么用 xff0c 现在大概清楚了 是不是这样可以实现更长时间的续航 xff0c 我之前再ACfly的群里看到一个人的六轴是上面放了两个电池的 xff0c 他这可能也是并联的
  • 任务的三要素是任务主体函数,任务栈和任务控制块

    任务的三要素是任务主体函数 xff0c 任务栈和任务控制块 由xTaskCreateStatic 函数来把三者联合起立 下面拍自野火的 FreeRTOS内核实现与应用开发实战指南
  • 如何用Realsense D435i运行VINS-Mono等VIO算法 获取IMU同步数据

    摘自 xff1a https blog csdn net qq 41839222 article details 86552367 如何用Realsense D435i运行VINS Mono等VIO算法 获取IMU同步数据 Manii 20
  • Opencv安装与环境配置

    转载自 xff1a https blog csdn net sm16111 article details 81238324 Opencv安装与环境配置 代码敌敌畏 2018 07 27 15 46 24 50411 收藏 94 分类专栏
  • 串口参数详解:波特率,数据位,停止位,奇偶校验位

    转载自 xff1a https blog csdn net sinat 35705952 article details 89034455 串口参数详解 xff1a 波特率 xff0c 数据位 xff0c 停止位 xff0c 奇偶校验位 W
  • cpp-httplib库简单原理,听说你还不会开源库?

    cpp httplib库的原理 听说你还不会开源库 xff1f 介绍httplib h头文件的处理流程httplib h头文件的组成httplib h头文件搭建服务端与客户端的原理Get接口listen 0 0 0 0 8989 接口 介绍
  • UART串口调试

    转载自 xff1a https www secpulse com archives 157847 html UART串口调试 脉搏文库 TideSec 2021 04 23 4 356 0x00前言 前段时间陆陆续续的对光猫 路由器 摄像头
  • visca协议及其实现的简单认识

    转载自 xff1a https latelee blog csdn net article details 35811777 visca协议及其实现的简单认识 李迟 2014 06 30 14 09 01 7064 收藏 12 分类专栏 x
  • C语言实现的一个简单的HTTP程序

    转载自 xff1a https www cnblogs com xuwenmin888 archive 2013 05 04 3059282 html C语言实现的一个简单的HTTP程序 以下是参考 lt winsock网络编程经络 gt
  • ideavim使用

    IdeaVim 常用操作 IdeaVim简介 IdeaVim是IntelliJ IDEA的一款插件 xff0c 他提高了我们写代码的速度 xff0c 对代码的跳转 xff0c 查找也很友好 安装之后它在 Tools gt Vim Emula
  • CAN总线——数据传输故障处理

    最近遇到CAN总线通讯的问题 上位机为arm板 xff0c 核心板为Cortex A9处理器 Linux内核 下位机为5块 STM32板 现象为 xff1a 如果上位机只接收数据 xff0c 一切通讯正常 当上位机下发命令 xff0c 那么
  • 升级构建工具,从Makefile到CMake

    更多博文 xff0c 请看音视频系统学习的浪漫马车之总目录 C C 43 43 编译 浅析C C 43 43 编译本质 一篇文章入门C C 43 43 自动构建利器之Makefile 升级构建工具 xff0c 从Makefile到CMake