Search code examples
c++gcccl

Include search paths from included header varies for different compilers


I have following folder structure:

project
├── header1.h
├── folder
│   └── header2.h
└── main.cpp

With following sources:

//main.cpp
#include "header1.h"
#include "folder/header2.h"
int main() {}

//header1.h
#pragma once
void function1() {}

//folder/header2.h
#pragma once
#include "header1.h"
void function2() {}

So 'header2.h' is including 'header1.h' which is not in the same folder.

Compiling this code with cl main.cpp is successful:

Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp Microsoft (R) Incremental Linker Version 14.00.24215.1
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:main.exe main.obj

But for gcc main.cpp I get error:

In file included from main.cpp:2:0:
folder/header2.h:2:21: fatal error: header1.h: No such file or directory
 #include "header1.h"
                     ^
compilation terminated.

Which totally makes sense. Seems like Microsoft is using their own rules to resolve includes. Is there a way to disable this behavior for cl (and Visual Studio)? Is there a way to enable cl-like behavior for gcc?


UPD.

I have checked with Clang 4.0.0 clang++ main.cpp on Windows:

In file included from main.cpp:2:
./folder/header2.h:2:10: warning: #include resolved using non-portable Microsoft search rules as: ./header1.h

[-Wmicrosoft-include] #include "header1.h" ^ 1 warning generated.

And it even has a specific rule -Wmicrosoft-include for that.


Solution

  • This article explains how both forms ("" and <>) of include directive is processed by the VC++.

    I guess that point (3) of the "" form causes this very broad search across possible include directories in the project:

    Quoted form

    (3) In the directories of the currently opened include files, in the reverse order in which they were opened. The search begins in the directory of the parent include file and continues upward through the directories of any grandparent include files.

    That is why, when header2.h is processed from within main.cpp, which also includes header1.h, it gives you no error.

    GCC search rules are quite different:

    1. For the quote form of the include directive, the directory of the current file is searched first.
    2. For the quote form of the include directive, the directories specified by -iquote options are searched in left-to-right order, as they appear on the command line.
    3. Directories specified with -I options are scanned in left-to-right order.
    4. Directories specified with -isystem options are scanned in left-to-right order.
    5. Standard system directories are scanned.
    6. Directories specified with -idirafter options are scanned in left-to-right order.

    It does not automatically search the directories of include files that were opened so far (included before), which is the cause of your error. I don't think there is a way to bypass this limitation and force either of the compilers to use search logic used by another one.