From 014f386f58f0d299af18849b34bd248a0a50036b Mon Sep 17 00:00:00 2001 From: Niels Grewe Date: Tue, 15 Dec 2020 12:00:19 +0100 Subject: [PATCH] Add support for libc++abi. Extends C++ interop with autodetected support for libc++abi in addition to the existing support for libcxxrt and libsubc++. Fixes #142. --- CMake/CMakeLists.txt | 7 +++++++ CMake/typeinfo_test.cc | 3 +++ CMakeLists.txt | 28 ++++++++++++++++++++++++---- azure-pipelines.yml | 23 ++++++++++++++++++++--- objcxx_eh.cc | 14 ++++++++++++-- 5 files changed, 66 insertions(+), 9 deletions(-) diff --git a/CMake/CMakeLists.txt b/CMake/CMakeLists.txt index 0bfd1bd..a4423c5 100644 --- a/CMake/CMakeLists.txt +++ b/CMake/CMakeLists.txt @@ -4,6 +4,13 @@ project(test_cxx_runtime) add_executable(test_cxx_runtime typeinfo_test.cc) add_executable(test_cxx_stdlib typeinfo_test.cc) if (CXX_RUNTIME) + if (CXX_RUNTIME MATCHES ".*libc\\+\\+abi.*") + find_library(M_LIBRARY m) + if (M_LIBRARY) + target_link_libraries(test_cxx_runtime ${M_LIBRARY}) + endif() + endif() + set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") target_link_libraries(test_cxx_runtime ${CXX_RUNTIME}) set_target_properties(test_cxx_runtime PROPERTIES LINKER_LANGUAGE C) diff --git a/CMake/typeinfo_test.cc b/CMake/typeinfo_test.cc index 74802f9..1d5536b 100644 --- a/CMake/typeinfo_test.cc +++ b/CMake/typeinfo_test.cc @@ -49,6 +49,9 @@ class type_info2 : public std::type_info virtual bool __do_catch(const type_info *thrown_type, void **thrown_object, unsigned outer) const { return true; } + virtual bool __do_upcast( + const __class_type_info *target, + void **thrown_object) const { return true; }; }; bool type_info2::__is_pointer_p() const { return true; } diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e2d114..d7c33aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -291,9 +291,11 @@ if (ENABLE_OBJCXX) if (NOT CXX_RUNTIME) test_cxx(supc++ false) endif (NOT CXX_RUNTIME) - # libc++abi does not currently work, don't try it. if (NOT CXX_RUNTIME) - # test_cxx(c++abi false) + list (FIND CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "c++" _libcxx_index) + if (${_libcxx_index} GREATER -1) + test_cxx(c++abi false) + endif() endif (NOT CXX_RUNTIME) # If we have a C++ ABI library, then we can produce a single libobjc that @@ -325,6 +327,9 @@ if (ENABLE_OBJCXX) MAIN_DEPENDENCY eh_trampoline.cc) list(APPEND libobjc_ASM_SRCS eh_trampoline.s) list(APPEND libobjc_CXX_SRCS objcxx_eh.cc) + + # Find libm for linking, as some versions of libc++ don't link against it + find_library(M_LIBRARY m) endif () endif (ENABLE_OBJCXX) @@ -377,6 +382,11 @@ if (LIBGC) target_link_libraries(objc ${LIBGC}) endif () +# Explicitly link libm, as an implicit dependency of the C++ runtime +if (M_LIBRARY) + target_link_libraries(objc ${M_LIBRARY}) +endif () + # Make weak symbols work on OS X if (APPLE) set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS @@ -459,8 +469,18 @@ include (CPack) if (BOEHM_GC) set(PC_REQUIRES_PRIVATE_BOEHM_GC "Requires.private: bdw-gc") endif () -if (ENABLE_OBJCXX AND NOT CXXRT_IS_STDLIB) - set(PC_LIBS_PRIVATE "Libs.private: -l${CXX_RUNTIME}") +if (ENABLE_OBJCXX) + if (CXXRT_IS_STDLIB) + set(PC_LIBS_PRIVATE ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES}) + else() + list(APPEND PC_LIBS_PRIVATE ${CXX_RUNTIME}) + if (M_LIBRARY) + list(APPEND PC_LIBS_PRIVATE ${M_LIBRARY}) + endif () + endif() + list(REMOVE_DUPLICATES PC_LIBS_PRIVATE) + string(REPLACE ";" " -l" PC_LIBS_PRIVATE "${PC_LIBS_PRIVATE}") + set(PC_LIBS_PRIVATE "Libs.private: -l${PC_LIBS_PRIVATE}") endif() configure_file("libobjc.pc.in" "libobjc.pc" @ONLY) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6653475..d48600f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,20 +7,36 @@ jobs: matrix: Debug: BuildType: Debug + StdLib: libstdc++ + CxxFlags: "" Release: BuildType: Release + StdLib: libstdc++ + CxxFlags: "" + Debug-libc++: + BuildType: Debug + StdLib: libc++ + CxxFlags: "-stdlib=libc++" + Release-libc++: + BuildType: Release + StdLib: libc++ + CxxFlags: "-stdlib=libc++" steps: - checkout: self submodules: true - script: | sudo add-apt-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" sudo apt-get update - sudo apt-get install -y ninja-build - sudo apt-get install -y clang-8 + sudo apt-get install -y ninja-build clang-8 + if [ "$(StdLib)" = "libc++" ]; then + sudo apt-get install -qy libc++-8-dev libc++abi-8-dev + fi + displayName: Install Dependencies - task: CMake@1 + displayName: Generate Build Scripts inputs: - cmakeArgs: '.. -GNinja -DCMAKE_BUILD_TYPE=$(BuildType) -DTESTS=ON -DCMAKE_CXX_COMPILER=clang++-8 -DCMAKE_C_COMPILER=clang-8' + cmakeArgs: '.. -GNinja -DCMAKE_BUILD_TYPE=$(BuildType) -DTESTS=ON -DCMAKE_CXX_COMPILER=clang++-8 -DCMAKE_C_COMPILER=clang-8 -DCMAKE_CXX_FLAGS="$(CxxFlags)"' - script: | ninja @@ -32,6 +48,7 @@ jobs: - script: | ctest -j 4 --output-on-failure -T test + displayName: 'Test' workingDirectory: build failOnStderr: false - task: PublishTestResults@2 diff --git a/objcxx_eh.cc b/objcxx_eh.cc index bc4740b..add5dea 100644 --- a/objcxx_eh.cc +++ b/objcxx_eh.cc @@ -292,6 +292,16 @@ namespace gnustep unsigned outer) const; }; } + + static inline id dereference_thrown_object_pointer(void** obj) { + /* libc++-abi does not have __is_pointer_p and won't do the double dereference + * required to get the object pointer. We need to do it ourselves if we have + * caught an exception with libc++'s exception class. */ + if (cxx_exception_class == llvm_cxx_exception_class) { + return **(id**)obj; + } + return *(id*)obj; + } }; @@ -316,7 +326,7 @@ bool gnustep::libobjc::__objc_class_type_info::__do_catch(const type_info *throw || (AppleCompatibleMode && dynamic_cast(thrownType))) { - thrown = *(id*)obj; + thrown = dereference_thrown_object_pointer(obj); // nil only matches id catch handlers in Apple-compatible mode, or when thrown as an id if (0 == thrown) { @@ -328,7 +338,7 @@ bool gnustep::libobjc::__objc_class_type_info::__do_catch(const type_info *throw } else if (dynamic_cast(thrownType)) { - thrown = *(id*)obj; + thrown = dereference_thrown_object_pointer(obj); found = isKindOfClass((Class)objc_getClass(thrownType->name()), (Class)objc_getClass(name())); }