视觉slam学习1--cmake

参考博客:https://blog.csdn.net/MOU_IT/article/details/88030911    cmake简介

1,简述

cmake与makefile的联系:

程序大体步骤为:用编辑器编写源代码,如.c文件 |——> 用编译器编译代码生成目标文件,如.o |——> 用链接器连接目标代码生成可执行文件,如.exe。

但如果源文件太多,一个一个编译时就会特别麻烦,于是人们想到,为什么不设计一种类似批处理的程序,来批处理编译源文件呢,于是就有了make工具(不是cmake),它是一个自动化编译工具,你可以使用一条命令实现完全编译。

但是你需要编写一个规则文件,make依据它来批处理编译,这个文件就是makefile(makefile语法链接,所以编写makefile文件也是一个程序员所必备的技能。

但是对于一个大工程,编写makefile实在是件复杂的事,于是人们又想,为什么不设计一个工具,读入所有源文件之后,自动生成makefile呢,于是就出现了cmake工具,它能够输出各种各样的makefile或者project文件,从而帮助程序员减轻负担。但是随之而来也就是编写cmakelist文件,它是cmake所依据的规则。(cmake是为了自动生成makefile文件而产生)

此外,如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的 Make 工具,就得为每一种标准写一次 Makefile ,这将是一件让人抓狂的工作。CMake就是针对上面问题所设计的工具:它首先允许开发者编写一种平台无关的 CMakeList.txt 文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程。从而做到“Write once, run everywhere”。显然,CMake 是一个比上述几种 make 更高级的编译配置工具。一些使用 CMake 作为项目架构系统的知名开源项目有 VTK、ITK、KDE、OpenCV、OSG 等。

linux下使用cmake生成makefile,并且编译的流程如下:

  1. 编写 CMake 配置文件 CMakeLists.txt ;
  2. 执行命令 cmake PATH 或者 ccmake PATH 生成 Makefile。 PATH 是 CMakeLists.txt 所在的目录;
  3. 使用 make 命令进行编译;

一般一个完整的项目大概目录如下:

├── build
| └── bin
| | └── <project_name>
├── doc
| └── <project_name>.txt
├── src
| ├── xxx.c
| └── CMakeLists.txt
├── CMakeLists.txt
├── COPYRIGHT
├── README
└── run<project_name>.sh

2,例子

2.1  cmake编译helloword:

1,根据上面的结构树建立项目。在helloword目录下新建三个文件CMakeLists.txx   COPYRIGHT  README  以及三个文件夹 src  doc  build

mkdir helloword
cd helloword

mkdir src bin doc
touch COPTRIGHT README CMakeLists.txt

此处的CMakeLists.txt为最简单版本

#./CMakeLists.txt
CMAKE——MINIMUM——REQUIRED(VERSION 2.8)
PROJECT(HELLO)
ADD——SUBDIRECTORY(src bin)

注解: 

 1)“#”开头表示注释;
  2)CMake指令大小写不敏感;
  3)CMAKE_MINIMUM_REQUIRED(VERSION 2.8):指定编译这个工程需要CMake的最低版本;
  4)PROJECT(HELLO):构建的工程的名称;
  5)ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL]):这个指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置。上面的例子定义了将 src 子目录加入工程,并指定编译输出(包含编译中间结果)路径为 bin 目录。如果不进行 bin 目录的指定,那么编译结果(包括中间结果)都将存放在 build/src 目录(这个目录跟原有的 src 目录对应) 指定 bin 目录后,相当于在编译时将 src 重命名为 bin,所有的中间结果和目标二进制都将存放在 bin 目录。
2,在src下放源文件以及一个CMakeLists.txt

cd src
touch main.cpp CMakeLists.txt

main.cpp的内容如下

#include <iostream>
using namespace std;
 
int main()
{
  cout << "Hello CMake." << endl;
  return 0;
}

src目录下的CMakeLists.txt内容如下

ADD_EXECUTABLE(hello main.cpp)

注解:ADD_EXECUTABLE(hello main.cpp):这个指令用于生成目标文件,hello是工程名字,后面接着源文件,如果有多个源文件,可以用空格或者分号隔开。

3,这样我们就可以开始构建,进入build目录下

cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..
make

然后可执行文件在build/bin目录下,运行hello

./bin/hello

得到结果。

2.2 同一目录,多个源文件编译的方法

假设src下新添加了mathfunction.cpp 和mathfunction.h

这种情况下修改src下的CMakeLists.txt即可

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 指定生成目标
add_executable(Demo main.cpp mathfunction.cpp)

唯一的改动只是在 add_executable 命令中增加了一个 MathFunctions.cc 源文件。这样写当然没什么问题,但是如果源文件很多,把所有源文件的名字都加进去将是一件烦人的工作。更省事的方法是使用 aux_source_directory 命令,该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名。其语法如下:

aux_source_directory(<dir><variable>)

因此,修改CMakeLists.txt如下

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})

这样,CMake 会将当前目录所有源文件的文件名赋值给变量 DIR_SRCS ,再指示变量 DIR_SRCS 中的源文件需要编译成一个名称为 Demo 的可执行文件。

2.3 多个目录,多个源文件的编译

目录结构如下:

./Demo3
    |
    +--- main.cc
    |
    +--- math/
          |
          +--- MathFunctions.cc
          |
          +--- MathFunctions.h

对于这种情况,需要分别在项目根目录Demo3和math目录里各编写一个CMakeLists.txt,为了方便,我们可以将math目录里的文件编译成静态库再由main函数调用。

根目录中的CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(Demo3)
aux_subdirectory(math)

add_exectable(Demo main.cc)
target_link_libraries(Demo MathFunctions)

