Можно ли при компиляции указать путь к файлу #include относительно текущего каталога пользователя?


Я знаю, что можно указать путь к файлу #include либо относительно каталога, в котором находится файл, как абсолютный путь к файлу, либо относительно любого из каталогов в системной переменной $PATH. Есть ли способ вместо этого указать его относительно текущего каталога пользователя, когда программа компилируется? Допустим, у меня есть следующая файловая структура:

|--dir_a/
|  |--a.c
|  |--a.h
|--dir_b/
|  |--b.c
|  |--b.h
|--makefile
Теперь предположим, что я хочу #include файл dir_a/a.h из dir_b/b.h. Используя расположение dir_b/b.h, это можно записать так: это:
#include ../dir_a/a.h
Однако, на мой взгляд, у этого подхода есть серьезный недостаток, поскольку он жестко кодирует расположение файлов относительно друг друга, что означает, что перемещение файла потребует обновления пути к файлу везде, где этот файл был включен.

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

Наконец, используя теги <> для указания пути к файлу это также неосуществимо, поскольку я не могу предположить, что проект будет перечислен в переменной $PATH.

Поэтому я хочу иметь возможность указать пути относительно того, откуда пользователь компилирует (или, еще лучше, из расположения файла makefile). В приведенном выше примере это позволило бы мне использовать следующее утверждение для #include dir_a/a.h из dir_b/b.h:

#include dir_a/a.h
Я думаю, что это было бы идеальным решением. Это сделало бы утверждения #include более последовательными и более простыми для выполнения, а также избегайте недостатков, которые я перечислил выше. Можно ли это сделать каким-либо образом, например. с флагом компилятора или что-то в этом роде? Я использую gcc в качестве компилятора.
3 4

3 ответа:

Если вы последовательно используете <> includes, то опций -I в файле makefile должно быть достаточно. Макет каталога показывает только один makefile, в Родительском каталоге. Это могло бы использовать

-Idir_a -Idir_b

В параметрах компилятора, а также .файлы c могли бы просто сделать

#include <a.h>
#include <b.h>

Одна из проблем с цитируемыми включениями заключается в том, что их поведение с другими компиляторами может отличаться, как отмечено в В чем разница между #include <filename> и #include “filename”? (стандарт не был достаточно ясным). С помощью расширение gcc, вероятно, не улучшает эту ситуацию.

Мне удалось решить мою проблему.

Первая часть решения включает указание флага -iquote в gcc при компиляции. Из man gcc:

-iquotedir
    Add the directory dir to the head of the list of directories to be searched for header files only for the case of #include "file"; they are not searched for #include <file>, otherwise just like -I.
Вторая часть головоломки заключалась в том, как найти путь к makefile внутри самого makefile. Ответ работал для меня. Я вставляю решение здесь для удобства:
ROOT_DIR = $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))

Edit : хотя этот подход работает, этот ответ более удобен для кросс-компилятора, поэтому я лично собираюсь использовать тот.

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

#include "first/second/third/folder/library.h"