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

时间:2019-10-11 19:14:33

标签: cmake zlib

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

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

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

然后:

target_link_libraries (my_binary z lib1 lib2)

也欢迎对此方法提出批评!

4 个答案:

答案 0 :(得分:2)

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

关于此主题,已经有一些关于SO的问题,但是有些问题比其他的早,因此有一些选择。

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

您还可以通过设置CMAKE_FIND_LIBRARY_SUFFIXES告诉CMake明确搜索静态库。调用find_package时,CMake可以使用以下命令搜索以.a结尾的库:

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

答案 1 :(得分:1)

例如,如果您有安装zlib的控制权,并且要在“持续集成”设置中安装依赖项,我建议只删除zlib动态库。

zlib无法选择静态或动态构建,而是自动生成两个版本。但是FindZlib.cmake优先考虑动态版本。

如果您无权修改需要CMakeLists.txt的第三方存储库zlib,我发现以下方法会更好:

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将查找静态库。

答案 2 :(得分:0)

我不推荐@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}
)

答案 3 :(得分:0)

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

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