Каковы преимущества относительного пути, например "../include/header.h" для заголовка?
Я рассмотрел вопросы правильно использовать директиву include и С++ #include semantics, и ни один из адресов это - и другие, предложенные SO, когда я набрал название...
Что, если таковые имеются, являются преимуществами написания:
#include "../include/someheader.h"
#include "../otherdir/another.h"
по сравнению с использованием простого имени файла:
#include "someheader.h"
#include "another.h"
или, возможно, относительное имя без '..
':
#include "include/someheader.h"
#include "otherdir/another.h"
Я вижу следующие проблемы:
- Вы не можете перемещать заголовок, не беспокоясь о том, какие исходные файлы включают его.
- Вы можете получить очень длинные пути для заголовков в зависимостях и отчетах об ошибках. Сегодня у меня был "
../dir1/include/../../include/../dir2/../include/header.h
".
Единственное, что я вижу, это то, что, хотя вам не нужно перемещать файлы, вы можете уйти, не всегда используя директивы "-I
" для поиска заголовков, но потеря гибкости и сложность компиляции в под-подкаталогах и т.д., кажется, перевешивает выгоду.
Итак, я не вижу преимущества?
Спасибо за входные данные. Я думаю, что консенсус в том, что нет никаких существенных преимуществ для нотации, использующей "..", которую я пропускаю. В общем, мне нравится нотация "где-то/header.h"; Я использую его в новых проектах. Тот, над которым я работаю, не что иное, как новый.
Одна из проблем заключается в том, что существуют различные группы заголовков, часто с префиксом, таким как rspqr.h
, rsabc.h
, rsdef.h
, rsxyz.h
. Все они связаны с кодом в каталоге rsmp
, но некоторые заголовки находятся в rsmp
, а другие находятся в центральной директории include, в которой нет подкаталогов, таких как rsmp
. (И повторите для разных других областей кода, есть заголовки в нескольких местах, которые необходимо случайным образом выполнять с помощью других битов кода.) Перемещение материала вокруг является серьезной проблемой, потому что код стал настолько запутанным на протяжении многих лет. И make файлы несовместимы, в которых предусмотрены опции -I
. В целом, это печальная история о не столь благожелательном пренебрежении в течение нескольких десятилетий. Фиксировать все это, не нарушая ничего, будет долгой, утомительной работой.
Ответы
Ответ 1
Я предпочитаю синтаксис пути, так как он очень четко определяет, какое пространство имен или модуль принадлежит файлу заголовка.
#include "Physics/Solver.h"
Очень самоописательно, не требуя, чтобы каждый модуль префикс их имени заголовочным файлам.
Я почти никогда не использую синтаксис "..", хотя вместо этого у меня в моем проекте указаны правильные базовые местоположения.
Ответ 2
Проблема с #include "../include/header.h"
заключается в том, что она часто срабатывает случайно, а затем, казалось бы, не связанное с ней изменение заставит ее перестать работать позже.
Например, рассмотрим следующий макет источника:
./include/header.h
./lib/library.c
./lib/feature/feature.c
И скажем, что вы используете компилятор с пуском include -I. -I./lib
. Что происходит?
-
./lib/library.c
может сделать #include "../include/header.h"
, что имеет смысл.
-
./lib/feature/feature.c
также может выполнять #include "../include/header.h"
, хотя это не имеет смысла. Это связано с тем, что компилятор попытается установить директиву #include
относительно местоположения текущего файла, и если это не удастся, он попытается установить директиву #include
относительно каждой записи -I
в пути #include
.
Кроме того, если вы позже удалите -I./lib
из пути #include
, вы разломете ./lib/feature/feature.c
.
Я считаю предпочтительным следующее:
./projectname/include/header.h
./projectname/lib/library.c
./projectname/lib/feature/feature.c
Я бы не добавлял никаких добавленных записей пути, кроме -I.
, а затем library.c
и feature.c
использовал бы #include "projectname/include/header.h"
. Предполагая, что "имя проекта", вероятно, будет уникальным, это не должно приводить к столкновениям имен или неоднозначностям в большинстве случаев. Вы также можете использовать путь include и/или сделать функцию VPATH
, чтобы разделить физический макет проекта на несколько каталогов, если это абсолютно необходимо (например, для размещения специально созданного для конкретной платформы кода - это то, что действительно ломается, когда вы используйте #include "../../somefile.h"
).
Ответ 3
IANALL, но я не думаю, что вы должны размещать ..
в реальных исходных файлах C или С++, потому что это не портативный, а стандарт не поддерживает его. Это похоже на использование \
в Windows. Делайте это только в том случае, если ваш компилятор не может работать с каким-либо другим способом.
Ответ 4
Подумайте о своем исходном дереве как вложенном пространстве имен, а путь include - вывести каталоги в корень этого пространства имен. Тогда возникает вопрос о создании логического пространства имен для вашей базы кода независимо от того, как код организован на диске.
Я бы избегал таких путей, как:
-
"include/foo/bar.h"
- "include" кажется нелогичным и избыточным
-
"../foo/bar.h"
- ".." предполагает относительное местоположение и хрупкое.
-
"bar.h"
- если bar.h не находится в текущем каталоге, это загрязняет глобальное пространство имен и запрашивает неоднозначность.
Лично я склоняюсь к тому, что в мои проекты добавляется следующий путь: path - "..;../..;../../..;../../../.."
.
Это позволяет применить какое-то правило скрытия к вашему #include
и разрешить некоторую свободу перемещения заголовков без нарушения другого кода. Конечно, это за счет введения риска привязки к неправильному заголовочному файлу, если вы не будете осторожны, так как не полностью квалифицированные имена могут (или становятся со временем) неоднозначными.
Я склонен полностью квалифицировать #include
в публичных заголовках, поэтому третьим лицам, покупающим мой код, не нужно добавлять "..;../..;../../..;../../../.."
к их проекту - это просто удобство для моего личного кода и системы сборки.
Ответ 5
Потому что тогда вы помещаете файл относительно корня проекта, и когда вы проверяете его на исходный элемент управления, а другой разработчик проверяет его в другом месте на своей локальной системе, все еще работает.
Ответ 6
Еще одна проблема с окнами с относительными путями - MAX_PATH. Это вызовет проблемы компиляции, когда, например, кросс-компиляция для android, и ваш путь увеличивается больше 260.