This is an automated email from the ASF dual-hosted git repository.

tqchen pushed a commit to branch static-libxml2
in repository https://gitbox.apache.org/repos/asf/tvm.git

commit 609ab46c8f38459b93e6a8fba60e596320a84f01
Author: tqchen <[email protected]>
AuthorDate: Mon Jun 1 15:11:59 2026 +0000

    [BUILD] Static-libxml2 + LLVM static build cross-platform support
    
    Three changes that together let TVM build with statically linked
    LLVM (no libxml2 runtime dep) on both Linux and Windows:
    
    1. USE_STATIC_LIBXML2_FROM_SOURCE option (default OFF) + new file
       cmake/utils/CompileStaticLibXml2.cmake. When enabled, FetchContent
       pulls libxml2 v2.15.0 from GNOME/libxml2 with all optional
       features OFF (no programs, tests, threading, output, xpath, etc.),
       builds it static, and substitutes it for whatever libxml2 the
       LLVM static link line would have brought in. Gated to only
       activate when USE_LLVM contains --link-static (FATAL_ERROR
       otherwise).
    
    2. -Wl,--no-relax workaround in CMakeLists.txt for the GNU ld bug
       ld/25754: when LLVM static archives are linked into the
       large libtvm_compiler.so, ld can incorrectly relax an addr32-
       prefixed indirect GOT call into a direct call with the wrong
       displacement, jumping into read-only data and crashing inside
       llvm::X86Subtarget. Gated to Linux + USE_LLVM ON.
    
    3. .github/workflows/main.yml — enable the static LLVM build with
       USE_STATIC_LIBXML2_FROM_SOURCE on Windows CI so this branch
       exercises the cross-platform story.
    
    Verified on Linux: mamba LLVM 22.1.x static and system LLVM 15
    static both build clean, libtvm_compiler.so has no libxml2 in ldd,
    tvm.build('llvm') smoke test passes.
---
 .github/workflows/main.yml             |  7 ++++
 CMakeLists.txt                         | 14 +++++++
 cmake/config.cmake                     |  9 +++++
 cmake/modules/LLVM.cmake               | 22 +++++++++++
 cmake/utils/CompileStaticLibXml2.cmake | 68 ++++++++++++++++++++++++++++++++++
 5 files changed, 120 insertions(+)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index a30bbc3421..5fbdce7978 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -88,6 +88,13 @@ jobs:
         shell: cmd /C call {0}
         run: |
           conda install -c conda-forge llvmdev cmake ninja zlib libxml2-devel
+      - name: Build TVM (static LLVM + static libxml2)
+        shell: cmd /C call {0}
+        run: |
+          mkdir build
+          cd build
+          cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DUSE_LLVM="llvm-config 
--link-static" -DUSE_STATIC_LIBXML2_FROM_SOURCE=ON -DUSE_CUDA=OFF 
-DUSE_LIBBACKTRACE=OFF -DBUILD_TESTING=OFF
+          ninja tvm tvm_runtime
       - name: Install TVM
         shell: cmd /C call {0}
         run: |
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a11a872970..a4b70d5b0c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -670,6 +670,20 @@ if (HIDE_PRIVATE_SYMBOLS AND NOT ${CMAKE_SYSTEM_NAME} 
MATCHES "Darwin")
   target_link_libraries(tvm_runtime PRIVATE ${HIDE_SYMBOLS_LINKER_FLAGS})
 endif()
 
+# Work around a GNU ld (binutils) relaxation bug that miscompiles
+# R_X86_64_GOTPCRELX relocations inside very large statically-linked archives.
+# When the full LLVM static libraries are linked into libtvm_compiler.so, the
+# library is large enough that ld can relax an indirect GOT call (LLVM built
+# with -fno-plt emits these) into a direct call with an incorrect displacement.
+# The call then targets read-only data instead of the intended function and
+# crashes at runtime with a SIGSEGV inside llvm::X86Subtarget during code
+# generation. Disabling linker relaxation keeps the GOT-indirect sequences and
+# avoids the miscompilation; it is harmless when LLVM is linked dynamically.
+# See binutils bug ld/25754.
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT ${USE_LLVM} MATCHES 
${IS_FALSE_PATTERN})
+  set_property(TARGET tvm_compiler APPEND PROPERTY LINK_OPTIONS 
"-Wl,--no-relax")
+endif()
+
 # Create the `cpptest` target if we can find GTest.  If not, we create dummy
 # targets that give the user an informative error message.
 if(GTEST_FOUND)
diff --git a/cmake/config.cmake b/cmake/config.cmake
index dfbe0d2178..0c4097a12f 100644
--- a/cmake/config.cmake
+++ b/cmake/config.cmake
@@ -135,6 +135,15 @@ set(USE_LLVM OFF)
 # Possible values: ON/OFF
 set(USE_MLIR OFF)
 
