Browse Source

enable libunwind in static builds (#19764)

* enable libunwind in static builds

* add libunwind and backtrace to buildinfo

* add linunwind to alpine packages

* add -dev packages

* add remove libunwind binary from the packages

* Vendor libunwind in static builds instead of using a copy from the build environment.

This is required to ensure that the C++ exception handling functionality
in libunwind is _disabled_, because it does not play nice with static
linking when using C++ with exception handling support enabled.

* Remove changes from local testing.

* Fix cross architecture builds.

* Disable libunwind on 64-bit POWER builds.

musl libc does not include functions that are required to build
libunwind for this platform, so just disable it there for now.

---------

Co-authored-by: Austin S. Hemmelgarn <austin@netdata.cloud>
Costa Tsaousis 6 days ago
parent
commit
e90f3f4e22

+ 13 - 5
CMakeLists.txt

@@ -2263,16 +2263,24 @@ if(ENABLE_LIBUNWIND)
   if(TARGET PkgConfig::LIBUNWIND)
   if(TARGET PkgConfig::LIBUNWIND)
     set(HAVE_LIBUNWIND On)
     set(HAVE_LIBUNWIND On)
 
 
+    if(STATIC_BUILD)
+      set(unwind_prefix /libunwind-static/lib/libunwind-)
+      set(suffix ${CMAKE_STATIC_LIBRARY_SUFFIX})
+    else()
+      set(unwind_prefix -lunwind-)
+      set(suffix "")
+    endif()
+
     if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(amd64)")
     if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(amd64)")
-      target_link_libraries(libnetdata PUBLIC PkgConfig::LIBUNWIND -lunwind-x86_64)
+      target_link_libraries(libnetdata PUBLIC PkgConfig::LIBUNWIND ${unwind_prefix}x86_64${suffix})
     elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i?.86")
     elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i?.86")
-      target_link_libraries(libnetdata PUBLIC PkgConfig::LIBUNWIND -lunwind-x86)
+      target_link_libraries(libnetdata PUBLIC PkgConfig::LIBUNWIND ${unwind_prefix}x86${suffix})
     elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm64)|(aarch64)")
     elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm64)|(aarch64)")
-      target_link_libraries(libnetdata PUBLIC PkgConfig::LIBUNWIND -lunwind-aarch64)
+      target_link_libraries(libnetdata PUBLIC PkgConfig::LIBUNWIND ${unwind_prefix}aarch64${suffix})
     elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
     elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
-      target_link_libraries(libnetdata PUBLIC PkgConfig::LIBUNWIND -lunwind-arm)
+      target_link_libraries(libnetdata PUBLIC PkgConfig::LIBUNWIND ${unwind_prefix}arm${suffix})
     elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "p(ower)?pc64")
     elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "p(ower)?pc64")
-      target_link_libraries(libnetdata PUBLIC PkgConfig::LIBUNWIND -lunwind-ppc64)
+      target_link_libraries(libnetdata PUBLIC PkgConfig::LIBUNWIND ${unwind_prefix}ppc64${suffix})
     else()
     else()
       message(WARNING "Unknown architecture ${CMAKE_SYSTEM_PROCESSOR} for libunwind. Stack traces may not work.")
       message(WARNING "Unknown architecture ${CMAKE_SYSTEM_PROCESSOR} for libunwind. Stack traces may not work.")
       target_link_libraries(libnetdata PUBLIC PkgConfig::LIBUNWIND)
       target_link_libraries(libnetdata PUBLIC PkgConfig::LIBUNWIND)

+ 2 - 0
packaging/makeself/bundled-packages.version

@@ -3,6 +3,8 @@ PACKAGES=("OPENSSL" "CURL" "BASH" "IOPING" "LIBNETFILTER_ACT")
 SOURCE_TYPES=("GH_REPO_CLONE" "GH_REPO_CLONE" "DW_TARBALL" "GH_REPO_SOURCE" "DW_TARBALL")
 SOURCE_TYPES=("GH_REPO_CLONE" "GH_REPO_CLONE" "DW_TARBALL" "GH_REPO_SOURCE" "DW_TARBALL")
 OPENSSL_VERSION="openssl-3.4.0"
 OPENSSL_VERSION="openssl-3.4.0"
 OPENSSL_SOURCE="https://github.com/openssl/openssl"
 OPENSSL_SOURCE="https://github.com/openssl/openssl"
