LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 45880 - regression: locally-built Clang can't find C++ stdlib headers on Mac
Summary: regression: locally-built Clang can't find C++ stdlib headers on Mac
Status: REOPENED
Alias: None
Product: new-bugs
Classification: Unclassified
Component: new bugs (show other bugs)
Version: trunk
Hardware: Macintosh MacOS X
: P normal
Assignee: Unassigned LLVM Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-05-11 18:23 PDT by Sean McBride
Modified: 2021-10-13 07:00 PDT (History)
5 users (show)

See Also:
Fixed By Commit(s): a3a24316087d0e1b4db0b8fee19cdee8b7968032


Attachments
patch (2.13 KB, patch)
2020-05-11 18:23 PDT, Sean McBride
Details
fix to search for standard library headers in the platform sdk automatically (3.15 KB, patch)
2020-11-20 12:43 PST, Jens B. Jorgensen
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Sean McBride 2020-05-11 18:23:30 PDT
Created attachment 23468 [details]
patch

On macOS with Xcode:

- check out clang from git master
- build with Xcode's AppleClang as per https://clang.llvm.org/get_started.html
- use resulting build to compile a Hello World C++ program (anything that #includes an STL header file)

Expected:
- for the STL header files that Xcode already provides to be found

Actual:
- compiler error, for example: "fatal error: 'string' file not found"

This used to work.  I'm not sure when it broke, I think it was in the svn to git switch.

It's been discussed on cfe-dev, I'm not alone in having this happen:
http://lists.llvm.org/pipermail/cfe-dev/2019-September/063394.html

List member Jens Jorgensen shared a patch, see attached.  It works for me, but I have no idea if it's fit to commit.
Comment 1 Hans Wennborg 2020-08-28 02:45:17 PDT
This is a problem that I wish Apple would address, but I don't think it's a regression from Clang 10 so I don't think we can block the release on it.
Comment 2 Sean McBride 2020-10-13 13:36:24 PDT
Jens Jorgensen's patch no longer applies, due to this (pretty sure):

-----------------
commit a3a24316087d0e1b4db0b8fee19cdee8b7968032
Author: Louis Dionne <ldionne@apple.com>
Date:   Wed Oct 7 14:27:55 2020 -0400

    [clang] Don't look into <sysroot> for C++ headers if they are found alongside the toolchain
    
    Currently, Clang looks for libc++ headers alongside the installation
    directory of Clang, and it also adds a search path for headers in the
    -isysroot. This is problematic if headers are found in both the toolchain
    and in the sysroot, since #include_next will end up finding the libc++
    headers in the sysroot instead of the intended system headers.
    
    This patch changes the logic such that if the toolchain contains libc++
    headers, no C++ header paths are added in the sysroot. However, if the
    toolchain does *not* contain libc++ headers, the sysroot is searched as
    usual.
    
    This should not be a breaking change, since any code that previously
    relied on some libc++ headers being found in the sysroot suffered from
    the #include_next issue described above, which renders any libc++ header
    basically useless.
    
    Differential Revision: https://reviews.llvm.org/D89001
-----------------
Comment 3 Louis Dionne 2020-10-14 14:05:14 PDT
As explained in https://reviews.llvm.org/D88984, we would like to transition the libc++ headers from the Xcode toolchain to the SDK. This means that as long as Clang's sysroot is set correctly to the SDK, it should find the libc++ headers as expected. In particular, this means that running `xcrun /path/to/trunk/clang` should be sufficient. Or, if you want to avoid xcrun, you'll be able to use `-DDEFAULT_SYSROOT=<path-to-sysroot>` when configuring Clang.

I know this doesn't solve the issue right now, however we're working on fixing this.
Comment 4 Sean McBride 2020-10-15 11:53:31 PDT
Thanks Louis for your reply!

I'm just a lowly user, not a clang hacker, so I don't fully grok your comment, but...

>Or, if you want to avoid xcrun, you'll be able to use `-DDEFAULT_SYSROOT=<path-to-sysroot>` when configuring Clang.

I believe I am specifying -DDEFAULT_SYSROOT when I build clang.  My exact command is:

cmake -Wno-dev -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLLVM_ENABLE_ASSERTIONS=ON -DDEFAULT_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;compiler-rt;libunwind' -DLLVM_CREATE_XCODE_TOOLCHAIN=ON -DLLVM_BUILD_TOOLS=ON -DCMAKE_INSTALL_PREFIX=~/llvm/llvm-install ../llvm
make -j16 install

the result is a clang executable that can't build a hello world:

$ clang -fsyntax-only ~/test.cxx 
/Users/sean/test.cxx:1:10: fatal error: 'iostream' file not found
#include <iostream>
         ^~~~~~~~~~
Comment 5 Louis Dionne 2020-10-15 13:44:05 PDT
Right, so what I was trying to say is that this very incantation doesn't work today because we don't ship the libc++ headers as part of the SDK, however once we do, it should work out of the box.
Comment 6 Sean McBride 2020-10-15 15:35:35 PDT
"the SDK" being the macOS SDK that's part of Xcode?  If I understand correctly, 'once we ship the libc++ headers as part of the SDK' basically implies/requires a new version of Xcode, right?

As new Xcodes never support old versions of macOS, doesn't this mean this would never be fixed for older macOS?

I've just downloaded the official clang 11 binary here:

https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/clang+llvm-11.0.0-x86_64-apple-darwin.tar.xz

and it somehow finds <iostream> compiling the same file:

$ /Users/sean/Downloads/clang+llvm-11.0.0-x86_64-apple-darwin/bin/clang-11 -fsyntax-only ~/Desktop/test.cxx
 
How come that works?  How can I build clang to also so work?

Thanks.
Comment 7 Louis Dionne 2020-10-16 06:15:50 PDT
> As new Xcodes never support old versions of macOS, doesn't this mean 
> this would never be fixed for older macOS?

As it is often the case, the fix will require updating to a SDK that contains
the fix, which is shipped with a new Xcode. The usual system requirements apply.


> I've just downloaded the official clang 11 binary here:
> [...]
> and it somehow finds <iostream> compiling the same file:
> [...]
> How come that works?  How can I build clang to also so work?

I'm not sure how that Clang is configured. I think I remember there's a trick 
one can do with C_INCLUDE_DIRS when configuring Clang -- that might be it.
Comment 8 Sean McBride 2020-10-16 09:06:04 PDT
I feel like I'm missing something here...

As of today, and until this new macOS SDK ships, how does anyone use clang on macOS (for C++)???  Aren't there clang developers that use macOS regularly?  How do they build a working compiler??
Comment 9 Louis Dionne 2020-10-16 09:34:30 PDT
You can build libc++ alongside Clang, and Clang should find the libc++ headers. Are you including libcxx in LLVM_ENABLE_PROJECTS?
Comment 10 Sean McBride 2020-10-20 16:48:02 PDT
>Are you including libcxx in LLVM_ENABLE_PROJECTS?

No.

Wouldn't that build a bleeding-edge libcxx instead of using the system one?

Also, the string "libcxx" does not even appear here:
https://clang.llvm.org/get_started.html

Anyway, I've given it a try, I modified step 3 to do:

cmake -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi" ../llvm

The resulting clang is able to compile trivialities like "#include <iostream>" but when I use it to build CMake, it fails with weird errors like:

error: no member named 'aligned_alloc' in the global namespace
using ::aligned_alloc;
      ~~^

error: no member named 'filesystem' in namespace 'std'; did you mean simply 'filesystem'?
using std::filesystem::path;
      ^

I never had weird errors like that using Jens' patch.
Comment 11 Jens B. Jorgensen 2020-11-05 07:12:17 PST
I haven't tried to build recently but catching up now on this. Per Sean's comment about the official binary he downloaded which works: where can we find the build script that produces those official binaries? If those work I for one would be happy to just rely on them.
Comment 12 Hans Wennborg 2020-11-05 09:22:11 PST
(In reply to Jens B. Jorgensen from comment #11)
> I haven't tried to build recently but catching up now on this. Per Sean's
> comment about the official binary he downloaded which works: where can we
> find the build script that produces those official binaries? If those work I
> for one would be happy to just rely on them.

The official binaries are built by this script:

https://github.com/llvm/llvm-project/blob/llvmorg-11.0.0/llvm/utils/release/test-release.sh

But there's no magic in there which makes them different from normal builds, really.
Comment 13 Jens B. Jorgensen 2020-11-20 12:41:26 PST
So I just merged my working copy with the main branch. I did have to massage my commit. And what I did was expand the 2 cases to 3 and only use the platform SDK when the first two don't succeed. 

I'll note in particular that when my patch is disabled it of course doesn't find the std library headers, and with it, everything works as expected.

Please find the patch attached.
Comment 14 Jens B. Jorgensen 2020-11-20 12:43:36 PST
Created attachment 24189 [details]
fix to search for standard library headers in the platform sdk automatically

I use this patch and build clang with:

cmake -DLLVM_ENABLE_PROJECTS=clang -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release DCLANG_XCODE_TOOLCHAIN_ROOT=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain

This allows me to access the standard library headers without need -sysroot
Comment 15 Jens B. Jorgensen 2020-11-20 12:46:29 PST
(In reply to Hans Wennborg from comment #1)
> This is a problem that I wish Apple would address, but I don't think it's a
> regression from Clang 10 so I don't think we can block the release on it.

So unless I'm mistaken the problem arose because Apple made the decision to no longer install the c++ std library headers included with the SDK into /usr/include. I would speculate that based on their trend of locking out changes to certain parts of the filesystem that they are unlikely to reverse this decision.
Comment 16 Sean McBride 2021-02-21 08:59:54 PST
Jens, I've only just got around to trying this now. But your new patch doesn't work for me.  I've tried on two different Macs.  Here are my exact steps:

cd ~
mkdir clang-test
cd clang-test
git clone https://github.com/llvm/llvm-project.git
cd llvm-project
patch -p1 <~/Downloads/0001-add-the-c-stdlibrary-from-xcode.patch
mkdir install
mkdir build
cd build
cmake -DLLVM_ENABLE_PROJECTS=clang -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=~/clang-test/llvm-project/install -DCLANG_XCODE_TOOLCHAIN_ROOT=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain ../llvm
make -j12 install

Then build trivial C++ file:

~/clang-test/llvm-project/install/bin/clang++ ~/Desktop/test.cxx 

In file included from /Users/builder/Desktop/test.cxx:1:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/iostream:37:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/ios:214:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/iosfwd:95:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/wchar.h:119:15: fatal error: 'wchar.h' file not found
#include_next <wchar.h>
              ^~~~~~~~~

Am I doing anything wrong here?
Comment 17 Jens B. Jorgensen 2021-02-22 08:46:49 PST
So this looks like the patch worked, but there's a different issue. I don't recall exactly but I think you just need to maybe run 'xcode-select --install" ? Something along those lines, google around a bit and I think you'll find the right incantation.
Comment 18 Sean McBride 2021-02-22 09:08:29 PST
Your patch definitely does something, because the resulting error message changes slightly wrt the paths.

I'll try to find the incantation, but shouldn't the instructions at:

https://clang.llvm.org/get_started.html

be able to produce a compiler that can build 'hello world'?  Am I trying to do something so weird here?
Comment 19 Jens B. Jorgensen 2021-02-22 09:16:24 PST
Yeah the instructions certainly should, but bear in mind the way macos supplies their system headers/libraries is different and certainly non-standard w.r.t *nix norms. That's really the root issue behind all of this. If stuff were just there in /usr/include we wouldn't be here in the first place ;-).
Comment 20 Sean McBride 2021-09-07 13:11:49 PDT
So I've downloaded the pre-built 13.0.0-rc1 binary from here:

https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0-rc1/clang+llvm-13.0.0-rc1-x86_64-apple-darwin.tar.xz

and it too can't build a 'hello world' example:

$ /Users/builder/Downloads/clang+llvm-13.0.0-rc1-x86_64-apple-darwin/bin/clang -fsyntax-only test.c
test.c:1:10: fatal error: 'stdio.h' file not found
#include <stdio.h>
         ^~~~~~~~~
1 error generated.
Comment 21 Louis Dionne 2021-09-07 14:16:36 PDT
Sean, do you have an Apple SDK installed? If so, you need to point Clang to those headers using one of the options below, otherwise Clang can't possibly guess where to use those headers from. Apple made the decision not to ship headers as part of the root system (which makes sense IMO since those are not necessary to run any software, so there is no reason for non-developer users to have those headers), and that means you need to tell Clang where to find them. The only thing we could do here is somehow try to guess what SDK you want to compile with, and set the `-isysroot` based on running `$(xcrun --sdk <the-sdk-you-want-to-use> --show-sdk-path)` from the Clang driver. I'm not sure that's a great solution, because how would we guess which SDK to use?

This issue was originally for C++, however that part of the issue was resolved. By default the libc++ headers shipped in <install>/../include/c++/v1 will be used, but you still need to use xcrun so it can find the C library headers:

  $ echo "#include <iostream>" | xcrun /path/to/clang++ -fsyntax-only -xc++ -

The `xcrun` bit will tell Clang what's the path to the SDK, and Clang should set up the correct header search paths based on that. Alternatively, you can drop `xcrun` and use `-isysroot` instead:

  $ echo "#include <iostream>" | /path/to/clang++ -fsyntax-only -xc++ - -isysroot $(xcrun --show-sdk-path)

Another alternative, which might be what you're looking for since you seem to want to use `clang` without any special flags, would be to globally set the root of the SDK using:

  $ export SDKROOT=$(xcrun --show-sdk-path)
  $ echo "#include <iostream>" | /path/to/clang++ -fsyntax-only -xc++ -

However, in all cases, that has to be performed on the user side because we can't know what the path of the SDK will be when we build Clang.

TL;DR: I suspect what you want is to add `export SDKROOT=$(xcrun --show-sdk-path)` to your `.zshrc` and be done with it, however you'll have to override `SDKROOT` if you ever want to compile with a LLVM Clang for a different SDK. I'm going to close this as RESOLVED since the underlying issue with C++ headers has been solved with a combination of a3a24316087d0e1b4db0b8fee19cdee8b7968032 and Apple shipping libc++ headers in recent SDKs.
Comment 22 Hans Wennborg 2021-09-08 00:57:10 PDT
Thanks for the comprehensive answer, Louis!

Since people keep running into this, maybe some of the information should be added to the Clang user's manual?


> $ echo "#include <iostream>" | /path/to/clang++ -fsyntax-only -xc++ - -isysroot $(xcrun --show-sdk-path)

Is there any reason the Clang driver couldn't just run `xcrun --show-sdk-path` itself to figure out where to look for headers?
Comment 23 Louis Dionne 2021-09-08 06:34:37 PDT
(In reply to Hans Wennborg from comment #22)
> Thanks for the comprehensive answer, Louis!
> 
> Since people keep running into this, maybe some of the information should be
> added to the Clang user's manual?
> 
> 
> > $ echo "#include <iostream>" | /path/to/clang++ -fsyntax-only -xc++ - -isysroot $(xcrun --show-sdk-path)
> 
> Is there any reason the Clang driver couldn't just run `xcrun
> --show-sdk-path` itself to figure out where to look for headers?

As I said above, it would be possible, but we'd have to guess what SDK the user wants to use. There are multiple SDKs, for example the macOS SDK, the watchOS SDK, the iOS SDK, etc.

One thing we could do is set the default to the result of running `xcrun ---show-sdk-path`, but if `SDKROOT` is in the environment, that would override the default. I can look into doing that.
Comment 24 Sean McBride 2021-09-08 13:05:41 PDT
Louis, thanks for the detailed reply.

>Sean, do you have an Apple SDK installed?

Yes; I have Xcode installed.

>If so, you need to point Clang to those headers using one of the options below, otherwise Clang can't possibly guess where to use those headers from.

Why can't it guess?  The Xcode clang seems to guess just fine.  Contrast:

```
$ /usr/bin/clang --version
Apple clang version 12.0.0 (clang-1200.0.32.29)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

$ ~/Downloads/clang+llvm-13.0.0-rc1-x86_64-apple-darwin/bin/clang --version
clang version 13.0.0
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Users/builder/Downloads/clang+llvm-13.0.0-rc1-x86_64-apple-darwin/bin

$ /usr/bin/clang -fsyntax-only test.c

$ ~/Downloads/clang+llvm-13.0.0-rc1-x86_64-apple-darwin/bin/clang -fsyntax-only test.c
test.c:1:10: fatal error: 'stdio.h' file not found
#include <stdio.h>
         ^~~~~~~~~
1 error generated.
```

If `/usr/bin/clang` can do it, why can't the open source binaries do it?
Comment 25 Louis Dionne 2021-09-08 13:12:15 PDT
(In reply to Sean McBride from comment #24)
> 
> If `/usr/bin/clang` can do it, why can't the open source binaries do it?

The main difference is that when you invoke Apple Clang (e.g. `/usr/bin/clang`), you're actually going through a shim that calls `xcrun /path/to/actual/clang/inside/Xcode.app`, and that sets the SDK to use by default. For the open-source Clang, you might or might not even have a SDK available, cause it's possible to install LLVM Clang without having any Xcode.

Regardless, I went ahead and tried implementing it in Clang: https://reviews.llvm.org/D109460. This patch does solve your problem but it creates other problems as well. I opened that review to see whether this was worth pursuing or not.

Reopening until we get to the bottom of this.
Comment 26 Sean McBride 2021-09-09 15:09:25 PDT
>The main difference is that when you invoke Apple Clang (e.g. `/usr/bin/clang`), you're actually going through a shim that calls `xcrun /path/to/actual/clang/inside/Xcode.app`, and that sets the SDK to use by default. 

Ah!  Thanks for the education.

It is a strange user experience that every other UNIX and also Apple's /usr/bin/clang shim work one way, but open source clang works another way.  Although I finally understand why, from a purely user point of view, it's still weird.  Hopefully your draft patch can be made to work magic!
Comment 27 Sean McBride 2021-10-13 07:00:53 PDT
Relatedly: I believe this lack of automatically finding headers is what causes CMake's BootstrapTest to fail, see also:

https://gitlab.kitware.com/cmake/cmake/-/issues/22755