Estoy usando Xcode 6 Beta 6.
Esto es algo que me ha estado molestando desde hace un tiempo, pero está llegando a un punto en el que ahora apenas se puede usar.
Mi proyecto está empezando a tener una buena tamaño de 65 archivos Swift y algunos archivos Objective-C en puente (que en realidad no son la causa del problema).
Parece que cualquier ligera modificación en cualquier archivo Swift (como agregar un espacio en blanco simple en una clase que apenas se usa en la aplicación) hará que se vuelvan a compilar todos los archivos Swift para el objetivo especificado.
Después de una investigación más profunda, descubrí que lo que toma casi el 100% del tiempo del compilador es la CompileSwift
fase en la que Xcode ejecuta elswiftc
comando en todos los archivos Swift de su objetivo.
Investigué un poco más, y si solo mantengo al delegado de la aplicación con un controlador predeterminado, la compilación es muy rápida, pero a medida que agregaba más y más archivos de mi proyecto, el tiempo de compilación comenzaba a ser muy lento.
Ahora con solo 65 archivos de origen, se tarda unos 8/10 segundos en compilar cada vez. No muy rápido en absoluto.
No he visto ninguna publicación que hable sobre este problema, excepto esta , pero era una versión antigua de Xcode 6. Así que me pregunto si soy el único en ese caso.
ACTUALIZAR
He comprobado algunos proyectos Swift en GitHub como Alamofire , Euler y CryptoSwift , pero ninguno de ellos tenía suficientes archivos Swift para comparar. El único proyecto que encontré que estaba comenzando a tener un tamaño decente fue SwiftHN , y aunque solo tenía una docena de archivos fuente, todavía pude verificar lo mismo, un espacio simple y todo el proyecto necesitaba una recompilación que comenzaba a tomar un poco tiempo (2/3 segundos).
En comparación con el código Objective-C, donde tanto el analizador como la compilación son extremadamente rápidos, realmente parece que Swift nunca podrá manejar grandes proyectos, pero por favor dígame que estoy equivocado.
ACTUALIZAR con Xcode 6 Beta 7
Todavía no hay mejora alguna. Esto está empezando a ponerse ridículo. Con la falta de #import
Swift, realmente no veo cómo Apple podrá optimizar esto.
ACTUALIZACIÓN con Xcode 6.3 y Swift 1.2
Apple ha agregado compilaciones incrementales (y muchas otras optimizaciones del compilador). Tienes que migrar tu código a Swift 1.2 para ver esos beneficios, pero Apple agregó una herramienta en Xcode 6.3 para ayudarte a hacerlo:
SIN EMBARGO
No te regocijes demasiado rápido como lo hice. El solucionador de gráficos que usan para hacer que la construcción sea incremental aún no está muy bien optimizado.
De hecho, en primer lugar, no analiza los cambios en la firma de la función, por lo que si agrega un espacio en el bloque de un método, se volverán a compilar todos los archivos dependiendo de esa clase.
En segundo lugar, parece crear el árbol en función de los archivos que se volvieron a compilar, incluso si un cambio no los afecta. Por ejemplo, si mueve estas tres clases a archivos diferentes
class FileA: NSObject {
var foo:String?
}
class FileB: NSObject {
var bar:FileA?
}
class FileC: NSObject {
var baz:FileB?
}
Ahora, si modifica FileA
, el compilador obviamente marcará FileA
como recompilado. También se recompilará FileB
(eso estaría bien en función de los cambios FileA
), pero también FileC
porque FileB
se vuelve a compilar, y eso es bastante malo porque FileC
nunca se usa FileA
aquí.
Así que espero que mejoren el solucionador de árboles de dependencia ... Abrí un radar con este código de muestra.
ACTUALIZACIÓN Con Xcode 7 beta 5 y Swift 2.0
Ayer Apple lanzó la versión beta 5 y dentro de las notas de la versión pudimos ver:
Swift Language & Compiler • Compilaciones incrementales: cambiar solo el cuerpo de una función ya no debería causar la reconstrucción de archivos dependientes. (15352929)
Lo he probado y debo decir que está funcionando realmente (¡realmente!) Ahora. Optimizaron enormemente las compilaciones incrementales en Swift.
Le recomiendo que cree una swift2.0
rama y mantenga su código actualizado con XCode 7 beta 5. Le agradarán las mejoras del compilador (sin embargo, diría que el estado global de XCode 7 sigue siendo lento y con errores)
ACTUALIZAR con Xcode 8.2
Ha pasado un tiempo desde mi última actualización sobre este tema, así que aquí está.
Nuestra aplicación ahora tiene aproximadamente 20k líneas de código Swift casi exclusivamente, que es decente pero no sobresaliente. Sufrió una migración rápida 2 y rápida 3. Se tarda unos 5 / 6m en compilar en una Macbook pro de mediados de 2014 (Intel Core i7 de 2.5 GHz), lo cual está bien en una compilación limpia.
Sin embargo, la construcción incremental sigue siendo una broma a pesar de que Apple afirma que:
Xcode no reconstruirá un objetivo completo cuando solo se hayan producido pequeños cambios. (28892475)
Obviamente, creo que muchos de nosotros simplemente nos reímos después de revisar estas tonterías (agregar una propiedad privada (¡privada!) A cualquier archivo de mi proyecto recompilará todo ...)
Me gustaría señalarles este hilo en los foros de desarrolladores de Apple que tiene más información sobre el problema (así como también agradeció la comunicación de desarrollo de Apple sobre el tema de vez en cuando)
Básicamente, las personas han ideado algunas cosas para tratar de mejorar la compilación incremental:
- Agregar una
HEADER_MAP_USES_VFS
configuración de proyecto establecida entrue
- Deshabilitar
Find implicit dependencies
de su esquema - Cree un nuevo proyecto y mueva su jerarquía de archivos al nuevo.
Intentaré la solución 3 pero la solución 1/2 no funcionó para nosotros.
Lo que es irónicamente gracioso en toda esta situación es que al mirar la primera publicación sobre este tema, estábamos usando Xcode 6 con el código Swift 1 o Swift 1.1 cuando llegamos a la primera lentitud de compilaciones y ahora unos dos años más tarde a pesar de las mejoras reales de Apple. la situación es tan mala como lo fue con Xcode 6. Qué irónico.
En realidad REALMENTE lamento elegido Swift sobre Obj / C para nuestro proyecto debido a la frustración diaria que esto implica. (Incluso cambio a AppCode pero esa es otra historia)
De todos modos, veo que esta publicación SO tiene más de 32k vistas y 143 ups al momento de escribir esto, así que supongo que no soy el único. Esperen, muchachos, a pesar de ser pesimistas sobre esta situación, puede haber algo de luz al final del túnel.
Si tienes tiempo (¡y coraje!), Supongo que Apple agradece el radar sobre esto.
¡Hasta la próxima! Salud
ACTUALIZAR con Xcode 9
Tropezar con esto hoy. Xcode presentó silenciosamente un nuevo sistema de compilación para mejorar el horrible rendimiento actual. Debe habilitarlo a través de la configuración del espacio de trabajo.
Ya lo probé, pero actualizaré esta publicación una vez que haya terminado. Sin embargo, parece prometedor.
Respuestas:
Bueno, resultó que Rob Napier tenía razón. Fue un solo archivo (en realidad, un método) lo que causó que el compilador se volviera loco.
Ahora no me malinterpretes. Swift recompila todos sus archivos cada vez, pero lo mejor ahora es que Apple agregó comentarios de compilación en tiempo real sobre los archivos que compila, por lo que Xcode 6 GM ahora muestra qué archivos Swift se están compilando y el estado de la compilación en tiempo real como puedes ver en esta captura de pantalla:
Esto es muy útil para saber cuál de sus archivos está tardando tanto. En mi caso fue este código:
porque la propiedad
title
era de tipovar title:String?
y noNSString
. El compilador se estaba volviendo loco al agregarlo alNSMutableDictionary
.Cambiándolo a:
hizo que la compilación pasara de 10/15 segundos (tal vez incluso más) a un solo segundo ... increíble.
fuente
Hemos intentado algunas cosas para combatir esto, ya que tenemos alrededor de 100k líneas de código Swift y 300k líneas de código ObjC.
Nuestro primer paso fue optimizar todas las funciones de acuerdo con la salida de los tiempos de compilación de funciones (por ejemplo, como se describe aquí https://thatthinginswift.com/debug-long-compile-times-swift/ )
A continuación, escribimos un script para fusionar todos los archivos rápidos en un solo archivo, esto rompe los niveles de acceso, pero llevó nuestro tiempo de compilación de 5-6 minutos a ~ 1 minuto.
Esto ya no está vigente porque le preguntamos a Apple sobre esto y nos aconsejaron que deberíamos hacer lo siguiente:
'Fast, Whole Module Optimization'
'-Onone'
Cuando se establecen estos indicadores, el compilador compilará todos los archivos Swift en un solo paso. Descubrimos que con nuestro script de fusión esto es mucho más rápido que compilar archivos individualmente. Sin embargo, sin la '
-Onone'
anulación ' , también optimizará todo el módulo, que es más lento. Cuando configuramos la'-Onone'
bandera en las otras banderas Swift, detiene la optimización, pero no deja de compilar todos los archivos Swift en un solo paso.Para obtener más información sobre la optimización de todo el módulo, consulte la publicación del blog de Apple aquí: https://swift.org/blog/whole-module-optimizations/
Hemos encontrado que estas configuraciones permiten que nuestro código Swift se compile en 30 segundos :-) No tengo evidencia de cómo funcionaría en otros proyectos, pero sugiero probarlo si los tiempos de compilación Swift siguen siendo un problema para usted.
Tenga en cuenta que para las compilaciones de su tienda de aplicaciones, debe
'-Onone'
omitir el indicador, ya que se recomienda la optimización para las compilaciones de producción.fuente
-Onone
. No podemos utilizar la optimización completa del módulo por ahora porque hace que el compilador se bloquee ... Pero su consejo aumenta casi x10 la velocidad de construcción. En MacBook Air (anual 2013) se estaba construyendo alrededor de 8 minutos, ahora se reduce a alrededor de 1 minuto y la mitad de ese tiempo se pasa cambiando entre objetivos (tenemos aplicaciones, extensiones y pocos marcos internos) y compilando guiones gráficos-Onone
ayuda para reducir los tiempos de construcción. Muchas gracias amigo!Es probable que tenga poco que ver con el tamaño de su proyecto. Probablemente sea un código específico, posiblemente incluso una sola línea. Puede probar esto intentando compilar un archivo a la vez en lugar de todo el proyecto. O intente ver los registros de compilación para ver qué archivo está tardando tanto.
Como ejemplo de los tipos de código que pueden causar problemas, esta esencia de 38 líneas tarda más de un minuto en compilarse en beta7. Todo esto es causado por este bloque:
Simplifique eso con solo una línea o dos y se compila casi al instante. El problema es que esto está causando un crecimiento exponencial (posiblemente un crecimiento factorial) en el compilador. Obviamente, eso no es lo ideal, y si puede aislar tales situaciones, debe abrir los radares para ayudar a solucionar esos problemas.
fuente
CompileSwift
fase. Toma todos los archivos rápidos incluso si solo se modificó uno. Entonces, si se trata de un archivo que está tardando un tiempo (lo cual dudo mucho), el compilador nunca le dirá cuál es.swiftc
para ver cuánto tardan.Si está tratando de identificar archivos específicos que ralentizan su tiempo de compilación, puede intentar compilarlo desde su línea de comandos a través de xctool, que le dará tiempos de compilación archivo por archivo.
Lo que hay que tener en cuenta es que, de forma predeterminada, crea 2 archivos simultáneamente por cada núcleo de CPU, y no le dará el tiempo transcurrido "neto", sino el tiempo absoluto de "usuario". De esta manera, todos los tiempos se igualan entre archivos paralelos y se ven muy similares.
Para superar esto, establezca el
-jobs
indicador en 1 , de modo que no paralelice las compilaciones de archivos. Tomará más tiempo, pero al final tendrá tiempos de compilación "netos" que puede comparar archivo por archivo.Este es un comando de ejemplo que debería hacer el truco:
xctool -workspace <your_workspace> -scheme <your_scheme> -jobs 1 build
El resultado de la fase "Compilar archivos Swift" sería algo así como:
A partir de esta salida, puede identificar rápidamente qué archivos tardan más que otros en compilarse. Además, puede determinar con alta precisión si sus refactorizaciones (conversiones explícitas, sugerencias de tipo, etc.) están reduciendo los tiempos de compilación para archivos específicos o no.
NOTA: técnicamente también podría hacerlo,
xcodebuild
pero el resultado es increíblemente detallado y difícil de consumir.fuente
Swift Compiler
→Optimization Level
paraFast, Whole Module Optimization [-O -whole-module-optimization]
En mi caso, Xcode 7 no hizo ninguna diferencia. Tenía varias funciones que requieren varios segundos para compilar.
Ejemplo
Después de desenvolver las opciones, el tiempo de construcción cayó en un 99.4% .
Ver más ejemplos en esta publicación y esta publicación .
Build Time Analyzer para Xcode
Yo desarrollé un plug-in de Xcode que puede ser útil para cualquier persona que experimenta estos problemas.
Parece que hay mejoras en Swift 3, así que esperamos ver nuestro código Swift compilar más rápido.
fuente
Probablemente no podamos arreglar el compilador Swift, ¡pero algo que podemos arreglar es nuestro código!
Hay una opción oculta en el compilador Swift que imprime los intervalos de tiempo exactos que toma el compilador para compilar cada función:
-Xfrontend -debug-time-function-bodies
. Nos permite encontrar cuellos de botella en nuestro código y mejorar significativamente el tiempo de compilación.Simplemente ejecute lo siguiente en la terminal y analice los resultados:
Impresionante Brian Irace escribió un artículo brillante al respecto Perfilando tus tiempos de compilación Swift .
fuente
alias grep='noglob grep'
primero, de lo contrario grep no funcionaráLa solución es el casting.
Tenía una gran variedad de toneladas de diccionarios, como este:
Le tomó aproximadamente 40 minutos compilarlo. Hasta que lancé los diccionarios así:
Esto funcionó para casi cualquier otro problema que encontré con respecto a los tipos de datos que codifiqué en mi aplicación.
fuente
Una cosa a tener en cuenta es que el motor de inferencia de tipo Swift puede ser muy lento con tipos anidados. Puede obtener una idea general sobre lo que está causando la lentitud mirando el registro de compilación de unidades de compilación individuales que están tardando mucho tiempo y luego copiando y pegando el comando completo generado por Xcode en una ventana de Terminal y luego presionando CTRL- \ para obtener Algunos diagnósticos. Eche un vistazo a http://blog.impathic.com/post/99647568844/debugging-slow-swift-compile-times para ver un ejemplo completo.
fuente
También asegúrese de que al compilar para la depuración (ya sea Swift u Objective-C), configure solo Build Active Architecture:
fuente
Dado que todo esto está en Beta, y dado que el compilador Swift (al menos a partir de hoy) no está abierto, supongo que no hay una respuesta real a su pregunta.
En primer lugar, comparar Objective-C con el compilador Swift es de alguna manera cruel. Swift todavía está en Beta, y estoy seguro de que Apple está trabajando para proporcionar funcionalidad y corregir errores, más que proporcionar la velocidad del rayo (no comienzas a construir una casa comprando los muebles). Supongo que Apple optimizará el compilador a su debido tiempo.
Si por alguna razón todos los archivos fuente tienen que compilarse por completo, una opción podría ser crear módulos / bibliotecas separados. Pero esta opción aún no es posible, ya que Swift no puede permitir bibliotecas hasta que el idioma sea estable.
Supongo que optimizarán el compilador. Por la misma razón por la que no podemos crear módulos precompilados, bien podría ser que el compilador necesite compilar todo desde cero. Pero una vez que el idioma alcanza una versión estable y el formato de los binarios ya no cambia, podremos crear nuestras bibliotecas, y tal vez (?) El compilador también podrá optimizar su trabajo.
Sin embargo, solo adivino, porque solo Apple sabe ...
fuente
Para Xcode 8, vaya a la configuración del proyecto, luego Editor> Agregar configuración de compilación> Agregar configuración definida por el usuario y agregue lo siguiente:
Agregar esta bandera redujo nuestros tiempos de compilación de compilación limpia de 7 minutos a 65 segundos para un proyecto rápido de 40KLOC, milagrosamente. También puede confirmar que 2 amigos han visto mejoras similares en proyectos empresariales.
Solo puedo suponer que se trata de algún tipo de error en Xcode 8.0
EDITAR: Parece que ya no funciona en Xcode 8.3 para algunas personas.
fuente
Desafortunadamente, el compilador Swift aún no está optimizado para una compilación rápida e incremental (a partir de Xcode 6.3 beta). Mientras tanto, puede usar algunas de las siguientes técnicas para mejorar el tiempo de compilación de Swift:
Divida la aplicación en Frameworks para reducir el impacto de la recompilación. Pero tenga en cuenta que debe evitar las dependencias cíclicas en su aplicación. Para obtener más información sobre este tema, consulte esta publicación: http://bits.citrusbyte.com/improving-swift-compile-time/
Use Swift para partes de su proyecto que sean bastante estables y que no cambien con frecuencia. Para otras áreas en las que necesita cambiar muy a menudo o áreas que requieren muchas iteraciones de compilación / ejecución para completarse (casi cualquier cosa relacionada con la interfaz de usuario), use mejor Objective-C con un enfoque de combinación y combinación.
Pruebe la inyección de código de tiempo de ejecución con 'Injection for Xcode'
Utilice el método roopc: http://roopc.net/posts/2014/speeding-up-swift-builds/
Alivie el motor de inferencia de tipo rápido dando algunas pistas con lanzamientos explícitos.
fuente
La construcción rápida de matrices y diccionarios parece ser una causa bastante popular para esto (especialmente para ustedes que provienen de un fondo Ruby ), es decir,
probablemente será la causa donde esto debería solucionarlo:
fuente
Para depurar y probar, asegúrese de utilizar la siguiente configuración para reducir el tiempo de compilación de alrededor de 20 minutos a menos de 2 minutos,
Perdí incontables horas esperando que el proyecto se construyera solo para darme cuenta de que tenía que hacer ese pequeño cambio y tuve que esperar otros 30 minutos para probarlo. Estas son las configuraciones que funcionaron para mí. (Todavía estoy experimentando con la configuración)
Pero asegúrese de al menos configurar "DWARF with dSYM" (si desea monitorear su aplicación) y Build Active Architecture en "NO" para Release / Archiving para enviar a iTunes Connect (recuerdo haber perdido algunas horas aquí también).
fuente
Set Build for Active Architecture: YES
me dio una reducción aproximada del 45% en el tiempo de compilación. Muchas gracias.El compilador pasa mucho tiempo inferiendo y verificando los tipos. Por lo tanto, agregar anotaciones de tipo ayuda mucho al compilador.
Si tiene muchas llamadas a funciones encadenadas como
Luego, el compilador tarda un tiempo en averiguar cuál
sum
debería ser el tipo de . Agregar el tipo ayuda. Lo que también ayuda es llevar los pasos intermitentes a variables separadas.Especialmente para los tipos numéricos
CGFloat
,Int
puede ayudar mucho. Un número literal como2
puede representar muchos tipos numéricos diferentes. Por lo tanto, el compilador debe determinar, a partir del contexto, cuál es.+
También se deben evitar las funciones que requieren mucho tiempo para buscar . El uso de varios+
para concatenar varios arreglos es lento porque el compilador necesita averiguar qué implementación de+
debe llamarse para cada uno+
. Entonces usa unvar a: [Foo]
conappend()
en su lugar si es posible.Puede agregar una advertencia para detectar qué funciones son lentas para compilar en Xcode .
En Configuración de compilación para su objetivo, busque Otras banderas rápidas y agregue
-Xfrontend -warn-long-function-bodies=100
para advertir sobre cada función que tarda más de 100 ms en compilarse.
fuente
Para los proyectos que mezclan Objetivo-C de código y Swift, podemos establecer
-enable-bridging-pch
enOther Swift Flags
. Con esto, el encabezado de puente se analiza solo una vez, y el resultado (un "encabezado precompilado" o archivo "PCH" temporal) se almacena en caché y se reutiliza en todos los archivos Swift en el destino. Apple afirmó que disminuye el tiempo de construcción en un 30%. Link de referencia:NOTA: Esto funciona solo para Swift 3.1 y superior.
fuente
Reiniciar mi Mac hizo maravillas con este problema. Pasé de 15 minutos a 30 segundos simplemente reiniciando.
fuente
Se mejoró el tiempo de compilación rápido en el nuevo Xcode 6.3
fuente
Aquí hay otro caso que puede causar ralentizaciones masivas con inferencia de tipos. Operadores coalescentes .
Líneas cambiantes como:
a
ayudó a llevar mi tiempo de compilación de los 70 a los 13
fuente
Nada funcionó para mí en Xcode 6.3.1: cuando agregué alrededor de 100 archivos Swift, Xcode colgó al azar en la compilación y / o indexación. He probado una opción modular sin éxito.
Instalar y usar Xcode 6.4 Beta realmente funcionó para mí.
fuente
Esto ha funcionado como magia para mí: Speed Up Swift Compilation . Redujo el tiempo de compilación a 3 minutos de 10 minutos.
Se dice que se debe encender el
Whole Module Optimization
tiempo que añade-Onone
enOther Swift Flags
.Estoy usando
Swift 3
enXcode 8.3
/Xcode 8.2
.fuente
Mezclar el entero entero y el literal flotante en una expresión también causa un tiempo de compilación prolongado.
Muchas expresiones de tiempo de compilación de más de 1000 ms se reducen a 10 ~ 100 ms después de poner un
.0
literal entero después.fuente