| # Copyright 2025 The IREE Authors | |
| # | |
| # Licensed under the Apache License v2.0 with LLVM Exceptions. | |
| # See https://llvm.org/LICENSE.txt for license information. | |
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| # Build libbacktrace from source for Linux stack traces. | |
| # Uses FetchContent to pull upstream and provides our own CMake build. | |
| # | |
| # libbacktrace (https://github.com/ianlancetaylor/libbacktrace) provides | |
| # complete stack trace functionality including unwinding and symbol resolution | |
| # with file:line:function information. | |
| # Only build libbacktrace on Linux when enabled. | |
| # Other platforms have their own stack trace implementations: | |
| # - Windows: dbghelp | |
| # - macOS: backtrace+dladdr | |
| if(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux" OR NOT IREE_ENABLE_LIBBACKTRACE) | |
| # Set empty target variable for consumers to use in DEPS. | |
| set(IREE_LIBBACKTRACE_TARGET "" CACHE INTERNAL "libbacktrace target (empty when disabled)") | |
| return() | |
| endif() | |
| # Set target variable for consumers to use in DEPS. | |
| set(IREE_LIBBACKTRACE_TARGET "libbacktrace::libbacktrace" CACHE INTERNAL "libbacktrace target") | |
| include(CheckSymbolExists) | |
| include(FetchContent) | |
| # pthreads is required for pthread_once used in status_stack_trace.c. | |
| find_package(Threads REQUIRED) | |
| # Suppress deprecation warning for FetchContent_Populate (CMake 4.x). | |
| # We use Populate because libbacktrace has no CMakeLists.txt. | |
| if(POLICY CMP0169) | |
| cmake_policy(SET CMP0169 OLD) | |
| endif() | |
| # Pin to a specific commit for reproducibility. | |
| set(LIBBACKTRACE_VERSION "b9e40069c0b47a722286b94eb5231f7f05c08713") | |
| FetchContent_Declare( | |
| libbacktrace_src | |
| GIT_REPOSITORY https://github.com/ianlancetaylor/libbacktrace.git | |
| GIT_TAG ${LIBBACKTRACE_VERSION} | |
| EXCLUDE_FROM_ALL | |
| ) | |
| # Just populate, don't configure (upstream has no CMake). | |
| FetchContent_GetProperties(libbacktrace_src) | |
| if(NOT libbacktrace_src_POPULATED) | |
| FetchContent_Populate(libbacktrace_src) | |
| endif() | |
| set(LIBBACKTRACE_SOURCE_DIR "${libbacktrace_src_SOURCE_DIR}") | |
| # Detect dl_iterate_phdr availability at configure time. | |
| # This is critical for cross-compilation: the check uses the cross-toolchain | |
| # so it correctly detects target capabilities, not host. | |
| # - glibc: always has it | |
| # - musl: has it (with some quirks on older versions) | |
| # - uclibc-ng: depends on configuration | |
| # - newlib/other minimal libc: usually not | |
| set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) | |
| check_symbol_exists(dl_iterate_phdr "link.h" LIBBACKTRACE_HAVE_DL_ITERATE_PHDR) | |
| unset(CMAKE_REQUIRED_DEFINITIONS) | |
| if(LIBBACKTRACE_HAVE_DL_ITERATE_PHDR) | |
| set(LIBBACKTRACE_DL_ITERATE_PHDR_DEF "#define HAVE_DL_ITERATE_PHDR 1") | |
| set(LIBBACKTRACE_LINK_H_DEF "#define HAVE_LINK_H 1") | |
| else() | |
| message(STATUS "libbacktrace: dl_iterate_phdr not found, shared library symbols won't be resolved") | |
| set(LIBBACKTRACE_DL_ITERATE_PHDR_DEF "/* dl_iterate_phdr not available */") | |
| set(LIBBACKTRACE_LINK_H_DEF "/* link.h not available */") | |
| endif() | |
| # Generate config.h with detected features. | |
| # Uses @VAR@ substitution for cross-compilation-safe detection. | |
| configure_file( | |
| ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in | |
| ${LIBBACKTRACE_SOURCE_DIR}/config.h | |
| @ONLY | |
| ) | |
| configure_file( | |
| ${CMAKE_CURRENT_SOURCE_DIR}/backtrace-supported.h | |
| ${LIBBACKTRACE_SOURCE_DIR}/backtrace-supported.h | |
| COPYONLY | |
| ) | |
| # Copy our wrapper header that re-exports backtrace.h. | |
| # This provides a consistent include path for both CMake and Bazel builds, | |
| # allowing status_stack_trace.c to use <iree_libbacktrace.h>. | |
| configure_file( | |
| ${CMAKE_CURRENT_SOURCE_DIR}/iree_libbacktrace.h | |
| ${LIBBACKTRACE_SOURCE_DIR}/iree_libbacktrace.h | |
| COPYONLY | |
| ) | |
| # Source files - include all platforms, let preprocessor handle selection. | |
| # Order matters for archive linking: implementations must come before stubs. | |
| # The linker picks the first symbol definition it finds when resolving from | |
| # an archive, so we list real implementations first and fallback stubs last. | |
| set(LIBBACKTRACE_SOURCES | |
| # Core files (always needed). | |
| ${LIBBACKTRACE_SOURCE_DIR}/atomic.c | |
| ${LIBBACKTRACE_SOURCE_DIR}/dwarf.c | |
| ${LIBBACKTRACE_SOURCE_DIR}/fileline.c | |
| ${LIBBACKTRACE_SOURCE_DIR}/posix.c | |
| ${LIBBACKTRACE_SOURCE_DIR}/print.c | |
| ${LIBBACKTRACE_SOURCE_DIR}/sort.c | |
| ${LIBBACKTRACE_SOURCE_DIR}/state.c | |
| # Unwinding - real implementations before stub. | |
| ${LIBBACKTRACE_SOURCE_DIR}/backtrace.c | |
| ${LIBBACKTRACE_SOURCE_DIR}/simple.c | |
| ${LIBBACKTRACE_SOURCE_DIR}/nounwind.c # Stub, must be after backtrace.c/simple.c. | |
| # Executable format - ELF/Mach-O/PE before unknown stub. | |
| ${LIBBACKTRACE_SOURCE_DIR}/elf.c | |
| ${LIBBACKTRACE_SOURCE_DIR}/macho.c | |
| ${LIBBACKTRACE_SOURCE_DIR}/pecoff.c | |
| ${LIBBACKTRACE_SOURCE_DIR}/unknown.c # Stub, must be after format files. | |
| # File I/O - mmap before read fallback. | |
| ${LIBBACKTRACE_SOURCE_DIR}/mmap.c | |
| ${LIBBACKTRACE_SOURCE_DIR}/mmapio.c | |
| ${LIBBACKTRACE_SOURCE_DIR}/read.c # Fallback, must be after mmapio.c. | |
| ) | |
| # Build libbacktrace as a STATIC library. | |
| # libbacktrace has multiple implementations of the same functions for different | |
| # platforms (e.g., elf.c vs pecoff.c vs macho.c). The autotools build selects | |
| # files at configure time, but we include all files and rely on archive linking | |
| # semantics - the linker only pulls in object files needed to resolve symbols, | |
| # so the first implementation wins and duplicates are ignored. | |
| add_library(libbacktrace_impl STATIC ${LIBBACKTRACE_SOURCES}) | |
| target_include_directories(libbacktrace_impl | |
| PUBLIC $<BUILD_INTERFACE:${LIBBACKTRACE_SOURCE_DIR}> | |
| ) | |
| target_compile_definitions(libbacktrace_impl | |
| PRIVATE _GNU_SOURCE # Required for dl_iterate_phdr on glibc. | |
| ) | |
| # Suppress warnings in third-party code. | |
| target_compile_options(libbacktrace_impl | |
| PRIVATE | |
| -Wno-unused-parameter | |
| -Wno-cast-function-type | |
| ) | |
| # Create libbacktrace::libbacktrace as an IMPORTED INTERFACE library. | |
| # IMPORTED libraries don't get tracked for export, which is what we want | |
| # since libbacktrace is only used internally during build. | |
| # Threads::Threads is needed for pthread_once used in status_stack_trace.c. | |
| # CMAKE_DL_LIBS is needed for dladdr used in status_stack_trace.c. | |
| # On modern glibc (2.34+), dladdr is in libc, but older systems need libdl. | |
| add_library(libbacktrace_libbacktrace INTERFACE IMPORTED GLOBAL) | |
| target_link_libraries(libbacktrace_libbacktrace | |
| INTERFACE | |
| libbacktrace_impl | |
| Threads::Threads | |
| ${CMAKE_DL_LIBS} | |
| ) | |
| target_include_directories(libbacktrace_libbacktrace | |
| INTERFACE $<BUILD_INTERFACE:${LIBBACKTRACE_SOURCE_DIR}> | |
| ) | |
| target_compile_definitions(libbacktrace_libbacktrace | |
| INTERFACE IREE_HAVE_LIBBACKTRACE=1 | |
| ) | |
| add_library(libbacktrace::libbacktrace ALIAS libbacktrace_libbacktrace) |