Le projet compile sous Linux, mais l’archive iOS échoue dès qu’Xcode, Simulator ou la signature entrent en jeu.
Solution la plus rapide : gardez sur un véritable nœud macOS toute la chaîne qui utilise les SDK Apple, Xcode, Simulator, la signature ou l’export d’application ; laissez Linux traiter les vérifications réellement indépendantes de la plateforme. Pour la plupart des équipes, l’architecture Linux plus Mac distant est le meilleur point de départ en 2026, tandis qu’une petite équipe peut d’abord valider le cycle complet sur un seul Mac distant.
À qui cette décision s’adresse
Cet article concerne les ingénieurs de build qui intègrent Bazel 9 dans un projet iOS et doivent délimiter les responsabilités entre Linux et macOS.
Il s’adresse également aux équipes DevOps qui entretiennent une grappe CI Linux, ainsi qu’aux responsables techniques qui doivent choisir entre un nœud Mac unique, une architecture hybride ou le report de la migration.
Dernière mise à jour : 29 août 2026. Les informations de version et de compatibilité ont été vérifiées à partir de la documentation de publication de Bazel, de l’annonce officielle de Bazel 9, des règles Apple et Swift, ainsi que des notes Apple relatives à Xcode 26.
La construction iOS avec Bazel 9 reste liée à l’outillage Apple
Bazel est un moteur d’analyse et d’exécution d’actions. Il peut sélectionner des plateformes, ordonner des dépendances et exploiter un cache, mais il ne remplace pas les composants propriétaires nécessaires à la production d’une application iOS.
La séparation des responsabilités doit être explicite :
| Élément | Responsabilité principale | Conséquence pour la CI |
|---|---|---|
| Bazel 9 | Analyse du graphe, planification et exécution des actions | Peut piloter des actions sur plusieurs plateformes |
| rules_apple | Description de nombreuses règles de construction Apple | Doit être vérifié avec la version de Bazel retenue |
| rules_swift | Intégration des actions Swift et de leurs outils | Ne fournit pas les SDK ni l’environnement Xcode |
| Xcode et SDK Apple | Compilation, liaison, Simulator, archive et outils Apple | Exigent un environnement macOS correspondant |
| Certificats et profils | Autorisation de signer et d’exporter l’application | Doivent être disponibles de façon contrôlée sur macOS |
Les versions publiées de rules_apple et la documentation de rules_swift indiquent les plages de prise en charge à examiner. La présence de Bazel 9 dans une matrice de support ne signifie donc pas que chaque combinaison avec chaque version mineure d’Xcode est automatiquement validée.
Apple documente les exigences de sa chaîne de développement dans les notes de version de Xcode 26 et dans ses exigences de construction à venir. Ces documents doivent être lus avec les versions exactes réellement installées sur le nœud.
Point de contrôle : une commande Bazel qui démarre sur Linux prouve seulement que l’analyse ou l’action initiale peut s’exécuter. Elle ne prouve ni que l’application peut être liée avec le SDK iOS, ni qu’elle peut être testée, archivée, signée ou exportée.
La première décision est donc binaire. Si le livrable attendu est un paquet iOS signé et testable, un nœud macOS reste obligatoire. Si le pipeline ne produit que des artefacts intermédiaires indépendants de l’écosystème Apple, une partie peut être déplacée vers Linux après vérification des actions.
Première étape : lire la plateforme réelle de chaque action
Le routage ne doit pas être déduit du nom d’un script. Un script appelé build-ios.sh peut lancer une génération indépendante de la plateforme, tandis qu’une règle apparemment générique peut invoquer un compilateur Apple ou consommer un SDK.
L’équipe doit commencer par produire un journal exploitable :
bazel build //app:archive \
--build_event_json_file=/tmp/<build-event>.json \
--profile=/tmp/<profile>.json
Les noms de cible et de fichiers restent volontairement génériques. Dans le journal d’événements et les informations d’action, recherchez notamment :
- la plateforme d’exécution effectivement sélectionnée ;
- les propriétés de plateforme attachées à l’action ;
- le groupe d’outils invoqué ;
- les entrées provenant d’un SDK Apple ou d’Xcode ;
- l’identité du nœud qui a exécuté l’action ;
- le statut du cache et la cause d’une nouvelle exécution.
La référence Bazel sur les plateformes et chaînes d’outils explique comment déclarer ces contraintes plutôt que de compter sur une déduction implicite.
Une répartition initiale peut prendre cette forme :
| Famille d’action | Linux | Mac distant | Preuve exigée |
|---|---|---|---|
| Analyse statique indépendante | Oui, si les outils sont disponibles | Possible | Journal sans dépendance Apple |
| Génération de code générique | Oui, si elle est hermétique | Possible | Entrées et outils déclarés |
| Tests unitaires sans SDK Apple | Souvent | Possible | Résultat identique sur clone propre |
| Compilation et liaison iOS | Non pour le livrable final | Oui | SDK, Xcode et plateforme macOS |
| Tests Simulator | Non | Oui | Résultat Simulator sans connexion graphique |
| Archive, signature et export | Non | Oui | Archive, signature et artefact vérifiables |
Le terme « souvent » dans ce tableau n’est pas une permission générale. Un test qui importe une bibliothèque Apple, lit un framework système ou dépend d’un runtime Simulator doit être réévalué. Le critère est l’action observée, non l’intention déclarée dans le pipeline.
La reproductibilité révèle les dépendances invisibles
Une migration Bazel 9 ne se limite pas à changer la ligne de version. Les dépendances, les règles et l’environnement hôte doivent former une combinaison traçable. L’équipe doit conserver dans le dépôt les déclarations pertinentes de MODULE.bazel, notamment les versions retenues pour rules_apple et rules_swift, puis documenter la version d’Xcode et les SDK utilisés sur chaque nœud macOS.
Bazel 9 ayant supprimé la prise en charge de l’ancien modèle WORKSPACE, les dépendances qui reposaient encore sur cette entrée doivent être vérifiées séparément dans les notes de migration et les fichiers de dépendances du projet. Il ne suffit pas de constater qu’une cible locale fonctionne après le changement : il faut confirmer le comportement depuis un environnement sans état antérieur.
Les dépendances non hermétiques les plus fréquentes sont les suivantes :
- un
PATHdifférent entre l’agent interactif et le service CI ; - un outil installé manuellement sur le Mac mais absent du dépôt ;
- un script qui lit un fichier dans le répertoire personnel ;
- une variable indiquant implicitement une version d’Xcode ;
- un trousseau déverrouillé par une session graphique ;
- un cache local qui masque une entrée manquante ;
- une commande téléchargée pendant l’action sans déclaration d’artefact.
La preuve minimale doit être obtenue depuis un clone propre, avec les caches locaux vidés, puis répétée sur un nœud équivalent. Le résultat à comparer n’est pas seulement le code de sortie. Il faut également examiner les artefacts, les journaux d’action, les versions d’outils et les chemins d’entrée.
git clone <repository-url> <workspace>
cd <workspace>
xcodebuild -version
xcrun --sdk iphonesimulator --show-sdk-path
bazel clean --expunge
bazel test //... --build_event_json_file=/tmp/<clean-test>.json
La commande xcodebuild sert ici à enregistrer l’environnement ; elle ne remplace pas les règles Bazel ni la validation du produit final.
Cache, exécution distante et Mac distant ne désignent pas la même chose
Trois mécanismes sont souvent confondus :
- Le cache distant conserve ou distribue des résultats d’actions déjà produites.
- L’exécution distante envoie une action à un environnement d’exécution compatible.
- L’accès à un Mac distant fournit une machine macOS réelle, accessible par SSH, VNC ou console, mais ne configure pas automatiquement le routage Bazel ni le cache.
La documentation Bazel sur l’exécution distante impose de raisonner en termes d’actions, d’entrées, d’outils et de plateforme. Un cache partagé ne rend pas Linux capable de produire une archive lorsque l’action exige Xcode. De même, un Mac accessible en SSH n’est pas encore un nœud CI fiable si le pipeline attend une session graphique, un trousseau déjà ouvert ou un état local persistant.
| Architecture | Avantage principal | Risque à mesurer | Condition de choix |
|---|---|---|---|
| Tout le flux sur un Mac distant | Modèle simple pour valider le cycle iOS complet | File d’attente, ressources limitées, mélange des tâches | Petite équipe ou charge encore peu parallèle |
| Linux plus Mac distant | Les contrôles génériques restent sur l’infrastructure existante | Routage incorrect et interfaces entre plateformes | Option par défaut pour une équipe disposant déjà de Linux |
| Linux plus plusieurs Mac et cache distant | Meilleure séparation des files et des outils | Complexité, invalidation du cache et maintenance | Charge Apple simultanée démontrée par les mesures |
| Migration différée | Évite une migration sans preuves | Maintien du processus actuel et dette technique | Compatibilité non établie ou signature non automatisable |
La documentation Bazel sur le build distant doit être utilisée pour distinguer le stockage des résultats et l’exécution des actions. Pour chaque essai, consignez le taux de réutilisation du cache, l’attente dans la file Mac, la durée des phases critiques, les échecs répétés et le temps d’intervention après incident. Sans ces mesures, une impression de lenteur peut venir du calcul, des transferts, de la file d’attente ou d’un routage erroné.
Aucun gain de performance chiffré ne doit être promis avant la mesure sur le projet concerné. Une petite modification des entrées, de la version du SDK ou des options de compilation peut invalider des résultats auparavant réutilisables.
La signature définit la frontière de livraison
Un test Simulator réussi ne prouve pas qu’une application peut être distribuée. L’archivage, la sélection de l’identité, la lecture du profil d’approvisionnement et l’export doivent fonctionner dans une session non interactive.
Apple décrit les relations entre identité de signature et profils dans sa note technique sur la signature de code. Dans une chaîne distante, les certificats, les profils, le trousseau et les journaux ne doivent pas être traités comme un seul fichier de configuration.
Il est préférable de séparer :
- les secrets injectés par un gestionnaire sécurisé ;
- le trousseau temporaire réservé au travail CI ;
- les profils associés au type d’export attendu ;
- le cache de compilation, qui ne doit pas devenir un dépôt de secrets ;
- les artefacts d’archive et les métadonnées de signature.
Le test doit démarrer après une déconnexion de session graphique ou dans un compte de service prévu à cet effet. L’équipe vérifie ensuite la présence de l’archive, l’identité utilisée, le profil associé et l’artefact exporté. Si la procédure ne fonctionne qu’après ouverture manuelle de Xcode, le nœud n’est pas prêt pour la livraison automatisée.
Expérience de terrain à retenir : une construction sans signature peut être utile pour isoler une erreur de compilation, mais elle ne valide pas le chemin de publication. L’acceptation doit couvrir le résultat que la chaîne est censée remettre à l’équipe, pas uniquement l’étape la plus facile à automatiser.
Les critères d’acceptation d’un Mac distant
Avant d’ajouter le nœud à la file de production, l’équipe peut exécuter la séquence suivante :
Vérifier l’environnement
- Enregistrer la version exacte de Bazel, de
rules_apple, derules_swift, d’Xcode, de macOS et des SDK. - Confirmer que
MODULE.bazeldécrit les dépendances attendues et qu’aucune étape critique ne dépend encore implicitement deWORKSPACE. - Comparer
PATH, variables d’environnement, outils disponibles et permissions entre une session SSH et le service CI. - Définir une propriété de plateforme explicite pour le nœud macOS.
- Refuser les actions Apple lorsqu’elles sont envoyées vers un nœud Linux.
Rejouer le cycle sans état local
- Partir d’un clone propre et vider le cache local.
- Lancer les tests sans ouvrir de session graphique.
- Produire une archive iOS et contrôler ses métadonnées.
- Signer et exporter avec un trousseau isolé.
- Refaire le travail après redémarrage du Mac et vérifier que l’automatisation ne demande pas d’intervention manuelle.
Tester les incidents
- Interrompre la connexion pendant une action puis observer la reprise ou l’échec contrôlé.
- Remplacer le nœud par un environnement équivalent et mesurer les différences d’artefacts.
- Changer de version Xcode sur un environnement de test séparé, jamais directement sur la file de production.
- Conserver la cause des échecs, les journaux d’action, l’état du cache et le résultat de la restauration.
Une équipe qui souhaite formaliser cette procédure peut consulter le guide NodeMini consacré à la mise en place et à l’acceptation d’un nœud Mac distant pour Bazel iOS. Pour comparer une capacité ponctuelle avec une capacité maintenue dans le temps, la page sur les solutions Mac mini cloud constitue un point de départ, sans remplacer les tests sur le projet réel.
Le choix d’architecture dépend des preuves, pas du nombre de serveurs
Le routage recommandé peut être formulé ainsi :
- Choisissez un Mac distant unique si une petite équipe doit d’abord prouver la compilation, les tests, l’archive, la signature et la reprise après redémarrage.
- Choisissez Linux plus Mac distant si les vérifications génériques occupent déjà la grappe Linux et que les actions Apple peuvent être identifiées avec précision.
- Ajoutez des Mac supplémentaires seulement lorsque les journaux montrent une attente de file persistante, des travaux Apple simultanés ou un besoin de séparer des versions Xcode.
- Suspendez la migration si la combinaison de versions n’est pas documentée, si les actions dépendent de fichiers hôtes invisibles ou si la signature exige encore une intervention graphique.
Pour estimer une extension, il faut suivre la charge Apple réelle plutôt que la durée moyenne globale du pipeline. Les indicateurs utiles sont la longueur de file par propriété de plateforme, le nombre de reconstructions causées par les changements d’outils, les échecs après redémarrage, la réutilisation du cache et le temps nécessaire au remplacement d’un nœud.
La logique de décision est donc progressive : prouver d’abord le parcours complet sur un environnement isolé, déplacer ensuite les actions réellement indépendantes vers Linux, puis augmenter la capacité macOS lorsque les données montrent une contrainte opérationnelle. Le guide NodeMini sur le choix et l’extension d’une CI Mac distante peut accompagner cette phase d’évaluation.
Questions fréquentes
Xcode est-il indispensable dans une construction Bazel iOS ?
Oui pour toute livraison qui consomme les SDK Apple, effectue une liaison iOS, exécute Simulator, crée une archive ou signe l’application. Bazel organise les actions, mais rules_apple et rules_swift ne redistribuent pas Xcode. Linux peut conserver les tâches préparatoires lorsque leurs outils et entrées sont hermétiques, mais il ne doit pas recevoir une action Apple simplement parce que le pipeline est lancé depuis une machine Linux.
Une CI Bazel 9 peut-elle rester entièrement sous Linux ?
Elle peut rester partiellement sous Linux, à condition de distinguer les actions indépendantes de la plateforme des actions Apple. Les contrôles de code, certaines générations et certains tests sans SDK peuvent y être exécutés. En revanche, la compilation finale, la liaison avec les SDK iOS, Simulator, l’archive, la signature et l’export doivent être vérifiés sur macOS avec la combinaison Xcode et SDK prévue par le projet.
Comment identifier les actions qui exigent macOS ?
L’équipe doit examiner les journaux d’événements Bazel, les informations d’action, les propriétés de plateforme et les outils réellement invoqués. La présence d’un mot comme « iOS » dans un nom de cible ne suffit pas. Une action qui lit un SDK Apple, appelle un outil Xcode, lance Simulator ou produit une archive doit être marquée pour macOS, même si elle est déclenchée par un script générique.
Quelle méthode permet de rattacher un Mac distant à Bazel ?
Le Mac doit disposer d’un environnement reproductible, d’un agent CI ou d’un mécanisme d’exécution compatible, ainsi que de propriétés de plateforme déclarées. La file doit utiliser ces propriétés pour router les actions Apple. L’accès SSH ou VNC sert à administrer et diagnostiquer la machine ; il ne remplace ni la déclaration Bazel, ni le contrôle des secrets, ni les essais de redémarrage et de perte de connexion.
Que faut-il accepter avant la mise en production du nœud ?
Il faut valider la combinaison des versions, la construction depuis un clone propre, les tests Simulator, l’archive, la signature, l’export et la reprise sans session graphique. Les contrôles doivent aussi couvrir le cache, les variables d’environnement, les dépendances non déclarées, la coupure réseau, le redémarrage et le remplacement du nœud. Une simple compilation réussie ne suffit pas à établir la capacité de livraison.
Recommandation finale
Un poste Linux reste pertinent pour les tâches génériques, mais il ne constitue pas une solution durable pour la chaîne iOS complète : il ne fournit pas les SDK Apple, ne remplace pas Xcode, ne lance pas Simulator et ne peut pas démontrer seul la signature ou l’export final. À l’inverse, faire fonctionner chaque action sur un Mac distant peut gaspiller une capacité Apple sur des contrôles qui n’en ont pas besoin et rendre la file plus difficile à dimensionner.
Une architecture Linux plus Mac distant permet donc de conserver les outils existants tout en réservant macOS aux actions qui l’exigent réellement. Pour une première validation isolée, NodeMini permet de tester un projet Bazel iOS sur un Mac distant, puis d’observer le cache, les tests, la signature et la reprise après redémarrage avant de décider d’une capacité permanente ou de plusieurs nœuds. Le choix final doit suivre les preuves recueillies sur le dépôt réel, plutôt qu’une hypothèse générale sur la vitesse ou la compatibilité.