Cmake库导入脚本:使用 CMakeLists.txt 创建自定义的库导入脚本

简介: Cmake库导入脚本:使用 CMakeLists.txt 创建自定义的库导入脚本

介绍

CMake是一款跨平台的构建工具,它可以帮助开发者管理项目的构建过程。通过CMake,开发者可以编写CMakeLists.txt文件来定义项目的构建规则,包括编译选项、依赖关系等。CMake具有高度可配置性和可扩展性,因此被广泛用于各种类型的项目。
宏(Macro)是一种CMake中的特殊语句,可以将重复的代码片段封装为一个函数式的结构,并在需要使用该代码片段的地方调用宏。宏可以带有参数,从而实现更加灵活的代码重用。
本篇博客的主题是编写一个CMake宏,用于批量导入库。在项目中,经常需要引入多个不同的库来实现各种功能。手动导入这些库的过程繁琐且容易出错,而逐个导入库的方法也很麻烦。因此,我们希望通过编写一个CMake宏来批量导入库,以提高代码的可维护性和开发效率。
如果库的数量比较少可以查看我的其他博客:
CMake之编写属于自己的Findxxx.cmake文件
Cmake 链接外部库


批量导入库的需求

在CMake项目中引入库有多种方法。其中,最基本的方法是手动导入库,即在CMakeLists.txt文件中使用target_link_libraries命令逐个引入需要的库。例如:
target_link_libraries(my_target lib1 lib2 lib3)
另一种方法是逐个导入库,即使用find_package命令查找并导入需要的库。例如:

find_package(Lib1 REQUIRED)
find_package(Lib2 REQUIRED)
find_package(Lib3 REQUIRED)
 target_link_libraries(my_target Lib1::Lib1 Lib2::Lib2 Lib3::Lib3)


这两种方法都有各自的缺点。手动导入库的方法需要自己手动添加每个库的引用,如果有很多库需要引入,就会非常繁琐且容易出错。而逐个导入库的方法则需要每个库都有对应的Find模块或Config文件,否则就需要手动编写对应的查找脚本,增加项目的维护成本。
因此,我们需要一种更加高效的方式来批量导入库。编写一个CMake宏来批量导入库可以解决这个问题。该宏可以接收一个库列表作为参数,然后自动引入所有库,从而避免了手动逐个导入的繁琐操作,同时也无需对每个库都编写对应的查找脚本。这样,我们就可以更加方便地管理项目中的库依赖,提高开发效率。

思路以及代码示例

首先,我们需要知道导入哪些库,可以在主CMake中传递,也可以用配置文件中记录。


  • 方式一:依据主 CMakeLists.txt传递定义模板文件批量导入库的示例:
# CMakeLists.txt
 # 定义一个目录路径
set(THIRD_PARTY_PATH "${CMAKE_SOURCE_DIR}/lib")
# 定义一个list变量
set(MYLIB_LIST "lib_name1" "lib_name2"  "lib_name3")
# 将变量导入到另一个cmake文件
configure_file(import_libs.cmake.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/import_libs.cmake.cmake @ONLY)

其中,configure_file命令会将import_libs.cmake.in文件中的变量替换后生成一个新的cmake文件${CMAKE_CURRENT_BINARY_DIR}/import_libs.cmake,其中的@ONLY表示只替换变量。
在import_libs.cmake.in文件中,你可以这样使用这个list变量:

# import_libs.cmake.in
# 导入list变量 
set(MY_LIST @MYLIB_LIST@)
set(THIRD_PARTY_PATH "@THIRD_PARTY_PATH@")
# 遍历list变量
foreach(name ${MYLIB_LIST })  
   set(INCLUDE_SEARCH_PATH "${THIRD_PARTY_PATH}/${line}/include") # 设置头文件搜索路径    
   set(LINK_SEARCH_PATH "${THIRD_PARTY_PATH}/${line}/lib") # 设置库文件搜索路径   
   include_directories(${INCLUDE_SEARCH_PATH})  # 添加头文件搜索路径   
   link_directories(${LINK_SEARCH_PATH})  # 添加库文件搜索路径    
  message(STATUS "ADD HEADER SEARCH PATH:${INCLUDE_SEARCH_PATH}")    
  message(STATUS "ADD LIBRARY SEARCH PATH:${LINK_SEARCH_PATH}")
endforeach()

在这个文件中,@ @内的变量会被替换会被替换为CMakeLists.txt文件中定义的变量,它代表占位符。
使用占位符的目的是在模板文件中将变量名标记出来,方便configure_file命令将占位符替换为实际的变量值。例如,set(MY_LIST @MY_LIST@)就是使用@MY_LIST@作为占位符。
使用占位符的好处是,当你需要在模板文件中使用多个变量时,可以将它们都标记出来,然后在configure_file命令中一次性将它们替换为实际的变量值,这样可以避免手动逐个替换变量名的麻烦。
然后你可以通过include命令将import_libs.cmake文件包含到其他CMakeLists.txt文件中,用于加载库。

# another_CMakeLists.txt
# 包含cmake文件
include(${CMAKE_CURRENT_BINARY_DIR}/other_cmake_file.cmake)
#在another_CMakeLists.txt文件中,你可以直接加载库。

  • 方式二:依据通过配置文件批量导入库的示例:
