Зависимости заголовочных файлов между модулями C ++ - PullRequest
7 голосов
/ 21 июля 2009

У меня есть большая база кода на C ++, и я думаю, что есть проблема с использованием заголовочных файлов.

Существует множество проектов Visual Studio, но проблема в концепции и не связана с VS. Каждый проект представляет собой модуль, выполняющий определенные функции. Каждый проект / модуль компилируется в библиотеку или двоичный файл. Каждый проект имеет каталог, содержащий все исходные файлы - * .cpp и * .h. Некоторые заголовочные файлы являются API модуля (я имею в виду подмножество заголовочных файлов, объявляющих API созданной библиотеки), некоторые являются внутренними для него.

Теперь к проблеме - когда модулю A нужно работать с модулем B, A добавляет исходный каталог B, чтобы включить путь поиска. Поэтому все внутренние заголовки модуля B видны A во время компиляции.

Как побочный эффект, разработчик не обязан концентрировать внимание на точном API каждого модуля, что я считаю вредной привычкой.

Я рассматриваю варианты, как это должно быть на первом месте. Я думал о создании в каждый проект выделенный каталог, содержащий только заголовочные файлы интерфейса. Клиентский модуль, желающий использовать модуль, может включать только интерфейсный каталог.

Этот подход в порядке? Как решается проблема у вас?

UPD На моем предыдущем месте разработка была сделана для Linux с использованием g ++ / gmake, и мы действительно использовали для установки заголовочных файлов API в общий каталог, как предлагают некоторые ответы. Теперь у нас есть проект Windows (Visual Studio) / Linux (g ++), использующий cmake для генерации файлов проекта. Как принудительно выполнить предварительную сборку заголовочных файлов API в Visual Studio?

Спасибо Дмитрий

Ответы [ 6 ]

3 голосов
/ 21 июля 2009

Звучит так, как будто вы на правильном пути. Многие сторонние библиотеки делают то же самое. Например:

3rdParty / myLib / src / - содержит заголовки и исходные файлы, необходимые для компиляции библиотеки
3rdParty / myLib / include / myLib / - содержит заголовки, необходимые для включения внешними приложениями

Некоторые люди / проекты просто помещают заголовки для включения внешних приложений в / 3rdParty / myLib / include, но добавление дополнительного каталога myLib может помочь избежать конфликтов имен

Предполагается, что вы используете структуру: 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 голосов
/ 21 июля 2009

Где я работаю, у нас есть структура папок доставки, созданная во время сборки. Заголовочные файлы, которые определяют библиотеки, копируются во включаемую папку. Мы используем пользовательские сценарии сборки, которые позволяют разработчику указывать, какие заголовочные файлы следует экспортировать.

Наша сборка затем основана на диске subst ed, что позволяет нам использовать абсолютные пути для включаемых каталогов.

У нас также есть сетевая эталонная сборка, которая позволяет нам использовать подключенный диск для ссылок include и lib.

ОБНОВЛЕНИЕ: Нашей эталонной сборкой является сетевой ресурс на нашем сервере сборки. Мы используем эталонный скрипт сборки, который устанавливает среду сборки и сопоставляет (используя net use ) именованный общий ресурс на сервере сборки (т.е. \ BLD_SRV \ REFERENCE_BUILD_SHARE). Затем во время еженедельной сборки (или вручную) мы устанавливаем общий ресурс (используя net share ), чтобы он указывал на новую сборку.

В наших проектах приведен список абсолютных путей для ссылок include и lib.

Например:

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

Сначала вам потребуются локальные изменения, затем, если вы не сделали никаких локальных изменений (или, по крайней мере, не создали их), он будет использовать заголовки и библиотеки из вашей последней сборки на сервере сборки.

2 голосов
/ 21 июля 2009

Разве не было бы более интуитивно понятно поместить заголовки интерфейса в корень проекта и создать подпапку (назовите ее «внутренняя» или «вспомогательная» или что-то в этом роде) для заголовков не-API?

0 голосов
/ 21 июля 2009

В группе, в которой я работал, все общедоступное хранилище находилось в папке, специфичной для модуля, тогда как личное содержимое (частный заголовок, файл cpp и т. Д.) Хранилось в папке _imp в этой папке:

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

Таким образом, вы можете просто найти структуру папок вашего проекта и получить нужный заголовок. Вы можете использовать директивы #include, содержащие _imp, и посмотреть на них. Вы также можете захватить всю папку, скопировать ее куда-нибудь и удалить все подпапки _imp, зная, что у вас все готово для выпуска API. Заголовки проектов обычно включаются как

#include "foo/foo.h"

Однако, если в проекте должен был использоваться какой-то API, тогда заголовки API будут копироваться / устанавливаться сборкой API, куда бы они ни направлялись на этой платформе системой сборки, а затем устанавливаться как системные заголовки:

#include <foo/foo.h>
0 голосов
/ 21 июля 2009

Как правило, я просто вижу каталог include, в который накапливаются все заголовки интерфейса. Это, безусловно, позволяет легко включать заголовки. Люди все еще должны думать о том, от каких модулей они зависят, когда задают модули для компоновщика.

Тем не менее, мне больше нравится ваш подход. Вы могли бы даже избежать добавления этих каталогов в путь включения, чтобы люди могли определить, от каких модулей зависит исходный файл, только по относительным путям в #include вверху.

В зависимости от структуры вашего проекта, это может быть проблематично при включении их из заголовков, так как относительный путь к заголовку берется из файла .cpp, а не из файла .h, поэтому файл .h не обязательно знает, где его .cpp файлы.

Однако, если ваши проекты имеют плоскую иерархию, это будет работать. Скажем, у вас есть

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

Теперь любой заголовочный файл может включать
#include "..\baz\inc\baz.h
и это будет работать, поскольку все файлы cpp на один уровень глубже, чем база.

0 голосов
/ 21 июля 2009

Я видел проблемы, подобные этой, с помощью набора заголовков в модуле B, которые копируются в каталог выпуска вместе с библиотекой lib как часть процесса сборки. Тогда модуль A видит только эти заголовки и никогда не имеет доступа к внутренним частям B. Обычно я видел это только в большом проекте, который был опубликован публично.

Для внутренних проектов это просто не происходит. Обычно бывает, что когда они маленькие, это не имеет значения. И когда они вырастают, это так грязно, чтобы отделить это, никто не хочет делать это.

...