← Todos os Posts

O Xcode 27 remove o ld64 e passa a exigir nomes de módulo únicos

A Apple aposentou um linker em uma única frase: “O linker ld64 foi removido e a opção -ld_classic não é mais suportada.”1 A flag que sumiu agora é a mesma que a Apple mandou os desenvolvedores adicionarem. As release notes do próprio Xcode 15 ofereciam -Wl,-ld_classic como contorno para dois bugs do linker.3

Resumo

  • O Xcode 27 remove o ld64 e para de aceitar -ld_classic.1 As notas do Xcode 15 prescreviam a flag para travamentos com símbolos fracos e para bugs de importação em LTO, o Xcode 16 marcou a opção como obsoleta e o Xcode 26 não disse absolutamente nada.3410
  • A segunda quebra está no compilador Swift. A Apple transformou a varredura de dependências em uma única ação compartilhada, então “todo módulo Clang alcançável a partir de uma única ação de varredura de dependências do Swift precisa ter um nome de módulo único.”2 A Apple faz duas ressalvas: a varredura “pode reportar um erro” e, antes disso, o varredor “pode ter tolerado nomes duplicados.”2
  • As duas quebras disparam na atualização do toolchain, não em uma escolha de deployment target ou de SDK, e nenhuma delas tem componente em tempo de execução. A população exposta: binários de terceiros embarcados, CocoaPods ou uma base de código grande e mista de Swift/Objective-C/C++.
  • O “pode” da Apple não é cautela editorial. No Xcode 26.6, coloquei dois module maps declarando o mesmo nome em um único search path e rodei o varredor 20 vezes: nove execuções quebraram com SIGSEGV, cinco abortaram e seis terminaram limpas.8
  • Um module map embarcado que redeclara um módulo do SDK — o caso que a Apple cita — compila em silêncio hoje e esconde o módulo real. Meu shim SQLite3 embarcado passou na checagem de tipos com exit 0, e sqlite3_open deixou de existir.8
  • Em sete projetos auditados: zero -ld_classic, OTHER_LDFLAGS sem valor definido em todos eles e zero nomes de módulo duplicados entre 391 module maps, porque nenhum repositório guarda um module map escrito à mão.9

As duas notas saíram nas release notes do Xcode 27 beta 4, junto com o Swift 6.4 e os SDKs da linha 27.11 Leia tudo como texto de beta.

A flag que a Apple mandou você adicionar

A história começa com a reescrita de um linker. O Xcode 15 anunciou um linker novo, tornou-o padrão “para todos os binários de macOS, iOS, tvOS e visionOS” e definiu os termos da aposentadoria em uma única oração: “O linker clássico ainda pode ser solicitado explicitamente com -ld64, e será removido em uma versão futura.”3

O linker novo chegou com bugs, e a Apple documentou a saída de emergência duas vezes na mesma página. O primeiro Known Issue: “Binários que usam símbolos com definição fraca travam em tempo de execução no iOS 14/macOS 12 ou anteriores. Isso afeta principalmente projetos C++, pelo uso extensivo que fazem de símbolos fracos.” O contorno da Apple era elevar o deployment target “ou adicionar -Wl,-ld_classic à build setting OTHER_LDFLAGS.”3 O segundo, sobre arquivos-objeto de LTO que linkavam importações de símbolos fracos como não fracas, oferecia “-Wl,-weak_reference_mismatches,weak ou -Wl,-ld_classic” na mesma configuração.3

Os dois bugs pegaram mais pesado em projetos C++, o que explica quem ainda carrega a flag. Ninguém volta a mexer numa configuração que impediu um crash.

O Xcode 16 avisou em uma frase: “a opção de linker -ld_classic está obsoleta e será removida em uma versão futura.”4 Depois, silêncio. Procurei ld_classic, ld64 e o linker clássico nas release notes do Xcode 26 e não achei nada.10

O toolchain atual ainda aceita a flag e ainda reclama. No Xcode 26.6, linkei um programa C trivial com ela:7

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

Status de saída zero. O binário linka. Trocar por -Wl,-ld64 produz o warning idêntico, citando -ld_classic, ou seja, as duas grafias que a Apple usou chegam hoje ao mesmo caminho de código.7 A nota do Xcode 27 cita apenas -ld_classic, e não tive como testar se -ld64 falha do mesmo jeito.

