Skip to content

Commit

Permalink
libunwind: add new submodule
Browse files Browse the repository at this point in the history
Investigation of GNU libunwind problems on the aarch64-linux-gnu
platform drive us to the conclusion that libunwind-1.2.1 provided by
major distribution packages is broken. Not to mention that its test
suite fails with SEGFAULTs.

Last but not least, some distributions, e.g. CentOS 8 (see tarantool#4611) do
not provide a libunwind package.

Hence, bundle libunwind: bundling is enabled by default on all
platforms, except for macOS — a system package can be used if its
version is greater or equal than 1.3.0 (minimal version that does not
seem to be broken on aarch64-linux-gnu).

* Add new submodule: bump it to current master.
* Refactor libunwind package search logic out of compiler.cmake.
* Add CMake script for building bundled libunwind.
* Add CMake script for extracting version of libunwind.
* Re-enable backtrace for all RHEL distributions by default.
* Remove libunwind from static build.

Needed for tarantool#4002
Closes tarantool#4611

NO_DOC=build system
NO_TEST=build system
  • Loading branch information
CuriousGeorgiy authored and locker committed Mar 18, 2022
1 parent dbaf03d commit 7dc9fe4
Show file tree
Hide file tree
Showing 12 changed files with 298 additions and 149 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,7 @@
[submodule "third_party/nghttp2"]
path = third_party/nghttp2
url = https://github.com/tarantool/nghttp2.git
[submodule "third_party/libunwind"]
path = third_party/libunwind
url = https://github.com/tarantool/libunwind.git
branch = libunwind-1.6.2-tarantool
44 changes: 43 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,47 @@ include(BuildMisc)
libmisc_build()
add_dependencies(build_bundled_libs misc)

#
# libunwind
#

if(ENABLE_BACKTRACE)
if(NOT HAVE_FORCE_ALIGN_ARG_POINTER_ATTR)
message(SEND_ERROR "backtrace feature requires \
`force_align_arg_pointer` function attribute \
support from C/C++ compiler")
endif()

if(NOT HAVE_CFI_ASM)
message(SEND_ERROR "backtrace feature requires CFI assembly support \
from C/C++ compiler")
endif()

if(ENABLE_BUNDLED_LIBUNWIND)
if(APPLE)
message(SEND_ERROR "libunwind does not support macOS")
endif()
if(NOT HAVE_STDATOMIC_H)
message(SEND_ERROR "building bundled libunwind requires stdatomic.h \
support from C compiler")
endif()

include(BuildLibUnwind)
libunwind_build()
add_dependencies(build_bundled_libs
bundled-libunwind
bundled-libunwind-platform)
else()
find_package(LibUnwind MODULE REQUIRED)
endif()
if(NOT APPLE AND NOT ENABLE_BUNDLED_LIBUNWIND AND
LIBUNWIND_VERSION VERSION_LESS "1.3" AND
${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
message(SEND_ERROR "versions of libunwind earlier than 1.3.0 are \
broken on AARCH64 architecture")
endif()
endif()

# cpack config. called package.cmake to avoid
# conflicts with the global CPack.cmake (On MacOS X
# file names are case-insensitive)
Expand Down Expand Up @@ -690,7 +731,8 @@ set(options PACKAGE VERSION BUILD C_COMPILER CXX_COMPILER C_FLAGS CXX_FLAGS
ENABLE_DIST
ENABLE_BUNDLED_LIBCURL
ENABLE_BUNDLED_LIBYAML
ENABLE_BUNDLED_MSGPUCK)
ENABLE_BUNDLED_MSGPUCK
ENABLE_BUNDLED_LIBUNWIND)
foreach(option IN LISTS options)
if (NOT DEFINED ${option})
set(value "${TARANTOOL_${option}}")
Expand Down
8 changes: 8 additions & 0 deletions changelogs/unreleased/add-libunwind-submodule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## feature/build

* Added bundling of _GNU libunwind_ to support backtrace feature on
_AARCH64_ architecture and distributives that don't provide _libunwind_
package.
* Re-enabled backtrace feature for all _RHEL_ distributions by default, except
for _AARCH64_ architecture and ancient _GCC_ versions, which lack compiler
features required for backtrace (gh-4611).
98 changes: 98 additions & 0 deletions cmake/BuildLibUnwind.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#[========================================================================[.rst:
libunwind_build
--------
Builds the libunwind library.
Result Variables
^^^^^^^^^^^^^^^^
``LIBUNWIND_INCLUDE_DIR``
Include directory needed to use libunwind.
``LIBUNWIND_LIBRARIES``
Libraries needed to link to libunwind.
Cache Variables
^^^^^^^^^^^^^^^
``LIBUNWIND_INCLUDE_DIR``
The directory containing ``libunwind.h``.
``LIBUNWIND_LIBRARIES``
The paths to the libunwind libraries.
#]========================================================================]

macro(libunwind_build)
set(LIBUNWIND_SOURCE_DIR ${PROJECT_SOURCE_DIR}/third_party/libunwind)
set(LIBUNWIND_BUILD_DIR ${PROJECT_BINARY_DIR}/build/libunwind)
set(LIBUNWIND_BINARY_DIR ${LIBUNWIND_BUILD_DIR}/work)
set(LIBUNWIND_INSTALL_DIR ${LIBUNWIND_BUILD_DIR}/dest)

include(ExternalProject)
ExternalProject_Add(bundled-libunwind-project
TMP_DIR ${LIBUNWIND_BUILD_DIR}/tmp
STAMP_DIR ${LIBUNWIND_BUILD_DIR}/stamp
SOURCE_DIR ${LIBUNWIND_SOURCE_DIR}
BINARY_DIR ${LIBUNWIND_BINARY_DIR}
INSTALL_DIR ${LIBUNWIND_INSTALL_DIR}

DOWNLOAD_COMMAND ""

CONFIGURE_COMMAND
<SOURCE_DIR>/configure
CC=${CMAKE_C_COMPILER}
CXX=${CMAKE_CXX_COMPILER}
--prefix=<INSTALL_DIR>
# Bundled libraries are linked statically.
--disable-shared
# Ditto.
--enable-static
# See https://github.com/libunwind/libunwind/blob/e07b43c02d5cf1ea060c018fdf2e2ad34b7c7d80/configure.ac#L122-L125.
--disable-coredump
# See https://github.com/libunwind/libunwind/blob/e07b43c02d5cf1ea060c018fdf2e2ad34b7c7d80/configure.ac#L130-L133.
--disable-ptrace
# See https://github.com/libunwind/libunwind/blob/e07b43c02d5cf1ea060c018fdf2e2ad34b7c7d80/configure.ac#L138-L141.
--disable-setjmp
# See https://github.com/libunwind/libunwind/blob/e07b43c02d5cf1ea060c018fdf2e2ad34b7c7d80/configure.ac#L143-L145
--disable-documentation
# See https://github.com/libunwind/libunwind/blob/e07b43c02d5cf1ea060c018fdf2e2ad34b7c7d80/configure.ac#L147-L149
--disable-tests
# By default libunwind provides a weak alias to
# `backtrace` function: this can lead to a conflict with
# glibc's `backtrace`, see https://github.com/libunwind/libunwind/blob/e07b43c02d5cf1ea060c018fdf2e2ad34b7c7d80/configure.ac#L151-L153
--disable-weak-backtrace
# See https://github.com/libunwind/libunwind/blob/e07b43c02d5cf1ea060c018fdf2e2ad34b7c7d80/configure.ac#L155-L157
--disable-unwind-header
# See https://github.com/libunwind/libunwind/blob/e07b43c02d5cf1ea060c018fdf2e2ad34b7c7d80/configure.ac#L302-L317
--disable-minidebuginfo
# See https://github.com/libunwind/libunwind/blob/e07b43c02d5cf1ea060c018fdf2e2ad34b7c7d80/configure.ac#L319-L334
--disable-zlibdebuginfo

LOG_CONFIGURE TRUE
LOG_BUILD TRUE
LOG_INSTALL TRUE
LOG_MERGED_STDOUTERR TRUE
LOG_OUTPUT_ON_FAILURE TRUE

EXCLUDE_FROM_ALL)

add_library(bundled-libunwind STATIC IMPORTED GLOBAL)
set_target_properties(bundled-libunwind PROPERTIES
IMPORTED_LOCATION
${LIBUNWIND_INSTALL_DIR}/lib/libunwind.a)
add_dependencies(bundled-libunwind bundled-libunwind-project)

add_library(bundled-libunwind-platform STATIC IMPORTED GLOBAL)
set_target_properties(bundled-libunwind-platform PROPERTIES
IMPORTED_LOCATION
${LIBUNWIND_INSTALL_DIR}/lib/libunwind-${CMAKE_SYSTEM_PROCESSOR}.a)
add_dependencies(bundled-libunwind-platform bundled-libunwind-project)

set(LIBUNWIND_INCLUDE_DIR ${LIBUNWIND_INSTALL_DIR}/include)
set(LIBUNWIND_LIBRARIES
${LIBUNWIND_INSTALL_DIR}/lib/libunwind-${CMAKE_SYSTEM_PROCESSOR}.a
${LIBUNWIND_INSTALL_DIR}/lib/libunwind.a)

message(STATUS "Using bundled libunwind")

unset(LIBUNWIND_SOURCE_DIR)
unset(LIBUNWIND_BUILD_DIR)
unset(LIBUNWIND_BINARY_DIR)
unset(LIBUNWIND_INSTALL_DIR)
endmacro()
86 changes: 86 additions & 0 deletions cmake/FindLibUnwind.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#[========================================================================[.rst:
FindLibUnwind
--------
Finds the libunwind library.
Result Variables
^^^^^^^^^^^^^^^^
``LIBUNWIND_FOUND``
True if the system has the libunwind library.
``LIBUNWIND_VERSION``
The version of the libunwind library which was found.
``LIBUNWIND_INCLUDE_DIR``
Include directory needed to use libunwind.
``LIBUNWIND_LIBRARIES``
Libraries needed to link to libunwind.
Cache Variables
^^^^^^^^^^^^^^^
``LIBUNWIND_INCLUDE_DIR``
The directory containing ``libunwind.h``.
``LIBUNWIND_LIBRARIES``
The paths to the libunwind libraries.
#]========================================================================]

include(FindPackageHandleStandardArgs)
include(GetLibUnwindVersion)

find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBUNWIND QUIET libunwind)

find_path(LIBUNWIND_INCLUDE_DIR libunwind.h ${PC_LIBUNWIND_INCLUDE_DIRS})
if(LIBUNWIND_INCLUDE_DIR)
include_directories(${LIBUNWIND_INCLUDE_DIR})
endif()

if(BUILD_STATIC AND NOT APPLE)
set(LIBUNWIND_LIBRARY_NAME libunwind.a)
else()
# Only a dynamic version of libunwind is available on macOS: also, we
# should link against the umbrella framework `System` — otherwise `ld` will
# complain that it cannot link directly with libunwind.tbd.
set(LIBUNWIND_LIBRARY_NAME System unwind)
endif()
find_library(LIBUNWIND_LIBRARY NAMES ${LIBUNWIND_LIBRARY_NAME}
PATHS ${PC_LIBUNWIND_LIBRARY_DIRS})

if(APPLE)
set(LIBUNWIND_LIBRARIES ${LIBUNWIND_LIBRARY})
else()
if(BUILD_STATIC)
set(LIBUNWIND_PLATFORM_LIBRARY_NAME
"libunwind-${CMAKE_SYSTEM_PROCESSOR}.a")
else()
set(LIBUNWIND_PLATFORM_LIBRARY_NAME
"unwind-${CMAKE_SYSTEM_PROCESSOR}")
endif()
find_library(LIBUNWIND_PLATFORM_LIBRARY ${LIBUNWIND_PLATFORM_LIBRARY_NAME}
${PC_LIBUNWIND_LIBRARY_DIRS})
set(LIBUNWIND_LIBRARIES ${LIBUNWIND_LIBRARY} ${LIBUNWIND_PLATFORM_LIBRARY})
endif()

if(BUILD_STATIC)
# libunwind could have been built with liblzma dependency:
# https://github.com/libunwind/libunwind/blob/4feb1152d1c4aaafbb2d504dbe34c6db5b6fe9f2/configure.ac#L302-L317
pkg_check_modules(PC_LIBLZMA QUIET liblzma)
find_library(LIBLZMA_LIBRARY liblzma.a ${PC_LIBLZMA_LIBRARY_DIRS})
if(NOT LIBLZMA_LIBRARY STREQUAL "LIBLZMA_LIBRARY-NOTFOUND")
message(STATUS "liblzma found")
set(LIBUNWIND_LIBRARIES ${LIBUNWIND_LIBRARIES} ${LIBLZMA_LIBRARY})
endif()
# Ditto,
# https://github.com/libunwind/libunwind/blob/4feb1152d1c4aaafbb2d504dbe34c6db5b6fe9f2/configure.ac#L319-L334
set(LIBUNWIND_LIBRARIES ${LIBUNWIND_LIBRARIES} ZLIB::ZLIB)
endif()

if(PC_LIBUNWIND_VERSION)
set(LIBUNWIND_VERSION ${PC_LIBUNWIND_VERSION})
else()
GetLibUnwindVersion(LIBUNWIND_VERSION)
endif()

find_package_handle_standard_args(GetLIBUNWINDVersion.cmake
VERSION_VAR LIBUNWIND_VERSION
REQUIRED_VARS LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES)

mark_as_advanced(LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES)
12 changes: 12 additions & 0 deletions cmake/GetLibUnwindVersion.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
function(GetLibUnwindVersion _LIBUNWIND_VERSION)
set(_LIBUNWIND_VERSION_HEADER "${LIBUNWIND_INCLUDE_DIR}/libunwind-common.h")
if(LIBUNWIND_LIBRARY AND EXISTS ${_LIBUNWIND_VERSION_HEADER})
file(READ ${_LIBUNWIND_VERSION_HEADER}
_LIBUNWIND_VERSION_HEADER_CONTENTS)
string(REGEX MATCH
"#define UNW_VERSION_MAJOR[ \t]+([0-9]+)\n#define UNW_VERSION_MINOR[ \t]+([0-9]+)"
_VERSION_REGEX "${_LIBUNWIND_VERSION_HEADER_CONTENTS}")
set(${_LIBUNWIND_VERSION} "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}"
PARENT_SCOPE)
endif()
endfunction()
101 changes: 31 additions & 70 deletions cmake/compiler.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -116,89 +116,50 @@ set (CMAKE_CXX_FLAGS_RELWITHDEBINFO

unset(CC_DEBUG_OPT)

message(STATUS "Looking for libunwind.h")
find_path(UNWIND_INCLUDE_DIR libunwind.h)
message(STATUS "Looking for libunwind.h - ${UNWIND_INCLUDE_DIR}")

if (UNWIND_INCLUDE_DIR)
include_directories(${UNWIND_INCLUDE_DIR})
endif()

set(CMAKE_REQUIRED_INCLUDES ${UNWIND_INCLUDE_DIR})
check_include_file(libunwind.h HAVE_LIBUNWIND_H)
set(CMAKE_REQUIRED_INCLUDES "")

if(BUILD_STATIC AND NOT TARGET_OS_DARWIN)
set(UNWIND_LIB_NAME libunwind.a)
else()
# libunwind can't be compiled on macOS.
# But there exists libunwind.dylib as a part of MacOSSDK
set(UNWIND_LIB_NAME unwind)
endif()
find_library(UNWIND_LIBRARY PATH_SUFFIXES system NAMES ${UNWIND_LIB_NAME})

# Disabled backtraces support on FreeBSD by default, because of
# gh-4278.
# Disabled backtraces support on arm64 by default, because of
# gh-6272, gh-6060 and gh-6222.
check_c_source_compiles(
"
#if defined(__x86_64__) && !__has_attribute(force_align_arg_pointer)
#error
#endif /* defined(__x86_64__) &&
!__has_attribute(force_align_arg_pointer) */
int main(){}
" HAVE_FORCE_ALIGN_ARG_POINTER_ATTR)
check_c_source_compiles(
"
#if !defined(__clang__) /* clang supports CFI assembly by default */ && \
(!defined(__GNUC__) || !defined(__GCC_HAVE_DWARF2_CFI_ASM))
#error
#endif /* !defined(__clang__) && (!defined(__GNUC__) ||
!defined(__GCC_HAVE_DWARF2_CFI_ASM)) */
int main(){}
" HAVE_CFI_ASM)
set(ENABLE_BACKTRACE_DEFAULT OFF)
if (NOT TARGET_OS_FREEBSD AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "arm*" AND
if(NOT TARGET_OS_FREEBSD AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "arm*" AND
NOT CMAKE_SYSTEM_PROCESSOR MATCHES "aarch*" AND
NOT CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "arm*" AND
NOT CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch*" AND
UNWIND_LIBRARY AND HAVE_LIBUNWIND_H)
HAVE_FORCE_ALIGN_ARG_POINTER_ATTR AND HAVE_CFI_ASM)
set(ENABLE_BACKTRACE_DEFAULT ON)
endif()

option(ENABLE_BACKTRACE "Enable output of fiber backtrace information in
'fiber.info()' command." ${ENABLE_BACKTRACE_DEFAULT})
option(ENABLE_BACKTRACE "Enable output of fiber backtrace information in \
'fiber.info()' command."
${ENABLE_BACKTRACE_DEFAULT})

if (ENABLE_BACKTRACE)
# unwind is required
if (NOT (UNWIND_LIBRARY AND HAVE_LIBUNWIND_H))
message (FATAL_ERROR "ENABLE_BACKTRACE option is set but unwind "
"library is not found")
endif()
if (TARGET_OS_DARWIN)
set (UNWIND_LIBRARIES ${UNWIND_LIBRARY})
else()
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR
CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
if(BUILD_STATIC)
set(UNWIND_PLATFORM_LIB_NAME "libunwind-${CMAKE_SYSTEM_PROCESSOR}.a")
else()
set(UNWIND_PLATFORM_LIB_NAME "unwind-${CMAKE_SYSTEM_PROCESSOR}")
endif()
elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "i686")
if(BUILD_STATIC)
set(UNWIND_PLATFORM_LIB_NAME "libunwind-x86.a")
else()
set(UNWIND_PLATFORM_LIB_NAME "unwind-x86")
endif()
elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "arm*")
if(BUILD_STATIC)
set(UNWIND_PLATFORM_LIB_NAME "libunwind-arm.a")
else()
set(UNWIND_PLATFORM_LIB_NAME "unwind-arm")
endif()
endif()
find_library(UNWIND_PLATFORM_LIBRARY PATH_SUFFIXES system
NAMES ${UNWIND_PLATFORM_LIB_NAME})
set(UNWIND_LIBRARIES ${UNWIND_PLATFORM_LIBRARY} ${UNWIND_LIBRARY})
endif()
if (BUILD_STATIC)
# some versions of libunwind need liblzma, and we don't use pkg-config
# so we just look whether liblzma is installed, and add it if it is.
# It might not be actually needed, but doesn't hurt if it is not.
# We don't need any headers, just the lib, as it's privately needed.
find_library(LZMA_LIBRARY PATH_SUFFIXES system NAMES liblzma.a)
if (NOT LZMA_LIBRARY STREQUAL "LZMA_LIBRARY-NOTFOUND")
message(STATUS "liblzma found")
set(UNWIND_LIBRARIES ${UNWIND_LIBRARIES} ${LZMA_LIBRARY})
endif()
endif()
find_package_message(UNWIND_LIBRARIES "Found unwind" "${UNWIND_LIBRARIES}")
check_include_file(stdatomic.h HAVE_STDATOMIC_H)
set(ENABLE_BUNDLED_LIBUNWIND_DEFAULT ON)
if(TARGET_OS_DARWIN OR NOT HAVE_STDATOMIC_H OR
NOT HAVE_FORCE_ALIGN_ARG_POINTER_ATTR)
set(ENABLE_BUNDLED_LIBUNWIND_DEFAULT OFF)
endif()
option(ENABLE_BUNDLED_LIBUNWIND "Bundled libunwind will be built"
${ENABLE_BUNDLED_LIBUNWIND_DEFAULT})

# On macOS there is no '-static-libstdc++' flag and it's use will
# raise following error:
Expand Down
Loading

0 comments on commit 7dc9fe4

Please sign in to comment.