Pourquoi le temps de compilation de Swift est-il si lent?

210

J'utilise Xcode 6 Beta 6.

C'est quelque chose qui me dérange depuis un certain temps maintenant, mais il atteint un point où il est à peine utilisable maintenant.

Mon projet commence à avoir une taille décente de 65 fichiers Swift et quelques fichiers Objective-C pontés (qui ne sont vraiment pas la cause du problème).

Il semble que toute légère modification d'un fichier Swift (comme l'ajout d'un simple espace blanc dans une classe à peine utilisée dans l'application) entraînera la recompilation de tous les fichiers Swift de la cible spécifiée.

Après une enquête plus approfondie, j'ai trouvé que ce qui prend à peu près 100% du temps du compilateur est la CompileSwiftphase où Xcode exécute la swiftccommande sur tous les fichiers Swift de votre cible.

J'ai fait une enquête plus approfondie, et si je ne garde que le délégué de l'application avec un contrôleur par défaut, la compilation est très rapide, mais comme j'ajoutais de plus en plus de mes fichiers de projet, le temps de compilation commençait à devenir très lent.

Maintenant, avec seulement 65 fichiers source, il faut environ 8/10 secondes pour compiler à chaque fois. Pas très rapide du tout.

Je n'ai vu aucun article parler de ce problème, sauf celui-ci , mais c'était une ancienne version de Xcode 6. Je me demande donc si je suis le seul dans ce cas.

METTRE À JOUR

J'ai vérifié quelques projets Swift sur GitHub comme Alamofire , Euler et CryptoSwift , mais aucun d'entre eux n'avait suffisamment de fichiers Swift pour vraiment les comparer. Le seul projet que j'ai trouvé qui commençait à avoir une taille décente était SwiftHN , et même s'il n'avait qu'une douzaine de fichiers source, je pouvais toujours vérifier la même chose, un espace simple et l'ensemble du projet avait besoin d'une recompilation qui commençait à prendre un peu de temps (2/3 secondes).

Comparé au code Objective-C où l'analyseur et la compilation sont rapides, cela donne vraiment l'impression que Swift ne pourra jamais gérer de gros projets, mais dites-moi que je me trompe.

MISE À JOUR Avec Xcode 6 Beta 7

Toujours aucune amélioration. Cela commence à devenir ridicule. Avec l'absence de #importSwift, je ne vois vraiment pas comment Apple pourra jamais optimiser cela.

MISE À JOUR Avec Xcode 6.3 et Swift 1.2

Apple a ajouté des versions incrémentielles (et de nombreuses autres optimisations du compilateur). Vous devez migrer votre code vers Swift 1.2 pour voir ces avantages, mais Apple a ajouté un outil dans Xcode 6.3 pour vous y aider:

Entrez la description de l'image ici

TOUTEFOIS

Ne te réjouis pas trop vite comme moi. Le solveur de graphes qu'ils utilisent pour rendre la construction incrémentielle n'est pas encore très bien optimisé.

En effet, tout d'abord, il ne regarde pas les changements de signature de fonction, donc si vous ajoutez un espace dans le bloc d'une méthode, tous les fichiers dépendant de cette classe seront recompilés.

Deuxièmement, il semble créer l'arborescence sur la base des fichiers qui ont été recompilés même si une modification ne les affecte pas. Par exemple, si vous déplacez ces trois classes dans des fichiers différents

class FileA: NSObject {
    var foo:String?
}
class FileB: NSObject {
    var bar:FileA?
}
class FileC: NSObject {
    var baz:FileB?
}

Maintenant, si vous modifiez FileA, le compilateur marquera évidemment FileApour être recompilé. Il sera également recompilé FileB(ce serait bien en fonction des modifications apportées à FileA), mais aussi FileCparce qu'il FileBest recompilé, et c'est assez mauvais car FileCjamais utilisé FileAici.

J'espère donc qu'ils amélioreront ce solveur d'arbre de dépendance ... J'ai ouvert un radar avec cet exemple de code.

MISE À JOUR Avec Xcode 7 beta 5 et Swift 2.0

Hier, Apple a publié la version bêta 5 et à l'intérieur des notes de version, nous pouvions voir:

Swift Language & Compiler • Constructions incrémentielles: changer uniquement le corps d'une fonction ne devrait plus entraîner la reconstruction des fichiers dépendants. (15352929)