+# Whether to fetch and statically link libxml2 in-tree instead of
+# depending on the system libxml2. Only valid when USE_LLVM is
+# configured with `--link-static`. When ON, FetchContent downloads
+# GNOME/libxml2 at v2.15.0 with all optional features OFF and links
+# the in-tree static archive into libtvm.so, replacing any -lxml2
+# that llvm-config --link-static emits.
+# Default OFF (preserves existing behavior).
+set(USE_STATIC_LIBXML2_FROM_SOURCE OFF)
+
 #---------------------------------------------
 # Contrib libraries
 #---------------------------------------------
diff --git a/cmake/modules/LLVM.cmake b/cmake/modules/LLVM.cmake
index f944b41304..adeaa420bb 100644
--- a/cmake/modules/LLVM.cmake
+++ b/cmake/modules/LLVM.cmake
@@ -25,6 +25,14 @@ add_definitions(-DNDEBUG=1)
 # TODO(@jroesch, @tkonolige): if we actually use targets we can do this.
 # target_compile_definitions(tvm_compiler PRIVATE NDEBUG=1)
 
+# Precondition: USE_STATIC_LIBXML2_FROM_SOURCE=ON is only supported with a 
static LLVM
+# link (i.e. USE_LLVM must contain "--link-static"). Catch the mismatch early.
+if(USE_STATIC_LIBXML2_FROM_SOURCE AND NOT (USE_LLVM MATCHES "--link-static"))
+  message(FATAL_ERROR
+    "USE_STATIC_LIBXML2_FROM_SOURCE=ON requires USE_LLVM to use --link-static "
+    "(e.g. set(USE_LLVM \"llvm-config --link-static\"))")
+endif()
+
 # Test if ${USE_LLVM} is not an explicit boolean false
 # It may be a boolean or a string
 if(NOT ${USE_LLVM} MATCHES ${IS_FALSE_PATTERN})
@@ -48,6 +56,20 @@ if(NOT ${USE_LLVM} MATCHES ${IS_FALSE_PATTERN})
     src/target/rocm/llvm/*.cc
     src/target/hexagon/llvm/*.cc
   )
+
+  # When USE_STATIC_LIBXML2_FROM_SOURCE=ON, fetch libxml2 in-tree (no 
submodule) and
+  # replace any system libxml2 reference that llvm-config emitted with the
+  # in-tree static target. This keeps libtvm.so free of a runtime libxml2 dep.
+  if(USE_STATIC_LIBXML2_FROM_SOURCE)
+    include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/utils/CompileStaticLibXml2.cmake)
+    _libxml2compile()
+    # Drop any -lxml2 / *libxml2* / *xml2* entries llvm-config injected.
+    list(FILTER LLVM_LIBS EXCLUDE REGEX "[Xx][Mm][Ll]2")
+    # Link the in-tree static target instead.
+    list(APPEND LLVM_LIBS LibXml2)
+    message(STATUS "USE_STATIC_LIBXML2_FROM_SOURCE=ON: replaced system xml2 
with in-tree LibXml2")
+  endif()
+
   list(APPEND TVM_LINKER_LIBS ${LLVM_LIBS})
   list(APPEND COMPILER_SRCS ${COMPILER_LLVM_SRCS})
   if(NOT MSVC)
diff --git a/cmake/utils/CompileStaticLibXml2.cmake 
b/cmake/utils/CompileStaticLibXml2.cmake
new file mode 100644
index 0000000000..f038b0d21b
--- /dev/null
+++ b/cmake/utils/CompileStaticLibXml2.cmake
@@ -0,0 +1,68 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+include(FetchContent)
+
+# Function: _libxml2compile — fetch libxml2 (no submodule) and produce a
+# static LibXml2 target with all optional deps disabled. Used when
+# USE_STATIC_LIBXML2_FROM_SOURCE=ON to avoid depending on a system libxml2.
+function(_libxml2compile)
+  FetchContent_Declare(
+    libxml2
+    GIT_REPOSITORY https://github.com/GNOME/libxml2.git
+    GIT_TAG        v2.15.0
+  )
+
+  # Static build, all optional features OFF.
+  # Anything not listed here keeps upstream default (typically cascade-OFF
+  # via libxml2's own cmake_dependent_option logic). See task file for the
+  # full cross-check.
+  set(BUILD_SHARED_LIBS        OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_PROGRAMS    OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_TESTS       OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_PYTHON      OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_DOCS        OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_ICU         OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_ICONV       OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_LEGACY      OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_ZLIB        OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_READLINE    OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_MODULES     OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_HTTP        OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_HTML        OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_CATALOG     OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_DEBUG       OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_XINCLUDE    OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_XPATH       OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_VALID       OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_REGEXPS     OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_PATTERN     OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_SAX1        OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_OUTPUT      OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_PUSH        OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_ISO8859X    OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_TLS         OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_THREAD_ALLOC OFF CACHE INTERNAL "")
+  set(LIBXML2_WITH_THREADS     OFF CACHE INTERNAL "")  # TVM never calls into 
libxml2
+
+  FetchContent_MakeAvailable(libxml2)
+
+  # Windows requires LIBXML_STATIC defined on consumers of the static lib.
+  if(WIN32)
+    target_compile_definitions(LibXml2 INTERFACE LIBXML_STATIC)
+  endif()
+endfunction()

Reply via email to