CMake 使用 install 与 export 导出库

NOTE: 因为 CSDN 上没有 CMake 的语法高亮,所以拿 lua 的替代了,还算看得过去。

关键词:CMake CMake install CMake export

废话不多说,先上成品!

给 VSCode 用的 Snippet 👇

{
    "CMake install configure": {
        "prefix": "cmake-install",
        "body": [
            "# --- BEGIN CMAKE INSTALL/EXPORT ---",
            "include(GNUInstallDirs)",
            "set(PROJECT_EXPORT_TARGETS ${1:\\${PROJECT_NAME\\}})",
            "set(PROJECT_EXPORT_NAME ${2:\\${PROJECT_NAME\\}})",
            "set(PROJECT_INSTALL_CMAKEDIR ${3:\\${CMAKE_INSTALL_LIBDIR\\}/cmake/\\${PROJECT_EXPORT_NAME\\}})",
            "",
            "# create aliases for targets",
            "foreach(target \\${PROJECT_EXPORT_TARGETS\\})",
            "\tadd_library(\\${PROJECT_EXPORT_NAME\\}::\\${target\\} ALIAS \\${target\\})",
            "endforeach()",
            "# install targets",
            "install(",
            "\tTARGETS \\${PROJECT_EXPORT_TARGETS\\}",
            "\tEXPORT \\${PROJECT_EXPORT_NAME\\}Targets",
            "\tARCHIVE DESTINATION \\${CMAKE_INSTALL_LIBDIR\\}",
            "\tLIBRARY DESTINATION \\${CMAKE_INSTALL_LIBDIR\\}",
            "\tRUNTIME DESTINATION \\${CMAKE_INSTALL_BINDIR\\}",
            "\tPUBLIC_HEADER DESTINATION \\${CMAKE_INSTALL_INCLUDEDIR\\}",
            "\tINCLUDES DESTINATION \\${CMAKE_INSTALL_INCLUDEDIR\\}",
            ")",
            "",
            "# install project headers",
            "install(",
            "\tDIRECTORY \\${CMAKE_CURRENT_SOURCE_DIR\\}/include/",
            "\tDESTINATION \\${CMAKE_INSTALL_INCLUDEDIR\\}",
            ")",
            "",
            "# install CMake xxxTargets.cmake",
            "export(",
            "\tEXPORT \\${PROJECT_EXPORT_NAME\\}Targets",
            "\tNAMESPACE \\${PROJECT_EXPORT_NAME\\}::",
            "\tFILE \\${PROJECT_EXPORT_NAME\\}Targets.cmake",
            ")",
            "install(",
            "\tFILES \\${CMAKE_CURRENT_BINARY_DIR\\}/\\${PROJECT_EXPORT_NAME\\}Targets.cmake",
            "\tDESTINATION \\${PROJECT_INSTALL_CMAKEDIR\\}",
            ")",
            "",
            "# install xxxConfigVersion.cmake",
            "include(CMakePackageConfigHelpers)",
            "write_basic_package_version_file(",
            "\t\\${PROJECT_EXPORT_NAME\\}ConfigVersion.cmake",
            "\tVERSION \\${PROJECT_VERSION\\}",
            "\tCOMPATIBILITY AnyNewerVersion",
            ")",
            "install(",
            "\tFILES \\${CMAKE_CURRENT_BINARY_DIR\\}/\\${PROJECT_EXPORT_NAME\\}ConfigVersion.cmake",
            "\tDESTINATION \\${PROJECT_INSTALL_CMAKEDIR\\}",
            ")",
            "",
            "# install CMake xxxConfig.cmake",
            "install(",
            "\tEXPORT \\${PROJECT_EXPORT_NAME\\}Targets",
            "\tFILE \\${PROJECT_EXPORT_NAME\\}Config.cmake",
            "\tNAMESPACE \\${PROJECT_EXPORT_NAME\\}::",
            "\tDESTINATION \\${PROJECT_INSTALL_CMAKEDIR\\}",
            ")",
            "# --- END CMAKE INSTALL/EXPORT ---"
        ],
        "description": "CMake 导出目标"
    }
}

简单讲讲

第一部分

#! 常用的模块了,设置 GNU 风格的 install 目录,变量命名为 CMAKE_INSTALL_xxxDIR
include(GNUInstallDirs)

#! 设置需要导出的目标(列表)
set(PROJECT_EXPORT_TARGETS ${PROJECT_NAME})

#! 设置导出的命名,在这份 snippet 中应用于 xxxConfig.cmake/xxxTargets.cmake/
#! xxxConfigVersion.cmake 和导出的目标的命名空间
set(PROJECT_EXPORT_NAME ${PROJECT_NAME})

#! 设置生成的 cmake 文件的 install 目录,通常会放在顶层目录为 share 或 lib/lib64 的
#! 目录下,在这里选择放在 lib/lib64 目录下
set(PROJECT_INSTALL_CMAKEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_EXPORT_NAME})

第二部分

