Ld64.lld: undefined symbol: close (and memcpy/memset/etc.) linking on macOS 26 (Xcode 26.2 SDK)

Since updating to macOS 26.6.2 with Xcode 26.2, Crystal fails to link any program — even a trivial puts "hello" — with undefined symbol errors for basic libc functions.

Environment

crystal --version
Crystal 1.21.0 (2026-07-16)
LLVM: 22.1.8
Default target: aarch64-apple-macosx26.0

sw_vers
ProductVersion: 26.6.2
BuildVersion:   25G83

xcode-select -p
/Applications/Xcode_26.2.app/Contents/Developer

Installed via Homebrew (crystal 1.21.0_1).

Repro

echo 'puts "hello"' > hello.cr
crystal build hello.cr

Error

ld64.lld: error: undefined symbol: close
>>> referenced by mach_o.cr:82 (.../crystal/src/crystal/system/unix/mach_o.cr:82)
>>>               E-xception5858C-allS-tack.o0.o:(symbol *Exception::CallStack::load_debug_info_impl:Nil+0xab8)
>>> referenced 18 more times

ld64.lld: error: too many errors emitted, stopping now
clang: error: linker command failed with exit code 1

Undefined symbols also include memcpy, memset, memcmp, and _Unwind_Backtrace — basically every libc/libunwind symbol the runtime needs, which suggests ld64.lld isn’t resolving libSystem.tbd at all on this SDK version.

Workaround

Forcing Apple’s linker instead of lld fixes it:

crystal build hello.cr --link-flags="-fuse-ld=ld"

Question

Has anyone else hit this on macOS 26? I couldn’t find it reported here or on the GitHub issue tracker yet. Given lld’s history of lagging behind new Xcode SDK TAPI (.tbd) formats (this bit Rust recently too — rust-lang/rust#162928), my guess is the Homebrew formula’s default -fuse-ld=lld needs to fall back to system ld on newer SDKs, or bump its bundled LLVM. Happy to provide more diagnostics if useful.

hit the same class of thing with rust recently, your diagnosis is right. the bundled ld64.lld just cant parse the newer tbd format in the xcode 26.2 sdk, so libsystem never resolves and every libc symbol goes missing. the -fuse-ld=ld workaround is the right call for now. worth filing an issue on the crystal repo so the homebrew formula can flip the default or bump its llvm, since more people will run into this as they update xcode.