jeremy-rifkin / cpptrace

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

Incorrent location for libdwarf headers when using PKG_CONFIG #131

Closed xokdvium closed 3 months ago

xokdvium commented 3 months ago

It's impossible to build the project with CPPTRACE_FIND_LIBDWARF_WITH_PKGCONFIG from trunk.

> -- Found PkgConfig: /nix/store/zdvrzlvzbn9ymb0z8na50w995j8np16z-pkg-config-wrapper-0.29.2/bin/pkg-config (found version "0.29.2")
       > -- Checking for module 'libdwarf'
       > --   Found libdwarf, version 0.9.2
       > CMake Error at CMakeLists.txt:468 (get_target_property):
       >   get_target_property() called with non-existent target "dwarf".
       >
       >
       > -- Looking for C++ include libdwarf/libdwarf.h
       > -- Looking for C++ include libdwarf/libdwarf.h - not found
       > -- Looking for C++ include libdwarf.h
       > -- Looking for C++ include libdwarf.h - not found
       > CMake Error at CMakeLists.txt:481 (message):
       >   Couldn't find libdwarf.h

I was able to get it working with the patch:

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 80c6cb8..29f94bf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -464,11 +464,15 @@ if(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF)
     # it's libdwarf/libdwarf.h and libdwarf/dwarf.h or just libdwarf.h and dwarf.h
     include(CheckIncludeFileCXX)
     # libdwarf's cmake doesn't properly set variables to indicate where its libraries live
-    if(NOT CPPTRACE_CONDA_LIBDWARF_WEIRDNESS)
+    if(NOT CPPTRACE_CONDA_LIBDWARF_WEIRDNESS AND NOT CPPTRACE_FIND_LIBDWARF_WITH_PKGCONFIG)
       get_target_property(LIBDWARF_INTERFACE_INCLUDE_DIRECTORIES ${LIBDWARF_LIBRARIES} INTERFACE_INCLUDE_DIRECTORIES)
       set(CMAKE_REQUIRED_INCLUDES ${LIBDWARF_INTERFACE_INCLUDE_DIRECTORIES})
     else()
       set(CMAKE_REQUIRED_INCLUDES ${LIBDWARF_INCLUDE_DIRS})
+      target_include_directories(${target_name} PRIVATE ${LIBDWARF_INCLUDE_DIRS})
+      message(STATUS "libdwarf includes: ${LIBDWARF_INCLUDE_DIRS}")
+    endif()
+    if(CPPTRACE_CONDA_LIBDWARF_WEIRDNESS)
       target_compile_definitions(${target_name} PRIVATE CPPTRACE_CONDA_LIBDWARF_WEIRDNESS)
     endif()
     CHECK_INCLUDE_FILE_CXX("libdwarf/libdwarf.h" LIBDWARF_IS_NESTED)

Judging by the amount of caused by inconsistent header locations and a combinatorial explosion of possible combinations of build-systems for libdwarf and various package-manager patches/workarounds it's not surprising at all.

What exactly does CPPTRACE_CONDA_LIBDWARF_WEIRDNESS address? According to upstream the canonical way (see details below) to include the headers with pkg-config is:

#include <libdwarf.h>
#include <dwarf.h>

The canonical libdwarf directory layout when building with autotools is:

 result-dev
├──  include
│  └──  libdwarf-0
│     ├──  dwarf.h
│     └──  libdwarf.h
├──  lib
│  └──  pkgconfig
│     └──  libdwarf.pc

Provided pkg-config template from upstream:

prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
pkgincludedir=@includedir@/libdwarf-@VMAJ@

Name: libdwarf
Description: DWARF debug symbols library
Version: @PROJECT_VERSION@
Requires.private: @requirements_libdwarf_pc@
Libs: -L${libdir} -ldwarf
Libs.private: @requirements_libdwarf_libs@
Cflags: -I${pkgincludedir}
Cflags.private: -DLIBDWARF_STATIC

For a build from nixpkgs this boils down to:

prefix=/nix/store/1ch23nm1vjqzazlv5d3lag2j9vq9yvrk-libdwarf-0.9.2
exec_prefix=${prefix}
libdir=/nix/store/ys4ilb3naawcahzwyh5isr269wvwnlsa-libdwarf-0.9.2-lib/lib
includedir=/nix/store/saqb5l2yp88bjv6r62ddgmzn0qhvjjd6-libdwarf-0.9.2-dev/include
pkgincludedir=/nix/store/saqb5l2yp88bjv6r62ddgmzn0qhvjjd6-libdwarf-0.9.2-dev/include/libdwarf-0

Name: libdwarf
Description: DWARF debug symbols library
Version: 0.9.2
Requires.private:
Libs: -L${libdir} -ldwarf
Libs.private: -lz -lzstd
Cflags: -I${pkgincludedir}
Cflags.private: -DLIBDWARF_STATIC

When passing the include dirs to the target like in patch I've attached prefixing with libdwarf-0 should not be necessary. Is this possible to do same thing for conda?

jeremy-rifkin commented 3 months ago

Thanks for opening this, unfortunately libdwarf has been extremely inconsistent in where it places headers. Sometimes it's include/libdwarf.h and include/dwarf.h, sometimes it's include/libdwarf/libdwarf.h and include/libdwarf/dwarf.h, sometimes it's include/libdwarf.h and include/libdwarf/dwarf.h, with the conda feedstock it wasinclude/libdwarf.h and include/libdwarf-0/dwarf.h (CPPTRACE_CONDA_LIBDWARF_WEIRDNESS was for this header layout, however that has now been fixed in the feedstock so it can be removed), and apparently now pkgconfig can be include/libdwarf-0/libdwarf.h and include/libdwarf-0/dwarf.h. Inconsistencies arise from both the build system and version of libdwarf, the placement has changed a couple times. This has been somewhat frustrating on my end. LIBDWARF_INCLUDE_DIRS should probably be sufficient, but another check for the placement of dwarf.h may be needed to accommodate everything.

xokdvium commented 3 months ago

Indeed, such a combinatorial explosion of possible build system configurations, package manager recipie quirks and version inconsistencies is impossible to support. libdwarf is built with cmake in conan, which behaves much more sensibly. However, nixpkgs builds it with autotools and thus I've run into such issues. I'd rather not rebuild libdwarf with cmake for the nix derivation, though it's a working approach. I appreciate that you are willing to put up with this massive pain. As I understand, in the current state CPPTRACE_CONDA_LIBDWARF_WEIRDNESS is no longer necessary and roughly the following should be enough to circumvent this issue?

target_include_directories(${target_name} PRIVATE ${LIBDWARF_INCLUDE_DIRS})
jeremy-rifkin commented 3 months ago

I think so, I will take more of a look tomorrow and I plan to do a release tomorrow.

jeremy-rifkin commented 3 months ago

Thanks for your patience, this should be resolved and will be part of the next release.

jeremy-rifkin commented 3 months ago

I've released v0.6.0