Accueil / Blog / Swift 6.4 duplic
ENGINEERING_BLOG · 2026.09.08

Swift 6.4 duplicate module name : correction du CI Mac distant 2026

Le nœud stable compile, mais le nœud Swift 6.4 échoue dès la première analyse avec duplicate module name : ne reconstruisez pas encore la machine et ne videz pas tout le cache.

La correction la plus rapide consiste à identifier les deux déclarations module.modulemap réellement accessibles, leurs chemins de recherche et leur dépendance d’origine, puis à supprimer la déclaration redondante, mettre à jour le SDK ou renommer votre module. Si le conflit vient d’un composant tiers impossible à modifier immédiatement, gardez l’outil stable en production et validez Swift 6.4 sur une ligne isolée.

SECTION 01 Périmètre du diagnostic

Cet article s’adresse aux développeurs qui maintiennent un projet Swift mêlant Objective-C, C, C++ ou SDK binaire et qui voient apparaître un conflit après une mise à niveau. Il concerne aussi les ingénieurs DevOps responsables des nœuds Mac distants, des caches de dépendances et du changement d’outil de compilation, ainsi que les responsables de plateforme qui doivent choisir entre correction, report et double CI.

Dernière mise à jour : 8 septembre 2026. Les informations relatives à Swift 6.4, à Xcode 27 beta 6 et au scanner de dépendances ont été vérifiées dans les notes de version officielles de Xcode 27 et dans les exigences système de Xcode. Une prochaine vérification sera nécessaire à la sortie de Xcode 27 RC ou final, de Swift 6.4 final, ou d’une correction majeure publiée par un fournisseur de dépendances.

Ne confondez pas les erreurs suivantes :

  • duplicate module name ou une variante équivalente : plusieurs déclarations de module homonymes sont visibles pendant l’analyse ;
  • redefinition : un symbole, une structure ou une définition est déclaré plusieurs fois ;
  • module not found : le compilateur ne trouve pas le module demandé ;
  • une erreur d’éditeur de liens : la compilation a abouti, mais une bibliothèque ou un symbole manque ensuite.

Le premier diagnostic exploitable du journal compte davantage que le code de sortie final. Conservez la commande complète, le commit, le fichier de dépendances verrouillées, l’outil actif, le SDK sélectionné et le nœud d’exécution. Un nœud stable et un nœud Swift 6.4 ne constituent pas une comparaison utile si leurs environnements ont changé en même temps.

SECTION 02 Source du conflit

Projet et module privé

La première source est votre propre couche d’intégration. Recherchez les fichiers module.modulemap dans le dépôt, les scripts de génération, les en-têtes exportés et les répertoires de bibliothèques internes. Un module privé peut être déclaré dans le dépôt tout en étant exposé une seconde fois par un paquet local ou une cible de test.

Ne vous contentez pas de compter les fichiers. Pour chaque déclaration, relevez :

  1. le nom placé après module ;
  2. l’en-tête ou le répertoire d’entrée ;
  3. le chemin absolu trouvé par la commande de compilation ;
  4. la cible qui ajoute ce chemin ;
  5. le composant propriétaire de la déclaration.

Un Bridging Header, un Header Search Path trop large et un paramètre transmis directement au compilateur peuvent rendre visible une copie qui n’était jamais chargée sur le poste local. La documentation Apple sur les réglages de construction d’une cible aide à distinguer les chemins hérités des chemins explicitement ajoutés par le projet.

La correction durable consiste à conserver une seule déclaration par nom et par périmètre. Fusionnez les entrées si elles décrivent réellement le même module ; renommez votre module si deux composants indépendants ont choisi le même identifiant ; retirez enfin le chemin redondant de la cible concernée. Supprimer un répertoire au hasard peut faire disparaître l’erreur pendant une exécution et casser une autre cible au prochain changement de configuration.

Dépendance tierce et SDK binaire

La seconde source se trouve dans une dépendance vendue ou générée en dehors du dépôt principal. Examinez les sources intégrées, les XCFramework, les paquets Swift, les SDK copiés manuellement et les archives produites par votre fournisseur. Un même nom peut apparaître dans deux composants tiers, ou un SDK peut déclarer à tort un nom déjà réservé par un module système.

Les instructions Swift Package Manager relatives aux dépendances de type bibliothèque système décrivent le rôle du module map dans cette intégration. Les informations techniques de swift-clang sur les modules permettent ensuite de vérifier la structure de la déclaration plutôt que de raisonner uniquement à partir du nom du fichier.

Deux décisions sont distinctes :

  • si deux composants tiers se déclarent sous le même nom, cherchez une version compatible, une option d’intégration officielle ou une variante du fournisseur ;
  • si un composant réutilise le nom d’un module système, isolez-le et confirmez la portée du problème avant toute modification locale.

Un correctif appliqué directement dans un binaire ou dans un dossier généré n’est pas une solution de production tant qu’il n’est pas reproductible. Documentez le fichier modifié, le paquet d’origine, le mécanisme de restauration et la condition de retrait. Pour une dépendance non modifiable, la ligne Swift 6.4 doit rester une validation de compatibilité, pas devenir le chemin de livraison par défaut.