Um detalhe complica a palavra “removido”. O linker do Xcode 26.6, quando é chamado a se identificar com xcrun ld -v, informa quais arquiteturas ele delega: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

O ld-classic existe como binário de verdade no toolchain, com man page própria, e o linker ainda roteia oito arquiteturas para ele.7 Nenhuma delas sobrevive em um SDK de app atual: o iPhoneOS 26.5 declara apenas arm64e e arm64, e o SDK do watchOS acrescenta arm64_32.7 A lista é de ARM de 32 bits, i386 e alvos embarcados Cortex-M. Ler a ausência dessas arquiteturas nos SDKs como a razão pela qual a remoção é segura para quem faz apps é inferência minha, não afirmação da Apple.

Achar a flag sem confiar no grep

O -ld_classic mora em OTHER_LDFLAGS, então pergunte ao build system qual valor ele resolve, em vez de caçar texto dentro dos arquivos:

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

No projeto Reps, volta uma linha só:9

    SUPPORTED_PLATFORMS = appletvos appletvsimulator iphoneos iphonesimulator macosx

O OTHER_LDFLAGS não aparece em lugar nenhum, e essa é a resposta: a configuração está sem valor, então nenhuma flag de linker chega à etapa de link por ela. Ausência nas configurações de build resolvidas carrega uma informação que ausência em busca textual não carrega. Para a pergunta sobre plataformas, leia também SUPPORTED_PLATFORMS, nunca um *_DEPLOYMENT_TARGET, que o Xcode escreve haja ou não um destino real.

Três armadilhas produziram resultados falsamente limpos durante a auditoria, e as três não imprimem nada e saem com sucesso. O timeout não existe no macOS de fábrica, então envolver o xcodebuild nele devolve exit 127 e saída vazia, que se lê como um projeto sem nenhuma flag de linker. No zsh, um --include=*.pbxproj sem aspas sofre expansão de glob antes de o grep vê-lo, então o comando morre com “no matches found” em vez de reportar zero ocorrências. E o find não segue um symlink passado como ponto de partida, o que importa porque xcrun --sdk iphoneos --show-sdk-path devolve justamente um: find "$SDK" -name '*.modulemap' não acha nada, enquanto find -H "$SDK" acha 266 arquivos.9 Coloque seus padrões entre aspas, passe -H e confirme que o comando casa com algo que você sabe estar lá antes de confiar em um zero.

Um target mantido à mão guarda a flag em project.pbxproj ou em um .xcconfig; um projeto com CocoaPods também pode recebê-la de um gancho post_install, que nenhum arquivo editado por desenvolvedor registra. A frota que auditei não tem nem um nem outro, então esse último caminho ficou sem verificação.9

A regra de nome de módulo e as duas ressalvas da Apple

A segunda quebra chega disfarçada de ganho de performance, arquivada em New Features e não em Deprecations. A entrada de Swift Compiler da Apple, na íntegra:

O varredor de dependências do Swift foi otimizado para evitar trabalho de configuração e buscas de header redundantes ao procurar módulos Clang durante uma única ação de varredura de dependências, melhorando substancialmente a performance da varredura. Como consequência dessa mudança, todo módulo Clang alcançável a partir de uma única ação de varredura de dependências do Swift precisa ter um nome de módulo único. Se dois module maps visíveis para a mesma varredura declararem um módulo Clang com o mesmo nome, a varredura pode reportar um erro. Antes, o varredor pode ter tolerado nomes duplicados. Os casos mais comuns são projetos ou SDKs que fornecem o mesmo nome de módulo Clang a partir de mais de um local no search path de headers, e fontes de terceiros embarcadas que trazem um module.modulemap redeclarando um módulo do SDK.2

Quatro coisas aí merecem ser separadas. A Apple limita a exigência ao que uma varredura consegue alcançar, não ao seu disco inteiro. A Apple descreve a consequência como “pode reportar um erro” e usa a mesma ressalva para o comportamento antigo. A Apple nomeia os dois formatos que disparam o problema: um nome de módulo fornecido a partir de dois locais no search path de headers e um module.modulemap embarcado redeclarando um módulo do SDK. E o gatilho é o toolchain, já que nada ali menciona deployment target nem versão de SDK.

