Enforcing inclusione manuale di un file di intestazione specifico (banned.h)

5

Banned.h è una lista di funzioni ANSI C che Microsoft sta cercando di convincere i programmatori a deprecare. So già come applicare l'inclusione automatica di banned.h (come la risposta a Garantire che le intestazioni siano esplicitamente incluse nel file CPP ). Sfortunatamente, questa risposta ha un importante svantaggio.

L'inclusione forzata nelle impostazioni del progetto include sempre l'intestazione forzata prima . Sfortunatamente, la maggior parte dei file di intestazione di sistema di Microsoft non sono banned.h compliant e molte intestazioni di librerie di terze parti non sono nemmeno banned.h compliant. Microsoft afferma che il loro utilizzo delle API bannate è sicuro e non ha intenzione di cambiare questa situazione. Il modo principale per utilizzare le intestazioni di sistema, quindi, è includerle prima di banned.h.

Un modo per risolverlo è creare una sorta di meta_banned.h, che include tutti i possibili header di sistema che sono usati ovunque nel tuo progetto, così come tutte le intestazioni di tutte le librerie di terze parti non conformi, prima di incluso il regolare banned.h. Questa è la prima cosa che ho fatto, ma causa una sfortuna per compilare il tempo perché alcune delle librerie di terze parti hanno intestazioni estese.

Abbiamo finito con un approccio ibrido - il meta_banned.h include le intestazioni di sistema alcuni e quindi le impostazioni del progetto per determinati file CPP eccezionali includono le intestazioni di terze parti come parte della forza- includere le impostazioni su quel particolare file. Funziona, ma è brutto e doloroso da mantenere. Il file per CPP forzato include in particolare sembra brutto.

Quello che voglio veramente è un metodo per garantire che banned.h sia incluso da qualche parte in ogni file, non necessariamente nella parte superiore. Finché è incluso in qualche punto, considero il file compatibile. Se non è incluso, voglio generare un errore di compilazione. Qualche suggerimento?

    
posta AHelps 06.12.2014 - 00:27
fonte

3 risposte

3

Dopo un lungo dibattito, abbiamo trovato un metodo che ci piace, ma ha comportato altre modifiche sostanziali al progetto. Abbiamo attivato le intestazioni precompilate . All'interno dell'intestazione precompilata, prima includiamo tutte le intestazioni di sistema (e altre intestazioni di libreria di terze parti) che non sono conformi a banned.h, e quindi includiamo banned.h.

Questo ha molte proprietà che ci interessano:

  1. Non rallenta la build, anche se sono incluse intestazioni raramente utilizzate. In realtà, una build completa richiede meno della metà del tempo che aveva prima, perché le intestazioni precompilate sono un'ottimizzazione.
  2. Non puoi inavvertitamente lasciare fuori banned.h, perché il compilatore impone l'inclusione dell'intestazione precompilata . Le intestazioni precompilate sono un'impostazione dell'intero progetto in Visual Studio e i singoli file devono essere esplicitamente disattivati se non desiderano utilizzarli. Quindi banned.h viene applicato in modo pulito ovunque.
  3. Possiamo forzare-includere l'intestazione precompilata per evitare di cambiare ogni file sorgente, oppure possiamo aggiungerlo all'inizio di ogni file sorgente. Questo ha fornito un bel percorso di migrazione. Tutte le nostre regole di eccezione per determinati file sorgente sono andate via.
  4. Tutti i compilatori di cui ci occupiamo (GNU C ++, clang, Visual C ++) supportano le intestazioni precompilate e il supporto è abbastanza simile da non richiedere #ifdefs o hack simili.

C'è uno svantaggio che ci ha catturato: se nel progetto sono stati combinati file sorgente C ++ e C, sarà necessario disporre di file banned.h separati per loro. Non è possibile utilizzare lo stesso file PCH per entrambe le lingue. Poiché tutta la nostra sorgente C proveniva da una libreria di terze parti, abbiamo deciso di creare un file lib separato per esso e collegarlo a valle, che ha risolto il problema. Ora non richiediamo impostazioni di progetto personalizzate per i singoli file sorgente, il progetto viene compilato rapidamente e stiamo implementando completamente banned.h.

    
risposta data 07.02.2015 - 20:35
fonte
5

Ok, non lo farei mai in un milione di anni, ma potresti fare qualcosa del genere:

Forza l'inclusione automatica di questo:

// forcebanned.h
#define for "You must include banned.h"

Quindi aggiungi questo:

// mybanned.h
#undef for
#include banned.h

Ma non farlo. Meglio è rendere l'inclusione di banned.h uno standard di codifica e affidarsi alle revisioni del codice per catturarlo.

Se sei davvero insistente nell'applicare tecnicamente questo, potresti avere una fase di compilazione personalizzata che grep'd file per "banned.h" prima della compilazione, fallendo la compilazione se la linea non viene trovata. (Oppure usa uno strumento di analisi statica che tagga le funzioni deprecate.) Facendo così parte della build mantieni il tuo codice più semplice e più portabile.

    
risposta data 06.12.2014 - 05:59
fonte
0

Potresti, invece di usare banned.h, scrivere un programma di analisi Clang che analizzi il tuo codice sorgente. Puoi usarlo per far rispettare le regole di codifica o le linee guida che ti piacciono, non solo il divieto di un set specifico di funzioni C, e puoi anche interrogare la posizione di origine di ogni dato codice e implementare regole specifiche per la posizione.

    
risposta data 07.02.2015 - 22:00
fonte