现代 CMake 简明教程--CMake 基础

2023-05-16

前言

用 CMake 来构建 C/C++ 项目是业内的主流做法。最近,我们的项目代码做了一些拆分和合并:引入其他仓库代码,并且将公共部分拆分以供多个仓库同时使用。为此,就得修改项目中的 CMake 以满足需求。

在做这件事情时,过程是相当痛苦的,修改的难度超过了我的预期。这份痛苦的回忆,让我陷入了沉思:这 CMake 咋这么不好使,是我的使用姿势不对吗?CMake 的最佳实践是啥?

在经过一番搜索和学习,我开始了解 Modern CMake 的一些用法与理念,它主张放弃传统的基于变量的方法,而采用基于 target 的结构化模式,使其成为一个更可维护、更直观、更易集成、更具意义的方案。

在这里对自己的学习做一个总结,主要内容包括:

  1. 介绍 Modern CMake 的基础语法与工具,让你对 CMake 能做些啥有更清楚的认识
  2. 介绍 Modern CMake 理念与最佳实践,并给出具体实例

CMake 基础

这部分内容是 An Introduction to Modern CMake 的总结,并不会讲的非常详细,希望通过几句话来高度总结各个用法,旨在了解 CMake 有哪能力,如果对某些部分感兴趣请大家自行查阅具体内容。

1. Modern CMake 介绍

  • 为什么需要一个好的构建系统?如果你有以下需求,那么使用 CMake 可以从中获益
    • 你想避免硬编码路径
    • 你需要在多台电脑上建立一个软件包。
    • 你想使用CI(持续集成)。
    • 你需要支持不同的操作系统(甚至可能只是Unix的不同版本)。
    • 你想支持多个编译器
    • 你想使用IDE,但也许并不是所有时间都想使用。
    • 你想要更好地组织程序的结构
    • 你想使用别人的库
    • 你想使用工具,比如Clang-Tidy,来帮助你编写代码。
    • 你想使用调试器
  • 为什么一定是 CMake?其他工具不行吗?
    • 各个 IDE 都支持 CMake,使用 CMake 可以有更大程度的方便, save you life
    • 目前很多 C/C++ 开源项目都在使用 CMake,通过 find CMake 或者 CMake config 很容易将它们集成至你的项目中
    • 使用 CMake 来管理发布,让别人更容易使用你的库
    • 更多理由请参考 19 reasons why CMake is actually awesome
  • 为什么要用现代 CMake?
    • 通常认为 3.1+ 版本是现代 CMake。CMake 是向下兼容的,可以放心使用
    • 至少应该使用你的编译器出来之后的 CMake 版本,因为它需要知道该版本的编译标志等等
    • 高版本 CMake 有更多特性,可以节省数百行和数小时的 CMakeLists.txt 编写工作,长运来看更容易维护

安装 CMake

  • All
    • Pip (official, sometimes delayed slightly)
    • Anaconda / Conda-Forge
  • Windows
    • Chocolatey
    • Scoop
    • MSYS2
    • Download binary (official)
  • MacOS
    • Homebrew
    • MacPorts
    • Download binary (official)
  • Linux
    • Snapcraft (official)
    • APT repository (Ubuntu/Debian only) (official)
    • Download binary (official)

运行 CMake

  • 经典用法

    ~/package $ mkdir build
    ~/package $ cd build
    ~/package/build $ cmake ..
    ~/package/build $ make
    
  • 新版本可以简单一点

    ~/package $ cmake -S . -B build
    ~/package $ cmake --build build
    
  • 安装命令

    #From the build directory (pick one)
    ~/package/build $ make install
    ~/package/build $ cmake --build . --target install
    ~/package/build $ cmake --install . # CMake 3.15+ only
    
    #From the source directory (pick one)
    ~/package $ cmake --build build --target install
    ~/package $ cmake --install build # CMake 3.15+ only
    
  • 推荐使用 --build 用法

    • 通过 -v 显示执行的构建命令: cmake --build build -v
    • 通过 --target 来选择目标:cmake --build --target install
  • 设置 CC 和 CXX 环境变量来选择 C/C++ 编译器

    ~/package/build $ CC=clang CXX=clang++ cmake ..
    
  • 选择不同的工具进行构建

    • make 通常是默认的,通过 cmake --help 查看支持的构建器
    • cmake -G"My Tool" 设置构建器,例如 cmake -S . -B buildXcode -G"Xcode"
  • 通过 -D 来设置选项,例如 cmake -S . -B build -DCMAKE_INSTALL_PREFIX=dist

  • --trace 打印 CMake configure 阶段的输出,例如 cmake -S . -B build --trace

