diff --git a/.gitignore b/.gitignore
index 6be74c99e8bc..b02321a54319 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+Build.props
Make.config.inc
Make.config.local
configure.inc
diff --git a/Directory.Build.props b/Directory.Build.props
index 3ceefd256418..0d4329c77a70 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -3,4 +3,5 @@
true
+
diff --git a/Make.config b/Make.config
index 4e5873937c81..f9edbe8d8b14 100644
--- a/Make.config
+++ b/Make.config
@@ -205,6 +205,21 @@ XCODE_URL=https://dl.internalx.com/internal-files/xcodes/Xcode_14.3.1.xip
XCODE_DEVELOPER_ROOT=/Applications/Xcode_14.3.1.app/Contents/Developer
XCODE_PRODUCT_BUILD_VERSION:=$(shell /usr/libexec/PlistBuddy -c 'Print :ProductBuildVersion' $(XCODE_DEVELOPER_ROOT)/../version.plist 2>/dev/null || echo " $(shell tput setaf 1 2>/dev/null)The required Xcode ($(XCODE_VERSION)) is not installed in $(basename $(basename $(XCODE_DEVELOPER_ROOT)))$(shell tput sgr0 2>/dev/null)" >&2)
+# We define stable Xcode as the Xcode app being named like "Xcode_#.#[.#].app"
+# and any other naming is deemed to be a beta. This is the safer approach: any
+# errors are likely to be Xcode classified as a beta, when it's not, and in that
+# case we'll accidentally release a prerelease version. This is not a problem:
+# we fix it, and release the fixed version to stable. The opposite scenario is
+# worse: when we release something as stable when it shouldn't be, so let's
+# try to avoid that.
+ifeq (OK,$(shell echo $(notdir $(abspath $(dir $(abspath $(dir $(XCODE_DEVELOPER_ROOT)))))) | sed -e 's/^Xcode[_0-9.]*[.]app$$/OK/'))
+XCODE_IS_STABLE=true
+XCODE_IS_PREVIEW=false
+else
+XCODE_IS_STABLE=false
+XCODE_IS_PREVIEW=true
+endif
+
# Tell both Xcode and our build logic which Xcode we're using.
export DEVELOPER_DIR=$(XCODE_DEVELOPER_ROOT)
export MD_APPLE_SDK_ROOT=$(abspath $(XCODE_DEVELOPER_ROOT)/../..)
@@ -597,13 +612,28 @@ ALL_PLATFORMS=iOS tvOS watchOS macOS
ALL_DOTNET_PLATFORMS=iOS macOS tvOS MacCatalyst
-include $(TOP)/dotnet.config
-$(TOP)/dotnet.config: $(TOP)/eng/Versions.props
+$(TOP)/dotnet.config: $(TOP)/eng/Versions.props $(TOP)/Build.props
$(Q) grep MicrosoftDotnetSdkInternalPackageVersion $(TOP)/eng/Versions.props | sed -e 's/<*\/*MicrosoftDotnetSdkInternalPackageVersion>//g' -e 's/[ \t]*/DOTNET_VERSION=/' >> $@.tmp
$(Q) grep MicrosoftNETCoreAppRefPackageVersion $(TOP)/eng/Versions.props | sed -e 's/<*\/*MicrosoftNETCoreAppRefPackageVersion>//g' -e 's/[ \t]*/BUNDLED_NETCORE_PLATFORMS_PACKAGE_VERSION=/' >> $@.tmp
$(Q) grep "<$$(grep EmscriptenWorkloadVersion $(TOP)/eng/Versions.props | sed -e 's_.*>$$[\(]\(.*\)[\)]<.*_\1_')>" $(TOP)/eng/Versions.props | sed -e 's/.*>\(.*\)<.*/EMSCRIPTEN_MANIFEST_PACKAGE_VERSION=\1/' >> $@.tmp
$(Q) $(foreach platform,$(ALL_DOTNET_PLATFORMS),grep Microsoft$(platform)SdkPackageVersion $(TOP)/eng/Versions.props | sed -e 's/<*\/*Microsoft$(platform)SdkPackageVersion>//g' -e 's/[ \t]*/NET7_$(shell echo $(platform) | tr '[:lower:]' '[:upper:]')_NUGET_VERSION_NO_METADATA=/' >> $@.tmp &&) true
$(Q) mv $@.tmp $@
+$(TOP)/Build.props: Make.config
+ $(Q) rm -f $@.tmp
+ $(Q) printf "\n" >> $@.tmp
+ $(Q) printf "\t\n" >> $@.tmp
+ifeq ($(XCODE_IS_STABLE),true)
+ # do nothing
+else ifeq ($(XCODE_IS_STABLE),false)
+ $(Q) printf "\t\ttrue\n" >> $@.tmp
+else
+ $(error "The variable XCODE_IS_STABLE is not set!")
+endif
+ $(Q) printf "\t\n" >> $@.tmp
+ $(Q) printf "\n" >> $@.tmp
+ $(Q) mv $@.tmp $@
+
DOTNET_DESTDIR ?= $(TOP)/_build
DOTNET_NUPKG_DIR ?= $(DOTNET_DESTDIR)/nupkgs
DOTNET_PKG_DIR ?= $(DOTNET_DESTDIR)/pkgs
diff --git a/dotnet/Makefile b/dotnet/Makefile
index bf6bd324f0b1..285e3eaad713 100644
--- a/dotnet/Makefile
+++ b/dotnet/Makefile
@@ -102,6 +102,7 @@ targets/Microsoft.$(1).Sdk.Versions.props: targets/Microsoft.Sdk.Versions.templa
-e 's*@VALID_RUNTIME_IDENTIFIERS@*$(foreach rid,$(3),\n\t\t<_XamarinValidRuntimeIdentifier Include="$(rid)" Platform="$(1)" />)*' \
-e 's/@DOTNET_TFM@/$(DOTNET_TFM)/g' \
-e 's/@RUNTIME_PACK_RUNTIME_IDENTIFIERS@/$(4)/g' \
+ -e 's/@XCODE_IS_PREVIEW@/$(XCODE_IS_PREVIEW)/g' \
$$< > $$@.tmp
$$(Q) mv $$@.tmp $$@
diff --git a/dotnet/targets/Microsoft.Sdk.Versions.template.props b/dotnet/targets/Microsoft.Sdk.Versions.template.props
index 40aa4d8e0130..30a53269afdf 100644
--- a/dotnet/targets/Microsoft.Sdk.Versions.template.props
+++ b/dotnet/targets/Microsoft.Sdk.Versions.template.props
@@ -7,6 +7,7 @@
<_ShortPackageVersion>@NUGET_VERSION_NO_METADATA@
<_PackageVersion>@NUGET_VERSION_FULL@
<_DefaultTargetPlatformVersion>@DEFAULT_TARGET_PLATFORM_VERSION@
+ <_XamarinIsPreviewRelease>@XCODE_IS_PREVIEW@
@VALID_RUNTIME_IDENTIFIERS@
diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets
index 496a66b7537b..00dbae3c0073 100644
--- a/dotnet/targets/Xamarin.Shared.Sdk.targets
+++ b/dotnet/targets/Xamarin.Shared.Sdk.targets
@@ -889,8 +889,16 @@
+
+
+
+
<_ComputeVariablesDependsOn>
+ _VerifyPreviewFeaturesIfUnstableXcode;
_VerifyValidRuntime;
_GenerateBundleName;
_ComputeFrameworkVariables;
diff --git a/msbuild/Directory.Build.props b/msbuild/Directory.Build.props
index a9df2a6de115..671391e88d3b 100644
--- a/msbuild/Directory.Build.props
+++ b/msbuild/Directory.Build.props
@@ -3,4 +3,5 @@
1.10.37
1.0.119
+