【问题标题】:clang++ does not respect -isystem flag, different behavior from g++clang++ 不尊重 -isystem 标志,与 g++ 不同的行为
【发布时间】:2021-05-25 06:23:45
【问题描述】:

在我的 macOS 系统上,我安装了以下内容:

  • Protobuf 3.14.0 通过brew install protobuf@3.14
  • g++ 10.2.0_4 通过brew install gcc@10
  • clang++ 1200.0.32.29 通过 XCode

当我查看 Google 的 Protobuf 存储库并使用 clang++ 构建文件时,它似乎忽略了我传递的 -isystem 标志:

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

这给出了一个错误:

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.

这是因为#include <google/protobuf/any.h> 找到了文件/usr/local/include/google/protobuf/any.h。我希望它能够找到文件src/google/protobuf/any.h,因为该文件存在并且我通过了-isystem src。自 3.14.0 版本以来,私有函数 InternalPackFrom 的签名已更改,因此出现错误。

另外,当我尝试用g++-10 替换clang++ 时,我得到了一个成功的构建。 (我的印象是 Clang 力求与 GCC 的 flag-for-flag 兼容):

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

为什么clang++ 在这里忽略了-isystem 标志?

【问题讨论】:

    标签: c++ macos clang++ include-path


    【解决方案1】:

    这不是因为-isystem src。出现问题是因为 clang++ 在其标准包含目录列表中包含路径 /usr/local/include,而 g++ 没有。

    您可以使用以下命令检查标准包含目录的列表:

    clang++ -nostdlib -Wp,-v -E -

    g++-10 -Wp,-v -E -

    为避免在 clang++ 中包含 /usr/local/include/google/protobuf/any.h,您可以删除文件或使用 -nostdinc-nostdinc++ 标志并手动传递旧的包含目录。

    【讨论】:

    • /usr/local/include 应该不是问题。如果您使用 -isystem 运行上述 clang 命令,您将看到它在队列中比默认包含的更早。
    • 我用完全相同的 clang++ 版本验证了我的机器上的问题是/usr/local/include。我没有 /usr/local/include 中的文件,并且 any_lite.cc 为我编译成功。
    • 谢谢,这很有帮助!我在我的系统上看到了同样的差异,Clang 有 /usr/local/include 而 GCC 没有。但有一件事仍不清楚:Clang 似乎没有遵循 GCC 为 -isystem 与“标准系统目录”定义的优先级。 IIUC -isystem 应优先于任何默认系统目录。 gcc.gnu.org/onlinedocs/gcc/Directory-Options.html
    • @AveMilia 当我运行clang++ -isystem src -Wp,-v -E - 时,我看到/usr/local/include 出现在src 上方,所以这似乎与您的评论相矛盾。 gist.github.com/kerrickstaley/34fab4f49b8bc264332fb3dd055a5b68
    • @KerrickStaley 哦,我想这只是 AppleClang 的另一个愚蠢行为......但很高兴我们弄清楚了。在 Linux 上,它的行为正确:gist.github.com/avemilia/8ad0a657585f33d7c92d191f8b36e9d8。我认为您可以通过自制软件在苹果上获得正常的叮当声。
    【解决方案2】:

    结合Anton MalyshevAve Milia的answers/cmets,显而易见的原因是Apple的自定义clang++版本(安装XCode时安装)总是在系统开头插入/usr/local/include包含路径列表,如上任何其他条目,包括在命令行上传递的-isystem 选项。 (这可能是一个错误)。您可以通过运行确认这一点

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

    并注意线条

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

    在输出中。

    上游 clang++g++ 都没有这种行为,所以这是 Apple 构建的一个怪癖。

    修复这个问题,你可以用 Homebrew 安装llvm

    brew install llvm
    

    然后按照输出的说明将 Homebrew 的 clang++ 放在您的路径上

    brew link llvm
    

    【讨论】:

      猜你喜欢
      • 2016-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-30
      • 2023-03-04
      相关资源
      最近更新 更多