Linux - CMake详细教程

目录

CMake详细教程

1 CMake简介

2 CMake特点

3 CMake安装

4 CMake使用注意事项

5 CMake常用指令介绍

5.1 CMake官方指令

5.2 CMake常用指令

5.3 静态库和共享库

6 ORB_SLAM2中Cmake文件解析


CMake详细教程


1 CMake简介

        CMake 是"Cross platform MAke"的缩写,CMake是开源、跨平台的构建工具,可以让我们通过编写简单的配置文件去生成本地的Makefile,这个配置文件是独立于运行平台和编译器的,这样就不用亲自去编写Makefile了,而且配置文件可以直接拿到其它平台上使用,无需修改,非常方便。

2 CMake特点

  • Cmake 支持很多语言: C、C++、Java 等
  • 跨平台使用,根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix的Makefile 或Windows 的 Visual Studio 工程
  • 能够管理大型项目,比如OpenCV、Caffe、MySql Server
  • 自动化构建编译,CMake 构建项目效率非常高
  • 需要根据CMake 专用语言和语法来自己编写CMakeLists.txt 文件
  • 如项目已经有非常完备的工程管理工具,并且不存在维护问题,没必要迁移到CMake

3 CMake安装

        Windows下:Windows下Cmake安装步骤详解(图文)_cmake安装windows_L_Li_L的博客-CSDN博客

        Linux下:Linux安装CMake_氷泠的博客-CSDN博客


4 CMake使用注意事项

  • CMake 构建专用定义文件,文件名严格区分大小写
  • 工程存在多个目录,可以每个目录都放一个CMakeLists.txt文件
  • 工程存在多个目录,也可以只用一个CMakeLists.txt文件管理
  • 不区分大小写,可以全用大写,全用小写,甚至大小写混合,自己统一风格即可
  • 严格大小写相关。名称中只能用字母、数字、下划线、破折号
  • 用${}来引用变量
  • 参数之间使用空格进行间隔

5 CMake常用指令介绍

5.1 CMake官方指令

        Index — CMake 3.26.0-rc6 Documentation

5.2 CMake常用指令

        以高翔《SLAM十四讲ch13》的案例为例。

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)

(1)指定要求最小的cmake版本,如果版本小于该要求,程序终止

cmake_minimum_required()

(2)设置当前项目名称

project(name)

(3)设置模式

CMAKE_BUILD_TYPE

# Debug: 调试模式,输出调试信息,不做优化
# Release: 发布模式,没有调试信息,全优化
# RelWithDebInfo::类似Release, 但包括调试信息
# MinSizeRel: 一种特殊的Release模式,会特别优化库的大小

(4)指定头文件的搜索路径

include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
  • 指定头文件的搜索路径,编译器查找相应头文件
  • 举例:include_directories("/usr/include/eigen3")查找eigen3库的路径
  • CMakeLists.txt 中添加 include_directories(/usr/local/include)

(5)set用于给下面的变量设置值

        参考文章:Cmake入门之——Set方法(六)_cmake set cache string_PGzxc的博客-CSDN博客

  • 一般变量(Set Normal Variable)
set(<variable> <value>... [PARENT_SCOPE])

# variable:只能有一个
# value:可以有0个,1个或多个,当value值为空时,方法同unset,用于取消设置的值
# PARENT_SCOPE(父作用域):作用域,除PARENT_SCOPE外还有function scope(方法作用域)和directory scope(目录作用域)
  • 缓存变量(Set Cache Entry)
set(<variable> <value>... CACHE <type> <docstring> [FORCE])

# variable:只能有一个
# value:可以有0个,1个或多个,当value值为空时,方法同unset,用于取消设置的值
# CACHE:关键字,说明是缓存变量设置
    ## type(类型):必须为以下中的一种:
    ## BOOL:有ON/OFF,两种取值
    ## FILEPATH:文件的全路径
    ## PATH:目录路径
    ## STRING:字符串
    ## INTERNAL:字符串
    ## docstring:总结性文字(字符串)
# [FORCE]:变量名相同,第二次调用set方法时,第一次的value将会被覆盖
  • 环境变量(Set Environment Variable)
set(ENV{<variable>} [<value>])

# variable:只能有一个
# value:一般来说,只有一个,为空时,将清除之前设置的变量值,多个时,取值最近的一个,之后的值将被忽略

(6)添加可执行文件