A regra é anterior à otimização. A linguagem de module map do Clang diz isso com todas as letras: “Cada módulo deve ter uma única definição.”6 O que a documentação nunca diz é a consequência de quebrar a regra, e esse silêncio se mostra bem merecido: a resposta do toolchain não é um comportamento, são vários.

O que uma colisão faz de verdade

As ressalvas da Apple me deram vontade de ver a falha, então montei a versão mínima: dois diretórios, cada um com um module.modulemap declarando o mesmo módulo.8

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

Com os dois diretórios no search path, uma checagem de tipos simples falha do mesmo jeito toda vez, 20 execuções em 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 é a string a procurar em um build log, e o clang do Xcode 26.6 já a emite. Tirar um dos search paths faz a mesma compilação passar, o que confirma que o gatilho é a visibilidade dentro de uma mesma compilação, não a presença no disco.8

O varredor de dependências se comporta de outro jeito, e essa diferença é a razão inteira de a Apple ter escrito “pode”. Passar os mesmos dois module maps por swiftc -scan-dependencies 20 vezes produziu três desfechos: nove quebras com SIGSEGV, cinco abortos e seis sucessos limpos.8 Os rastreamentos de pilha das execuções que quebraram passam por performParallelClangModuleLookup, o que combina com uma condição de corrida na busca paralela que a Apple diz estar substituindo. Atribuir o não determinismo a essa corrida é minha leitura do rastreamento, não afirmação da Apple.

O segundo caso citado pela Apple é o silencioso. Escrevi um module map embarcado declarando SQLite3, um módulo real do SDK do iPhoneOS, coloquei no search path e compilei contra ele:8

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

A compilação passou. Exit 0, nenhum warning, nenhuma nota, nenhum diagnóstico de espécie alguma. Aí pedi sqlite3_open à mesma configuração:8

error: cannot find 'sqlite3_open' in scope

Sem o diretório embarcado no search path, o arquivo idêntico compila. O module map embarcado sombreou por completo o SQLite3 do SDK, e o toolchain não disse nada. Ou seja, hoje o caso da redeclaração embarcada não falha em alto e bom som; ele falha com API ausente em um módulo que você achava ter importado. A nota da Apple diz que no Xcode 27 a varredura “pode reportar um erro” nesse ponto, o que converteria um sombreamento silencioso em falha de build.

Eu compilo no Xcode 26.6 (build 17F113), então todo diagnóstico acima vem do toolchain anterior.78 Não tenho como reportar o texto de erro do Xcode 27 e não inventei nenhum. A maquinaria de diagnóstico, a string para procurar e a tolerância que a Apple descreve estar aposentando já existem hoje.

Auditar nomes de módulo duplicados

Enumerar nomes de módulo declarados parece um grep de uma linha, mas duas construções da linguagem de module map produzem respostas erradas.

extern module Foo "Foo.modulemap" é uma referência antecipada, não uma definição, e o SDK da Apple usa 79 delas em um único module map.7 Uma varredura ingênua conta a referência e a definição real como duas declarações de Foo. Segundo, module Darwin.C { ... } usa um module-id com ponto para estender um módulo declarado em outro lugar; 13 module maps do SDK abrem module Darwin.something, e ler o primeiro componente como declaração de topo junta os 13 com a declaração real de Darwin em uma colisão de 14 arquivos.7 Os dois falsos positivos apareceram no meu primeiro rascunho.

O que sobreviveu lida com comentários, com profundidade de chaves — para que submódulos explicit module aninhados fiquem de fora — e com caminhos que contêm espaços:

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

O controle negativo mais forte disponível é o próprio SDK da Apple, que precisa satisfazer a regra para o toolchain sequer funcionar. Apontado para o SDK do iPhoneOS 26.5, o comando encontra 1.099 declarações de topo em usr/include e 205 nos module maps de frameworks, com zero duplicatas nos dois casos.7 Apontado para fixtures montadas para colidir, ele nomeia a duplicata e os dois arquivos.8

