blob: 43ee7d624ff24a1ecd021ba2d3b1977d844ffb17 [file] [log] [blame]
# 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)