0
点赞
收藏
分享

微信扫一扫

CMake快速构建安装工具、CMake快速封包脚本——PKG.cmake

CMake快速构建安装工具、CMake快速封包脚本——PKG.cmake

       你是否有过在正式写代码之前焦头烂额地编写一大堆CMake构建代码?你是否有过在封装自己的库时写了一堆install()、export()等CMake安装导出代码?你是否曾希望过自己能快速构建出能够被别人find_package得到的库?你是否曾想过自己能够快速构建出像boost那样的多组件库?那么,接下来的内容,将会让你眼前一亮,耳目一新。
       Github链接

介绍

       简化项目安装过程中的大量代码,使用单个函数封装一些导出和安装操作,以方便构建安装单个项目或多组件项目。

使用方法

最简单的构建安装库示例
PKG(
  _NAME PKG_lib
  _INCLUDE_DIRS "include/"		# 此处意为“include中的所有文件或目录将被安装,但不包括include本身”
)

执行库安装后,就可以在其他项目中引用PKG_lib库:

find_package(PKG_lib REQUIRED)

怎么样,是不是很简单?

那么我们再来看看怎么构建安装可执行文件(即不要include和lib)↓

简单的构建安装可执行文件示例
PKG(
  _NAME PKG_exe
  _MODE Runtime
  _INSTALL_BIN_DIR "."    # Windows系统适用:默认可执行文件安装在安装目录的bin目录,该代码可以使可执行文件安装到安装目录根目录上
  _DISABLE_INTERFACE
  _DISABLE_CONFIG
  _DISABLE_VERSION
)

进行编译安装(不懂怎么使用cmake进行库编译安装的自己去百度,本篇文章不属于基础教学),你就会神奇的发现,它安装到了C:\Program Files (x86)\PKG_exe目录中,当然这个安装目录是可以修改的,以上例子只是简单的介绍基本功能。

一个较为完整的动态库封包示例
cmake_minimum_required(VERSION 3.20)
project(PKG_shared VERSION 1.2.3.4)

add_library(PKG_shared SHARED)
add_library(PKGNS::PKG_shared ALIAS PKG_shared)
set_target_properties(
  PKG_shared PROPERTIES
  VERSION 1.2.3.4
  #SOVERSION 1.2
  DEFINE_SYMBOL "${COMPONENT_NAME}_EXPORTS"
  MSVC_RUNTIME_LIBRARY "${MSVC_RUNTIME_LIB}"
)

include(cmake/PKG.cmake)
PKG(
  _NAME "PKG_shared"
  #_VERSION 1.2.3.4         # 因为PKG_shared已经定义了VERSION属性,这句就免了
  _DEBUG_POSTFIX "d"        # 相当于‘set_target_properties(PKG_shared PROPERTIES DEBUG_POSTFIX "d")’
  _NAMESPACE "PKGNS"
  _INCLUDE_DIRS "include/"
  _INCLUDE_EXCLUDE_REG ".*\\.(svn|h\\.in|hpp\\.in)$"
  _INCLUDE_DESTINATION "include/${PROJECT_NAME}-1.2.3.4"
  _EXPORT_HEADER "comm1_export.h"        # 相对于CMAKE_CURRENT_BINARY_DIR
  _INSTALL_PDB              # 仅MSVC有效
  #_ADD_LIB_SUFFIX          # 如果在64位计算机上,_BINARY_LIB_DIR和_INSTALL_LIB_DIR的值将添加后缀'64'
  _ADD_UNINSTALL
)

target_sources(
  PKG_shared PRIVATE "src/add.cpp"
)

target_include_directories(
  PKG_shared PRIVATE
  "include"
  "${PKG_PKG_shared_EXPORT_HEADER_DIR}"
)

一个麻雀虽小五脏俱全的多组件项目封包示例

如果要打包多组件项目,此脚本将为您提供极大的便利。该功能提供两个特殊选项: _IS_COMPONENT_IS_COMPONENTS_IS_COMPONENT指定当前_NAME目标是项目的一个组件,则此组件将附属于_PROJECT项目,_PROJECT在定义_IS_COMPONENT参数时就默认为PROJECT_NAME_PROJECT可以定制。

主项目部分:

project(PKG VERSION 0.0.1)

