cmake: 生成库的配置和版本信息,做成独立的库

原来一直自己写库的导出信息,但看qt的库引用方式非常好,今天仔细研究了下,弄明白了一部分,记录下。

先说明下它最大的好处。cmake提供的这个功能,可以自动适应不同的编译条件,像debug/release/…,不同的编译输出会存到target不同的变量里

使用cmake功能生成配置文件

其实,cmake早已做好了这部分工作,只是之前没注意到这个功能。

输出库的配置(ModuleTargets.cmake)

用法很简单:

install(TARGETS myexe EXPORT myproj DESTINATION bin) # 设置这个库的输出名为`myproj`
install(EXPORT myproj NAMESPACE mp_ DESTINATION lib/myproj) # 输出名为`myproj`的配置文件

其中,myexe是当前的target,EXPORT表示这个target要被输出,输出的配置名叫myproj。那么配置文件的名默认为myproj.cmake
使用这个功能的好处

让cmake为不同的编译条件生成不同的targets<Config>.cmake文件,例如在debug模式时生成 ModuleTarget-Debug.cmake
cmake会同时生成ModuleTargets.cmake文件,最终只需include这个文件即可

输出库的查找文件(Module-config.cmake)

这个文件是find_package时要用的,详见cmake : 详解find_package
Module-config.cmakeinclude(ModuleTargets.cmake),然后就可放心的使用find_package()
cmake也为这个config文件设置了帮助函数

include(CMakePackageConfigHelpers)
configure_package_config_file(
	<input> # 输入的config.cmake.in,需要预先准备
	<output> # 输出的文件
	INSTALL_DESTINATION <path> # 输出的路径,可以是绝对路径,如果不是绝对路径,会基于最后一个参数INSTALL_PREFIX计算绝对路径
  	[PATH_VARS <var1> <var2> ... <varN>] # 生成的变量,命名方式为`PACKAKE_VAR`,这些变量必须在config.cmake.in里使用
  	[NO_SET_AND_CHECK_MACRO] # 不生成 set_and_check 宏,这个宏用于检查路径是否合法
  	[NO_CHECK_REQUIRED_COMPONENTS_MACRO] # 不生成check_required_components宏,这个宏用于检查依赖项是否存在
  	[INSTALL_PREFIX <path>]	# 安装路径,必须是绝对路径,不设置时默认使用 CMAKE_INSTALL_PREFIX
  )

使用示例(cmake官方文档)
CmakeLists.txt

set(INCLUDE_INSTALL_DIR include/ ... CACHE )
set(LIB_INSTALL_DIR lib/ ... CACHE )
set(SYSCONFIG_INSTALL_DIR etc/foo/ ... CACHE )
#...
include(CMakePackageConfigHelpers)
configure_package_config_file(FooConfig.cmake.in
  ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
  INSTALL_DESTINATION ${LIB_INSTALL_DIR}/Foo/cmake
  PATH_VARS INCLUDE_INSTALL_DIR SYSCONFIG_INSTALL_DIR)
write_basic_package_version_file(
  ${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake
  VERSION 1.2.3
  COMPATIBILITY SameMajorVersion )
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
              ${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake
        DESTINATION ${LIB_INSTALL_DIR}/Foo/cmake )

预先配置好的config.cmake.in

set(FOO_VERSION x.y.z)
...
@PACKAGE_INIT@   #!!! 这行后,参数中的宏才会生效
...
set_and_check(FOO_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
set_and_check(FOO_SYSCONFIG_DIR "@PACKAGE_SYSCONFIG_INSTALL_DIR@")

check_required_components(Foo)

输出版本的配置(module-config-version.cmake)

include(CMakePackageConfigHelpers)
write_basic_package_version_file(
        ${CMAKE_BINARY_DIR}/cmake/eccad-version-config.cmake
        VERSION 0.1.8
        COMPATIBILITY AnyNewerVersion
        )

这里只有一点要非常注意,版本配置的文件名要和库配置文件名配对。具体点就是,

  1. <TargetName>-config.cmake配置<TargetName>-config-version.cmake
  2. <TargetName>Config.cmake配置<TargetName>ConfigVersion.cmake
    两者任选其一。
    再简单说下函数
write_basic_package_version_file( 
	filename 		# 文件名,要注意文件名配对
	[VERSION major.minor.patch] # 版本号信息
	COMPATIBILITY (AnyNewerVersion|SameMajorVersion) #AnyNewerVersion向后兼容,SameMajorVersion只对同一个大版本号生效
	)

在其他库中引用

引用的话非常方便
首先告诉cmake库在哪个目录,有三种方法:

  1. set(<TargetExportName>_ROOT <path>)
  2. set(<TargetExportName>_DIR <path>) # 设定*_DIR会使用*_ROOT失效
  3. set(CMAKE_PREFIX_PATH <path-to-TargetExportDir>) # 推荐这种
    然后直接查找即可
find_package(<TargetExportName>  # 本例中为“myproj”
   					<Version>	 # 格式类似1.1.1.1,最长为4
   					REQUIRED     # 找不到这个库,则停止执行cmake     
   					)

详解输出配置的函数install(EXPORT)

第一个比较常见,这里重点讲第二个install()函数。

install(EXPORT <export-name> 
		DESTINATION <dir>
        [NAMESPACE <namespace>] 
        [FILE <name>.cmake]
        [PERMISSIONS permissions...]
        [CONFIGURATIONS [Debug|Release|...]]
        [EXPORT_LINK_INTERFACE_LIBRARIES]
        [COMPONENT <component>])

EXPORT指定输出的配置target名,即在第一小节中用install(TARGETS)指定的<export-name>
DESTINATION配置文件放到哪个目录,建议自己指定,之后好找
NAMESPACE指定前缀,方便识别,使用时全名是<namespace><export-name>,如Qt5::Widgets的namespace是Qt5::
FILE:文件名,必须以*.cmake结尾,如果在这些指定了路径,那么DESTINATION可空着
PERMISSIONS:文件访问权限
CONFIGURATIONS:默认为空,即全部生效,如指定特定配置,那么只在特定配置生效,如指定release,则只在release时输出配置文件
EXPORT_LINK_INTERFACE_LIBRARIES:如果使用,那么在CMP0022NEW时,只有匹配(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)?的属性才会被输出
COMPONENT:(没看明白,附上原文)If a COMPONENT option is specified that does not match that given to the targets associated with the behavior is undefined. If a library target is included in the export but a target to which it links is not included the behavior is unspecified

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值