SLAM算法与工程实践——CMake使用(1)

news2025/2/27 17:30:07

SLAM算法与工程实践系列文章

下面是SLAM算法与工程实践系列文章的总链接,本人发表这个系列的文章链接均收录于此

SLAM算法与工程实践系列文章链接


下面是专栏地址:

SLAM算法与工程实践系列专栏


文章目录

  • SLAM算法与工程实践系列文章
    • SLAM算法与工程实践系列文章链接
    • SLAM算法与工程实践系列专栏
  • 前言
  • SLAM算法与工程实践——CMake使用(1)
    • Make 概述
    • CMake 构建项目2种方式:中央集权、地方分权
      • 第一种:中央集权式
      • 第二种:地方分权
    • CMake 的使用
      • 注释
        • 注释行
        • 注释块
      • 简单使用示例


前言

这个系列的文章是分享SLAM相关技术算法的学习和工程实践


SLAM算法与工程实践——CMake使用(1)

Make 概述

CMake 是一个项目构建工具,并且是跨平台的。关于项目构建我们所熟知的还有 Makefile(通过 make 命令进行项目的构建),大多是 IDE 软件都集成了 make,比如:VS 的 nmake、linux 下的 GNU make、Qt 的 qmake 等,如果自己动手写 makefile,会发现,makefile 通常依赖于当前的编译平台,而且编写 makefile 的工作量比较大,解决依赖关系时也容易出错。

而 CMake 恰好能解决上述问题, 其允许开发者指定整个工程的编译流程,在根据编译平台,自动生成本地化的Makefile和工程文件,最后用户只需 make 编译即可,所以可以把 CMake 看成一款自动生成 Makefile 的工具,其编译流程如下图:

在这里插入图片描述

  • 蓝色虚线表示使用 makefile 构建项目的过程

  • 红色实线表示使用 cmake 构建项目的过程

介绍完 CMake 的作用之后,再来总结一下它的优点:

  • 跨平台

  • 能够管理大型项目

  • 简化编译构建过程和编译过程

  • 可扩展:可以为 cmake 编写特定功能的模块,扩充

    cmake 功能

CMake 构建项目2种方式:中央集权、地方分权

一般来说,我们的工程是存在多个目录的。使用CMakeLists.txt构建工程有两种方法。

第一种:中央集权式

工程存在多个目录,只用一个CMakeLists.txt文件来管理

//include文件夹
include
	inc1.h
	inc2.h

//source文件夹
source
	srcl.cpp
	src2.cpp

//app为主函数文件夹
app
	main.cpp
  
//CMakeLists.txt和include、source及app位于同级目录下
CMakeLists.txt

一个典型的案例就是ORB-SLAM2代码,它只在最外层使用了一个CMakeLists.txt来构建整个工程。

第二种:地方分权

工程存在多个目录,每个源文件目录都使用一个CMakeLists.txt文件来管理。

//include文件夹
include
	incl.h
	inc2.h

//source文件夹下除了源文件,还有CMakeLists.txt文件
source
	srcl.cpp
	src2.cpp
	CMakeLists.txt

//app为主函数文件夹,其下除了源文件,还有CMakeLists.txt文件
app
	main.cpp
	CMakeLists.txt

//CMakeLists.txt和include、source及app位于同级目录下
CMakeLists.txt

一个典型的案例就是《视觉SLAM十四讲:从理论到实践》里的源代码,我们以该书第13章中的代码为例进行说明。

它在最外层使用了一个CMakeLists.txt来构建整个工程,如下所示。

cmake_minimum_required(VERSION 2.8)
project(myslam)

set(CMAKE_BUILD_TYPE Release)

set(CMAKE_CXX_FLAGS "-std=c++11 -Wall")
set(CMAKE_CXX_FLAGS_RELEASE  "-std=c++11 -O3 -fopenmp -pthread")

list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

############### dependencies ######################
# Eigen
include_directories("/usr/include/eigen3")

# OpenCV
find_package(OpenCV 3.1 REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})

# pangolin
find_package(Pangolin REQUIRED)
include_directories(${Pangolin_INCLUDE_DIRS})

# Sophus
find_package(Sophus REQUIRED)
include_directories(${Sophus_INCLUDE_DIRS})

# G2O
find_package(G2O REQUIRED)
include_directories(${G2O_INCLUDE_DIRS})

# glog
find_package(Glog REQUIRED)
include_directories(${GLOG_INCLUDE_DIRS})

# gtest
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})

# gflags
find_package(GFlags REQUIRED)
include_directories(${GFLAGS_INCLUDE_DIRS})

# csparse
find_package(CSparse REQUIRED)
include_directories(${CSPARSE_INCLUDE_DIR})