+LIBUNWIND_VERSION="177deb5f89c5d792c9618db54fdcebd260e271e8" # Should be updated to a stable version once https://github.com/libunwind/libunwind/issues/742 is fixed.
+LIBUNWIND_SOURCE="https://github.com/libunwind/libunwind"
 CURL_VERSION="curl-8_11_1"
 CURL_VERSION="curl-8_11_1"
 CURL_SOURCE="https://github.com/curl/curl"
 CURL_SOURCE="https://github.com/curl/curl"
 BASH_VERSION="5.2.37"
 BASH_VERSION="5.2.37"

+ 3 - 2
packaging/makeself/install-alpine-packages.sh

@@ -32,6 +32,7 @@ apk add --no-cache -U \
   lz4-static \
   lz4-static \
   make \
   make \
   ncurses \
   ncurses \
+  ncurses-dev \
   netcat-openbsd \
   netcat-openbsd \
   openssh \
   openssh \
   pkgconfig \
   pkgconfig \
@@ -42,5 +43,5 @@ apk add --no-cache -U \
   wget \
   wget \
   xz \
   xz \
   zlib-dev \
   zlib-dev \
-  zlib-static ||
-  exit 1
+  zlib-static \
+  || exit 1

+ 59 - 0
packaging/makeself/jobs/20-libunwind.install.sh

@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# Can’t do libunwind on ppc64le with musl, so skip it.
+[ "${BUILDARCH}" = "ppc64le" ] && exit 0
+
+# shellcheck source=packaging/makeself/functions.sh
+. "$(dirname "${0}")/../functions.sh" "${@}" || exit 1
+# Source of truth for all the packages we bundle in static builds
+. "$(dirname "${0}")/../bundled-packages.version"
+# shellcheck disable=SC2015
+[ "${GITHUB_ACTIONS}" = "true" ] && echo "::group::Building libunwind" || true
+
+export CFLAGS="${TUNING_FLAGS} -fno-lto -pipe"
+export CXXFLAGS="${CFLAGS}"
+export LDFLAGS="-static"
+export PKG_CONFIG="pkg-config --static"
+
+if [ -d "${NETDATA_MAKESELF_PATH}/tmp/libunwind" ]; then
+  rm -rf "${NETDATA_MAKESELF_PATH}/tmp/libunwind"
+fi
+
+cache="${NETDATA_SOURCE_PATH}/artifacts/cache/${BUILDARCH}/libunwind"
+
+if [ -d "${cache}" ]; then
+  echo "Found cached copy of build directory for libunwind, using it."
+  cp -a "${cache}/libunwind" "${NETDATA_MAKESELF_PATH}/tmp/"
+  CACHE_HIT=1
+else
+  echo "No cached copy of build directory for libunwind found, fetching sources instead."
+  run git clone "${LIBUNWIND_SOURCE}" "${NETDATA_MAKESELF_PATH}/tmp/libunwind"
+  cd "${NETDATA_MAKESELF_PATH}/tmp/libunwind" && run git checkout "${LIBUNWIND_VERSION}"
+  CACHE_HIT=0
+fi
+
+cd "${NETDATA_MAKESELF_PATH}/tmp/libunwind" || exit 1
+
+if [ "${CACHE_HIT:-0}" -eq 0 ]; then
+  run autoreconf -ivf
+
+  run ./configure \
+    --prefix=/libunwind-static \
+    --build="$(gcc -dumpmachine)" \
+    --disable-cxx-exceptions \
+    --disable-documentation \
+    --disable-tests \
+    --disable-shared \
+    --enable-static \
+    --disable-dependency-tracking
+
+  run make -j "$(nproc)"
+fi
+
+run make -j "$(nproc)" install
+
+store_cache libunwind "${NETDATA_MAKESELF_PATH}/tmp/libunwind"
+
+# shellcheck disable=SC2015
+[ "${GITHUB_ACTIONS}" = "true" ] && echo "::endgroup::" || true