Do’s and Don’ts

  • 不好的 CMake 的用法

    • 不要使用全局函数,例如 link_directoriesinclude_librariesadd_definitions 等,请你忘记它们
    • 不要滥用 PUBLIC,除非有依赖传递,否则请你使用 PRIVATE 替换 PUBLIC
    • 不要使用 GLOB 来添加文件
    • 不要直接链接文件,而是链接目标
    • 链接时千万不要跳过 PUBLIC/PRIVATE,这会导致未来的链接都没有关键字
  • 良好的 CMake 用法

    • 把 CMake 视作代码,保持它的整洁和可读性
    • 围绕 target 构建你的 CMake。将需要的信息打包在 target 里,然后链接那个目标
    • 导出你的接口
    • 写 Config.cmake 文件,这是一个库作者应该做的,可以方便别人使用你的库
    • 使用 ALAS 目标,以保持使用一致性
    • 将常用的功能提取成函数或者宏,通常函数更好
    • 使用小写的函数名,全大写是变量
    • 使用 cmake_policy 或者 range of versions

2. 基础语法

  • 最低版本

    • cmake_minimum_required(VERSION 3.1) 指定最低版本
    • cmake_minimum_required(VERSION 3.7...3.18) CMake 3.12+ 后,可以指定版本范围
  • Project

    • VERSION 指定版本,并设置一系列变量,例如MyProject_VERSION 等
    • DESCRIPTION 项目的描述
    • LANGUAGES 支持 C/CXX/Fortran/ASM/CUDA(3.8+)/CSharp(3.8+)/SWIFT(3.15+)C/C++ 为默认值
    project(MyProject VERSION 1.0
                      DESCRIPTION "Very nice project"
                      LANGUAGES CXX)
    
  • 生成可执行文件

    add_executable(one two.cpp three.h)
    
  • 生成库

    • 库类型包括 STATIC、SHARED、MODULE、OBJECT 等。如果没有指定库类型,那么 BUILD_SHARED_LIBS 的值将决定编译 STATIC 或者 SHARED
    • 有些库并不需要编译,例如 header only 库。基于 target 的思想,我们可以将它们打包在一种叫 INTERFACE 的库中。
    add_library(one STATIC two.cpp three.h)
    
  • 给 target 添加属性

    • target_include_directories 为 target 添加 include 路径
    • PUBLIC 对于可执行文件而言意义不大,对于库来说,它让 CMake 知道链接这个目标的目标也需要这个 include 目录。也就是 “我自己要用,其他链接我的也要用”,具有传递性
    • PRIVATE 表示 “我自己用,其他人不用”
    • INTERFACE 表示 “我自己不用,其他链接我的要用”
    • target 的属性包括 include 文件夹、需要链接的库、编译选项、宏定义等,这些都可以通过 target_link_libraries 进行传递
    # PUBLIC 表示外部也需要这个 include 目录
    target_include_directories(one PUBLIC include)
    add_library(another STATIC another.cpp another.h)
    # 由于具有传递性,another 可以连接 one 的 include 目录
    target_link_libraries(another PUBLIC one)
    

变量与缓存

  • 局部变量
    • set(MY_VARIABLE "value") 设置局部变量,其作用域为当前文件夹,以及 add_subdirectory 进入的文件夹
    • set(MY_VARIABLE "value" PARENT_SCOPE) 将作用域设置为父目录,通常用在子目录向父目录传递信息
    • set(MY_LIST "one" "two") 会在变量值中间加入 “;”,等价于 set(MY_LIST "one;two")
  • 缓存变量
    • 通过 set(MY_CACHE_VARIABLE "VALUE" CACHE STRING "Description") 设置缓存变量
    • 缓存变量将持久存在于 CMakeCache.txt 中
    • 通过 cmake -DXXX 命令传递的参数为缓存变量

关于局部变量与缓冲变量的示例,请参考 cmake-变量和全局变量缓存

  • 环境变量
    • set(ENV{variable_name} value) 设置环境变量
    • $ENV{variable_name} 获取环境变量
  • 属性
    • 属性有点像变量,但它依附在某个 target 或者文件、目录上。许多属性的初始值来自于 CMAKE_ 开头的变量,例如设置 CMAKE_CXX_STANDARD,将会设置 target 的 CXX_STANDARD 属性初始值。
    • set_property 用于设置属性,get_property 用于获取属性。参看 cmake-properties 查阅有哪些属性