SECTION 03 Preuves dans le CI distant

Un CI Mac distant ajoute souvent des variables que le poste du développeur ne possède pas : chemin Homebrew, répertoire d’outils partagé, SDK sélectionné, compte de service, shell non interactif, répertoire de travail différent ou cache réutilisé entre projets. Le problème n’est donc pas nécessairement « le Mac distant » ; il peut venir d’un répertoire supplémentaire devenu visible pendant l’analyse.

Comparez, pour une exécution locale réussie et une exécution distante échouée :

  • la version et le chemin de l’outil Swift actif ;
  • le SDK et la destination de compilation ;
  • les variables d’environnement exportées par le service CI ;
  • le contenu de Package.resolved ou de l’équivalent utilisé ;
  • les paramètres de recherche des en-têtes et des modules ;
  • les arguments ajoutés par le script de construction ;
  • le compte, le shell et le répertoire de travail.

Les diagnostics du compilateur doivent vous montrer quel module.modulemap est chargé. Utilisez les options de traçage documentées par votre version de Clang et de Swift, puis archivez la sortie avec les autres journaux. La documentation officielle de Clang sur les modules est la référence pour interpréter la recherche et le chargement des modules ; elle ne remplace toutefois pas la preuve issue de votre commande réelle.

Attention : un nettoyage global du nœud peut supprimer les indices nécessaires, interrompre des tâches concurrentes et rendre impossible la comparaison avec l’exécution précédente. Copiez d’abord les journaux et testez dans un cache dédié.

Le cache peut masquer deux situations opposées. Un Module Cache ou un répertoire DerivedData ancien peut conserver un état qui n’existe plus dans une copie propre ; inversement, un nettoyage précipité peut faire croire que le conflit est résolu alors que deux déclarations restent présentes. Commencez par un nouveau répertoire de travail et un chemin de cache indépendant. Ne supprimez ensuite que le cache associé à cette expérience, en notant son propriétaire, sa portée et la méthode de restauration.

SECTION 04 Parcours de correction

Suivez cet ordre afin de conserver une preuve exploitable :

  1. Figer le cas de référence. Enregistrez le commit, le fichier de dépendances, l’outil actif, le SDK, la commande complète et le premier diagnostic. Ne remplacez pas ces éléments par le seul code de sortie.
  2. Reproduire sans héritage. Lancez le même commit dans un répertoire neuf avec un cache indépendant. Si l’erreur disparaît, comparez les chemins et les journaux avant de conclure à un problème de cache.
  3. Cartographier les déclarations. Listez les module.modulemap, les noms de modules, les entrées d’en-têtes et les chemins de recherche. Reliez chaque chemin à une cible, un paquet, un XCFramework ou un script.
  4. Classer la cause. Décidez s’il s’agit d’un doublon du projet, de deux dépendances tierces, d’un conflit avec un module système ou d’un chemin CI supplémentaire.
  5. Appliquer la correction la moins invasive. Retirez un chemin redondant, fusionnez une déclaration maîtrisée, renommez votre module ou adoptez une version tierce compatible. Ne modifiez pas durablement un artefact généré sans procédure de reproduction.
  6. Tester à froid. Construisez sans l’ancien Module Cache ni les anciens artefacts, puis archivez les chemins chargés et le résultat.
  7. Tester en incrémental. Relancez la même cible avec le cache nouvellement créé. Une construction incrémentale réussie ne suffit pas si la construction froide échoue.
  8. Comparer les outils. Rejouez le même commit et les mêmes paramètres avec l’outil stable et Swift 6.4. Conservez les deux journaux, y compris lorsque les deux constructions réussissent.
  9. Décider le déploiement. N’élargissez pas Swift 6.4 à la production tant que la source du module n’est pas unique et que plusieurs exécutions comparables ne sont pas cohérentes.

SECTION 05 Conditions de décision

  • Si une seule dépendance contrôlée par votre équipe possède la déclaration en double, choisissez la fusion ou le renommage, puis validez une construction froide et une incrémentale.
  • Si deux composants tiers portent le même nom, choisissez la mise à jour ou la variante officiellement compatible ; sinon, isolez le composant et maintenez l’outil stable en production.
  • Si le problème apparaît uniquement avec un chemin ajouté par le CI, choisissez la correction du script ou de la cible ; ne supprimez pas les répertoires partagés sans savoir quelles autres tâches les utilisent.
  • Si le nettoyage ciblé change seulement le résultat d’une exécution, choisissez une nouvelle reproduction et recherchez l’état de cache ; le nettoyage n’est pas encore une réparation.
  • Si le module reste ambigu après la correction, revenez temporairement à l’outil stable et gardez Swift 6.4 sur une ligne de compatibilité.
  • Si le module est unique, que la construction froide et la construction incrémentale passent avec les mêmes paramètres, autorisez une montée progressive, avec retour documenté.

SECTION 06 Questions fréquentes

Pourquoi l’ancien outil réussissait-il ?

