Xcode 11 recompile trop

12

Xcode 11 recompile (presque?) Tout mon projet, même si je change juste une variable privée locale, ou change une valeur d'une constante dans la portée locale, parfois même dans la portée de la fonction privée locale. Je peux parfois obtenir 2 ou 3 changements avec des builds rapides comme prévu, mais assez tôt, il décide de tout recompiler à nouveau (ce qui prend trop de temps).

Quelques idées sur ce qui pourrait se passer? Est-ce que Xcode n'est pas en mesure de déterminer ce qui a changé, pourquoi recompile-t-il tant d'autres choses (même d'autres modules).

Tout conseil est très apprécié, merci!

Nikolay Suvandzhiev
la source
2
Je conseillerais: assurez-vous que vous faites des builds de débogage avec une construction incrémentielle, pas une optimisation de module entière. Quittez et nettoyez DerivedData. Et mise à jour vers Xcode 11.4, il se compile parfois si vite que je ne le vois même pas se produire.
mat
1
Ce fil pourrait répondre à votre question: stackoverflow.com/questions/25537614/…
Endanke
Il est très dépendant du projet, il doit analyser le journal de construction sur ce qui se passe. Je n'observe pas un tel comportement avec Xcode 11.2+, alors que j'ai de très gros projets. Souhaitez-vous donner accès à vos sources de projet d'une manière ou d'une autre, sinon tous les conseils sont insensés?
Asperi
Vérifiez la propriété Legacy Build System, elle ne doit pas être cochée si vous ne modifiez pas les sous
BrunoLoops

Réponses:

8

Nous avons eu le même problème et nous l'avons résolu. Deux fois.

Construction incrémentielle (même machine de construction):

avant: ~ 10m après: ~ 35s

COMMENT?

Commençons par notre expérience d'abord. Nous avions un énorme projet Swift / Obj-C et c'était la principale préoccupation: les temps de construction étaient lents et vous deviez créer un nouveau projet pour implémenter une nouvelle fonctionnalité (littéralement). Points bonus pour une coloration syntaxique qui ne fonctionne jamais.

Théorie

Pour vraiment résoudre ce problème, vous devez vraiment comprendre comment fonctionne le système de génération. Par exemple, essayons cet extrait de code:

import FacebookSDK
import RxSwift
import PinLayout

et imaginez que vous utilisez toutes ces importations dans votre fichier. Et aussi ce fichier dépend d'un autre fichier, qui dépend d'une autre bibliothèque, qui à son tour utilise une autre bibliothèque, etc.

Donc, pour compiler votre fichier, Xcode doit compiler chaque bibliothèque que vous avez mentionnée et chaque fichier dont il dépend, donc si vous changez l'un des fichiers "de base", Xcode doit reconstruire littéralement le projet entier.

Arbre de dépendance

La construction Xcode est multithread , mais elle se compose de nombreuses arborescences monothread .

Donc, à la première étape de chaque construction incrémentielle, Xcode décide quels fichiers doivent être recompilés et crée une arborescence AST . Si vous modifiez un fichier qui agit comme " fiable " sur d'autres fichiers, tous les autres fichiers qui agissent comme " dépendants " doivent être recompilés.

Couplage

Le premier conseil est donc de réduire le couplage . Les parties de votre projet doivent être indépendantes les unes des autres.

Pont Obj-C / Swift

Problème avec ces arbres si vous utilisez un pont Obj-C / Swift, Xcode doit passer par plus de phases que d'habitude:

Monde parfait:

  1. Construit le code Obj-C
  2. Construire du code Swift

Pont Swift / Obj-C

Pont Obj-C / Swift:

  1. [ÉTAPE RÉPÉTABLE] Construisez le code Swift, qui est nécessaire pour compiler le code Obj-C
  2. [ÉTAPE RÉPÉTABLE] Construisez le code Obj-C, qui est nécessaire pour compiler le code Swift
  3. Répétez 1 et 2 jusqu'à ce qu'il ne vous reste que du code Swift et Obj-C non fiable
  4. Construire le code Obj-C
  5. Construire du code Swift

Pont Obj-C / Swift

Donc, si vous changez quelque chose de l'étape 1 ou 2, vous êtes fondamentalement en difficulté. La meilleure solution consiste à minimiser Obj-C / Swift Bridge (et à le supprimer de votre projet).

Si vous n'avez pas de pont Obj-C / Swift, c'est génial et vous êtes prêt à passer à l'étape suivante:

Swift Package Manager

Il est temps de passer à SwiftPM (ou au moins de mieux configurer vos Cocoapods).

Le fait est que la plupart des frameworks avec la configuration par défaut des Cocoapods traînent avec eux-mêmes beaucoup de choses dont vous n'avez pas besoin.

Pour tester cela, créez un projet vide avec une seule dépendance comme PinLayout, par exemple et essayez d'écrire ce code avec Cocoapods (configuration par défaut) et SwiftPM.

import PinLayout

final class TestViewController: UIViewController {

}

Spoiler: Cocoapods compilera ce code, car Cocoapods importera CHAQUE IMPORTATION de PinLayout (y compris UIKit) et SwiftPM ne le fera pas parce que SwiftPM importe les frameworks atomiquement.

Hack sale

Vous souvenez-vous que la construction Xcode est multi-thread?

Eh bien, vous pouvez en abuser si vous pouvez diviser votre projet en plusieurs éléments indépendants et les importer tous en tant que cadres indépendants dans votre projet. Cela réduit le couplage et c'était en fait la première solution que nous avons utilisée, mais ce n'était pas très efficace, car nous ne pouvions réduire le temps de construction incrémentiel qu'à ~ 4-5 m, ce qui n'est RIEN par rapport à la première méthode.

x0 z1
la source
Bonne chance mec. Partagez votre expérience sur la façon dont vous avez réduit le couplage dans votre projet. Au revoir!
x0 z1
3

Il n'y a pas de solution miracle ici, mais beaucoup de choses à vérifier:

  • Assurez-vous que vous utilisez réellement la configuration de débogage dans votre schémaÉditeur de schéma Xcode utilisant la configuration de débogage

  • Voir ci-dessous pour savoir comment vous assurer que vous utilisez des versions incrémentielles par rapport au module entier selon les conseils de matt. Assurez-vous également que votre niveau d'optimisation pour les versions de débogage est nul. Paramètres de construction Xcode montrant les constructions incrémentielles

  • Si vous utilisez des frameworks lourds d'inférence de type comme RxSwift, l'ajout d'annotations de type explicites peut accélérer les temps de construction.

  • Si le projet est très important, vous pouvez envisager de refactoriser des groupes logiques de fichiers source dans des frameworks, mais cela peut être un changement trop radical que vous ne préférez

Cela pourrait être utile si vous fournissiez des détails supplémentaires sur le projet: liez-vous statiquement des bibliothèques? Est-ce un cadre ou une cible d'application? Quelle est la taille et quelle version rapide utilisez-vous? Avez-vous des phases de construction personnalisées comme des linters ou la génération de code qui pourraient parfois être ignorées?

nteissler
la source