用 CMake 编程

  • 控制流

    • 利用 if 语句来控制程序流
    • if语句中支持的关键字包括:
      • 一元判断:NOT、‘TARGET’、EXISTSDEFINED 等
      • 二元判断:STRQUALANDORMATCHVERSION_LESSVERSION_LESS_EQUAL
    if(variable)
        # If variable is `ON`, `YES`, `TRUE`, `Y`, or non zero number
    else()
        # If variable is `0`, `OFF`, `NO`, `FALSE`, `N`, `IGNORE`, `NOTFOUND`, `""`, or ends in `-      NOTFOUND`
    endif()
    # If variable does not expand to one of the above, CMake will expand it then try again
    
    if(NOT TARGET libA OR EXISTS "test.xml")
     # If libA or test.xml exist 
    endif()
    
    
  • 生成器表达式, generator-expressions

    • CMake 大多数命令在 configure 阶段就被执行了,而生成器表达可以在 build 阶段,或者 install 阶段被执行
    target_include_directories(MyTarget 
        PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:include>
    )
    
  • 宏与函数

    • 它们的区别:函数里头的变量作用域为该函数,而宏没有作用域
    • 推荐用函数,因为它不会 “泄露” 变量。即使想要从函数中传递某些变量给外面,可以主动通过 PARENT_SCOPE 来设置
  • 参数。可以通过 cmake_parse_arguments 来解析函数参数

与你的代码进行交互

  • 从 CMake 中获取信息,并生成代码。configure_file 命令可以实现这个。
  • 读取文件,例如从 version.h 中获取版本信息。file 命令可以实现这个。

如何组织你的工程

- project
  - .gitignore
  - README.md
  - LICENCE.md
  - CMakeLists.txt
  - cmake
    - FindSomeLib.cmake
    - something_else.cmake
  - include
    - project
      - lib.hpp
  - src
    - CMakeLists.txt
    - lib.cpp
  - apps
    - CMakeLists.txt
    - app.cpp
  - tests
    - CMakeLists.txt
    - testlib.cpp
  - docs
    - CMakeLists.txt
  - extern
    - googletest
  - scripts
    - helper.py

运行其他程序

  • 在 configure 阶段运行命令
    • execute_process 在 configure 阶段运行命令
    find_package(Git QUIET)
    
    if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
        execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
                        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                        RESULT_VARIABLE GIT_SUBMOD_RESULT)
        if(NOT GIT_SUBMOD_RESULT EQUAL "0")
            message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
        endif()
    endif()
    
  • 在 build 阶段运行命令
    find_package(PythonInterp REQUIRED)
    add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include/Generated.hpp"
        COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/GenerateHeader.py" --argument
        DEPENDS some_target)
    
    add_custom_target(generate_header ALL
        DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/include/Generated.hpp")
    
    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/Generated.hpp DESTINATION include)
    
  • cmake -E <mode> 运行内置的一些命令,例如解压、复制等,具体参看 Run a Command-Line Tool

一个简单的示例

  • 简易版
  • 复杂一些的版本

3. 添加特性

C++11 及以后

  • CMake 3.8+: Meta compiler features
    • target_compile_features(myTarget PUBLIC cxx_std_11) 开启 c++11 特性,当然你也可以选择 cxx_std_14 和 cxx_std_17
    • set_target_properties(myTarget PROPERTIES CXX_EXTENSIONS OFF),关闭扩展特性
  • CMake 3.1+: 全局和属性设置
  • 全局变量设置
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    set(CMAKE_CXX_EXTENSIONS OFF)
    

 

  • 属性设置
    set_target_properties(myTarget PROPERTIES
        CXX_STANDARD 11
        CXX_STANDARD_REQUIRED YES
        CXX_EXTENSIONS NO
    )
    

