Search code examples
c++macosclang++include-path

clang++ does not respect -isystem flag, different behavior from g++


On my macOS system, I have the following installed:

  • Protobuf 3.14.0 via brew install [email protected]
  • g++ 10.2.0_4 via brew install gcc@10
  • clang++ 1200.0.32.29 via XCode

When I check out Google's Protobuf repo and build a file using clang++, it seems to ignore the -isystem flag that I pass:

git clone https://github.com/protocolbuffers/protobuf.git && cd protobuf && git checkout 326ea555b
clang++ -std=c++17 -isystem src -c src/google/protobuf/any_lite.cc

This gives an error:

src/google/protobuf/any_lite.cc:56:19: error: return type of out-of-line definition of 'google::protobuf::internal::AnyMetadata::InternalPackFrom' differs from that in the declaration
bool AnyMetadata::InternalPackFrom(const MessageLite& message,
~~~~              ^
/usr/local/include/google/protobuf/any.h:108:8: note: previous declaration is here
  void InternalPackFrom(const MessageLite& message,
  ~~~~ ^
1 error generated.

This happens because #include <google/protobuf/any.h> finds the file /usr/local/include/google/protobuf/any.h. I would expect it to find the file src/google/protobuf/any.h, because that file exists and I passed -isystem src. The signature of the private function InternalPackFrom has changed since version 3.14.0, hence the error.

Also, when I try replacing clang++ with g++-10, I get a successful build. (I was under the impression that Clang strives for flag-for-flag compatibility with GCC):

git clone https://github.com/protocolbuffers/protobuf.git && cd protobuf && git checkout 326ea555b
g++-10 -std=c++17 -isystem src -c src/google/protobuf/any_lite.cc

Why does clang++ ignore the -isystem flag here?


Solution

  • Combining answers/comments from Anton Malyshev and Ave Milia, the apparent reason is that Apple's custom clang++ version (installed when you install XCode) always inserts /usr/local/include at the start of the system include path list, above any other entries, including -isystem options passed on the command line. (This is probably a bug). You can confirm this by running

    clang++ -isystem /tmp -Wp,-v -E -
    

    and noting the lines

    #include <...> search starts here:
     /usr/local/include
     /tmp
    

    in the output.

    Neither upstream clang++ nor g++ have this behavior, so it is a quirk of Apple's build.

    To fix this problem, you can install llvm with Homebrew:

    brew install llvm
    

    and then put Homebrew's clang++ on your path by following the instructions output by

    brew link llvm