2009-02-12 6 views
57

Recientemente tuve motivos para trabajar con algunos proyectos de Visual Studio C++ con las configuraciones habituales de depuración y liberación, pero también 'Liberar todo' y 'Depurar todo', que nunca había visto antes.#incluye todos los archivos .cpp en una sola unidad de compilación?

Resulta que el autor de los proyectos tiene un único ALL.cpp que # incluye todos los demás archivos .cpp. * Todas las configuraciones solo compilan este archivo ALL.cpp. Por supuesto, está excluido de las configuraciones normales, y las configuraciones normales no compilan ALL.cpp

Me pregunto si esta es una práctica común. ¿Qué ventajas ofrece? (Mi primera reacción fue que olía mal.)

¿Qué tipo de escollos es probable que encuentres con esto? Uno en el que puedo pensar es si tienes espacios de nombres anónimos en tu .cpps, ya no son 'privados' para ese cpp, ¿pero ahora también están visibles en otros cpps?

Todos los proyectos crean archivos DLL, por lo que tener datos en espacios de nombres anónimos no sería una buena idea, ¿no? Pero las funciones estarían bien?

Saludos.

+0

Nuestra estructura oficial siempre se necesita una reconstrucción por lo que creen que este enfoque podría mejorar el rendimiento de construcción mucho. Pero dado que los builds oficiales son principalmente consumidos por Devs, pero los pdbs generados por UnityBuild pueden ser inválidos para el código no-unitybuild. (No queremos desarrollar con una configuración de compilación unitaria, ¿verdad?) –

+0

Razón completamente diferente para incluir algunos archivos de implementación en otro archivo de implementación es: estos archivos pueden autogenerarse. Es mucho más fácil generar automáticamente un archivo completo que tratar cambios de inyección en el código existente. –

+1

Definitivamente patológico; Solo puedo adivinar el motivo por el que cualquiera podría querer hacer eso (si, por otro lado, puede preguntarles directamente, debería hacerlo). Normalmente en C++ quieres hacer lo contrario, no solo mantener los archivos de implementación sino también los encabezados bien separados. (Una trampa común de los proyectos de C++ es "#include spaghetti", con cada archivo de cabecera dependiendo de cada uno). ¿Quizás para poner a prueba el compilador? – Morendil

Respuesta

47

Algunos (y google-able) lo mencionan como "Unity Build". Vincula locamente rápido y compila razonablemente rápido también. Es ideal para compilaciones en las que no necesita iterar, como una compilación de lanzamiento desde un servidor central, pero no es necesariamente para compilación incremental.

Y es un PITA para mantener.

EDIT: aquí está el primer enlace de Google para obtener más información: http://buffered.io/posts/the-magic-of-unity-builds/

Lo que hace que sea rápido es que el compilador sólo tiene que leer en todo una vez, compilar a cabo, a continuación, enlace, en lugar de hacer que por cada archivo .cpp

Bruce Dawson tiene una mucho mejor redactar sobre esto en su blog: http://randomascii.wordpress.com/2014/03/22/make-vc-compiles-fast-through-parallel-compilation/

+19

No es solo por E/S. Cada archivo .cpp individual a menudo incluye muchos archivos de encabezado. Si los compila por separado, compila el código en los archivos de encabezado varias veces, una para cada archivo .o. Si usa "Unity Build", estos archivos de encabezado y todo lo demás se compilan solo una vez. – Frank

+5

Er ... que cae bajo E/S. Pero sí, eso es más preciso. – MSN

+8

Las compilaciones * no * normalmente están vinculadas a E/S, a menos que tenga memoria insuficiente. Vea mi respuesta abajo.La memoria caché de disco funciona. La publicación vinculada emplea mucho tiempo en sofistería para explicar qué tan mala es la E/S de disco, pero es irrelevante debido a la memoria caché de disco. Además, * compilar * el código en los archivos de encabezado varias veces es completamente diferente de E/S. La compilación redundante es el problema, la E/S redundante nunca ocurre en realidad. Algunos de los peligros de las construcciones de unidades se cubren aquí: http://randomascii.wordpress.com/2014/03/22/make-vc-compiles-fast-through-parallel-compilation/ –

6

Me pregunto si eso ALL.cpp está tratando de poner todo el proyecto dentro de una sola unidad de compilación, para mejorar la capacidad para el compilador para optimizar el programa para el tamaño?

Normalmente, algunas optimizaciones solo se realizan en distintas unidades de compilación, como la eliminación de código duplicado y la alineación.

