Domanda

Ho un sacco di codice legacy per il quale devo scrivere test unitari. Utilizza intestazioni precompilate ovunque, quindi quasi tutti i file .cpp dipendono da stdafx.h, il che rende difficile interrompere le dipendenze per scrivere i test.

Il mio primo istinto è quello di rimuovere tutti questi file stdafx.h che, per la maggior parte, contengono direttive #include e inseriscono tali #include direttamente nei file di origine, se necessario.

Ciò renderebbe necessario disattivare le intestazioni precompilate poiché dipendono dalla presenza di un file come stdafx.h per determinare dove si fermano le intestazioni precompilate.

Esiste un modo per mantenere le intestazioni precompilate senza le dipendenze stdafx.h? Esiste un modo migliore per affrontare questo problema?

È stato utile?

Soluzione

Sì, c'è un modo migliore.

Il problema, IMHO, con lo "stile di procedura guidata" delle intestazioni precompilate è che incoraggiano l'accoppiamento non richiesto e rendono il riutilizzo del codice più difficile di quanto dovrebbe essere. Inoltre, il codice che è stato scritto con lo stile 'just stick Everything in stdafx.h' è incline a essere un problema da mantenere poiché la modifica di qualsiasi cosa in qualsiasi file di intestazione può causare la ricompilazione dell'intera base di codice ogni volta. Ciò può rendere semplice il refactoring per sempre, poiché ogni ciclo di modifica e ricompilazione richiede molto più tempo di quanto dovrebbe.

Un modo migliore, sempre IMHO, è usare #pragma hdrstop e / Yc e / Yu. Ciò consente di impostare facilmente configurazioni di build che utilizzano intestazioni precompilate e di creare configurazioni che non utilizzano intestazioni precompilate. I file che utilizzano intestazioni precompilate non hanno una dipendenza diretta dall'intestazione precompilata stessa nel file di origine che consente di crearli con o senza l'intestazione precompilata. Il file di progetto determina quale file sorgente genera l'intestazione precompilata e la riga #pragma hdrstop in ciascun file sorgente determina quali inclusioni sono prese dall'intestazione precompilata (se utilizzata) e quali sono prese direttamente dal file sorgente ... Ciò significa che quando facendo manutenzione useresti la configurazione che non usa le intestazioni precompilate e verrà ricostruito solo il codice che devi ricostruire dopo una modifica del file di intestazione. Quando si eseguono build complete, è possibile utilizzare le configurazioni di intestazione precompilate per accelerare il processo di compilazione. Un'altra cosa positiva dell'avere l'opzione di compilazione dell'intestazione non precompilata è che si assicura che i file cpp includano solo ciò di cui hanno bisogno e includano tutto ciò di cui hanno bisogno (qualcosa di difficile se si utilizza lo "stile di procedura guidata" dell'intestazione precompilata.

Ho scritto un po 'su come funziona qui: http://www.lenholgate.com/blog/2004/07/fi-stlport-precompiled-headers-warning-level-4-and-pragma-hdrstop. html (ignora le cose su / FI) e ho alcuni progetti di esempio che si basano sul metodo #pragma hdrstop e / Yc / Yu qui: http://www.lenholgate.com/blog/2008/04/practical-testing-16 --- fixing-a-timeout-bug.html .

Ovviamente, passare dall'utilizzo dell'intestazione precompilata "stile mago" a uno stile più controllato è spesso non banale ...

Altri suggerimenti

Quando usi normalmente le intestazioni precompilate, " stdafx.h " serve 2 scopi. Definisce un insieme di file include comuni e stabili. Inoltre, in ogni file .cpp, funge da marcatore come dove finiscono le intestazioni precompilate.

Sembra che quello che vuoi fare sia:

  • Lascia attivata l'intestazione precompilata.
  • Lascia " stdafx.h " includere in ogni file .cpp.
  • Svuota le inclusioni da " stdafx.h " ;.
  • Per ogni file .cpp, capire quali inclusioni erano necessarie dal vecchio "stdafx.h". Aggiungi questi prima di #include " stdafx.h " in ogni file .cpp.

Quindi ora hai un set minimo di dipendenze e stai ancora usando le intestazioni precompilate. La perdita è che non stai precompilando il tuo set comune di intestazioni solo una volta. Questo sarebbe un grande successo per una ricostruzione completa. Per la modalità di sviluppo, in cui stai ricompilando solo pochi file alla volta, sarebbe meno efficace.