+ 5 - 4
packaging/makeself/jobs/70-netdata-git.install.sh

@@ -7,12 +7,12 @@
 cd "${NETDATA_SOURCE_PATH}" || exit 1
 cd "${NETDATA_SOURCE_PATH}" || exit 1
 
 
 if [ "${NETDATA_BUILD_WITH_DEBUG}" -eq 0 ]; then
 if [ "${NETDATA_BUILD_WITH_DEBUG}" -eq 0 ]; then
-  export CFLAGS="${TUNING_FLAGS} -ffunction-sections -fdata-sections -static -O2 -funroll-loops -DNETDATA_STATIC_BUILD=1 -I/openssl-static/include -I/libnetfilter-acct-static/include/libnetfilter_acct -I/curl-local/include/curl -I/usr/include/libmnl -pipe"
+  export CFLAGS="${TUNING_FLAGS} -ffunction-sections -fdata-sections -static -O2 -funroll-loops -DNETDATA_STATIC_BUILD=1 -I/libunwind-static/include -I/openssl-static/include -I/libnetfilter-acct-static/include/libnetfilter_acct -I/curl-local/include/curl -I/usr/include/libmnl -pipe"
 else
 else
-  export CFLAGS="${TUNING_FLAGS} -static -O1 -pipe -ggdb -Wall -Wextra -Wformat-signedness -DNETDATA_STATIC_BUILD=1 -DNETDATA_INTERNAL_CHECKS=1 -I/openssl-static/include -I/libnetfilter-acct-static/include/libnetfilter_acct -I/curl-local/include/curl -I/usr/include/libmnl"
+  export CFLAGS="${TUNING_FLAGS} -static -O1 -pipe -ggdb -Wall -Wextra -Wformat-signedness -DNETDATA_STATIC_BUILD=1 -DNETDATA_INTERNAL_CHECKS=1 -I/libunwind-static/include -I/openssl-static/include -I/libnetfilter-acct-static/include/libnetfilter_acct -I/curl-local/include/curl -I/usr/include/libmnl"
 fi
 fi
 
 
-export LDFLAGS="-Wl,--gc-sections -static -L/openssl-static/lib64 -L/libnetfilter-acct-static/lib -lnetfilter_acct -L/usr/lib -lmnl -L/usr/lib -lzstd -L/curl-local/lib"
+export LDFLAGS="-Wl,--gc-sections -static -L/libuwnind-static/lib -L/openssl-static/lib64 -L/libnetfilter-acct-static/lib -lnetfilter_acct -L/usr/lib -lmnl -L/usr/lib -lzstd -L/curl-local/lib"
 
 
 # We export this to 'yes', installer sets this to .environment.
 # We export this to 'yes', installer sets this to .environment.
 # The updater consumes this one, so that it can tell whether it should update a static install or a non-static one
 # The updater consumes this one, so that it can tell whether it should update a static install or a non-static one
@@ -21,11 +21,12 @@ export IS_NETDATA_STATIC_BINARY="yes"
 # Set eBPF LIBC to "static" to bundle the `-static` variant of the kernel-collector
 # Set eBPF LIBC to "static" to bundle the `-static` variant of the kernel-collector
 export EBPF_LIBC="static"
 export EBPF_LIBC="static"
 export PKG_CONFIG="pkg-config --static"
 export PKG_CONFIG="pkg-config --static"
