Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

regression: locally-built Clang can't find C++ stdlib headers on Mac #45225

Open
seanm opened this issue May 12, 2020 · 29 comments
Open

regression: locally-built Clang can't find C++ stdlib headers on Mac #45225

seanm opened this issue May 12, 2020 · 29 comments
Labels
bugzilla Issues migrated from bugzilla clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' platform:macos

Comments

@seanm
Copy link

seanm commented May 12, 2020

Bugzilla Link 45880
Version trunk
OS MacOS X
Attachments patch
CC @zmodem,@jensbjorgensen,@ldionne
Fixed by commit(s) a3a2431

Extended Description

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.

@zmodem
Copy link
Collaborator

zmodem commented Aug 28, 2020

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.

@seanm
Copy link
Author

seanm commented Oct 13, 2020

Jens Jorgensen's patch no longer applies, due to this (pretty sure):


commit a3a2431
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

@ldionne
Copy link
Member

ldionne commented Oct 14, 2020

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.

@seanm
Copy link
Author

seanm commented Oct 15, 2020

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
^~~~~~~~~~

@ldionne
Copy link
Member

ldionne commented Oct 15, 2020

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.

@seanm
Copy link
Author

seanm commented Oct 15, 2020

"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 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.

@ldionne
Copy link
Member

ldionne commented Oct 16, 2020

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 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.

@seanm
Copy link
Author

seanm commented Oct 16, 2020

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??

@ldionne
Copy link
Member

ldionne commented Oct 16, 2020

You can build libc++ alongside Clang, and Clang should find the libc++ headers. Are you including libcxx in LLVM_ENABLE_PROJECTS?

@seanm
Copy link
Author

seanm commented Oct 20, 2020

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 " 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.

@jensbjorgensen
Copy link

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.

@zmodem
Copy link
Collaborator

zmodem commented Nov 5, 2020

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.

@jensbjorgensen
Copy link

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.

@jensbjorgensen
Copy link

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

@jensbjorgensen
Copy link

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.

@seanm
Copy link
Author

seanm commented Feb 21, 2021

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?

@jensbjorgensen
Copy link

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.

@seanm
Copy link
Author

seanm commented Feb 22, 2021

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?

@jensbjorgensen
Copy link

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 ;-).

@seanm
Copy link
Author

seanm commented Sep 7, 2021

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.

@ldionne
Copy link
Member

ldionne commented Sep 7, 2021

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 /../include/c++/v1 will be used, but you still need to use xcrun so it can find the C library headers:

$ echo "#include " | 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 " | /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 " | /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 a3a2431 and Apple shipping libc++ headers in recent SDKs.

@zmodem
Copy link
Collaborator

zmodem commented Sep 8, 2021

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 " | /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?

@ldionne
Copy link
Member

ldionne commented Sep 8, 2021

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 " | /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.

@seanm
Copy link
Author

seanm commented Sep 8, 2021

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?

@ldionne
Copy link
Member

ldionne commented Sep 8, 2021

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.

@seanm
Copy link
Author

seanm commented Sep 9, 2021

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!

@seanm
Copy link
Author

seanm commented Oct 13, 2021

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

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
@ldionne
Copy link
Member

ldionne commented Sep 8, 2023

The latest instance of the patch is https://reviews.llvm.org/D136315, but it seems blocked.

@EugeneZelenko EugeneZelenko added clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' platform:macos labels Sep 8, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Sep 8, 2023

@llvm/issue-subscribers-clang-driver

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' platform:macos
Projects
None yet
Development

No branches or pull requests

6 participants