# Its components also set this value to the default value of their _INSTALL_DIR, unless custom _INSTALL_DIR
set(PKG_PKG_INSTALL_DIR "/home/pkg/pkg_install")

add_subdirectory(component)

# Called after all child components
PKG(
  _IS_COMPONENTS
  _NAME ${PROJECT_NAME}
  _VERSION 0.0.1
  #_INCLUDE_DIRS "macro"             # 在这里,您可以将其他include目录添加到 _INCLUDE_DESTINATION 指定的路径中
  _INCLUDE_FILES "macro/global.h" "macro/macro.h"    #  结果同上,只是这里是针对文件而不是目录
  _INCLUDE_EXCLUDE_REG ".*\\.(svn|h\\.in|hpp\\.in)$"
  #_INCLUDE_DESTINATION "include"    # _INCLUDE_DESTINATION 的值默认为 _INSTALL_INCLUDE_DIR,也就是 "include"
  _SHARED_LIBS
  _ADD_UNINSTALL
)

组件部分:

add_library(component SHARED)
PKG(
  _IS_COMPONENT
  _NAME component
  _PROJECT PKG
  _NAMESPACE "${PROJECT_NAME}"
  _DEBUG_POSTFIX "d"
  _INCLUDE_DIRS "include/"
  _INCLUDE_EXCLUDE_REG ".*\\.(svn|h\\.in|hpp\\.in)$"
  _INCLUDE_DESTINATION "include/${PROJECT_NAME}"
  _EXPORT_HEADER "include/component_export.h"    # 将定义 PKG_PKG_component_EXPORT_HEADER_DIR 变量
  _INSTALL_PDB
)

接下来,您可以在其他项目中使用find_package()来查询该组件:

find_package(PKG COMPONENTS component REQUIRED)
...
target_link_libraries(... PRIVATE PKG::component)
...

PKG()的功能很强大,详细介绍可前往Github查看。

PKG()的代码注释

以下的内容是PKG()的开头中文注释(Github上我删掉了这部分,为了简化代码):

