cmake中多级CMakeLists.txt调用

这篇具有很好参考价值的文章主要介绍了cmake中多级CMakeLists.txt调用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


  在c/c++工程开发中,往往会涉及多级CMakeLists.txt的调用,并且调用方式错综复杂,主要有以下两种方式:
  1. 子目录中的CMakeLists.txt独立生成目标,不作为主目标生成过程主的依赖存在,与主目标并无任何关系。
  2. 子目录中的CMakeLists.txt作为主目标的依赖源文件,不单独生成目标,作为主目标生成过程主的部分源文件,通常以生成.a静态库的方式提供给主CMakeLists.txt使用。

一.工程目录结构

  下面给出了测试工程目录,进行了两项测试:一是unit-test目录作为独立生成目标,其CMakeLists.txt在主CMakeLists.txt主被调用;二是subfunc和subsubfunc作为主CMakeLists.txt向下两级的依赖,为主CMakeLists.txt提供源文件支持,其CMakeLists.txt为逐级调用的方式:CMakeLists.txt----->/subfunc/CMakeLists.txt------>/subfunc/subsubfunc/CMakeLists.txt
  具体目录结构如下:

cmaketest
├── build                                   // 编译目录,生成的目标执行文件文件、静态库、中间缓存文件均存在此处
├── inc                                     // 主头文件目录
│   └── func1.hpp
│   └── func2.hpp
│
└── src                                     // 主源文件目录
│    └── func1.cpp
│    └── func2.cpp
│
└── subfunc                                 // 依赖的一级子目录
│    └── subsubfunc                         // 依赖的二级子目录
│    │        └── subsubfunc.cpp
│    │        └── subsubfunc.hpp
│    │        └──CMakeLists.txt             // 被cmaketest/subfunc/CMakeLists.txt调用
│    └── subfunc.cpp
│    └── subfunc.hpp
│    └── CMakeLists.txt                     // 被cmaketest/CMakeLists.txt调用
│
└── unit-test                               // 单元测试目录,独立生成目标文件
│    └──unit-test.cpp
│    └── CMakeLists.txt                    // 被cmaketest/CMakeLists.txt调用
│
├── main.cpp
├── CMakeLists.txt                        // 最上层、主CMakeLists.txt 

二.工程源代码

2.1 上层目录

2.1.1 cmaketest/CMakeLists.txt

cmake_minimum_required(VERSION 3.8)     # 1.cmake版本
PROJECT(cmaketest)                      # 2.工程名

# set the project name
set(PROJECT_NAME cmaketest)             # 3.设置工程名

# specify the C++ standard 
set(CMAKE_CXX_STANDARD 17)              # 4.设置c++标准为c++17
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 5.设置本地头文件路径,注意:子目录中的头文件通过target_include_directories添加到${PROJECT_NAME}INCLUDE_DIRECTORIES(
    inc                 # 上层头文件路径
    ${SUB_INCLUDE_DIR}  # 下级头文件目录
)

# 6.将源文件路径添加到变量SRC_LIST中
AUX_SOURCE_DIRECTORY(.          SRC_LIST)
AUX_SOURCE_DIRECTORY(src        SRC_LIST)

# 7.生成目标(可执行文件):cmaketest
ADD_EXECUTABLE(${PROJECT_NAME} ${SRC_LIST})

# 8.设置编译时依赖的subfunc静态库
target_link_libraries(${PROJECT_NAME}    #目标:tcu
    subfunc        # sub子目录下的静态库文件
    subsubfunc     # subsub子目录下的静态库文件
)

# 9.添加子目录,这样子目录中的CMakeLists.txt才会被调用
add_subdirectory(subfunc)    # 调用subfunc子目录中的CMakeLists.txt,生成静态库而不生成新目标,目标与主CMakeLists.txt中设定的一致

add_subdirectory(unit-test)   # 调用unit-test子目录中的CMakeLists.txt,生成新目标,目标与主CMakeLists.txt中设定的无关,仅仅是调用

注意:INCLUDE_DIRECTORIES包含的是的头文件的路径可以被各级子目录中的目标所使用,而target_include_directories包含的头文件路径只能被特定目标所使用;另外,注意这里采用的是变量传递( ${SUB_INCLUDE_DIR}引入子路径 )的方式引入子目录中的头文件路径。

2.1.2 cmaketest/main.cpp

#include <iostream>
#include <string>
#include "func1.hpp"   //应用层头文件1
#include "func2.hpp"   //应用层头文件2

int main(int argc, char *argv[])
{
    func1();  //调用上层func1
    func2();  //调用上层func2
    return 0;
}

