2009-07-21 5 views
7

En mi lugar tenemos una gran base de código C++ y creo que hay un problema con la forma en que se usan los archivos de encabezado.Dependencias de los archivos de encabezado entre los módulos de C++

Hay muchos proyectos de Visual Studio, pero el problema está en el concepto y no está relacionado con VS. Cada proyecto es un módulo, que realiza una funcionalidad particular. Cada proyecto/módulo está compilado para biblioteca o binario. Cada proyecto tiene un directorio que contiene todos los archivos fuente - * .cpp y * .h. Algunos archivos de encabezado son API del módulo (me refiero al subconjunto de archivos de encabezado que declaran la API de la biblioteca creada), algunos son internos.

Ahora al problema: cuando el módulo A necesita trabajar con el módulo B, A agrega el directorio de origen de B para incluir la ruta de búsqueda. Por lo tanto, todos los encabezados internos del módulo B son vistos por A en el tiempo de compilación.

Como efecto secundario, el desarrollador no está obligado a concentrar cuál es la API exacta de cada módulo, lo que considero un mal hábito de todos modos.

Considero una opción de cómo debería ser en primer lugar. Pensé en crear en cada proyecto un directorio dedicado que solo contenga archivos de encabezado de interfaz. Un módulo de cliente que desee utilizar el módulo puede incluir solo el directorio de interfaz.

¿Este enfoque está bien? ¿Cómo se resuelve el problema en tu lugar?

UPD En mi lugar anterior, el desarrollo se realizó en Linux con g ++/gmake y, de hecho, utilizamos para instalar archivos de cabecera de API en un directorio común es algunas de las respuestas propuestas. Ahora tenemos el proyecto de Windows (Visual Studio)/Linux (g ++) usando cmake para generar archivos de proyecto. ¿Cómo fuerzo la instalación preconstruida de archivos de encabezado API en Visual Studio?

Gracias Dmitry

Respuesta

3

Parece que su en el camino correcto. Muchas bibliotecas de terceros hacen este mismo tipo de cosas. Por ejemplo:

3RDPARTY/MYLIB/src/                                 : contiene los encabezados y archivos de origen necesarios para compilar la biblioteca
3RDPARTY/MYLIB/include/myLib/    - contiene los encabezados necesarios para aplicaciones externas que incluyen

Algunas personas/proyectos simplemente colocan los encabezados para ser incluidos por aplicaciones externas en/3rdParty/myLib/include, pero agregar el directorio myLib adicional puede ayudar a evitar colisiones de nombres.

Asumiendo que su uso de la estructura: 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

¿No sería más intuitivo para poner las cabeceras de interfaz en la raíz del proyecto, y hacer una subcarpeta (llamada es 'interno' o 'ayudante' o algo así) para los encabezados que no son API?

+0

Creo que Google coloca todos sus encabezados internos en una carpeta llamada interna. – xian

0

He visto problemas como este tratados al tener un conjunto de encabezados en el módulo B que se copian en el directorio de versiones junto con la lib como parte del proceso de compilación. El Módulo A solo ve esos encabezados y nunca tiene acceso a las partes internas de B.Por lo general, solo he visto esto en un gran proyecto que se publicó públicamente.

Para proyectos internos simplemente no sucede. Lo que generalmente sucede es que cuando son pequeños no importa. Y cuando crezcan es tan complicado separarlo que nadie quiere hacerlo.

0

Normalmente veo un directorio de inclusión en el que se apilan todos los encabezados de interfaz. Ciertamente hace que sea fácil incluir encabezados. La gente todavía tiene que pensar en qué módulos están tomando dependencias cuando especifican los módulos para el vinculador.

Dicho esto, me gusta un poco su acercamiento. Incluso podría evitar agregar estos directorios a la ruta de inclusión, de modo que las personas puedan decir de qué módulos depende un archivo fuente solo por las rutas relativas en los #includes en la parte superior.

Dependiendo de cómo se diseñe su proyecto, esto puede ser problemático al incluirlos desde los encabezados, ya que la ruta relativa a un encabezado es del archivo .cpp, no del archivo .h, por lo que el .h archivo no necesariamente sabe dónde están sus archivos .cpp.

Si sus proyectos tienen una jerarquía plana, sin embargo, esto funcionará. Digamos que tiene

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

Ahora, cualquier archivo de cabecera puede incluir
#include "..\baz\inc\baz.h
y funcionará ya que todos los archivos cpp son un nivel más profundo que el de base.

2

Donde trabajo tenemos una estructura de carpeta de entrega creada en tiempo de compilación. Los archivos de encabezado que definen las bibliotecas se copian en una carpeta de inclusión. Usamos scripts de compilación personalizados que permiten al desarrollador denotar qué archivos de encabezado deben exportarse.

Nuestra compilación se inicia en una unidad de disco subst, lo que nos permite usar rutas absolutas para incluir directorios.

También tenemos una construcción de referencia basada en red que nos permite utilizar una unidad mapeada para las referencias de inclusión y lib.

ACTUALIZACIÓN: Nuestra construcción de referencia es un recurso compartido de red en nuestro servidor de compilación. Utilizamos una secuencia de comandos de compilación de referencia que configura el entorno de compilación y los mapas (utilizando net use) el recurso compartido con nombre en el servidor de compilación (es decir, \ BLD_SRV \ REFERENCE_BUILD_SHARE). Luego, durante una compilación semanal (o manual) establecemos el recurso compartido (usando net share) para apuntar a la nueva compilación.

Nuestros proyectos presentan una lista de rutas absolutas para las referencias include y lib.

Por ejemplo:

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 

Esto le llevará cambios locales en primer lugar, a continuación, si no se ha realizado ningún cambio locales (o al menos no los han incorporado) que utilizará los encabezados y bibliotecas de la última construcción en el servidor de compilación.

+0

¿Puede explicarnos qué es una construcción de referencia basada en red? – dimba

0

En un grupo que había estado trabajando, todo público se mantuvo en una carpeta específica del módulo, mientras que cosas privadas (cabecera privada, etc. cpp) se mantuvieron en una carpeta dentro de esta _imp:

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

De esta manera podría simplemente buscar dentro de la estructura de su carpeta de proyectos y obtener el encabezado que desea.Puede grep para las directivas #include que contienen _imp y echarles un buen vistazo. También puede tomar toda la carpeta, copiarla en algún lugar y eliminar todas las subcarpetas _imp, sabiendo que tendrá todo listo para lanzar una API. Dentro cabeceras proyectos en los que por lo general incluye como

#include "foo/foo.h" 

Sin embargo, si el proyecto tuvo que utilizar un poco de API, a continuación, las cabeceras API se pueden copiar/instalado por la acumulación de la API dondequiera que se supone que debe ir en esa plataforma por la acumulación sistema y luego instalarse como encabezados del sistema:

#include <foo/foo.h> 
Cuestiones relacionadas