diff --git a/CHANGELOG.md b/CHANGELOG.md index 7eaef44afb..40cc779973 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - Improve log and metric delivery when telemetry is captured faster than envelopes can be serialized by offloading serialization to an internal thread pool. ([#1946](https://github.com/getsentry/sentry-native/pull/1946)) - Wine: fix OS version detection and cross-compiling Windows builds from Linux. ([#2001](https://github.com/getsentry/sentry-native/pull/2001)) - Destroy condition variables as approriate when no longer needed. ([#2004](https://github.com/getsentry/sentry-native/pull/2004)) +- CMake: `pkg-config` is no longer a hard build requirement. `SENTRY_LIBUNWIND_SYSTEM` and `SENTRY_BREAKPAD_SYSTEM` still prefer the `pkg-config` metadata of the system package, but now fall back to `find_library()`/`find_path()` when the tool or the `.pc` file is missing. The same applies to the exported CMake config, which no longer requires consumers of a static build to have `pkg-config` installed. - Crashpad/Windows: preserve module CodeView UUIDs for minimal PDB70 records with empty PDB filenames. ([#2003](https://github.com/getsentry/sentry-native/pull/2003)) ## 0.16.3 diff --git a/CMakeLists.txt b/CMakeLists.txt index e955145be8..ad90eebe65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -640,6 +640,7 @@ if(WIN32) endif() include(cmake/utils.cmake) +include(cmake/sentry-find-system-library.cmake) if (WIN32 AND SENTRY_BUILD_SHARED_LIBS) sentry_add_version_resource(sentry "Client Library") endif() @@ -705,12 +706,11 @@ endif() if(SENTRY_WITH_LIBUNWIND) if(LINUX) if(SENTRY_LIBUNWIND_SYSTEM) - find_package(PkgConfig REQUIRED) - pkg_check_modules(LIBUNWIND REQUIRED IMPORTED_TARGET libunwind) + sentry_find_libunwind() if(SENTRY_BUILD_SHARED_LIBS) - target_link_libraries(sentry PRIVATE PkgConfig::LIBUNWIND) + target_link_libraries(sentry PRIVATE sentry::libunwind) else() - target_link_libraries(sentry PUBLIC PkgConfig::LIBUNWIND) + target_link_libraries(sentry PUBLIC sentry::libunwind) endif() else() # Use vendored libunwind @@ -802,13 +802,12 @@ elseif(SENTRY_BACKEND_BREAKPAD) option(SENTRY_BREAKPAD_SYSTEM "Use system breakpad" OFF) if(SENTRY_BREAKPAD_SYSTEM) target_compile_definitions(sentry PRIVATE SENTRY_BREAKPAD_SYSTEM) - # system breakpad is using pkg-config, see `external/breakpad/breakpad-client.pc.in` - find_package(PkgConfig REQUIRED) - pkg_check_modules(BREAKPAD REQUIRED IMPORTED_TARGET breakpad-client) + # system breakpad ships pkg-config metadata, see `external/breakpad/breakpad-client.pc.in` + sentry_find_breakpad_client() if(SENTRY_BUILD_SHARED_LIBS) - target_link_libraries(sentry PRIVATE PkgConfig::BREAKPAD) + target_link_libraries(sentry PRIVATE sentry::breakpad-client) else() - target_link_libraries(sentry PUBLIC PkgConfig::BREAKPAD) + target_link_libraries(sentry PUBLIC sentry::breakpad-client) endif() else() add_subdirectory(external) @@ -934,8 +933,8 @@ elseif(SENTRY_BACKEND_NATIVE) if(SENTRY_WITH_LIBUNWIND AND LINUX) if(SENTRY_LIBUNWIND_SYSTEM) - pkg_check_modules(LIBUNWIND_PTRACE REQUIRED IMPORTED_TARGET libunwind-ptrace) - target_link_libraries(sentry-crash PRIVATE PkgConfig::LIBUNWIND PkgConfig::LIBUNWIND_PTRACE) + sentry_find_libunwind_ptrace() + target_link_libraries(sentry-crash PRIVATE sentry::libunwind sentry::libunwind-ptrace) else() # Use unwind_remote for the daemon (includes ptrace accessors # for remote DWARF unwinding of the crashed process) @@ -1018,6 +1017,8 @@ sentry_install( FILES "${PROJECT_BINARY_DIR}/sentry-config.cmake" "${PROJECT_BINARY_DIR}/sentry-config-version.cmake" + # `sentry-config.cmake` recreates the system-library targets for consumers of a static build + "${SENTRY_SOURCE_DIR}/cmake/sentry-find-system-library.cmake" DESTINATION "${CMAKE_INSTALL_CMAKEDIR}") if(WIN32 AND MSVC AND SENTRY_BUILD_SHARED_LIBS) sentry_install(FILES $ diff --git a/README.md b/README.md index d9c63cc171..c895fa592a 100644 --- a/README.md +++ b/README.md @@ -266,8 +266,8 @@ using `cmake -D BUILD_SHARED_LIBS=OFF ..`. This instructs the build system to use system-installed breakpad libraries instead of the in-tree version. - `SENTRY_LIBUNWIND_SYSTEM` (Default: `OFF`, only for Linux): - This instructs the build system to use a system-installed `libunwind` (found via `pkg-config`) instead of the - vendored copy in `vendor/libunwind`. + This instructs the build system to use a system-installed `libunwind` instead of the vendored copy in + `vendor/libunwind`. In contrast to the vendored `libunwind` which is always built as a static archive and either linked into the resulting shared library or colocated with the other static artifacts, with `SENTRY_LIBUNWIND_SYSTEM=ON`, the library @@ -275,6 +275,11 @@ using `cmake -D BUILD_SHARED_LIBS=OFF ..`. controls how the dependency is exposed to consuming CMake projects, not the library type of the system `libunwind` itself. Ensure matching build and target environments when using system packages. + Both `SENTRY_BREAKPAD_SYSTEM` and `SENTRY_LIBUNWIND_SYSTEM` read the `pkg-config` metadata of the system package + when `pkg-config`/`pkgconf` is installed, and fall back to CMake's own `find_library()`/`find_path()` lookup when it + is not, so `pkg-config` is a convenience rather than a build requirement for either option. The only remaining + build-time user of `pkg-config` is the vendored `crashpad`, and only on Linux with `CRASHPAD_ENABLE_STACKTRACE=ON`. + - `SENTRY_TRANSPORT_COMPRESSION` (Default: `OFF`): Adds Gzip transport compression. Requires `zlib`. diff --git a/cmake/sentry-find-system-library.cmake b/cmake/sentry-find-system-library.cmake new file mode 100644 index 0000000000..e0536b5cd9 --- /dev/null +++ b/cmake/sentry-find-system-library.cmake @@ -0,0 +1,104 @@ +# Locates a system library the way CMake's own find modules do: `pkg-config` supplies search hints +# when it happens to be installed, and `find_library()`/`find_path()` do the actual lookup either way. +# See `FindLibinput`, `FindFontconfig` and the other bundled modules that follow the same shape. +# +# The only places sentry-native consults `pkg-config` are the optional `SENTRY_LIBUNWIND_SYSTEM` and +# `SENTRY_BREAKPAD_SYSTEM` code paths, and only on Linux. Requesting it with +# `find_package(PkgConfig REQUIRED)` nevertheless turned the tool into a hard build requirement for +# anyone packaging sentry-native, which is why package managers end up declaring it on every platform, +# including those where it is never invoked. +# +# Defines the imported target `TARGET` on success, and fails through +# `find_package_handle_standard_args()` with the usual "could not find" diagnostic otherwise. +# +# sentry_find_system_library( +# TARGET +# PKG_CONFIG_MODULE +# LIBRARY_NAMES ... +# [HEADER_NAMES
...] +# [HEADER_PATH_SUFFIXES ...]) +function(sentry_find_system_library NAME) + cmake_parse_arguments(SFSL "" "TARGET;PKG_CONFIG_MODULE" + "LIBRARY_NAMES;HEADER_NAMES;HEADER_PATH_SUFFIXES" ${ARGN}) + + if(TARGET "${SFSL_TARGET}") + return() + endif() + + # Hints only. A missing tool or a missing `.pc` file just leaves the hints empty. The guard is + # needed because `pkg_check_modules()` is defined by `FindPkgConfig` itself, so it does not exist + # when that module was never loaded. + find_package(PkgConfig QUIET) + if(PKG_CONFIG_FOUND) + pkg_check_modules(PC_${NAME} QUIET "${SFSL_PKG_CONFIG_MODULE}") + endif() + + set(libraries "") + set(required_vars "") + foreach(library_name IN LISTS SFSL_LIBRARY_NAMES) + string(MAKE_C_IDENTIFIER "${NAME}_${library_name}_LIBRARY" cache_var) + find_library("${cache_var}" NAMES "${library_name}" HINTS ${PC_${NAME}_LIBRARY_DIRS}) + mark_as_advanced("${cache_var}") + list(APPEND libraries "${${cache_var}}") + list(APPEND required_vars "${cache_var}") + endforeach() + + if(SFSL_HEADER_NAMES) + find_path(${NAME}_INCLUDE_DIR + NAMES ${SFSL_HEADER_NAMES} + HINTS ${PC_${NAME}_INCLUDE_DIRS} + PATH_SUFFIXES ${SFSL_HEADER_PATH_SUFFIXES}) + mark_as_advanced(${NAME}_INCLUDE_DIR) + list(APPEND required_vars ${NAME}_INCLUDE_DIR) + endif() + + # These lookups only run once the user has opted into a system library, so a miss is fatal. + # `find_package_handle_standard_args()` reads this to pick the failure mode and the message. + set(${NAME}_FIND_REQUIRED TRUE) + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(${NAME} REQUIRED_VARS ${required_vars}) + + add_library("${SFSL_TARGET}" INTERFACE IMPORTED) + set_target_properties("${SFSL_TARGET}" PROPERTIES INTERFACE_LINK_LIBRARIES "${libraries}") + if(${NAME}_INCLUDE_DIR) + set_target_properties("${SFSL_TARGET}" PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${${NAME}_INCLUDE_DIR}") + endif() + if(PC_${NAME}_CFLAGS_OTHER) + set_target_properties("${SFSL_TARGET}" PROPERTIES + INTERFACE_COMPILE_OPTIONS "${PC_${NAME}_CFLAGS_OTHER}") + endif() +endfunction() + +# The lookups below are shared between the build itself and the installed `sentry-config.cmake`, which +# has to recreate the same imported targets for consumers of a static sentry-native. Keeping them here +# means the two cannot drift. + +function(sentry_find_libunwind) + sentry_find_system_library(SentryLibunwind + TARGET sentry::libunwind + PKG_CONFIG_MODULE libunwind + LIBRARY_NAMES unwind + HEADER_NAMES libunwind.h) +endfunction() + +function(sentry_find_libunwind_ptrace) + # `libunwind-ptrace.pc` declares `Requires: libunwind-generic libunwind`; the generic half has to + # be named here, and callers link `sentry::libunwind` alongside for the other. + sentry_find_system_library(SentryLibunwindPtrace + TARGET sentry::libunwind-ptrace + PKG_CONFIG_MODULE libunwind-ptrace + LIBRARY_NAMES unwind-ptrace unwind-generic + HEADER_NAMES libunwind-ptrace.h) +endfunction() + +function(sentry_find_breakpad_client) + # `breakpad-client.pc` exposes the headers below `${includedir}/breakpad`, matching the + # `client//...` includes in `src/backends/sentry_backend_breakpad.cpp`. + sentry_find_system_library(SentryBreakpadClient + TARGET sentry::breakpad-client + PKG_CONFIG_MODULE breakpad-client + LIBRARY_NAMES breakpad_client + HEADER_NAMES google_breakpad/common/breakpad_types.h + HEADER_PATH_SUFFIXES breakpad) +endfunction() diff --git a/sentry-config.cmake.in b/sentry-config.cmake.in index 73ac15117c..a30b7c3c2d 100644 --- a/sentry-config.cmake.in +++ b/sentry-config.cmake.in @@ -1,5 +1,6 @@ @PACKAGE_INIT@ include(CMakeFindDependencyMacro) +include("${CMAKE_CURRENT_LIST_DIR}/sentry-find-system-library.cmake") set(SENTRY_BACKEND @SENTRY_BACKEND@) set(SENTRY_TRANSPORT @SENTRY_TRANSPORT@) @@ -16,12 +17,10 @@ if(NOT SENTRY_BUILD_SHARED_LIBS) find_dependency(ZLIB) endif() if(SENTRY_BACKEND STREQUAL "breakpad" AND SENTRY_BREAKPAD_SYSTEM) - find_dependency(PkgConfig) - pkg_check_modules(BREAKPAD REQUIRED IMPORTED_TARGET breakpad-client) + sentry_find_breakpad_client() endif() if(SENTRY_LIBUNWIND_SYSTEM) - find_dependency(PkgConfig) - pkg_check_modules(LIBUNWIND REQUIRED IMPORTED_TARGET libunwind) + sentry_find_libunwind() endif() if(SENTRY_TRANSPORT STREQUAL "curl" AND NOT SENTRY_LINK_CURL STREQUAL "OFF") find_dependency(CURL)