cmake, HOW TO

@vrqq  August 12, 2019
有时就该放弃幻想

CMake使用技巧合集

我们需要引第三方库的时候,有几个法子:

  • add_subdirectory(subprojectfolder)
  • include(findRapidJson.cmake) -> findRapidJson()
  • ExternalProject_Add(childproject ...)

最后一个:ExternalProject_Add是万金油写法,指执行外部脚本编译。

无论subproject是否是cmake编译的,都能使用。
使用方法:一般是给subproject的编译脚本传参,指定installPath,然后把installPath返回给我们的主项目CMakeLists.txt使用,我们面对的是一个已经编译好的库,只是install到了我们指定的位置,方便主project引用。

ExternalProject_Add(project_luajit
  URL http://luajit.org/download/LuaJIT-2.0.1.tar.gz
  PREFIX ${CMAKE_CURRENT_BINARY_DIR}/luajit-2.0.1
  CONFIGURE_COMMAND ""
  BUILD_COMMAND make
  INSTALL_COMMAND make install
  PREFIX=${CMAKE_CURRENT_BINARY_DIR}/luajit-2.0.1
)
ExternalProject_Get_Property(project_luajit install_dir)

Refereed from: https://mirkokiefer.com/cmake-by-example-f95eb47d45b1

第一个add_subdirectory: 首先要求subprojectfolder是由cmake构建的。

先普及一个概念:cmake中,不同的project靠的是cache进行传变量值,因此若subproject没有将变量export或者在cache中暴露,主project是读不到这个变量的!
这种一般适用于:subproject的文档里明确表示会暴露${SUB_INCLUDES}, ${SUB_LIBS}可供使用。
因此说即便是subproject也是cmake系统,但它并没有让主项目引他的想法,而且写的盘根错节,我们不知道该怎么改这个外来的cmakelists,暴露那些,这时候就放弃幻想,直接用上面那种各自build各自的。(人家虽然也是cmake,但是就是自己用用,可没想给你行方便啊。)

但是我们也可以手动暴露subproject的变量,在subprojectfolder/CMakeLists.txt中最后加上

set(CLIENT_LIBS ${CLIENT_LIBS} CACHE INTERNAL "")

即可把subproject的变量${CLIENT_LIBS}通过cmakecache暴露给我们的主project。

其实add_subdirectory是设计给子项目和主项目完全可控,都是自己写的情况的。比如我们把我们写的代码分了几个文件夹,互相串和一下这种。

中间那个include(.cmake): 腾讯的RapidJson采用的办法,提供了一个cmake脚本。

主project执行这个脚本,脚本内有搜索library的语句。先include()然后再调用,从而得到变量包含include/libs等等。。

其他的办法

find_package() / find_file() / find_library()
这些一般会写在cmake脚本里,探测指定地点有没有库的。
这种要说也能,那subproject就请自己一个个编译了哦。

另外想说的:add_subdirectory在过早的CMake里面没有哦。

一些疑问以及能否改进的地方

目前尚没有修改subproject的CMakeFiles.txt的方法,比如aliyun-oss-cpp-sdk,明确在其CMakeLists中标定了--no-rtti。
但是我就是想用rtti又绕不过编译脚本。
我想到写一个patch.cmake然后在里面include(CMakeFiles.txt)结果是不让,说include里面有project关键字。仔细想,这个include其实设计成引入脚本的,但或许以后怎么样就不得而知了。

一些思考

  • 我们的工程需要编译成 .so + binary_file吗?
    比如7zip这种是需要的,因为会有人引它的库
  • subproject是编译成 .so 然后由主项目引用吗?涉及到部署环境和开发环境不同。
    Idea 1:docker,随意摆放依赖。
    Idea 2:全部打包成静态库,最后build Release后是一个几百M的binary file。这个很难过,我们自己不依赖库,但我们很难保证subproject依赖的库的特定版本。我们在开发机上编译,那么引的例如libc都是开发机的版本。而选择了.so就一镜到底了。
    Idea 3:带到运行环境编译/和运行环境相同的开发机,很麻烦的啊!
  • 这也正是说为什么各路发行版会各自安排依赖路径,很难兼容。
  • 我们需要一个工具,把开发环境的.so依赖树全部提出来,这不就相当于进了docker吗。
  • 想想windows,为啥下载的软件里不见引用ntdll.dll的,而有时会包含msvcrt110.dll(当然有的也不含就楞报错)。
    因为Windows就他自己哟,也没听说过fedorawindows archwindows 嘻嘻嘻 一家独大的优势。。

已有 2 条评论

  1. SPYNGELION SPYNGELION

    学习一个!

添加新评论