营销型网站建设特点,做网站用什么数据库好用,网站建设空标记,排行榜C最佳实践之工程编译
在大型c/c工程开发中#xff0c;往往会涉及多级CMakeLists.txt的调用#xff0c;并且调用方式错综复杂#xff0c;主要有以下两种方式#xff1a;
1. 子目录中的CMakeList.txt独立生成目标#xff0c;不作为主目标生成过程的依赖关系#xff08;比…C最佳实践之工程编译
在大型c/c工程开发中往往会涉及多级CMakeLists.txt的调用并且调用方式错综复杂主要有以下两种方式
1. 子目录中的CMakeList.txt独立生成目标不作为主目标生成过程的依赖关系比如dev_tool、driver、ut_test等与主目标并无任何关系。2. 子目录中的CMakeList.txt作为主目标的依赖源文件不单独生成目标作为主目标生成过程主的部分源文件通常以生成.a源文件的方式提供给主CMakeList.txt使用。一、工程目录结构
下面给出了测试工程目录进行了两项测试 unit—test目录作为独立生成目标其CMakeLists.txt在主CMakeList.txt主被调用 subfunc和subsubfunc作为主CMakeList.txt向下两级的依赖为主CMakeList.txt提供源文件支持其CMakeLists.txt为逐级调用的方式 CMakeList.txt-subfunc/CMakeList.txt-subfunc/subfuncfunc/CMakeLists.txt
具体目录结构如下 build: 编译目录生成的目标执行文件、静态库、中间缓存文件都在此处inc主头文件目录src主源文件目录subfunc依赖的一级子目录uinit-test单元测试目录独立生成的目标文件CMakeList.txt最上层主CMakeList.txt
二、工程源代码
2.1、工程源代码
cmake_minimum_required(VERSION 3.8) # cmake 版本
PROJECT(cmaketest) # 工程名#set project name
set(PROJECT_NAME cmaketest) # 设置工程名字set(CMAKE_CXX_STANDARD 17) # 设置C标准为C17
set(CMAKE_CXX_STANDARD_REQUIRED ON) # 设置本地头文件路径注意子目录的头文件是通过target_include_directories添加到${PROJECT_NAME}中
INCLUDE_DIRECTORIES(inc #上层头文件${SUB_INCLUDE_DIR} #下级头文件
)#将源文件路径添加到变量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} #目标tcusubfunc # sub子目录下的静态库文件subsubfunc # subsub子目录下的静态库文件
)# 9.添加子目录这样子目录中的CMakeLists.txt才会被调用# 调用subfunc子目录中的CMakeLists.txt生成静态库而不生成新目标目标与主CMakeLists.txt中设定的一致
add_subdirectory(subfunc)
# 调用unit-test子目录中的CMakeLists.txt生成新目标目标与主CMakeLists.txt中设定的无关仅仅是调用
add_subdirectory(unit-test)
注意
include_directories包含的头文件路径可以被各级子目录中的目标所引用;target_include_directories包含的头文件只能被特定目标使用采用变量传递的方式(${sub_include_dir}引入子路径)引入子目录的头文件路径cmakettest/main.cpp:
#include iostream
#include string
#include func1.hpp //应用层头文件1
#include func2.hpp //应用层头文件2int main(int argc, char *argv[])
{func1(); //调用上层func1func2(); //调用上层func2return 0;
}cmakettest/inc/func1.hpp:
#ifndef __FUNC1_HPP__
#define __FUNC1_HPP__int func1(void);#endifcmakettest/inc/func2.hpp:
#ifndef __FUNC2_HPP__
#define __FUNC2_HPP__int func2(void);#endifcmakettest/src/func1.cpp:
#include subfunc.hpp //subfunc头文件
#include func1.hpp //应用层头文件1
#include iostream
#include stringint func1(void)
{std::cout------------func1函数调用开始----------std::endl;subfunc1();std::cout------------func1函数调用结束----------std::endlstd::endl;return 0;
}cmakettest/src/func2.cpp:
#include subfunc.hpp //subfunc头文件
#include func2.hpp //应用层头文件1
#include iostream
#include stringint func2(void)
{std::cout------------func2函数调用开始----------std::endl;subfunc2();std::cout------------func2函数调用结束----------std::endl;return 0;
}2.2、subfunc以及subsubfunc子目录
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)
cmaketest/subfunc/subfunc.hpp:
#ifndef __SUB_FUNC_HPP__
#define __SUB_FUNC_HPP__int subfunc1(void);
int subfunc2(void);#endifcmaketest/subfunc/subfunc.cpp:
#include subfunc.hpp
#include subsubfunc.hpp
#include iostream
#include stringint 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;
}
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})
分析
1. 头文件目录变量的逐级向上传递通过设置sub_sub_include_dir变量必须包含cache internel “subsubfunc include dir”描述将subsubfunc下的头文件路径传递给了上级subfunc的CMakeList.txt2. 通过设置SUB_INCLUDE_DIR变量必须添加CACHE INTERNAL subfunc include dir描述将subfunc文件下的头文件路径包含之前获得的${SUB_SUB_INCLUDE_DIR}传递给了最上层文件下的CMakeLists.txt。2.3、UT子目录
cmaketest/unit-test/CMakeLists.txt
add_executable(unit-test unit-test.cpp)
target_link_libraries(unit-test boost_system pthread)cmaketest/unit-test/unit-test.cpp
#include boost/asio.hpp
#include iostreamint main(int argc,char* argv[])
{std::coutunit-test代码调用!!!std::endl;return 0;
}
三、编译与实践
在项目路径下创建/build文件夹用于存放cmake编译过程中生成的各种中间文件、库、最终目标文件等
cd build
cmake ..
make在cmake编译的过程中发现了一个问题就是一开始执行cmake . .时候并没有完成头文件变量的传递导致make编译出错。执行结果如下 make结果如下 可以看到由于SUB_SUB_INCLUDE_DIR变量并没有传递到subfunc层的CMakeLists.txt从而导致了在subfunc层并没有包含全部发头文件路径导致编译的时候找不到subsubfunc.hpp。
解决方案
经过反复测试发现多执行几次cmake…(三次以上)就可以解决这个问题猜测是因为多次执行cmake的过程完成了SUB_SUB_INCLUDE_DIR和SUB_INCLUDE_DIR变量向上层的传递:
四、build目录分析 unit-test作为独立的子目录生成了独立的目标文件unit-testsubfunc下生成了libsubfunc.a的静态库文件在subsubfunc下生成了libsubsubfunc.a的静态库文件这两个库文件供最上层CMakeLists.txt调用并最终生成一个目标文件cmaketest
五、程序执行结果 六、总结
1. 一种是独立的unit-test生成独立的目标文件与主CMakeLists.txt仅有一个调用与被调用的关系并不存在任何的编译依关系2. 另一种多级CMakeLists.txt调用之间存在上下级的依赖关系下层的源代码给上层的调用提供支持以生成静态库的方式这里进行了分层设计。3. 下层的头文件路径仅传递给调用的上一层而不会传递给最上层这种变量传递的方式提高了代码的分层性这里需要注意变量的设置CACHE INTERNAL属性的必须添加以完成下层到上层的变量传递上述的两种分层CMakeLists.txt调用方式可覆盖基本的全部开发场景。七、未完待续
下章将继续介绍C相关的工程能力。欢迎关注知乎北京不北欢迎关注douyinnear.X 北京不北欢迎Vbeijing_bubei获得免费答疑长期技术交流。八、参考文献
这里进行了分层设计。
3. 下层的头文件路径仅传递给调用的上一层而不会传递给最上层这种变量传递的方式提高了代码的分层性这里需要注意变量的设置CACHE INTERNAL属性的必须添加以完成下层到上层的变量传递上述的两种分层CMakeLists.txt调用方式可覆盖基本的全部开发场景。七、未完待续
下章将继续介绍C相关的工程能力。欢迎关注知乎北京不北欢迎关注douyinnear.X 北京不北欢迎Vbeijing_bubei获得免费答疑长期技术交流。八、参考文献
https://blog.csdn.net/weixin_42700740/article/details/126364574