diff --git a/tests/test-libraries/Makefile b/tests/test-libraries/Makefile
index 325962426d..34adc5835c 100644
--- a/tests/test-libraries/Makefile
+++ b/tests/test-libraries/Makefile
@@ -1,7 +1,7 @@
TOP=../..
include $(TOP)/Make.config
-SUBDIRS += custom-type-assembly
+SUBDIRS += custom-type-assembly frameworks
# without this many compiler warnings about unused functions and variables
# in system headers show up.
diff --git a/tests/test-libraries/frameworks/Info-iphoneos.plist b/tests/test-libraries/frameworks/Info-iphoneos.plist
new file mode 100644
index 0000000000..cb2329386c
--- /dev/null
+++ b/tests/test-libraries/frameworks/Info-iphoneos.plist
@@ -0,0 +1,57 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleIdentifier
+ xamarin.ios.%NAME%
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ %NAME%
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 3.12
+ NSPrincipalClass
+
+ CFBundleExecutable
+ %NAME%
+ BuildMachineOSBuild
+ 13F34
+ CFBundleDevelopmentRegion
+ en
+ CFBundleSupportedPlatforms
+
+ iPhoneOS
+
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ DTPlatformBuild
+ 12D508
+ DTPlatformName
+ iphoneos
+ DTPlatformVersion
+ 8.2
+ DTSDKBuild
+ 12D508
+ DTSDKName
+ iphoneos8.2
+ DTXcode
+ 0620
+ DTXcodeBuild
+ 6C131e
+ MinimumOSVersion
+ 8.1
+ UIDeviceFamily
+
+ 1
+ 2
+
+
+
diff --git a/tests/test-libraries/frameworks/Info-iphonesimulator.plist b/tests/test-libraries/frameworks/Info-iphonesimulator.plist
new file mode 100644
index 0000000000..cb2329386c
--- /dev/null
+++ b/tests/test-libraries/frameworks/Info-iphonesimulator.plist
@@ -0,0 +1,57 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleIdentifier
+ xamarin.ios.%NAME%
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ %NAME%
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 3.12
+ NSPrincipalClass
+
+ CFBundleExecutable
+ %NAME%
+ BuildMachineOSBuild
+ 13F34
+ CFBundleDevelopmentRegion
+ en
+ CFBundleSupportedPlatforms
+
+ iPhoneOS
+
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ DTPlatformBuild
+ 12D508
+ DTPlatformName
+ iphoneos
+ DTPlatformVersion
+ 8.2
+ DTSDKBuild
+ 12D508
+ DTSDKName
+ iphoneos8.2
+ DTXcode
+ 0620
+ DTXcodeBuild
+ 6C131e
+ MinimumOSVersion
+ 8.1
+ UIDeviceFamily
+
+ 1
+ 2
+
+
+
diff --git a/tests/test-libraries/frameworks/Info-mac.plist b/tests/test-libraries/frameworks/Info-mac.plist
new file mode 100644
index 0000000000..b3aa891a71
--- /dev/null
+++ b/tests/test-libraries/frameworks/Info-mac.plist
@@ -0,0 +1,48 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleIdentifier
+ xamarin.ios.%NAME%
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ %NAME%
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 3.12
+ NSPrincipalClass
+
+ CFBundleExecutable
+ %NAME%
+ BuildMachineOSBuild
+ 13F34
+ CFBundleDevelopmentRegion
+ en
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ DTPlatformBuild
+ 12D508
+ DTPlatformName
+ macosx
+ DTPlatformVersion
+ 10.9
+ DTSDKBuild
+ 12D508
+ DTSDKName
+ macosx10.9
+ DTXcode
+ 0620
+ DTXcodeBuild
+ 6C131e
+ LSMinimumSystemVersion
+ 10.9
+
+
diff --git a/tests/test-libraries/frameworks/Info-maccatalyst.plist b/tests/test-libraries/frameworks/Info-maccatalyst.plist
new file mode 100644
index 0000000000..bb3db7a811
--- /dev/null
+++ b/tests/test-libraries/frameworks/Info-maccatalyst.plist
@@ -0,0 +1,48 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleIdentifier
+ xamarin.ios.%NAME%
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ %NAME%
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 3.12
+ NSPrincipalClass
+
+ CFBundleExecutable
+ %NAME%
+ BuildMachineOSBuild
+ 13F34
+ CFBundleDevelopmentRegion
+ en
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ DTPlatformBuild
+ 12D508
+ DTPlatformName
+ macosx
+ DTPlatformVersion
+ 10.15
+ DTSDKBuild
+ 12D508
+ DTSDKName
+ macosx10.15
+ DTXcode
+ 0620
+ DTXcodeBuild
+ 6C131e
+ LSMinimumSystemVersion
+ 10.15
+
+
diff --git a/tests/test-libraries/frameworks/Info-tvos.plist b/tests/test-libraries/frameworks/Info-tvos.plist
new file mode 100644
index 0000000000..96779468cd
--- /dev/null
+++ b/tests/test-libraries/frameworks/Info-tvos.plist
@@ -0,0 +1,56 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleIdentifier
+ xamarin.ios.%NAME%
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ %NAME%
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 3.12
+ NSPrincipalClass
+
+ CFBundleExecutable
+ %NAME%
+ BuildMachineOSBuild
+ 13F34
+ CFBundleDevelopmentRegion
+ en
+ CFBundleSupportedPlatforms
+
+ AppleTVOS
+
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ DTPlatformBuild
+ 12D508
+ DTPlatformName
+ appletvos
+ DTPlatformVersion
+ 9.0
+ DTSDKBuild
+ 12D508
+ DTSDKName
+ appletvos9.0
+ DTXcode
+ 0620
+ DTXcodeBuild
+ 6C131e
+ MinimumOSVersion
+ 9.0
+ UIDeviceFamily
+
+ 3
+
+
+
diff --git a/tests/test-libraries/frameworks/Info-tvsimulator.plist b/tests/test-libraries/frameworks/Info-tvsimulator.plist
new file mode 100644
index 0000000000..96779468cd
--- /dev/null
+++ b/tests/test-libraries/frameworks/Info-tvsimulator.plist
@@ -0,0 +1,56 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleIdentifier
+ xamarin.ios.%NAME%
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ %NAME%
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 3.12
+ NSPrincipalClass
+
+ CFBundleExecutable
+ %NAME%
+ BuildMachineOSBuild
+ 13F34
+ CFBundleDevelopmentRegion
+ en
+ CFBundleSupportedPlatforms
+
+ AppleTVOS
+
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ DTPlatformBuild
+ 12D508
+ DTPlatformName
+ appletvos
+ DTPlatformVersion
+ 9.0
+ DTSDKBuild
+ 12D508
+ DTSDKName
+ appletvos9.0
+ DTXcode
+ 0620
+ DTXcodeBuild
+ 6C131e
+ MinimumOSVersion
+ 9.0
+ UIDeviceFamily
+
+ 3
+
+
+
diff --git a/tests/test-libraries/frameworks/Info-watchos.plist b/tests/test-libraries/frameworks/Info-watchos.plist
new file mode 100644
index 0000000000..2ae197bc92
--- /dev/null
+++ b/tests/test-libraries/frameworks/Info-watchos.plist
@@ -0,0 +1,56 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleIdentifier
+ xamarin.ios.%NAME%
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ %NAME%
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 3.12
+ NSPrincipalClass
+
+ CFBundleExecutable
+ %NAME%
+ BuildMachineOSBuild
+ 13F34
+ CFBundleDevelopmentRegion
+ en
+ CFBundleSupportedPlatforms
+
+ WatchOS
+
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ DTPlatformBuild
+ 12D508
+ DTPlatformName
+ watchos
+ DTPlatformVersion
+ 2.0
+ DTSDKBuild
+ 12D508
+ DTSDKName
+ watchos2.0
+ DTXcode
+ 0620
+ DTXcodeBuild
+ 6C131e
+ MinimumOSVersion
+ 2.0
+ UIDeviceFamily
+
+ 4
+
+
+
diff --git a/tests/test-libraries/frameworks/Info-watchsimulator.plist b/tests/test-libraries/frameworks/Info-watchsimulator.plist
new file mode 100644
index 0000000000..2ae197bc92
--- /dev/null
+++ b/tests/test-libraries/frameworks/Info-watchsimulator.plist
@@ -0,0 +1,56 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleIdentifier
+ xamarin.ios.%NAME%
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ %NAME%
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 3.12
+ NSPrincipalClass
+
+ CFBundleExecutable
+ %NAME%
+ BuildMachineOSBuild
+ 13F34
+ CFBundleDevelopmentRegion
+ en
+ CFBundleSupportedPlatforms
+
+ WatchOS
+
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ DTPlatformBuild
+ 12D508
+ DTPlatformName
+ watchos
+ DTPlatformVersion
+ 2.0
+ DTSDKBuild
+ 12D508
+ DTSDKName
+ watchos2.0
+ DTXcode
+ 0620
+ DTXcodeBuild
+ 6C131e
+ MinimumOSVersion
+ 2.0
+ UIDeviceFamily
+
+ 4
+
+
+
diff --git a/tests/test-libraries/frameworks/Makefile b/tests/test-libraries/frameworks/Makefile
new file mode 100644
index 0000000000..0cbe2e07cf
--- /dev/null
+++ b/tests/test-libraries/frameworks/Makefile
@@ -0,0 +1,192 @@
+TOP=../../..
+include $(TOP)/Make.config
+
+# These frameworks are used by the test nugets (which are then used in the BundleStructure test)
+NAMES+=FrameworksInRuntimesNativeDirectory1 FrameworksInRuntimesNativeDirectory2
+# These frameworks are used in the BundleStructure test
+NAMES+=FrameworkTest1 FrameworkTest2 FrameworkTest3 FrameworkTest4 FrameworkTest5
+NAMES+=UnknownD UnknownE UnknownF1 UnknownF2 SomewhatUnknownD SomewhatUnknownE SomewhatUnknownF1 SomewhatUnknownF2
+
+# a few lookup tables, because the data we have is not always in the format we need it
+
+COMMON_DYLIB_ARGS=-g -dynamiclib -gdwarf-2 -fms-extensions shared.c -Wall -framework Foundation -lz
+iphonesimulator_DYLIB_FLAGS=$(COMMON_DYLIB_ARGS) -mios-simulator-version-min=8.0 -isysroot $(SIMULATOR_SDK)
+iphoneos_DYLIB_FLAGS=$(COMMON_DYLIB_ARGS) -miphoneos-version-min=8.0 -isysroot $(DEVICE_SDK)
+tvsimulator_DYLIB_FLAGS=$(COMMON_DYLIB_ARGS) -mtvos-simulator-version-min=9.0 -isysroot $(SIMULATORTV_SDK)
+tvos_DYLIB_FLAGS=$(COMMON_DYLIB_ARGS) -mtvos-version-min=9.0 -fembed-bitcode -isysroot $(DEVICETV_SDK)
+maccatalyst_DYLIB_FLAGS=$(COMMON_DYLIB_ARGS) $(MACCATALYST_COMMON_CFLAGS)
+mac_DYLIB_FLAGS=$(COMMON_DYLIB_ARGS) -mmacosx-version-min=$(MIN_OSX_VERSION_FOR_MAC) -isysroot $(XCODE_DEVELOPER_ROOT)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX$(OSX_SDK_VERSION).sdk
+
+maccatalyst-x64_DYLIB_FLAGS=$(MACCATALYST_X86_64_CFLAGS)
+maccatalyst-arm64_DYLIB_FLAGS=$(MACCATALYST_ARM64_CFLAGS)
+
+iossimulator-x64_ARCHITECTURES=x86_64
+iossimulator-arm64_ARCHITECTURES=arm64
+iossimulator-x86_ARCHITECTURES=i386
+ios-arm_ARCHITECTURES=armv7 armv7s
+ios-arm64_ARCHITECTURES=arm64
+tvossimulator-x64_ARCHITECTURES=x86_64
+tvossimulator-arm64_ARCHITECTURES=arm64
+tvos-arm64_ARCHITECTURES=arm64
+osx-x64_ARCHITECTURES=x86_64
+osx-arm64_ARCHITECTURES=arm64
+maccatalyst-x64_ARCHITECTURES=x86_64
+maccatalyst-arm64_ARCHITECTURES=arm64
+
+mac_SYMLINKS=1
+mac_INFO_PLIST_INFIX=/Versions/A/Resources
+mac_BINARY_INFIX=/Versions/A
+maccatalyst_SYMLINKS=1
+maccatalyst_INFO_PLIST_INFIX=/Versions/A/Resources
+maccatalyst_BINARY_INFIX=/Versions/A
+
+# For XCFrameworks, we have to lipo some of the RID-specific frameworks together (the ones with multiple RIDs below)
+iphonesimulator_XC_RUNTIMEIDENTIFIERS=iossimulator-x86 iossimulator-x64 iossimulator-arm64
+iphoneos_XC_RUNTIMEIDENTIFIERS=ios-arm ios-arm64
+tvsimulator_XC_RUNTIMEIDENTIFIERS=tvossimulator-x64 tvossimulator-arm64
+tvos_XC_RUNTIMEIDENTIFIERS=tvos-arm64
+mac_XC_RUNTIMEIDENTIFIERS=osx-x64 osx-arm64
+maccatalyst_XC_RUNTIMEIDENTIFIERS=maccatalyst-x64 maccatalyst-arm64
+
+ifeq ($(V),)
+ZIP=zip --symlinks --quiet
+else
+ZIP=zip --symlinks
+endif
+
+define FrameworkTemplate
+
+$(1)_$(3)_TARGETS += \
+ .libs/$(3)/$(1).framework$($(2)_BINARY_INFIX)/$(1) \
+ .libs/$(3)/$(1).framework$($(2)_INFO_PLIST_INFIX)/Info.plist \
+ .libs/$(3)/lib$(1).dylib \
+ .libs/$(3)/$(1).framework \
+
+ifeq ($($(2)_SYMLINKS),1)
+$(1)_$(3)_TARGETS += \
+ .libs/$(3)/$(1).framework/$(1) \
+ .libs/$(3)/$(1).framework/Resources \
+ .libs/$(3)/$(1).framework/Versions/Current \
+ .libs/$(3)/$(1).framework/Versions/A/Resources/Info.plist \
+
+endif
+
+$(3)_TARGETS += \
+ $($(1)_$(3)_TARGETS) \
+ .libs/$(3)/$(1).framework.stamp \
+
+all-local:: $$($(3)_TARGETS)
+
+.libs/$(3)/$(1).framework.stamp: $$($(1)_$(3)_TARGETS)
+ $$(Q) touch $$@
+
+.libs/$(3)/lib$(1).dylib: shared.c | .libs/$(3)
+ $$(call Q_2,CC, [$(3)]) $$(XCODE_CC) -o $$@ $$(foreach arch,$$($(3)_ARCHITECTURES),-arch $$(arch)) $$($(2)_DYLIB_FLAGS) $$($(3)_DYLIB_FLAGS) -DNAME=$(1)
+ $$(Q) $(XCODE_DEVELOPER_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/install_name_tool -id @rpath/lib$(1).dylib $$@
+
+.libs/$(3)/$(1).framework$($(2)_BINARY_INFIX)/$(1): .libs/$(3)/lib$(1).dylib | .libs/$(3)/$(1).framework$($(2)_BINARY_INFIX)
+ $$(Q) $(CP) $$^ $$@
+ $$(Q) $(XCODE_DEVELOPER_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/install_name_tool -id @rpath/$(1).framework/$(1) $$@
+
+.libs/$(3)/$(1).framework$($(2)_INFO_PLIST_INFIX)/Info.plist: Info-$(2).plist | .libs/$(3)/$(1).framework$($(2)_INFO_PLIST_INFIX)
+ $$(Q) sed 's/%NAME%/$(1)/g' $$^ > $$@
+
+$(3)_$(1)_DIRECTORIES = \
+ .libs/$(3)/$(1).framework \
+ .libs/$(3)/$(1).framework/Versions \
+
+$$($(3)_$(1)_DIRECTORIES):
+ $$(Q) mkdir -p $$@
+
+.libs/$(3)/$(1).framework.zip: $$($(3)_TARGETS)
+ $$(Q_ZIP) cd $$(dir $$@) && $(ZIP) -r $$(notdir $$@) $(1).framework
+
+ZIPPED_TARGETS += .libs/$(3)/$(1).framework.zip
+
+# some additional targets if the framework has macOS-like structure (i.e. has symlinks)
+ifeq ($($(2)_SYMLINKS),1)
+.libs/$(3)/$(1).framework$($(2)_BINARY_INFIX) .libs/$(3)/$(1).framework$($(2)_INFO_PLIST_INFIX):
+ $$(Q) mkdir -p $$@
+
+.libs/$(3)/$(1).framework/$(1): | .libs/$(3)/$(1).framework
+ $$(Q) ln -fs Versions/A/$(1) $$@
+
+.libs/$(3)/$(1).framework/Resources: | .libs/$(3)/$(1).framework
+ $$(Q) ln -fs Versions/Current/Resources $$@
+
+.libs/$(3)/$(1).framework/Versions/Current: | .libs/$(3)/$(1).framework/Versions
+ $$(Q) ln -fs A $$@
+endif
+
+# create binding resource package
+
+.libs/$(3)/$(1).resources/manifest: .libs/$(3)/$(1).framework.zip manifest-framework.in
+ $$(Q) mkdir -p .libs/$(3)/$(1).resources
+ $$(Q) rm -Rf .libs/$(3)/$(1).resources/$(1).framework
+ $$(Q) $$(CP) -R .libs/$(3)/$(1).framework .libs/$(3)/$(1).resources/
+ $$(Q) sed 's/%NAME%/$(1)/g' manifest-framework.in > $$@
+
+.libs/$(3)/$(1).resources.zip: .libs/$(3)/$(1).resources/manifest
+ $$(Q) rm -f $$@
+ $$(Q_ZIP) cd .libs/$(3)/$(1).resources && $(ZIP) -r $$(abspath .libs/$(3)/$(1).resources.zip) .
+
+## a binding resource package needs an adjacent assembly to be considered a binding resource package, so create a dummy assembly.
+.libs/$(3)/$(1).dll:
+ $$(Q) printf "Fake assembly named $(3)\n" > $$@
+
+$(3)_BINDING_RESOURCE_PACKAGE_TARGETS += \
+ .libs/$(3)/$(1).resources/manifest \
+ .libs/$(3)/$(1).resources.zip \
+ .libs/$(3)/$(1).dll \
+
+all-local:: $$($(3)_BINDING_RESOURCE_PACKAGE_TARGETS)
+endef
+
+# 1: name
+# 2: sdk platform (iphoneos, iphonesimulator, tvos, tvsimulator, maccatalyst, mac)
+# 3: runtime identifier
+$(foreach name,$(NAMES),$(foreach platform,$(DOTNET_PLATFORMS),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(eval $(call FrameworkTemplate,$(name),$(DOTNET_$(rid)_SDK_PLATFORM),$(rid))))))
+
+define XCTemplate
+.libs/$(3)/$(1).framework.stamp: $$(foreach rid,$$($(3)_XC_RUNTIMEIDENTIFIERS),.libs/$$(rid)/$(1).framework.stamp) | .libs/$(3)
+ $$(Q) rm -Rf .libs/$(3)/$(1).framework
+ $$(Q) $(CP) -R .libs/$$(firstword $$($(3)_XC_RUNTIMEIDENTIFIERS))/$(1).framework .libs/$(3)/$(1).framework
+ifneq ($$(words $($(3)_XC_RUNTIMEIDENTIFIERS)),1)
+ $$(Q) $(XCODE_DEVELOPER_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo $$(foreach rid,$$($(3)_XC_RUNTIMEIDENTIFIERS),.libs/$$(rid)/$(1).framework$($(3)_BINARY_INFIX)/$(1)) -create -output .libs/$(3)/$(1).framework$($(3)_BINARY_INFIX)/$(1)
+endif
+ $$(Q) touch $$@
+
+$(1)_XCPLATFORMS += $(3)
+$(1)_XCTARGETS += .libs/$(3)/$(1).framework.stamp
+$(1)_XCFRAMEWORKS += -framework .libs/$(3)/$(1).framework
+endef
+
+# 1: name
+# 2: sdk platform (iphoneos, iphonesimulator, tvos, tvsimulator, maccatalyst, mac)
+# 3: platform as used by xcframework
+$(foreach name,$(NAMES),$(foreach platform,$(DOTNET_PLATFORMS),$(foreach xcplatform,$(DOTNET_$(platform)_SDK_PLATFORMS),$(eval $(call XCTemplate,$(name),$(platform),$(xcplatform))))))
+
+$(foreach platform,$(DOTNET_PLATFORMS),$(foreach xcplatform,$(DOTNET_$(platform)_SDK_PLATFORMS),.libs/$(xcplatform))):
+ $(Q) mkdir -p $@
+
+$(foreach platform,$(DOTNET_PLATFORMS),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),.libs/$(rid))):
+ $(Q) mkdir -p $@
+
+define XCFrameworkTemplate
+.libs/$(1).xcframework.stamp: $$($(1)_XCTARGETS) Makefile
+ $$(Q) rm -rf .libs/$(1).xcframework
+ $$(Q_GEN) $(XCODE_DEVELOPER_ROOT)/usr/bin/xcodebuild -quiet -create-xcframework $$($(1)_XCFRAMEWORKS) -output .libs/$(1).xcframework
+ $$(Q) touch $$@
+
+.libs/$(1).xcframework.zip: .libs/$(1).xcframework.stamp
+ $$(Q_ZIP) cd $$(dir $$@) && $(ZIP) -r $$(notdir $$@) $(1).xcframework
+
+ZIPPED_TARGETS += .libs/$(1).xcframework.zip
+
+all-local:: .libs/$(1).xcframework.stamp
+endef
+
+$(foreach name,$(NAMES),$(eval $(call XCFrameworkTemplate,$(name))))
+
+zip: $(ZIPPED_TARGETS)
+all-local:: $(ZIPPED_TARGETS)
diff --git a/tests/test-libraries/frameworks/README.md b/tests/test-libraries/frameworks/README.md
new file mode 100644
index 0000000000..67df8708af
--- /dev/null
+++ b/tests/test-libraries/frameworks/README.md
@@ -0,0 +1,14 @@
+# Test libraries
+
+This directory contains the logic to build multiple very simple native
+frameworks (.framework), xc frameworks (.xcframework) and plugins (.bundle).
+
+For each NAME in the NAMES variable in the Makefile, the makefile will create
+a framework/xcframework/plugin with a dynamic library that exports a single
+getNAME function which returns a constant char* value "NAME".
+
+The point is to have numerous test frameworks/plugins that can be included in
+the same project for testing how our build logic with regards to native
+libraries.
+
+A binding resource package is also created for each framework (but not plugin).
diff --git a/tests/test-libraries/frameworks/manifest-framework.in b/tests/test-libraries/frameworks/manifest-framework.in
new file mode 100644
index 0000000000..348940349b
--- /dev/null
+++ b/tests/test-libraries/frameworks/manifest-framework.in
@@ -0,0 +1,12 @@
+
+
+ Framework
+
+ False
+
+
+
+
+
+
+
diff --git a/tests/test-libraries/frameworks/shared.c b/tests/test-libraries/frameworks/shared.c
new file mode 100644
index 0000000000..dbb41f82f7
--- /dev/null
+++ b/tests/test-libraries/frameworks/shared.c
@@ -0,0 +1,5 @@
+
+#define PASTER(y) extern const char * get ## y () { return # y; }
+#define CREATE_FUNC(name) PASTER(name)
+
+CREATE_FUNC(NAME)