Dicho esto, parece recordar que los compiladores recientes (de Microsoft, Intel, pero no creo que esto incluya a GCC) pueden hacer esta optimización en varias unidades de compilación, por lo que sospecho que este 'truco' es innecesario.

Dicho esto, sería curioso ver si hay alguna diferencia.

+2

Visual C++ puede hacer la optimización del programa completo con el/Conmutador LTCG (generación de código de tiempo de enlace) –

+1

en estos días, GCC y clang también son compatibles con LTO – justin

+0

Entonces, ciertamente no es necesario. – Arafangion

40

Unity construye velocidades de construcción mejoradas por tres razones principales. La primera razón es que todos los archivos de encabezado compartidos solo deben analizarse una vez. Muchos proyectos C++ tienen muchos archivos de cabecera incluidos por la mayoría o todos los archivos CPP y el análisis redundante de estos es el principal costo de compilación, especialmente si tiene muchos archivos fuente cortos. Los archivos de encabezado precompilados pueden ayudar con este costo, pero generalmente hay muchos archivos de encabezado que no se precompilan.

La siguiente razón principal por la que las compilaciones unitarias mejoran las velocidades de compilación es porque el compilador se invoca menos veces. Hay un cierto costo inicial al invocar el compilador.

Finalmente, la reducción en el análisis de encabezado redundante significa una reducción en código-gen redundante para funciones en línea, por lo que el tamaño total de los archivos de objeto es menor, lo que hace que la vinculación sea más rápida.

Las compilaciones de Unity también pueden dar mejor código-gen.

Las compilaciones de Unity son NOT más rápidas debido a la E/S de disco reducida. He perfilado muchas compilaciones con xperf y sé de lo que estoy hablando. Si tiene suficiente memoria, la memoria caché de disco del sistema operativo evitará la E/S redundante; las lecturas posteriores de un encabezado provendrán de la memoria caché de disco del sistema operativo. Si no tienes suficiente memoria, las compilaciones unificadas pueden incluso empeorar los tiempos de compilación al hacer que el espacio de memoria del compilador exceda la memoria disponible y se deslocalice.

La E/S de disco es costosa, por lo que todos los sistemas operativos almacenan datos en caché agresivamente para evitar la E/S de disco redundante.

+1

La mayoría de las respuestas correctas aquí. Para proyectos masivos, no hay alternativa para la velocidad de compilación. Por cierto, sugirió msbuild/LTCG aumentar el tiempo de enlace de 4 minutos a la noche! (Clang fue mejor). – ChocoBilly

+0

Tenga en cuenta que VS 2015 soluciona el error enumerado a continuación, lo que hace que los enlaces LTCG se ejecuten de manera significativamente más rápida, tres veces más rápido en algunas pruebas recientes a gran escala. https://connect.microsoft.com/VisualStudio/feedback/details/1064219/ltcg-linking-of-chromes-pdf-dll-spends-60-of-time-in-c2-dll-ssrfree –

+0

Correcto. La compilación de C++ es lenta porque cada compilación se debe compilar por separado [¿Por qué tarda tanto la compilación de C++?] (Http://stackoverflow.com/q/318398/995714) –

1

Estoy de acuerdo con Bruce; según mi experiencia, intenté implementar Unity Build para uno de mis proyectos .dll, que incluía una gran cantidad de encabezados y muchos .cpps; para reducir el tiempo de compilación general en el VS2010 (ya había agotado las opciones de compilación incremental) pero en lugar de reducir el tiempo de compilación, me quedé sin memoria y la compilación no pudo terminar la compilación.

Sin embargo, agregar; Encontré que habilitar la opción de compilación multiprocesador en Visual Studio ayuda bastante a reducir el tiempo de compilación; No estoy seguro si dicha opción está disponible en otros compiladores de plataforma.

+2

Si acepta y no agrega nada, no lo hace Parece que esto debería ser una respuesta. Esto suena como más una historia y comentario. – RacerNerd

+1

En realidad; Tenía la intención de agregar un comentario sobre mi propia experiencia con el tema (sobre una base de código de fortaleza industrial y tamaño); para alguien que intenta lo mismo porque la idea de Unity Builds da la impresión de que casi daría como resultado una compilación menor; que no es el caso para proyectos grandes. La razón por la que intentaríamos esto en primer lugar; pero no soy nadie para descartar excepciones y ciertas consideraciones de diseño. – spforay

Cuestiones relacionadas