Symptôme : la commande de compilation se termine correctement, puis l’étape d’archivage signale que le binaire, le rapport de test ou l’archive est introuvable.
Correctif le plus rapide : ne devinez plus les sous-dossiers de .build ; exécutez swift build --show-bin-path avec les mêmes paramètres que la compilation, puis alignez la collecte d’artefacts et l’identité du cache sur ce chemin réel.
Cet article s’adresse aux personnes qui maintiennent des scripts Shell, Fastlane ou CI après une mise à niveau vers SwiftPM 6.4. Il concerne aussi les auteurs de Swift Package et de plugins, ainsi que les ingénieurs DevOps responsables de nœuds Mac distants, de caches et de procédures de retour arrière.
Dernière mise à jour : 27 août 2026. Les informations de comportement et de statut sont vérifiées dans les documents SwiftPM, Swift Build, Swift Evolution et Apple Developer référencés ci-dessous. Le statut de Swift 6.4 et celui de Xcode 27 doivent être revérifiés lors d’une nouvelle version Beta, RC ou finale.
Diagnostic initial du pipeline
La première distinction à faire est entre trois pannes qui se ressemblent dans les journaux :
- la compilation échoue réellement ;
- la compilation réussit, mais le script reconstruit un mauvais chemin ;
- la commande s’exécute dans un autre répertoire de travail que celui utilisé par la phase de collecte.
Depuis le changement documenté du système de build par défaut, l’ancien modèle mental « le binaire se trouve toujours à tel emplacement sous .build » ne constitue plus une interface CI fiable. La documentation officielle de migration vers Swift Build recommande précisément d’interroger le chemin de sortie plutôt que de dépendre d’une arborescence interne.
Conservez donc, dans un artefact de diagnostic, les éléments suivants :
- la commande exacte, avec toutes ses options ;
- le répertoire de travail absolu ;
- la version de Swift et l’état de
xcode-select; - l’architecture, la configuration et la destination ;
- la sortie complète de
swift build --show-bin-path; - le chemin effectivement utilisé pour la copie ;
- l’état de sortie de chaque étape, et non seulement celui du pipeline final.
cd manquant.
Grille de décision avant modification
Ne commencez pas par remplacer toutes les commandes du pipeline. Identifiez d’abord le rôle de chaque chemin et la personne qui le consomme. Un binaire destiné à l’exécution, une ressource de plugin et un rapport de test ne doivent pas être traités comme s’ils provenaient nécessairement du même répertoire.
| Élément observé | Hypothèse risquée | Vérification recommandée | Score de confiance |
|---|---|---|---|
| Binaire exécutable | Sous-dossier .build fixe | swift build --show-bin-path avec les paramètres du build | 5/5 |
| Ressource ou sortie de plugin | Chemin concaténé dans le plugin | Inspecter les entrées, sorties et journaux du plugin | 4/5 |
| Rapport de test | Tous les tests partagent un dossier | Contrôler la source du rapport et l’état de swift test | 4/5 |
| Archive de publication | Le répertoire du build suffit | Vérifier séparément la commande d’archivage et son fichier final | 3/5 |
| Cache CI | Le chemin seul identifie le résultat | Ajouter outil, architecture, configuration et verrouillage des dépendances | 5/5 |
5/5 signifie que vous utilisez une information produite par l’outil lui-même, tandis qu’un score inférieur signale une hypothèse à confirmer dans vos journaux.
Scripts et collecte d’artefacts
Le premier chantier concerne les fichiers Shell, Makefile, Fastlane ou scripts de publication. Recherchez les constructions qui ressemblent à :
BUILD_DIR=".build/..."
BIN="$BUILD_DIR/debug/..."
cp "$BIN" "$CI_ARTIFACTS/"
Le problème n’est pas nécessairement la commande cp. Il peut se trouver plusieurs lignes plus tôt, lorsque le script fabrique un chemin à partir de debug, d’une architecture ou d’un nom de produit sans demander à SwiftPM où la tâche a réellement écrit le résultat.
Une version plus robuste conserve les paramètres dans une même liste :
PACKAGE_DIR="${CI_WORKSPACE}/<package>"
CONFIGURATION="debug"
ARCHITECTURE="<architecture>"
DESTINATION="<destination>"
cd "$PACKAGE_DIR" || exit 1
BUILD_ARGS=(
--configuration "$CONFIGURATION"
--arch "$ARCHITECTURE"
--destination "$DESTINATION"
)
swift build "${BUILD_ARGS[@]}"
BIN_PATH="$(
swift build "${BUILD_ARGS[@]}" --show-bin-path
)" || exit 1
test -d "$BIN_PATH" || {
printf '%s\n' "Répertoire de sortie absent : $BIN_PATH" >&2
exit 1
}
find "$BIN_PATH" -type f -maxdepth 2 -print
Adaptez les options disponibles à votre version et à votre type de produit, mais gardez la règle essentielle : la commande de requête doit reprendre la même configuration, la même architecture et la même destination que la commande de compilation. Une requête effectuée en mode debug ne valide pas la collecte d’un build release.
Ne masquez pas les erreurs de résolution :
printf 'workspace=%s\n' "$PWD"
printf 'swift=%s\n' "$(swift --version)"
printf 'bin_path=%s\n' "$BIN_PATH"
Dans Fastlane, transmettez la valeur obtenue à l’étape qui archive ou téléverse le produit, au lieu de dupliquer la logique de chemin dans plusieurs actions. Dans un Makefile, utilisez une cible de découverte séparée, mais appelez-la avec les variables du même contexte. Dans tous les cas, refusez silencieusement un répertoire vide : un téléversement « réussi » d’un mauvais dossier est plus difficile à détecter qu’un échec explicite.
Paquets et plugins
Les auteurs de Swift Package ont un autre risque : leur propre code peut contenir la même hypothèse fragile que le script CI. Examinez les plugins de build, les plugins de commande, les cibles binaires, le traitement des ressources et les scripts qui fabriquent un chemin relatif à partir de .build.
Un plugin devrait déclarer clairement ce qu’il consomme et ce qu’il produit. Il faut pouvoir répondre à quatre questions dans ses journaux :
- quelles entrées ont été fournies ;
- quelle commande a été exécutée ;
- où la sortie a été écrite ;
- quel fichier précis est ensuite consommé par la phase suivante.
Les ressources demandent une vérification distincte. Une image, un fichier audio, une bibliothèque native ou une ressource de design peut être copiée par une étape différente de celle qui produit le binaire. Pour un projet audio ou vidéo, ne validez donc pas uniquement l’existence de l’exécutable : contrôlez aussi les noms, les permissions et la présence des ressources attendues dans le paquet final.
Si vous rencontrez une divergence qui ne s’explique pas par votre script, créez un dossier de problème séparé pour le comportement Swift Build. Le suivi officiel d’une différence de répertoire de sortie doit servir de référence pour documenter un cas reproductible, pas de justification pour ignorer une erreur locale de chemin.
Tests et rapports
La collecte de tests ne doit pas être réduite à test -f rapport. Un pipeline fiable vérifie au minimum trois résultats indépendants :
- l’état de sortie de
swift test; - la source réelle du rapport ou du journal ;
- la capacité à identifier la suite et le cas ayant échoué.
Conservez temporairement deux tâches de comparaison :
swift test \
--configuration "<configuration>" \
--parallel
printf 'test_exit=%s\n' "$?"
La commande exacte dépend de votre projet et de votre version d’outillage ; l’important est d’enregistrer son état avant qu’un script de nettoyage ne l’écrase. Ajoutez ensuite une étape qui liste les rapports réellement présents, avec leur chemin absolu, puis archivez uniquement les fichiers attendus.
Pour une comparaison avec le système native, utilisez le même commit, la même configuration, la même architecture et un espace de travail neuf. Si Swift Build réussit et que native échoue, ou inversement, ne concluez pas à un problème du Mac distant avant d’avoir comparé les journaux et les paramètres. Une différence de rapport peut venir du lanceur de test, pas du compilateur.
Cache et nœuds Mac distants
Un cache CI ne doit jamais être identifié par le seul nom du dépôt. Au minimum, son identité doit intégrer :
- la version de Swift ;
- le système de build sélectionné ;
- l’architecture ;
- la configuration ;
- la destination ;
- le fichier de verrouillage des dépendances ;
- les paramètres qui modifient la production des artefacts.
Sur chaque Mac distant, contrôlez également :
printf 'user=%s\n' "$USER"
printf 'workspace=%s\n' "$PWD"
xcode-select -p
swift --version
uname -m
Ne prenez pas uname -m comme preuve suffisante de l’architecture réellement ciblée : comparez-le avec l’architecture passée au build et avec celle attendue par le produit. Vérifiez aussi que le compte d’exécution possède les droits de lecture sur le workspace et d’écriture dans le répertoire d’artefacts. Une session SSH, une session VNC et un agent CI peuvent utiliser des environnements différents, notamment pour le PATH, le trousseau et les variables chargées par le shell.
La validation doit couvrir trois situations : cache froid, cache chaud et tâche exécutée après redémarrage du nœud. Un Mac distant utilisé comme nœud permanent doit être testable après une reconnexion SSH, une relance de l’agent et une recréation du workspace. Si votre infrastructure actuelle mélange ces responsabilités, vous pouvez examiner une configuration de développement Swift sur Mac distant avant de déplacer le correctif en production.
Matrice de basculement
Le retour temporaire au système native est un outil de diagnostic, non une réparation automatique. Le changement officiellement documenté du système par défaut doit être confronté aux paramètres de votre dépôt, à vos plugins et à vos rapports de test. La note de développement sur le changement du système par défaut donne le contexte nécessaire, tandis que le dépôt officiel Swift Evolution permet de vérifier le statut des versions et propositions.
| Parcours | Build | Tests | Collecte | Signature ou publication | Décision |
|---|---|---|---|---|---|
| Swift Build, cache froid | Réussi ou échec documenté | État conservé | Chemin interrogé | Contrôle complet | Base de référence |
| Swift Build, cache chaud | Même commit validé | Rapport retrouvé | Aucun ancien chemin utilisé | Même résultat | Autoriser l’essai prolongé |
| Swift Build après redémarrage | Nœud correctement initialisé | Agent reconnecté | Répertoire recréé | Publication contrôlée | Valider la reprise |
| Native, mêmes paramètres | Comparaison | Comparaison | Chemin séparé | Comparaison | Diagnostiquer seulement |
| Production actuelle | Résultat historique | Résultat historique | Ancienne logique | Livraison existante | Ne pas considérer comme preuve |
- si Swift Build réussit dans les trois conditions et que la collecte interroge son chemin réel, poursuivez avec Swift Build ;
- si seule la collecte échoue, corrigez le script et le cache avant de changer de système ;
- si Swift Build et native divergent avec un minimum reproductible, isolez le problème et consultez les problèmes officiels ;
- si le nœud distant est instable après redémarrage, suspendez le basculement et corrigez d’abord l’environnement ;
- si la production ne peut pas absorber le risque, maintenez temporairement native, mais fixez une condition explicite de retour à Swift Build.
Validation avant livraison
Utilisez cette liste sur un commit identique, d’abord dans un workspace neuf, puis sur un nœud déjà utilisé :
- [ ] La commande complète de build est enregistrée avec sa version de Swift.
- [ ]
swift build --show-bin-pathreprend la configuration du build. - [ ] L’architecture et la destination sont identiques entre compilation et interrogation.
- [ ] Aucun script ne concatène un ancien sous-dossier
.builden dur. - [ ] Le binaire, les ressources et les éventuels plugins sont contrôlés séparément.
- [ ] L’état de sortie de
swift testest conservé avant le nettoyage. - [ ] Le rapport de test permet de retrouver une suite et un cas défaillant.
- [ ] La clé de cache contient l’outil, le système de build et le verrouillage des dépendances.
- [ ] Un cache froid et un cache chaud donnent une collecte équivalente.
- [ ] Le pipeline fonctionne après redémarrage du Mac distant et reconnexion de l’agent.
- [ ] La tâche native parallèle utilise le même commit et les mêmes paramètres.
- [ ] Le choix de production, de retour arrière ou d’essai isolé est écrit dans le runbook.
Votre solution actuelle, fondée sur un Mac physique dédié ou sur un nœud partagé, peut rester pertinente pour une charge stable, un accès continu à des périphériques physiques ou une longue exploitation amortie. Elle devient toutefois moins confortable lorsque chaque mise à niveau exige de conserver une machine allumée, de nettoyer manuellement les caches, de reproduire un environnement qui dérive et de réserver une capacité pour un incident ponctuel. Pour une campagne de validation isolée, louer un Mac avec MACGPU vous permet de disposer d’un environnement distant réinitialisable, d’exécuter les scénarios à froid et après redémarrage, puis de décider avec des journaux plutôt qu’avec une hypothèse. Consultez les options de Mac distant pour vos essais CI si votre nœud de production ne doit pas être le premier terrain de migration.
Questions fréquentes
SwiftPM 6.4 et les binaires introuvables
Un changement d’organisation interne peut rendre obsolète un chemin codé en dur sous .build, sans empêcher la compilation de produire un résultat. La correction consiste à demander à SwiftPM le répertoire associé aux paramètres courants, puis à faire consommer cette valeur par le script d’archivage. Si l’emplacement interrogé est lui-même incohérent, conservez un minimum reproductible avant de modifier le pipeline.
Récupération du chemin dans le CI
Appelez swift build --show-bin-path après avoir défini le répertoire du paquet et les variables de configuration, d’architecture et de destination. La commande de découverte doit recevoir les mêmes options que la compilation ; sinon, elle peut renvoyer un emplacement valide mais sans rapport avec l’artefact recherché. Vérifiez ensuite le répertoire, listez son contenu et échouez explicitement s’il est vide.
Différence entre Swift Build et native
Les deux systèmes peuvent produire un résultat fonctionnel comparable tout en exposant des chemins, des rapports ou des fichiers intermédiaires différents. La comparaison doit donc porter sur les sorties réellement imprimées, et non sur une reconstitution de .build. Un scénario native qui fonctionne ne démontre pas que votre script Swift Build est correct ; il peut seulement révéler une différence à documenter.
Échec d’envoi depuis un Mac distant
Commencez par déterminer si l’échec se produit avant ou après la production du fichier. Sur le Mac distant, capturez le workspace, le compte, xcode-select, l’architecture, la version Swift, les permissions et le chemin retourné. Nettoyez ensuite le cache et répétez la tâche. Si le problème persiste uniquement avec Swift Build, gardez native comme voie temporaire de diagnostic et ne généralisez pas ce résultat à tous les nœuds.
La correction durable est donc précise : interroger le chemin produit par l’outil, rendre le cache dépendant de l’environnement réel, puis prouver la collecte sur un workspace neuf, un cache existant et un nœud redémarré. Si vous devez isoler ce changement sans exposer votre chaîne de livraison, un Mac distant réinitialisable est généralement plus approprié qu’une modification directe du seul nœud de production.