Cmakelist写法

Cmakelist写法

c++编译原理

这一节可以不看,主要是辅助理解cmakelist为什么要那么写

img

  • 预处理

    在预处理阶段主要是处理一些#号相关的命令,例如 #include #define #ifdef ,在这里实现语句的替换。比如 #define m 5 ,在这个阶段就会将程序中所有的m替换为5。

    #include "xxx.h" 或者 #include <xxx.h> 中。我们可以把常量、宏定义等放入头文件。但是这要求类型只能被定义和命名一次(定义在头文件中,此后不可在其他文件里再进行重复定义)。这两种语法形式都会让include指令替换为整个文件的内容,但是在未指定路径时预处理器搜索路径的方法不同。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M3qmgsN4-1689924877452)(C:\Users\oc\AppData\Roaming\Typora\typora-user-images\image-20230721133408231.png)]

    不过在我们平时写代码时似乎没有太大的影响,观察了很多代码,大家习惯将自己写的头文件使用带引号形式,在使用标准库时使用尖括号形式。

  • 编译处理

  • 汇编器

  • 链接器

    链接分为静态链接和动态链接,动态链接库常是.so文件或.dll文件,而静态链接库是.a或者.lib文件。显然,他们都是前人留下来的轮子,我们只需要直接使用即可。他们的区别如下:

    • 静态链接:在编译链接时,会将库文件中的代码全部加入到可执行文件(.o文件)中,不过静态库对函数库的链接放在编译时期完成,程序在运行时和函数库再无关系。
    • 动态链接:在程序运行时才会被载入,如果不同的应用程序调用相同的库,那么内存里只需要有一份该共享库的实例,避免了空间浪费、程序更新部署和发布的麻烦。

    这些都可以在王道的考研书里找到关于链接的内容,所以我只是简单地写一下。

cmakelist写法

由上图可知,c++编译的过程主要分为预处理、编译、汇编和链接,对应到cmakelist的写法为

  • cmake的一些小操作
    在这里插入图片描述

  • 源代码

    如果我们的.cpp文件都放在某一个大目录下(这个目录可以包含其他类型文件如.h文件),则可以这样指定源文件位置:

    aux_source_directory(. SRC_LIST)

    file(GLOB_RECURSE SRC_LIST ${PROJECT_SOURCE_DIR}/xxx/*.c*)

    这里的xxx可以直接替换为该大目录

  • 预处理

在这里插入图片描述

在工程中我们经常将.h文件放在include文件夹下(或者自己自定义的文件夹),所以将自己的文件夹写进include_directories之中即可。

  • 编译

    在编译中我们可以指定一些选项,比如
    在这里插入图片描述
    在这里插入图片描述

    这些选项可以放在cmakeList的最前端

  • 生成可执行文件

    我们需要将第一步的源代码生成可执行文件,之后再进行链接。因此需要

    add_executable(xxx ${SRC_LIST})

    这里的xxx是你的可执行文件名字,可以自己指定

  • 链接

    首先我们需要在指定目录下查找库,因此可以借助find_library

    find_library(<var> name [path1 path2 ...])

    • 用于存储该命令执行的结果,也就是找到的库的全路径。如果能找到指定库,那么中会存放正常的库路径,否则就是存放NOTFOUND。因此我们也可以借助这一条指令判断是否查找库成功

    • name指定待查找的库名称,可以使用全称如libxxx.a,也可以不带前缀和后缀,直接是xxx

    • path用来指定库的查找路径

    • 一些细节

      • HINTS: 库的搜索路径一般分为两种:默认搜索路径和附加搜索路径。默认搜索路径包含CMake定义的以CMAKE开头的一些变量(CMAKE_PREFIX_PATH)、标准的系统环境变量(如系统环境变量LIB和PATH定义的路径)、系统默认的库安装路径(/usr或者/usr/lib等)。附加搜索路径即我们在find_library中通过HINTS或PATHS指定的路径。具体的内容可参见Cmake命令之find_library介绍 - 简书 (jianshu.com)

    查找结束后即可进行链接

    使用 target_link_libraries(可执行文件名称 ${存储库路径的变量})

    这里的可执行文件名称同本节“生成可执行文件”中的设置,存储库路径的变量则是在find_library中的var。如果有多个var(有多种库的情况),则执行多条target_link_libraries即可。

分层/不分层架构

有时候会发现有的工程会使用多级cmakelist,一般个人写的小demo不必使用。

多级cmakelist的好处在于

  1. 隐藏实现细节,通过多级cmakelist可以将项目的实现细节隐藏在每个模块内部,只需要在顶层CMakelist里暴露必要的接口和变量即可。
  2. 有利于分布式开发,多级cmakelist可以让大家各写各的,最后在顶层cmakelist中集成即可。
  3. 构建顺序控制:如果模块之间存在依赖关系,那么使用多级cmakelist也比较好

总的来说,大型项目使用多级,小型的使用一个就可以了。

假设项目结构如下:

在这里插入图片描述

  • 顶层cmakelist

    一般负责设置项目的一般性信息,如cmake的最低版本要求、项目名称、编译选项等,并且包含对各个子目录中的cmakelist文件进行引用。

在这里插入图片描述

  • src/CMakelist

    一般不做太多配置,而是将任务委托给各个子模块的cmakelist

  • src/module1/CMakelist

    参照上面的cmakelist写法,指定源文件、编译选项、链接库、生成目标代码等

正规组织结构

上两节只是讲了如何使用cmakelist来编译我们的代码,但是在工程中还有一些别的要求。一般来说会把源文件放在src目录中,头文件放入include文件夹下,生成的对象文件放在build文件夹下。

因此我们可以使用

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

这就是指定将生成的elf文件存放到工程根目录下的bin目录。

然后我们再切到build目录下执行cmake .. 和make,这样cmake运行生成的文件就只会呆在build目录下(这其实是默认在哪执行cmake就将所运行生成的文件放在哪里,好像是可以自己重新定义生成位置,不过我懒得找了)

参考

Linux下的静态链接库和动态链接库有什么区别? - 知乎 (zhihu.com)

(12条消息) 动态链接库和静态链接库的区别_静态链接库和动态链接库的区别_wqfhenanxc的博客-CSDN博客

(12条消息) C++的编译流程_c++编译_Lu Zelin的博客-CSDN博客

(12条消息) C++的编译过程及原理_c++编译原理_qq_43133135的博客-CSDN博客

#include 指令 (C/C++) | Microsoft Learn

(12条消息) Linux下CMake简明教程_linux cmake_爱就是恒久忍耐的博客-CSDN博客

-directive-c-cpp?view=msvc-170)

(12条消息) Linux下CMake简明教程_linux cmake_爱就是恒久忍耐的博客-CSDN博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值