2026-04-15 : données dérivées Xcode, TMPDIR et xcresult sur Mac cloud loué (CI)
Les équipes mobiles qui louent des Mac mini M4 à Hong Kong, Tokyo, Séoul, Singapour et US Est accusent souvent « Xcode lent » alors que le vrai problème est la contention disque : deux pipelines écrivent la même tranche DerivedData, un job de tests UI remplit /tmp, ou un bundle .xcresult dépasse 6 Go et affame des archives concurrentes. Ce guide daté du 2026-04-15 précise qui a besoin d’isolation par job, recense des défaillances concrètes sur builders SSH sans tête, compare des stratégies dans un tableau, fournit un runbook shell en huit étapes chiffré, et renvoie vers SwiftPM cache & registre et signature auto vs manuelle pour garder des enchaînements déterministes.
Le silicium Apple Silicon nu réduit le bruit CPU, mais le NVMe reste borné. Partager ~/Library/Developer/Xcode/DerivedData par défaut produit des échecs SwiftEmitModule aléatoires et des cartes de modules obsolètes. Lier DERIVED_DATA_PATH, TMPDIR, -resultBundlePath et -clonedSourcePackagesDirPath à un même préfixe de job rend la planification capacitaire honnête lorsque vous comparez des nœuds régionaux.
Qui profite d’un DerivedData par job sur Mac cloud
L’isolation est pertinente lorsque trois processus xcodebuild ou plus peuvent toucher la même famille de workspace sur une fenêtre glissante de 24 heures — typique du trunk iOS ou des usines white-label. Sans chemins dédiés, les pièces jointes XCTest disparaissent et l’indexation se bat avec la compilation. Regrouper les IO temporaires sous un arbre prévisible permet de décider d’ajouter un second M4 à partir des courbes disque, pas d’une impression.
Défaillances observées sur builders SSH headless
- Indexer pendant le build — l’index du job A mute ce que le job B lit, d’où « type introuvable » jusqu’à un clean complet.
- TMPDIR partagé — SwiftPM/clang laissent des centaines de milliers de petits fichiers ; le script de nettoyage d’un autre job supprime encore un préfixe ouvert.
- xcresult sans quotas — vidéos et captures UI : trois suites peuvent dépasser 8 Go.
- Archive puis tests — enchaîner sur le même DerivedData augmente le risque de corruption si l’archive s’arrête à mi-chemin.
DERIVED_DATA_PATH, TMPDIR, le chemin du bundle de résultats et -clonedSourcePackagesDirPath comme un unique préfixe de job créé à l’enqueue et supprimé via trap à la sortie.
Stratégies d’isolation comparées
| Approche | Avantages | Inconvénients | Quand |
|---|---|---|---|
DERIVED_DATA_PATH par job sous /Volumes/builds |
Nettoyages déterministes, quotas par pipeline | Premier build plus lent sans cache chaud | CI parallèle sur Mac mini M4 partagé |
| Cache chaud lecture seule + copie overlay | Compilations froides plus rapides | rsync complexe ; difficile en SSH pur | Trains de release avec mêmes mineurs Xcode |
| Comptes utilisateur macOS séparés | Isolement fort des identités de signature | Coût ops et licences plus élevés | Locataires réglementés mélangés |
Budget NVMe : chiffres copiables
| Artefact | Régime typique | Pic UI tests |
|---|---|---|
| DerivedData (app moyenne, Debug) | 6–14 Go | + 3 Go scratch |
| Checkout SwiftPM + build | 1–4 Go | + 2 Go si nouveaux tags |
| Bundle xcresult | 400–900 Mo tests unitaires | 3–10 Go avec vidéo |
Runbook en huit étapes pour Mac cloud loués
- Horodater —
JOB_ID=$(date +%s)-$RANDOM,ROOT=/Volumes/builds/$JOB_ID,mkdir -ppour DerivedData/tmp/results. - Épingler l’environnement — exporter
DERIVED_DATA_PATH,TMPDIR,TEMP,TMP. - trap — après vérification d’unicité du
JOB_ID,trap 'rm -rf "$ROOT"' EXIT; agents long-running archivent d’abord. - xcodebuild — ajouter
-resultBundlePath "$ROOT/results/Test-$JOB_ID.xcresult"pour les tests ; IPA vers stockage objet selon export IPA. - SwiftPM —
-clonedSourcePackagesDirPath "$ROOT/spm"aligné sur l’auth registre de l’article SwiftPM. - Plafond de parallélisme — sur 24 Go RAM, limitez à ≤2 jobs UI lourds ; mutex côté file.
- Upload —
ditto -c -k --sequesterRsrc --keepParentpuis contrôle d’intégrité avant suppression locale. - Télémétrie —
df -havant/après ; alerte si durée > 42 min avec disque > 90 % (pièces jointes en folie).
export JOB_ROOT=/Volumes/builds/ci-$CI_PIPELINE_ID
mkdir -p "$JOB_ROOT"/{dd,tmp,res,spm}
export DERIVED_DATA_PATH="$JOB_ROOT/dd" TMPDIR="$JOB_ROOT/tmp" TEMP="$JOB_ROOT/tmp" TMP="$JOB_ROOT/tmp"
Crochets métriques ajoutables en une demi-journée
Sans observation, l’isolation disque ne sert à rien. Émettez trois jauges : (1) du -sk "$ROOT" post-compile, (2) secondes murales dans xcodebuild archive, (3) gigaoctets libres sur le volume hébergeant /Volumes/builds. Si la taille médiane DerivedData dérive de plus de 18 % semaine sur semaine, cherchez d’abord une désactivation d’incremental ou une étape de codegen lourde, pas un achat matériel immédiat. Journalisez aussi le numéro de build Xcode avec JOB_ID : alterner 16.2 et 16.3 sur un même hôte fragmente l’index. Planifiez xcrun simctl delete unavailable hors fenêtres de pointe.
Pont vers SwiftPM et discipline de signature
L’isolation DerivedData ne remplace pas l’hygiène de provisioning. Les rotations hebdomadaires de certificats doivent suivre le guide signature automatique vs manuelle pour éviter que codesign n’attende une UI. Gardez Package.resolved versionné et évitez de mélanger un répertoire global SourcePackages avec un DerivedData par job — les verrouillages de checkout restent des courses.
FAQ : DerivedData sur Apple Silicon loué
| Question | Réponse pratique |
|---|---|
| Lier DerivedData vers NFS ? | Évitez sauf RTT < 2 ms ; préférez NVMe local + upload d’artefacts. |
| Layout Xcode Server legacy ? | Ignorez /Library/Developer/XcodeServer ; imposez des chemins explicites. |
| Rosetta ? | Ne mélangez pas simulateurs x86_64 et préfixes arm64 ; isolez par architecture. |
Pourquoi les nœuds régionaux M4 comptent encore
Les dossiers isolés suppriment les courses logicielles, pas la physique : tirer des artefacts depuis US Est depuis Tokyo coûte des minutes RTT. Colocalisez builders, SCM et auditeurs ; l’empreinte MacXCode HK / JP / KR / SG / US sert à placer /Volumes/builds sur le bon continent. Lisez l’aide pour les bases SSH, puis montez la concurrence seulement après 14 nuits consécutives de métriques disque au vert.
En bref : DERIVED_DATA_PATH + TMPDIR + chemins xcresult explicites transforment les builds rouges aléatoires en budgets IO mesurables — puis vous pouvez dimensionner via les tarifs plutôt qu’au doigt mouillé.
Montez en charge sur M4 bare metal isolé
HK · JP · KR · SG · US · SSH / VNC