#===============================================================================
#
# @brief 快速打包项目或项目内的组件
#
# @par 可用参数
# _IS_COMPONENT             opt,当前安装的是项目的小部件
# _IS_COMPONENTS            opt,当前安装的是组件集,组件集不能是可生成目标,也就是说 `_NAME`不能是`add_library`或`add_executable`等命令生成的目标
# _NAME                     one,项目名称/组件名称(无默认)
# _PROJECT                  one,`_IS_COMPONENT` 开启时可用,指定本组件所附属的项目名称(默认:${PROJECT_NAME})
# _VERSION                  one,版本(默认:目标(_NAME)属性 VERSION 的值|未定义)
# _COMPATIBILITY            one,定义目标的版本兼容性,
#                           支持的值: `AnyNewerVersion|SameMajorVersion|SameMinorVersion|ExactVersion`(默认:AnyNewerVersion)
# _DEBUG_POSTFIX            one,在Debug的编译文件的文件名后面添加标识,例如:"d",对Release无效(无默认)
# _SHARED_LIBS              opt,指定函数作用域内的 BUILD_SHARED_LIBS 变量值,将会在PKG_components-config.cmake.in用到
# _BINARY_DIR               one,指定项目的二进制目录(默认:${CMAKE_BINARY_DIR})
# _BINARY_BIN_DIR           one,指定项目的二进制目录的 runtime 目录,相对于 `_BINARY_DIR`,也可定义绝对路径(默认:bin)
# _BINARY_LIB_DIR           one,指定项目的二进制目录的 library 目录,相对于 `_BINARY_DIR`,也可定义绝对路径(默认:lib)
# _INSTALL_DIR              one,指定项目的安装目录(默认:${CMAKE_INSTALL_PREFIX})
# _INSTALL_INCLUDE_DIR      one,指定项目的安装目录的 include 目录,相对于 `_INSTALL_DIR`,也可定义绝对路径(默认:include)
# _INSTALL_BIN_DIR          one,指定项目的安装目录的 runtime 目录,相对于 `_INSTALL_DIR`,也可定义绝对路径(默认:bin)
# _INSTALL_LIB_DIR          one,指定项目的安装目录的 library 目录,相对于 `_INSTALL_DIR`,也可定义绝对路径(默认:lib)
# _ADD_LIB_SUFFIX           opt,在 library 目录名添加后缀"64",仅64位系统有效
# _INCLUDE_FILES            mul,目标公共标头的文件位置,可以是绝对或相对路径,相对路径相对于 `CMAKE_CURRENT_SOURCE_DIR`,支持生成器表达式(无默认)
# _INCLUDE_DIRS             mul,目标公共标头的目录位置,可以是绝对或相对路径,相对路径相对于 `CMAKE_CURRENT_SOURCE_DIR`,支持生成器表达式(无默认)
# _INCLUDE_EXCLUDE_REG      one,安装目标公共标头时忽略的文件或目录的完整路径相匹配的正则表达式(无默认)
# _INCLUDE_DESTINATION      one,匹配目标的 `INSTALL_INTERFACE` 包含目录(默认:${_INSTALL_INCLUDE_DIR})
# _DISABLE_INTERFACE        opt,禁止把 `_INCLUDE_DESTINATION` 指定的目录包含到 `INSTALL_INTERFACE` 中
# _MODE                     one,安装模式,支持的值: `Runtime | Development`(默认:Development)
# _NAMESPACE                one,使用命名空间安装您的目标,不要添加额外的'::'(无默认)
# _EXPORT_HEADER            one,此处设置创建的导出标头的文件绝对或相对路径,相对路径相对于 `CMAKE_CURRENT_BINARY_DIR`(无默认)
# _EXPORT_MACRO             one,导出标头中的宏定义(默认:`${_NAME}_API|${_PROJECT}_${_NAME}_API`,将变为大写)
# _INSTALL_PDB              opt,安装PDB文件,仅MSVC有效
# _DISABLE_CONFIG           opt,禁用 `*-config.cmake` 文件生成
# _DISABLE_VERSION          opt,始终禁用 `*-config-version.cmake` 文件生成,如果没有基于 `_VERSION` 参数值以及没有定义 `_NAME` 的属性VERSION,`*-config-version.cmake` 文件也不会生成
# _CONFIG_TEMPLATE          one, 用于生成 `*-config.cmake` 文件的 config 模板文件(默认:${CMAKE_SOURCE_DIR}/cmake/PKG_normal-config.cmake.in|
#                                                                                   ${CMAKE_SOURCE_DIR}/cmake/PKG_components-config.cmake.in)
# _ADD_UNINSTALL            opt,`_IS_COMPONENT` 关闭时可用,添加卸载命令
# _UNINSTALL_TEMPLATE       one,`_IS_COMPONENT` 关闭时可用,卸载操作的模板文件(默认:${CMAKE_SOURCE_DIR}/cmake/PKG_cmake_uninstall.cmake.in)
# _UNINSTALL_ADDITIONAL     mul,`_IS_COMPONENT` 关闭时可用,附加卸载的文件或目录,被附加的文件或目录将在卸载操作进行时一同进行卸载(无默认)
#
# @par 全局变量
# PKG_<PROJECT>_BINARY_DIR  如果未自定义 _BINARY_DIR 参数,则会使用改变量值作为其参数值,该值会影响附属于<PROJECT>的组件
# PKG_<PROJECT>_INSTALL_DIR 如果未自定义 _INSTALL_DIR 参数,则会使用改变量值作为其参数值,该值会影响附属于<PROJECT>的组件
#
# @par 函数导出的变量
# PKG_<_PROJECT>_<_NAME>_EXPORT_HEADER_DIR  _IS_COMPONENT 开启时有效,值为导出标头的所在目录(确保 _EXPORT_HEADER 参数已定义)
# PKG_<_NAME>_EXPORT_HEADER_DIR             _IS_COMPONENT 与_IS_COMPONENTS 均关闭时有效,值为导出标头的所在目录(确保 _EXPORT_HEADER 参数已定义)

其实以上的注释也足以让大家知道怎么使用该脚本,无非就是熟悉一个函数——PKG()。

结束语

       PKG.cmake才是刚刚起步,有bug也在所难免,希望大家多给建议,在GitHub上多献上您的Issues,我收到信息后就会第一时间进行测试和修正,让PKG.cmake对你更有帮助。

举报

相关推荐

0 条评论