有时就该放弃幻想
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 嘻嘻嘻 一家独大的优势。。
学习一个!
指导的好