As exclusões pesam. -not -path '*/build/*' não exclui .build/, porque o padrão precisa do nome literal do diretório, e o SwiftPM escreve module maps gerados dentro de .build às dúzias. Deixar o .build no caminho produziu as minhas únicas “duplicatas” nos sete projetos: GrappleCore em seis arquivos e GrappleRender em três, tudo saída do SwiftPM, cobrindo dois targets Swift em build roots diferentes.9 Os nove nem sequer são idênticos byte a byte, e o motivo é instrutivo: cada um declara o mesmo nome de módulo apontando para um caminho absoluto até o header gerado do seu próprio build root, então diferem em uma string e em nada que importe. Uma auditoria que chama isso de colisão esgota a própria credibilidade antes de chegar a qualquer coisa real.

O Xcode fabrica o mesmo falso positivo com menos ambiguidade. Dentro de uma única árvore de DerivedData, ele escreve o module map gerado de cada pacote Swift duas vezes, em GeneratedModuleMaps-iphonesimulator/ e nos intermediários do próprio target, com caminho de header relativo nas duas. Na árvore de um dos projetos, 15 nomes aparecem duas vezes cada, e os 15 pares são idênticos byte a byte.9 Limite a auditoria ao código-fonte, não à saída de build.

O que sete projetos contêm

Rodei as duas auditorias em sete projetos Xcode no Xcode 26.6. O resultado honesto é um zero limpo.9

Projeto Arquivos Swift Objective-C / C++ / C Dependências -ld_classic Module maps no código-fonte
Reps 77 0 2 SPM locais 0 0
Return 57 0 nenhuma 0 0
Banana List 55 0 nenhuma 0 0
Ace Citizenship 26 0 nenhuma externa 0 0
Water 34 0 (2 .metal) nenhuma 0 0
ResumeGeni 71 0 3 SPM remotos, 9 pins 0 0
Yawara 143 0 2 SPM locais 0 0
Total 463 0 só SPM 0 0

O OTHER_LDFLAGS está sem valor nos sete projetos, não existe nenhum arquivo .xcconfig em lugar algum da frota, e não há CocoaPods, nem Carthage, nem .framework ou .xcframework embarcado.9 A auditoria de nomes de módulo examinou 391 module maps, 204 dentro dos diretórios de projeto e 187 no DerivedData compartilhado onde caem os builds da GUI do Xcode, e todos são saída de build.9 Nenhum repositório guarda um module map escrito à mão.

Os dois zeros têm a mesma causa, e é essa a conclusão que vale levar: a população exposta é a dos projetos de linguagem mista, e estes não são. Em 463 arquivos Swift, a frota tem zero fonte Objective-C, zero C++ e zero C, com dois shaders Metal no Water como único código compilado que não é Swift.9 Um resultado nulo vindo de uma base de código que nunca esteve em risco é evidência fraca sobre os perigos e evidência forte sobre quem precisa auditar.

Dois detalhes importam mais que os zeros. Os únicos module maps escritos à mão nos pacotes resolvidos pertencem ao swift-crypto, que fornece quatro shims em C chamados CCryptoBoringSSL, CCryptoBoringSSLShims, CXKCP e CXKCPShims, todos distintos.9 E nenhum nome declarado pela frota aparece em lugar algum do namespace de módulos Clang do SDK, conferido contra todos os 1.318 nomes de topo que o comando encontra no SDK do iPhoneOS 26.5.9 Até os genéricos que chegam pelo Supabase passam longe: o SDK declara módulos Clang chamados Foundation, UIKit e SQLite3, e nenhum chamado Crypto, Storage ou Auth.

O piso de deployment do C++ se movendo por baixo

Uma mudança vizinha atinge exatamente os projetos C++ que guardam -ld_classic. A Apple elevou um piso, citando o macOS e nenhuma outra plataforma: “O deployment target mínimo suportado no macOS para a biblioteca padrão do C++ subiu para 11.0.”5

A mesma entrada oferece uma saída de emergência e marca a remoção dela na frase seguinte. A libc++ mudou o resultado de lower_bound e upper_bound em std::map e std::set para comparadores que não são uma ordem fraca estrita, e definir _LIBCPP_ENABLE_LEGACY_TREE_LOWER_UPPER_BOUND “vai reverter para a implementação histórica dessas operações.” Em seguida: “Essa saída de emergência será removida em uma versão próxima (provavelmente na próxima).”5 Uma mudança relacionada faz multimap::find e multiset::find deixarem de necessariamente retornar o primeiro elemento igual, comportamento que a Apple observa “nunca ter sido garantido pelo Padrão”, ainda que a libc++ sempre o oferecesse, e vem sem opção de desativar.5 Trate a macro como um ticket de migração, não como correção.

