c++ - compilar - gcc linux install
Cómo acelerar el tiempo de compilación de g++(cuando se usan muchas plantillas) (11)
Esta pregunta es quizás algo extraña, pero ¿cómo puedo acelerar el tiempo de compilación de g ++? Mi código C ++ utiliza mucho boost y plantillas. Ya me moví tanto como fuera posible de los archivos de encabezados y uso la opción -j, pero aún me lleva bastante tiempo compilar (y vincular).
¿Hay alguna herramienta que analice mi código y señale cuellos de botella para el compilador? ¿O puede uno de alguna manera perfilar el compilador que se ejecuta en mi código? Esto sería muy bueno, porque a veces tengo la impresión de que pasé demasiado tiempo mirando el registro de la consola del compilador ...
Además de lo que todos los demás agregaron y de lo que ya estás haciendo (compilación paralelizada, opciones de compilación, etc.), considera ocultar las plantillas en las clases de implementación, a las que se accede a través de las interfaces. Eso significa que en lugar de tener una clase como:
// ClsWithNoTemplates.h file, included everywhere
class ClsWithTemplates
{
ComplicatedTemplate<abc> member;
// ...
public:
void FunctionUsingYourMember();
};
Deberías:
// ClsWithNoTemplates.h file:
class ClsWithTemplatesImplementation; // forward declaration
// definition included in the ClsWithNoTemplates.cpp file
// this class will have a ComplicatedTemplate<abc> member, but it is only
// included in your ClsWithNoTemplates definition file (that is only included once)
class ClsWithNoTemplates
{
ClsWithTemplatesImplementation * impl; // no templates mentioned anywhere here
public:
void FunctionUsingYourMember(); // call impl->FunctionUsingYourMember() internally
};
Esto cambia el diseño de su OOP un poco, pero es para bien: incluso la definición de ''ClsWithNoTemplates'' ahora es rápida y solo (previamente) compilará la definición de ''ClsWithNoTemplates'' una vez.
Además, si cambia el código de implementación, probablemente no sea necesario redefinir ningún código que incluya ClsWithNoTemplates.h.
Este cambio debería aumentar drásticamente el tiempo de compilación parcial, y también ayudará en el caso en que su ClsWithNoTemplates sea una interfaz pública exportada desde un archivo de biblioteca: dado que el archivo no se cambia cuando solo cambia la implementación, su código de cliente dependiente no Necesito ser recompilado en absoluto.
Crea una instancia de menos plantillas y funciones en línea. Precompila todo lo que puedas y solo vincúlalo en lugar de compilar todo desde cero. Asegúrese de estar utilizando la última versión de GCC.
Sin embargo, es un hecho simple que C ++ es un lenguaje increíblemente complejo y compilarlo lleva bastante tiempo.
Esto es lo que he hecho para acelerar las compilaciones en un escenario muy similar al descrito (boost, templates, gcc)
- construir en un disco local en lugar de un sistema de archivos de red como NFS
- actualizar a una versión más nueva de gcc
- investigar distcc
- sistemas de compilación más rápidos, especialmente más RAM
Lo que me ha sido más útil:
- Construya sobre un sistema de archivos RAM. Esto es trivial en Linux. Es posible que desee mantener una copia de los archivos de encabezado comunes (archivos precompilados o .h reales) en el sistema de archivos RAM también.
- Cabeceras precompiladas . Tengo una biblioteca por (principal) (por ejemplo, Boost, Qt, stdlib).
- Declarar en lugar de incluir clases cuando sea posible. Esto reduce las dependencias, por lo que reduce la cantidad de archivos que se deben recompilar cuando se cambia un archivo de encabezado.
- Paralelizar hacer . Esto generalmente ayuda caso por caso, pero tengo
-j3
globalmente para hacer. Sin embargo, asegúrate de que tus gráficos de dependencia sean correctos en tu Makefile o de que tengas problemas. - Use
-O0
si no está probando la velocidad de ejecución o el tamaño del código (y su computadora es lo suficientemente rápida para que no le importe demasiado el golpe de rendimiento (probablemente pequeño)). - Compila cada vez que guardes. A algunas personas no les gusta esto, pero le permite ver los errores de manera temprana y puede hacerlo en segundo plano, lo que reduce el tiempo que tiene que esperar cuando termina de escribir y está listo para la prueba.
Por lo general, las partes más costosas de la compilación son (a) leer los archivos fuente ( TODOS ) y (b) cargar el compilador en la memoria para cada archivo fuente.
Si tiene 52 archivos de origen (.cc), cada uno de los cuales #incluye 47 #include (.h) archivos, va a cargar el compilador 52 veces, y va a arar a través de 2496 archivos. Dependiendo de la densidad de los comentarios en los archivos, puede pasar un buen rato comiendo caracteres inútiles. (En una organización que he visto, los archivos de encabezado variaban entre 66% y 90% de comentarios, con solo 10% -33% del archivo siendo "significativo". Lo mejor que se podía hacer para mejorar la legibilidad de esos archivos era la tira hasta el último comentario, dejando solo el código).
Eche un vistazo a cómo está organizado físicamente su programa. Vea si puede combinar archivos de origen y simplificar su jerarquía de #include archivos.
Décadas atrás, empresas como IBM entendían esto y escribían sus compiladores para que al compilador se le entregara una lista de archivos para compilar, no solo un archivo, y el compilador solo se cargara una vez.
Pruebe la técnica PIMPL, esta pregunta: ¿Qué técnicas se pueden usar para acelerar los tiempos de compilación de C ++?
Evitará que el compilador siga la cadena de archivos de cabecera y las implementaciones cada vez que necesite hacer algo.
Si está haciendo una gran cantidad de recompilación, ccache podría ayudar. En realidad, no acelera la compilación, pero le dará un resultado en caché si realiza una compilación inútil por alguna razón. Puede dar la impresión de abordar el problema equivocado, pero a veces las reglas de reconstrucción son tan complicadas que en realidad terminas con el mismo paso de compilación durante una nueva compilación.
Idea adicional: si su código se compila con clang , clang su lugar. Por lo general, es más rápido que gcc.
Si hay muchos archivos, puede acelerar mucho la compilación con solo tener un archivo .cpp que # incluya todos los demás archivos .cpp. Por supuesto, esto requiere que tenga más cuidado con las macros y que ya las haya definido por archivo, ya que ahora serán visibles para otros archivos cpp.
Si hay muchos archivos, esto puede reducir mucho el tiempo de compilación.
Supongo que estamos hablando de minutos para compilar un archivo, es decir, los encabezados precompilados o los problemas del disco local no son el problema.
Los largos tiempos de compilación con un código de plantilla profundo (boost, etc.) a menudo están arraigados en el comportamiento asintótico antipático de gcc cuando se trata de la creación de instancias de plantillas, en particular cuando se emulan plantillas variadic con argumentos predeterminados de plantilla.
Aquí hay un documento que nombra el tiempo de compilación reducido como una motivación para plantillas variadic:
cpptruths tenía un artículo sobre cómo gcc-4.5 es mucho mejor en este nombre y cómo lo hace brillantemente con sus plantillas variadic:
IIRC luego BOOST tiene una manera de limitar la generación de parámetros predeterminados de la plantilla para las pseudovariadicas, creo que ''g ++ -DBOOST_MPL_LIMIT_LIST_SIZE = 10'' debería funcionar (el valor predeterminado es 20)
ACTUALIZACIÓN: También hay un buen hilo con técnicas generales para acelerar la compilación aquí en SO que podría ser útil:
ACTUALIZACIÓN: Esta es sobre los problemas de rendimiento al compilar plantillas, la respuesta aceptada también recomienda gcc-4.5, también se menciona el clang como un ejemplo positivo:
Este documento describe un método para compilar código de plantilla muy similar a los archivos de objetos no tradicionales "tradicionales". Guarda el tiempo de compilación y enlace, con solo una línea de sobrecarga de código por instanciación de plantilla.
Compilando con g ++ usando múltiples núcleos