2009-07-21 17 views
7

Al mio posto abbiamo una grande base di codice C++ e penso che ci sia un problema con i file di intestazione.Dipendenze dei file di intestazione tra i moduli C++

Ci sono molti progetti di Visual Studio, ma il problema è nel concetto e non è correlato a VS. Ogni progetto è un modulo, che esegue funzionalità particolari. Ogni progetto/modulo è compilato in libreria o binario. Ogni progetto ha una directory contenente tutti i file sorgente - * .cpp e * .h. Alcuni file header sono API del modulo (intendo il sottoinsieme di file header che dichiarano API della libreria creata), alcuni sono interni ad esso.

Ora al problema: quando il modulo A deve lavorare con il modulo B, allora A aggiunge la directory sorgente di B per includere il percorso di ricerca. Pertanto tutte le intestazioni interne del modulo B vengono visualizzate da A al momento della compilazione.

Come effetto collaterale, lo sviluppatore non è costretto a concentrarsi su quale sia l'esatta API di ciascun modulo, che comunque considero una cattiva abitudine.

Considero un'opzione come dovrebbe essere al primo posto. Ho pensato di creare in ogni progetto una directory dedicata contenente solo i file di intestazione dell'interfaccia. Un modulo client che desidera utilizzare il modulo può includere solo la directory dell'interfaccia.

Questo approccio è corretto? Come si risolve il problema al posto tuo?

UPD Sul mio posto precedente, lo sviluppo è stato fatto su Linux con g ++/gmake e abbiamo davvero usato per installare i file di intestazione API in una directory comune è alcune risposte propongono. Ora abbiamo il progetto Windows (Visual Studio)/Linux (g ++) che usa cmake per generare file di progetto. Come impongo l'installazione di pre-installazione dei file di intestazione API in Visual Studio?

Grazie Dmitry

risposta

3

Sembra che il tuo sulla strada giusta. Molte librerie di terze parti fanno lo stesso genere di cose. Per esempio:

3rdParty/myLib/src/                                  -contains le intestazioni e file di origine necessari per compilare la libreria
3rdParty/myLib/include/myLib/    - contiene le intestazioni necessarie per le applicazioni esterne per includere

Alcune persone/progetti inseriscono semplicemente le intestazioni da includere nelle app esterne in/3rdParty/myLib/include, ma l'aggiunta della directory myLib aggiuntiva può aiutare a evitare conflitti di nome.

Assumendo che il utilizzando la struttura: 3rdParty/myLib/include/myLib/

 

In Makefile of external app: 
--------------- 
INCLUDE =-I$(3RD_PARTY_PATH)/myLib/include 
INCLUDE+=-I$(3RD_PARTY_PATH)/myLib2/include 
... 
... 

In Source/Headers of the external app 
#include "myLib/base.h" 
#include "myLib/object.h" 

#include "myLib2/base.h" 
2

Non sarebbe più intuitivo per mettere le intestazioni di interfaccia nella root del progetto, e fare una sottocartella (chiamata è 'interno' o 'helper' o qualcosa del genere) per le intestazioni non API?

+0

Credo che Google inserisce tutte le intestazioni interne in una cartella denominata interna. – xian

0

Ho visto problemi come questo indirizzati da un set di intestazioni nel modulo B che viene copiato nella directory di rilascio insieme alla lib come parte del processo di compilazione. Il modulo A quindi vede solo quelle intestazioni e non ha mai accesso agli interni di B.Di solito ho visto solo questo in un grande progetto che è stato rilasciato pubblicamente.

Per i progetti interni non succede. Quello che succede di solito è che quando sono piccoli non importa. E quando crescono è così disordinato da separarlo, nessuno vuole farlo.

0

In genere vedo solo una directory di inclusione su cui vengono inserite tutte le intestazioni dell'interfaccia. Certamente rende facile includere intestazioni. Le persone devono ancora riflettere su quali moduli assumono dipendenze quando specificano i moduli per il linker.

Detto questo, mi piace il tuo approccio migliore. Potresti anche evitare di aggiungere queste directory al percorso di inclusione, in modo che le persone possano capire quali moduli un file sorgente dipende solo dai relativi percorsi nella #include in alto.

A seconda di come è strutturato il progetto, questo può essere problematico quando li si include dalle intestazioni, tuttavia, poiché il percorso relativo a un'intestazione proviene dal file .cpp, non dal file .h, quindi .h il file non sa necessariamente dove sono i suoi file .cpp.

Se i progetti hanno una gerarchia piatta, tuttavia, funzionerà. Diciamo che avete

base\foo\foo.cpp 
base\bar\bar.cpp 
base\baz\baz.cpp 
base\baz\inc\baz.h 

Ora, qualsiasi file di intestazione può includere
#include "..\baz\inc\baz.h
e funzionerà poiché tutti i file cpp sono di un livello più profondo di base.

2

Dove lavoro abbiamo una struttura di cartelle di consegna creata al momento della compilazione. I file di intestazione che definiscono le librerie vengono copiati in una cartella di inclusione. Utilizziamo script di compilazione personalizzati che consentono allo sviluppatore di indicare quali file di intestazione devono essere esportati.

La nostra build è quindi rootata su un'unità subst e questo ci consente di utilizzare percorsi assoluti per includere le directory.

Abbiamo anche una build di riferimento basata sulla rete che ci consente di utilizzare un'unità mappata per i riferimenti include e lib.

AGGIORNAMENTO: la nostra build di riferimento è una condivisione di rete sul nostro server di build. Usiamo uno script di build di riferimento che imposta l'ambiente di compilazione e le mappe (utilizzando net use) la condivisione denominata sul server di build (ad es. \ BLD_SRV \ REFERENCE_BUILD_SHARE). Quindi durante una build settimanale (o manualmente) impostiamo la condivisione (usando net share) per puntare alla nuova build.

I nostri progetti quindi un elenco di percorsi assoluti per i riferimenti include e lib.

Ad esempio:

subst'ed local build drive j:\ 
mapped drive to reference build: p:\ 
path to headers: root:\build\headers 
path to libs: root:\build\release\lib 
include path in project settings j:\build\headers; p:\build\headers 
lib path in project settings  j:\build\release\lib;p:\build\release\lib 

Questo vi porterà modifiche locali, poi se non sono state apportate modifiche locali (o almeno non li avete costruito) userà le intestazioni e le librerie da l'ultima build sul server di build.

+0

Puoi spiegare cos'è la creazione di riferimento basata sulla rete? – dimba

0

In un gruppo avevo lavorato, tutto pubblico è stato tenuto in una cartella specifica del modulo, mentre cose private (intestazione privato, il file cpp etc.) sono stati tenuti in una cartella all'interno di questa _imp:

base\foo\foo.h 
base\foo\_imp\foo_private.h 
base\foo\_imp\foo.cpp 

In questo modo è possibile aggrapparsi alla struttura della cartella dei progetti e ottenere l'intestazione desiderata.# Puoi includere le direttive #include che contengono _imp e guardarle bene. Puoi anche prendere l'intera cartella, copiarla da qualche parte ed eliminare tutte le sottocartelle _imp, sapendo che avresti tutto pronto per rilasciare un'API. all'interno di progetti intestazioni dove solitamente incluso come

#include "foo/foo.h" 

Tuttavia, se il progetto ha dovuto usare alcune API, quindi le intestazioni API sarebbero copiati/installato da accumulo del API ovunque dovevamo andare su quella piattaforma per la costruzione sistema e quindi essere installato come intestazioni di sistema:

#include <foo/foo.h> 
Problemi correlati