Je l'ai essayé et je dois dire que ça fonctionne vraiment (vraiment!) Bien maintenant. Ils ont grandement optimisé les versions incrémentielles de Swift.

Je vous recommande fortement de créer une swift2.0branche et de maintenir votre code à jour à l'aide de XCode 7 beta 5. Vous serez satisfait des améliorations du compilateur (mais je dirais que l'état global de XCode 7 est toujours lent et bogué)

MISE À JOUR Avec Xcode 8.2

Cela fait un moment depuis ma dernière mise à jour sur ce problème alors le voici.

Notre application compte maintenant environ 20 000 lignes de code Swift presque exclusivement, ce qui est décent mais pas exceptionnel. Il a subi une migration rapide 2 et plus rapide que 3. Il faut environ 5 / 6m pour compiler sur un Macbook pro mi-2014 (Intel Core i7 2,5 GHz), ce qui est correct sur une version propre.

Cependant, la construction incrémentielle est toujours une blague malgré Apple affirmant que:

Xcode ne reconstruira pas une cible entière lorsque seuls de petits changements se sont produits. (28892475)

Évidemment, je pense que beaucoup d'entre nous ont juste ri après avoir vérifié ce non-sens (l'ajout d'une propriété privée (privée!) À n'importe quel fichier de mon projet recompilera le tout ...)

Je voudrais vous signaler ce fil sur les forums de développeurs Apple qui contient de plus amples informations sur le problème (ainsi que la communication appréciée des développeurs Apple à ce sujet de temps en temps)

Fondamentalement, les gens ont trouvé quelques choses pour essayer d'améliorer la construction incrémentielle:

  1. Ajouter un HEADER_MAP_USES_VFSparamètre de projet défini surtrue
  2. Désactiver Find implicit dependenciesde votre schéma
  3. Créez un nouveau projet et déplacez votre hiérarchie de fichiers vers le nouveau.

J'essaierai la solution 3 mais la solution 1/2 n'a pas fonctionné pour nous.

Ce qui est ironiquement drôle dans toute cette situation, c'est qu'en regardant le premier post sur ce problème, nous utilisions Xcode 6 avec je crois que le code swift 1 ou swift 1.1 lorsque nous avons atteint la première lenteur des compilations et maintenant environ deux ans plus tard malgré les améliorations réelles d'Apple le la situation est aussi mauvaise qu'elle l'était avec Xcode 6. Quelle ironie.

Je regrette vraiment d'avoir choisi Swift plutôt que Obj / C pour notre projet en raison de la frustration quotidienne que cela implique. (Je passe même à AppCode mais c'est une autre histoire)

Quoi qu'il en soit, je vois que ce message SO a 32k + vues et 143 ups à ce jour, donc je suppose que je ne suis pas le seul. Accrochez-vous les gars malgré le pessimisme de cette situation, il pourrait y avoir de la lumière au bout du tunnel.

Si vous avez le temps (et le courage!), Je suppose qu'Apple se réjouit du radar à ce sujet.

Jusqu'à la prochaine fois! À votre santé

MISE À JOUR Avec Xcode 9

Trébuchez sur cela aujourd'hui. Xcode a discrètement introduit un nouveau système de construction pour améliorer les performances horribles actuelles. Vous devez l'activer via les paramètres de l'espace de travail.

entrez la description de l'image ici

J'ai déjà essayé, mais je mettrai à jour ce message une fois terminé. Cela semble prometteur.

apouche
la source
1
Intéressant! Je me demande si c'est juste une optimisation manquante ou la nécessité d'analyser autant de fichiers car il n'y a pas de fichiers d'interface.
zaph
2
J'ai eu des problèmes similaires, et à la fin j'ai réalisé que c'était à cause des opérateurs personnalisés utilisés dans les classes d'entité pour désérialiser de JSON. Si vous en utilisez, je vous suggère d'essayer de vous convertir en fonction normale une par une et de voir si quelque chose change.
Antonio
4
La compilation est devenue extrêmement lente dans mon projet depuis XCode 6 beta 6. Où je ne sais pas si c'est dû à des changements dans la beta ou à mon code. Mais mon projet n'est pas encore grand (~ 40-50 fichiers Swift).
BadmintonCat
2
La compilation est devenue insupportablement lente à mesure que mon projet grandissait. Je compte également sur plusieurs pods, ce qui exaspère certainement le problème. Ceci utilise la récente version non bêta.
Andy
2
La construction incrémentielle est toujours effectuée dans une «analyse de dépendance conservatrice, vous pouvez donc toujours voir plus de fichiers à reconstruire qu'absolument nécessaire». Espérons que cela s'améliorera avec le temps.
nmdias