#! 在同一个 CMake build tree 中,每个项目的 targets 对外都是可见的,比如 A 项目中有一个
#! foobar 的静态库目标,那么在 B 项目中就可以直接链接 foobar 目标。
#! 但是一般情况在 CMake 使用第三方库引入库都会有命名空间(命名冲突问题),这时链接的目标可
#! 能就是 foobar::foobar !(如果不是的话假设就是!!!)
#! 出于统一性考虑,应尽可能使得同一 build tree 内外链接同名目标。
#! 然而 build tree 内即使进行了 install/export 操作,依旧不能直接使用带有命名空间的目标
#! (可能以某种参数进行的 install/export 可以做到,但是我写的时候实在是在这上面找不到办法)
#! 故而曲线救国,在这里额外对导出的目标定义带命名空间的别名,完美!
#! NOTE: 不会吧不会吧?不会有人连这种别名都能造成命名冲突吧?
#! NOTE: 我自认为因为别名没在这里被导出,所以不会影响外部 CMake 项目的引入,或许只不过是我
#> 多虑了,其实根本就不存在这种问题呢?不过说到底我对此机理并未深究,故留个疑问在这。
foreach(target ${PROJECT_EXPORT_TARGETS})
    add_library(${PROJECT_EXPORT_NAME}::${target} ALIAS ${target})
endforeach()

第三部分

#! 重头之一:配置待导出目标们的 install 选项,主要包括相关文件的 install 目录,
#! 其中 EXPORT 参数指示了被导出目标集合的导出名,该项将在 export 中被使用以代替显
#! 式地列出目标。另
install(
    TARGETS ${PROJECT_EXPORT_TARGETS}
    EXPORT ${PROJECT_EXPORT_NAME}Targets
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

第四部分

#! 导出头文件
#! 实际上该命令单纯地用于 install 目录(当路径后跟着 "/" 时表示仅导入目录下的文件与子目录)
#! 但是由于我个人的习惯,即项目结构一般服从如下:
#! Project
#! |   CMakeLists.txt
#! +---include
#! |   \---ProjectInc
#! |           [Public Headers]
#! \---src
#!         *.cpp
#!         [Private Headers]
#!         CMakeLists.txt
#! 所以就方便如下这样直接导出公共头文件了!另外在这份 snippet 中还有几个地方也需要前置要求
#! 如上的目录结构,如果要直接挪用的话可能需要注意一下!
install(
    DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

第五部分

#! 重头之二:生成用于导入被导出目标的 xxxTargets.cmake 文件
#! export 支持 export(TARGETS) 命令和 export(EXPORT) 命令,在第三部分中提过,install
#! 中指定了待导入目标们的导出名,在此处则直接使用导出名指代被导出的目标。这与代换后的
#! export(TARGETS) 命令是等价的。
export(
    EXPORT ${PROJECT_EXPORT_NAME}Targets
    NAMESPACE ${PROJECT_EXPORT_NAME}::
    FILE ${PROJECT_EXPORT_NAME}Targets.cmake
)

#! export 执行生成的 xxxTargets.cmake 存在于 ${CMAKE_CURRENT_BINARY_DIR} 目录下(也就
#! 是 CMake 构造目录下的与源代码同名子目录),故而需要额外导入该文件。
install(
    FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_EXPORT_NAME}Targets.cmake
    DESTINATION ${PROJECT_INSTALL_CMAKEDIR}
)

第六部分

#! 生成 xxxConfig.cmake 的版本配置脚本 xxxConfigVersion.cmake
#! NOTE: 不是特别重要,可以跳过~
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
    ${PROJECT_EXPORT_NAME}ConfigVersion.cmake
    VERSION ${PROJECT_VERSION}
    COMPATIBILITY AnyNewerVersion
)

#! 原因同第五部分,需要手动导入!
install(
    FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_EXPORT_NAME}ConfigVersion.cmake
    DESTINATION ${PROJECT_INSTALL_CMAKEDIR}
)

第七部分

#! 重头之三:生成库的配置文件 xxxConfig.cmake xxxConfig-<config>.cmake
#! 其中 EXPORT 是一个已经被指派的导出名,剩下的部分敢敢当当,一目了然!
install(
    EXPORT ${PROJECT_EXPORT_NAME}Targets
    FILE ${PROJECT_EXPORT_NAME}Config.cmake
    NAMESPACE ${PROJECT_EXPORT_NAME}::
    DESTINATION ${PROJECT_INSTALL_CMAKEDIR}
)
数据分析,数据科学及AI算法是当前最热门的职业。这些职业有着共同的特点:面向数字的,针对编程的以及采取分析手段的。 这些当代热点特性使得在就业市场上对以上职位需求激增也就不足为奇了。但是,市场上提供这方面的大型综合的培训课程是有限,如果说有,大多是知识范围狭窄且非综合性的,而且大多培训都缺乏方法论与实务结合。一般的情况是讲师讲述某种语言的一堆代码,学生听完后甚至连使用方法及代码的前提都不清楚,更别提实际应用场景了。这里,掌握一门数据分析软件本身没错,但仅通过单一的编程培训很难获得聘用为数据分析师或数据科学家所需的技能。那我的解决方案是什么呢?首先,我把所有数据分析中的典型问题都归类总结出来,再结合相应的实际问题,数据以及案例,同时采用世界上最流行的两种数据分析软件:PYTHON 和 SAS去解决这些问题,并将这些解决方法传授给学生。学生在完成培训后更重要的收获是知道每一问题从产生直至解决的前因后果和应用场景,这是因为我在每一课程章节最前都会交代方法论,知识要点及应用场合。SAS和PYTHON可以一起学吗?当然可以。因为我就是这样做到的。具体步骤是,我在课程当中安排了一系列主题,然后使用两种编程语言解决同样的问题。我总结出这样做的好处是边学习边比较,最后在不知不觉当中掌握了两门语言的精华和数据分析的通用方法或模式。过程虽有点长,但十分有趣。最后,为了巩固已学的知识和技能,我还专门安排了针对PYTHON 和 SAS的中小型项目及详细代码讲解。另外,课程当中使用的全部编程代码及数据文件都将免费地提供给注册的学生。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周上行Ryer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值