jeremy-rifkin / cpptrace

Simple, portable, and self-contained stacktrace library for C++11 and newer
MIT License
701 stars 75 forks source link

Undefined dwarf symbols in static mingw build from vcpkg #70

Closed HybridEidolon closed 8 months ago

HybridEidolon commented 10 months ago

When using the cpptrace port in vcpkg on x86-mingw-static or x64-mingw-static (and not the dynamic triplets), libdwarf does not seem to be linked correctly, despite libdwarf.a showing up in the vcpkg_installed directory.

Even if I link libdwarf::dwarf-static directly in my own CMake target, cpptrace still references symbols that aren't resolved for some reason.

CMakeLists.txt

add_executable(foo main.cpp)
target_link_libraries(foo PRIVATE cpptrace::cpptrace)

main.cpp

#include <cpptrace/cpptrace.hpp>

int main(int argc, char** argv)
{
    cpptrace::generate_trace().print();
}

vcpkg.json

{
  "dependencies": [
    "cpptrace"
  ]
}

configure and build line

cmake -S . -B build -G "Ninja" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x86-mingw-static -DVCPKG_HOST_TRIPLET=x86-mingw-static -DCMAKE_MAKE_PROGRAM=$(which ninja)
cmake --build build

build output

...
C:/msys64/mingw32/bin/../lib/gcc/i686-w64-mingw32/13.2.0/../../../../i686-w64-mingw32/bin/ld.exe: vcpkg_installed/x86-mingw-static/debug/lib/libcpptrace.a(symbols_with_libdwarf.cpp.obj): in function `ZNK8cpptrace6detail8libdwarf10die_object13dwarf4_rangesIZNKS2_9pc_in_dieEiyEUlyyE_EEvyT_':
C:/Users/Eidolon/Code/cpp/vcpkg/buildtrees/cpptrace/src/v0.3.1-8308ed0a27.clean/src/utils/dwarf.hpp:337:(.text$_ZNK8cpptrace6detail8libdwarf10die_object13dwarf4_rangesIZNKS2_9pc_in_dieEiyEUlyyE_EEvyT_[__ZNK8cpptrace6detail8libdwarf10die_object13dwarf4_rangesIZNKS2_9pc_in_dieEiyEUlyyE_EEvyT_]+0x85): undefined reference to `_imp__dwarf_attr'
...
jeremy-rifkin commented 10 months ago

Thank you! This is a super helpful report, I’ll look into it.

HybridEidolon commented 10 months ago

Seems to also affect x64-mingw-static, but neither mingw dynamic triplet, so I'll add that to the description. It might be that the portfile for libdwarf is set up incorrectly.

HybridEidolon commented 10 months ago

cpptrace seems to output object files which link against the libdwarf symbols with the _imp_ prefix, but libdwarf.a does not have that prefix. e.g. _dwarf_get_ranges_b vs _imp__dwarf_get_ranges_b

HybridEidolon commented 10 months ago

libdwarf's cmake config output does not specify LIBDWARF_STATIC as a public definition of libdwarf::dwarf-static, so if cpptrace is statically linking against libdwarf, it needs to define it itself. That macro causes libdwarf not to export symbols with declspec(dllexport). Either libdwarf should be patched upstream or cpptrace's cmakelists should be patched, but I'm not sure which would be correct here. I have a port overlay of cpptrace which just adds the definition if dwarf-static is available, and it links correctly.

I now have a different issue in that it is unable to fully resolve symbols with libdwarf if the binary has had its symbols stripped... however mgwhelp has the same problem, so I'm not worried about it here.

jeremy-rifkin commented 8 months ago

I tested locally and this seems to be resolved as of libdwarf 0.9.1