Réponses:

70

Eh bien, il s'est avéré que Rob Napier avait raison. C'était un seul fichier (en fait une seule méthode) qui faisait que le compilateur devenait berzek.

Maintenant, ne vous méprenez pas. Swift recompile tous vos fichiers à chaque fois, mais la grande chose maintenant, c'est qu'Apple a ajouté des commentaires de compilation en temps réel sur les fichiers qu'il compile, donc Xcode 6 GM montre maintenant quels fichiers Swift sont en cours de compilation et l'état de la compilation en temps réel comme vous pouvez le voir sur cette capture d'écran:

Entrez la description de l'image ici

Cela est donc très pratique pour savoir lequel de vos fichiers prend si longtemps. Dans mon cas, c'était ce morceau de code:

var dic = super.json().mutableCopy() as NSMutableDictionary
dic.addEntriesFromDictionary([
        "url" : self.url?.absoluteString ?? "",
        "title" : self.title ?? ""
        ])

return dic.copy() as NSDictionary

car la propriété titleétait de type var title:String?et non NSString. Le compilateur devenait fou en l'ajoutant au NSMutableDictionary.

Le changer en:

var dic = super.json().mutableCopy() as NSMutableDictionary
dic.addEntriesFromDictionary([
        "url" : self.url?.absoluteString ?? "",
        "title" : NSString(string: self.title ?? "")
        ])

return dic.copy() as NSDictionary

fait passer la compilation de 10/15 secondes (peut-être même plus) à une seule seconde ... incroyable.

apouche
la source
3
Merci d'avoir suivi la réponse. Cela peut être très utile pour d'autres qui y poursuivent, le moteur d'inférence de type s'enlisant pendant la compilation.
Rob Napier
1
Où avez-vous eu cette vue @apouche? Je ne le vois pas dans xcode
Eric
2
Vous devez ouvrir l'assistant de débogage (CMD + 8) et cliquer sur la version actuelle
apouche
1
oui, je suis sûr qu'Apple optimisera cela plus tard, sinon faire des projets du monde réel en swift est voué ici et là.
apouche
1
Comment puis-je accéder à cet outil qui montre quels fichiers sont en cours de compilation?
jgvb
42

Nous avons essayé pas mal de choses pour lutter contre cela, car nous avons environ 100 000 lignes de code Swift et 300 000 lignes de code ObjC.

Notre première étape a été d'optimiser toutes les fonctions en fonction de la sortie des temps de compilation des fonctions (par exemple, comme décrit ici https://thatthinginswift.com/debug-long-compile-times-swift/ )

Ensuite, nous avons écrit un script pour fusionner tous les fichiers rapides en un seul fichier, cela brise les niveaux d'accès mais cela a porté notre temps de compilation de 5-6 minutes à ~ 1 minute.

Ceci est maintenant disparu car nous avons interrogé Apple à ce sujet et ils nous ont conseillé de faire ce qui suit:

  1. Activez «Optimisation du module entier» dans le paramètre de génération «Compilateur Swift - Génération de code». Sélectionner'Fast, Whole Module Optimization'

entrez la description de l'image ici

  1. Dans 'Swift Compiler - Custom Flags', pour vos builds de développement, ajoutez '-Onone'

entrez la description de l'image ici entrez la description de l'image ici

Lorsque ces indicateurs sont définis, le compilateur compile tous les fichiers Swift en une seule étape. Nous avons constaté que notre script de fusion est beaucoup plus rapide que la compilation de fichiers individuellement. Cependant, sans le ' -Onone'override ' , il optimisera également l'ensemble du module, ce qui est plus lent. Lorsque nous définissons l' '-Onone'indicateur dans les autres indicateurs Swift, cela arrête l'optimisation, mais il ne cesse pas de compiler tous les fichiers Swift en une seule étape.

Pour plus d'informations sur l'optimisation du module entier, consultez le blog d'Apple ici - https://swift.org/blog/whole-module-optimizations/

Nous avons constaté que ces paramètres permettent à notre code Swift de compiler en 30 secondes :-) Je n'ai aucune preuve de la façon dont cela fonctionnerait sur d'autres projets, mais je suggère de faire un essai si les temps de compilation Swift sont toujours un problème pour vous.

