当前位置:   article > 正文

(学习笔记)制作一个简单的C++工程

c++工程

本文参考资料:《视觉SLAM十四讲》

目录

一、新建一个库

二、新建一个CMakeLists.txt文件

三、新建一个头文件

四、新建C++程序

五、使用cmake


当我们刚入门C++的时候,一定会编写一个如下的C++程序:

  1. #include <iostream>
  2. using namespace std;
  3. void print_Hello();
  4. int main()
  5. {
  6. print_Hello();
  7. return 0;
  8. }
  9. void print_Hello()
  10. {
  11. cout << "Hello!" << endl;
  12. }

然后使用g++编译这个程序,最后输入./a.out运行刚刚编译的程序,输出Hello!。

        现在让我们来修改一下这个程序,我们尝试着自己编写头文件以代替#include <iostream>,编写一个库用来存放函数,最后使用cmake代替g++完成程序的编译和管理源代码。

一、新建一个库

        在一个C++工程中,并不是所有代码都会编译成可执行文件。只有带main函数的文件才会生成可执行程序,而另一些代码,我们只想把它们打包成一个东西,供其他程序调用,这个东西叫做库(library)。

        一个库往往是许多算法、程序的集合,我们要学习如何用cmake生成库,并且使用库中的函数。现在我们演示如何自己编写一个库:

        首先在Linux系统中建一个文件夹,命名为C++_project,在这个文件夹下新建一个libhello.cpp文件:

  1. #include<iostream>
  2. using namespace std;
  3. void printHello()
  4. {
  5. cout << "Hello!" << endl;
  6. }

        这个库提供了一个printHello函数,调用此函数将输出一条信息。但是它没有main函数,这意味着这个库里没有可执行文件。

二、新建一个CMakeLists.txt文件

我们在C++_project文件夹下新建一个CMakeLists.txt文件,内容如下:

  1. #声明要求的cmake最低版本
  2. cmake_minimum_required(VERSION 2.8)
  3. #声明一个cmake工程
  4. project(hello)

        CMakeLists.txt文件用于告诉cmake要对这个目录下的文件做什么事情。CMakeLists.txt文件的内容需要遵循cmake的语法。根据注释,我们应该理解每句话做了些什么。

我们在CMakeLists.txt里加上如下内容:

add_library(hello libhello.cpp)

这条命令告诉cmake,我们想把这个文件编译成一个叫做“hello” 的库。

        在Linux中,库文件分成静态库和共享库两种。静态库以.a作为后缀名,共享库以.so结尾。所有库都是一些函数打包后的集合,差别在于静态库每次被调用都会生成一个副本,而共享库则只有一个副本,更省空间。如果想生成共享库而不是静态库,只需要在CMakeLists.txt中把上一条语句换成以下语句:

add_library(hello_shared SHARED libhello.cpp)

三、新建一个头文件

        库文件是一个压缩包,里面有编译好的二进制函数。如果仅有.a或.so库文件,那么我们并不知道里面的函数具体是什么,调用的形式又是什么样的。为了让别人(或自己)使用那个库,我们需要提供一个头文件,说明这些库里都有些什么。因此,对库的使用者,只要拿到了头文件和库文件。就可以调用这个库。

下面编写libhello的头文件,命名为libhello.h:

  1. #ifndef LIBHI_H_
  2. #define LIBHI_H_
  3. //上面的宏定义是为了防止重复引用这个头文件而引起的重定义错误
  4. //打印一句hello的函数
  5. void printHello();
  6. #endif

这样,根据这个文件和库文件,就可以使用printHello函数了。

四、新建C++程序

最后,我们新建一个hello.cpp文件,写一个可执行程序来调用这个简单的函数:

  1. #include "libhello.h"
  2. //使用libhello.h中的printHello()函数
  3. int main()
  4. {
  5. printHello();
  6. return 0;
  7. }

然后,在CMakeLists.txt中添加一个可执行的生成命令,链接到刚才使用的库上:

  1. #添加一个可执行程序
  2. #语法:add_executable(程序名 源代码文件)
  3. add_executable(hello hello.cpp)
  4. target_link_libraries(hello hello_shared)

通过这两行语句,hello程序就能顺利使用hello_shared库中的代码了。

五、使用cmake

        当我们编写好头文件、库、CMakeLists.txt文件、C++程序后,我们就要对这个程序进行编译和运行了。

        实际上,任何一个C++程序都可以用g++来编译。但是当所写的程序规模越来越大时,一个工程里可能有许多个文件夹和源文件,当我们要编译时,输入的编译命令将越来越长。通常,一个小型的C++项目可能含有十几个类,各类间还存在着复杂的依赖关系。其中一部分要编译成可执行文件,另一部分编译成库文件。如果仅靠g++命令,则需要大量的编译指令,整个编译过程会变得异常繁琐。因此,对于C++项目,使用一些工程管理工具会更加高效。

        在一个cmake工程中,我们会用cmake命令生成一个makefile文件,然后用make命令根据这个makefile文件的内容编译整个工程。

        现在,在当前目录下,调用cmake对该工程进行cmake编译(指令最后有个句点,这表示在当前目录下进行cmake):

cmake .

        cmake会输出一些编译信息,然后在当前目录下生成一些中间文件,其中最重要的就是MakeFile。由于MakeFile是自动生成的,我们不必修改它。现在,用make命令对工程进行编译:

终端输入:

make

        在编译过程中会输入一个编译进度。如果顺利通过,我们就可以得到在CMakeLists.txt中声明的那个可执行文件hello。执行它:

./hello

终端会输出Hello!。

        这次我们使用了先执行cmake再执行make的做法,执行cmake的过程处理了工程文件之间的关系,而执行make过程实际调用了g++来编译程序。虽然这个过程中多了调用cmake和make的步骤,但我们对项目的编译管理工作从输入一串g++命令,变成了维护若干个比较直观的CMakeLists.txt文件,这将明显降低维护整个工程的难度。例如,如果想新增一个可执行文件,只需在CMakeLists.txt中添加一行“add_executable”命令即可,而后续的步骤是不变的。cmake会帮我们解决代码的依赖关系,无需输入一大串g++命令。

        在这个过程中唯一让我们不满的是,cmake生成的中间文件还留在我们的代码文件中。当我们想要发布代码时,我们并不希望把这些中间文件一同发布出去。这时我们还需要把它们一个一个地删除。一种更好的做法是让这些中间文件都放在一个中间目录中,在编译成功后,把这个中间目录删除即可。所以,更常见的的编译cmake工程的做法如下:

  1. mkdir build
  2. cd build
  3. cmake ..
  4. make

        我们新建了一个中间文件夹“build”,然后进入build文件夹,通过cmake ..命令对上一层文件夹也就是代码所在文件夹进行编译。这样,cmake产生的中间文件就会生成在build文件夹中,与源代码分开。当发布源代码时,只要把build文件夹删了就行。

现在,简单回顾一下我们之前做了什么:

1、程序代码由头文件和源文件组成;

2、带有main函数的源文件编译成可执行文件,其他的编译成库文件;

3、如果可执行程序想调用库文件中的函数,则它需要参考该库提供的头文件,以明白调用的格式,同时,要把可执行程序链接到库文件上。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/146132
推荐阅读
相关标签
  

闽ICP备14008679号