Le changement de version peut modifier la façon dont les dépendances atteignables sont examinées, mais l’échec précis doit rester attaché au journal de votre projet. Les notes de version de Xcode 27 indiquent que les noms de modules Clang visibles lors d’une même analyse doivent être uniques. Cela explique pourquoi un doublon auparavant toléré ou non atteint devient bloquant, sans prouver que chaque projet est affecté.

Correspondance des fichiers module.modulemap

Commencez par la commande réellement exécutée sur le nœud distant, puis activez ses diagnostics de chargement. Cherchez les chemins lus, pas seulement les noms de fichiers présents sur le disque. Comparez ensuite ces chemins avec les sources vendues, les XCFramework et les paquets Swift. Une copie non chargée n’est pas encore la cause ; une copie chargée depuis un répertoire inattendu est une piste prioritaire.

Le nettoyage de DerivedData est-il suffisant ?

Il ne l’est que si le cache contient un état périmé et que les déclarations accessibles sont déjà uniques. Dans le cas contraire, le prochain nœud ou la prochaine construction recréera le conflit. Utilisez un chemin de cache indépendant pour tester cette hypothèse, conservez l’ancien cache tant que les journaux ne sont pas archivés et vérifiez ensuite une construction froide puis une construction incrémentale.

Retour ou double ligne pour un SDK tiers ?

Lorsque le SDK ne peut pas être modifié, la double ligne est généralement plus sûre qu’un retour global : l’outil stable protège la livraison, tandis que Swift 6.4 expose la compatibilité à corriger. Cette séparation exige le même commit, les mêmes dépendances verrouillées et des paramètres comparables. Un retour complet n’est justifié que si la ligne de validation consomme des ressources ou bloque d’autres livraisons.

SECTION 07 Comparaison des stratégies

Le tableau suivant ne remplace pas la preuve du journal ; il sert à choisir le prochain mouvement après classification du conflit.

Situation observée Action immédiate Validation attendue Décision de livraison
Déclaration double dans votre projet Fusionner ou renommer le module contrôlé Construction froide puis incrémentale Swift 6.4 possible après répétition cohérente
Deux dépendances tierces homonymes Chercher une version ou une intégration compatible Même commit avec dépendances verrouillées Stable en production tant que le fournisseur n’a pas corrigé
Chemin ajouté uniquement par le CI Corriger le script ou la cible Journal des chemins avant et après Déploiement progressif après comparaison
Cache suspect Utiliser un cache indépendant et ciblé Résultats froid et incrémental Pas de conclusion avant les deux essais
Module système redéclaré Isoler le SDK et vérifier sa documentation Cible minimale puis projet complet Double ligne si le SDK reste non modifiable

Si vous gérez plusieurs générations de nœuds, consignez aussi le chemin de l’outil, le SDK et le compte de service dans l’artefact de CI. Pour une équipe qui doit maintenir plusieurs versions de Xcode, la démarche de déploiement d’un environnement de développement sans droits administrateur sur Mac distant peut compléter ce diagnostic, notamment lorsque les outils et les caches ne doivent pas être installés dans les répertoires personnels des développeurs.

SECTION 08 Repères de validation du nœud

Élément à comparer Nœud stable Nœud Swift 6.4 Preuve à conserver
Commit source Identique Identique Identifiant du commit
Dépendances Même verrouillage Même verrouillage Fichier de résolution archivé
Paramètres de compilation Identiques Identiques Commande complète
Chemins de modules Journalisés Journalisés Sortie de diagnostic
Cache Référence connue Indépendant au premier essai Chemin et date de création
Résultat Construction froide et incrémentale Construction froide et incrémentale Journaux et statut de chaque étape

Un Mac distant est particulièrement utile ici si vous pouvez réserver un nœud de validation isolé, conserver deux outils côte à côte et réinitialiser uniquement les répertoires nécessaires. Il est moins adapté si votre processus exige un périphérique physique précis ou si la charge de compilation reste lourde et constante sur une longue période : dans ce cas, comparez le coût d’un Mac dédié, d’un nœud interne et d’une location selon votre durée réelle d’utilisation. Vous pouvez consulter les formules Mac distantes de VPSNIX, puis vérifier les conditions d’accès et de réinitialisation avant de choisir.

Pour une équipe qui doit installer un nœud de comparaison rapidement, la procédure de commande d’un Mac distant n’a de sens qu’après avoir défini les versions d’outils, les caches à isoler et les secrets qui ne doivent pas quitter la ligne de production. Le but n’est pas de déplacer aveuglément le CI, mais de rendre la comparaison Swift 6.4/stable répétable.

Votre environnement actuel peut masquer le conflit par des chemins implicites, dépendre d’un Mac local indisponible en permanence ou mélanger plusieurs caches entre projets ; il peut aussi exiger un achat matériel pour une validation qui ne dure que quelques jours. Une location VPSNIX offre alors une voie plus souple pour maintenir la ligne stable tout en disposant d’un Mac distant réinitialisable pour l’essai Swift 6.4. En revanche, pour une charge continue et prévisible ou pour l’accès à du matériel physique, l’achat ou l’hébergement interne peut rester plus pertinent. Décidez uniquement après avoir mesuré la durée de la double ligne et la fréquence de vos validations.

Pour aller plus loin