2.1.3 cmaketest/inc/func1.hpp

#ifndef __FUNC1_HPP__
#define __FUNC1_HPP__

int func1(void);

#endif

2.1.4 cmaketest/inc/func2.hpp

#ifndef __FUNC2_HPP__
#define __FUNC2_HPP__

int func2(void);

#endif

2.1.5 cmaketest/src/func1.cpp

#include "subfunc.hpp"   //subfunc头文件
#include "func1.hpp"     //应用层头文件1
#include <iostream>
#include <string>

int func1(void)
{
    std::cout<<"------------func1函数调用开始----------"<<std::endl;
    subfunc1();
    std::cout<<"------------func1函数调用结束----------"<<std::endl<<std::endl;
    return 0;
}

2.1.6 cmaketest/src/func2.cpp

#include "subfunc.hpp"   //subfunc头文件
#include "func2.hpp"     //应用层头文件1
#include <iostream>
#include <string>

int func2(void)
{
    std::cout<<"------------func2函数调用开始----------"<<std::endl;
    subfunc2();
    std::cout<<"------------func2函数调用结束----------"<<std::endl;
    return 0;
}

2.2 subfunc及subsubfunc子目录

2.2.1 cmaketest/subfunc/CMakeLists.txt

# 1.将本目录下的所有.c 文件添加到SUB_DIR_LIB_SRCS变量
AUX_SOURCE_DIRECTORY(. SUB_DIR_SRC_LIST)

# 2.设置当前的头文件路径
set(SUB_INCLUDE_DIR 
    ${CMAKE_CURRENT_SOURCE_DIR}          # 当前源文件路径
    ${SUB_SUB_INCLUDE_DIR}               # 由下层subsubfunc目录传递的头文件路径
    CACHE INTERNAL "subfunc include dir" # 这个字符串相当于对变量SUB_INCLUDE_DIR的描述说明,不能省略,但可以自己随便定义,只有添加了这个描述SUB_INCLUDE_DIR变量才能被上层CMakeLists.txt调用!!!
)

MESSAGE(STATUS "subfunc层头文件路径 :${SUB_INCLUDE_DIR}")

# 3.生成静态库
add_library(subfunc ${SUB_DIR_SRC_LIST})

# 4.添加subsubfunc子目录,这样子目录中的CMakeLists.txt才会被调用
add_subdirectory(subsubfunc)

2.2.2 cmaketest/subfunc/subfunc.hpp

#ifndef __SUB_FUNC_HPP__
#define __SUB_FUNC_HPP__

int subfunc1(void);
int subfunc2(void);

#endif

2.2.3 cmaketest/subfunc/subfunc.cpp

#include "subfunc.hpp"
#include "subsubfunc.hpp"
#include <iostream>
#include <string>

int subfunc1(void)
{
    std::cout<<"------subfunc1函数调用开始------"<<std::endl;
    /* 中间调用subsubfunc1函数 */
subsubfunc1();
    std::cout<<"------subfunc1函数调用结束------"<<std::endl;
    return 0;
}
int subfunc2(void)
{
    std::cout<<"------subfunc2函数调用开始------"<<std::endl;
subsubfunc2();

    /* 中间调用subsubfunc2函数 */

    std::cout<<"------subfunc2函数调用结束------"<<std::endl;
    return 0;
}

2.2.4 cmaketest/subfunc/subsubfunc/CMakeLists.txt

# 1.将本目录下的所有.c 文件添加到SUB_DIR_LIB_SRCS变量
AUX_SOURCE_DIRECTORY(. SUB_SUB_DIR_SRC_LIST)

# 2.设置当前的头文件路径
set(SUB_SUB_INCLUDE_DIR 
    ${CMAKE_CURRENT_SOURCE_DIR}              # 当前源文件路径
    CACHE INTERNAL "subsubfunc include dir"  # 这个字符串相当于对变量SUB_SUB_INCLUDE_DIR的描述说明,不能省略,但可以自己随便定义,只有添加了这个描述SUB_SUB_INCLUDE_DIR变量才能被上层CMakeLists.txt调用!!!
)

MESSAGE(STATUS "subsubfunc层头文件路径 :${SUB_SUB_INCLUDE_DIR}")

# 3.生成静态库
add_library(subsubfunc ${SUB_SUB_DIR_SRC_LIST})

2.2.5 cmaketest/subfunc/subsubfunc/subsubfunc.hpp

#ifndef __SUB_SUB_FUNC_HPP__
#define __SUB_SUB_FUNC_HPP__

int subsubfunc1(void);
int subsubfunc2(void);

#endif