set(THIRD_PARTY_LIBS
        ${OpenCV_LIBS}
        ${Sophus_LIBRARIES}
        ${Pangolin_LIBRARIES} GL GLU GLEW glut
        g2o_core g2o_stuff g2o_types_sba g2o_solver_csparse g2o_csparse_extension
        ${GTEST_BOTH_LIBRARIES}
        ${GLOG_LIBRARIES}
        ${GFLAGS_LIBRARIES}
        pthread
        ${CSPARSE_LIBRARY}
        )

enable_testing()

############### source and test ######################
include_directories(${PROJECT_SOURCE_DIR}/include)
add_subdirectory(src)
add_subdirectory(test)
add_subdirectory(app)

CMake 的使用

CMake 支持大写、小写、混合大小写的命令。如果在编写 CMakeLists.txt 文件时使用的工具有对应的命令提示,那么大小写随缘即可,不要太过在意。

注释

注释行

CMake 使用 # 进行行注释,可以放在任何位置。

# CMakeLists.txt 注释
cmake_minimum_required(VERSION 3.0.0)
注释块

CMake 使用 #[[ ]] 形式进行块注释。

#[[ 这是一个 CMakeLists.txt 注释
这是一个 CMakeLists.txt 注释
这是一个 CMakeLists.txt 注释]]
cmake_minimum_required(VERSION 3.0.0)

简单使用示例

(1)准备工作,为了方便测试,在本地准备一下几个 .c 的测试文件

  • add.c
#include <stdio.h>
#include "head.h"

int add(int a, int b)
{
    return a+b;
}
  • sub.c
#include <stdio.h>
#include "head.h"

// 你好
int subtract(int a, int b)
{
    return a-b;
}
  • mult.c
#include <stdio.h>
#include "head.h"

int multiply(int a, int b)
{
    return a*b;
}
  • div.c
#include <stdio.h>
#include "head.h"

double divide(int a, int b)
{
    return (double)a/b;
}
  • head.h
#ifndef _HEAD_H
#define _HEAD_H
// 加法
int add(int a, int b);
// 减法
int subtract(int a, int b);
// 乘法
int multiply(int a, int b);
// 除法
double divide(int a, int b);
#endif
  • main.c
#include <stdio.h>
#include "head.h"

int main()
{
    int a = 20;
    int b = 12;
    printf("a = %d, b = %d\n", a, b);
    printf("a + b = %d\n", add(a, b));
    printf("a - b = %d\n", subtract(a, b));
    printf("a * b = %d\n", multiply(a, b));
    printf("a / b = %f\n", divide(a, b));
    return 0;
}

(2)上述文件的目录结构如下:

$ tree
.
├── add.c
├── div.c
├── head.h
├── main.c
├── mult.c
└── sub.c

(3)加 CMakeLists.txt 文件

在上述源文件所在目录下添加一个新文件 CMakeLists.txt,文件内容如下:

cmake_minimum_required(VERSION 3.0)
project(CALC)
add_executable(app add.c div.c main.c mult.c sub.c)

接下来依次介绍一下在 CMakeLists.txt 文件中添加的三个命令:

  • cmake_minimum_required:指定使用的 cmake 的最低版本
    • 可选,非必须,如果不加可能会有警告
  • project:定义工程名称,并可指定工程的版本、工程描述、web 主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
# PROJECT 指令的语法是:
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
       [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
       [DESCRIPTION <project-description-string>]
       [HOMEPAGE_URL <url-string>]
       [LANGUAGES <language-name>...])
  • add_executable:定义工程会生成一个可执行程序
add_executable(可执行程序名 源文件名称)

这里的可执行程序名和 project 中的项目名没有任何关系

源文件名可以是一个也可以是多个,如有多个可用空格或 ; 间隔

# 样式1
add_executable(app add.c div.c main.c mult.c sub.c)
# 样式2
add_executable(app add.c;div.c;main.c;mult.c;sub.c)

(4)执行 CMake 命令

CMakeLists.txt 文件编辑好之后,就可以执行 cmake 命令了。

# cmake 命令原型
cmake CMakeLists.txt文件所在路径
# 在此处即为
cmake .
$ tree
.
├── add.c
├── CMakeLists.txt
├── div.c
├── head.h
├── main.c
├── mult.c
└── sub.c

0 directories, 7 files
robin@OS:~/Linux/3Day/calc$ cmake .

当执行 cmake 命令之后,CMakeLists.txt 中的命令就会被执行,所以一定要注意给 cmake 命令指定路径的时候一定不能出错。

执行命令之后,看一下源文件所在目录中是否多了一些文件:

$ tree -L 1
.
├── add.c
├── CMakeCache.txt         # new add file
├── CMakeFiles             # new add dir
├── cmake_install.cmake    # new add file
├── CMakeLists.txt
├── div.c
├── head.h
├── main.c
├── Makefile               # new add file
├── mult.c
└── sub.c

