C/C++ includes search path order?


I’m wondering what the order is that clang uses for search paths?

Background: I’ve just started porting our code base from Windows (main platform) and Linux to MacOS and I’ve run into a brick wall with regards to how included files are located.

We generally use angle brackets, <>, for system headers, and double quotes, “”, for our own header files.

On Windows this generally works well because the Visual Studio compiler searches system paths followed by user paths for includes using angle brackets, and user paths followed by system paths for includes using double quotes.

Most platform headers and system libraries exclusively use angle brackets, so once we pull in one of those all their subsequent includes are self contained.

However, clang on MacOS (and I presume on all other platforms) doesn’t seem to make much sense in this regard. When we include <Cocoa/Cocoa.h> it, in turn includes <Foundation/Foundation.h> which clang resolves to one of our header files contained within a user include path. (Specified with -I on the command line and included from our own code with “Foundation/Foundation.h”.)

Obviously, this is not ideal.

So in the first instance I would like to understand how clang searches for header files and how it treats user include paths (defined with -I) and system include paths (defined with -isystem) differently and how (if at all) how it treats paths differently when using angle brackets and double quotes?


I’m not familiar with the implementation, though I did already find the following documentation: Clang command line argument reference — Clang 17.0.0git documentation
There are a couple of interesting flags in there, like -I- and --system-header-prefix and -iquote

Yeah, I read that already.

That seems to imply user paths are always searched before system paths which seems like a monumentally bad idea to me. :frowning:

I see --include-barrier could probably be coerced into getting what I want, but the snag there is we’re using Premake, and I suspect trying to get that to insert that argument in the right place will be a nightmare.

Not really answering your question but looks like -iquote should help with your issue (thanks Jeroen for this answer). Specifically, using -iquote path/to/your/headers would allow you to use #include "Foundation/Foundation.h" while #import <Foundation/Foundation.h> wouldn’t notice your header and would use a system header.

To get a better idea of header search paths, you can add -v flag and clang would dump the entire search list. The logic is that at first clang checks double quotes locations and then angle bracket locations (of course, depending on your actual #include). But for system and user header search paths there is no such precedence, they are searched in the order they are specified and both added as angle-bracket paths. Another non-obvious clang decision is that “explicitly specified paths should be searched before any implicitly added paths”. Hope this helps to understand the header search mechanism a little bit better.

1 Like

Yeah, -iquote seems the most sane way to go. I think to the point it should be used exclusively for include paths that resolve to our own code and we can then let third party libraries and platform headers fight it out among themselves for the remaining paths.

That said, due to Premake not directly supporting -iquote (we could shoehorn it in with the buildoptions section, but I’d rather wait for proper support), I decided, in this particular instance, to just rename our header to something which doesn’t clash.

Thanks for the help,