2.2.6 cmaketest/subfunc/subsubfunc/subsubfunc.cpp

#include "subsubfunc.hpp"

#include <iostream>
#include <string>

int subsubfunc1(void)
{
    std::cout<<"-subsubfunc1函数调用开始-"<<std::endl;
    
    std::cout<<"-subsubfunc1函数调用结束-"<<std::endl;
    return 0;
}
int subsubfunc2(void)
{
    std::cout<<"-subsubfunc2函数调用开始-"<<std::endl;

    std::cout<<"-subsubfunc2函数调用结束-"<<std::endl;
    return 0;
}

分析:注意头文件目录变量的逐级向上传递,通过设置SUB_SUB_INCLUDE_DIR变量(必须添加CACHE INTERNAL "subsubfunc include dir"描述),将subsubfunc文件下的头文件路径传递给了上级sunfunc文件下的CMakeLists.txt;通过设置SUB_INCLUDE_DIR变量(必须添加CACHE INTERNAL "subfunc include dir"描述),将subfunc文件下的头文件路径(包含之前获得的${SUB_SUB_INCLUDE_DIR})传递给了最上层文件下的CMakeLists.txt。

2.3 unit-test子目录

2.3.1 cmaketest/unit-test/CMakeLists.txt

add_executable(unit-test unit-test.cpp)
target_link_libraries(unit-test boost_system pthread)

2.3.2 cmaketest/unit-test/unit-test.cpp

#include <boost/asio.hpp> 
#include <iostream>

int main(int argc,char* argv[])
{
    std::cout<<"unit-test代码调用!!!"<<std::endl;
    return 0;
}

2.4 源代码git路径

https://github.com/hututu578/cmaketest

三.编译及出现的问题

  在项目路径下创建/build文件夹,用于存放cmake编译过程中生成的各种中间文件、库、最终目标文件等:

cd build
cmake . .
make

  在cmake编译的过程中发现了一个问题,就是一开始执行cmake . .时候,并没有完成头文件变量的传递,导致make编译出错。cmake . .执行与make执行结果如下:
cmake . .
多层级 cmakelists,C++,c++,单元测试,junit
make
多层级 cmakelists,C++,c++,单元测试,junit
  可以看到,由于SUB_SUB_INCLUDE_DIR变量并没有传递到subfunc层的CMakeLists.txt,从而导致了在subfunc层并没有包含全部发头文件路径,导致编译的时候找不到subsubfunc.hpp。
解决方案:
  经过反复测试发现,多执行几次cmake . .(三次以上)就可以解决这个问题,猜测是因为多次执行cmake . .的过程完成了SUB_SUB_INCLUDE_DIR和SUB_INCLUDE_DIR变量向上层的传递,多执行几次cmake . .的执行结果如下:
多层级 cmakelists,C++,c++,单元测试,junit

四.build目录分析

  下面是执行编译完成后的build文件目录结构:
多层级 cmakelists,C++,c++,单元测试,junit
可以看出,unit-test作为独立的子目录,生成了独立的目标文件unit-test。而在subfunc下生成了libsubfunc.a的静态库文件,在subsubfunc下生成了libsubsubfunc.a的静态库文件,这两个库文件供最上层CMakeLists.txt调用,并最终生成一个目标文件cmaketest。

五.程序执行结果

多层级 cmakelists,C++,c++,单元测试,junit

六.总结

  上述测试了两种类型的多级CMakeLists.txt调用,一种是独立的unit-test生成独立的目标文件,与主CMakeLists.txt仅有一个调用与被调用的关系,并不存在任何的编译依关系;
  而另一种多级CMakeLists.txt调用之间存在上下级的依赖关系,下层的源代码给上层的调用提供支持(以生成静态库的方式),这里进行了分层设计,下层的头文件路径仅传递给调用的上一层而不会传递给最上层,这种变量传递的方式提高了代码的分层性,这里需要注意变量的设置(CACHE INTERNAL属性的必须添加)以完成下层到上层的变量传递,上述的两种分层CMakeLists.txt调用方式可覆盖基本的全部开发场景。文章来源地址https://www.toymoban.com/news/detail-784396.html

