From d4f0f4929dac3f4262d2ef4aa58a3f8888b2f211 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 17 Mar 2025 12:52:25 +0100 Subject: [PATCH 01/10] Bump to NDK r29-beta1 Changes: https://github.com/android/ndk/wiki/Changelog-r29 Most important changes: * Bump LLVM version to 20.0 --- .../xaprepare/ConfigAndData/BuildAndroidPlatforms.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs index f767821a506..8508a68781c 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs @@ -5,8 +5,8 @@ namespace Xamarin.Android.Prepare { class BuildAndroidPlatforms { - public const string AndroidNdkVersion = "28c"; - public const string AndroidNdkPkgRevision = "28.2.13676358"; + public const string AndroidNdkVersion = "29-beta1"; + public const string AndroidNdkPkgRevision = "29.0.13113456"; public const int NdkMinimumAPI = 21; public const int NdkMinimumAPILegacy32 = 21; From f63250eca9339411b7e9f6448c6aaa833a9ffe10 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 2 Jul 2025 09:42:40 +0200 Subject: [PATCH 02/10] Bump to r29-beta2 --- .../xaprepare/ConfigAndData/BuildAndroidPlatforms.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs index 8508a68781c..3cc50722bee 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs @@ -5,8 +5,8 @@ namespace Xamarin.Android.Prepare { class BuildAndroidPlatforms { - public const string AndroidNdkVersion = "29-beta1"; - public const string AndroidNdkPkgRevision = "29.0.13113456"; + public const string AndroidNdkVersion = "29-beta2"; + public const string AndroidNdkPkgRevision = "29.0.13599879"; public const int NdkMinimumAPI = 21; public const int NdkMinimumAPILegacy32 = 21; From d1dee071d4ec440ef7315b47436fe330c2162bd7 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 7 Aug 2025 16:31:47 +0200 Subject: [PATCH 03/10] Bump to beta3 --- .../xaprepare/ConfigAndData/BuildAndroidPlatforms.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs index 3cc50722bee..24759d0d80e 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs @@ -5,8 +5,8 @@ namespace Xamarin.Android.Prepare { class BuildAndroidPlatforms { - public const string AndroidNdkVersion = "29-beta2"; - public const string AndroidNdkPkgRevision = "29.0.13599879"; + public const string AndroidNdkVersion = "29-beta3"; + public const string AndroidNdkPkgRevision = "29.0.13846066"; public const int NdkMinimumAPI = 21; public const int NdkMinimumAPILegacy32 = 21; From d6086af5289b64989acdd0bb474fe8b6081c2aa1 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 16 Oct 2025 09:15:13 +0200 Subject: [PATCH 04/10] Fix after rebase From dde53bad1c4702dfb26bb99cde12372b4fb536af Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 16 Oct 2025 09:16:11 +0200 Subject: [PATCH 05/10] Bump to the release version --- .../xaprepare/ConfigAndData/BuildAndroidPlatforms.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs index 24759d0d80e..8bc4193eb15 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs @@ -5,8 +5,8 @@ namespace Xamarin.Android.Prepare { class BuildAndroidPlatforms { - public const string AndroidNdkVersion = "29-beta3"; - public const string AndroidNdkPkgRevision = "29.0.13846066"; + public const string AndroidNdkVersion = "29"; + public const string AndroidNdkPkgRevision = "29.0.14206865"; public const int NdkMinimumAPI = 21; public const int NdkMinimumAPILegacy32 = 21; From ab3d81979323e19b7dcdf5c6c1669303bc1f45ed Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 9 Jan 2026 14:30:09 +0100 Subject: [PATCH 06/10] Disable linking against libc++ Step 1. Cause breakage --- .../targets/Microsoft.Android.Sdk.NativeAOT.targets | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets index ba0ae385391..f10deb35148 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets @@ -121,8 +121,8 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. <_NdkLibs Include="@(RuntimePackAsset->WithMetadataValue('Filename', 'libnaot-android.$(Configuration.ToLower())-static-$(Configuration.ToLower())'))" /> - <_NdkLibs Include="$(_NdkSysrootDir)libc++_static.a" /> - <_NdkLibs Include="$(_NdkSysrootDir)libc++abi.a" /> + + From bb7d6df124cef60d5e88bdd7c20aca354bf51a57 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 9 Jan 2026 20:46:10 +0100 Subject: [PATCH 07/10] libc++ bits and pieces --- src-ThirdParty/llvm/libcxx/src/new.cpp | 226 ++++++++++++++++++ .../llvm/libcxx/src/verbose_abort.cpp | 65 +++++ src/native/nativeaot/cxx-abi/string.cc | 12 + src/native/nativeaot/cxx-abi/terminate.cc | 17 ++ 4 files changed, 320 insertions(+) create mode 100644 src-ThirdParty/llvm/libcxx/src/new.cpp create mode 100644 src-ThirdParty/llvm/libcxx/src/verbose_abort.cpp create mode 100644 src/native/nativeaot/cxx-abi/string.cc create mode 100644 src/native/nativeaot/cxx-abi/terminate.cc diff --git a/src-ThirdParty/llvm/libcxx/src/new.cpp b/src-ThirdParty/llvm/libcxx/src/new.cpp new file mode 100644 index 00000000000..e010fe4c4f1 --- /dev/null +++ b/src-ThirdParty/llvm/libcxx/src/new.cpp @@ -0,0 +1,226 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "include/overridable_function.h" +#include <__assert> +#include <__memory/aligned_alloc.h> +#include +#include +#include + +#if !defined(__GLIBCXX__) && !defined(_LIBCPP_ABI_VCRUNTIME) + +// The code below is copied as-is into libc++abi's libcxxabi/src/stdlib_new_delete.cpp +// file. The version in this file is the canonical one. + +inline void __throw_bad_alloc_shim() { std::__throw_bad_alloc(); } + +# define _LIBCPP_ASSERT_SHIM(expr, str) _LIBCPP_ASSERT(expr, str) + +// ------------------ BEGIN COPY ------------------ +// Implement all new and delete operators as weak definitions +// in this shared library, so that they can be overridden by programs +// that define non-weak copies of the functions. + +static void* operator_new_impl(std::size_t size) { + if (size == 0) + size = 1; + void* p; + while ((p = std::malloc(size)) == nullptr) { + // If malloc fails and there is a new_handler, + // call it to try free up memory. + std::new_handler nh = std::get_new_handler(); + if (nh) + nh(); + else + break; + } + return p; +} + +_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC { + void* p = operator_new_impl(size); + if (p == nullptr) + __throw_bad_alloc_shim(); + return p; +} + +_LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept { +# if !_LIBCPP_HAS_EXCEPTIONS +# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION + _LIBCPP_ASSERT_SHIM( + !std::__is_function_overridden(static_cast(&operator new)), + "libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, " + "but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because " + "`operator new(size_t, nothrow_t)` must call `operator new(size_t)`, which will terminate in case " + "it fails to allocate, making it impossible for `operator new(size_t, nothrow_t)` to fulfill its " + "contract (since it should return nullptr upon failure). Please make sure you override " + "`operator new(size_t, nothrow_t)` as well."); +# endif + + return operator_new_impl(size); +# else + void* p = nullptr; + try { + p = ::operator new(size); + } catch (...) { + } + return p; +# endif +} + +_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC { + return ::operator new(size); +} + +_LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept { +# if !_LIBCPP_HAS_EXCEPTIONS +# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION + _LIBCPP_ASSERT_SHIM( + !std::__is_function_overridden(static_cast(&operator new[])), + "libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, " + "but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because " + "`operator new[](size_t, nothrow_t)` must call `operator new[](size_t)`, which will terminate in case " + "it fails to allocate, making it impossible for `operator new[](size_t, nothrow_t)` to fulfill its " + "contract (since it should return nullptr upon failure). Please make sure you override " + "`operator new[](size_t, nothrow_t)` as well."); +# endif + + return operator_new_impl(size); +# else + void* p = nullptr; + try { + p = ::operator new[](size); + } catch (...) { + } + return p; +# endif +} + +_LIBCPP_WEAK void operator delete(void* ptr) noexcept { std::free(ptr); } + +_LIBCPP_WEAK void operator delete(void* ptr, const std::nothrow_t&) noexcept { ::operator delete(ptr); } + +_LIBCPP_WEAK void operator delete(void* ptr, size_t) noexcept { ::operator delete(ptr); } + +_LIBCPP_WEAK void operator delete[](void* ptr) noexcept { ::operator delete(ptr); } + +_LIBCPP_WEAK void operator delete[](void* ptr, const std::nothrow_t&) noexcept { ::operator delete[](ptr); } + +_LIBCPP_WEAK void operator delete[](void* ptr, size_t) noexcept { ::operator delete[](ptr); } + +# if _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION + +static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) { + if (size == 0) + size = 1; + if (static_cast(alignment) < sizeof(void*)) + alignment = std::align_val_t(sizeof(void*)); + + // Try allocating memory. If allocation fails and there is a new_handler, + // call it to try free up memory, and try again until it succeeds, or until + // the new_handler decides to terminate. + void* p; + while ((p = std::__libcpp_aligned_alloc(static_cast(alignment), size)) == nullptr) { + std::new_handler nh = std::get_new_handler(); + if (nh) + nh(); + else + break; + } + return p; +} + +_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* +operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { + void* p = operator_new_aligned_impl(size, alignment); + if (p == nullptr) + __throw_bad_alloc_shim(); + return p; +} + +_LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { +# if !_LIBCPP_HAS_EXCEPTIONS +# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION + _LIBCPP_ASSERT_SHIM( + !std::__is_function_overridden(static_cast(&operator new)), + "libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, " + "but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because " + "`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will " + "terminate in case it fails to allocate, making it impossible for `operator new(size_t, align_val_t, nothrow_t)` " + "to fulfill its contract (since it should return nullptr upon failure). Please make sure you override " + "`operator new(size_t, align_val_t, nothrow_t)` as well."); +# endif + + return operator_new_aligned_impl(size, alignment); +# else + void* p = nullptr; + try { + p = ::operator new(size, alignment); + } catch (...) { + } + return p; +# endif +} + +_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* +operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { + return ::operator new(size, alignment); +} + +_LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { +# if !_LIBCPP_HAS_EXCEPTIONS +# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION + _LIBCPP_ASSERT_SHIM( + !std::__is_function_overridden(static_cast(&operator new[])), + "libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, " + "but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because " + "`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will " + "terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, " + "nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you " + "override " + "`operator new[](size_t, align_val_t, nothrow_t)` as well."); +# endif + + return operator_new_aligned_impl(size, alignment); +# else + void* p = nullptr; + try { + p = ::operator new[](size, alignment); + } catch (...) { + } + return p; +# endif +} + +_LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr); } + +_LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { + ::operator delete(ptr, alignment); +} + +_LIBCPP_WEAK void operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept { + ::operator delete(ptr, alignment); +} + +_LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment) noexcept { + ::operator delete(ptr, alignment); +} + +_LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { + ::operator delete[](ptr, alignment); +} + +_LIBCPP_WEAK void operator delete[](void* ptr, size_t, std::align_val_t alignment) noexcept { + ::operator delete[](ptr, alignment); +} + +# endif // _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION +// ------------------ END COPY ------------------ + +#endif // !__GLIBCXX__ && !_LIBCPP_ABI_VCRUNTIME diff --git a/src-ThirdParty/llvm/libcxx/src/verbose_abort.cpp b/src-ThirdParty/llvm/libcxx/src/verbose_abort.cpp new file mode 100644 index 00000000000..fd6bc4943d6 --- /dev/null +++ b/src-ThirdParty/llvm/libcxx/src/verbose_abort.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include <__config> +#include <__verbose_abort> +#include +#include +#include + +#ifdef __BIONIC__ +# include +extern "C" void android_set_abort_message(const char* msg); +#endif // __BIONIC__ + +#if defined(__APPLE__) && __has_include() +# include +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_WEAK void __libcpp_verbose_abort(char const* format, ...) _LIBCPP_VERBOSE_ABORT_NOEXCEPT { + // Write message to stderr. We do this before formatting into a + // buffer so that we still get some information out if that fails. + { + va_list list; + va_start(list, format); + std::vfprintf(stderr, format, list); + va_end(list); + } + + // Format the arguments into an allocated buffer for CrashReport & friends. + // We leak the buffer on purpose, since we're about to abort() anyway. + char* buffer; + (void)buffer; + va_list list; + va_start(list, format); + +#if defined(__APPLE__) && __has_include() + // Note that we should technically synchronize accesses here (by e.g. taking a lock), + // however concretely we're only setting a pointer, so the likelihood of a race here + // is low. + vasprintf(&buffer, format, list); + CRSetCrashLogMessage(buffer); +#elif defined(__BIONIC__) + vasprintf(&buffer, format, list); + + // Show error in tombstone. + android_set_abort_message(buffer); + + // Show error in logcat. + openlog("libc++", 0, 0); + syslog(LOG_CRIT, "%s", buffer); + closelog(); +#endif + va_end(list); + + std::abort(); +} + +_LIBCPP_END_NAMESPACE_STD diff --git a/src/native/nativeaot/cxx-abi/string.cc b/src/native/nativeaot/cxx-abi/string.cc new file mode 100644 index 00000000000..30d528e14ac --- /dev/null +++ b/src/native/nativeaot/cxx-abi/string.cc @@ -0,0 +1,12 @@ +// +// Defining the macro will make the the explicit instantations below truely hidden +// +#define _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS + +#include + +_LIBCPP_BEGIN_NAMESPACE_STD + +template class __attribute__ ((__visibility__("hidden"))) basic_string; + +_LIBCPP_END_NAMESPACE_STD diff --git a/src/native/nativeaot/cxx-abi/terminate.cc b/src/native/nativeaot/cxx-abi/terminate.cc new file mode 100644 index 00000000000..8a9700dad94 --- /dev/null +++ b/src/native/nativeaot/cxx-abi/terminate.cc @@ -0,0 +1,17 @@ +// +// Simple implementation of std::terminate() for Xamarin.Android +// +// Does NOT support terminate handlers, since we don't use them. +// +#include +#include + +#include "helpers.hh" + +namespace std { + [[noreturn]] void + terminate () noexcept + { + xamarin::android::Helpers::abort_application ("std::terminate() called. Aborting."); + } +} From e628eae16b8c4d4508c9da30ddf5e9e6fa8ee2c7 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 12 Jan 2026 18:45:47 +0100 Subject: [PATCH 08/10] Still broken, baby steps --- src-ThirdParty/llvm/libcxx/src/new.cpp | 226 ---------------------- src/native/CMakeLists.txt | 17 +- src/native/CMakePresets.json.in | 40 ++-- src/native/native.targets | 13 +- src/native/nativeaot/cxx-abi/new.cc | 181 +++++++++++++++++ src/native/nativeaot/cxx-abi/terminate.cc | 2 +- src/native/nativeaot/host/CMakeLists.txt | 13 ++ 7 files changed, 240 insertions(+), 252 deletions(-) delete mode 100644 src-ThirdParty/llvm/libcxx/src/new.cpp create mode 100644 src/native/nativeaot/cxx-abi/new.cc diff --git a/src-ThirdParty/llvm/libcxx/src/new.cpp b/src-ThirdParty/llvm/libcxx/src/new.cpp deleted file mode 100644 index e010fe4c4f1..00000000000 --- a/src-ThirdParty/llvm/libcxx/src/new.cpp +++ /dev/null @@ -1,226 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "include/overridable_function.h" -#include <__assert> -#include <__memory/aligned_alloc.h> -#include -#include -#include - -#if !defined(__GLIBCXX__) && !defined(_LIBCPP_ABI_VCRUNTIME) - -// The code below is copied as-is into libc++abi's libcxxabi/src/stdlib_new_delete.cpp -// file. The version in this file is the canonical one. - -inline void __throw_bad_alloc_shim() { std::__throw_bad_alloc(); } - -# define _LIBCPP_ASSERT_SHIM(expr, str) _LIBCPP_ASSERT(expr, str) - -// ------------------ BEGIN COPY ------------------ -// Implement all new and delete operators as weak definitions -// in this shared library, so that they can be overridden by programs -// that define non-weak copies of the functions. - -static void* operator_new_impl(std::size_t size) { - if (size == 0) - size = 1; - void* p; - while ((p = std::malloc(size)) == nullptr) { - // If malloc fails and there is a new_handler, - // call it to try free up memory. - std::new_handler nh = std::get_new_handler(); - if (nh) - nh(); - else - break; - } - return p; -} - -_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC { - void* p = operator_new_impl(size); - if (p == nullptr) - __throw_bad_alloc_shim(); - return p; -} - -_LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept { -# if !_LIBCPP_HAS_EXCEPTIONS -# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION - _LIBCPP_ASSERT_SHIM( - !std::__is_function_overridden(static_cast(&operator new)), - "libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, " - "but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because " - "`operator new(size_t, nothrow_t)` must call `operator new(size_t)`, which will terminate in case " - "it fails to allocate, making it impossible for `operator new(size_t, nothrow_t)` to fulfill its " - "contract (since it should return nullptr upon failure). Please make sure you override " - "`operator new(size_t, nothrow_t)` as well."); -# endif - - return operator_new_impl(size); -# else - void* p = nullptr; - try { - p = ::operator new(size); - } catch (...) { - } - return p; -# endif -} - -_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC { - return ::operator new(size); -} - -_LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept { -# if !_LIBCPP_HAS_EXCEPTIONS -# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION - _LIBCPP_ASSERT_SHIM( - !std::__is_function_overridden(static_cast(&operator new[])), - "libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, " - "but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because " - "`operator new[](size_t, nothrow_t)` must call `operator new[](size_t)`, which will terminate in case " - "it fails to allocate, making it impossible for `operator new[](size_t, nothrow_t)` to fulfill its " - "contract (since it should return nullptr upon failure). Please make sure you override " - "`operator new[](size_t, nothrow_t)` as well."); -# endif - - return operator_new_impl(size); -# else - void* p = nullptr; - try { - p = ::operator new[](size); - } catch (...) { - } - return p; -# endif -} - -_LIBCPP_WEAK void operator delete(void* ptr) noexcept { std::free(ptr); } - -_LIBCPP_WEAK void operator delete(void* ptr, const std::nothrow_t&) noexcept { ::operator delete(ptr); } - -_LIBCPP_WEAK void operator delete(void* ptr, size_t) noexcept { ::operator delete(ptr); } - -_LIBCPP_WEAK void operator delete[](void* ptr) noexcept { ::operator delete(ptr); } - -_LIBCPP_WEAK void operator delete[](void* ptr, const std::nothrow_t&) noexcept { ::operator delete[](ptr); } - -_LIBCPP_WEAK void operator delete[](void* ptr, size_t) noexcept { ::operator delete[](ptr); } - -# if _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION - -static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) { - if (size == 0) - size = 1; - if (static_cast(alignment) < sizeof(void*)) - alignment = std::align_val_t(sizeof(void*)); - - // Try allocating memory. If allocation fails and there is a new_handler, - // call it to try free up memory, and try again until it succeeds, or until - // the new_handler decides to terminate. - void* p; - while ((p = std::__libcpp_aligned_alloc(static_cast(alignment), size)) == nullptr) { - std::new_handler nh = std::get_new_handler(); - if (nh) - nh(); - else - break; - } - return p; -} - -_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* -operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { - void* p = operator_new_aligned_impl(size, alignment); - if (p == nullptr) - __throw_bad_alloc_shim(); - return p; -} - -_LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { -# if !_LIBCPP_HAS_EXCEPTIONS -# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION - _LIBCPP_ASSERT_SHIM( - !std::__is_function_overridden(static_cast(&operator new)), - "libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, " - "but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because " - "`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will " - "terminate in case it fails to allocate, making it impossible for `operator new(size_t, align_val_t, nothrow_t)` " - "to fulfill its contract (since it should return nullptr upon failure). Please make sure you override " - "`operator new(size_t, align_val_t, nothrow_t)` as well."); -# endif - - return operator_new_aligned_impl(size, alignment); -# else - void* p = nullptr; - try { - p = ::operator new(size, alignment); - } catch (...) { - } - return p; -# endif -} - -_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* -operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { - return ::operator new(size, alignment); -} - -_LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { -# if !_LIBCPP_HAS_EXCEPTIONS -# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION - _LIBCPP_ASSERT_SHIM( - !std::__is_function_overridden(static_cast(&operator new[])), - "libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, " - "but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because " - "`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will " - "terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, " - "nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you " - "override " - "`operator new[](size_t, align_val_t, nothrow_t)` as well."); -# endif - - return operator_new_aligned_impl(size, alignment); -# else - void* p = nullptr; - try { - p = ::operator new[](size, alignment); - } catch (...) { - } - return p; -# endif -} - -_LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr); } - -_LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { - ::operator delete(ptr, alignment); -} - -_LIBCPP_WEAK void operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept { - ::operator delete(ptr, alignment); -} - -_LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment) noexcept { - ::operator delete(ptr, alignment); -} - -_LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { - ::operator delete[](ptr, alignment); -} - -_LIBCPP_WEAK void operator delete[](void* ptr, size_t, std::align_val_t alignment) noexcept { - ::operator delete[](ptr, alignment); -} - -# endif // _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION -// ------------------ END COPY ------------------ - -#endif // !__GLIBCXX__ && !_LIBCPP_ABI_VCRUNTIME diff --git a/src/native/CMakeLists.txt b/src/native/CMakeLists.txt index 3b65133c34a..e0e587ce728 100644 --- a/src/native/CMakeLists.txt +++ b/src/native/CMakeLists.txt @@ -155,7 +155,15 @@ include(CheckLinkerFlag) # # General config # +file(REAL_PATH "../../" REPO_ROOT_DIR) +set(EXTERNAL_DIR "${REPO_ROOT_DIR}/external") +set(JAVA_INTEROP_SRC_PATH "${EXTERNAL_DIR}/Java.Interop/src/java-interop") +set(LIBUNWIND_SOURCE_DIR "${EXTERNAL_DIR}/libunwind") +set(ROBIN_MAP_DIR "${EXTERNAL_DIR}/robin-map") + set(XA_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../bin/Build${XA_BUILD_CONFIGURATION}") +set(THIRD_PARTY_SOURCE_DIR "${REPO_ROOT_DIR}/src-ThirdParty") + include("${XA_BUILD_DIR}/xa_build_configuration.cmake") # @@ -221,13 +229,6 @@ else() message(FATAL "${ANDROID_ABI} is not supported for .NET 6+ builds") endif() - -file(REAL_PATH "../../" REPO_ROOT_DIR) -set(EXTERNAL_DIR "${REPO_ROOT_DIR}/external") -set(JAVA_INTEROP_SRC_PATH "${EXTERNAL_DIR}/Java.Interop/src/java-interop") -set(LIBUNWIND_SOURCE_DIR "${EXTERNAL_DIR}/libunwind") -set(ROBIN_MAP_DIR "${EXTERNAL_DIR}/robin-map") - # # Include directories # @@ -243,7 +244,7 @@ else() set(CLR_REPO_ROOT_PATH "${LOCAL_CORECLR_PATH}/../..") set(RUNTIME_INCLUDE_DIR "${CLR_REPO_ROOT_PATH}/src/native/corehost;${CLR_REPO_ROOT_PATH}/src/coreclr/hosts/inc") else() - set(RUNTIME_INCLUDE_DIR ${REPO_ROOT_DIR}/src-ThirdParty/dotnet/runtime) + set(RUNTIME_INCLUDE_DIR ${THIRD_PARTY_SOURCE_DIR}/dotnet/runtime) endif() endif() diff --git a/src/native/CMakePresets.json.in b/src/native/CMakePresets.json.in index 79a3ac46282..9a163e9e286 100644 --- a/src/native/CMakePresets.json.in +++ b/src/native/CMakePresets.json.in @@ -54,25 +54,23 @@ }, { - "name": "analyzers-common", + "name": "nativeaot-default-common", "hidden": true, "inherits": "common", "cacheVariables": { - "ANDROID_STL": "c++_static", - "ANDROID_CPP_FEATURES": "rtti exceptions" + "ANDROID_STL": "none", + "ANDROID_CPP_FEATURES": "no-rtti no-exceptions" } }, { - "name": "default-debug", - "hidden": true, - "inherits": ["default-common", "common-debug"] - }, - - { - "name": "default-release", + "name": "analyzers-common", "hidden": true, - "inherits": ["default-common", "common-release"] + "inherits": "common", + "cacheVariables": { + "ANDROID_STL": "c++_static", + "ANDROID_CPP_FEATURES": "rtti exceptions" + } }, { @@ -196,11 +194,21 @@ "inherits": ["default-common", "common-debug", "common-arm64-v8a"] }, + { + "name": "nativeaot-default-debug-arm64-v8a", + "inherits": ["nativeaot-default-common", "common-debug", "common-arm64-v8a"] + }, + { "name": "default-release-arm64-v8a", "inherits": ["default-common", "common-release", "common-arm64-v8a"] }, + { + "name": "nativeaot-default-release-arm64-v8a", + "inherits": ["nativeaot-default-common", "common-release", "common-arm64-v8a"] + }, + { "name": "analyzers-debug-arm64-v8a", "hidden": true, @@ -284,11 +292,21 @@ "inherits": ["default-common", "common-debug", "common-x86_64"] }, + { + "name": "nativeaot-default-debug-x86_64", + "inherits": ["nativeaot-default-common", "common-debug", "common-x86_64"] + }, + { "name": "default-release-x86_64", "inherits": ["default-common", "common-release", "common-x86_64"] }, + { + "name": "nativeaot-default-release-x86_64", + "inherits": ["nativeaot-default-common", "common-release", "common-x86_64"] + }, + { "name": "analyzers-debug-x86_64", "hidden": true, diff --git a/src/native/native.targets b/src/native/native.targets index 9cd05f59b3a..90797d35cee 100644 --- a/src/native/native.targets +++ b/src/native/native.targets @@ -118,6 +118,7 @@ Inputs="@(_ConfigureRuntimesInputs)" Outputs="@(_ConfigureRuntimesOutputs)"> + <_PresetPrefix Condition=" '$(CMakeRuntimeFlavor)' == 'NativeAOT' ">nativeaot- <_NoInline Condition=" '$(DoNotInlineMonodroid)' == 'true' ">-DDONT_INLINE=ON <_NoStrip Condition=" '$(DoNotStripMonodroid)' == 'true' ">-DSTRIP_DEBUG=OFF <_LocalDotNetRuntimePath Condition=" '$(CLRLocalRuntimePath)' != '' And '$(CMakeRuntimeFlavor)' == 'CoreCLR' ">-DLOCAL_CORECLR_PATH="$(CLRLocalRuntimePath)" @@ -128,13 +129,13 @@ <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - --preset default-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + --preset $(_PresetPrefix)default-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) $(FlavorIntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Debug <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - --preset default-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + --preset $(_PresetPrefix)default-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) $(FlavorIntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-Release @@ -142,25 +143,25 @@ <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - --preset asan-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + --preset $(_PresetPrefix)asan-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) $(FlavorIntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Debug <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - --preset asan-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + --preset $(_PresetPrefix)asan-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) $(FlavorIntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-asan-Release <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - --preset ubsan-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + --preset $(_PresetPrefix)ubsan-debug-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) $(FlavorIntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Debug <_ConfigureRuntimeCommands Include="@(AndroidSupportedTargetJitAbi)"> $(CmakePath) - --preset ubsan-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) + --preset $(_PresetPrefix)ubsan-release-%(AndroidSupportedTargetJitAbi.Identity) $(_CmakeAndroidFlags) $(FlavorIntermediateOutputPath)%(AndroidSupportedTargetJitAbi.AndroidRID)-ubsan-Release diff --git a/src/native/nativeaot/cxx-abi/new.cc b/src/native/nativeaot/cxx-abi/new.cc new file mode 100644 index 00000000000..5aa1298aff0 --- /dev/null +++ b/src/native/nativeaot/cxx-abi/new.cc @@ -0,0 +1,181 @@ +// +// Code based on the original libc++ `libcxx/src/new.cpp` source, modified +// heavily for our use +// + +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include <__assert> +#include <__memory/aligned_alloc.h> +#include +#include +#include + +#include + +#define _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE [[gnu::section ("__TEXT,__lcxx_override,regular,pure_instructions")]] + +namespace { + void* operator_new_impl(std::size_t size) + { + if (size == 0) { + size = 1; + } + + return std::malloc (size); + } +} + +_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE +[[gnu::weak]] +void* operator new (std::size_t size) +{ + void *p = operator_new_impl (size); + if (p == nullptr) { + xamarin::android::Helpers::abort_application ("Out of memory in the `new` operator"); + } + + return p; +} + +[[gnu::weak]] +void* operator new (size_t size, const std::nothrow_t&) noexcept +{ + return operator_new_impl (size); +} + +_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE +[[gnu::weak]] +void* operator new[] (size_t size) +{ + return ::operator new (size); +} + +[[gnu::weak]] +void* operator new[] (size_t size, const std::nothrow_t&) noexcept +{ + return operator_new_impl (size); +} + +[[gnu::weak]] +void operator delete(void* ptr) noexcept +{ + std::free (ptr); +} + +[[gnu::weak]] +void operator delete (void* ptr, const std::nothrow_t&) noexcept +{ + ::operator delete(ptr); +} + +[[gnu::weak]] +void operator delete (void* ptr, size_t) noexcept +{ + ::operator delete(ptr); +} + +[[gnu::weak]] +void operator delete[] (void* ptr) noexcept +{ + ::operator delete(ptr); +} + +[[gnu::weak]] +void operator delete[] (void* ptr, const std::nothrow_t&) noexcept +{ + ::operator delete[](ptr); +} + +[[gnu::weak]] +void operator delete[] (void* ptr, size_t) noexcept +{ + ::operator delete[](ptr); +} + +namespace { + void* operator_new_aligned_impl (std::size_t size, std::align_val_t alignment) + { + if (size == 0) { + size = 1; + } + + if (static_cast(alignment) < sizeof(void*)) { + alignment = std::align_val_t(sizeof(void*)); + } + + return std::__libcpp_aligned_alloc (static_cast(alignment), size); + } +} + +_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE +[[gnu::weak]] +void* operator new (std::size_t size, std::align_val_t alignment) +{ + void* p = operator_new_aligned_impl (size, alignment); + if (p == nullptr) { + xamarin::android::Helpers::abort_application ("Out of memory in the aligned `new` operator"); + } + + return p; +} + +[[gnu::weak]] +void* operator new (size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + return operator_new_aligned_impl (size, alignment); +} + +_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE +[[gnu::weak]] +void* operator new[] (size_t size, std::align_val_t alignment) +{ + return ::operator new (size, alignment); +} + +[[gnu::weak]] +void* operator new[] (size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + return operator_new_aligned_impl (size, alignment); +} + +[[gnu::weak]] +void operator delete (void* ptr, std::align_val_t) noexcept +{ + std::__libcpp_aligned_free(ptr); +} + +[[gnu::weak]] +void operator delete (void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + ::operator delete(ptr, alignment); +} + +[[gnu::weak]] +void operator delete (void* ptr, size_t, std::align_val_t alignment) noexcept +{ + ::operator delete(ptr, alignment); +} + +[[gnu::weak]] +void operator delete[] (void* ptr, std::align_val_t alignment) noexcept +{ + ::operator delete(ptr, alignment); +} + +[[gnu::weak]] +void operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept +{ + ::operator delete[](ptr, alignment); +} + +[[gnu::weak]] void operator delete[] (void* ptr, size_t, std::align_val_t alignment) noexcept +{ + ::operator delete[](ptr, alignment); +} diff --git a/src/native/nativeaot/cxx-abi/terminate.cc b/src/native/nativeaot/cxx-abi/terminate.cc index 8a9700dad94..772eb2e5b5b 100644 --- a/src/native/nativeaot/cxx-abi/terminate.cc +++ b/src/native/nativeaot/cxx-abi/terminate.cc @@ -6,7 +6,7 @@ #include #include -#include "helpers.hh" +#include namespace std { [[noreturn]] void diff --git a/src/native/nativeaot/host/CMakeLists.txt b/src/native/nativeaot/host/CMakeLists.txt index 9f4ce16fb25..4bd9ceae924 100644 --- a/src/native/nativeaot/host/CMakeLists.txt +++ b/src/native/nativeaot/host/CMakeLists.txt @@ -14,6 +14,10 @@ if(DEBUG_BUILD) set(CMAKE_CXX_FLAGS_DEBUG ${XA_COMPILER_FLAGS_DEBUG}) endif() +# Extra source directories +set(LIBCXX_SOURCE_DIR "${THIRD_PARTY_SOURCE_DIR}/llvm/libcxx/src") +set(CXXABI_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../cxx-abi) + # Library directories set(XA_LIBRARY_OUTPUT_DIRECTORY "${XA_LIB_TOP_DIR}/lib/${ANDROID_RID}") @@ -35,6 +39,15 @@ set(XAMARIN_MONODROID_SOURCES ../runtime-base/android-system.cc + # libc++ sources + ${LIBCXX_SOURCE_DIR}/thread.cpp + ${LIBCXX_SOURCE_DIR}/verbose_abort.cpp + + # C++ ABI sources + ${CXXABI_SOURCE_DIR}/new.cc + ${CXXABI_SOURCE_DIR}/string.cc + ${CXXABI_SOURCE_DIR}/terminate.cc + # Sources from CoreCLR host ${CLR_SOURCES_PATH}/host/bridge-processing.cc ${CLR_SOURCES_PATH}/host/gc-bridge.cc From 067ddcfc8a63fe543a15a4a958b6bc3c28d2a7dc Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 12 Jan 2026 19:16:22 +0100 Subject: [PATCH 09/10] Not there --- src/native/nativeaot/host/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/native/nativeaot/host/CMakeLists.txt b/src/native/nativeaot/host/CMakeLists.txt index 4bd9ceae924..78670aba9f5 100644 --- a/src/native/nativeaot/host/CMakeLists.txt +++ b/src/native/nativeaot/host/CMakeLists.txt @@ -40,7 +40,6 @@ set(XAMARIN_MONODROID_SOURCES ../runtime-base/android-system.cc # libc++ sources - ${LIBCXX_SOURCE_DIR}/thread.cpp ${LIBCXX_SOURCE_DIR}/verbose_abort.cpp # C++ ABI sources From fbfb35f579b857ea1b2ea874380b7fdbc31ef6cf Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 12 Jan 2026 19:21:36 +0100 Subject: [PATCH 10/10] Better, but still broken. TBC tomorrow --- src/native/nativeaot/host/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/native/nativeaot/host/CMakeLists.txt b/src/native/nativeaot/host/CMakeLists.txt index 78670aba9f5..5a542111ace 100644 --- a/src/native/nativeaot/host/CMakeLists.txt +++ b/src/native/nativeaot/host/CMakeLists.txt @@ -16,6 +16,7 @@ endif() # Extra source directories set(LIBCXX_SOURCE_DIR "${THIRD_PARTY_SOURCE_DIR}/llvm/libcxx/src") +set(BIONIC_SOURCE_DIR "${THIRD_PARTY_SOURCE_DIR}/bionic") set(CXXABI_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../cxx-abi) # Library directories @@ -39,6 +40,9 @@ set(XAMARIN_MONODROID_SOURCES ../runtime-base/android-system.cc + # Bionic sources + ${BIONIC_SOURCE_DIR}//cxa_guard.cc + # libc++ sources ${LIBCXX_SOURCE_DIR}/verbose_abort.cpp