PC パソコン

Xcode: Fix “Global is external, but doesn’t have external or weak linkage!” in Swift 6.4

A Release build made with Xcode 27 beta and Swift 6.4 can abort with Global is external, but doesn't have external or weak linkage! followed by Broken module found, compilation aborted!. The regression requires an interaction between explicit Cross-Module Optimization, a public generic function, and a dynamic cast to a non-public protocol.

Representative log

Global is external, but doesn't have external or weak linkage!
ptr @"$s...Updatable...WP"
<unknown>:0: error: fatal error encountered during compilation
<unknown>:0: note: Broken module found, compilation aborted!
Stack dump:
0. Running pass "verify" on module ".../Client.o"

If the protocol is changed from private to internal, the frontend crash may become a linker failure instead:

Undefined symbols for architecture arm64:
"protocol conformance descriptor for Types.Incident.Update : Core.Updatable in Core"

Cause

Swift issue #91771 describes a public generic function in a module built with -cross-module-optimization. Its body dynamically casts a value to a non-public protocol, while the conforming type comes from another module. Client-side specialization folds the cast into direct references to a conformance descriptor and witness table that cannot be resolved outside the defining module.

This is not the usual missing-library linker error. A Debug build that succeeds while the optimized Release build fails is an important diagnostic clue.

Affected versions and conditions

  • Xcode 27.0 beta; the public reproducer used build 27A5252f
  • Apple Swift 6.4, including swiftlang-6.4.0.33.1
  • A Release module built with explicit -cross-module-optimization
  • A public generic function that performs as? against a non-public protocol
  • The conforming type is imported from another module

The reproducer succeeds with Xcode 26.6 and Swift 6.3.3, in Debug, and in Release after removing explicit CMO. The issue also notes that SwiftPM’s conservative -enable-default-cmo does not trigger the reduced case by itself.

Reduced structure

// Core module, built with -cross-module-optimization
import Types

private protocol Updatable {
    func write()
}

extension Incident.Update: Updatable {
    func write() {}
}

public func process<T>(_ value: T) {
    guard let value = value as? any Updatable else { return }
    value.write()
}

Recommended fix

  1. Confirm the toolchain and failing configuration.
    xcodebuild -version
    xcrun swiftc --version
    swift build -c release -v
  2. Remove explicit -cross-module-optimization from the affected module and rebuild Release. Check Other Swift Flags in Xcode and swiftSettings in SwiftPM.
  3. Separate the non-public protocol cast from the public generic body. Prefer keeping the implementation inside its defining module so it is not serialized and specialized by a client.
  4. Only when it is appropriate API design, reconsider whether the protocol and conformance must be externally visible. Merely changing private to internal can turn the crash into the undefined-symbol failure shown above.
  5. When a Swift or Xcode build containing the fix is verified, update, clear generated artifacts, and retest.
    rm -rf ~/Library/Developer/Xcode/DerivedData/*
    swift package clean
    swift build -c release

Alternative workarounds

  • Temporarily build with Xcode 26.6 and Swift 6.3.3 if project requirements allow it
  • Disable explicit CMO only for the affected module after measuring the performance impact
  • Move the cast from the public generic function into a non-public, non-generic helper

The issue reports a workaround using @_semantics("optimize.no.crossmodule"), but underscored attributes are unsupported implementation details. Do not treat that attribute as a stable permanent fix.

How to verify

  1. Build Debug and Release separately
  2. Use verbose output to confirm explicit -cross-module-optimization is absent from the affected Release compilation
  3. Confirm that both the LLVM verifier message and the protocol-conformance undefined symbol are gone
  4. Measure performance and binary size after changing optimization settings

Important notes

Undefined symbols for architecture arm64 has many unrelated causes, including missing libraries and target configuration mistakes. Attribute this failure to issue #91771 only when Swift 6.4, Release, explicit CMO, and non-public protocol conformance are all present. The issue is closed, but the public record does not identify the first shipping Xcode release containing the fix.

Summary

This Swift 6.4 regression lets CMO emit a reference to a non-public protocol conformance that a client module cannot resolve. Disable explicit CMO for the affected module first, then redesign the boundary between the public generic function and the non-public protocol where practical.

Official references