如何在 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")
我使用的是 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")