琐琐碎碎

  • 地址无关代码(Position independent code; PIC),CMake 会自动将 -fPIC 添加到 SHARED 和 MODULE 库中,当然你也可以显示指定

    • 作用于全局变量,set(CMAKE_POSITION_INDEPENDENT_CODE ON)
    • 或者作用于 target,set_target_properties(lib1 PROPERTIES POSITION_INDEPENDENT_CODE ON)
  • 小型库

    • 如果你需要 dl 库,那么这么写最简单 target_link_libraries(libA PRIVATE ${CMAKE_DL_LIBS})
    • 有些库就没有这么方便了,例如 mpthread 等,但你可以这么写
      find_library(MATH_LIBRARY m)
      if(MATH_LIBRARY)
          target_link_libraries(MyTarget PUBLIC ${MATH_LIBRARY})
      endif()
      
  • Interprocedural optimization,运行时优化(link time optimization),即 -flto

    • CMake 3.9+ 支持设置全局变量开启 set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
    • CMake 3.8+ 支持设置属性
      set_target_properties(myTarget PROPERTIES 
                          INTERPROCEDURAL_OPTIMIZATION ON)
      
    • 通过 check_ipo_supported 来检查当前版本是否支持 LTO
      include(CheckIPOSupported)
      check_ipo_supported(RESULT result)
      if(result)
        set_target_properties(foo PROPERTIES 
                      INTERPROCEDURAL_OPTIMIZATION TRUE)
      endif()
      
  • 在 CMake 中可以配合其他工具

    • CCache,使用它来加快编译速度
    • Clang tidy,对你的代码做静态扫描
    • Include what you use, 检查冗余头文件
    • Clang-format,很不幸 CMake 没法直接使用 Clang-format,但是可以通过一些小技巧将它嵌入到 CMake 流程中来。参考这里还有这里
  • CMake Modules 非常有用,简单介绍一些常用的

    • CMakeDependentOption,根据一组变量来设置选项,例如
      include(CMakeDependentOption)
      cmake_dependent_option(BUILD_TESTS "Build your tests" ON "VAL1;VAL2" OFF)
      
    • CMakePrintHelpers,用于打印属性或变量
    • CheckCXXCompilerFlag,用于判断是否支持某个编译选项
    • WriteCompilerDetectionHeader,与 CheckCXXCompilerFlag 类似,但它更强大。它可以找到编译器支持的特性列表,并生成 C++ 头文件,让你知道哪些特性可用
    • try_compile/try_run,可以让尝试编译(运行)一些代码,这可以让你获得系统能力的信息
  • 调试 CMake 代码

    • 打印永远是调试的最简单的办法
      message(STATUS "MY_VARIABLE=${MY_VARIABLE}")
      
      include(CMakePrintHelpers)
      cmake_print_variables(MY_VARIABLE)
      
      cmake_print_properties(
        TARGETS my_target
        PROPERTIES POSITION_INDEPENDENT_CODE)
      
    • --trace-source="filename" 让你观察 CMake 文件到底发生了什么,例如:
      cmake -S . -B build --trace-source=CMakeLists.txt
      
      •  

4. 引入其他项目

Submodule

  • 通过 git submodule add ../../owner/repo.git extern/repo 将 extern 添加为子仓库
  • 可以在 CMake 中内置子仓库更新命令
    find_package(Git QUIET)
    if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
    # Update submodules as needed
        option(GIT_SUBMODULE "Check submodules during build" ON)
        if(GIT_SUBMODULE)
            message(STATUS "Submodule update")
            execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
                            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                            RESULT_VARIABLE GIT_SUBMOD_RESULT)
            if(NOT GIT_SUBMOD_RESULT EQUAL "0")
                message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
            endif()
        endif()
    endif()
    
    if(NOT EXISTS "${PROJECT_SOURCE_DIR}/extern/repo/CMakeLists.txt")
        message(FATAL_ERROR "The submodules were not downloaded! GIT_SUBMODULE was turned off or failed. Please update submodules and try again.")
    endif()
    

DownloadProject

  • 在 CMake 3.11 以前,主要下载命令都是在 build 阶段完成的(例如 ExternalProject_Add)。这就导致你无法使用 add_subdirectory
  • CMake 3.11之前,如果想要在 configure 阶段下载,参考 Crascit/DownloadProject

Fetch(CMake 3.11+)

  • CMake 3.11 后,你可以使用 FetchContent 在 configure 阶段下载文件或者项目

5. 测试

  • 通常不在子目录时编译测试代码
    if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING)
      add_subdirectory(tests)
    endif()
    
  • 通过 add_test(NAME TestName COMMAND TargetName) 注册测试

GoogleTest

  • 推荐通过以 git submodule 的形式引入 GoogleTest
  • 可以通过作者提供的 AddGoogleTest 工具引入 GoogleTest
  • 通过 FetchContent 引入 GoogleTest

