Tracking down what broke boehm-gc-static-aarch64-apple-darwin

I’d like help tracking down what went wrong with statically building boehmgc on aarch64-darwin. The build currently fails because of missing symbols

Undefined symbols for architecture arm64:
  "std::bad_alloc::bad_alloc()", referenced from:
      _main in test_cpp.o
      GC_throw_bad_alloc() in libgccpp.a(gc_badalc.o)
      operator new(unsigned long) in libgccpp.a(gc_cpp.o)
      operator new[](unsigned long) in libgccpp.a(gc_cpp.o)
  "std::bad_alloc::~bad_alloc()", referenced from:
      _main in test_cpp.o
      GC_throw_bad_alloc() in libgccpp.a(gc_badalc.o)
      operator new(unsigned long) in libgccpp.a(gc_cpp.o)
      operator new[](unsigned long) in libgccpp.a(gc_cpp.o)
  "std::terminate()", referenced from:
      ___clang_call_terminate in test_cpp.o
      ___clang_call_terminate in libgccpp.a(gc_cpp.o)
  "typeinfo for std::bad_alloc", referenced from:
      _main in test_cpp.o
      GC_throw_bad_alloc() in libgccpp.a(gc_badalc.o)
      operator new(unsigned long) in libgccpp.a(gc_cpp.o)
      operator new[](unsigned long) in libgccpp.a(gc_cpp.o)
  "vtable for __cxxabiv1::__class_type_info", referenced from:
      typeinfo for A in test_cpp.o
      typeinfo for gc in test_cpp.o
  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
  "vtable for __cxxabiv1::__si_class_type_info", referenced from:
      typeinfo for E in test_cpp.o
      typeinfo for F in test_cpp.o
  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
  "vtable for __cxxabiv1::__vmi_class_type_info", referenced from:
      typeinfo for B in test_cpp.o
      typeinfo for gc_cleanup in test_cpp.o
      typeinfo for C in test_cpp.o
  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
  "___cxa_allocate_exception", referenced from:
      _main in test_cpp.o
      GC_throw_bad_alloc() in libgccpp.a(gc_badalc.o)
      operator new(unsigned long) in libgccpp.a(gc_cpp.o)
      operator new[](unsigned long) in libgccpp.a(gc_cpp.o)
  "___cxa_begin_catch", referenced from:
      ___clang_call_terminate in test_cpp.o
      ___clang_call_terminate in libgccpp.a(gc_cpp.o)
  "___cxa_throw", referenced from:
      _main in test_cpp.o
      GC_throw_bad_alloc() in libgccpp.a(gc_badalc.o)
      operator new(unsigned long) in libgccpp.a(gc_cpp.o)
      operator new[](unsigned long) in libgccpp.a(gc_cpp.o)
  "___gxx_personality_v0", referenced from:
      _main in test_cpp.o
      C::C(int) in test_cpp.o
      F::F() in test_cpp.o
      B::~B() in test_cpp.o
      B::~B() in test_cpp.o
      gc_cleanup::~gc_cleanup() in test_cpp.o
      gc_cleanup::~gc_cleanup() in test_cpp.o
      ...

I’ve dealt with missing symbol errors before, but these don’t make any sense to me why they’d be missing since they’re all std:: and not from some other library.

I managed to bisect the Nixpkgs-unstable branch and the last good/working commit was 14feac318eefa31d936d9b6a2aacb1928899abfe which has the drv
/nix/store/sg15pylagk87xnd0zn5sr7lr7z5drcvq-boehm-gc-static-aarch64-apple-darwin-8.2.4.drv resulting in
/nix/store/lsylryf60mjc204xxwwn9zr4ywxgwgdn-boehm-gc-static-aarch64-apple-darwin-8.2.4

The next commit cd20c0c426cc7d5cbba6fdeeda19166787809500 breaks static building for boehmgc with drv /nix/store/wlqjkrfrg1n436y47d2pb3r4r8bjws6c-boehm-gc-static-aarch64-apple-darwin-8.2.4.drv

They’re both the same version of boehmgc and it’s a big merge commit, so it’s hard to see what in there caused the change. I attempted a bit to do a bisect of the master commits between those but it causes way too much rebuilding of random packages to finish in any reasonable amount of time with my hardware. I attempted just bisecting on nix-instantiate output, but that seemed to change too much also.

Any help in what things to look for to track down why this broke would be super appreciated.

I also encountered this problem. And thanks for your bisection. I am new to Nix, I just wanted to take a look at the commit, in case something really pops up.

Since boehm-gc does not have external dependencies, it’s most likely related to the changes to the toolchain. I examined that changes, and found it’s likely broken by the removal of -lc++abi, in cc-wrapper/default.nix L548/568, i.e. Merge branch 'staging' into staging-next · NixOS/nixpkgs@cd20c0c · GitHub

Then, I manually added -lc++abi to LDFLAGS to boehm-gc as overlay,

boehmgc = prev.boehmgc.overrideAttrs (oldAttrs: final.lib.optionalAttrs (prev.boehmgc.stdenv.hostPlatform.useLLVM or false) {
  LDFLAGS = (oldAttrs.LDFLAGS or "") + " -lc++abi";
});

The problem went away.

It was tested on my modified pkgsStatic pkgs (with LLVM) with tons of workaround and modifications, so I am not sure if it’s really relevant. But hope it helps.

unclear what the correct fix is. the upstream LLVM build is setup so only -lc++ is required when linking against shared objects, which is why libc++.so is a linker script and on darwin libc++.dylib re-exports libc++abi.dylib but on static builds there isn’t any such provision.

⚙ D96070 [clang] [driver] Enable static linking to libc++ suggests to just merge libc++abi.a into libc++.a which seems reasonable. I no longer have access to a darwin system but this patch to libcxx makes nix-build -A pkgsStatic.pkgsLLVM.boehmgc build on linux without having to add -lc++abi.

diff --git a/pkgs/development/compilers/llvm/common/libcxx/default.nix b/pkgs/development/compilers/llvm/common/libcxx/default.nix
index de895125f883..a5945804dfd2 100644
--- a/pkgs/development/compilers/llvm/common/libcxx/default.nix
+++ b/pkgs/development/compilers/llvm/common/libcxx/default.nix
@@ -126,6 +126,21 @@ stdenv.mkDerivation (rec {
   postInstall = lib.optionalString (cxxabi != null) ''
     lndir ${lib.getDev cxxabi}/include $dev/include/c++/v1
     lndir ${lib.getLib cxxabi}/lib $out/lib
+  '' + ''
+    if [[ -f $out/lib/libc++.a && -f $out/lib/libc++abi.a ]]; then
+      scratch="$(mktemp -d)"
+      mv $out/lib/libc++.a $scratch/libcxx.a
+      cp $out/lib/libc++abi.a $scratch/libcxxabi.a
+      $AR -M <<MRI
+      create libcxx.a
+      addlib $scratch/libcxx.a
+      addlib $scratch/libcxxabi.a
+      save
+      end
+    MRI
+      mv libcxx.a $out/lib/libc++.a
+      rm -rf $scratch
+    fi
   '';
 
   passthru = {