我们可以看到在对应的目录下生成了一个 makefile 文件,此时再执行 make 命令,就可以对项目进行构建得到所需的可执行程序了。

$ make
Scanning dependencies of target app
[ 16%] Building C object CMakeFiles/app.dir/add.c.o
[ 33%] Building C object CMakeFiles/app.dir/div.c.o
[ 50%] Building C object CMakeFiles/app.dir/main.c.o
[ 66%] Building C object CMakeFiles/app.dir/mult.c.o
[ 83%] Building C object CMakeFiles/app.dir/sub.c.o
[100%] Linking C executable app
[100%] Built target app

# 查看可执行程序是否已经生成
$ tree -L 1
.
├── add.c
├── app					# 生成的可执行程序
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── CMakeLists.txt
├── div.c
├── head.h
├── main.c
├── Makefile
├── mult.c
└── sub.c

最终可执行程序 app 就被编译出来了(可执行程序的名字是在 CMakeLists.txt 中指定的)。

综上,所用的命令如下所示

# CMakeLists.txt中内容如下
cmake_minimum_required(VERSION 3.0)
project(CALC)
add_executable(app add.c div.c main.c mult.c sub.c)

# CMakeLists.txt就在当前目录下,所以用.表示即可
cmake .
make

在这里插入图片描述

实践了上面的简单例子就可以知道,如果在 CMakeLists.txt 文件所在目录执行了 cmake 命令之后就会生成一些目录和文件(包括 makefile 文件),如果再基于 makefile文件执行 make 命令,程序在编译过程中还会生成一些中间文件和一个可执行文件,这样会导致整个项目目录看起来很混乱,不太容易管理和维护,此时我们就可以把生成的这些与项目源码无关的文件统一放到一个对应的目录里边,一般将这个目录命名为 build :

# 先创建 build 文件夹
$ mkdir build
# 进入 build 文件夹
$ cd build
# 开始编译
$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.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/robin/Linux/build

现在 cmake 命令是在 build 目录中执行的,但是 CMakeLists.txt 文件是 build 目录的上一级目录中,所以 cmake 命令后指定的路径为 ..,即当前目录的上一级目录。

当命令执行完毕之后,在 build 目录中会生成一个 makefile 文件

$ tree build -L 1
build
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
└── Makefile

1 directory, 3 files

这样就可以在 build 目录中执行 make 命令编译项目,生成的相关文件自然也就被存储到 build 目录中了。

这样通过 cmake 和 make 生成的所有文件就全部和项目源文件隔离开了。

综上,用cmake执行编译的命令为

# 注意要删除除了CMakeLists.txt以外的,之前产生的cmake相关的文件
mkdir build
cd build
cmake ..
make

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【vue】深入探讨vue中组件间多种传值方式

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

直流调速器DCS800-S02-0260-05模块DCS800S02026005

型号代码&#xff1a;DCS800-S02-0260-05 电压&#xff1a;525V&#xff1b; 电流&#xff1a;350A&#xff1b; 双桥&#xff1b; 重量&#xff1a;25公斤&#xff1b; 定制&#xff1a;否 最小起订量&#xff1a;1 件 产品名称&#xff1a;DCS800直流调速模块 产品净深/长度&…

Kotlin: 协程的四种启动模式(CoroutineStart)

点击查看CoroutineStart英文文档 创建协程的三种方式 runBlocking 运行一个协程并且会阻塞当前线程&#xff0c;直到它完成。launch 启动一个新的协程&#xff0c;不会阻塞当前线程&#xff0c;并且返回一个Job&#xff0c;可以取消。async async和await是两个函数&#xff0c…

【CSPP】2021-04-2 邻域均值 经典二维前缀和

2021-04-2 邻域均值 经典二维前缀和 索引2021-04-2 邻域均值 经典二维前缀和思路遇到的问题完整代码 索引 历年CSP认证考试真题题解总汇持续更新 2021-04-2 邻域均值 经典二维前缀和 这题算是第二题中简单的那种了&#xff0c;但是我还是写了接近40分钟才AC&#xff0c;写二…