add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [source1] [source2 ...])
  • 用指定的源文件为工程添加可执行文件
  • name:生成可执行文件的名字,必须在工程内全局唯一
  • WIN32:有此参数时,WIN32_EXECUTABLE属性会被置为true,此时在windows环境下创建的可执行文件将以WinMain函数代替main函数作为程序入口,构建而成的可执行文件为GUI应用程序而不是控制台应用程序
  • MACOSX_BUNDLE: 有此参数时,MACOSX_BUNDLE属性会被置为true,此时在macOS或者iOS上构建可执行文件目标时,目标会成为一个从Finder启动的GUI可执行程序
  • EXCLUDE_FROM_ALL:有此参数时,此目标就会被排除在all target列表之外,即在执行默认的make时,不会构造此目标,需要构造此目标的时候,需要手动构建,如:

(7)生成链接库文件

add_library(libname STATIC/SHARED sources)
  • 将指定的源文件生成链接库文件。STATIC 为静态链接库,SHARED 为共享链接库

(8)添加库链接

target_link_libraries (target library1 library2 ...)
  • 为库或二进制可执行文件添加库链接,要用在add_executable之后。

(9)源文件向项目(project)添加可执行文件

add_executable(<name> IMPORTED [GLOBAL])

# Debug: 调试模式,输出调试信息,不做优化
# Release: 发布模式,没有调试信息,全优化
# RelWithDebInfo::类似Release, 但包括调试信息
# MinSizeRel: 一种特殊的Release模式,会特别优化库的大小
  •  name:导入可执行文件目标的名字
  • IMPORTED:导入的目标文件需指定IMPORTED属性,IMPORTED属性指定后,目标文件的属性IMPORTED被置为true,在工程内构建生成的可执行文件的IMPORTED属性会被置为false

(10)指明当前的执行程序依赖的动态库

add_dependencies (target-name depend)
  • 为上层target添加依赖,一般不用
  • 若只有一个targets有依赖关系,一般选择使用 target_link_libraries
  • 如果两个targets有依赖关系,并且依赖库也是通过编译源码产生的。这时候用该指令可以在编译

(11)向当前工程添加存放源文件的子目录

add_subdirectory(source_dir)
  • 向当前工程添加存放源文件的子目录,目录可以是绝对路径或相对路径

(12)在目录下查找所有源文件

aux_source_directory( dir varname)

(13)打印输出信息

message(mode "message text" )
  • 打印输出信息,mode包括FATAL_ERROR、WARNING、STATUS、DEBUG等
  • message(STATUS “Set debug mode")

        PROJECT_NAME:项目名称,与project( xxx) 一致
        PROJECT_SOURCE_DIR:即内含 project() 指令的 CMakeLists 所在的文件夹
        EXECUTABLE_OUTPUT_PATH:可执行文件输出路径
        LIBRARY_OUTPUT_PATH :库文件输出路径
        CMAKE_BINARY_DIR:默认是build文件夹所在的绝对路径
        CMAKE_SOURCE_DIR:源文件所在的绝对路径

(14)搜索外部库

find_package(package version EXACT/QUIET/REQUIRED)
  • 功能:采用两种模式( FindXXX.cmake和XXXConfig.cmake )搜索外部库
  • 示例:find_package( OpenCV 3.4 REQUIRED )
  • version:指定查找库的版本号。EXACT:要求该版本号必须精确匹配。QUIET:禁掉没有找到时的警告信息。REQUIRED选项表示如果包没有找到的话,CMake的过程会终止,并输出警告信息。

        搜索有两种模式

  • Module模式:搜索CMAKE_MODULE_PATH指定路径下的FindXXX.cmake文件,执行该文件从而找到XXX库。其中,具体查找库并给XXX_INCLUDE_DIRS和XXX_LIBRARIES两个变量赋值的操作由FindXXX.cmake模块完成。
  • Config模式:搜索XXX_DIR指定路径下的XXXConfig.cmake文件从而找到XXX库。其中具体查找库并给XXX_INCLUDE_DIRS和XXX_LIBRARIES两个变量赋值的操作由XXXConfig.cmake模块完成。

        两种模式看起来似乎差不多,不过cmake默认采取Module模式,如果Module模式未找到库,才会采取Config模式。
        如果XXX_DIR路径下找不到XXXConfig.cmake文件,则会找/usr/local/lib/cmake/XXX/中的XXXConfig.cmake文件。总之,Config模式是一个备选策略。通常,库安装时会拷贝一份XXXConfig.cmake到系统目录中,因此在没有显式指定搜索路径时也可以顺利找到。
        若XXX安装时没有安装到系统目录,则无法自动找到XXXConfig.cmake,需要在CMakeLists.txt最前面添加XXX的搜索路径。

(15)列表操作

LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules)
list(LENGTH <list><output variable>)
list(GET <list> <elementindex> [<element index> ...]<output variable>)
list(APPEND <list><element> [<element> ...])
list(FIND <list> <value><output variable>)
list(INSERT <list><element_index> <element> [<element> ...])
list(REMOVE_ITEM <list> <value>[<value> ...])
list(REMOVE_AT <list><index> [<index> ...])
list(REMOVE_DUPLICATES <list>)
list(REVERSE <list>)
list(SORT <list>)
  • ENGTH:回list的长度
  • GET:返回list中index的element到value中
  • APPEND:添加新element到list中
  • FIND:返回list中element的index,没有找到返回-1
  • INSERT:将新element插入到list中index的位置
  • REMOVE_ITEM:从list中删除某个element
  • REMOVE_AT:从list中删除指定index的element
  • REMOVE_DUPLICATES:从list中删除重复的element
  • REVERSE:将list的内容反转
  • SORT:将list按字母顺序排序