到了这里,关于cmake中多级CMakeLists.txt调用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • CMake Error at CMakeLists.txt: (FIND_PACKAGE)找不到ncnn包的解决方法

    demo指路:https://github.com/EdVince/Stable-Diffusion-NCNN 在 Linux端 使用 cmake 编译文件时, 执行 cmake .. 命令,报错: 拉取 ncnn 的代码库(包括submodule)后没有 build and Install ,所以 cmake 时找不到对应的包,只需要让它找到对应的包即可,分为2步: 生成对应的cmake文件( ncnnConfig.cmake

    2024年02月11日
    浏览(121)
  • CMake Error: The source directory “XXX“ does not appear to contain CMakeLists.txt

    正常CMakeLists.txt文件是在项目根目录下,而我们在项目的build文件夹中进行cmake,导致找不到文件,解决方法,命令行后加两个点表示上级目录,关键就是这两个点:

    2024年02月04日
    浏览(43)
  • CMake Error at CMakeLists.txt:5 (find_package):By not providing “FindOpenCV.cmake“ in CMAKE_MODULE

    CMake Error at CMakeLists.txt:5 (find_package): By not providing \\\"FindOpenCV.cmake\\\" in CMAKE_MODULE_PATH this project has asked CMake to find a package configuration file provided by \\\"OpenCV\\\", but CMake did not find one.  CMake Error at CMakeLists.txt:5 (find_package): By not providing \\\"FindOpenCV.cmake\\\" in CMAKE_MODULE_PATH this project has asked CMake to

    2024年04月27日
    浏览(35)
  • ncnn - ubuntu调用vulkan加速ncnn是的CMakeLists.txt和bashrc配置

    ncnn使用vulkan来加速时,需要先安装vulkan,然后再使用vulkan来编译ncnn,最后才是使用编译好的ncnn来推理模型。。 这里的vulkan再Ubuntu中通常是直接解压安装,然后配置环境变量如下: export VULKAN_SDK=/home/fwq/softs/1.2.182.0/x86_64 1.2.182.0 是我使用的vulkan版本。。 配置完上述路径后,

    2024年01月23日
    浏览(27)
  • 【ORB-SLAM3】CMake Error at CMakeLists.txt:37 (message): OpenCV > 2.4.3 not found.

    ZED2相机配置使用ORB-SLAM3,出现关于opencv的报错 CMake Error at CMakeLists.txt:37 (message): OpenCV 2.4.3 not found. 由于我的opencv是4版本的,而Cmakelist里面第33行找的是find_package(OpenCV 3.0 QUIET)也就是3版本的,所以找不到,因此而报错 将 find_package(OpenCV 3.0 QUIET) 改为 find_package(OpenCV 4.0 QUIET) 即可

    2024年02月07日
    浏览(36)
  • CMake Error at CMakeLists.txt:1:Parse error.Expected a command name, got unquoted argument with text

    1.CMake升级       通过查阅CMake升级博客,个人觉得是这个问题概率较小,也可以找编译成功的人,通过下列命令查看版本号对比来判断是否与这有关。     如果没有多余空格仍然报错,可在终端使用vim打开文件检查是否有多余的代码。ubantu安装vim的命令如下: vim打开CMakeL

    2024年02月15日
    浏览(32)
  • CMakeLists.txt编写简单介绍:CMakeLists.txt同时编译.cpp和.cu

    不想付费的同学可以参考本人知乎添加链接描述,关于CMakeLists.txt的相关介绍,这里不赘诉,本人的出发点是借助于CMakeLists.txt掌握基本的C++构建项目流程,下面是本人根据网络资料以及个人实践掌握的资料。 下图是一个使用CUDA实现hello world的项目,一般来说,一个标准的C

    2024年04月10日
    浏览(27)
  • ROS功能包目录下CMakeLists.txt

    CMake基础教程(24)add_executable生成目标可执行文件 CMake中add_executable的使用 CMake中的add_executable命令用于使用指定的源文件向项目(project)添加可执行文件,其格式如下: 这里我们用到 Normal Executables这种用法,Normal Executables:添加一个名为的可执行目标(executable target),该目标将

    2024年02月11日
    浏览(27)
  • VSCode:使用CMakeLists.txt构建C++项目

    插件: CMake插件主要功能是CMake语法高亮、自动补全 CMake Tools的功能主要是结合VSCode IDE使用CMake这个工具,比如生成CMake项目、构建CMake项目等 CMake Tools Helper CMake工具本身还是要下载到本地,并且配置环境变量。 包括6部分:build文件夹、include文件夹、src文件夹、lib文件夹、

    2024年02月03日
    浏览(52)
  • CUDA和C++混合编程及CMakeLists.txt

    首先认识一个问题,单从CMakeLists.txt的角度来看,无法同时使用两种编译器编译两种语言。不过直接编写Makefile是可以的,通过设置不同的任务,可以实现一个Makefile编译两个语言。但这不是这里要讨论的重点。 使用CUDA和C++进行混合编程的意思是:在cpp文件中调用CUDA函数,实

    2024年02月11日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包