2008-11-14 5 views
10

Tengo un montón de código heredado para el que necesito escribir pruebas unitarias. Utiliza encabezados precompilados en todas partes, por lo que casi todos los archivos .cpp tienen una dependencia en stdafx.h, lo que hace que sea difícil romper las dependencias para escribir pruebas.¿Hay alguna manera de usar encabezados precompilados en VC++ sin requerir stdafx.h?

Mi primer instinto es eliminar todos estos archivos stdafx.h que, en su mayoría, contienen las directivas #include y colocar esos #includes directamente en los archivos de origen según sea necesario.

Esto haría necesario desactivar encabezados precompilados ya que dependen de tener un archivo como stdafx.h para determinar dónde se detienen los encabezados precompilados.

¿Hay alguna manera de mantener encabezados precompilados sin las dependencias de stdafx.h? ¿Hay una mejor manera de abordar este problema?

+0

Personalmente utilizo encabezados precompilados (tanto para código normal como para pruebas unitarias) pero uso el nombre Precompilado.h/cpp. Los encabezados precompilados para las pruebas unitarias incluyen encabezados adicionales para que la compilación sea más rápida. – Daemin

+0

vote por ESTO: http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4931119-allow-precompiled-headers-to-be-shared-between-pro –

+0

Sí, hay una mejor camino. Solo se puede usar un encabezado precompilado para cada archivo fuente, pero el archivo pch se puede especificar antes * de cada archivo fuente o conjunto de archivos fuente. También puede especificar qué archivos fuente usan o no usan un encabezado precompilado. Ver mi respuesta a continuación. – riderBill

Respuesta

9

Sí, hay una manera mejor.

El problema, en mi humilde opinión, con el 'estilo de asistente' de los encabezados precompilados es que fomentan el acoplamiento no requerido y hacen que el código de reutilización sea más difícil de lo que debería ser. Además, el código que se ha escrito con el estilo 'solo pegue todo en stdafx.h' es propenso a ser difícil de mantener, ya que es probable que cambiar todo en cualquier archivo de encabezado vuelva a compilar todo el código base en todo momento. Esto puede hacer que la refactorización simple dure para siempre ya que cada ciclo de cambio y recompilación lleva mucho más tiempo de lo que debería.

Una mejor manera, de nuevo en mi humilde opinión, es el uso de pragma hdrstop y/Yc y/Yu. Esto le permite configurar fácilmente configuraciones de compilación que utilizan encabezados precompilados y también configuraciones de compilación que no usan encabezados precompilados. Los archivos que usan encabezados precompilados no tienen una dependencia directa en el encabezado precompilado en sí en el archivo de origen, lo que les permite compilarse con o sin el encabezado precompilado. El archivo del proyecto determina qué archivo fuente crea el encabezado precompilado y la línea #pragma hdrstop en cada archivo fuente determina qué incluye se toman del encabezado precompilado (si se usa) y cuáles se toman directamente del archivo fuente ... Esto significa que cuando Al realizar el mantenimiento, utilizaría la configuración que no usa encabezados precompilados y solo se reconstruirá el código que necesita reconstruir después de que se modifique el archivo de encabezado. Al realizar compilaciones completas, puede usar las configuraciones de encabezado precompiladas para acelerar el proceso de compilación.Otra ventaja de tener la opción de compilación de encabezado no precompilado es que se asegura de que los archivos cpp solo incluyan lo que necesitan e incluyan todo lo que necesiten (algo que es difícil si usa el 'estilo de asistente' del encabezado precompilado.

he escrito un poco sobre cómo funciona aquí: http://www.lenholgate.com/blog/2004/07/fi-stlport-precompiled-headers-warning-level-4-and-pragma-hdrstop.html (ignorar la materia sobre/FI) y tengo algunos proyectos de ejemplo que se acumulan con el hdrstop #pragma y el método/YC/Yu aquí:. http://www.lenholgate.com/blog/2008/04/practical-testing-16---fixing-a-timeout-bug.html

Por supuesto, pasar del uso de encabezado precompilado de "estilo de asistente" a un estilo más controlado a menudo no es trivial ...

+0

Consulte: http://stackoverflow.com/questions/7282853/what-does-pragma-hdrstop-without-parameter-do-when-used-in-multiple-files - gracias. –

2

No, probablemente haya NO una mejor manera.

Sin embargo, para un archivo .cpp individual dado, puede decidir que no necesita el encabezado precompilado. Puede modificar la configuración para ese archivo .cpp y eliminar la línea stdafx.h.

(En realidad, sin embargo, no sé cómo el esquema de encabezado precompilado está interfiriendo con la escritura de las pruebas de su unidad).

+0

Sí, hay una mejor manera. Ver mi respuesta a continuación. La respuesta de @Len Holgate también funciona. – riderBill

2

No. encabezados precompilados se basa en un solo encabezado incluido por todas las fuentes compiladas de esta manera. puede especificar que una sola fuente (o todas) no use encabezados precompilados en absoluto, pero eso no es lo que desea.

En el pasado, el compilador Borland C++ realizaba la compilación previa sin un encabezado específico. sin embargo, si dos archivos de fuentes incluían los mismos encabezados pero en diferentes ordenados, se compilaron por separado, ya que, de hecho, el orden de los archivos de encabezado en C++ puede importar ...