5.3 静态库和共享库

(1)静态库

        原理:在编译时将源代码复制到程序中,运行时不用库文件依旧可以运行。
        优点:运行已有代码,运行时不用再用库;无需加载库,运行更快
        缺点:占用更多的空间和磁盘;静态库升级,需要重新编译程序

(2)共享库(常用)

        原理:编译时仅仅是记录用哪一个库里面的哪一个符号,不复制相关代码
        优点:不复制代码,占用空间小;多个程序可以同时调用一个库;升级方便,无需重新编译
        缺点:程序运行需要加载库,耗费一定时间

6 ORB_SLAM2中Cmake文件解析

cmake_minimum_required(VERSION 2.8)		#设定cmake最小版本号
project(ORB_SLAM2)						#指定项目工程

#IF 和 ENDIF构成一个if语句
IF(NOT CMAKE_BUILD_TYPE)			    #编译的类型(debug;release)
  SET(CMAKE_BUILD_TYPE Release)	        
ENDIF()

MESSAGE("Build type: " ${CMAKE_BUILD_TYPE})		#输出消息:"Build type: Release"(打印调试信息)

#cmake_c_flags用来设置编译选项 如 -g -wall(不展示警告);-march=native,GCC会自动检测你的CPU支持的指令集
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}  -Wall  -O3 -march=native ")	
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall   -O3 -march=native")

# Check C++11 or C++0x support
include(CheckCXXCompilerFlag)			#include:从文件或模块加载并运行CMake代码 ;CheckCXXCompilerFlag: 检查CXX编译器是否支持给定标志

#以下代码都用于自动判断系统编译器是否支持c++11标准;	
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)		
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
   add_definitions(-DCOMPILEDWITHC11)
   message(STATUS "Using flag -std=c++11.")
elseif(COMPILER_SUPPORTS_CXX0X)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
   add_definitions(-DCOMPILEDWITHC0X)
   message(STATUS "Using flag -std=c++0x.")
else()
   message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules)
#list(APPEND <list><element> [<element> ...])  添加新element到list中
#CMAKE_MODULE_PATH:  指定要由CMake模块加载的CMake模块的搜索路径include() 要么 find_package()命令,然后检查CMake随附的默认模块。								
#{PROJECT_SOURCE_DIR}为包含PROJECT()的最近一个CMakeLists.txt文件所在的文件夹									
#cmake_modules:用于找寻不知名库时,事先在CMakeLists.txt相同位置建立一个叫cmake_modules的文件夹,在里面创建寻找库并命名的指令								


#设置OpenCV的目录
set(OpenCV_DIR /home/z/cmake-3.4.9/build)  
find_package(OpenCV 3.4.9 QUIET)
if(NOT OpenCV_FOUND)
      message(FATAL_ERROR "OpenCV > 2.4.3 not found.")
endif()

#找到各种头文件以及源码
find_package(Eigen3 3.1.0 REQUIRED)			
find_package(Pangolin REQUIRED)

include_directories(					
#提供头文件路径它提供了一个搜索头文件暂时的根目录,即你可以在cmakelists中写上
#include_directories(/usr/local/include)来让库文件搜索以/usr/local/include为基础,即在main函数前写上#include “opencv/cv.h"即可	
						
${PROJECT_SOURCE_DIR}		
#{PROJECT_SOURCE_DIR}为包含PROJECT()的最近一个CMakeLists.txt文件所在的文件夹			
${PROJECT_SOURCE_DIR}/include
${EIGEN3_INCLUDE_DIR}
${Pangolin_INCLUDE_DIRS}
)

