Как использовать макрос препроцессора внутри include?

Я пытаюсь создать freetype2, используя мою собственную систему сборки (я не хочу использовать Jam, и я готов поставить время, чтобы понять это). Я нашел что-то странное в заголовках. Freetype определяет макросы следующим образом:

#define FT_CID_H  <freetype/ftcid.h>

а затем использует их позже:

#include FT_CID_H 

Я не думал, что это возможно, и действительно, Clang 3.9.1 жалуется:

error: expected "FILENAME" or <FILENAME>
#include FT_CID_H
  • В чем смысл этих макросов?
  • Является ли это допустимым C/С++?
  • Как убедить Клана разобрать эти заголовки?

Это связано с Как использовать макрос в директиве #include?, но отличается тем, что здесь речь идет о компиляции freetype, а не о создании нового кода.

Ответ 1

Является ли это допустимым C/С++?

Использование допустимо C, при условии, что определение макроса находится в области видимости в точке, где появляется директива #include. В частности, пункт 6.10.2/4 C11 говорит

Директива предварительной обработки формы

# include pp-tokens new-line

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

(Добавлен акцент). Поскольку препроцессор имеет ту же семантику в С++, что и в C, насколько мне известно, использование также допустимо в С++.

В чем смысл этих макросов?

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

Как я могу убедить Клана разобрать эти заголовки?

При условии, что определение макроса находится в области видимости в точке, где появляется директива #include, вам не нужно ничего делать. Если это так, то Кланг в этом отношении ошибся. В этом случае, после подачи отчета об ошибке (если эта проблема еще не известна), вам, вероятно, необходимо вручную раскрыть связанные с этим макросы.

Но прежде чем вы это сделаете, убедитесь, что определения макросов действительно находятся в области видимости. В частности, они могут быть защищены директивами условной компиляции - в этом случае лучший способ действий, вероятно, будет заключаться в том, чтобы обеспечить любое макроопределение (через командную строку компилятора) для удовлетворения условия. Если вы ожидаете сделать это вручную, тогда, безусловно, в документации по сборке обсуждается это. Прочтите инструкции по сборке.

Ответ 2

Я рассмотрю ваши три вопроса не по порядку.

Вопрос 2

Является ли это допустимым C/С++?

Да, это действительно так. Расширение макроса можно использовать для создания окончательной версии директивы #include. Цитирование С++ 14 (N4140) [cpp.include] 16.2/4:

Директива предварительной обработки формы

# include pp-tokens new-line

(который не соответствует одной из двух предыдущих форм). Точки предварительной обработки после includeв директиве обрабатываются так же, как и в обычном тексте (то есть каждый идентификатор, определенный в настоящее время как имя макроса, заменяется его списком заметок для токенов предварительной обработки). Если директива, полученная после всех замен, не соответствует одной из двух предыдущих форм, поведение undefined.

"Предыдущие формы" упомянуты #include "..." и #include <...>. Так что да, законно использовать макрос, который расширяется до заголовка/файла для включения.

Вопрос 1

В чем смысл этих макросов?

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

Вопрос 3

Как я могу убедить Клана разобрать эти заголовки?

Поскольку это законный С++, вам не нужно ничего делать. Действительно, пользователь @Fanael продемонстрировал что Clang способен анализировать такой код. Должна быть какая-то другая проблема в вашей установке или что-то еще, что вы еще не показали.