-export PKG_CONFIG_PATH="/openssl-static/lib64/pkgconfig:/libnetfilter-acct-static/lib/pkgconfig:/usr/lib/pkgconfig:/curl-local/lib/pkgconfig"
+export PKG_CONFIG_PATH="/libunwind-static/lib/pkgconfig:/openssl-static/lib64/pkgconfig:/libnetfilter-acct-static/lib/pkgconfig:/usr/lib/pkgconfig:/curl-local/lib/pkgconfig"
 
 
 # Set correct CMake flags for building against non-System OpenSSL
 # Set correct CMake flags for building against non-System OpenSSL
 # See: https://github.com/warmcat/libwebsockets/blob/master/READMEs/README.build.md
 # See: https://github.com/warmcat/libwebsockets/blob/master/READMEs/README.build.md
 export CMAKE_FLAGS="-DOPENSSL_ROOT_DIR=/openssl-static -DOPENSSL_LIBRARIES=/openssl-static/lib64 -DCMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE=/openssl-static -DLWS_OPENSSL_INCLUDE_DIRS=/openssl-static/include -DLWS_OPENSSL_LIBRARIES=/openssl-static/lib64/libssl.a;/openssl-static/lib64/libcrypto.a"
 export CMAKE_FLAGS="-DOPENSSL_ROOT_DIR=/openssl-static -DOPENSSL_LIBRARIES=/openssl-static/lib64 -DCMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE=/openssl-static -DLWS_OPENSSL_INCLUDE_DIRS=/openssl-static/include -DLWS_OPENSSL_LIBRARIES=/openssl-static/lib64/libssl.a;/openssl-static/lib64/libcrypto.a"
+[ "${BUILDARCH}" != "ppc64le" ] && export NETDATA_CMAKE_OPTIONS="-DENABLE_LIBUNWIND=ON"
 
 
 run ./netdata-installer.sh \
 run ./netdata-installer.sh \
   --install-prefix "${NETDATA_INSTALL_PARENT}" \
   --install-prefix "${NETDATA_INSTALL_PARENT}" \

+ 23 - 0
src/daemon/buildinfo.c

@@ -78,6 +78,8 @@ typedef enum __attribute__((packed)) {
     BIB_LIB_LIBCRYPTO,
     BIB_LIB_LIBCRYPTO,
     BIB_LIB_LIBYAML,
     BIB_LIB_LIBYAML,
     BIB_LIB_LIBMNL,
     BIB_LIB_LIBMNL,
+    BIB_LIB_LIBUNWIND,
+    BIB_LIB_BACKTRACE,
     BIB_PLUGIN_APPS,
     BIB_PLUGIN_APPS,
     BIB_PLUGIN_LINUX_CGROUPS,
     BIB_PLUGIN_LINUX_CGROUPS,
     BIB_PLUGIN_LINUX_CGROUP_NETWORK,
     BIB_PLUGIN_LINUX_CGROUP_NETWORK,
@@ -726,6 +728,22 @@ static struct {
             .json = "libmnl",
             .json = "libmnl",
             .value = NULL,
             .value = NULL,
         },
         },
+        [BIB_LIB_LIBUNWIND] = {
+            .category = BIC_LIBS,
+            .type = BIT_BOOLEAN,
+            .analytics = "libunwind",
+            .print = "libunwind (library for getting stack traces)",
+            .json = "libunwind",
+            .value = NULL,
+        },
+        [BIB_LIB_BACKTRACE] = {
+            .category = BIC_LIBS,
+            .type = BIT_BOOLEAN,
+            .analytics = "backtrace",
+            .print = "backtrace (library for getting stack traces)",
+            .json = "backtrace",
+            .value = NULL,
+        },
         [BIB_PLUGIN_APPS] = {
         [BIB_PLUGIN_APPS] = {
                 .category = BIC_PLUGINS,
                 .category = BIC_PLUGINS,
                 .type = BIT_BOOLEAN,
                 .type = BIT_BOOLEAN,
@@ -1269,6 +1287,11 @@ __attribute__((constructor)) void initialize_build_info(void) {
 #ifdef HAVE_LIBMNL
 #ifdef HAVE_LIBMNL
     build_info_set_status(BIB_LIB_LIBMNL, true);
     build_info_set_status(BIB_LIB_LIBMNL, true);
 #endif
 #endif
+#ifdef HAVE_LIBUNWIND
+    build_info_set_status(BIB_LIB_LIBUNWIND, true);
+#elif defined(HAVE_BACKTRACE)
+    build_info_set_status(BIB_LIB_BACKTRACE, true);
+#endif
 
 
 #ifdef ENABLE_PLUGIN_APPS
 #ifdef ENABLE_PLUGIN_APPS
     build_info_set_status(BIB_PLUGIN_APPS, true);
     build_info_set_status(BIB_PLUGIN_APPS, true);