Remarque pour vos builds App Store, vous devez laisser le '-Onone'drapeau désactivé, car l'optimisation est recommandée pour les builds de production.

Sam Stow
la source
4
Merci beaucoup pour ce conseil! Je ne comprends tout simplement pas pourquoi il n'y a rien de tel dans les sources officielles (du moins faciles à trouver), par exemple l'article dont vous parlez devrait (doit!) Avoir la remarque -Onone. Nous ne pouvons pas utiliser l'optimisation de module entier pour l'instant car cela fait planter le compilateur ... Mais vos conseils donnent presque 10 fois plus de vitesse à notre build. Sur MacBook Air (annuel 2013), la durée de construction était d'environ 8 minutes, il en est maintenant à environ 1 minute et demie de ce temps, il passe entre les cibles (nous avons des applications, des extensions et quelques cadres internes) et compile des storyboards
Ilya Puchka
J'ai également testé cette méthode et ce n'est que la méthode mentionnée qui inclut le -Onone et elle réduit considérablement le temps de construction.
Vlad
Travaillez aussi avec le mien. Utiliser l' -Ononeaide pour réduire les temps de construction. Merci beaucoup mon pote!
nahung89
34

Cela a probablement peu à voir avec la taille de votre projet. Il s'agit probablement d'un morceau de code spécifique, peut-être même d'une seule ligne. Vous pouvez tester cela en essayant de compiler un fichier à la fois plutôt que l'ensemble du projet. Ou essayez de regarder les journaux de construction pour voir quel fichier prend si longtemps.

À titre d'exemple des types de code qui peuvent causer des problèmes, cet essentiel de 38 lignes prend plus d'une minute à compiler en version bêta7. Tout cela est causé par ce seul bloc:

let pipeResult =
seq |> filter~~ { $0 % 2 == 0 }
  |> sorted~~ { $1 < $0 }
  |> map~~ { $0.description }
  |> joinedWithCommas

Simplifiez cela par juste une ligne ou deux et il se compile presque instantanément. Le problème est que quelque chose provoque une croissance exponentielle (peut-être une croissance factorielle) dans le compilateur. Évidemment, ce n'est pas idéal, et si vous pouvez isoler de telles situations, vous devriez ouvrir des radars pour aider à résoudre ces problèmes.

Rob Napier
la source
Je ne suis pas sûr que vous ayez vu mon commentaire concernant la CompileSwiftphase. Il prend tous les fichiers rapides même si un seul a été modifié. Donc, si c'est un fichier qui prend du temps (ce dont je doute fortement), le compilateur ne vous dira jamais de quel fichier il s'agit.
apouche
10
Vous pouvez compiler des fichiers individuels à l'aide de swiftcpour voir combien de temps ils prennent.
Rob Napier
Je m'excuse de ne pas vous avoir donné la prime parce que je ne le croirais pas au début. J'ai également essayé de compiler les fichiers un par un mais c'était trop lourd à faire (j'ai dû donner correctement les frameworks et les deps à chaque fois) alors j'ai abandonné. S'il vous plaît voir ma dernière réponse à ce poste pour une explication complète
apouche
Je ne pense pas que ce soit basé sur la taille du projet. Mon projet n'a que 4 fichiers rapides et a soudainement commencé à compiler incroyablement lentement. Il faisait très vite hier. Je ne peux pas mettre le doigt sur tout ce que j'ai fait pour mon projet en particulier, sauf ajouter une icône et lancer des images.
Travis M.
33

Si vous essayez d'identifier des fichiers spécifiques qui ralentissent votre temps de compilation, vous pouvez essayer de le compiler à partir de votre ligne de commande via xctool qui vous donnera des temps de compilation fichier par fichier.

La chose à noter est que, par défaut, il crée 2 fichiers simultanément pour chaque cœur de CPU, et ne vous donnera pas le temps écoulé "net", mais le temps "utilisateur" absolu. De cette façon, tous les timings se répartissent entre les fichiers parallélisés et se ressemblent beaucoup.

Pour résoudre ce problème, définissez l' -jobsindicateur sur 1 , afin qu'il ne parallélise pas les générations de fichiers. Cela prendra plus de temps, mais à la fin vous aurez des temps de compilation "nets" que vous pourrez comparer fichier par fichier.

Voici un exemple de commande qui devrait faire l'affaire:

xctool -workspace <your_workspace> -scheme <your_scheme> -jobs 1 build

Le résultat de la phase "Compiler des fichiers Swift" serait quelque chose comme:

...Compile EntityObserver.swift (1623 ms)Compile Session.swift (1526 ms)Compile SearchComposer.swift (1556 ms)
...

À partir de cette sortie, vous pouvez identifier rapidement les fichiers dont la compilation prend plus de temps que d'autres. De plus, vous pouvez déterminer avec une grande précision si vos refactorings (transtypages explicites, indices de type, etc ...) réduisent ou non les temps de compilation pour des fichiers spécifiques.

REMARQUE: techniquement, vous pouvez également le faire avec xcodebuildmais la sortie est incroyablement verbeuse et difficile à consommer.

Andrea Sprega
la source
1
Assurez-vous simplement que l'optimisation du module entier de votre projet est définie sur false, sinon cela ne séparera pas les fichiers Swift individuels.
sabes
1
Voir Swift CompilerOptimization LevelpourFast, Whole Module Optimization [-O -whole-module-optimization]
Matt
27

Dans mon cas, Xcode 7 n'a fait aucune différence. J'ai eu plusieurs fonctions nécessitant plusieurs secondes pour compiler.

Exemple

// Build time: 5238.3ms
return CGSize(width: size.width + (rightView?.bounds.width ?? 0) + (leftView?.bounds.width ?? 0) + 22, height: bounds.height)

Après avoir déballé les options, le temps de construction a chuté de 99,4% .

// Build time: 32.4ms
var padding: CGFloat = 22
if let rightView = rightView {
    padding += rightView.bounds.width
}

if let leftView = leftView {
    padding += leftView.bounds.width
}
return CGSizeMake(size.width + padding, bounds.height)

Voir plus d'exemples dans cet article et cet article .

Générer un analyseur de temps pour Xcode

J'ai développé un plug-in Xcode qui peut être utile pour quiconque rencontre ces problèmes.

image

Il semble y avoir des améliorations dans Swift 3, donc nous espérons que notre code Swift se compilera plus rapidement.

Robert Gummesson
la source
Génial, j'espère pouvoir vous donner plus de +1. vous êtes vrai et votre plugin est super aussi. je l'ai utilisé et mon temps de construction est abandonné, ce qui signifie un développement super rapide car ces options sont parfois un cauchemar et ralentissent le compilateur.
hardikdevios
Fantastique! Votre outil m'aide beaucoup. Merci
Phil
Super plugin - Vraiment utile! Merci
365SplendidSuns
@Robert Gummesson, avons-nous un outil pour le code Objective-C?
Ashok
20

Nous ne pouvons probablement pas réparer le compilateur Swift, mais quelque chose que nous pouvons corriger est notre code!

Il y a une option cachée dans le compilateur rapide qui imprime les intervalles de temps précis que le compilateur prend pour compiler chaque fonction: -Xfrontend -debug-time-function-bodies. Cela nous permet de trouver des goulots d'étranglement dans notre code et d'améliorer considérablement le temps de compilation.

Exécutez simplement les éléments suivants dans le terminal et analysez les résultats:

xcodebuild -workspace App.xcworkspace -scheme App clean build OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" | grep [1-9].[0-9]ms | sort -nr > culprits.txt

Génial Brian Irace a écrit un article brillant à ce sujet. Profilage de votre temps de compilation Swift .

Valentin Shergin
la source
2
Pour ceux avec zsh en alias grep='noglob grep'premier, sinon le grep ne fonctionnera pas
Jaime Agudo
16

La solution est de lancer.

J'avais une vaste gamme de tonnes de dictionnaires, comme ceci:

["title" : "someTitle", "textFile" : "someTextFile"],
["title" : "someTitle", "textFile" : "someTextFile"],
["title" : "someTitle", "textFile" : "someTextFile"],
["title" : "someTitle", "textFile" : "someTextFile"],
.....

Il a fallu environ 40 minutes pour le compiler. Jusqu'à ce que je lance les dictionnaires comme ceci:

["title" : "someTitle", "textFile" : "someTextFile"] as [String : String],
["title" : "someTitle", "textFile" : "someTextFile"] as [String : String],
["title" : "someTitle", "textFile" : "someTextFile"] as [String : String],
....

Cela a fonctionné pour presque tous les autres problèmes que j'ai rencontrés concernant les types de données que j'ai codés en dur dans mon application.