HTML静态网页成品作业(HTML+CSS)——世博园介绍(2个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有2个页面。 二、作品演示 三、代…

四.流程控制(顺序,分支,循环,嵌套)

c刚刚转过来的记得写在public static void main&#xff08;String[] args&#xff09;的花括号里 一.顺序结构 二.分支结构 if &#xff0c;switch 1.if (条件判断&#xff09; 2.if else 3.if else if else if ... else(它是一个一个否定来一个个执行判断的 4.s…

torchvision pytorch预训练模型目标检测使用

参考&#xff1a; https://pytorch.org/vision/0.13/models.html https://blog.csdn.net/weixin_42357472/article/details/131747022 有分类、检测、分割相关预训练模型 1、目标检测 https://pytorch.org/vision/0.13/models.html#object-detection-instance-segmentation-…

Springboot笔记-03

1.properties配置文件 #配制oerson的值 person.lastname张三 person.age12 person.birth2017/12/12 person.bossfalse person.dog.namedag person.dog.age15 person.maps.k1v1 person.maps.k212 person.listsa,b,c运行结果乱码 因为idea默认是utf-8编码而properties是ascall编…

禅道二次开发——创建需求

获取Token 官网参考 https://www.zentao.net/book/api/setting-369.html post http://xxx:8442/zentaopms/www/api.php/v1/tokensbody {"account": "xxx", "password": "xxx"}结果如下图 创建需求 官网参考 https://www.zentao.…

一文掌握:Gitlab的完整使用手册

&#x1f413;序言 GitLab是一个强大的版本控制和协作平台&#xff0c;用于管理代码仓库、项目、问题跟踪、持续集成和部署等软件开发任务。可以做一些创建项目、添加成员、管理代码、问题跟踪和持续集成等方面功能。 &#x1f413;创建Gitlab账户 如果你还没有GitLab账户&…

如何正确理解和区分承诺型OKR与愿景型OKR?

在目标管理的实践中&#xff0c;OKR&#xff08;Objectives and Key Results&#xff09;工作法作为一种高效的目标设定与跟踪工具&#xff0c;得到了广泛的应用。然而&#xff0c;OKR并非一种固定的模式&#xff0c;它可以根据企业的战略需求和文化背景进行灵活调整。其中&…

npm i安装依赖报错,但是cnpm i 却安装成功

问题描述&#xff1a;在a项目中npm i 安装依赖时发生以上报错&#xff0c;但是cnpm i 却成功&#xff0c;而且在其他项目中npm i 安装其他项目依赖也能成功.... 解决办法&#xff1a;删除项目中package-lock.json文件后再npm i 即可

Linux系统——数据库Mysql

目录 一、数据库原理 1.数据的时代 2.数据的分类 3.数据库的发展史 3.1文件管理系统的缺点 3.2数据库系统发展阶段 4. 数据库的基本概念 4.1数据 4.2表 4.3数据库 5.DBMS——数据库管理系统 5.1数据库管理系统的优点 5.2数据库管理系统的基本功能 5.3数据库管理系…

ruoyi-nbcio-plus基于vue3的flowable定时边界事件代码升级修改(二)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统http://122.227.135.243:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a;…

用 二层口 实现三层口 IP 通信的一个实现方法

我们一般用 undo portswitch 来将二层口转为三层口&#xff0c;但如果设备不支持的话&#xff0c;那么。。。 一、拓朴图&#xff1a; 二、实现方法&#xff1a; 起一个 vlan x&#xff0c;配置 vlanif地址&#xff0c;然后二层口划分到 vlan x 下&#xff0c;对端做同样的配置…

【Web】浅聊Hessian异常toString姿势学习复现

目录 前言 利用关键 调用分析 如何控制第一个字节 EXP 前言 Hessian CVE-2021-43297&#xff0c;本质是字符串和对象拼接导致隐式触发了该对象的 toString 方法&#xff0c;触发toString方法便可生万物&#xff0c;而后打法无穷也&#xff01; 这个CVE针对的是Hessian2I…

Re62:读论文 GPT-2 Language Models are Unsupervised Multitask Learners

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文全名&#xff1a;Language Models are Unsupervised Multitask Learners 论文下载地址&#xff1a;https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learner…

解锁编程潜能:ChatGPT如何革新软件开发

目录 一、背景 二、功能描述 三、总结 一、背景 在这个飞速发展的数字时代&#xff0c;软件开发的效率和质量成了衡量一个开发者能力的重要标准。随着人工智能技术的不断进步&#xff0c;越来越多的开发者开始寻找能够提升工作效率的新方法。我就是其中之一&#xff0c;最近…

【RabbitMQ | 第五篇】RabbitMQ实现消息的可靠抵达

文章目录 5.RabbitMQ实现消息的可靠抵达5.1引入背景5.2确认机制分类5.2.1ConfirmCallback (确认模式&#xff1a;消息生产者确认)&#xff08;1&#xff09;开启确认配置&#xff08;2&#xff09;实现ConfirmCallback回调接口 5.2.2ReturnCallback&#xff08;回退模式&#x…

vue3.x 使用jsplumb进行多列拖拽连线

前言&#xff1a; 最近很多小伙伴问到使用jsplumb进行多列拖拽连线怎么实现&#xff1f; 下面介绍vue3.x 使用jsplumb进行多列拖拽连线示例&#xff0c;以三列举例&#xff1a; 安装 npm install --save jsplumb引入 <script lang"ts" setup>import {ref, r…