当前位置:首页 > 编程笔记 > 正文
已解决

基于CMake的C++项目管理实践

来自网友在路上 172872提问 提问时间:2023-10-20 21:26:14阅读次数: 72

最佳答案 问答题库728位专家为你答疑解惑

文章目录

  • 基于CMake的C++项目管理实践
    • 示例代码项目结构
    • 示例代码文件内容
      • liba库-内容
        • `call/usage_func.hpp:`
        • `call/usage_func.cxx:`
        • `call/CMakeLists.txt:`
        • `inherit/base_func.hpp:`
        • `inherit/base_func.cxx:`
        • `inherit/CMakeLists.txt:`
        • `liba_exports.hpp:`
        • `liba_config.hpp.in:`
        • `Config.cmake.in:`
        • `CMakeLists.txt:`
      • libb库-内容
        • `redefining/derived_func.hpp:`
        • `redefining/derived_func.cxx:`
        • `redefining/CMakeLists.txt:`
        • `libb_exports.hpp:`
        • `libb_config.hpp.in:`
        • `Config.cmake.in:`
        • `CMakeLists.txt`
      • tutorial库-内容
        • `main.cxx:`
        • `CMakeLists.txt:`
    • 构建使用示例:
      • `liba-构建命令`
      • `libb-构建命令`
      • `tutorial-构建命令`


基于CMake的C++项目管理实践

使用CMake的find_package和configuration文件进行管理

以一个例子作为说明:

  • liba: lib库
  • libb: lib库,且引用liba
  • tutorial: exe,且引用liba和libb

示例代码项目结构

liba库-项目结构:

liba
├── build_debug/ : Debug模式构建目录
├── build_release/ : Release模式构建目录
├── call/ : call.lib 库目录
│   ├── CMakeLists.txt
│   ├── usage_func.cxx
│   └── usage_func.hpp
├── CMakeLists.txt
├── Config.cmake.in
├── inherit/ : inherit.lib 库目录
│   ├── base_func.cxx
│   ├── base_func.hpp
│   ├── CMakeLists.txt
│   ├── mysqrt.cxx
│   └── mysqrt.h
├── liba_config.hpp.in
└── liba_exports.hpp

libb库-项目结构:

libb
├── build_debug/ : Debug模式构建目录
├── build_release/ : Release模式构建目录
├── CMakeLists.txt
├── Config.cmake.in
├── libb_config.hpp.in
├── libb_exports.hpp
└── redefining/ : redefining.lib 库目录├── CMakeLists.txt├── derived_func.cxx└── derived_func.hpp

tutorial库-项目结构:

liba
├── build_debug/ : Debug模式构建目录
├── build_release/ : Release模式构建目录
├── CMakeLists.txt
└── main.cxx

示例代码文件内容

liba库-内容

call/usage_func.hpp:
#pragma once #include "liba_exports.hpp"namespace liba{class LIBA_DECLSPEC CUsageFunction {public:CUsageFunction() = default;virtual~CUsageFunction() = default;double sqrt(double);void message();};
}

call/usage_func.cxx:
#include "usage_func.hpp"#include <iostream>
#include <cmath>namespace liba {double CUsageFunction::sqrt(double num) {double v = std::sqrt(num);std::cout << "liba CUsageFunction sqrt on cmath: std::sqrt(" << num << ")=" << v << std::endl;  return v;}void CUsageFunction::message() {std::cout << "liba CUsageFunction message!" << std::endl;}
}

call/CMakeLists.txt:
set(COMPONENT call)set(SRC_LST usage_func.cxx)# 设置-DBUILD_SHARED_LIBS=ON后,此处可以不显式设置类型(STATIC, SHARED),也可以生成具体类型的库
add_library(${COMPONENT} ${SRC_LST})# namespaced alias
add_library(${CMAKE_PROJECT_NAME}::${COMPONENT} ALIAS ${COMPONENT})message(STATUS "Current COMPONENT:" ${COMPONENT})
message(STATUS "Current COMPONENT:" ${COMPONENT})
message(STATUS "${COMPONENT}-CMAKE_CURRENT_SOURCE_DIR:" ${CMAKE_CURRENT_SOURCE_DIR})
message(STATUS "${COMPONENT}-PROJECT_SOURCE_DIR:" ${PROJECT_SOURCE_DIR})
message(STATUS "${COMPONENT}-PROJECT_BINARY_DIR:" ${PROJECT_BINARY_DIR})# state that anybody linking to us needs to include the current source dir
# to find base_func.hpp, while we don't.
# 调用程序链接inherit本目标时,需要包含base_func.hpp
# 但是inherit本目标编译时,不需要链接base_func.hpp
# 利用INTERFACE作用域限定include作用域:target本身不链接,传递到调用方链接
# ${CMAKE_CURRENT_SOURCE_DIR}: The path to the source directory currently being processed. 
# ${CMAKE_CURRENT_SOURCE_DIR}: 当前处理的源目录,即当前CMakeLists.txt所在目录
# ${PROJECT_SOURCE_DIR}: 表示项目主CMakeLists.txt文件所在目录
# ${CMAKE_INSTALL_INCLUDEDIR}: include
# $<BUILD_INTERFACE:xxx>: 表示库链接过程中需要包含的路径
# $<INSTALL_INTERFACE:xxx>: 表示在安装目录下引用库需要包含的路径
# 项目链接了${PROJECT_SOURCE_DIR}/liba_exports.hpp 故${PROJECT_SOURCE_DIR}作用域需要设置为PUBLIC
target_include_directories(${COMPONENT}INTERFACE$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>PUBLIC$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>)# 添加BUILD_SHARED_LIBS判断是否编译动态库和静态库
if(BUILD_SHARED_LIBS)# 在Windows平台下,动态库和静态库的导出符号需要区别对待target_compile_definitions(${COMPONENT} PRIVATE "SHARED_LIBA_BUILD")
endif()# link our compiler flags interface library
# project_cxx_compiler_flags: 项目主CMakeLists.txt文件中定义的继承了C++特性的接口库
# 链接接口库的编译标记
# target_link_libraries(${COMPONENT} PUBLIC project_cxx_compiler_flags)
target_link_libraries(${COMPONENT} PRIVATE project_cxx_compiler_flags)# 定义windows通用的导入导出符号,否则windows平台不会为dll生成导入库lib
target_compile_definitions(${COMPONENT} PRIVATE "SHARED_LIBA_EXPORTING")# 为target添加DEBUG_POSTFIX属性
set_target_properties(${COMPONENT} PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})# 安装lib
# set(installable_libs ${COMPONENT} project_cxx_compiler_flags)
set(installable_libs ${COMPONENT})
# 若需要提供SqrtLibrary安装,则执行如下代码
# if(TARGET SqrtLibrary)
#   # 将SqrtLibrary添加到installable_libs 变量中
#   list(APPEND installable_libs SqrtLibrary)
# endif()# EXPORT可以导出其他CMake项目直接使用此项目的信息
# 导出后可以将信息输出到xxx.cmake文件,方便其它项目find_package调用
install(TARGETS ${installable_libs}EXPORT ${COMPONENT}-TargetsLIBRARY DESTINATION $<IF:$<CONFIG:Debug>,libd,lib>ARCHIVE DESTINATION $<IF:$<CONFIG:Debug>,libd,lib>RUNTIME DESTINATION $<IF:$<CONFIG:Debug>,bind,bin>INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${COMPONENT}")# 安装include
# 方法一:
# install(FILES usage_func.hpp DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${COMPONENT}")
# 方法二:
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}FILES_MATCHING PATTERN "*.hpp")# 生成和安装export file
# generate and install export file
install(EXPORT ${COMPONENT}-TargetsFILE ${CMAKE_PROJECT_NAME}-${COMPONENT}Targets.cmakeNAMESPACE ${CMAKE_PROJECT_NAME}::DESTINATION "cmake")