Por lo tanto, significa que el borland pre los encabezados compilados ahorraron tiempo solo si incluyeron muy rígidamente las fuentes en el mismo orden, o si incluyeron un único archivo de inclusión (primero) en todos los demás archivos ... - ¿le suena familiar?!?!

+0

No es cierto; puede especificar un encabezado precompilado diferente para cada archivo fuente individual o especificar que algunos archivos souce usan uno y otros no. – riderBill

1

Mi consejo es - no elimine los encabezados precompilados a menos que quiera hacer que sus compilaciones sean muy lentas. Es, básicamente, tiene tres opciones aquí:

  1. Elimina encabezados precompilados (no se recomienda)
  2. Crear una biblioteca independiente para el código de la herencia; de esa manera puedes construirlo por separado.
  3. Usar múltiples encabezados precompilados dentro de un único proyecto. Puede seleccionar archivos C++ individuales en su Solution Explorer y decirles qué encabezado precomiled debe usar. También necesitaría configurar su OtherStdAfx.h/cpp para generar un encabezado precompilado.
0

Solo uso encabezados precompilados para el código que debe incluir las cosas afx___, generalmente solo UI, que no realizo pruebas unitarias. El código de UI maneja la IU y llama a las funciones que sí tienen pruebas unitarias (aunque la mayoría actualmente no se debe a que la aplicación sea heredada).

Para la mayor parte del código no uso encabezados precompilados.

G.

4

Cuando normalmente utiliza encabezados precompilados, "stdafx.h" 2 propósitos. Define un conjunto de archivos de inclusión estables y comunes. También en cada archivo .cpp, sirve como un marcador como donde terminan los encabezados precompilados.

suena como lo que quieres hacer es:

  • Dejar encabezado precompilado encendido.
  • Deje la inclusión de "stdafx.h" en cada archivo .cpp.
  • Vaciar las inclusiones de "stdafx.h".
  • Para cada archivo .cpp, descubra qué elementos eran necesarios del antiguo "stdafx.h". Agregue estos antes del #include "stdafx.h" en cada archivo .cpp.

Así que ahora tiene el conjunto mínimo de dependencias, y todavía está utilizando encabezados precompilados. La pérdida es que no estás precompilando tu conjunto común de encabezados solo una vez. Esto sería un gran golpe para una reconstrucción completa. Para el modo de desarrollo, donde solo está recompilando algunos archivos a la vez, sería menos exitoso.

+0

Gracias. Decidí una variación de este enfoque. stdafx.h solo puede contener #includes de bibliotecas externas (encabezados de ventanas, STL, impulso, etc.) Todos los encabezados de aplicaciones internas deben incluirse directamente en archivos .cpp. – Ferruccio

2

Sí. El nombre "stdafx.h/stdafx.pch" es solo una convención. Puede otorgar a cada archivo .cpp su propio encabezado precompilado. Esto probablemente sería más fácil de lograr mediante un pequeño script para editar el XML en su .vcproj. A la baja: terminas con una gran pila de encabezados precompilados, y no se comparten entre TU.

posible, pero inteligente? No puedo decirlo con certeza

1

cabeceras pre-compilado se basan en la idea de que todo va a incluir el mismo conjunto de cosas. Si desea utilizar encabezados precompilados, debe vivir con las dependencias que esto implica. Todo se reduce a una compensación de las dependencias frente a la velocidad de compilación. Si puede construir en un tiempo razonable con los encabezados precompilados apagados, hágalo por todos los medios.

Otro aspecto a considerar es que usted puede tener uno PCH por biblioteca. Por lo tanto, es posible que pueda dividir su código en bibliotecas más pequeñas y que cada una de ellas tenga un conjunto más ajustado de dependencias.

0

Los encabezados precompilados pueden ahorrar una gran cantidad de t ime al reconstruir un proyecto, pero si un encabezado precompilado cambia, cada archivo fuente dependiendo del encabezado se volverá a compilar, independientemente de si el cambio lo afecta o no. Afortunadamente, los encabezados precompilados se usan para compilar, no enlace; cada archivo fuente no tiene que usar el mismo mismo encabezado precompilado.

pch1.h:

#include <bigHeader1.h> 
#include ... 


pch1.cpp:

#include "pch1.h" 


source1.cpp:

#include "pch1.h" 
[code] 


pch2.h:

#include <bigHeader2.h> 
#include ... 


pch2.cpp:

#include "pch2.h" 


source2.cpp

#include "pch2.h" 
[code] 

Seleccionar pch1.cpp, clic derecho, Propiedades, Propiedades de configuración, C/C++, encabezados precompilados.
encabezado precompilado: Crear (/ Yc)
encabezado precompilado del archivo: pch1.h
encabezado precompilado archivo de salida: $ (IntDir) pch1.pch

Seleccionar source1.cpp
encabezado precompilado: uso (/ Yu)
encabezado precompilado del archivo: pch1.h
encabezado precompilado archivo de salida: $ (IntDir) pch1.pch (no creo que esto es importante para los/Yu)

Hacer lo mismo para pch2.cpp y source2.CPP, pero coloque el archivo de cabecera y encabezado del archivo de salida a pch2.h y pch2.pch. Funciona para mi.

Cuestiones relacionadas