FAQ

Por que meu projeto tem -ld_classic?

Quase certamente porque as release notes do Xcode 15 mandaram. Dois Known Issues de lá recomendavam adicionar -Wl,-ld_classic a OTHER_LDFLAGS: um em que binários usando símbolos definidos como fracos travavam em tempo de execução no iOS 14 e no macOS 12 ou anteriores, o que a Apple registrou como algo que “afeta principalmente projetos C++”, e outro em que arquivos-objeto de LTO linkavam importações de símbolos fracos como não fracas.3 A Apple marcou a opção como obsoleta no Xcode 16 e removeu o linker por trás dela no Xcode 27.14 Se a flag estiver lá, confirme que o bug original ainda se reproduz antes de sair caçando substituto.

Como encontro nomes de módulo Clang duplicados no meu projeto?

Enumere as declarações de módulo de topo em todos os module maps, procure um nome que apareça em dois arquivos e tire os diretórios de build do resultado. Três coisas fazem disso mais que um grep: extern module Foo "path" é uma referência, não uma definição; module Foo.Bar estende um módulo declarado em outro lugar em vez de declarar Foo; e submódulos explicit module aninhados não colidem com nomes de topo.6 Exclua .build, build e DerivedData explicitamente, já que -not -path '*/build/*' deixa o .build passar e tanto o SwiftPM quanto o Xcode duplicam module maps gerados o tempo todo.9

Como é o erro no Xcode 27?

Não tenho como dizer, e ninguém que compila no Xcode 26 tem. Minha máquina roda o Xcode 26.6 (build 17F113), então não reporto nenhuma saída do Xcode 27.78 O que o Xcode 26.6 emite para dois module maps declarando o mesmo nome é error: redefinition of module 'Widget' com uma note: previously defined here, em toda execução de uma checagem de tipos simples.8 A formulação da Apple para o Xcode 27 é que a varredura “pode reportar um erro”, então procure redefinition of module nos logs, e não uma string que alguém chutou.

Uma falha de nome de módulo único depende do meu deployment target?

Não. A Apple formula a exigência em torno de uma única ação de varredura de dependências do Swift e não cita versão de sistema, SDK nem deployment target na entrada.2 A mudança do linker se lê do mesmo jeito, como remoção do toolchain.1 As duas caem no primeiro build no Xcode 27, ao lado da macro @State, e não junto das exigências disparadas pelo SDK no mesmo ciclo.

Principais conclusões

Para desenvolvedores iOS: - Consulte OTHER_LDFLAGS via xcodebuild -showBuildSettings -configuration Release -sdk iphoneos em vez de fazer grep por -ld_classic. Ausência nas configurações resolvidas significa que a configuração está sem valor; ausência em busca textual não significa nada.9 - Procure redefinition of module nos logs de build — o diagnóstico que o Xcode 26.6 já emite — e não um texto de erro do Xcode 27 inventado.8

Para times com dependências C ou C++ embarcadas: - Audite primeiro os arquivos module.modulemap embarcados contra o namespace do SDK: é o caso que a Apple cita, e hoje ele falha em silêncio. Meu shim SQLite3 embarcado compilou com exit 0 e fez sqlite3_open sumir.8 - Limite a auditoria ao código-fonte e exclua .build, build e DerivedData. Toda duplicata aparente entre 391 module maps era saída de build gerada para um único target Swift.9

Para quem gerencia releases: - Trate as duas mudanças como disparadas pelo toolchain e programe-as para o primeiro build no Xcode 27, não para a migração de SDK. Nenhuma delas menciona deployment target nem tem componente em tempo de execução.12 - Mantenha as ressalvas da Apple no ticket. A varredura “pode reportar um erro”, e 20 execuções de uma mesma colisão deram três desfechos diferentes, então um build que passa uma vez não prova nada.28