inherit/base_func.hpp:
#pragma once #include "liba_exports.hpp"namespace liba{class LIBA_DECLSPEC CBaseFunction {public:CBaseFunction() = default;virtual~CBaseFunction() = default;double sqrt(double);void message();};
}

inherit/base_func.cxx:
#include "base_func.hpp"#include <iostream>#ifdef USE_MYMATH
#   include "mysqrt.h"
#else 
#   include <cmath>
#endifnamespace liba {double CBaseFunction::sqrt(double num) {
#ifdef USE_MYMATHdouble v = detail::mysqrt(num);std::cout << "liba CBaseFunction sqrt on mysqrt: mysqrt(" << num << ")=" << v << std::endl;  return v;
#elsedouble v = std::sqrt(num);std::cout << "liba CBaseFunction sqrt on cmath: std::sqrt(" << num << ")=" << v << std::endl;  return v;
#endif}void CBaseFunction::message() {std::cout << "liba CBaseFunction message!" << std::endl;}
}

inherit/CMakeLists.txt:
set(COMPONENT inherit)set(SRC_LST base_func.cxx)# 设置-DBUILD_SHARED_LIBS=ON后,此处可以不显式设置类型(STATIC, SHARED),也可以生成具体类型的库
add_library(${COMPONENT} ${SRC_LST})# namespaced alias
add_library(${CMAKE_PROJECT_NAME}::${COMPONENT} ALIAS ${COMPONENT})message(STATUS "Current COMPONENT:" ${COMPONENT})
message(STATUS "Current COMPONENT:" ${COMPONENT})
message(STATUS "${COMPONENT}-CMAKE_CURRENT_SOURCE_DIR:" ${CMAKE_CURRENT_SOURCE_DIR})
message(STATUS "${COMPONENT}-PROJECT_SOURCE_DIR:" ${PROJECT_SOURCE_DIR})
message(STATUS "${COMPONENT}-PROJECT_BINARY_DIR:" ${PROJECT_BINARY_DIR})# state that anybody linking to us needs to include the current source dir
# to find base_func.hpp, while we don't.
# 调用程序链接inherit本目标时,需要包含base_func.hpp
# 但是inherit本目标编译时,不需要链接base_func.hpp
# 利用INTERFACE作用域限定include作用域:target本身不链接,传递到调用方链接
# ${CMAKE_CURRENT_SOURCE_DIR}: The path to the source directory currently being processed. 
# ${CMAKE_CURRENT_SOURCE_DIR}: 当前处理的源目录,即当前CMakeLists.txt所在目录
# ${PROJECT_SOURCE_DIR}: 表示项目主CMakeLists.txt文件所在目录
# ${CMAKE_INSTALL_INCLUDEDIR}: include
# $<BUILD_INTERFACE:xxx>: 表示库链接过程中需要包含的路径
# $<INSTALL_INTERFACE:xxx>: 表示在安装目录下引用库需要包含的路径
# 项目链接了${PROJECT_SOURCE_DIR}/liba_exports.hpp 故${PROJECT_SOURCE_DIR}作用域需要设置为PUBLIC
target_include_directories(${COMPONENT}INTERFACE$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>PUBLIC$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>)# should we use our own math functions
# option定义CMake构建编译系统的选项
option(USE_MYMATH "Use mymath implementation" ON)if(USE_MYMATH)# target_compile_definitions定义CMake编译选项# 如下面语句为C++源码定义了USE_MYMATH宏定义# PRIVATE: 作用域只限于本项目target_compile_definitions(${COMPONENT} PRIVATE "USE_MYMATH")# USE_MYMATH模式下 使用项目自定义sqrt实现# 定义SqrtLibrary静态库add_library(SqrtLibrary STATIC mysqrt.cxx)# state that SqrtLibrary need PIC when the default is shared libraries# 当inherit构建动态库时,SqrtLibrary静态库的POSITION_INDEPENDENT_CODE属性不设置为True,构建会失败set_target_properties(SqrtLibrary PROPERTIESPOSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS})# link our compiler flags interface library# project_cxx_compiler_flags: 项目主CMakeLists.txt文件中定义的继承了C++特性的接口库# 链接接口库的编译标记target_link_libraries(SqrtLibrary PUBLIC project_cxx_compiler_flags)# 为inherit目标添加链接库SqrtLibrary# PRIVATE:SqrtLibrary作用域仅限于本项目target_link_libraries(${COMPONENT} PRIVATE SqrtLibrary)
endif()# 添加BUILD_SHARED_LIBS判断是否编译动态库和静态库
if(BUILD_SHARED_LIBS)# 在Windows平台下,动态库和静态库的导出符号需要区别对待target_compile_definitions(${COMPONENT} PRIVATE "SHARED_LIBA_BUILD")
endif()# link our compiler flags interface library
# project_cxx_compiler_flags: 项目主CMakeLists.txt文件中定义的继承了C++特性的接口库
# 链接接口库的编译标记
# target_link_libraries(${COMPONENT} PUBLIC project_cxx_compiler_flags)
target_link_libraries(${COMPONENT} PRIVATE project_cxx_compiler_flags)# 定义windows通用的导入导出符号,否则windows平台不会为dll生成导入库lib
target_compile_definitions(${COMPONENT} PRIVATE "SHARED_LIBA_EXPORTING")# 为target添加DEBUG_POSTFIX属性
set_target_properties(${COMPONENT} PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})# 安装lib
# set(installable_libs ${COMPONENT} project_cxx_compiler_flags)
set(installable_libs ${COMPONENT})
# 若需要提供SqrtLibrary安装,则执行如下代码
# if(TARGET SqrtLibrary)
#   # 将SqrtLibrary添加到installable_libs 变量中
#   list(APPEND installable_libs SqrtLibrary)
# endif()# EXPORT可以导出其他CMake项目直接使用此项目的信息
# 导出后可以将信息输出到xxx.cmake文件,方便其它项目find_package调用
install(TARGETS ${installable_libs}EXPORT ${COMPONENT}-TargetsLIBRARY DESTINATION $<IF:$<CONFIG:Debug>,libd,lib>ARCHIVE DESTINATION $<IF:$<CONFIG:Debug>,libd,lib>RUNTIME DESTINATION $<IF:$<CONFIG:Debug>,bind,bin>INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${COMPONENT}")# 安装include
# 方法一:
# install(FILES base_func.hpp DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${COMPONENT}")
# 方法二:
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}FILES_MATCHING PATTERN "*.hpp")# 生成和安装export file
# generate and install export file
install(EXPORT ${COMPONENT}-TargetsFILE ${CMAKE_PROJECT_NAME}-${COMPONENT}Targets.cmakeNAMESPACE ${CMAKE_PROJECT_NAME}::DESTINATION "cmake")