YichenBman
la source
6
Eh bien oui, cela fait partie des optimisations que vous faites pour améliorer les temps de compilation, mais le principal problème avec le compilateur Swift actuel, c'est qu'il recompile toujours tout le fichier Swift à chaque fois que vous apportez la moindre modification.
apouche
4
Ce serait drôle si ce n'était pas si triste.
Tom Andersen
15

Une chose à noter est que le moteur d'inférence de type Swift peut être très lent avec les types imbriqués. Vous pouvez avoir une idée générale de ce qui cause la lenteur en regardant le journal de construction des unités de compilation individuelles qui prennent beaucoup de temps, puis en copiant et en collant la commande complète générée par Xcode dans une fenêtre de terminal, puis en appuyant sur CTRL- \ pour obtenir quelques diagnostics. Jetez un œil à http://blog.impathic.com/post/99647568844/debugging-slow-swift-compile-times pour un exemple complet.

marcprux
la source
C'est pour moi la meilleure réponse (voir le lien). Je pouvais FACILEMENT trouver les deux lignes différentes qui posaient problème et le résoudre en décomposant mes lignes en lignes plus petites.
Nico
C'est une réponse très utile car elle montre comment trouver où le compilateur est devenu fou. Dans mon cas, c'était le suivant: 'curScore [curPlayer% 2] + curScore [2 + curPlayer% 2] == 3 && maker% 2 == curPlayer% 2' Dès que je l'ai déplacé de 'if' vers 'let ', cela a eu pour résultat "l'expression était trop complexe pour être résolue dans un délai raisonnable; envisagez de diviser l'expression en sous-expressions distinctes"
Dmitry
C'est certainement le moyen le plus utile pour résoudre ce problème.
Richard Venable
9

Assurez-vous également que lors de la compilation pour le débogage (Swift ou Objective-C), vous définissez sur Build Active Architecture uniquement:

entrez la description de l'image ici

Rivera
la source
6

Étant donné que tout cela est en version bêta et que le compilateur Swift n'est pas ouvert (du moins à ce jour), je suppose qu'il n'y a pas de vraie réponse à votre question.

Tout d'abord, comparer Objective-C au compilateur Swift est en quelque sorte cruel. Swift est toujours en version bêta, et je suis sûr qu'Apple travaille à fournir des fonctionnalités et à corriger les bugs, plus qu'à fournir une vitesse fulgurante (vous ne commencez pas à construire une maison en achetant les meubles). Je suppose qu'Apple optimisera le compilateur en temps voulu.

Si, pour une raison quelconque, tous les fichiers source doivent être compilés complètement, une option peut être de créer des modules / bibliothèques séparés. Mais cette option n'est pas encore possible, car Swift ne peut pas autoriser les bibliothèques tant que la langue n'est pas stable.

Je suppose qu'ils optimiseront le compilateur. Pour la même raison que nous ne pouvons pas créer de modules précompilés, il se pourrait bien que le compilateur ait besoin de tout compiler à partir de zéro. Mais une fois que le langage aura atteint une version stable et que le format des binaires ne changera plus, nous pourrons créer nos bibliothèques, et peut-être (?) Le compilateur pourra également optimiser son travail.

Mais devinez, car Apple seul le sait ...

George
la source
"Pour la même raison que nous ne pouvons pas créer de modules précompilés, il se pourrait bien que le compilateur ait besoin de tout compiler à partir de zéro." belle observation, je n'y avais pas pensé de cette façon auparavant.
chakrit
1
2017 et ça continue
Pedro Paulo Amorim
2017 avec Xcode 9 et un nouveau système de construction et toujours lent
pableiros
2018 avec Xcode 9, j'ai un projet avec plus de 50 fichiers rapides, si je nettoie la construction, il a maintenant passé 5 minutes et ma compilation n'est pas encore terminée.
Chen Li Yong
5

Pour Xcode 8, accédez aux paramètres du projet, puis à Éditeur> Ajouter un paramètre de génération> Ajouter un paramètre défini par l'utilisateur, puis ajoutez les éléments suivants:

SWIFT_WHOLE_MODULE_OPTIMIZATION = YES

L'ajout de cet indicateur a fait passer miraculeusement nos temps de compilation de construction propre de 7 minutes à 65 secondes pour un projet rapide 40KLOC. Peut également confirmer que 2 amis ont vu des améliorations similaires sur des projets d'entreprise.

Je peux seulement supposer que c'est une sorte de bogue dans Xcode 8.0

EDIT: Cela ne semble plus fonctionner dans Xcode 8.3 pour certaines personnes.

