From 04e8ca215fbfc910c0b31d3b61c63e4643230778 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Thu, 6 Nov 2025 20:56:07 +0000 Subject: [PATCH] [cmake] Add support for statically linking libxml2 Dynamically depending on libxml2 results in various annoyances across different linux distros for release artifacts. Specifically on fedora and nixos the library has a different name than on debian, and on arch-linux they tried to remove the old name entirely. With this, enabled by default for releases, we don't sacrifice any behavior changes, but no longer have these issues. For lld the binary size impact is <1mb macOS ignores this setting since libxml2 is part of the OS and stable enough. This mirrors what we do for zstd Fixes https://github.com/llvm/llvm-project/issues/113696 Fixes https://github.com/llvm/llvm-project/issues/138225 Fixes https://discourse.llvm.org/t/official-builds-without-libxml2-and-libtinfo/58169 --- clang/cmake/caches/Release.cmake | 1 + lldb/source/Host/CMakeLists.txt | 7 ++++- llvm/CMakeLists.txt | 2 ++ llvm/cmake/config-ix.cmake | 39 +++++++++++++++---------- llvm/cmake/modules/LibXml2.cmake | 31 ++++++++++++++++++++ llvm/lib/WindowsManifest/CMakeLists.txt | 29 ++++++++++++------ 6 files changed, 84 insertions(+), 25 deletions(-) create mode 100644 llvm/cmake/modules/LibXml2.cmake diff --git a/clang/cmake/caches/Release.cmake b/clang/cmake/caches/Release.cmake index 25f7970119d07..45343c66dfb7f 100644 --- a/clang/cmake/caches/Release.cmake +++ b/clang/cmake/caches/Release.cmake @@ -171,6 +171,7 @@ set_final_stage_var(CPACK_GENERATOR "TXZ" STRING) set_final_stage_var(CPACK_ARCHIVE_THREADS "0" STRING) set_final_stage_var(LLVM_USE_STATIC_ZSTD "ON" BOOL) +set_final_stage_var(LLVM_USE_STATIC_LIBXML2 "ON" BOOL) if (LLVM_RELEASE_ENABLE_LTO) set_final_stage_var(LLVM_ENABLE_FATLTO "ON" BOOL) set_final_stage_var(CPACK_PRE_BUILD_SCRIPTS "${CMAKE_CURRENT_LIST_DIR}/release_cpack_pre_build_strip_lto.cmake" STRING) diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index c9e8afe48fcde..f3f59fde35784 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -152,7 +152,7 @@ set(EXTRA_LIBS) if (CMAKE_SYSTEM_NAME MATCHES "NetBSD") list(APPEND EXTRA_LIBS kvm) endif() -if (LLDB_ENABLE_LIBXML2) +if (LLDB_ENABLE_LIBXML2 AND NOT LLVM_USE_STATIC_LIBXML2) list(APPEND EXTRA_LIBS LibXml2::LibXml2) endif() if (HAVE_LIBDL) @@ -190,3 +190,8 @@ add_lldb_library(lldbHost NO_PLUGIN_DEPENDENCIES ${LLDB_LIBEDIT_LIBS} ) +if (LLDB_ENABLE_LIBXML2 AND LLVM_USE_STATIC_LIBXML2) + target_link_libraries(lldbHost PRIVATE ${LIBXML2_LIBRARIES}) + target_include_directories(lldbHost PUBLIC ${LIBXML2_INCLUDE_DIRS}) + add_dependencies(lldbHost libxml2) +endif() diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index f192cd05b5a34..45ed2ca0e92d0 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -605,6 +605,8 @@ set(LLVM_TARGET_ARCH "host" set(LLVM_ENABLE_LIBXML2 "ON" CACHE STRING "Use libxml2 if available. Can be ON, OFF, or FORCE_ON") +set(LLVM_USE_STATIC_LIBXML2 "OFF" CACHE BOOL "Use static version of libxml2. Can be ON, or OFF") + option(LLVM_ENABLE_LIBEDIT "Use libedit if available." ON) option(LLVM_ENABLE_LIBPFM "Use libpfm for performance counters if available." ON) diff --git a/llvm/cmake/config-ix.cmake b/llvm/cmake/config-ix.cmake index ed2bfa6df68f4..d374226214fe7 100644 --- a/llvm/cmake/config-ix.cmake +++ b/llvm/cmake/config-ix.cmake @@ -210,22 +210,31 @@ if(LLVM_ENABLE_ZSTD) endif() if(LLVM_ENABLE_LIBXML2) - if(LLVM_ENABLE_LIBXML2 STREQUAL FORCE_ON) - find_package(LibXml2 REQUIRED) - elseif(NOT LLVM_USE_SANITIZER MATCHES "Memory.*") - find_package(LibXml2) + if(APPLE) + set(LLVM_USE_STATIC_LIBXML2 OFF) endif() - if(LibXml2_FOUND) - # Check if libxml2 we found is usable; for example, we may have found a 32-bit - # library on a 64-bit system which would result in a link-time failure. - cmake_push_check_state() - list(APPEND CMAKE_REQUIRED_INCLUDES ${LIBXML2_INCLUDE_DIRS}) - list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBXML2_LIBRARIES}) - list(APPEND CMAKE_REQUIRED_DEFINITIONS ${LIBXML2_DEFINITIONS}) - check_symbol_exists(xmlReadMemory libxml/xmlreader.h HAVE_LIBXML2) - cmake_pop_check_state() - if(LLVM_ENABLE_LIBXML2 STREQUAL FORCE_ON AND NOT HAVE_LIBXML2) - message(FATAL_ERROR "Failed to configure libxml2") + + if(LLVM_USE_STATIC_LIBXML2) + include(LibXml2) + set(HAVE_LIBXML2 1) + else() + if(LLVM_ENABLE_LIBXML2 STREQUAL FORCE_ON) + find_package(LibXml2 REQUIRED) + elseif(NOT LLVM_USE_SANITIZER MATCHES "Memory.*") + find_package(LibXml2) + endif() + if(LibXml2_FOUND) + # Check if libxml2 we found is usable; for example, we may have found a 32-bit + # library on a 64-bit system which would result in a link-time failure. + cmake_push_check_state() + list(APPEND CMAKE_REQUIRED_INCLUDES ${LIBXML2_INCLUDE_DIRS}) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBXML2_LIBRARIES}) + list(APPEND CMAKE_REQUIRED_DEFINITIONS ${LIBXML2_DEFINITIONS}) + check_symbol_exists(xmlReadMemory libxml/xmlreader.h HAVE_LIBXML2) + cmake_pop_check_state() + if(LLVM_ENABLE_LIBXML2 STREQUAL FORCE_ON AND NOT HAVE_LIBXML2) + message(FATAL_ERROR "Failed to configure libxml2") + endif() endif() endif() set(LLVM_ENABLE_LIBXML2 "${HAVE_LIBXML2}") diff --git a/llvm/cmake/modules/LibXml2.cmake b/llvm/cmake/modules/LibXml2.cmake new file mode 100644 index 0000000000000..151cb8cfe7985 --- /dev/null +++ b/llvm/cmake/modules/LibXml2.cmake @@ -0,0 +1,31 @@ +include(ExternalProject) + +if (NOT LIBXML2_PREFIX) + set (LIBXML2_PREFIX libxml2) +endif() + +set(LIBXML2_PATH ${CMAKE_CURRENT_BINARY_DIR}/${LIBXML2_PREFIX}/src/${LIBXML2_PREFIX}) +set(LIBXML2_LIB_PATH ${LIBXML2_PATH}-build/libxml2.a) + +ExternalProject_Add(${LIBXML2_PREFIX} + PREFIX ${LIBXML2_PREFIX} + GIT_REPOSITORY https://github.com/GNOME/libxml2.git + GIT_TAG v2.15.1 + CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DBUILD_SHARED_LIBS=OFF + -DLIBXML2_WITH_PYTHON=OFF + -DLIBXML2_WITH_PROGRAMS=OFF + -DLIBXML2_WITH_TESTS=OFF + -DLIBXML2_WITH_LZMA=OFF + -DLIBXML2_WITH_ZLIB=OFF + CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} + -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} + -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON + BUILD_BYPRODUCTS ${LIBXML2_LIB_PATH} + UPDATE_COMMAND "" + INSTALL_COMMAND "" + ) + +set(LIBXML2_INCLUDE_DIRS ${LIBXML2_PATH}/include ${LIBXML2_PATH}-build) +set(LIBXML2_LIBRARIES ${LIBXML2_LIB_PATH}) +set(LIBXML2_DEFINITIONS "") diff --git a/llvm/lib/WindowsManifest/CMakeLists.txt b/llvm/lib/WindowsManifest/CMakeLists.txt index 910132a4c7dec..0eef3a52ec1a3 100644 --- a/llvm/lib/WindowsManifest/CMakeLists.txt +++ b/llvm/lib/WindowsManifest/CMakeLists.txt @@ -1,6 +1,6 @@ include(GetLibraryName) -if(LLVM_ENABLE_LIBXML2) +if(LLVM_ENABLE_LIBXML2 AND NOT LLVM_USE_STATIC_LIBXML2) set(imported_libs LibXml2::LibXml2) endif() @@ -18,17 +18,28 @@ add_llvm_component_library(LLVMWindowsManifest Support ) +if(LLVM_ENABLE_LIBXML2 AND LLVM_USE_STATIC_LIBXML2) + target_link_libraries(LLVMWindowsManifest PRIVATE ${LIBXML2_LIBRARIES}) + target_include_directories(LLVMWindowsManifest PRIVATE ${LIBXML2_INCLUDE_DIRS}) + add_dependencies(LLVMWindowsManifest libxml2) +endif() + # This block is only needed for llvm-config. When we deprecate llvm-config and # move to using CMake export, this block can be removed. if(LLVM_ENABLE_LIBXML2) - # CMAKE_BUILD_TYPE is only meaningful to single-configuration generators. - if(CMAKE_BUILD_TYPE) - string(TOUPPER ${CMAKE_BUILD_TYPE} build_type) - get_property(libxml2_library TARGET LibXml2::LibXml2 PROPERTY LOCATION_${build_type}) - endif() - if(NOT libxml2_library) - get_property(libxml2_library TARGET LibXml2::LibXml2 PROPERTY LOCATION) + if(LLVM_USE_STATIC_LIBXML2) + # When using static libxml2 built via ExternalProject, use the library path directly + get_library_name(${LIBXML2_LIBRARIES} libxml2_library) + else() + # CMAKE_BUILD_TYPE is only meaningful to single-configuration generators. + if(CMAKE_BUILD_TYPE) + string(TOUPPER ${CMAKE_BUILD_TYPE} build_type) + get_property(libxml2_library TARGET LibXml2::LibXml2 PROPERTY LOCATION_${build_type}) + endif() + if(NOT libxml2_library) + get_property(libxml2_library TARGET LibXml2::LibXml2 PROPERTY LOCATION) + endif() + get_library_name(${libxml2_library} libxml2_library) endif() - get_library_name(${libxml2_library} libxml2_library) set_property(TARGET LLVMWindowsManifest PROPERTY LLVM_SYSTEM_LIBS ${libxml2_library}) endif()