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
SQLite3embarcado passou na checagem de tipos com exit 0, esqlite3_opendeixou de existir.8 - Em sete projetos auditados: zero
-ld_classic,OTHER_LDFLAGSsem 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
-
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_classicnã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.” ↩↩↩↩↩ -
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. ↩↩↩↩↩↩
-
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 settingOTHER_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,weakou-Wl,-ld_classicà build settingOTHER_LDFLAGS.” Verificado contra o JSON da documentação da Apple em 26 de julho de 2026. ↩↩↩↩↩↩ -
Apple, Xcode 16 Release Notes, seção Linking, Deprecations (radar 128502299): “a opção de linker
-ld_classicestá obsoleta e será removida em uma versão futura.” Verificado contra o JSON da documentação da Apple em 26 de julho de 2026. ↩↩↩ -
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 porfindvai quebrar, elower_boundouequal_rangedevem 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_BOUNDvai 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. ↩↩↩ -
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 qualificadorexplicitsó 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 arquivomodule.modulemap, commodule.mapprocurado 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. ↩↩ -
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_classicimprime “ld: warning: -ld_classic is deprecated and will be removed in a future release” e sai com 0; trocar por-Wl,-ld64imprime o warning idêntico, citando-ld_classic.xcrun ld -vreportaPROJECT:ld-1267e as listas de arquitetura citadas acima. Old-classicestá 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 deSDKSettings.plist: iPhoneOS 26.5 declaraarm64eearm64; WatchOS 26.5 declaraarm64,arm64eearm64_32. As contagens de module maps do SDK (1.099 declarações de topo emusr/include, 205 emSystem/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çõesextern moduleestão emusr/include/module.modulemap, e 13 module maps no mesmo diretório abrem ummodule Darwin.*com ponto (bank,Darwin_C,Darwin_Mach,Darwin_Mach_machine,Darwin_machine,Darwin_POSIX,Darwin_sys,device,mach_debug,net,netinet,netinet6euuid), que uma leitura por primeiro componente agrupa com a declaração real deDarwinemDarwin.modulemapcomo 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. ↩↩↩↩↩↩↩↩↩↩ -
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.modulemapdeclarandomodule Widget, compilados com os dois diretórios no search path viaswiftc.-typecheckproduziuerror: redefinition of module 'Widget'comnote: previously defined hereem 20 de 20 execuções, exit 1; tirar um dos caminhos-Ifez o mesmo arquivo compilar com exit 0.-scan-dependenciessobre 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 porswift::ModuleDependencyScanner::performParallelClangModuleLookup. Separadamente, um module map embarcado declarandoSQLite3(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 osqlite3_opendo 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. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
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_classiceld64aparecem zero vezes em qualquer working tree, eOTHER_LDFLAGSestá sem valor em todos os projetos, sem nenhum arquivo.xcconfig, sem Podfile, sem Carthage e sem.frameworkou.xcframeworkembarcado 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 linhaSUPPORTED_PLATFORMScitada para o Reps vem dexcodebuild -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/DerivedDatacompartilhado (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 (obuild/DerivedDatainterno ao projeto), escritos uma vez emGeneratedModuleMaps-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/DerivedDatacompartilhado guarda 16, e a varianteIndex.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 deGrappleCoree os três deGrappleRendersob os diretórios.builddo 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.hgerado 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 sobusr/includee 205 sobSystem/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. OCryptoKitestá ausente dessa lista porque é distribuído como framework só de Swift, sem module map Clang, então a ausência de colisão emCryptose apoia no fato de o SDK não declarar nenhum módulo Clang com esse nome, e não em oCryptoKitocupá-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 doSymbolKitestã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.venvesite-packagese 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: otimeoutnão existe no macOS de fábrica e sai com 127; o zsh expande um--include=*.pbxprojsem aspas e aborta com “no matches found”; excrun --sdk iphoneos --show-sdk-pathdevolve um symlink, contra o qual ofindsem-Hreporta zero module maps onde ofind -Hreporta 266. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple, Xcode 26 Release Notes. Busca por
ld_classic,ld64e 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. ↩↩ -
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. ↩