Xcode 11 kompiliert zu viel neu

12

Xcode 11 kompiliert (fast?) Mein gesamtes Projekt neu, selbst wenn ich nur eine lokale private Variable oder einen Wert einer Konstanten im lokalen Bereich ändere, manchmal sogar im lokalen privaten Funktionsbereich. Ich kann manchmal 2 oder 3 Änderungen mit schnellen Builds wie erwartet erhalten, aber bald genug entscheidet es sich, alles erneut zu kompilieren (was zu lange dauert).

Irgendwelche Ideen, was los sein könnte? Kann Xcode nicht feststellen, was geändert wurde, warum werden so viele andere Dinge (sogar andere Module) neu kompiliert?

Jeder Rat wird sehr geschätzt, danke!

Nikolay Suvandzhiev
quelle
2
Ich würde raten: Stellen Sie sicher, dass Sie Debug-Builds mit inkrementeller Erstellung und nicht mit Optimierung des gesamten Moduls durchführen. Beenden und bereinigen Sie DerivedData. Und Update auf Xcode 11.4, es kompiliert manchmal so schnell, dass ich nicht einmal sehe, dass es passiert.
Matt
1
Dieser Thread könnte Ihre Frage beantworten: stackoverflow.com/questions/25537614/…
Endanke
Es ist sehr projektabhängig und muss das Build-Protokoll dahingehend analysieren, was gerade passiert. Ich beobachte ein solches Verhalten mit Xcode 11.2+ nicht, obwohl ich sehr große Projekte habe. Würden Sie irgendwie Zugriff auf Ihre Projektquellen gewähren, sonst sind alle Ratschläge sinnlos?
Asperi
Überprüfen Sie die Legacy Build System-Eigenschaft. Sie sollte
deaktiviert

Antworten:

8

Wir hatten das gleiche Problem und haben es behoben. Zweimal.

Inkrementeller Build (gleiche Build-Maschine):

vor: ~ 10m nach: ~ 35s

WIE?

Beginnen wir zuerst mit unserer Erfahrung. Wir hatten ein riesiges Swift / Obj-C-Projekt und das war das Hauptanliegen: Die Erstellungszeiten waren langsam und Sie mussten ein neues Projekt erstellen, um eine neue Funktion zu implementieren (im wahrsten Sinne des Wortes). Bonuspunkte für nie funktionierende Syntaxhervorhebung.

Theorie

Um dies wirklich zu beheben, müssen Sie wirklich verstehen, wie das Build-System funktioniert. Versuchen wir zum Beispiel dieses Code-Snippet:

import FacebookSDK
import RxSwift
import PinLayout

und stellen Sie sich vor, Sie verwenden alle diese Importe in Ihrer Datei. Und auch diese Datei hängt von einer anderen Datei ab, die von anderen Bibliotheken abhängt, die wiederum andere Bibliotheken usw. verwendet.

Um Ihre Datei zu kompilieren, muss Xcode jede Bibliothek kompilieren, die Sie erwähnt haben, und jede Datei, von der es abhängt. Wenn Sie also eine der "Kern" -Dateien ändern, muss Xcode buchstäblich das gesamte Projekt neu erstellen.

Abhängigkeitsbaum

Der Xcode-Build ist ein Multithread-Baum , besteht jedoch aus vielen Single-Thread- Bäumen .

Im ersten Schritt jedes inkrementellen Builds entscheidet Xcode, welche Dateien neu kompiliert werden müssen, und erstellt einen AST-Baum . Wenn Sie eine Datei ändern, die von anderen Dateien als " zuverlässig " fungiert, muss jede andere Datei, die als " abhängig " fungiert, neu kompiliert werden.

Kupplung

Der erste Rat ist also, die Kupplung zu senken . Ihre Projektteile müssen unabhängig voneinander sein.

Obj-C / Swift Brücke

Problem mit diesen Bäumen Wenn Sie eine Obj-C / Swift-Brücke verwenden, muss Xcode mehr Phasen als gewöhnlich durchlaufen:

Perfekte Welt:

  1. Erstellt Obj-C-Code
  2. Erstellen Sie Swift-Code