liba_exports.hpp:
#pragma once #if (defined(_WIN32) || defined(_WIN64))
#  if defined(SHARED_LIBA_BUILD)
#    if defined(SHARED_LIBA_EXPORTING)
#      define LIBA_DECLSPEC __declspec(dllexport)
#    else
#      define LIBA_DECLSPEC __declspec(dllimport)
#    endif
#  else // non shared
#    define LIBA_DECLSPEC
#  endif
#else // non windows
#  define LIBA_DECLSPEC
#endif

liba_config.hpp.in:
// the configured options and settings for liba
// 
//# ${LIBA_VERSION_MAJOR} = ${PROJECT_VERSION_MAJOR}
//# ${LIBA_VERSION_MINOR} = ${PROJECT_VERSION_MINOR}#pragma once#define LIBA_PROJ_VERSION "@PROJECT_VERSION@"
#define LIBA_PROJ_VERSION_MAJOR @LIBA_VERSION_MAJOR@
#define LIBA_PROJ_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define LIBA_PROJ_VERSION_PATCH @LIBA_VERSION_PATCH@
#define LIBA_PROJ_VERSION_TWEAK @PROJECT_VERSION_TWEAK@
#define TEST_VERBOSE "@TEST_VERBOSE_FLAG@"

Config.cmake.in:
@PACKAGE_INIT@# include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )# <Package>_FOUND=False
# <Package>_<Component>_FOUND=Trueset(_liba_supported_components inherit call)foreach(_comp ${LIBA_FIND_COMPONENTS})if (NOT _comp IN_LIST _liba_supported_components)set(LIBA_FOUND False)set(LIBA_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}")endif()include("${CMAKE_CURRENT_LIST_DIR}/LIBA-${_comp}Targets.cmake")
endforeach()

CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)# project指定项目名、版本号、编程语言
# 关于软件版本命名规则:主版本号.子版本号.修订版本号.日期-阶段版本号
# * 主版本号:当功能模块有较大的变动,比如增加多个模块或者整体架构发生变化。此版本号由项目决定是否修改。
# * 子版本号:当功能有一定的增加或变化,比如增加了对权限控制、增加自定义视图等功能。此版本号由项目决定是否修改
# * 修订版本号:一般是 Bug 修复或是一些小的变动,要经常发布修订版,时间间隔不限,修复一个严重的bug即可发布一个修订版。此版本号由项目经理决定是否修改。
# * 日期-阶段版本号:日期用于记录修改项目的当前日期,此版本号由开发人员决定是否修改;阶段版本号用于标注当前版本的软件处于哪个开发阶段,此版本号由项目决定是否修改,一般是希腊字母。
# 例如,1.1.12.20230117-Release
# 阶段版本号说明:
# * Base:此版本表示该软件仅仅是一个假页面链接,通常包括所有的功能和页面布局,但是页面中的功能都没有做完整的实现,只是做为整体网站的一个基础架构。
# * Alpha:此版本表示该软件在此阶段主要是以实现软件功能为主,通常只在软件开发者内部交流,一般而言,该版本软件的Bug较多,需要继续修改。
# * Beta: 该版本相对于Alpha版已有了很大的改进,消除了严重的错误,但还是存在着一些缺陷,需要经过多次测试来进一步消除。
# * RC:该版本已经相当成熟了,基本上不存在导致错误的BUG,与即将发行的正式版相差无几。
# * Release:该版本意味“最终版本”,在前面版本的一系列测试版之后,终归会有一个正式版本,是最终交付用户使用的一个版本。
# 关于CMake的版本规则:MAJOR.MINOR.PATCH.TWEAK
# CMake的版本号各个部分必须是数字组成
# 例如:1.1.1.20231017
project(LIBA VERSION 1.1.1.20231017 LANGUAGES C CXX)# make cache variables for install destinations
include(GNUInstallDirs)# 指定C++编译标准
# 方式一:利用set指定 the C++ standard
# set(CMAKE_CXX_STANDARD 11)
# set(CMAKE_CXX_STANDARD_REQUIRED True)
# 方式二:利用接口库的形式
add_library(project_cxx_compiler_flags INTERFACE)
target_compile_features(project_cxx_compiler_flags INTERFACE cxx_std_11)# debug模式以'd'结尾
set(CMAKE_DEBUG_POSTFIX d)# 指定自定义变量
set(TEST_VERBOSE_FLAG "${PROJECT_NAME} Demo")# 判断当前使用的编译器
# 基于生成器表达式
# $<COMPILE_LANG_AND_ID:language,compiler_ids>: 当项目所用编程语言匹配language,
# 且项目所用编译器匹配compiler_ids时,此表达式返回1,否则返回0
# * Create a new variable gcc_like_cxx that is true if we are using CXX and
#   any of the following compilers: ARMClang, AppleClang, Clang, GNU, LCC
# * Create a new variable msvc_cxx that is true if we are using CXX and MSVC
set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")# 为接口库project_cxx_compiler_flags 增加编译警告选项
# 基于条件生成器表达式
# * $<condition:true_string> : 当condition为真则返回true_string,否则返回空字符串
# * $<IF:condition,true_string,false_string> : 当condition为真则返回true_string,否则返回false_string
# 生成器表达式支持嵌套
# INTERFACE作用域表示project_cxx_compiler_flags 本身不需要,但是project_cxx_compiler_flags 调用方需要使用
# BUILD_INTERFACE生成器表达式
# 我们只想在编译阶段使用警告选项,而不会在安装阶段使用,可以利用BUILD_INTERFACE限制
target_compile_options(project_cxx_compiler_flags INTERFACE "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>""$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
)# BUILD_SHARED_LIBS控制库类型的生成
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)# configure a header file to pass some of the CMake settings
# to the source code
# 利用configure_file()命令可以实现文件复制,并且替换文件中@var@的变量值
configure_file(liba_config.hpp.in ${PROJECT_BINARY_DIR}/include/liba_config.hpp)message(STATUS "PROJECT_NAME:" ${PROJECT_NAME})
message(STATUS "CMAKE_PROJECT_NAME:" ${CMAKE_PROJECT_NAME})
message(STATUS "CMAKE_CURRENT_SOURCE_DIR:" ${CMAKE_CURRENT_SOURCE_DIR})
message(STATUS "CMAKE_CURRENT_BINARY_DIR:" ${CMAKE_CURRENT_BINARY_DIR})message(STATUS "LIBA_BINARY_DIR:" ${LIBA_BINARY_DIR})
message(STATUS "PROJECT_SOURCE_DIR:" ${PROJECT_SOURCE_DIR})
message(STATUS "CMAKE_SOURCE_DIR:" ${CMAKE_SOURCE_DIR})# 配置默认安装路径
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)# ${CMAKE_SOURCE_DIR}表示源码树顶层目录路径set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/../install/${PROJECT_NAME})
endif()# 添加inherit库和call库
add_subdirectory(${PROJECT_SOURCE_DIR}/inherit inherit_build)
add_subdirectory(${PROJECT_SOURCE_DIR}/call call_build)# 安装config.hpp exports.hpp
install(FILES "${PROJECT_BINARY_DIR}/include/liba_config.hpp" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES "${PROJECT_SOURCE_DIR}/liba_exports.hpp" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})# include CMakePackageConfigHelpers macro
include(CMakePackageConfigHelpers)# 针对target设置版本属性
#set_property(TARGET ${PROJECT_NAME} PROPERTY VERSION ${PROJECT_VERSION})
#set_property(TARGET ${PROJECT_NAME} PROPERTY SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR})
#set_property(TARGET ${PROJECT_NAME} PROPERTY
#  INTERFACE_${PROJECT_NAME}_MAJOR_VERSION ${PROJECT_VERSION_MAJOR})
#set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY
#  COMPATIBLE_INTERFACE_STRING ${PROJECT_NAME}_MAJOR_VERSION
#)# generate the version file for the config file
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"VERSION "${PROJECT_VERSION}"COMPATIBILITY AnyNewerVersion
)
# generate the config file that includes the exports
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"INSTALL_DESTINATION "cmake"NO_SET_AND_CHECK_MACRONO_CHECK_REQUIRED_COMPONENTS_MACRO
)
# install config files
install(FILES${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmakeDESTINATION "cmake"
)

libb库-内容

redefining/derived_func.hpp:
#pragma once#include "libb_exports.hpp"#include <base_func.hpp>namespace libb {class LIBB_DECLSPEC CDerivedFunction : public liba::CBaseFunction {public:CDerivedFunction() = default;virtual~CDerivedFunction() = default;// 重定义(redefining)double sqrt(double);void message();};
}