#import_libs.cmake
cmake_minimum_required(VERSION 3.20)
############################Set up auxiliary macros###################################################
MACRO(GETLINES _LINES _FILENAME)
 #读取指定文件 ${_FILENAME} 的内容,并将其赋值给变量 contents
 FILE(READ ${_FILENAME} contents) 
 message("TEST_FILE contents:" ${contents})
 #将变量 contents 中的所有换行符 \n 替换为分号 ;,并将结果存储在变量 ${_LINES} 中。这里使用了正则表达式替换,其中 \n 被转义为 \\n。
 #在 CMake 中,分号通常用于分隔列表中的元素
 STRING(REGEX REPLACE "\n" ";" ${_LINES} "${contents}")
ENDMACRO()
############################Set key macro##############################################################
MACRO(INIT_LIB_INFO)
 set(THIRD_PARTY_PATH "${CMAKE_SOURCE_DIR}/third_party")
 set(CONTIDEP_file "${CMAKE_SOURCE_DIR}/lib.config") # 设置依赖文件路径
 set(lines "")
GETLINES(lines ${CONTIDEP_file}) # 读取依赖文件内容
 set(DEPENDENCIES_PATH ${lines})# 设置依赖路径
   foreach (line ${lines})     
   set(INCLUDE_SEARCH_PATH "${THIRD_PARTY_PATH}/${line}/include") # 设置头文件搜索路径    
   set(LINK_SEARCH_PATH "${THIRD_PARTY_PATH}/${line}/lib") # 设置库文件搜索路径   
   include_directories(${INCLUDE_SEARCH_PATH})  # 添加头文件搜索路径   
   link_directories(${LINK_SEARCH_PATH})  # 添加库文件搜索路径    
  message(STATUS "ADD HEADER SEARCH PATH:${INCLUDE_SEARCH_PATH}")    
  message(STATUS "ADD LIBRARY SEARCH PATH:${LINK_SEARCH_PATH}")
  endforeach ()
ENDMACRO()
######################################################################################################
#list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/third_party/cmake")
INIT_LIB_INFO()

单一加载库和批量加载库的对比


使用link_libraries包含目录后用target_link_directories链接库:
优点:
简单,直观,易于使用;
可以在CMakeLists.txt中直接指定库的搜索路径,避免了手动设置环境变量;
可以一次性链接多个库。
缺点:
只能链接指定路径下的库,不能使用系统默认的搜索路径;
不支持查找系统库。
使用find_library查找库后用target_link_directories链接库:
优点:
可以查找系统默认的库,更加灵活;
可以通过设置CMAKE_PREFIX_PATH环境变量增加搜索路径;
可以通过设置CMAKE_MODULE_PATH环境变量控制find_library的搜索路径。
缺点:
较为繁琐,需要手动指定库名和搜索路径;
如果库名或搜索路径发生变化,需要手动修改CMakeLists.txt文件。
使用场景: 如果需要链接的库在指定路径下已经存在,且不需要查找系统库,可以使用link_libraries包含目录后用target_link_directories链接库的方式。如果需要查找系统库或者需要通过设置环境变量增加搜索路径,可以使用find_library查找库后用target_link_directories链接库的方式。

总结

本篇博客介绍了如何编写一个CMake宏来批量导入库。首先介绍了CMake和宏的概念,然后分别介绍了手动导入和逐个导入库的方法以及它们的缺点。最后,我们提出了批量导入库的需求,并说明了编写CMake宏的优点和重要性。
通过编写一个CMake宏,我们可以更加方便地管理项目中的库依赖,提高项目的可维护性和开发效率。同时,我们也需要注意一些细节问题,例如在使用宏时需要保证库的正确性和版本兼容性等。
总之,编写CMake宏是一个非常实用的技巧,可以使我们的开发工作更加高效和便捷。希望本篇博客对读者有所帮助!


目录
相关文章
|
2月前
|
存储 缓存 IDE
CMake之编写属于自己的Findxxx.cmake文件:定义一个定制化的CMakeLists.txt文件
CMake之编写属于自己的Findxxx.cmake文件:定义一个定制化的CMakeLists.txt文件
37 1
|
2月前
|
安全 Python
Python如何对文件进行重命名操作?
Python如何对文件进行重命名操作?
26 0
|
9月前
|
存储 Python
python--导入,模块的引用,包,__name__
python--导入,模块的引用,包,__name__
|
9月前
python-- 上传小文件
python-- 上传小文件
|
算法 数据处理 Python
python ——批量读取相同格式文件(多个文件夹/单个文件夹)---nc文件为例
在处理多个相同格式的文件时,python中的许多模块可以为我们提供很多遍历。 比如,我们想读取一个文件夹下多个相同格式的文件时 可以使用os模块,
python ——批量读取相同格式文件(多个文件夹/单个文件夹)---nc文件为例
|
10月前
|
Python
python运行环境模块导入和导出命令
python运行环境模块导入和导出命令
50 0
|
12月前
|
Python
python导出项目所依赖的所有的库文件以及安装
python导出项目所依赖的所有的库文件以及安装
144 0
|
JavaScript Windows
XRename(文件文件夹超级重命名工具)简介
XRename(文件文件夹超级重命名工具)简介
148 0
XRename(文件文件夹超级重命名工具)简介
python 如何实现删除指定文件夹下的指定后缀名文件
python 如何实现删除指定文件夹下的指定后缀名文件