Xcode 27 Removes ld64 and Requires Unique Module Names

Apple retired a linker in one sentence: “The ld64 linker has been removed and the -ld_classic option is no longer supported.”1 The flag now gone is a flag Apple told developers to add. Xcode 15’s own release notes offered -Wl,-ld_classic as the workaround for two linker bugs.3

TL;DR

  • Xcode 27 removes ld64 and stops accepting -ld_classic.1 Apple’s Xcode 15 notes prescribed the flag for weak-symbol crashes and LTO import bugs, Xcode 16 deprecated it, and Xcode 26 said nothing at all.3410
  • A second break sits in the Swift compiler. Apple made dependency scanning one shared action, so “every Clang module reachable from a single Swift dependency-scan action must have a unique module name.”2 Apple hedges twice: the scan “may report an error,” and previously the scanner “may have tolerated duplicating names.”2
  • Both fire on toolchain upgrade rather than a deployment target or SDK choice, and neither has a runtime component. The exposed population: vendored binaries, CocoaPods, or a large mixed Swift/Objective-C/C++ codebase.
  • Apple’s “may” is not editorial caution. Under Xcode 26.6 I put two module maps declaring one name on a single search path and ran the scanner 20 times: nine runs crashed with SIGSEGV, five aborted, and six finished cleanly.8
  • A vendored module map redeclaring an SDK module, the case Apple names, compiles silently today and hides the real module. My vendored SQLite3 shim typechecked with exit 0, and sqlite3_open stopped existing.8
  • Across seven audited projects: zero -ld_classic, OTHER_LDFLAGS unset everywhere, and zero duplicate module names among 391 module maps, because no repository holds a hand-authored one.9

Both notes ship in the Xcode 27 beta 4 release notes, alongside Swift 6.4 and the 27 SDKs.11 Read them as beta text.

The flag Apple told you to add

The story starts with a linker rewrite. Xcode 15 announced a new linker, made it the default “for all macOS, iOS, tvOS and visionOS binaries,” and set the terms of the retirement in one clause: “The classic linker can still be explicitly requested using -ld64, and will be removed in a future release.”3

The new linker arrived with bugs, and Apple documented the escape hatch twice on the same page. The first Known Issue: “Binaries using symbols with a weak definition crash at runtime on iOS 14/macOS 12 or older. This impacts primarily C++ projects due to their extensive use of weak symbols.” Apple’s workaround was to raise the deployment target “or add -Wl,-ld_classic to the OTHER_LDFLAGS build setting.”3 The second, covering LTO object files that linked weak symbol imports as non-weak, offered “-Wl,-weak_reference_mismatches,weak or -Wl,-ld_classic” in the same setting.3

Both bugs hit C++ projects hardest, which explains who still carries the flag. Nobody revisits a setting that stopped a crash.

Xcode 16 gave notice in one sentence: “-ld_classic linker option is deprecated and will be removed in a future release.”4 Then silence. I searched the Xcode 26 release notes for ld_classic, ld64, and the classic linker and found none.10

The current toolchain still accepts the flag and still complains. On Xcode 26.6 I linked a trivial C program with it:7

xcrun clang hello.c -o hello -Wl,-ld_classic
ld: warning: -ld_classic is deprecated and will be removed in a future release

Exit status zero. The binary links. Substituting -Wl,-ld64 produces the identical warning naming -ld_classic, so both spellings Apple used reach the same code path today.7 Apple’s Xcode 27 note names only -ld_classic, and I could not test whether -ld64 fails the same way.

One detail complicates the word “removed.” Xcode 26.6’s linker, asked to identify itself with xcrun ld -v, reports which architectures it delegates:7