该文件添加了下面的内容: 第3行,使用命令 add_subdirectory 指明本项目包含一个子目录 math,这样 math 目录下的 CMakeLists.txt 文件和源代码也会被处理 。第6行,使用命令 target_link_libraries 指明可执行文件 main 需要连接一个名为 MathFunctions 的链接库 。

子目录中的CMakeLists.txt

aux_source_directory(.DIR_LIB_SRCS)

add_library(MathFunctions ${DIR_LIB_SRCS})

在该文件中使用命令 add_library 将 src 目录中的源文件编译为静态链接库

3,CMakeLists文件的语法总结

1)project
    命令语法:project(<projectname> [languageName1 languageName2 … ] )
    命令简述:用于指定项目的名称
    使用范例:project(Main)
2)cmake_minimum_required
    命令语法:cmake_minimum_required(VERSION major[.minor[.patch[.tweak]]][FATAL_ERROR])
    命令简述:用于指定需要的 CMake 的最低版本
    使用范例:cmake_minimum_required(VERSION 2.8)
3)aux_source_directory
    命令语法:aux_source_directory(<dir> <variable>)
    命令简述:用于将 dir 目录下的所有源文件的名字保存在变量 variable 中
    使用范例:aux_source_directory(. DIR_SRCS)
4)add_executable(重要)
    命令语法:add_executable(<name> [WIN32] [MACOSX_BUNDLE][EXCLUDE_FROM_ALL] source1 source2 … sourceN)
    命令简述:用于指定从一组源文件 source1 source2 … sourceN 编译出一个可执行文件且命名为 name
    使用范例:add_executable(Main ${DIR_SRCS})
5)add_library 
    命令语法:add_library([STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1source2 … sourceN)
    命令简述:用于指定从一组源文件 source1 source2 … sourceN 编译出一个库文件且命名为 name
    使用范例:add_library(Lib ${DIR_SRCS})
6)add_dependencies 
    命令语法:add_dependencies(target-name depend-target1 depend-target2 …)
    命令简述:用于指定某个目标(可执行文件或者库文件)依赖于其他的目标。这里的目标必须是 add_executable、add_library、add_custom_target 命令创建的目标
7)add_subdirectory 
    命令语法:add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
    命令简述:用于添加一个需要进行构建的子目录
    使用范例:add_subdirectory(Lib)
8)target_link_libraries(重要)
    命令语法:target_link_libraries(<target> [item1 [item2 […]]][[debug|optimized|general] ] …)
    命令简述:用于指定 target 需要链接 item1 item2 …。这里 target 必须已经被创建,链接的 item 可以是已经存在的 target(依赖关系会自动添加)
    使用范例:target_link_libraries(Main Lib)
9)set(重要)
    命令语法:set(<variable> <value> [[CACHE <type><docstring> [FORCE]] | PARENT_SCOPE])
    命令简述:用于设定变量 variable 的值为 value。如果指定了 CACHE 变量将被放入 Cache(缓存)中。
    使用范例:set(ProjectName Main),例如:set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g"),加调试信息。
10)unset
    命令语法:unset(<variable> [CACHE])
    命令简述:用于移除变量 variable。如果指定了 CACHE 变量将被从 Cache 中移除。
    使用范例:unset(VAR CACHE)
11)message 
    命令语法:message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] “message todisplay”…)
    命令简述:用于输出信息
    使用范例:message(“Hello World”)
12)include_directories(重要)
    命令语法:include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)
    命令简述:用于设定目录,这些设定的目录将被编译器用来查找 include 文件
    使用范例:include_directories(${PROJECT_SOURCE_DIR}/lib)

13)find_path 命令
    命令语法:find_path(<VAR> name1 [path1 path2 …])
    命令简述:用于查找包含文件 name1 的路径,如果找到则将路径保存在 VAR 中(此路径为一个绝对路径),如果没有找到则结果为 <VAR>-NOTFOUND。默认的情况下,VAR 会被保存在 Cache 中,这时候我们需要清除 VAR 才可以进行下一次查询(使用 unset 命令)。find_package和find_path命令相似。
    使用范例:
    find_path(LUA_INCLUDE_PATH lua.h${LUA_INCLUDE_FIND_PATH})
    if(NOT LUA_INCLUDE_PATH)
         message(SEND_ERROR "Header file lua.h not found")
    endif()
14)find_library 命令(重要)
    命令语法:find_library(<VAR> name1 [path1 path2 …])
    命令简述:用于查找库文件 name1 的路径,如果找到则将路径保存在 VAR 中(此路径为一个绝对路径),如果没有找到则结果为 <VAR>-NOTFOUND。一个类似的命令 link_directories 已经不太建议使用了

15) find_package 命令:
    命令语法:FIND_PACKAGE( <name> [version] [EXACT] [QUIET] [NO_MODULE] [ [ REQUIRED | COMPONENTS ] [ componets... ] ] )
    命令描述:这条命令执行后,CMake 会到变量 CMAKE_MODULE_PATH 指示的目录中查找文件 Findname.cmake 并执行。也可以自己定义 Find<name>模块,将其放入工程的某个目录中,通过 SET(CMAKE_MODULE_PATH dir)设置查找路径,供工程FIND_PACKAGE使用。find_package采用两种模式搜索库:

    Module模式:搜索CMAKE_MODULE_PATH指定路径下的 Findname.cmake文件,执行该文件从而找到name库。其中,具体查找库并给name_INCLUDE_DIRS和name_LIBRARIES两个变量赋值的操作由Findname.cmake模块完成。
    Config模式:搜索name_DIR指定路径下的 nameConfig.cmake文件,执行该文件从而找到name库。其中具体查找库并给name_INCLUDE_DIRS和name_LIBRARIES两个变量赋值的操作由nameConfig.cmake模块完成。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值