Xcode 11 si ricompila troppo


12

Xcode 11 sta ricompilando (quasi?) Il mio intero progetto, anche se cambio semplicemente una variabile privata locale o cambio un valore di una costante nell'ambito locale, a volte anche nell'ambito della funzione privata locale. A volte posso ottenere 2 o 3 modifiche con build veloci come previsto, ma abbastanza presto decide di ricompilare di nuovo tutto (che richiede troppo tempo).

Qualche idea su cosa potrebbe succedere? Xcode non è in grado di determinare cosa è cambiato, perché ricompila così tante altre cose (anche altri moduli).

Ogni consiglio è molto apprezzato, grazie!


2
Vorrei consigliare: assicurarsi di eseguire build di debug con creazione incrementale, non ottimizzazione dell'intero modulo. Esci e ripulisci DerivedData. E aggiorna a Xcode 11.4, a volte si compila così velocemente che non vedo nemmeno che accada.
matt

1
Questo thread potrebbe rispondere alla tua domanda: stackoverflow.com/questions/25537614/...
Endanke

Dipende molto dal progetto, deve analizzare il registro di build su ciò che sta accadendo. Non osservo questo comportamento con Xcode 11.2+, mentre ho progetti molto grandi. Forniresti l'accesso alle fonti del tuo progetto in qualche modo, altrimenti tutti i consigli sono insensati?
Asperi

Controlla la proprietà Legacy Build System, deve essere deselezionata se non stai modificando i sottomoduli
BrunoLoops

Risposte:


8

Abbiamo avuto lo stesso problema e lo abbiamo risolto. Due volte.

Build incrementale (stessa build machine):

prima: ~ 10m dopo: ~ 35s

COME?

Cominciamo prima con la nostra esperienza. Avevamo un enorme progetto Swift / Obj-C e questa era la preoccupazione principale: i tempi di costruzione erano lenti e dovevi creare un nuovo progetto per implementare una nuova funzionalità (letteralmente). Punti bonus per l'evidenziazione della sintassi mai funzionante.

Teoria

Per risolvere veramente questo problema, devi veramente capire come funziona il sistema di compilazione. Ad esempio, proviamo questo snippet di codice:

import FacebookSDK
import RxSwift
import PinLayout

e immagina di usare tutte queste importazioni nel tuo file. E anche questo file dipende da un altro file, che dipende da altre librerie, che a loro volta usano altre librerie ecc.

Quindi per compilare il tuo file Xcode deve compilare ogni libreria che hai citato e ogni file da cui dipende, quindi se cambi uno dei file "core" Xcode deve ricostruire letteralmente l'intero progetto.

Albero delle dipendenze

La build di Xcode è multi-thread , ma è composta da molti alberi a thread singolo .

Quindi sul primo passo di ogni build incrementale Xcode sta decidendo quali file devono essere ricompilati e costruisce un albero AST . Se si modifica un file che si comporta come " affidabile " su altri file, è necessario ricompilare ogni altro file che agisce come " dipendente ".

accoppiamento

Quindi il primo consiglio è di abbassare l'accoppiamento . Le parti del progetto devono essere indipendenti l'una dall'altra.

Ponte Obj-C / Swift

Problema con quegli alberi se stai usando un bridge Obj-C / Swift, Xcode deve attraversare più fasi del solito:

Mondo perfetto:

  1. Costruisce il codice Obj-C
  2. Crea codice Swift

Ponte Swift / Obj-C

Ponte Obj-C / Swift:

  1. [PASSO RIPETIBILE] Crea codice Swift, necessario per compilare il codice Obj-C
  2. [PASSO RIPETIBILE] Crea il codice Obj-C, necessario per compilare il codice Swift
  3. Ripeti 1 e 2 fino a quando ti rimane solo il codice Swift & Obj-C non affidabile
  4. Costruisci il codice Obj-C
  5. Crea codice Swift

Ponte Obj-C / Swift

Quindi, se cambi qualcosa dal passaggio 1 o 2, sei sostanzialmente nei guai. La soluzione migliore è minimizzare Obj-C / Swift Bridge (e rimuoverlo dal progetto).

Se non hai un Obj-C / Swift Bridge, è fantastico e sei a posto per andare al passo successivo:

Swift Package Manager

È ora di passare a SwiftPM (o almeno configurare meglio i tuoi Cocoapods).

Il fatto è che la maggior parte dei framework con configurazione Cocoapods predefinita trascina con sé molte cose che non ti servono.

Per testarlo, crea un progetto vuoto con una sola dipendenza come PinLayout, ad esempio, e prova a scrivere questo codice con Cocoapods (configurazione predefinita) e SwiftPM.

import PinLayout

final class TestViewController: UIViewController {

}

Spoiler: Cocoapods compilerà questo codice, perché Cocoapods importerà OGNI IMPORTANTE di PinLayout (incluso UIKit) e SwiftPM non lo farà perché SwiftPM importa i framework atomicamente.

Hack sporco

Ricordi che Xcode build è multi-thread?

Bene, puoi abusarne, se sei in grado di dividere il tuo progetto in molti pezzi indipendenti e importarli tutti come framework indipendenti nel tuo progetto. Abbassa l'accoppiamento e questa è stata in realtà la prima soluzione che abbiamo usato, ma in realtà non era molto efficace, perché potevamo solo ridurre il tempo di costruzione incrementale a ~ 4-5 m, il che è NULLA rispetto al primo metodo.


Buona fortuna amico. Condividi la tua esperienza su come hai abbassato l'accoppiamento nel tuo progetto. Ciao!
x0 z1,

3

Non ci sono proiettili d'oro qui, ma molte cose da controllare:

  • Assicurati di utilizzare effettivamente la configurazione di debug nel tuo schemaXcode Scheme Editor utilizzando la configurazione di debug

  • Vedi sotto per come assicurarti di usare build incrementali rispetto all'intero modulo secondo i consigli di Matt. Assicurati anche che il tuo livello di ottimizzazione per build di debug non sia nessuno. Impostazioni Build Xcode che mostrano Build incrementali

  • Se si utilizzano framework pesanti di tipo-inferenza come RxSwift, l'aggiunta di annotazioni di tipo esplicite può accelerare i tempi di costruzione.

  • Se il progetto è molto grande, potresti prendere in considerazione il refactoring di gruppi logici di file sorgente in framework, ma potrebbe essere un cambiamento troppo drastico di quanto preferiresti

Potrebbe essere utile se hai fornito alcune informazioni più specifiche sul progetto: stai collegando staticamente qualche libreria? È un framework o un target di app? Quanto è grande e quale versione rapida stai usando? Hai delle fasi di costruzione personalizzate come linter o generazione di codice che potrebbero essere saltate a volte?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.