#设置变量到工程lib下	构建时将所有LIBRARY目标放置的位置
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)	

#建立共享库
add_library(${PROJECT_NAME} SHARED			
src/System.cc
src/Tracking.cc
src/LocalMapping.cc
src/LoopClosing.cc
src/ORBextractor.cc
src/ORBmatcher.cc
src/FrameDrawer.cc
src/Converter.cc
src/MapPoint.cc
src/KeyFrame.cc
src/Map.cc
src/MapDrawer.cc
src/Optimizer.cc
src/PnPsolver.cc
src/Frame.cc
src/KeyFrameDatabase.cc
src/Sim3Solver.cc
src/Initializer.cc
src/Viewer.cc
)

#该指令的作用为将目标文件与库文件进行链接
target_link_libraries(${PROJECT_NAME}		
${OpenCV_LIBS}
${EIGEN3_LIBS}
${Pangolin_LIBRARIES}
${PROJECT_SOURCE_DIR}/Thirdparty/DBoW2/lib/libDBoW2.so
${PROJECT_SOURCE_DIR}/Thirdparty/g2o/lib/libg2o.so
)


#指定可执行文件的输出位置	CMAKE_RUNTIME_OUTPUT_DIRECTORY: 构建RUNTIME目标文件的输出目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/Examples/RGB-D)	

#使用指定的源文件将可执行文件添加到项目中。
add_executable(rgbd_tum					
Examples/RGB-D/rgbd_tum.cc)
target_link_libraries(rgbd_tum ${PROJECT_NAME})

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/Examples/Stereo)

add_executable(stereo_kitti
Examples/Stereo/stereo_kitti.cc)
target_link_libraries(stereo_kitti ${PROJECT_NAME})

add_executable(stereo_euroc
Examples/Stereo/stereo_euroc.cc)
target_link_libraries(stereo_euroc ${PROJECT_NAME})		


set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/Examples/Monocular)

add_executable(mono_tum
Examples/Monocular/mono_tum.cc)
target_link_libraries(mono_tum ${PROJECT_NAME})

add_executable(mono_kitti
Examples/Monocular/mono_kitti.cc)
target_link_libraries(mono_kitti ${PROJECT_NAME})

add_executable(mono_euroc
Examples/Monocular/mono_euroc.cc)
target_link_libraries(mono_euroc ${PROJECT_NAME})




  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
CMake是一种跨平台的开源构建工具,它可以自动生成与操作系统和编译器兼容的构建脚本,使项目的构建更加简单和灵活。本文将针对Linux系统进行CMake入门教程。 首先,你需要在Linux系统上安装CMake。你可以通过包管理工具,如apt或yum,在终端中运行相应的安装命令来安装CMake。 安装完成后,你可以进入你的项目目录,创建一个CMakeLists.txt文件来配置你的项目。CMakeLists.txt是CMake的配置文件,它定义了项目的目标、依赖关系和编译选项等。 打开一个文本编辑器,在CMakeLists.txt中添加以下内容: ``` cmake_minimum_required(VERSION 3.10) project(MyProject) set(CMAKE_CXX_STANDARD 11) add_executable(MyExecutable main.cpp) ``` 在这个配置中,我们首先指定了CMake的最低版本要求,并命名了我们的项目。接下来,我们设置了C++的标准为C++11。然后,我们使用add_executable命令添加了一个可执行文件目标,并指定其源文件为main.cpp。 保存并关闭CMakeLists.txt文件。 然后,你需要在终端中进入你的项目目录,并创建一个build目录用于构建过程。 ``` mkdir build cd build ``` 在build目录中,你可以运行cmake命令来配置你的项目。 ``` cmake .. ``` 这将根据CMakeLists.txt文件生成构建脚本。如果你在CMakeLists.txt中没有错误,你将看到一些输出信息,并且build目录中将生成构建脚本。 最后,你可以运行make命令来编译你的项目。 ``` make ``` 这将根据生成的构建脚本编译你的项目。如果你的项目没有编译错误,你将在build目录中得到一个可执行文件。 至此,你已经成功入门了CMakeLinux系统上的使用。你可以根据自己的需要修改CMakeLists.txt来添加更多的目标、库和编译选项等。 总结起来,CMake是一个功能强大且易于使用的构建工具,它可以帮助你更好地管理和构建你的项目。希望这个教程对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

几度春风里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值