diff --git a/AK/Assertions.cpp b/AK/Assertions.cpp index bc096d6a72a..f5adf981f35 100644 --- a/AK/Assertions.cpp +++ b/AK/Assertions.cpp @@ -8,18 +8,22 @@ #include #include #include -#include -#include #if defined(AK_OS_ANDROID) && (__ANDROID_API__ >= 33) # include # define EXECINFO_BACKTRACE # define PRINT_ERROR(s) __android_log_write(ANDROID_LOG_WARN, "AK", (s)) #else -# define PRINT_ERROR(s) (void)fputs((s), stderr) +# include +# define PRINT_ERROR(s) (void)::fputs((s), stderr) #endif -#if defined(AK_HAS_BACKTRACE_HEADER) +#if defined(AK_HAS_STD_STACKTRACE) +# include +# include +#elif defined(AK_HAS_BACKTRACE_HEADER) +# include +# include # include #endif @@ -29,7 +33,16 @@ # define ERRORLN warnln #endif -#if defined(AK_HAS_BACKTRACE_HEADER) +#if defined(AK_HAS_STD_STACKTRACE) +namespace { +ALWAYS_INLINE void dump_backtrace() +{ + // We assume the stacktrace implementation demangles symbols, as does microsoft/STL + PRINT_ERROR(std::to_string(std::stacktrace::current(2)).c_str()); + PRINT_ERROR("\n"); +} +} +#elif defined(AK_HAS_BACKTRACE_HEADER) namespace { ALWAYS_INLINE void dump_backtrace() { @@ -94,7 +107,7 @@ bool ak_colorize_output(void) void ak_trap(void) { -#if defined(AK_HAS_BACKTRACE_HEADER) +#if defined(AK_HAS_BACKTRACE_HEADER) || defined(AK_HAS_STD_STACKTRACE) dump_backtrace(); #endif __builtin_trap(); diff --git a/AK/CMakeLists.txt b/AK/CMakeLists.txt index 6705f945379..11bfad3f689 100644 --- a/AK/CMakeLists.txt +++ b/AK/CMakeLists.txt @@ -49,19 +49,9 @@ serenity_lib(AK ak) serenity_install_headers(AK) serenity_install_sources(AK) -find_package(Backtrace) +include(stacktrace) configure_file(Backtrace.h.in Backtrace.h @ONLY) - -if (Backtrace_FOUND) - if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.30) - target_link_libraries(AK PRIVATE Backtrace::Backtrace) - else() - target_include_directories(AK PRIVATE ${Backtrace_INCLUDE_DIRS}) - target_link_libraries(AK PRIVATE ${Backtrace_LIBRARIES}) - endif() -else() - message(WARNING "Backtrace not found, stack traces will be unavailable") -endif() +link_stacktrace_library(AK STD_DEFINITION AK_HAS_STD_STACKTRACE) find_package(simdutf REQUIRED) swizzle_target_properties_for_swift(simdutf::simdutf) diff --git a/Meta/CMake/common_options.cmake b/Meta/CMake/common_options.cmake index 72f71003ba6..23bd279c767 100644 --- a/Meta/CMake/common_options.cmake +++ b/Meta/CMake/common_options.cmake @@ -13,6 +13,11 @@ if (POLICY CMP0157) set(CMAKE_Swift_COMPILATION_MODE "$,wholemodule,incremental>") endif() +# Check arguments to return() +if (POLICY CMP0140) + cmake_policy(SET CMP0140 NEW) +endif() + serenity_option(ENABLE_COMPILETIME_FORMAT_CHECK ON CACHE BOOL "Enable compiletime format string checks") serenity_option(ENABLE_UNDEFINED_SANITIZER OFF CACHE BOOL "Enable undefined behavior sanitizer testing in gcc/clang") serenity_option(UNDEFINED_BEHAVIOR_IS_FATAL OFF CACHE BOOL "Make undefined behavior sanitizer errors non-recoverable") @@ -35,6 +40,7 @@ serenity_option(ENABLE_CLANG_PLUGINS_INVALID_FUNCTION_MEMBERS OFF CACHE BOOL "En serenity_option(ENABLE_GUI_TARGETS ON CACHE BOOL "Enable building GUI targets") serenity_option(ENABLE_INSTALL_HEADERS ON CACHE BOOL "Enable installing headers") serenity_option(ENABLE_SWIFT OFF CACHE BOOL "Enable building Swift files") +serenity_option(ENABLE_STD_STACKTRACE OFF CACHE BOOL "Force use of std::stacktrace instead of libbacktrace. If it is not supported the build will fail") if (ENABLE_SWIFT) include(${CMAKE_CURRENT_LIST_DIR}/Swift/swift-settings.cmake) diff --git a/Meta/CMake/stacktrace.cmake b/Meta/CMake/stacktrace.cmake new file mode 100644 index 00000000000..f23f4b53ea1 --- /dev/null +++ b/Meta/CMake/stacktrace.cmake @@ -0,0 +1,76 @@ +# +# Provides definitions for stack trace support via libbacktrace or std::stacktrace +# + +include_guard() + +find_package(Backtrace) +include(CheckCXXSourceCompiles) + +function(check_std_stacktrace link_lib library_target out_var) + set(CMAKE_REQUIRED_LIBRARIES ${link_lib}) + set(check_var HAVE_STD_STACKTRACE_CHECK) + if (link_lib) + set(check_var "HAVE_STD_STACKTRACE_WITH_${link_lib}") + endif() + check_cxx_source_compiles(" + #include + #include + #include + #if !defined(__cpp_lib_stacktrace) || (__cpp_lib_stacktrace < 202011L) + # error \"No std::stacktrace available\" + #endif + int main() { + std::cout << std::stacktrace::current() << std::endl; + return 0; + }" + ${check_var} + ) + set(${out_var} ${${check_var}}) + if (${out_var}) + target_link_libraries(${library_target} PRIVATE "${link_lib}") + endif() + return(PROPAGATE ${out_var}) +endfunction() + +function(link_stacktrace_library target) + cmake_parse_arguments(PARSE_ARGV 1 ARG "" "STD_DEFINITION" "") + + if (Backtrace_FOUND AND NOT ENABLE_STD_STACKTRACE) + if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.30) + target_link_libraries(${target} PRIVATE Backtrace::Backtrace) + else() + target_include_directories(${target} PRIVATE ${Backtrace_INCLUDE_DIRS}) + target_link_libraries(${target} PRIVATE ${Backtrace_LIBRARIES}) + endif() + else() + check_std_stacktrace("" ${target} HAVE_STD_STACKTRACE) + + if(NOT HAVE_STD_STACKTRACE AND CMAKE_CXX_COMPILER_ID STREQUAL GNU) + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 14.1) + check_std_stacktrace("stdc++exp" ${target} HAVE_STD_STACKTRACE) + else() + check_std_stacktrace("stdc++_libbacktrace" ${target} HAVE_STD_STACKTRACE) + endif() + endif() + + if (NOT HAVE_STD_STACKTRACE AND CMAKE_CXX_COMPILER_ID MATCHES "Clang$") + foreach(lib IN ITEMS "stdc++exp" "stdc++_libbacktrace" "c++experimental" ) + check_std_stacktrace("${lib}" ${target} HAVE_STD_STACKTRACE) + if(HAVE_STD_STACKTRACE) + break() + endif() + endforeach() + endif() + + if(HAVE_STD_STACKTRACE) + target_compile_definitions(${target} PRIVATE ${ARG_STD_DEFINITION}) + else() + set(msg_level WARNING) + if (ENABLE_STD_STACKTRACE) + set(msg_level FATAL_ERROR) + endif() + message(${msg_level} "Backtrace and not found, stack traces will be unavailable") + endif() + endif() +endfunction()