如何在 CMake 中找到 zlib 的静态版本?

How to find static version of zlib in CMake?

我使用的是 cmake 版本 3.12.1,我想构建一个使用 ZLIB 的静态可执行文件。我的机器上有静态 (libz.a) 和共享 (libz.so) 库。我如何告诉 find_package(ZLIB) 到 return 静态版本?也许还有另一种方法可以找到 libz.a

我目前的解决方法是指定:

SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")

然后:

target_link_libraries (my_binary z lib1 lib2)

也欢迎对这种方法提出批评!

考虑到 find_package(ZLIB),特别是 FindZLIB.cmake 调用的 CMake 模块的限制,您的方法是有效的。虽然其他 FindXXX.cmake 模块有一个用于获取静态库的特殊选项,但 zlib 模块没有。

SO 上已经有一些关于此主题的问题,但有些问题比其他问题更早,因此有几个选项。

您可以通过将 -static 标志添加到您的 target_link_libraries 调用来在更精细的级别上应用它(而不是编辑全局 CMAKE_EXE_LINKER_FLAGS 变量)。这样它将仅适用于该目标——如果您正在构建其他非静态目标则很有用。

您还可以通过设置 CMAKE_FIND_LIBRARY_SUFFIXES 告诉 CMake 显式搜索静态库。当调用 find_package 时,CMake 可以使用以下方法搜索以 .a 结尾的库:

SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
find_package(ZLIB REQUIRED) 

如果您可以控制安装 zlib,例如,您在持续集成设置中安装依赖项,我建议只删除 zlib 动态库。

zlib 没有静态或动态构建的选项,它会自动生成两个版本。但是 FindZlib.cmake 优先考虑动态版本。

如果您无权修改需要 zlib:

的第三方存储库 CMakeLists.txt,我发现以下方法更好
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  set(_compiler_is_msvc ON)
endif()
option(ZLIB_FORCE_STATIC "Remove the dynamic libraries after zlib install" ON)
mark_as_advanced(ZLIB_FORCE_STATIC)

set(OUTPUT_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH "Base folder where builds and source folder will be installed: i.e. OUTPUT_BUILD_DIR/zlib")

if(_compiler_is_msvc)
  set(ZLIB_GIT_TAG cacf7f1d4e3d44d871b605da3b647f07d718623f) # Version 1.2.11
  message(STATUS "ZLIB_VERSION: ${ZLIB_GIT_TAG} : Version 1.2.11")
  set(ZLIB_BUILD_DIR ${OUTPUT_BUILD_DIR}/zlib-build)
  set(ZLIB_INSTALL_DIR ${OUTPUT_BUILD_DIR}/zlib)
  set(ZLIB_SRC_FOLDER_NAME zlib-src)
  set(ZLIB_SRC_DIR ${OUTPUT_BUILD_DIR}/${ZLIB_SRC_FOLDER_NAME})
  set(ZLIB_GIT_REPOSITORY "https://github.com/madler/zlib")

  ExternalProject_Add(ep_zlib
    GIT_REPOSITORY ${ZLIB_GIT_REPOSITORY}
    GIT_TAG ${ZLIB_GIT_TAG}
    # GIT_SHALLOW TRUE
    GIT_PROGRESS TRUE
    CMAKE_GENERATOR ${CMAKE_GENERATOR}
    SOURCE_DIR ${ZLIB_SRC_DIR}
    BINARY_DIR ${ZLIB_BUILD_DIR}
    CMAKE_ARGS
        -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
        -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
        -DCMAKE_BUILD_TYPE:STRING=${SGEXT_CMAKE_BUILD_TYPE}
        -DBUILD_SHARED_LIBS:BOOL=OFF
        -DCMAKE_INSTALL_PREFIX=${ZLIB_INSTALL_DIR}
    )

  if(ZLIB_FORCE_STATIC)
    ExternalProject_Add_Step(
      ep_zlib zlib_remove_dll
      COMMENT "Remove zlib.lib and zlib.dll, leaves only zlibstatic.lib"
      DEPENDEES install
      COMMAND ${CMAKE_COMMAND} -E remove -f ${ZLIB_INSTALL_DIR}/lib/zlib.lib ${ZLIB_INSTALL_DIR}/bin/zlib.dll
      )
  endif()

endif()

最后一步去掉了动态版本,所以默认FindZLIB会找静态库

我不推荐@phcerdan 提出的解决方案,因为在我的情况下,已安装的共享库与已安装的版本发生冲突,因此唯一的解决方案是确保它永远不会首先安装。关键思想是使用 SKIP_INSTALL_LIBRARIES 完全禁用目标安装,而是手动“安装”静态库。尽管如此,我的解决方案非常相似:

EXTERNALPROJECT_ADD(zlib_external
     GIT_REPOSITORY    https://github.com/madler/zlib.git
     GIT_TAG           v1.2.11

     CMAKE_ARGS
          -DSKIP_INSTALL_FILES=ON  # Disable install of manual and pkgconfig files
          -DSKIP_INSTALL_LIBRARIES=ON  # Do not install libraries automatically. It will be handled manually to avoid installing shared libs
          -DBUILD_SHARED_LIBS=OFF
          -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
          -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX}
          -DCMAKE_C_FLAGS:STRING=${CMAKE_COMPILE_FLAGS_EXTERNAL}
          ${EXTERNALPROJECT_BUILD_TYPE_CMD}
     INSTALL_DIR ${CMAKE_INSTALL_PREFIX}
)

if(NOT WIN32)
     set(zlib_BUILD_LIB_PATH "<BINARY_DIR>/libz.a")
     set(zlib_PATH "${CMAKE_INSTALL_PREFIX}/lib/libz.a")
else()
     set(zlib_BUILD_LIB_PATH "<BINARY_DIR>/Release/zlibstatic.lib")
     set(zlib_PATH "${CMAKE_INSTALL_PREFIX}/lib/zlibstatic.lib")
endif()

ExternalProject_Add_Step(
     zlib_external zlib_install_static_only
     COMMENT "Manually installing only static library"
     DEPENDEES install
     COMMAND ${CMAKE_COMMAND} -E copy ${zlib_BUILD_LIB_PATH} ${zlib_PATH}
)

我找到的最佳解决方案是在调用 CMake 时明确命名库:

cmake -DZLIB_LIBRARY=/usr/lib/x86_64-linux-gnu/libz.a /path/to/source

自 CMake 3.24 起,使用:set(ZLIB_USE_STATIC_LIBS "ON")

Source