No, probabilmente c'è NON un modo migliore.

Tuttavia, per un determinato file .cpp individuale, potresti decidere di non aver bisogno dell'intestazione precompilata. È possibile modificare le impostazioni per quel file .cpp e rimuovere la riga stdafx.h.

(In realtà, però, non so come lo schema di intestazione precompilato stia interferendo con la scrittura dei test delle tue unità).

No. le intestazioni precompilate si basano su una singola intestazione inclusa da tutte le fonti compilate in questo modo. puoi specificare per una singola fonte (o tutte) di non usare affatto le intestazioni precompilate, ma non è quello che vuoi.

In passato, il compilatore Borland C ++ eseguiva la pre-compilazione senza un'intestazione specifica. tuttavia, se due file sorgente includevano le stesse intestazioni ma in ordine diverso, venivano compilati separatamente, poiché, in effetti, l'ordine dei file di intestazione in C ++ può importare ...

Quindi significa che le intestazioni precompilate di Borland hanno risparmiato tempo solo se hai inserito in modo molto rigido le fonti nello stesso ordine, o se un singolo file include incluso (primo) da tutti gli altri file ... - sembra familiare ?! ?!

Sì. "Stdafx.h / stdafx.pch" il nome è solo convenzione. Puoi dare a ogni .cpp la sua intestazione precompilata. Questo sarebbe probabilmente più facile da ottenere con un piccolo script per modificare l'XML nel tuo .vcproj. Unico inconveniente: si finisce con una grande pila di intestazioni precompilate e non sono condivise tra le TU.

Possibile, ma intelligente? Non posso dirlo con certezza.

Il mio consiglio è: non rimuovere le intestazioni precompilate a meno che non si desideri rallentare dolorosamente le build. Fondamentalmente hai tre opzioni qui:

  1. Elimina le intestazioni precompilate (non raccomandato)
  2. Crea una libreria separata per il codice legacy; in questo modo puoi costruirlo separatamente.
  3. Utilizza più intestazioni precompilate all'interno di un singolo progetto. È possibile selezionare singoli file C ++ in Esplora soluzioni e indicare quale intestazione precomilata utilizzare. Dovresti anche configurare OtherStdAfx.h / cpp per generare un'intestazione precompilata.

Le intestazioni precompilate sono basate sull'idea che tutto includerà lo stesso set di cose. Se si desidera utilizzare le intestazioni precompilate, è necessario convivere con le dipendenze che ciò implica. Si tratta di un compromesso tra dipendenze e velocità di costruzione. Se riesci a costruire in un tempo ragionevole con le intestazioni precompilate disattivate, allora fallo.

Un'altra cosa da considerare è che puoi avere un pch per libreria. Quindi potresti essere in grado di dividere il tuo codice in librerie più piccole e avere ciascuna di esse una serie più stretta di dipendenze.

Uso solo le intestazioni precompilate per il codice che deve includere la roba afx___ - di solito solo l'interfaccia utente, che non testo l'unità. Il codice dell'interfaccia utente gestisce l'interfaccia utente e chiama le funzioni che dispongono di test unitari (sebbene la maggior parte non lo faccia attualmente perché l'app è legacy).

Per la maggior parte del codice non uso intestazioni precompilate.

G.

Le intestazioni precompilate possono risparmiare molto tempo durante la ricostruzione di un progetto, ma se un'intestazione precompilata cambia, ogni il file di origine a seconda dell'intestazione verrà ricompilato, indipendentemente dal fatto che la modifica influisca o meno. Fortunatamente, le intestazioni precompilate vengono utilizzate per compilare , non per link ; ogni file sorgente non deve utilizzare la stessa intestazione precompilata.

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]

Seleziona pch1.cpp , fai clic con il pulsante destro del mouse, Proprietà, Proprietà di configurazione, C / C ++, Intestazioni precompilate .
Intestazione precompilata: Crea (/ Yc)
File di intestazione precompilato: pch1.h
File di output dell'intestazione precompilato : $ (intDir) pch1.pch

Seleziona source1.cpp
Intestazione precompilata: usa (/ Yu)
File di intestazione precompilato: pch1.h
File di output delle intestazioni precompilato : $ (intDir) pch1.pch (non credo che questo sia importante per / Yu)

Fai la stessa cosa per pch2.cpp e source2.cpp , tranne per impostare File di intestazione e File di output dell'intestazione in pch2.h e pch2.pch . Questo funziona per me.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top