libbacktrace is meant to work on all platforms, including macOS and mingw. But on macOS, it does not work out of the box: Instead of meaningful stack traces, I only got
../../gltests/test-c32isalnum.c:42: assertion 'ret == n' failed Stack trace: libbacktrace: no debug info in Mach-O executable See https://github.com/ianlancetaylor/libbacktrace/issues/122 . In order to make things work, here is a wrapper around the compiler command, specifically for macOS. I don't know whether this wrapper is also needed for use of a debugger (gdb or lldb). Apple disallows use of a debugger by a non-privileged user, and the workarounds (for users with admin permissions) changed several times over the years, with the result that many developers cannot use a debugger on this platform any more. 2024-05-20 Bruno Haible <br...@clisp.org> Make it easy to generate debug info for libbacktrace on macOS. * build-aux/macos-compile: New file. =========================== build-aux/macos-compile =========================== #!/bin/sh # Wrapper for compilers on macOS # that lose debug information in the final link of an executable. scriptversion=2024-05-20.15; # UTC # Copyright (C) 2024 Free Software Foundation, Inc. # # This file is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation, either version 3 of the License, # or (at your option) any later version. # # This file is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. # Written by Bruno Haible <br...@clisp.org>, 2024. # The problem: # 1) On macOS, debug information for executables is not stored in the # executable itself, but in a separate file: If the executable is in # ${DIR}/${BASENAME} # the debug info is in # ${DIR}/${BASENAME}.dSYM/Contents/Resources/DWARF/${BASENAME} # 2) The Apple compilers on macOS, in the linking step that creates an # executable from object files, do not create this debug info. # An extra command # dsymutil ${DIR}/${BASENAME} # is necessary in order to create it. # # See # https://stackoverflow.com/questions/32297349/why-does-a-2-stage-command-line-build-with-clang-not-generate-a-dsym-directory # https://stackoverflow.com/questions/10044697/where-how-does-apples-gcc-store-dwarf-inside-an-executable/12827463#12827463 # https://wiki.dwarfstd.org/Apple%27s_%22Lazy%22_DWARF_Scheme.md # The solution: # Make # macos-compile clang [OPTION...] FILE... # behave like # clang [OPTION...] FILE... # does on other platforms, namely to create the debug info during linking # of the executable (instead of leaving it for later). # Note: 1) is also a problem for the 'install' command that installs an # executable in a public location. This is not handled here. # func_usage # outputs to stdout the --help usage message. func_usage () { echo "\ Usage: macos-compile COMPILER [OPTION...] FILE... Invokes COMPILER [OPTION...] FILE... and handles debug information. Report bugs to <bug-gnulib@gnu.org>." } # Handle --help and --version. case "$1" in --help) func_usage exit $? ;; --version) echo "macos-compile (GNU gnulib) $scriptversion Copyright (C) 2024 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Written by Bruno Haible." exit $? ;; esac # Set to true for the linking step that creates an executable. linking=true # The executable created by the command. output_file='a.out' output_file_is_next=false # Whether debug information is requested. debugging=false # Process the command-line options. first=true for arg do if $first; then first=false set -- "$arg" else if $output_file_is_next; then output_file="$arg" output_file_is_next=false else case "$arg" in -c | -E | -S | -fdriver-only | --precompile ) linking=false ;; -o ) output_file_is_next=true ;; -g* ) debugging=true ;; esac fi set -- "$@" "$arg" fi done # Execute the command and the $output_file.dSYM workaround. if $linking; then rm -rf "$output_file.dSYM" fi "$@" || exit $? if $linking; then # Do this dsymutil invocation also when not $debugging. # The linking step is supposed to copy and link the debug information from # the previous steps always. # Example: $CC -g -O2 -c foo.c && $CC foo.o dsymutil "$output_file" || exit $? fi exit 0