Après l’ouverture à distance d’un vaste espace de travail Xcode, les ventilateurs restent hors de vue, mais la courbe CPU affichée dans le terminal continue de grimper. La complétion de code demeure bloquée sur « Indexation en cours » et l’accès à la définition ne renvoie aucun résultat. Dans cette situation, l’action la plus risquée n’est pas d’attendre, mais de supprimer directement tout le répertoire de développement. Il faut d’abord déterminer si la charge provient de la compilation ou de SourceKit, puis conserver les éléments de diagnostic avant de reconstruire uniquement l’index concerné.
Distinguer une reconstruction normale d’un véritable blocage
SourceKit reconstruit l’index lors de la première ouverture d’un projet, après un changement de version de Xcode, une modification du fichier de verrouillage des dépendances ou le basculement entre de nombreuses branches. Une charge CPU élevée pendant une courte période n’indique pas nécessairement une panne. Commencez par arrêter toute compilation active, ne modifiez aucun fichier de l’espace de travail et observez deux ou trois instantanés successifs des processus :
date
ps -axo pid,ppid,%cpu,%mem,etime,command | grep -E 'SourceKit|sourcekitd|XCBBuildService|swift-frontend' | grep -v grep
Vérifiez en priorité trois points : si XCBBuildService ou swift-frontend compile encore ; si la durée d’exécution des processus SourceKit continue d’augmenter ; et si, après l’arrêt des modifications, la charge CPU reste longtemps concentrée sur le même groupe de processus. Si des processus de compilation sont toujours actifs, laissez-les se terminer afin de ne pas confondre la charge de compilation avec un blocage de l’indexation.
Une seule mesure du CPU ne suffit pas pour conclure à un blocage. Un nettoyage n’est justifié que si quatre conditions sont réunies : l’ensemble des fichiers est stable, aucune compilation n’est en cours, la complétion ne progresse plus depuis longtemps et les journaux désignent constamment le même module.
Conserver des éléments de diagnostic comparables
Ne redémarrez pas Xcode immédiatement. Créez d’abord un répertoire de diagnostic regroupant la liste des processus, les journaux et l’échantillon de pile. Vous pourrez ainsi déterminer ensuite si la correction a réellement fonctionné.
STAMP="$(date +%Y%m%d-%H%M%S)"
OUT="$HOME/sourcekit-diagnostics/$STAMP"
mkdir -p "$OUT"
ps -axo pid,ppid,%cpu,%mem,etime,command > "$OUT/processes.txt"
log show --last 10m --style compact --predicate 'process CONTAINS[c] "SourceKit" OR process == "Xcode"' > "$OUT/sourcekit.log"
PID="$(pgrep -n -f 'SourceKit|sourcekitd')"
test -n "$PID" && sample "$PID" 10 -file "$OUT/sourcekit.sample.txt"
Pendant l’échantillonnage, ne changez pas de branche et ne modifiez pas de fichiers en masse. Dans les journaux, recherchez en priorité les noms de modules répétés, les chemins illisibles, les échecs de chargement de plug-ins et les boucles d’annulation de requêtes. Si la pile revient plusieurs fois sur l’analyse du même fichier Swift ou du même fichier généré, vérifiez d’abord si un script réécrit continuellement ce fichier.
Écarter une boucle liée aux fichiers générés
Une cause fréquente est un générateur de code qui réécrit l’horodatage à chaque exécution. Même si le contenu ne change pas, l’indexeur doit alors retraiter le fichier. Le script de génération doit commencer par comparer le contenu, puis écrire la cible à l’aide d’un remplacement atomique. Vérifiez également que le répertoire généré n’est pas ajouté au projet à la fois comme référence de dossier et comme répertoire de sources.
Isoler DerivedData pour chaque espace de travail
Le partage d’un même DerivedData permet aux différentes branches, versions de Xcode et tâches parallèles de se perturber mutuellement. Sur un Mac cloud, il est plus fiable d’attribuer un chemin explicite à chaque espace de travail ou tâche CI :
ROOT="$PWD"
DERIVED="$ROOT/.derived-data"
xcodebuild \
-workspace App.xcworkspace \
-scheme App \
-derivedDataPath "$DERIVED" \
-showBuildSettings > "$ROOT/build-settings.txt"
Le répertoire .derived-data ne doit pas être ajouté au dépôt. Pour les tâches parallèles, ajoutez également un identifiant de tâche, par exemple .derived-data/job-42, afin d’éviter que deux compilations écrivent simultanément dans le cache des modules.
| Scénario | Stratégie DerivedData | Stratégie d’indexation |
|---|---|---|
| Développement interactif à distance | Répertoire indépendant fixe pour l’espace de travail | Laisser activée |
| Compilation de validation ponctuelle | Répertoire indépendant pour chaque tâche | Activer selon les besoins |
| Compilation et tests exclusivement en CI | Répertoire indépendant pour chaque tâche | L’écriture de l’index peut être désactivée |
| Changement de version de Xcode | Utiliser un nouveau répertoire de version | Régénérer |
Pour les tâches CI qui n’ont pas besoin de la complétion de code, ajoutez COMPILER_INDEX_STORE_ENABLE=NO à la ligne de commande. Ne l’inscrivez pas sans condition dans la configuration partagée du projet, sous peine de priver les développeurs de la navigation, des diagnostics et de la complétion.
Procéder à une récupération ciblée selon l’étendue du problème
Avant le nettoyage, fermez l’espace de travail et vérifiez qu’aucun processus xcodebuild, swift-frontend ou SourceKit n’utilise encore le répertoire cible. Commencez par supprimer uniquement l’index et le cache des modules :
DERIVED="$PWD/.derived-data"
rm -rf "$DERIVED/Index.noindex"
rm -rf "$DERIVED/ModuleCache.noindex"
Après avoir rouvert le projet, conservez la même branche et les mêmes dépendances, puis attendez la fin de la première indexation. Si le problème réapparaît, supprimez le DerivedData isolé du projet actuel au lieu d’effacer tout ~/Library/Developer. S’il persiste encore, revenez aux éléments de diagnostic : vérifiez si une seule branche déclenche le problème, si un fichier généré change continuellement ou si un plug-in de compilation est incompatible avec la version actuelle de Xcode.
Ne considérez pas le fait qu’un redémarrage de la machine rétablisse le fonctionnement comme une conclusion. Le redémarrage ne fait qu’arrêter les processus ; il ne permet pas de savoir si la cause est un cache endommagé, des fluctuations dans les fichiers d’entrée ou une différence de chaîne d’outils.
Établir une checklist de validation reproductible
Après la correction, effectuez une nouvelle validation avec le même commit, le même chemin Xcode et la même stratégie DerivedData. Il est recommandé de consigner les résultats suivants :
xcodebuild -versionetxcode-select -pdésignent la chaîne d’outils attendue.- Après l’ouverture de l’espace de travail, l’indexation se termine et la complétion ainsi que l’accès à la définition fonctionnent de nouveau.
- Après l’arrêt des modifications et des compilations, l’utilisation CPU de SourceKit diminue.
- Les journaux ne répètent plus en boucle le même fichier ou module.
- Le problème ne réapparaît pas après plusieurs fermetures et réouvertures de l’espace de travail.
- La CI et le développement interactif utilisent des répertoires DerivedData distincts.
Sur NowMini, les sessions à distance doivent également conserver le répertoire de diagnostic avec les journaux de compilation, sans collecter le contenu du code source, les secrets ni les variables d’environnement non expurgées. L’objectif final n’est pas de ramener immédiatement le CPU à zéro, mais de démontrer que les entrées de l’index sont stables, que les processus continuent de progresser et que le nettoyage n’affecte que le projet en cours.
Questions fréquentes
Une forte utilisation CPU de SourceKit indique-t-elle toujours un blocage ?
Non. Elle est normale lors d’une première ouverture, d’un changement de version de Xcode ou d’une modification des dépendances. Il faut rechercher une répétition durable sur le même module sans progrès visible.
Faut-il supprimer tout le dossier DerivedData ?
Non. Arrêtez d’abord Xcode et les builds, puis supprimez seulement Index.noindex et ModuleCache.noindex dans le DerivedData dédié au projet. Une reconstruction complète du projet reste le dernier recours.
Peut-on désactiver l’index pendant un build CI ?
Oui, pour une tâche sans édition interactive, avec COMPILER_INDEX_STORE_ENABLE=NO. Ne propagez pas ce réglage aux sessions de développement qui dépendent de la navigation et de la complétion.
Lancez votre prochaine tâche sur un nœud physique dédié
Utilisez un Mac dans le cloud équipé d’une puce M4, de 16 Go de RAM et d’un SSD de 256 Go, avec un nœud à Singapour, Tokyo, Séoul ou Hong Kong selon la durée de votre tâche.