Chris
la source
2
Où sont les "paramètres du projet" s'il vous plaît?
Raniys
@Raniys Cliquez sur l'icône bleue au niveau racine dans le volet gauche de Xcode.
Chris
Je constate qu'à partir de Xcode 8.3 (non bêta) cela ne fonctionne plus dans mon cas :(
Chris
4

Malheureusement, le compilateur Swift n'est toujours pas optimisé pour une compilation rapide et incrémentielle (à partir de Xcode 6.3 beta). Pendant ce temps, vous pouvez utiliser certaines des techniques suivantes pour améliorer le temps de compilation de Swift:

  • Divisez l'application en cadres pour réduire l'impact de la recompilation. Mais sachez que vous devez éviter les dépendances cycliques dans votre application. Pour plus d'informations sur ce sujet, consultez cet article: http://bits.citrusbyte.com/improving-swift-compile-time/

  • Utilisez Swift pour les parties de votre projet qui sont assez stables et ne changent pas souvent. Pour d'autres zones où vous devez changer très souvent ou des zones qui nécessitent beaucoup d'itérations de compilation / exécution pour être complètes (presque toutes les choses liées à l'interface utilisateur), mieux utiliser Objective-C avec une approche mix-and-match.

  • Essayez l'injection de code d'exécution avec 'Injection for Xcode'

  • Utilisez la méthode roopc: http://roopc.net/posts/2014/speeding-up-swift-builds/

  • Soulagez le moteur d'inférence de type rapide en donnant des indices avec des transtypages explicites.

vorterixe
la source
4

La construction de tableaux et de dictionnaires rapides semble être une cause assez populaire pour cela (spécialement pour vous qui venez d'un arrière-plan Ruby ), c'est-à-dire,

var a = ["a": "b",
         "c": "d",
         "e": "f",
         "g": "h",
         "i": "j",
         "k": "l",
         "m": "n",
         "o": "p",
         "q": "r",
         "s": "t",
         "u": "v",
         "x": "z"]

sera probablement la cause où cela devrait le corriger:

var a = NSMutableDictionary()
a["a"] = "b"
a["c"] = "d"
... and so on
Marcelo Ribeiro
la source
4

Pour le débogage et les tests, assurez-vous d'utiliser les paramètres suivants pour réduire le temps de compilation d'environ 20 minutes à moins de 2 minutes,

  1. Dans les paramètres de construction du projet, recherchez «Optimisation». Tournez Debug sur «Fastest [-O3]» ou supérieur.
  2. Définir la construction pour l'architecture active: OUI
  3. Format des informations de débogage: DWARF
  4. Optimisation du module entier: NON

J'ai perdu d'innombrables heures à attendre la construction du projet pour me rendre compte que je devais faire ce petit changement et que j'ai dû attendre encore 30 minutes pour le tester. Ce sont les paramètres qui ont fonctionné pour moi. (J'expérimente toujours avec les paramètres)

Mais, assurez-vous au moins de définir "DWARF avec dSYM" (si vous voulez surveiller votre application) et de créer une architecture active sur "NON" pour la publication / l'archivage à pousser vers iTunes Connect (je me souviens avoir perdu quelques heures ici aussi).

Mahesh
la source
4
Je me trompe peut-être, mais la définition de niveaux d'optimisation accrus n'augmenterait-elle pas réellement le temps de construction? Les niveaux d'optimisation amélioreront les performances d'exécution.
Michael Waterfall
1
Set Build for Active Architecture: YESm'a donné une réduction d'environ 45% du temps de compilation. Grand merci.
Jean Le Moignan
4

Le compilateur passe beaucoup de temps à déduire et à vérifier les types. L'ajout d'annotations de type aide donc beaucoup le compilateur.

Si vous avez beaucoup d'appels de fonctions en chaîne comme

let sum = [1,2,3].map({String($0)}).flatMap({Float($0)}).reduce(0, combine: +)

Ensuite, le compilateur prend un certain temps pour déterminer quel sumdevrait être le type de . L'ajout du type aide. Ce qui aide également, c'est de tirer les étapes intermittentes dans des variables distinctes.

let numbers: [Int] = [1,2,3]
let strings: [String] = sum.map({String($0)})
let floats: [Float] = strings.flatMap({Float($0)})
let sum: Float = floats.reduce(0, combine: +)

Surtout pour les types numériques CGFloat, Intcela peut beaucoup aider. Un nombre littéral comme 2peut représenter de nombreux types numériques différents. Le compilateur doit donc déterminer à partir du contexte de quel il s'agit.

Les fonctions dont la recherche prend beaucoup de temps +doivent également être évitées. L'utilisation de plusieurs +pour concaténer plusieurs tableaux est lente car le compilateur doit déterminer quelle implémentation de +doit être appelée pour chacun +. Utilisez donc un var a: [Foo]avec à la append()place si possible.

Vous pouvez ajouter un avertissement pour détecter les fonctions qui sont lentes à compiler dans Xcode .

Dans les paramètres de construction de votre cible, recherchez les autres drapeaux Swift et ajoutez

-Xfrontend -warn-long-function-bodies=100

pour avertir pour chaque fonction qui prend plus de 100 ms à compiler.

orkoden
la source
4

Pour les projets qui se mélangent Objective-C et le code Swift, nous pouvons mettre -enable-bridging-pchen Other Swift Flags. Avec cela, l'en-tête de pontage n'est analysé qu'une seule fois et le résultat (un fichier «en-tête précompilé» ou «PCH» temporaire) est mis en cache et réutilisé dans tous les fichiers Swift de la cible. Apple a affirmé qu'il réduit le temps de construction de 30%. Lien de référence:

REMARQUE: cela ne fonctionne que pour Swift 3.1 et supérieur.

iHS
la source
2

Le redémarrage de mon Mac a fait des merveilles pour ce problème. Je suis passé de versions de 15 minutes à des versions de 30 secondes simplement en redémarrant.

Sigma4Life
la source
1

Le temps de compilation rapide a été amélioré dans le nouveau Xcode 6.3

Améliorations du compilateur

Le compilateur Swift 1.2 a été conçu pour être plus stable et améliorer les performances à tous points de vue. Ces modifications offrent également une meilleure expérience lorsque vous travaillez avec Swift dans Xcode. Certaines des améliorations les plus visibles comprennent:

Constructions incrémentielles

Les fichiers source qui n'ont pas changé ne seront plus recompilés par défaut, ce qui améliorera considérablement les temps de construction pour la plupart des cas courants. Des modifications structurelles plus importantes de votre code peuvent nécessiter la reconstruction de plusieurs fichiers.

Exécutables plus rapides

Les versions de débogage produisent des fichiers binaires qui s'exécutent beaucoup plus rapidement, et de nouvelles optimisations offrent des performances de génération de version encore meilleures.

De meilleurs diagnostics du compilateur

Des messages d'erreur et d'avertissement plus clairs, ainsi que de nouveaux correctifs, facilitent l'écriture du code Swift 1.2 approprié.

Améliorations de stabilité

Les plantages du compilateur les plus courants ont été corrigés. Vous devriez également voir moins d'avertissements SourceKit dans l'éditeur Xcode.

Vojtech Vrbka
la source
0

Voici un autre cas qui peut provoquer des ralentissements massifs avec l'inférence de type. Opérateurs coalescents .

Changer les lignes comme:

abs(some_optional_variable ?? 0)

à

abs((some_optional_variable ?? 0) as VARIABLE_TYPE)

aidé à porter mon temps de compilation de 70 à 13

Harry Mexican
la source
0

Rien n'a fonctionné pour moi dans Xcode 6.3.1 - lorsque j'ai ajouté environ 100 fichiers Swift Xcode accroché au hasard sur la construction et / ou l'indexation. J'ai essayé une option modulaire sans succès.

L'installation et l'utilisation de Xcode 6.4 Beta ont réellement fonctionné pour moi.

hris.to
la source
0

Cela a fonctionné comme par magie pour moi - Speed ​​Up Swift Compilation . Il a réduit le temps de compilation à 3 minutes au lieu de 10 minutes.

Il dit que vous devez mettre le Whole Module Optimizationtout en ajoutant -Ononedans Other Swift Flags.

J'utilise Swift 3sur Xcode 8.3/Xcode 8.2 .

Forger
la source
0

Le mélange du littéral entier et du littéral flottant dans une expression entraîne également une longue durée de compilation.

1.0 + (1.0 + (1  * (1.0 + 1.0))) // 3429ms

1.0 + (1.0 + (1.0  * (1.0 + 1.0))) // 5ms

Beaucoup d'expressions de compilation de 1000 + ms sont réduites à 10 ~ 100 ms après avoir mis un .0littéral après entier.

Chen OT
la source