How do I use a preprocessor macro inside an include?
Asked Answered
M

2

9

I am trying to build freetype2 using my own build system (I do not want to use Jam, and I am prepared to put the time into figuring it out). I found something odd in the headers. Freetype defines macros like this:

#define FT_CID_H  <freetype/ftcid.h>

and then uses them later like this:

#include FT_CID_H 

I didn't think that this was possible, and indeed Clang 3.9.1 complains:

error: expected "FILENAME" or <FILENAME>
#include FT_CID_H
  • What is the rationale behind these macros?
  • Is this valid C/C++?
  • How can I convince Clang to parse these headers?

This is related to How to use a macro in an #include directive? but different because the question here is about compiling freetype, not writing new code.

Maltreat answered 17/3, 2017 at 12:50 Comment(10)
That is an unusual way to do things - normally the #define would be used with #ifdef to conditionally include different header files.Unilobed
Possible duplicate of How to use a macro in an #include directive?Fraze
So far as I can see, this is valid (at least in C99 - see paragraph 4 of section 6.10.2).Eddington
Cannot reproduce: godbolt.org/g/2DiIL0Baluchi
Take a look at: #32066704 What you are trying to "should" be possible, but it is pretty bad practice. (I am not 100% sure on what standard says, but I am guessing it is implementation dependent, based upon the order that the preprocessor reads it.)Poore
CLang 3.5.0 does not complain, GCC 4.9.2 neither.Lichenology
@ChrisBritt It's actually perfectly legal and well-defined in the standard, not implementation-dependent.Leontina
My bet goes on a single standalone #include, probably due to a typo or another missing #include. You want to look a the pre-processor's output.Lichenology
My bet goes on: did you include the header that define FT_CID_H before using it?Itself
This isn't an answer, but you may also be interested in using __has_include since it sounds like you are trying to include headers based on their availability.Agile
S
6

Is this valid C/C++?

The usage is valid C, provided that the macro definition is in scope at the point where the #include directive appears. Specifically, paragraph 6.10.2/4 of C11 says

A preprocessing directive of the form

# include pp-tokens new-line

(that does not match one of the two previous forms) is permitted. The preprocessing tokens after include in the directive are processed just as in normal text. (Each identifier currently defined as a macro name is replaced by its replacement list of preprocessing tokens.) The directive resulting after all replacements shall match one of the two previous forms.

(Emphasis added.) Inasmuch as the preprocessor has the same semantics in C++ as in C, to the best of my knowledge, the usage is also valid in C++.

What is the rationale behind these macros?

I presume it is intended to provide for indirection of the header name or location (by providing alternative definitions of the macro).

How can I convince Clang to parse these headers?

Provided, again, that the macro definition is in scope at the point where the #include directive appears, you shouldn't have to do anything. If indeed it is, then Clang is buggy in this regard. In that case, after filing a bug report (if this issue is not already known), you probably need to expand the troublesome macro references manually.

But before you do that, be sure that the macro definitions really are in scope. In particular, they may be guarded by conditional compilation directives -- in that case, the best course of action would probably be to provide whatever macro definition is needed (via the compiler command line) to satisfy the condition. If you are expected to do this manually, then surely the build documentation discusses it. Read the build instructions.

Suilmann answered 17/3, 2017 at 13:23 Comment(2)
Thanks for the answer, it led me to a solution. It turns out the include path macros need to be defined at the command-line. These usually are generated by flags passed to make, so I simply needed to copy the flags from the Makefile. What a needlessly crazy build system!Maltreat
Just an extra note for people trying to build freetype2: not every file should be compiled (e.g. aflatin2.c) and not every header actually gets included (e.g. ftconfig.h)!Maltreat
L
11

I will address your three questions out of order.

Question 2

Is this valid C/C++?

Yes, this is indeed valid. Macro expansion can be used to produce the final version of a #include directive. Quoting C++14 (N4140) [cpp.include] 16.2/4:

A preprocessing directive of the form

# include pp-tokens new-line

(that does not match one of the two previous forms) is permitted. The preprocessing tokens after include in the directive are processed just as in normal text (i.e., each identifier currently defined as a macro name is replaced by its replacement list of preprocessing tokens). If the directive resulting after all replacements does not match one of the two previous forms, the behavior is undefined.

The "previous forms" mentioned are #include "..." and #include <...>. So yes, it is legal to use a macro which expands to the header/file to include.

Question 1

What is the rationale behind these macros?

I have no idea, as I've never used the freetype2 library. That would be a question best answered by its support channels or community.

Question 3

How can I convince Clang to parse these headers?

Since this is legal C++, you shouldn't have to do anything. Indeed, user @Fanael has demonstrated that Clang is capable of parsing such code. There must be some problem other problem in your setup or something else you haven't shown.

Leontina answered 17/3, 2017 at 13:8 Comment(0)
S
6

Is this valid C/C++?

The usage is valid C, provided that the macro definition is in scope at the point where the #include directive appears. Specifically, paragraph 6.10.2/4 of C11 says

A preprocessing directive of the form

# include pp-tokens new-line

(that does not match one of the two previous forms) is permitted. The preprocessing tokens after include in the directive are processed just as in normal text. (Each identifier currently defined as a macro name is replaced by its replacement list of preprocessing tokens.) The directive resulting after all replacements shall match one of the two previous forms.

(Emphasis added.) Inasmuch as the preprocessor has the same semantics in C++ as in C, to the best of my knowledge, the usage is also valid in C++.

What is the rationale behind these macros?

I presume it is intended to provide for indirection of the header name or location (by providing alternative definitions of the macro).

How can I convince Clang to parse these headers?

Provided, again, that the macro definition is in scope at the point where the #include directive appears, you shouldn't have to do anything. If indeed it is, then Clang is buggy in this regard. In that case, after filing a bug report (if this issue is not already known), you probably need to expand the troublesome macro references manually.

But before you do that, be sure that the macro definitions really are in scope. In particular, they may be guarded by conditional compilation directives -- in that case, the best course of action would probably be to provide whatever macro definition is needed (via the compiler command line) to satisfy the condition. If you are expected to do this manually, then surely the build documentation discusses it. Read the build instructions.

Suilmann answered 17/3, 2017 at 13:23 Comment(2)
Thanks for the answer, it led me to a solution. It turns out the include path macros need to be defined at the command-line. These usually are generated by flags passed to make, so I simply needed to copy the flags from the Makefile. What a needlessly crazy build system!Maltreat
Just an extra note for people trying to build freetype2: not every file should be compiled (e.g. aflatin2.c) and not every header actually gets included (e.g. ftconfig.h)!Maltreat

© 2022 - 2024 — McMap. All rights reserved.