O ciclo 27 continua falhando em lugares diferentes: a chave da launch screen barra um envio, a obrigatoriedade do ciclo de vida de cenas barra a inicialização e a macro @State barra o build no nível do código-fonte. A remoção do linker e a regra de nome de módulo barram uma camada abaixo, nas partes do toolchain que ninguém configura de propósito. O hub completo é a Série Ecossistema Apple.

Referências


  1. Apple, Xcode 27 Release Notes, seção Linking, Deprecations in Xcode 27 Beta (radar 165165518). Fonte da remoção, citada na íntegra: “O linker ld64 foi removido e a opção -ld_classic não é mais suportada.” Verificado contra o JSON da documentação da Apple em 26 de julho de 2026, já que a página HTML renderiza o conteúdo via JavaScript. O título da página nessa data é “Xcode 27 Beta 4 Release Notes.” 

  2. Apple, Xcode 27 Release Notes, seção Swift Compiler, New Features in Xcode 27 Beta (radar 136303612). Fonte da entrada sobre o varredor de dependências, citada palavra por palavra e na íntegra no corpo deste artigo, incluindo as duas ressalvas (“a varredura pode reportar um erro” e “Antes, o varredor pode ter tolerado nomes duplicados”) e os dois casos nomeados. Verificado contra o JSON da documentação da Apple em 26 de julho de 2026. Registrado como arquivado em New Features, e não em Deprecations ou Known Issues. 

  3. Apple, Xcode 15 Release Notes, seção Linking. New Features (radar 108915312) é a fonte de “Um novo linker foi escrito para acelerar significativamente o link estático. Ele é o padrão para todos os binários de macOS, iOS, tvOS e visionOS e para quem usa o recurso ‘Mergeable Libraries’. O linker clássico ainda pode ser solicitado explicitamente com -ld64, e será removido em uma versão futura.” Known Issues é a fonte dos dois contornos que recomendam a flag: radar 114813650 (FB13097713), “Binários que usam símbolos com definição fraca travam em tempo de execução no iOS 14/macOS 12 ou anteriores. Isso afeta principalmente projetos C++, pelo uso extensivo que fazem de símbolos fracos.”, com o contorno de elevar o deployment target “ou adicionar -Wl,-ld_classic à build setting OTHER_LDFLAGS”; e radar 115521975 (FB13171424), “Importações de símbolos fracos são linkadas como importações não fracas quando usadas a partir de arquivos-objeto de LTO.”, com o contorno “Adicionar as opções -Wl,-weak_reference_mismatches,weak ou -Wl,-ld_classic à build setting OTHER_LDFLAGS.” Verificado contra o JSON da documentação da Apple em 26 de julho de 2026. 

  4. Apple, Xcode 16 Release Notes, seção Linking, Deprecations (radar 128502299): “a opção de linker -ld_classic está obsoleta e será removida em uma versão futura.” Verificado contra o JSON da documentação da Apple em 26 de julho de 2026. 

  5. Apple, Xcode 27 Release Notes, seção C++ Standard Library, Deprecations in Xcode 27 Beta. A Apple imprime um único radar para o bloco inteiro, 178191050, ao final do último item em vez de ao lado de cada um. Fonte de “O deployment target mínimo suportado no macOS para a biblioteca padrão do C++ subiu para 11.0”, da mudança em multi{map,set}::find (“código que depende de o primeiro elemento ser retornado por find vai quebrar, e lower_bound ou equal_range devem ser usados no lugar”) e da saída de emergência e seu prazo: “Como isso pode ser difícil de contornar em alguns casos, esta versão fornece uma saída de emergência: definir _LIBCPP_ENABLE_LEGACY_TREE_LOWER_UPPER_BOUND vai reverter para a implementação histórica dessas operações. Essa saída de emergência será removida em uma versão próxima (provavelmente na próxima).” Verificado contra o JSON da documentação da Apple em 26 de julho de 2026. 

  6. Time do Clang, Clang Modules documentation, Module Map Language. Fonte de “Cada módulo deve ter uma única definição”, da regra de module-id e da declaração extern module, de “O qualificador explicit só pode ser aplicado a um submódulo, isto é, a um módulo aninhado dentro de outro módulo”, e da descoberta de module maps pelo nome de arquivo module.modulemap, com module.map procurado por compatibilidade. Citado como referência do próprio toolchain para a linguagem de module map, e não como documento para desenvolvedores da Apple; o clang da Apple deriva dessa implementação. 

  7. Testes do autor no macOS 26.5.2 (build 25F84) com Xcode 26.6 (build 17F113), Apple clang 21.0.0, 26 de julho de 2026. Saída de comando reproduzida ao pé da letra. xcrun clang hello.c -o hello -Wl,-ld_classic imprime “ld: warning: -ld_classic is deprecated and will be removed in a future release” e sai com 0; trocar por -Wl,-ld64 imprime o warning idêntico, citando -ld_classic. xcrun ld -v reporta PROJECT:ld-1267 e as listas de arquitetura citadas acima. O ld-classic está presente em /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld-classic, com man page ao lado. As arquiteturas do SDK vêm de SDKSettings.plist: iPhoneOS 26.5 declara arm64e e arm64; WatchOS 26.5 declara arm64, arm64e e arm64_32. As contagens de module maps do SDK (1.099 declarações de topo em usr/include, 205 em System/Library/Frameworks, zero duplicatas nos dois casos) vêm de rodar o comando publicado acima contra o SDK do iPhoneOS 26.5; as 79 declarações extern module estão em usr/include/module.modulemap, e 13 module maps no mesmo diretório abrem um module Darwin.* com ponto (bank, Darwin_C, Darwin_Mach, Darwin_Mach_machine, Darwin_machine, Darwin_POSIX, Darwin_sys, device, mach_debug, net, netinet, netinet6 e uuid), que uma leitura por primeiro componente agrupa com a declaração real de Darwin em Darwin.modulemap como uma única colisão de 14 arquivos. O comportamento no Xcode 27 não foi testado, porque o Xcode 27 não estava instalado na máquina usada. 

  8. Reprodução do autor na mesma máquina e no mesmo toolchain, 26 de julho de 2026. Dois diretórios, cada um com um module.modulemap declarando module Widget, compilados com os dois diretórios no search path via swiftc. -typecheck produziu error: redefinition of module 'Widget' com note: previously defined here em 20 de 20 execuções, exit 1; tirar um dos caminhos -I fez o mesmo arquivo compilar com exit 0. -scan-dependencies sobre a mesma entrada, em 20 execuções, produziu nove saídas com sinal 11 (SIGSEGV), cinco com sinal 6 (SIGABRT) e seis saídas com status 0, com os rastreamentos de pilha das execuções que quebraram passando por swift::ModuleDependencyScanner::performParallelClangModuleLookup. Separadamente, um module map embarcado declarando SQLite3 (um módulo do SDK do iPhoneOS 26.5) colocado no search path passou na checagem de tipos com exit 0 e sem nenhum diagnóstico, enquanto um arquivo chamando o sqlite3_open do SDK sob a mesma configuração falhou com “error: cannot find ‘sqlite3_open’ in scope” e compilou limpo assim que o diretório embarcado saiu do search path. As fixtures incluíram um caminho com espaço para verificar o comando publicado. Esse comando compara nomes entre arquivos, então um nome declarado duas vezes dentro de um mesmo module map está fora do escopo dele por design. Nenhuma saída do Xcode 27 é reportada em qualquer ponto deste artigo. 

  9. Auditoria do autor em sete projetos Xcode (Reps, Return, Banana List, Ace Citizenship, Water, ResumeGeni e Yawara) no macOS 26.5.2 com Xcode 26.6 (build 17F113), 26 de julho de 2026. -ld_classic e ld64 aparecem zero vezes em qualquer working tree, e OTHER_LDFLAGS está sem valor em todos os projetos, sem nenhum arquivo .xcconfig, sem Podfile, sem Carthage e sem .framework ou .xcframework embarcado em lugar nenhum da frota; a busca cobriu apenas as working trees atuais, não o histórico do git nem logs de build arquivados, então o resultado é “ausente agora” e não “nunca usado”. A linha SUPPORTED_PLATFORMS citada para o Reps vem de xcodebuild -showBuildSettings -configuration Release -sdk iphoneos. Totais de module maps: 391 examinados, 204 sob os diretórios dos sete projetos e 187 nas árvores desses mesmos sete projetos dentro do ~/Library/Developer/Xcode/DerivedData compartilhado (o diretório compartilhado inteiro guarda muito mais, pertencentes a outros projetos), todos saída de build, com zero module maps escritos à mão ou embarcados em qualquer um dos sete repositórios. As duplicatas aparentes foram checadas por hash de conteúdo, e os dois geradores se comportam de formas diferentes. Os 15 pares de nomes do Xcode na árvore auditada do ResumeGeni (o build/DerivedData interno ao projeto), escritos uma vez em GeneratedModuleMaps-iphonesimulator/ e uma vez nos intermediários do target, são idênticos byte a byte nas 15 vezes, porque o Xcode emite caminho de header relativo. A contagem é por árvore, não por projeto: a árvore do mesmo app sob o ~/Library/Developer/Xcode/DerivedData compartilhado guarda 16, e a variante Index.noindex, 22. O que generaliza é o mecanismo, não o número. As cópias do SwiftPM não são idênticas: os seis arquivos de GrappleCore e os três de GrappleRender sob os diretórios .build do Yawara carregam seis e três hashes distintos e vão de 171 a 185 bytes, porque cada um embute um caminho absoluto para o -Swift.h gerado dentro do seu próprio build root e é idêntico no resto. Nenhum nome de módulo declarado na frota aparece entre os 1.318 nomes de topo distintos de módulos Clang que o comando publicado encontra quando apontado para o SDK inteiro do iPhoneOS 26.5, dos quais 1.099 ficam sob usr/include e 205 sob System/Library/Frameworks; a interseção com os nomes declarados pela frota é vazia. A mesma varredura reporta zero duplicatas no SDK inteiro, que é o controle negativo que a regra exige. O CryptoKit está ausente dessa lista porque é distribuído como framework só de Swift, sem module map Clang, então a ausência de colisão em Crypto se apoia no fato de o SDK não declarar nenhum módulo Clang com esse nome, e não em o CryptoKit ocupá-lo. O swift-crypto 4.4.0 fornece os únicos module maps escritos à mão no grafo de dependências resolvido (CCryptoBoringSSL, CCryptoBoringSSLShims, CXKCP, CXKCPShims, uma declaração cada). As variantes de host-tool e de target do SymbolKit estão no pacote local compartilhado 941Kit, não nos sete apps. As contagens de fontes excluem virtualenvs de Python, e essa correção fez diferença: uma contagem ingênua creditou ao Reps arquivos C e headers que, no fim, moravam todos dentro de .venv e site-packages e não são compilados por nenhum target do Xcode. O Water não tem árvore de build local, então sua contagem zero de module maps reflete um projeto não compilado, e não um grafo de build verificado como limpo. As três armadilhas de falso-limpo foram confirmadas uma a uma: o timeout não existe no macOS de fábrica e sai com 127; o zsh expande um --include=*.pbxproj sem aspas e aborta com “no matches found”; e xcrun --sdk iphoneos --show-sdk-path devolve um symlink, contra o qual o find sem -H reporta zero module maps onde o find -H reporta 266. 

  10. Apple, Xcode 26 Release Notes. Busca por ld_classic, ld64 e qualquer entrada que descrevesse o linker clássico em 26 de julho de 2026; nenhuma aparece, então o aviso de obsolescência da Apple no Xcode 16 e a remoção no Xcode 27 não têm nenhuma reafirmação intermediária. 

  11. Apple, Xcode 27 Release Notes, Overview: “O Xcode 27 beta 4 inclui o Swift 6.4 e SDKs para iOS 27, iPadOS 27, tvOS 27, watchOS 27, macOS 27 e visionOS 27.” As mesmas notas registram, em Intel Deprecation (radar 162138432), que “o Xcode 27 só será instalado e executado em Macs com Apple silicon”. Checado em 26 de julho de 2026. 

Artigos relacionados

A macro @State: o que o Xcode 27 deixa de compilar

O Xcode 27 reimplementa o @State do SwiftUI como macro do Swift. A quebra vem da atualização do toolchain, não do deploy…

18 min de leitura

Xcode 27 abandona o Intel: o que acaba e o que continua sendo distribuído

O Xcode 27 só roda em Apple silicon, ainda gera apps Universal até o macOS 12 e remove o x86_64 do ARCHS_STANDARD com de…

23 min de leitura