redefining/derived_func.cxx:
#include "derived_func.hpp"#include <iostream>
#include <cmath>namespace libb {double CDerivedFunction::sqrt(double num) {double v = std::sqrt(num);std::cout << "liba CDerivedFunction sqrt on cmath: std::sqrt(" << num << ")=" << v << std::endl;return v;  }void CDerivedFunction::message() {std::cout << "liba CDerivedFunction message!" << std::endl;}
}

redefining/CMakeLists.txt:
set(COMPONENT redefining)set(SRC_LST derived_func.cxx)message(STATUS "${COMPONENT}-find_package location(CMAKE_CURRENT_SOURCE_DIR):" "${CMAKE_CURRENT_SOURCE_DIR}/../install/LIBA/cmake")
message(STATUS "${COMPONENT}-find_package location(CMAKE_SOURCE_DIR):" "${CMAKE_SOURCE_DIR}/../install/LIBA/cmake")# 添加路径到CMAKE_PREFIX_PATH 使find_package可以搜索加载package
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/../install/LIBA/cmake")foreach(_dir ${CMAKE_PREFIX_PATH})message(STATUS "${CMAKE_PROJECT_NAME}::${COMPONENT}-find_package in dir:${_dir}")
endforeach()find_package(LIBA 1.1.0 REQUIRED COMPONENTS inherit)
if(NOT LIBA_FOUND)message(FATAL_ERROR "${COMPONENT}-package: LIBA not found!")
endif()# project_cxx_compiler_flags可以从LIBA库可以传递过来
# 设置-DBUILD_SHARED_LIBS=ON后,此处可以不显式设置类型(STATIC, SHARED),也可以生成具体类型的库
# add_library(${COMPONENT} ${SRC_LST} ${project_cxx_compiler_flags})
add_library(${COMPONENT} ${SRC_LST})# namespaced alias
add_library(${CMAKE_PROJECT_NAME}::${COMPONENT} ALIAS ${COMPONENT})message(STATUS "Current COMPONENT:" ${COMPONENT})
message(STATUS "Current COMPONENT:" ${COMPONENT})
message(STATUS "${COMPONENT}-CMAKE_CURRENT_SOURCE_DIR:" ${CMAKE_CURRENT_SOURCE_DIR})
message(STATUS "${COMPONENT}-PROJECT_SOURCE_DIR:" ${PROJECT_SOURCE_DIR})
message(STATUS "${COMPONENT}-PROJECT_BINARY_DIR:" ${PROJECT_BINARY_DIR})# state that anybody linking to us needs to include the current source dir
# to find base_func.hpp, while we don't.
# 调用程序链接inherit本目标时,需要包含base_func.hpp
# 但是inherit本目标编译时,不需要链接base_func.hpp
# 利用INTERFACE作用域限定include作用域:target本身不链接,传递到调用方链接
# ${CMAKE_CURRENT_SOURCE_DIR}: The path to the source directory currently being processed. 
# ${CMAKE_CURRENT_SOURCE_DIR}: 当前处理的源目录,即当前CMakeLists.txt所在目录
# ${PROJECT_SOURCE_DIR}: 表示项目主CMakeLists.txt文件所在目录
# ${CMAKE_INSTALL_INCLUDEDIR}: include
# $<BUILD_INTERFACE:xxx>: 表示库链接过程中需要包含的路径
# $<INSTALL_INTERFACE:xxx>: 表示在安装目录下引用库需要包含的路径
# 项目链接了${PROJECT_SOURCE_DIR}/libb_exports.hpp 故${PROJECT_SOURCE_DIR}作用域需要设置为PUBLIC
target_include_directories(${COMPONENT}INTERFACE$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>PUBLIC$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>)# 添加BUILD_SHARED_LIBS判断是否编译动态库和静态库
if(BUILD_SHARED_LIBS)# 在Windows平台下,动态库和静态库的导出符号需要区别对待target_compile_definitions(${COMPONENT} PRIVATE "SHARED_LIBB_BUILD")
endif()# project_cxx_compiler_flags可以从LIBA库可以传递过来
# link our compiler flags interface library
# project_cxx_compiler_flags: 项目主CMakeLists.txt文件中定义的继承了C++特性的接口库
# 链接接口库的编译标记
# target_link_libraries(${COMPONENT} PUBLIC project_cxx_compiler_flags LIBA::inherit)
target_link_libraries(${COMPONENT} PUBLIC LIBA::inherit)# 定义windows通用的导入导出符号,否则windows平台不会为dll生成导入库lib
target_compile_definitions(${COMPONENT} PRIVATE "SHARED_LIBB_EXPORTING")# 为target添加DEBUG_POSTFIX属性
set_target_properties(${COMPONENT} PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})# project_cxx_compiler_flags可以从LIBA库可以传递过来
# 安装lib
# set(installable_libs ${COMPONENT} project_cxx_compiler_flags)
set(installable_libs ${COMPONENT})# EXPORT可以导出其他CMake项目直接使用此项目的信息
# 导出后可以将信息输出到xxx.cmake文件,方便其它项目find_package调用
install(TARGETS ${installable_libs}EXPORT ${COMPONENT}-TargetsLIBRARY DESTINATION $<IF:$<CONFIG:Debug>,libd,lib>ARCHIVE DESTINATION $<IF:$<CONFIG:Debug>,libd,lib>RUNTIME DESTINATION $<IF:$<CONFIG:Debug>,bind,bin>INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${COMPONENT}")# 安装include
# 方法一:
# install(FILES usage_func.hpp DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${COMPONENT}")
# 方法二:
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}FILES_MATCHING PATTERN "*.hpp")# 生成和安装export file
# generate and install export file
install(EXPORT ${COMPONENT}-TargetsFILE ${CMAKE_PROJECT_NAME}-${COMPONENT}Targets.cmakeNAMESPACE ${CMAKE_PROJECT_NAME}::DESTINATION "cmake")

