diff --git a/conf/machine-sdk/darwin-common.inc b/conf/machine-sdk/darwin-common.inc
index 1e3f03b..a23c605 100644
--- a/conf/machine-sdk/darwin-common.inc
+++ b/conf/machine-sdk/darwin-common.inc
@@ -91,3 +91,9 @@ fakeroot create_macos_img() {
 # every nativesdk/cross-canadian compiler command line, and those end up in
 # headers (e.g. gmp.h's __GMP_CC), libraries and binaries.
 ERROR_QA:remove = "buildpaths"
+
+# gcc's built-in header search on Darwin only covers the OS SDK include tree
+# (.../runtime/usr/include); headers staged by our own nativesdk recipes live
+# one level up and are only found via an explicit -I. Do this for every
+# nativesdk recipe instead of per recipe (see e.g. curl, nettle).
+CPPFLAGS:append:class-nativesdk = " -I${STAGING_INCDIR}"
diff --git a/recipes-devtools/clang/llvm_%.bbappend b/recipes-devtools/clang/llvm_%.bbappend
new file mode 100644
index 0000000..8565d67
--- /dev/null
+++ b/recipes-devtools/clang/llvm_%.bbappend
@@ -0,0 +1,15 @@
+# Unlike autotools recipes (nettle, curl), cmake.bbclass feeds CMAKE_C_FLAGS/
+# CMAKE_CXX_FLAGS from CFLAGS/CXXFLAGS only, not CPPFLAGS, so the usual
+# CPPFLAGS:append trick for missing nativesdk headers has no effect here.
+# zstd's headers are staged in the nested nativesdk sysroot, not the runtime
+# macOS SDK tree gcc's default search covers.
+CFLAGS:append:class-nativesdk:darwin21 = " -I${STAGING_INCDIR}"
+CXXFLAGS:append:class-nativesdk:darwin21 = " -I${STAGING_INCDIR}"
+
+# OSXSDK is only set in clang's own bbappend, which doesn't carry over to this
+# recipe's metadata, so redefine it here too.
+OSXSDK:class-nativesdk:darwin21 = "${STAGING_DIR_TARGET}${SDKPATHNATIVE}/runtime"
+
+# dsymutil (tools/dsymutil/CFBundle.cpp) needs the CoreFoundation framework;
+# frameworks need -F, not -I.
+CXXFLAGS:append:class-nativesdk:darwin21 = " -F${OSXSDK}/System/Library/Frameworks"