Catch

  • Catch 是个 header only 库,如果直接将它的 include 引入你的仓库中,你需要做一些准备,以便使用
    # Prepare "Catch" library for other executables
    set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/catch)
    add_library(Catch2::Catch IMPORTED INTERFACE)
    set_property(Catch2::Catch PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CATCH_INCLUDE_DIR}")
    
  • 通过 ExternalProjectFetchContent 或者 git submodule 引入 Catch,那么直接 add_subdirectory 即可

6. Exporting and Installing

  • 关于 Installing,参考 CMake之install方法的使用
  • 关于 Exporting,可以将 build directories 信息导出,以供其他工程使用(注意与 Installing 的区别:Installing 导出的是安装目录的信息)
  • 关于 Package ,没怎么用过,似乎是将你需要的内容进行打包

7. 寻找库

介绍了引入 CUDA、OpenMP、Boost、MPI、ROOT、Minuit2 等库的标准姿势

参考资料

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

现代 CMake 简明教程--CMake 基础 的相关文章

  • Postgresql中每一类别的前10条数据查询

    以下sql中的内层查询 row number over partition by transactionchannel order by transactiontype sumalltranscount desc 意思是 xff0c 根据t
  • python类初始化详解_Python C头文件解析和反向初始化

    我有兴趣使用Python以递归方式解析C头文件 只有结构和变量声明 Python C头文件解析和反向初始化 这是我正在寻找的一个例子 假设如下 xff1a typedef struct double value 3 vector3 type
  • excel vba编程代码大全_实战VBA代码一键提取EXCEL中的所有公式!

    有的时候 xff0c 我们希望把表中的公式提取出来 xff0c 进行保存 xff01 少量 xff0c 我们可以手动复制 xff0c 量大 xff0c 猝 所以我们今天就分享一下如何一键提取 用什么 xff0c VBA上吧 xff01 还是
  • linux系统备份路径,linux系统备份恢复到本机或是别的机器上

    最近一直搞Xtion2 openni2 一下装完一个东西就不能用了 xff0c 由于ubuntu系统不熟 xff0c 找不到错误 xff0c 弄得每次都要重新装系统 xff0c 当我配了好几天的系统 xff0c 里面带着mxnet orbs
  • cmake之 ADD_LIBRARY()

    上一篇我分析了如何调用别人的第三方库 xff0c 现在我继续分析如何构建一个库供他人使用 完成这个任务需要用到ADD LIBRARY 强烈建议学习cmake的同学多多参考官方文档 xff0c 自己也是参考了一部分 1 xff1a ADD L
  • ESB企业服务总线

    ESB企业服务总线 提供位置透明性的消息路由和寻址服务提供服务注册和命名的管理功能支持多种消息传递范性支持多种可以广泛使用的传输协议支持多种数据格式及其相互转换提供日志和监控功能
  • 对Nginx的简单理解

    Nginx 同行是apache nginx同apache一样都是一种web服务器 xff0c 基于rest架构风格 xff0c 以统一资源描述符URI或者统一资源定位符URL作为沟通依据 xff0c 通过HTTP协议提供各种网络服务 apa
  • VSCode+clangd阅读linux内核源码

    1 clangd 原理介绍 clangd 插件用于代码语义分析 代码补全 跳转等 能做到代码精准跳转 精准自动补全 xff0c 其根本原理是通过读取工程编译自动生成的compile commands json 文件来索引其中包含的源文件和关
  • 旋转矩阵、欧拉角

    旋转矩阵 欧拉角 注 xff1a 下面为学习空间机器人技术系列课程笔记 xff0c 加上一些自己的整理 xff0c 方便复习 一 旋转矩阵的引出 下面坐标系0的基向量为 x 0 xff0c
  • Makefile的入门完整教程(包学包会)

    Makefile的完整入门教程 xff08 实现不了来打我TAT xff09 看完能够了解Makefile是什么 xff1b 我们能用makefile做什么 xff1b makefile的简易使用 1 什么是Makefile Makefil
  • ubuntu18.04 升级内核后,进入系统页面卡在“started gnome display manager“的解决方案

    问题描述 安装了18 04后 xff0c 系统的内核是5 0的 xff0c 不支持电脑的wifi xff0c 所以就想升级一下 升级到5 4后在grub界面选择5 4的内核后 xff0c 进入系统 xff0c 界面一直卡在started g
  • Ubuntu 14.04下,分辨率只有800×600的解决方法

    对于Ubuntu 14 04 xff0c 在安装好后 xff0c 默认的分辨率是800 600 xff0c 对于有着高分辨率例如1920 1080的显示器 xff0c 或者想要拓展双屏 xff0c 本身默认显示器驱动无法实现 xff0c 因
  • ubuntu14.04下安装cmake 3.5

    对于ros的应用 xff0c 很多还局限在indigo下 xff0c 因此要求的Ubuntu版本还限制在14 04 但对于很多新的功能包 是在kinetic下运行的 xff0c 很多cmake要求在3 5以上 xff0c 而安装ros in
  • Ubuntu16.04下使用ros_qtc_plugin在qt下进行编译

    系统测试环境 系统版本 Ubuntu16 04ROS版本 kinetic 按照官网的教程https ros qtc plugin readthedocs io en latest source Improve ROS Qt Creator
  • Ubuntu16.04下openpose编译及测试demo

    一 安装 官方安装流程见openpose官方 在安装前 xff0c 尽量保证有很好的显卡以及内存 xff0c 不然在运行demo的过程中会出现out of memory的情况出现 流程如下 xff1a 1 下载 git clone http
  • ubuntu16.04 通过anaconda建立虚拟环境,安装tensorflow1.10,cuda9.0,cudnn7.1.2

    1 anaconda建立虚拟环境及conda操作 env name代表你想要建立的环境名字 n表示名字 conda create n env name python 61 3 5 激活环境 source activate env name
  • 运维人员核心职责

    运维小知识点 xff01 网站数据不能丢网站7 24小时运转提升用户体验 xff0c 访问速度要快 云计算 1 公有云 2 私有云 就是自己内部的运维工程师部署的一个云平台 xff0c 资源管理平台数据都放在自己手中 xff0c 不被别人看
  • Ubuntu16.04下向github传送或修改代码

    初次使用Git设置 这段针对的是初次使用Git的设置 xff0c 如果初次设置之后 xff0c 就直接跳到下一阶段 将本地仓库push至github远程仓库 1 首先要确定Ubuntu下是否有git 终端运行指令 sudo apt inst
  • 字符串尾部得加'\0'原因

    39 0 39 一般放在字符串的结束处 xff0c 表示字符串的结束 xff0c 其是ascii值为0的字符的转义 在头文件 include lt string h gt 中包含的一些字符串处理函数等中 xff0c 一般处理字符串时 xff
  • cmake-CMakeLists.txt中添加目标编译选项的方法

    CMakeLists txt中添加目标编译选项的方法 原因 xff1a 如果程序中用到了宏来区分不同的方法 xff0c 但是又不想每次在用到不同的方法的时候都要在程序中更改宏定义后再进行编译 xff0c 那么可以在CMakeLists tx