libb_exports.hpp:
#pragma once #if (defined(_WIN32) || defined(_WIN64))
#  if defined(SHARED_LIBB_BUILD)
#    if defined(SHARED_LIBB_EXPORTING)
#      define LIBB_DECLSPEC __declspec(dllexport)
#    else
#      define LIBB_DECLSPEC __declspec(dllimport)
#    endif
#  else // non shared
#    define LIBB_DECLSPEC
#  endif
#else // non windows
#  define LIBB_DECLSPEC
#endif

libb_config.hpp.in:
// the configured options and settings for libb
// 
//# ${LIBB_VERSION_MAJOR} = ${PROJECT_VERSION_MAJOR}
//# ${LIBB_VERSION_MINOR} = ${PROJECT_VERSION_MINOR}#pragma once#define LIBB_PROJ_VERSION "@PROJECT_VERSION@"
#define LIBB_PROJ_VERSION_MAJOR @LIBB_VERSION_MAJOR@
#define LIBB_PROJ_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define LIBB_PROJ_VERSION_PATCH @LIBB_VERSION_PATCH@
#define LIBB_PROJ_VERSION_TWEAK @PROJECT_VERSION_TWEAK@
#define TEST_VERBOSE "@TEST_VERBOSE_FLAG@"

Config.cmake.in:
@PACKAGE_INIT@#include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )foreach(_dir ${CMAKE_CURRENT_LIST_DIR})message(STATUS "MONO CMAKE_CURRENT_LIST_DIR:" ${_dir})
endforeach()# find dependency 
# libb <- liba
include(CMakeFindDependencyMacro)
# needing LIBA's location
#find_dependency(LIBA 1.1.0)
find_dependency(LIBA 1.1.0 COMPONENTS inherit NO_DEFAULT_PATH PATHS ${CMAKE_CURRENT_LIST_DIR}/../../LIBA/cmake)set(_libb_supported_components redefining)# <Package>_FOUND=False
# <Package>_<Component>_FOUND=Trueforeach(_comp ${LIBB_FIND_COMPONENTS})if (NOT _comp IN_LIST _libb_supported_components)set(LIBB_FOUND False)set(LIBB_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}")endif()include("${CMAKE_CURRENT_LIST_DIR}/LIBB-${_comp}Targets.cmake")
endforeach()