Swift / Obj-C Brücke

Obj-C / Swift-Brücke:

  1. [WIEDERHOLBARER SCHRITT] Erstellen Sie Swift-Code, der zum Kompilieren von Obj-C-Code benötigt wird
  2. [WIEDERHOLBARER SCHRITT] Erstellen Sie Obj-C-Code, der zum Kompilieren von Swift-Code benötigt wird
  3. Wiederholen Sie 1 und 2, bis Sie nur noch einen nicht zuverlässigen Swift & Obj-C-Code haben
  4. Erstellen Sie den Obj-C-Code
  5. Erstellen Sie Swift-Code

Obj-C / Swift Brücke

Wenn Sie also etwas von Schritt 1 oder 2 ändern, sind Sie im Grunde in Schwierigkeiten. Die beste Lösung besteht darin, Obj-C / Swift Bridge zu minimieren (und aus Ihrem Projekt zu entfernen).

Wenn Sie keine Obj-C / Swift-Brücke haben, ist das großartig und Sie können mit dem nächsten Schritt fortfahren:

Schneller Paketmanager

Zeit, zu SwiftPM zu wechseln (oder zumindest Ihre Cocoapods besser zu konfigurieren).

Die meisten Frameworks mit der Standardkonfiguration von Cocoapods ziehen eine Menge Dinge mit sich, die Sie nicht benötigen.

Um dies zu testen, erstellen Sie ein leeres Projekt mit nur einer Abhängigkeit wie beispielsweise PinLayout und versuchen Sie, diesen Code mit Cocoapods (Standardkonfiguration) und SwiftPM zu schreiben.

import PinLayout

final class TestViewController: UIViewController {

}

Spoiler: Cocoapods kompilieren diesen Code, da Cocoapods JEDEN IMPORT von PinLayout (einschließlich UIKit) importieren und SwiftPM nicht, weil SwiftPM Frameworks atomar importiert.

Schmutziger Hack

Erinnerst du dich, dass Xcode Build Multithreaded ist?

Nun, Sie können es missbrauchen, wenn Sie Ihr Projekt in viele unabhängige Teile aufteilen und alle als unabhängige Frameworks in Ihr Projekt importieren können. Es verringert zwar die Kopplung und das war tatsächlich die erste Lösung, die wir verwendeten, aber es war tatsächlich nicht sehr effektiv, da wir die inkrementelle Bauzeit nur auf ~ 4-5 m reduzieren konnten, was im Vergleich zur ersten Methode NICHTS ist.

x0 z1
quelle
Viel Glück, Junge. Teilen Sie Ihre Erfahrungen mit, wie Sie die Kopplung in Ihrem Projekt gesenkt haben. Tschüss!
x0 z1
3

Hier gibt es keine goldene Kugel, aber es gibt viele Dinge zu überprüfen:

  • Stellen Sie sicher, dass Sie tatsächlich die Debug- Konfiguration in Ihrem Schema verwendenXcode Scheme Editor mit der Debug-Konfiguration

  • Im Folgenden erfahren Sie, wie Sie sicherstellen können, dass Sie inkrementelle Builds im Vergleich zum gesamten Modul gemäß den Empfehlungen von matt verwenden. Stellen Sie außerdem sicher, dass Ihre Optimierungsstufe für Debug-Builds keine ist. Xcode Build-Einstellungen, die inkrementelle Builds anzeigen

  • Wenn Sie typabhängige Frameworks wie RxSwift verwenden, kann das Hinzufügen expliziter Typanmerkungen die Erstellungszeiten verkürzen.

  • Wenn das Projekt sehr groß ist, können Sie logische Gruppen von Quelldateien in Frameworks umgestalten. Dies kann jedoch zu drastisch sein, als Sie es bevorzugen

Es könnte hilfreich sein, wenn Sie weitere Einzelheiten zum Projekt angeben: Verknüpfen Sie statisch Bibliotheken? Ist es ein Framework oder ein App-Ziel? Wie groß und welche schnelle Version verwenden Sie? Haben Sie benutzerdefinierte Build-Phasen wie Linters oder Codegenerierung, die manchmal übersprungen werden können?

nteissler
quelle