@(#)PROGRAM:ld PROJECT:ld-1267
BUILD 16:38:58 Jun  8 2026
configured to support archs: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em armv8m.main armv8.1m.main
will use ld-classic for: armv6 armv7 armv7s i386 armv6m armv7k armv7m armv7em

ld-classic exists as a real binary in the toolchain, with its own man page, and the linker still routes eight architectures to it.7 None survives in a current app SDK: iPhoneOS 26.5 declares arm64e and arm64 only, and the watchOS SDK adds arm64_32.7 The list is 32-bit ARM, i386, and Cortex-M embedded targets. Reading their absence from the SDKs as the reason the removal is safe for app developers is my inference rather than Apple’s claim.

Finding the flag without trusting grep

-ld_classic lives in OTHER_LDFLAGS, so ask the build system what it resolves to rather than searching files for text:

xcodebuild -showBuildSettings \
  -project YourApp.xcodeproj \
  -configuration Release -sdk iphoneos 2>/dev/null \
  | grep -E "OTHER_LDFLAGS|SUPPORTED_PLATFORMS"

Against the Reps project one line comes back:9

    SUPPORTED_PLATFORMS = appletvos appletvsimulator iphoneos iphonesimulator macosx

OTHER_LDFLAGS does not appear at all, which is the answer: the setting is unset, so no linker flags reach the link step from it. Absence in resolved build settings carries information that absence in a text search does not. Read SUPPORTED_PLATFORMS for the platform question too, never a *_DEPLOYMENT_TARGET, which Xcode writes whether or not a destination is real.

Three traps produced false clean results during the audit, and all three print nothing and exit successfully. timeout does not exist on stock macOS, so wrapping xcodebuild in it returns exit 127 and empty output that reads like a project with no linker flags. Under zsh an unquoted --include=*.pbxproj gets glob-expanded before grep sees it, so the command dies with “no matches found” instead of reporting zero hits. And find does not follow a symlink given as its starting point, which matters because xcrun --sdk iphoneos --show-sdk-path returns one: find "$SDK" -name '*.modulemap' finds nothing, while find -H "$SDK" finds 266 files.9 Quote your patterns, pass -H, and confirm the command matches something you know is there before trusting a zero.

A hand-maintained target keeps the flag in project.pbxproj or an .xcconfig; a CocoaPods project can also receive it from a post_install hook, which no developer-edited file records. The fleet I audited has neither, so that last path went unverified.9

The module-name rule, and Apple’s two hedges

The second break arrives disguised as a performance win, filed under New Features rather than Deprecations. Apple’s Swift Compiler entry, in full:

The Swift dependency scanner has been optimized to avoid redundant setup work and header searches when looking up Clang modules during a single dependency-scan action, substantially improving scanning performance. As a consequence of this change, every Clang module reachable from a single Swift dependency-scan action must have a unique module name. If two module maps visible to the same scan declare a Clang module with the same name, the scan may report an error. Previously, the scanner may have tolerated duplicating names. The most common cases are projects or SDKs that vend the same Clang module name from more than one location on the header search path, and vendored third-party sources that ship a module.modulemap redeclaring an SDK module.2

Four things there deserve separating. Apple scopes the requirement to what one scan can reach, not your whole disk. Apple states the consequence as “may report an error,” and hedges the old behavior the same way. Apple names the two triggering shapes: one module name vended from two locations on the header search path, and a vendored module.modulemap redeclaring an SDK module. And the trigger is the toolchain, since nothing references a deployment target or SDK version.

The rule predates the optimization. Clang’s module map language states it plainly: “Each module shall have a single definition.”6 What the documentation never states is the consequence of breaking the rule, and that silence turns out to be well earned: the toolchain’s answer is not one behavior but several.

What a collision actually does

Apple’s hedges made me want to see the failure, so I built the smallest version: two directories, each with a module.modulemap declaring the same module.8

A/module.modulemap    B/module.modulemap
module Widget {       module Widget {
    header "widget.h"     header "widget.h"
    export *              export *
}                     }

With both directories on the search path, a plain typecheck fails the same way every time, 20 runs out of 20:8

B/module.modulemap:1:8: error: redefinition of module 'Widget'
1 | module Widget {
  |        `- error: redefinition of module 'Widget'
A/module.modulemap:1:8: note: previously defined here

redefinition of module is the string to search for in a build log, and Xcode 26.6’s clang already emits it. Dropping one search path makes the same compile succeed, confirming visibility to one compilation as the trigger rather than presence on disk.8

The dependency scanner behaves differently, and the difference is the whole reason Apple wrote “may.” Running the same two module maps through swiftc -scan-dependencies 20 times produced three outcomes: nine crashes with SIGSEGV, five aborts, and six clean successes.8 The crashing runs’ stack traces pass through performParallelClangModuleLookup, which fits a race in the parallel lookup Apple describes replacing. Attributing the nondeterminism to that race is my reading of the trace, not Apple’s statement.

Apple’s second named case is the quiet one. I wrote a vendored module map declaring SQLite3, a real module in the iPhoneOS SDK, put it on the search path, and compiled against it:8

Vendor/module.modulemap
module SQLite3 {
    header "shim.h"
    export *
}

The compile succeeded. Exit 0, no warning, no note, no diagnostic of any kind. Then I asked the same configuration for sqlite3_open:8

error: cannot find 'sqlite3_open' in scope

Without the vendored directory on the search path, the identical file compiles. The vendored module map shadowed the SDK’s SQLite3 completely, and the toolchain said nothing. So today the vendored-redeclaration case does not fail loudly; it fails as a missing API in a module you thought you imported. Apple’s note says the Xcode 27 scan “may report an error” there, which would convert a silent shadowing into a build failure.

I build on Xcode 26.6 (build 17F113), so every diagnostic above comes from the previous toolchain.78 I cannot report Xcode 27’s error text and have not invented any. The diagnostic machinery, the string to grep for, and the tolerance Apple describes retiring all exist today.

Auditing for duplicate module names

Enumerating declared module names looks like a one-line grep, but two constructs in the module map language produce wrong answers.

extern module Foo "Foo.modulemap" is a forward reference, not a definition, and Apple’s SDK uses 79 of them in one module map.7 A naive scan counts the reference and the real definition as two declarations of Foo. Second, module Darwin.C { ... } uses a dotted module-id to extend a module declared elsewhere; 13 SDK module maps open module Darwin.something, and reading the first component as a top-level declaration lumps all 13 in with the real Darwin declaration as one 14-file collision.7 Both false positives appeared in my first draft.

What survives handles comments, brace depth so nested explicit module submodules stay out, and paths containing spaces:

find -H "${1:-.}" \( -name '*.modulemap' -o -name 'module.map' \) \
  -not -path '*/build/*' -not -path '*/.build/*' \
  -not -path '*/DerivedData*/*' -print0 |
while IFS= read -r -d '' map; do
  awk -v f="$map" '
    { line = $0; sub(/\/\/.*/, "", line)
      if (depth == 0 && line !~ /extern[[:space:]]+module/ &&
          match(line, /(^|[[:space:]])module[[:space:]]+[A-Za-z_][A-Za-z0-9_.]*/)) {
        n = substr(line, RSTART, RLENGTH); sub(/.*module[[:space:]]+/, "", n)
        if (n !~ /\./) print n "\t" f
      }
      for (i = 1; i <= length(line); i++) {
        c = substr(line, i, 1)
        if (c == "{") depth++; else if (c == "}") depth--
      }
    }' "$map"
done | sort -u > /tmp/modnames.txt

cut -f1 /tmp/modnames.txt | uniq -d | while read -r n; do
  echo "duplicate: $n"
  awk -F'\t' -v n="$n" '$1==n {print "  " $2}' /tmp/modnames.txt
done

The strongest available negative control is Apple’s own SDK, which must satisfy the rule for the toolchain to work at all. Pointed at the iPhoneOS 26.5 SDK the command finds 1,099 top-level declarations under usr/include and 205 across the framework module maps, with zero duplicates in either.7 Pointed at fixtures built to collide, it names the duplicate and both files.8

The exclusions carry weight. -not -path '*/build/*' does not exclude .build/, because the pattern needs the literal directory name, and SwiftPM writes generated module maps into .build by the dozen. Leaving .build in produced my only “duplicates” across seven projects: GrappleCore in six files and GrappleRender in three, all SwiftPM output, spanning two Swift targets across different build roots.9 The nine are not even byte-identical, and the reason is instructive: each wraps the same module name around an absolute path to its own build root’s generated header, so they differ in one string and in nothing that matters. An audit that calls them collisions exhausts its credibility before reaching anything real.

Xcode manufactures the same false positive with less ambiguity. Inside a single DerivedData tree it writes each Swift package’s generated module map twice, into GeneratedModuleMaps-iphonesimulator/ and into the target’s own intermediates, with a relative header path both times. In one project’s tree 15 names appear twice each, all 15 pairs byte-identical.9 Scope the audit to source, not build output.

What seven projects contain

I ran both audits against seven Xcode projects on Xcode 26.6. The honest result is a clean null.9

Project Swift files Objective-C / C++ / C Dependencies -ld_classic Source module maps
Reps 77 0 2 local SPM 0 0
Return 57 0 none 0 0
Banana List 55 0 none 0 0
Ace Citizenship 26 0 none external 0 0
Water 34 0 (2 .metal) none 0 0
ResumeGeni 71 0 3 remote SPM, 9 pins 0 0
Yawara 143 0 2 local SPM 0 0
Total 463 0 SPM only 0 0

OTHER_LDFLAGS is unset in all seven projects, no .xcconfig file exists anywhere in the fleet, and there is no CocoaPods, no Carthage, and no vendored .framework or .xcframework.9 The module-name audit examined 391 module maps, 204 inside the project directories and 187 in the shared DerivedData where Xcode’s GUI builds land, and every one is build output.9 Not one repository holds a hand-authored module map.

Both zeros have the same cause, and it is the finding worth carrying away: the exposed population is mixed-language projects, and these are not. Across 463 Swift files the fleet holds zero Objective-C, zero C++, and zero C sources, with two Metal shaders in Water as the only non-Swift compiled code.9 A null result from a codebase never at risk is weak evidence about the hazards and strong evidence about who needs to audit.

Two details matter more than the zeros. The only hand-written module maps in the resolved packages belong to swift-crypto, which vends four C shims named CCryptoBoringSSL, CCryptoBoringSSLShims, CXKCP, and CXKCPShims, all distinct.9 And no name the fleet declares appears anywhere in the SDK’s Clang module namespace, checked against all 1,318 top-level names the command finds in the iPhoneOS 26.5 SDK.9 Even the generic ones arriving through Supabase miss: the SDK declares Clang modules named Foundation, UIKit, and SQLite3, and none named Crypto, Storage, or Auth.

The C++ deployment floor moving underneath

One adjacent change hits the same C++ projects that hold -ld_classic. Apple raised a floor, naming macOS and no other platform: “The minimum supported deployment target on macOS for the C++ standard library has been increased to 11.0.”5

The same entry offers an escape hatch and dates its removal in the next sentence. libc++ changed the result of lower_bound and upper_bound on std::map and std::set for comparators that are not a strict weak order, and defining _LIBCPP_ENABLE_LEGACY_TREE_LOWER_UPPER_BOUND “will revert to the historical implementation of these operations.” Then: “That escape hatch will be removed in an upcoming release (likely in the next release).”5 A related change stops multimap::find and multiset::find necessarily returning the first equal element, behavior Apple notes “was never guaranteed by the Standard” though libc++ always provided it, and it ships with no opt-out.5 Treat the macro as a migration ticket, not a fix.

FAQ

Why does my project have -ld_classic in it?

Almost certainly because Apple’s Xcode 15 release notes prescribed it. Two Known Issues there recommended adding -Wl,-ld_classic to OTHER_LDFLAGS: one where binaries using weakly defined symbols crashed at runtime on iOS 14 and macOS 12 or older, which Apple noted “impacts primarily C++ projects,” and one where LTO object files linked weak symbol imports as non-weak.3 Apple deprecated the option in Xcode 16 and removed the linker behind it in Xcode 27.14 If the flag is there, confirm the original bug still reproduces before hunting a replacement.

How do I find duplicate Clang module names in my project?

Enumerate top-level module declarations across every module map, look for a name appearing in two files, and drop build directories from the results. Three things make the job more than a grep: extern module Foo "path" is a reference rather than a definition, module Foo.Bar extends a module declared elsewhere instead of declaring Foo, and nested explicit module submodules do not collide with top-level names.6 Exclude .build, build, and DerivedData explicitly, since -not -path '*/build/*' misses .build and both SwiftPM and Xcode duplicate generated module maps routinely.9

What does the error look like under Xcode 27?

I cannot say, and neither can anyone building on Xcode 26. My machine runs Xcode 26.6 (build 17F113), so I report no Xcode 27 output at all.78 What Xcode 26.6 emits for two module maps declaring one name is error: redefinition of module 'Widget' with a note: previously defined here, on every run of a plain typecheck.8 Apple’s wording for Xcode 27 is that the scan “may report an error,” so search logs for redefinition of module rather than a string someone guessed.

Does a unique-module-name failure depend on my deployment target?

No. Apple frames the requirement against a single Swift dependency-scan action and names no OS version, SDK, or deployment target in the entry.2 The linker change reads the same way, as a removal from the toolchain.1 Both land on the first build in Xcode 27, alongside the @State macro rather than the SDK-triggered requirements in the same cycle.

Key Takeaways

For iOS developers: - Query OTHER_LDFLAGS through xcodebuild -showBuildSettings -configuration Release -sdk iphoneos instead of grepping for -ld_classic. Absence from resolved settings means unset; absence from a text search means nothing.9 - Search build logs for redefinition of module, the diagnostic Xcode 26.6 already emits, not invented Xcode 27 error text.8

For teams with vendored C or C++ dependencies: - Audit vendored module.modulemap files against the SDK namespace first: Apple names that case, and it fails silently today. My vendored SQLite3 shim compiled with exit 0 and made sqlite3_open disappear.8 - Scope the audit to source and exclude .build, build, and DerivedData. Every apparent duplicate across 391 module maps was generated build output for a single Swift target.9

For release managers: - Treat both changes as toolchain-triggered and schedule them for the first Xcode 27 build, not the SDK migration. Neither references a deployment target or has a runtime component.12 - Keep Apple’s hedges in the ticket. The scan “may report an error,” and 20 runs of one collision gave three different outcomes, so a build passing once proves nothing.28


The 27 cycle keeps failing in different places: the launch screen key stops a submission, the scene life cycle mandate stops a launch, and the @State macro stops a build at the source level. The linker removal and the module-name rule stop it one layer lower, in the parts of the toolchain nobody configures on purpose. The full series hub is the Apple Ecosystem Series.

References


  1. Apple, Xcode 27 Release Notes, Linking section, Deprecations in Xcode 27 Beta (radar 165165518). Source of the removal, quoted in full: “The ld64 linker has been removed and the -ld_classic option is no longer supported.” Verified against Apple’s documentation JSON on July 26, 2026, since the HTML page renders its content through JavaScript. The page title at that date is “Xcode 27 Beta 4 Release Notes.” 

  2. Apple, Xcode 27 Release Notes, Swift Compiler section, New Features in Xcode 27 Beta (radar 136303612). Source of the dependency-scanner entry, quoted verbatim and in full in the body of this article, including both hedges (“the scan may report an error” and “Previously, the scanner may have tolerated duplicating names”) and the two named cases. Verified against Apple’s documentation JSON on July 26, 2026. Noted as filed under New Features rather than Deprecations or Known Issues. 

  3. Apple, Xcode 15 Release Notes, Linking section. New Features (radar 108915312) is the source of “A new linker has been written to significantly speed up static linking. It’s the default for all macOS, iOS, tvOS and visionOS binaries and anyone using the ‘Mergeable Libraries’ feature. The classic linker can still be explicitly requested using -ld64, and will be removed in a future release.” Known Issues is the source of both workarounds recommending the flag: radar 114813650 (FB13097713), “Binaries using symbols with a weak definition crash at runtime on iOS 14/macOS 12 or older. This impacts primarily C++ projects due to their extensive use of weak symbols,” with the workaround to raise the deployment target “or add -Wl,-ld_classic to the OTHER_LDFLAGS build setting”; and radar 115521975 (FB13171424), “Weak symbol imports are linked as non-weak imports, when used from LTO object files,” with the workaround “Add -Wl,-weak_reference_mismatches,weak or -Wl,-ld_classic options to the OTHER_LDFLAGS build setting.” Verified against Apple’s documentation JSON on July 26, 2026. 

  4. Apple, Xcode 16 Release Notes, Linking section, Deprecations (radar 128502299): “-ld_classic linker option is deprecated and will be removed in a future release.” Verified against Apple’s documentation JSON on July 26, 2026. 

  5. Apple, Xcode 27 Release Notes, C++ Standard Library section, Deprecations in Xcode 27 Beta. Apple prints a single radar for the whole block, 178191050, trailing its final item rather than beside each one. Source of “The minimum supported deployment target on macOS for the C++ standard library has been increased to 11.0,” of the multi{map,set}::find change (“code relying on the first element being returned from find will be broken, and lower_bound or equal_range should be used instead”), and of the escape hatch and its expiry: “Since this may be tricky to work around in some cases, an escape hatch is provided in this release: defining _LIBCPP_ENABLE_LEGACY_TREE_LOWER_UPPER_BOUND will revert to the historical implementation of these operations. That escape hatch will be removed in an upcoming release (likely in the next release).” Verified against Apple’s documentation JSON on July 26, 2026. 

  6. Clang team, Clang Modules documentation, Module Map Language. Source of “Each module shall have a single definition,” of the module-id rule and the extern module declaration, of “The explicit qualifier can only be applied to a submodule, i.e., a module that is nested within another module,” and of module map discovery by the filename module.modulemap with module.map searched for compatibility. Cited as the toolchain’s own reference for the module map language rather than as an Apple developer document; Apple’s clang derives from this implementation. 

  7. Author’s testing on macOS 26.5.2 (build 25F84) with Xcode 26.6 (build 17F113), Apple clang 21.0.0, July 26, 2026. Command output reproduced verbatim. xcrun clang hello.c -o hello -Wl,-ld_classic prints “ld: warning: -ld_classic is deprecated and will be removed in a future release” and exits 0; substituting -Wl,-ld64 prints the identical warning naming -ld_classic. xcrun ld -v reports PROJECT:ld-1267 and the architecture lists quoted above. ld-classic is present at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld-classic with a man page alongside it. SDK architectures come from SDKSettings.plist: iPhoneOS 26.5 declares arm64e and arm64, WatchOS 26.5 declares arm64, arm64e, and arm64_32. The SDK module-map counts (1,099 top-level declarations across usr/include, 205 across System/Library/Frameworks, zero duplicates in either) come from running the command published above against the iPhoneOS 26.5 SDK; the 79 extern module declarations are in usr/include/module.modulemap, and 13 module maps in the same directory open a dotted module Darwin.* (bank, Darwin_C, Darwin_Mach, Darwin_Mach_machine, Darwin_machine, Darwin_POSIX, Darwin_sys, device, mach_debug, net, netinet, netinet6, and uuid), which a first-component reading groups with the real Darwin declaration in Darwin.modulemap as a single 14-file collision. Behavior under Xcode 27 was not tested, because Xcode 27 was not installed on the machine used. 

  8. Author’s reproduction on the same machine and toolchain, July 26, 2026. Two directories each containing a module.modulemap declaring module Widget, compiled with both directories on the search path via swiftc. -typecheck produced error: redefinition of module 'Widget' with note: previously defined here on 20 of 20 runs, exit 1; dropping one -I path made the same file compile with exit 0. -scan-dependencies on the same input across 20 runs produced nine exits with signal 11 (SIGSEGV), five with signal 6 (SIGABRT), and six exits with status 0, with the crashing runs’ stack traces passing through swift::ModuleDependencyScanner::performParallelClangModuleLookup. Separately, a vendored module map declaring SQLite3 (a module in the iPhoneOS 26.5 SDK) placed on the search path typechecked with exit 0 and no diagnostic, while a file calling the SDK’s sqlite3_open under the same configuration failed with “error: cannot find ‘sqlite3_open’ in scope” and compiled cleanly once the vendored directory was removed from the search path. Fixtures included a path containing a space to verify the published command. That command compares names between files, so a name declared twice inside one module map is out of its scope by design. No Xcode 27 output is reported anywhere in this article. 

  9. Author’s audit of seven Xcode projects (Reps, Return, Banana List, Ace Citizenship, Water, ResumeGeni, and Yawara) on macOS 26.5.2 with Xcode 26.6 (build 17F113), July 26, 2026. -ld_classic and ld64 appear zero times in any working tree, and OTHER_LDFLAGS is unset in every project, with no .xcconfig files, no Podfile, no Carthage, and no vendored .framework or .xcframework anywhere in the fleet; the search covered current working trees only, not git history or archived build logs, so the result is “absent now” rather than “never used.” The SUPPORTED_PLATFORMS line quoted for Reps comes from xcodebuild -showBuildSettings -configuration Release -sdk iphoneos. Module-map totals: 391 examined, 204 under the seven project directories and 187 in those seven projects’ own trees under the shared ~/Library/Developer/Xcode/DerivedData (the whole shared directory holds far more, belonging to other projects), all of them build output, with zero hand-authored or vendored module maps in any of the seven repositories. Apparent duplicates were checked by content hash, and the two generators behave differently. Xcode’s 15 name pairs in the audited ResumeGeni tree (the in-project build/DerivedData), written once under GeneratedModuleMaps-iphonesimulator/ and once under the target’s intermediates, are byte-identical 15 times out of 15, because Xcode emits a relative header path. The count is per tree rather than per project: the same app’s tree under the shared ~/Library/Developer/Xcode/DerivedData holds 16, and its Index.noindex variant 22. The mechanism is what generalizes, not the number. SwiftPM’s copies are not: the six GrappleCore and three GrappleRender files under Yawara’s .build directories carry six and three distinct hashes and range from 171 to 185 bytes, because each embeds an absolute path to the generated -Swift.h inside its own build root and is otherwise identical. No module name declared across the fleet appears among the 1,318 distinct top-level Clang module names the published command finds when pointed at the whole iPhoneOS 26.5 SDK, of which 1,099 sit under usr/include and 205 under System/Library/Frameworks; the intersection with the fleet’s declared names is empty. The same scan reports zero duplicates across the entire SDK, which is the negative control the rule demands. CryptoKit is absent from that list because it ships as a Swift-only framework with no Clang module map, so the absence of a Crypto collision rests on the SDK declaring no Clang module by that name rather than on CryptoKit occupying it. swift-crypto 4.4.0 vends the only hand-written module maps in the resolved dependency graph (CCryptoBoringSSL, CCryptoBoringSSLShims, CXKCP, CXKCPShims, one declaration each). The SymbolKit host-tool and target variants are in the shared local package 941Kit rather than in the seven apps. Source counts exclude Python virtualenvs, which is a correction that mattered: a naive count credited Reps with C and header files that all turned out to live inside .venv and site-packages and are compiled by no Xcode target. Water has no local build tree, so its zero module-map count reflects an unbuilt project rather than a verified-clean build graph. The three false-clean traps were each confirmed directly: timeout is absent from stock macOS and exits 127; zsh expands an unquoted --include=*.pbxproj and aborts with “no matches found”; and xcrun --sdk iphoneos --show-sdk-path returns a symlink, against which find without -H reports zero module maps where find -H reports 266. 

  10. Apple, Xcode 26 Release Notes. Searched for ld_classic, ld64, and any entry describing the classic linker on July 26, 2026; none appears, so Apple’s deprecation notice in Xcode 16 and the removal in Xcode 27 have no intervening restatement. 

  11. Apple, Xcode 27 Release Notes, Overview: “Xcode 27 beta 4 includes Swift 6.4 and SDKs for iOS 27, iPadOS 27, tvOS 27, watchOS 27, macOS 27, and visionOS 27.” The same notes record under Intel Deprecation (radar 162138432) that “Xcode 27 will only install and run on Apple silicon Macs.” Checked July 26, 2026. 

관련 게시물

The @State Macro: What Xcode 27 Stops Compiling

Xcode 27 reimplements SwiftUI's @State as a Swift macro. The break lands on toolchain upgrade, not deployment target, an…

20 분 소요

The iOS 27 Launch Screen Rule: Four Keys or Rejection

Apps built with the iOS 27 SDK must declare a launch screen or the App Store rejects them. The four keys, and how to aud…

16 분 소요