CMakeLists.txt
cmake_minimum_required(VERSION 3.20)# project指定项目名、版本号、编程语言
# 关于软件版本命名规则:主版本号.子版本号.修订版本号.日期-阶段版本号
# * 主版本号:当功能模块有较大的变动,比如增加多个模块或者整体架构发生变化。此版本号由项目决定是否修改。
# * 子版本号:当功能有一定的增加或变化,比如增加了对权限控制、增加自定义视图等功能。此版本号由项目决定是否修改
# * 修订版本号:一般是 Bug 修复或是一些小的变动,要经常发布修订版,时间间隔不限,修复一个严重的bug即可发布一个修订版。此版本号由项目经理决定是否修改。
# * 日期-阶段版本号:日期用于记录修改项目的当前日期,此版本号由开发人员决定是否修改;阶段版本号用于标注当前版本的软件处于哪个开发阶段,此版本号由项目决定是否修改,一般是希腊字母。
# 例如,1.1.12.20230117-Release
# 阶段版本号说明:
# * Base:此版本表示该软件仅仅是一个假页面链接,通常包括所有的功能和页面布局,但是页面中的功能都没有做完整的实现,只是做为整体网站的一个基础架构。
# * Alpha:此版本表示该软件在此阶段主要是以实现软件功能为主,通常只在软件开发者内部交流,一般而言,该版本软件的Bug较多,需要继续修改。
# * Beta: 该版本相对于Alpha版已有了很大的改进,消除了严重的错误,但还是存在着一些缺陷,需要经过多次测试来进一步消除。
# * RC:该版本已经相当成熟了,基本上不存在导致错误的BUG,与即将发行的正式版相差无几。
# * Release:该版本意味“最终版本”,在前面版本的一系列测试版之后,终归会有一个正式版本,是最终交付用户使用的一个版本。
# 关于CMake的版本规则:MAJOR.MINOR.PATCH.TWEAK
# CMake的版本号各个部分必须是数字组成
# 例如:1.1.1.20231017
project(LIBB VERSION 1.1.1.20231017 LANGUAGES C CXX)# make cache variables for install destinations
include(GNUInstallDirs)# project_cxx_compiler_flags可以从LIBA库可以传递过来
# 指定C++编译标准
# 方式一:利用set指定 the C++ standard
# set(CMAKE_CXX_STANDARD 11)
# set(CMAKE_CXX_STANDARD_REQUIRED True)
# 方式二:利用接口库的形式
# add_library(project_cxx_compiler_flags INTERFACE)
# target_compile_features(project_cxx_compiler_flags INTERFACE cxx_std_11)# debug模式以'd'结尾
set(CMAKE_DEBUG_POSTFIX d)# 指定自定义变量
set(TEST_VERBOSE_FLAG "${PROJECT_NAME} Demo")# project_cxx_compiler_flags可以从LIBA库可以传递过来
# 判断当前使用的编译器
# 基于生成器表达式
# $<COMPILE_LANG_AND_ID:language,compiler_ids>: 当项目所用编程语言匹配language,
# 且项目所用编译器匹配compiler_ids时,此表达式返回1,否则返回0
# * Create a new variable gcc_like_cxx that is true if we are using CXX and
#   any of the following compilers: ARMClang, AppleClang, Clang, GNU, LCC
# * Create a new variable msvc_cxx that is true if we are using CXX and MSVC
# set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
# set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")# project_cxx_compiler_flags可以从LIBA库可以传递过来
# 为接口库project_cxx_compiler_flags 增加编译警告选项
# 基于条件生成器表达式
# * $<condition:true_string> : 当condition为真则返回true_string,否则返回空字符串
# * $<IF:condition,true_string,false_string> : 当condition为真则返回true_string,否则返回false_string
# 生成器表达式支持嵌套
# INTERFACE作用域表示project_cxx_compiler_flags 本身不需要,但是project_cxx_compiler_flags 调用方需要使用
# BUILD_INTERFACE生成器表达式
# 我们只想在编译阶段使用警告选项,而不会在安装阶段使用,可以利用BUILD_INTERFACE限制
# target_compile_options(project_cxx_compiler_flags INTERFACE 
#  "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
#  "$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
# )# BUILD_SHARED_LIBS控制库类型的生成
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)# configure a header file to pass some of the CMake settings
# to the source code
# 利用configure_file()命令可以实现文件复制,并且替换文件中@var@的变量值
configure_file(libb_config.hpp.in ${PROJECT_BINARY_DIR}/include/libb_config.hpp)message(STATUS "PROJECT_NAME:" ${PROJECT_NAME})
message(STATUS "CMAKE_PROJECT_NAME:" ${CMAKE_PROJECT_NAME})
message(STATUS "CMAKE_CURRENT_SOURCE_DIR:" ${CMAKE_CURRENT_SOURCE_DIR})
message(STATUS "CMAKE_CURRENT_BINARY_DIR:" ${CMAKE_CURRENT_BINARY_DIR})message(STATUS "LIBB_BINARY_DIR:" ${LIBB_BINARY_DIR})
message(STATUS "PROJECT_SOURCE_DIR:" ${PROJECT_SOURCE_DIR})
message(STATUS "CMAKE_SOURCE_DIR:" ${CMAKE_SOURCE_DIR})# 配置默认安装路径
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)# ${CMAKE_SOURCE_DIR}表示源码树顶层目录路径set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/../install/${PROJECT_NAME})
endif()# 添加redefining库
add_subdirectory(${PROJECT_SOURCE_DIR}/redefining redefining_build)# 安装config.hpp exports.hpp
install(FILES "${PROJECT_BINARY_DIR}/include/libb_config.hpp" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES "${PROJECT_SOURCE_DIR}/libb_exports.hpp" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})# include CMakePackageConfigHelpers macro
include(CMakePackageConfigHelpers)# 针对target设置版本属性
#set_property(TARGET ${PROJECT_NAME} PROPERTY VERSION ${PROJECT_VERSION})
#set_property(TARGET ${PROJECT_NAME} PROPERTY SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR})
#set_property(TARGET ${PROJECT_NAME} PROPERTY
#  INTERFACE_${PROJECT_NAME}_MAJOR_VERSION ${PROJECT_VERSION_MAJOR})
#set_property(TARGET ${PROJECT_NAME} APPEND PROPERTY
#  COMPATIBLE_INTERFACE_STRING ${PROJECT_NAME}_MAJOR_VERSION
#)# generate the version file for the config file
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"VERSION "${PROJECT_VERSION}"COMPATIBILITY AnyNewerVersion
)
# generate the config file that includes the exports
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"INSTALL_DESTINATION "cmake"NO_SET_AND_CHECK_MACRONO_CHECK_REQUIRED_COMPONENTS_MACRO
)
# install config files
install(FILES${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmakeDESTINATION "cmake"
)

tutorial库-内容

main.cxx:
// A simple program that computes the square root of a number
#include <iostream>
#include <sstream>
#include <string>#include <liba_config.hpp>
#include <libb_config.hpp>
#include <call/usage_func.hpp>
#include <redefining/derived_func.hpp>int main(int argc, char* argv[])
{if (argc < 2) {// report versionstd::cout << argv[0] << "liba version:" << LIBA_PROJ_VERSION<< " --- libb version:" << LIBB_PROJ_VERSION << std::endl;std::cout << "Usage: " << argv[0] << " number" << std::endl;return 1;}// convert input to doubleconst double iv = std::stod(argv[1]);std::cout << "liba::CUsageFunction: " << std::endl;liba::CUsageFunction uf;double ufv = uf.sqrt(iv);std::cout << "The square root of " << iv << " is " << ufv<< std::endl;uf.message();std::cout << "libb::CDerivedFunction: " << std::endl;libb::CDerivedFunction df;double dfv = df.sqrt(iv);std::cout << "The square root of " << iv << " is " << dfv<< std::endl;df.message();return 0;
}

CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)# project指定项目名、版本号、编程语言
# 关于软件版本命名规则:主版本号.子版本号.修订版本号.日期-阶段版本号
# * 主版本号:当功能模块有较大的变动,比如增加多个模块或者整体架构发生变化。此版本号由项目决定是否修改。
# * 子版本号:当功能有一定的增加或变化,比如增加了对权限控制、增加自定义视图等功能。此版本号由项目决定是否修改
# * 修订版本号:一般是 Bug 修复或是一些小的变动,要经常发布修订版,时间间隔不限,修复一个严重的bug即可发布一个修订版。此版本号由项目经理决定是否修改。
# * 日期-阶段版本号:日期用于记录修改项目的当前日期,此版本号由开发人员决定是否修改;阶段版本号用于标注当前版本的软件处于哪个开发阶段,此版本号由项目决定是否修改,一般是希腊字母。
# 例如,1.1.12.20230117-Release
# 阶段版本号说明:
# * Base:此版本表示该软件仅仅是一个假页面链接,通常包括所有的功能和页面布局,但是页面中的功能都没有做完整的实现,只是做为整体网站的一个基础架构。
# * Alpha:此版本表示该软件在此阶段主要是以实现软件功能为主,通常只在软件开发者内部交流,一般而言,该版本软件的Bug较多,需要继续修改。
# * Beta: 该版本相对于Alpha版已有了很大的改进,消除了严重的错误,但还是存在着一些缺陷,需要经过多次测试来进一步消除。
# * RC:该版本已经相当成熟了,基本上不存在导致错误的BUG,与即将发行的正式版相差无几。
# * Release:该版本意味“最终版本”,在前面版本的一系列测试版之后,终归会有一个正式版本,是最终交付用户使用的一个版本。
# 关于CMake的版本规则:MAJOR.MINOR.PATCH.TWEAK
# CMake的版本号各个部分必须是数字组成
# 例如:1.1.1.20231017
project(TUTORIAL VERSION 1.1.1.20231017 LANGUAGES C CXX)# make cache variables for install destinations
include(GNUInstallDirs)# 指定C++编译标准
# 方式一:利用set指定 the C++ standard
# set(CMAKE_CXX_STANDARD 11)
# set(CMAKE_CXX_STANDARD_REQUIRED True)
# 方式二:利用接口库的形式
add_library(tutorial_cxx_compiler_flags INTERFACE)
target_compile_features(tutorial_cxx_compiler_flags INTERFACE cxx_std_11)# debug模式以'd'结尾
set(CMAKE_DEBUG_POSTFIX d)# 指定自定义变量
set(TEST_VERBOSE_FLAG "${PROJECT_NAME} Demo")# 判断当前使用的编译器
# 基于生成器表达式
# $<COMPILE_LANG_AND_ID:language,compiler_ids>: 当项目所用编程语言匹配language,
# 且项目所用编译器匹配compiler_ids时,此表达式返回1,否则返回0
# * Create a new variable gcc_like_cxx that is true if we are using CXX and
#   any of the following compilers: ARMClang, AppleClang, Clang, GNU, LCC
# * Create a new variable msvc_cxx that is true if we are using CXX and MSVC
set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")# 为接口库tutorial_cxx_compiler_flags 增加编译警告选项
# 基于条件生成器表达式
# * $<condition:true_string> : 当condition为真则返回true_string,否则返回空字符串
# * $<IF:condition,true_string,false_string> : 当condition为真则返回true_string,否则返回false_string
# 生成器表达式支持嵌套
# INTERFACE作用域表示tutorial_cxx_compiler_flags 本身不需要,但是tutorial_cxx_compiler_flags 调用方需要使用
# BUILD_INTERFACE生成器表达式
# 我们只想在编译阶段使用警告选项,而不会在安装阶段使用,可以利用BUILD_INTERFACE限制
target_compile_options(tutorial_cxx_compiler_flags INTERFACE "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>""$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
)message(STATUS "PROJECT_NAME:" ${PROJECT_NAME})
message(STATUS "CMAKE_PROJECT_NAME:" ${CMAKE_PROJECT_NAME})
message(STATUS "CMAKE_CURRENT_SOURCE_DIR:" ${CMAKE_CURRENT_SOURCE_DIR})
message(STATUS "CMAKE_CURRENT_BINARY_DIR:" ${CMAKE_CURRENT_BINARY_DIR})message(STATUS "LIBB_BINARY_DIR:" ${LIBB_BINARY_DIR})
message(STATUS "PROJECT_SOURCE_DIR:" ${PROJECT_SOURCE_DIR})
message(STATUS "CMAKE_SOURCE_DIR:" ${CMAKE_SOURCE_DIR})# 添加路径到CMAKE_PREFIX_PATH 使find_package可以搜索加载package
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../install/LIBA/cmake")
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../install/LIBB/cmake")foreach(_dir ${CMAKE_PREFIX_PATH})message(STATUS "${CMAKE_PROJECT_NAME}-find_package in dir:${_dir}")
endforeach()# TUTORIAL <-- LIBB <-- LIBA
# TUTORIAL <-- LIBA
# LIBB <-- LIBA
find_package(LIBB 1.1.0 REQUIRED COMPONENTS redefining)
if(NOT LIBB_FOUND)message(FATAL_ERROR "${COMPONENT}-package: LIBB not found!")
endif()find_package(LIBA 1.1.0 REQUIRED COMPONENTS call)
if(NOT LIBA_FOUND)message(FATAL_ERROR "${COMPONENT}-package: LIBA not found!")
endif()# add the executable
add_executable(${PROJECT_NAME} main.cxx)target_link_libraries(${PROJECT_NAME} LIBB::redefining LIBA::call tutorial_cxx_compiler_flags)# 为target添加DEBUG_POSTFIX属性
set_target_properties(${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})

构建使用示例:

以Release模式为例:先构建liba,再构建libb,最后构建tutorial

liba-构建命令

> cd @liba目录
> mkdir build_release
> cd build_release
> cmake -G "Visual Studio 16 2019" -DCMAKE_BUILD_TYPE=Release ..
> cmake --build .
> cmake --install .

libb-构建命令

> cd @libb目录
> mkdir build_release
> cd build_release
> cmake -G "Visual Studio 16 2019" -DCMAKE_BUILD_TYPE=Release ..
> cmake --build .
> cmake --install .

tutorial-构建命令

> cd @liba目录
> mkdir build_release
> cd build_release
> cmake -G "Visual Studio 16 2019" -DCMAKE_BUILD_TYPE=Release ..
> cmake --build .

注意:针对multi-configuration生成器,比如Visual Studio,是会忽略CMAKE_BUILD_TYPE选项的;只有single-configuration生成器,比如Makefile,才支持CMAKE_BUILD_TYPE选项。
故在CMakeLists.txt中判断Debug模式还是Release模式,需要使用生成器表达式:

$<IF:$<CONFIG:Debug>,true_string,false_string>
查看全文

99%的人还看了

猜你感兴趣

版权申明

本文"基于CMake的C++项目管理实践":http://eshow365.cn/6-20396-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!