背景

最近把ubuntu系统从2404升级到了2604,发现使用drogon框架的一个http服务启动不了,原因是本地的jsoncpp库由libjsoncpp.so.25升级到了libjsoncpp.so.26
因此想把jsoncpp改成链接静态库

解决过程

修改USE_STATIC_LIBS_ONLY变量

查看drogon的CMakeLists.txt文件,发现有如下代码:

option(USE_STATIC_LIBS_ONLY "Use only static libraries as dependencies" OFF)

# jsoncpp
find_package(Jsoncpp REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC Jsoncpp_lib)

在自己的CMakeLists.txt文件中,将USE_STATIC_LIBS_ONLY设置为ON,编译之后,发现还是链接的jsoncpp动态库,USE_STATIC_LIBS_ONLY并没有影响到jsoncpp的链接方式

查看jsoncpp的cmake文件

从jsoncpp的cmake文件中可以发现,jsoncpp导出了两个变量jsoncpp_libjsoncpp_static其中jsoncpp_lib是动态库,jsoncpp_static是静态库把drogon的cmake改为如下:

# jsoncpp
find_package(Jsoncpp REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC Jsoncpp_static)

修改之后编译会导致找不到jsoncpp的头文件再把Jsoncpp改为全小写jsoncpp

# jsoncpp
find_package(jsoncpp REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp_static)

这次终于生效了

find_package的搜索过程

find_package有两种搜索模式:

  • Config 模式:CMake 提供配置文件时,大小写不敏感
    • 需要原项目定义了CMakePackageConfigHelpers
    • 在ubuntu中,库的cmake config文件一般放在/usr/lib/x86_64-linux-gnu/cmake/目录下
  • Module 模式:使用自定义查找脚本时,大小写敏感
    • 依赖内置的和用户自定义的Find.cmake脚本
    • 可以在官方文档查看预制的find功能,预定义的模块可以直接使用,不用自己实现一个Find.cmake脚本
      find_package会先使用Module模式,如果Module模式没有找到,才会使用Config模式

在drogon项目中可以发现提供了cmake_modules/FindJsoncpp.cmake脚本,所以使用带的Jsoncpp会先使用这个脚本查找jsoncpp库,这个脚本只查找了Jsoncpp_lib,所以使用jsoncpp_static会报错改成小写jsoncpp之后,会因为大小写敏感,找不到Findjsoncpp.cmake脚本,会使用config模式,jsoncpp当前1.9.7版本是支持config模式的,所以修改之后可以编译成功并链接静态库

cmake可以通过一下配置优先使用config模式

set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)

也可以在find_package里指定

dropgon的CMakeLists.txt文件jsoncpp引入可以修改为如下:

find_package(jsoncpp REQUIRED CONFIG)
if (jsoncpp_FOUND)
  message(STATUS "jsoncpp found by config")
  if (USE_STATIC_LIBS_ONLY)
    target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp_static)
  else()
    target_link_libraries(${PROJECT_NAME} PUBLIC jsoncpp_lib)
   endif()
 else()
  find_package(Jsoncpp REQUIRED MODULE)
  target_link_libraries(${PROJECT_NAME} PUBLIC Jsoncpp_lib)
endif()