随机推荐

  • GDB多线程调试和死锁

    set schedular locking on off 条件断点查看循环中的某些变量 break if命令 示例 xff1a break test c 34 if x amp y 61 61 1 默认情况下我们执行到断点处继续执行时 xf
  • Gazebo仿真踩坑系列-乱飞、抖动等

    本文章记录机械臂 塔吊等仿真过程中遇到的各种问题 塔吊建模 前言 gazebo机械臂等控制仿真最重要的是建模 xff0c 也就是URDF的编写 xff0c 而这里面有着特别多要注意的地方 xff0c 否则会发生 启动乱飞 控制乱飞 和 启动
  • Qt6新创建CMake项目启动不了

    错误如下 xff1a 1 error CMake was unable to find a build program corresponding to 34 Ninja 34 CMAKE MAKE PROGRAM is not set Y
  • Linux/Centos 安装oracle报错“调用makefile ‘/oracle/product/11.2.0/dbhome_1/sysman/lib/ins_emagent.mk的目标” 解决

    解决centos7 redhat7安装oracle11g到 70报错问题 Linux Centos 安装oracle报错 调用makefile 39 oracle product 11 2 0 dbhome 1 sysman lib ins
  • C++使用技巧(四):单双冒号“:”和“::”用法

    C 43 43 单冒号与双冒号的作用 1 冒号 xff08 xff09 用法 xff08 1 xff09 表示结构体内位域的定义 xff08 即该变量占几个bit空间 xff09 span class token keyword typed
  • 交换机与路由器

    交换机 VS 路由器 交换机 xff1a 把数据包发送到正确的位置 xff0c 相当于邮递员 xff0c 根据数据包中的目标mac地址 xff0c 找到他对应的物理端口 xff0c 一台交换机有很多个端口 xff0c 它们都有自己的编号 x
  • 在C++中使用openmp进行多线程编程

    声明 xff1a 本文是基于Joel Yliluoma写的Guid into OpenMP Easy multithreading programming for C 43 43 而写的 xff0c 基本是按照自己的理解 xff0c 用自己
  • CMakeLists 写法总结

    0 前言 之前简单介绍了makefile的写法 xff0c 但实际工程中基本不会手写makefile xff0c 通常情况是会写一个CMakeLists甚至是多层多个CMakeLists来构建整个工程 关于makefile和CMakeLis
  • C++成员函数后面跟冒号冒号

    冒号后面跟的是赋值 xff0c 这种写法是C 43 43 的特性 A int aa int bb a aa b bb 相当于 A int aa int bb a 61 aa b 61 bb
  • Apollo 算法阅读之Public Road轨迹规划算法--路径规划(含源代码)

    本次博文主要介绍apollo 5 0版本内使用的轨迹规划算法 public road xff0c 该算法的核心思想是PV解耦 xff0c 即Path Velocity的解耦 xff0c 其主要包含两个过程 xff1a 1 路径规划 xff0
  • 交互式多模型 IMM的原理

    交互式多模型简单原理 交互式多模型 IMM xff08 Interacting Multiple Model xff09 控制算法的主体思想是基于贝叶斯理论而提出的模型间的自动识别与切换 xff1a 在任意跟踪时刻 xff0c 通过设置对应
  • Apollo算法阅读之基于Sqp的Referenceline全局参考路线优化(含源码)

    算法来源于Apollo代码 代码源地址 xff0c 通过序列优化思想 xff0c 建立无人驾驶车辆参考路径的平滑 xff0c 利用泰勒展开将曲率约束线性化表达 xff0c 目标函数中利用弹性带思想 xff0c 并尽可能缩短参考路径长度且保持
  • 离散点间曲率计算

    本文转自知乎计算离散点的曲率 xff08 附Python MATLAB代码 xff09 在很多学科中的很多计算任务中都需要用到曲线的曲率 xff08 或者曲率半径 xff09 xff0c numpy库里和matlab build in里都没
  • 关于Frenet坐标系内曲率约束

    本文摘自于apollo直播公开课 xff0c 因为车辆存在最小的转弯半径 xff0c 所以我们要对车辆运动学进行限制 由于转弯半径是基于笛卡尔坐标系的 xff0c 需要基于Frenet坐标系进行转换 假设 xff1a xff0c 车辆朝向与
  • caffe内CHECK_EQ等函数意义解释

    个人在学习caffe源码文件时遇到了CHECK EQ函数 xff0c 不理解什么含义 xff0c 经过上下文理解 xff0c 明白了其中含义 CHECK EQ x y lt lt 34 x 61 y 34 xff0c EQ即equation
  • 电路交换方式与分组交换方式计算题

    已知网络速率为1Mb S xff0c 对于每个用户来说 xff0c 有10 的时间是活跃的 xff0c 活跃时网速为100kb s 对于电路交换方式来说 xff0c 最多只能支持10位用户接入网络 由于1Mb 61 1000kb xff0c
  • Carla编译make launch过程中出现UE4_ROOT is not defined

    在编译carla过程中出现如下情况 xff1a BuildCarlaUE4 sh ERROR UE4 ROOT is not defined or points to a non existant directory please set
  • request 模块可以帮助我们发起http请求

    request 模块可以帮助我们发起http请求 步骤 xff1a 1 首先import 下 request 模块 2 然后看请求的方式 xff0c 选择对应的请求方法 3 接受返回的报文信息 有requests get requests
  • 自动提取论文公式方法

    需要的软件 MathType 7 Mathpix Snipping Tool 软件获取链接 xff1a 链接 xff1a https pan baidu com s 1Fz VGkgZJbZhlocL4y1AoA 提取码 xff1a ci0
  • 现代 CMake 简明教程--CMake 基础

    前言 用 CMake 来构建 C C 43 43 项目是业内的主流做法 最近 xff0c 我们的项目代码做了一些拆分和合并 xff1a 引入其他仓库代码 xff0c 并且将公共部分拆分以供多个仓库同时使用 为此 xff0c 就得修改项目中的