cmake简单使用

简介

理论上,任意一个C++程序都可以用g++来编译

当程序规模越来越大时,一个工程可能有许多个文件夹和源文件,这时输入的编译命令将越来越长。通常,一个小型C++项目可能含有十几个类,各类间还存在着复杂的依赖关系。其中一部分要编译成可执行文件,另一部分编译成库文件。如果仅靠g++命令,则需要输入大量的编译指令,整个编译过程会变得异常烦琐。因此,对于C++项目,使用一些工程管理工具会更加高效。在历史上,工程师们曾使用makefile进行自动编译,但下面要谈的cmake比它更加方便。并且cmake在工程上广泛使用

cmake允许开发者编写一种与平台无关(跨平台)的CMakeLists.txt 文件来制定整个工程的编译流程,cmake 工具会解析CMakeLists.txt 文件语法规则,再根据当前的编译平台,生成本地化的Makefile 和工程文件

简而言之,makefile是一个定义源文件编译过程的文件,而CMakeLists.txt是一个可以生成makefile的文件,它们之间的关系如下图所示:

cmake简单使用_第1张图片

cmake的下载

sudo apt-get install cmake

 cmake的使用

单个文件编译

如下,我们写了一个简单的cpp文件

 #include                                                            
 using namespace std;
  
 int main()
 {
     cout<<"hello slam!"<

现在我们想编译该文件以生成一个可执行文件,如果使用g++进行编译是这样的:

g++ helloSLAM.cpp -o helloSLAM

如果我们使用cmake,则我们首先需要编写CMakeLists.txt文件,内容如下:

  #声明cmake的最低版本
  cmake_minimum_required(VERSION 2.8)
  #声明一个cmake工程
  project(hello)
  #添加一个可执行文件,类似于执行g++ helloSLAM.cpp -o helloSLAM                 
  add_executable(helloSLAM helloSLAM.cpp )

文件中内容的各行作用如注释所示

当前路径下各文件如下所示:

保存该文件后,执行如下命令

cmake ./

cmake 后面携带的路径指定了CMakeLists.txt 文件的所在路径,执行结果如下所示

cmake简单使用_第2张图片

可以看到,执行完cmake 之后,除了源文件main.c 和CMakeLists.txt 之外,生成了很多其它的文件或文件夹,包括:CMakeCache.txt、CmakeFiles、cmake_install.cmake、Makefile 

接下来,我们之间执行make编译命令即可生成可执行文件

cmake简单使用_第3张图片

执行可执行文件,执行结果如下 

cmake简单使用_第4张图片

为了便于管理,我们可以把cmake生成的文件单独存放在一个文件夹内, 这时我们只需创建一个build文件夹

之后进入build文件夹,执行

cmake ../

cmake简单使用_第5张图片

可以看到,此时cmake生成的文件就全部在build文件中了 

使用库文件

如果我们的源代码中使用了库文件,该如何编写CMakeLists.txt文件呢

库文件libHelloSLAM.h

  #ifndef LIBHELLOSLAM_H                                                        
  #define LIBHELLOSLAM_H
  
  void printHello();
  
  #endif

libHelloSLAM.cpp

  #include
  using namespace std;
  void printHello()
  {
      cout<<"hello SLAM!"<

helloSLAM.cpp 

  #include
  using namespace std;
  #include"libHelloSLAM.h"
  int main()
  {
  //  cout<<"hello slam!"<

则CMakeLists.txt文件内容如下:

  #声明cmake的最低版本                                                          
  cmake_minimum_required(VERSION 2.8)
  #声明一个cmake工程
  project(hello)
  
  #添加一个静态库文件
  add_library(helloLib libHelloSLAM.cpp)
  #添加一个可执行文件,类似于执行g++ helloSLAM.cpp -o helloSLAM
  add_executable(helloSLAM helloSLAM.cpp )
  #将库文件内容链接到可执行程序上
  target_link_libraries(helloSLAM helloLib)

此时文件结构如下:

之后再次进入build文件夹执行cmake ../命令,文件夹结构没有什么变化

但是执行完make编译命令后,再次查看build文件夹,会发现多了一个libhelloLib.a的文件,该文件就是我们的静态库文件

cmake简单使用_第6张图片

在Linux中,库文件分成静态库和共享库两种静态库以.a作为后缀名,共享库以.so结尾。所有库都是一些函数打包后的集合,差别在于静态库每次被调用都会生成一个副本,而共享库则只有一个副本,更省空间

如果想生成共享库而不是静态库,只需使用以下语句即可。 

add_library(helloSharedLib SHARED libHelloSLAM.cpp) 

此时CMakeLists.txt文件内容为:

  #声明cmake的最低版本
  cmake_minimum_required(VERSION 2.8)
  #声明一个cmake工程
  project(hello)
  
  #添加一个静态库文件
  #add_library(helloLib libHelloSLAM.cpp)
  #添加一个动态库文件
  add_library(helloSharedLib SHARED libHelloSLAM.cpp)
  #添加一个可执行文件,类似于执行g++ helloSLAM.cpp -o helloSLAM
  add_executable(helloSLAM helloSLAM.cpp )
  #将库文件内容链接到可执行程序上
  target_link_libraries(helloSLAM helloSharedLib) 

再次执行cmake ..命令和make编译命令后,build文件内容如下:
cmake简单使用_第7张图片

将源文件放在不同的目录

文件结构如下:
 

.
├── build
├── CMakeLists.txt
├── libHello
│   ├── CMakeLists.txt
│   ├── libHelloSLAM.cpp
│   └── libHelloSLAM.h
└── src
    ├── CMakeLists.txt
    └── helloSLAM.cpp

  • 顶层CMakeLists.txt
  #声明cmake的最低版本
  cmake_minimum_required(VERSION 2.8)
  #声明一个cmake工程
  project(hello)
  
  #添加子文件
  add_subdirectory(libHello)
  add_subdirectory(src) 

其中add_subdirectory 命令告诉cmake 去子目录中寻找新的CMakeLists.txt 文件并解析它 

  • libHello文件夹内的CMakeLists.txt文件 
  add_library(libSharedHello SHARED libHelloSLAM.cpp) 

libHello文件夹内存放的是库文件,因此该 CMakeLists.txt文件表示生成一个共享库文件

  • src文件夹内的 CMakeLists.txt文件 
  include_directories(../libHello)                                              
  add_executable(helloSLAM helloSLAM.cpp)
  target_link_libraries(helloSLAM libSharedHello)

该文件夹内存放的是主程序,其中include_directories 命令用来指明头文件所在的路径 

或者如下:

  include_directories(${PROJECT_SOURCE_DIR}/libHello)
  add_executable(helloSLAM helloSLAM.cpp)
  target_link_libraries(helloSLAM libSharedHello)

这种方式使用到了PROJECT_SOURCE_DIR 变量,该变量指向了一个路径,从命名上可知,该变量表示工程源码的目录。 

和前面一样,进入到build 目录下进行构建、编译,最终会得到可执行文件helloSLAM(build/src/helloSLAM)和库文件libSharedHello.so(build/libHello/libSharedHello.so)

将生成的可执行文件和库文件放在不同的目录

如果我想让可执行文件单独放置在bin目录下,而库文件单独放置在lib目录下,如下所示

├──build
	├──lib
	│	└──libSharedHello.so
	└──bin
		└──helloSLAM

可以通过两个变量来实现,将src 目录下的CMakeList.txt 文件进行修改,如下所示:

  include_directories(${PROJECT_SOURCE_DIR}/libHello)
  set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
  add_executable(helloSLAM helloSLAM.cpp)
  target_link_libraries(helloSLAM libSharedHello)

然后再对libhello 目录下的CMakeList.txt 文件进行修改,如下所示:

  set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)                            
  add_library(libSharedHello SHARED libHelloSLAM.cpp)

EXECUTABLE_OUTPUT_PATH 变量控制可执行文件的输出路径,
LIBRARY_OUTPUT_PATH 变量控制库文件的输出路径。

cmake简单使用_第8张图片

参考:

【精选】CMake 入门与进阶_.cmake文件-CSDN博客 

你可能感兴趣的:(c++,Linux系统,linux,运维,服务器)