cc-wrapper: always include libc++ in the search path#445095
cc-wrapper: always include libc++ in the search path#445095reckenrode merged 2 commits intoNixOS:stagingfrom
Conversation
| # This duplicates the behavior of a native toolchain, which can find the | ||
| # libc++ headers but requires `-lc++` to be specified explicitly when linking. |
There was a problem hiding this comment.
This doesn’t quite seem right:
shion:/v/f/1/j/T/tmp.FU3kWEOHHp
❭ clang foo.c
foo.c:1:10: fatal error: 'cstdint' file not found
1 | #include <cstdint>
| ^~~~~~~~~
1 error generated.
Even #include <c++/v1/cstdint> fails, because it tries to include other headers without that prefix.
We should certainly make clang -x c work, but I’m not sure this header behaviour is quite right?
BTW, there’s a -stdlib++-isystem and -cxx-isystem that probably do exactly what we want here, but they’re Clang‐only.
There was a problem hiding this comment.
How are you testing? Aside from my Swift branch, which worked, this is what I get when I nix develop something early in the bootstrap (like libiconv-1.17; because I haven’t bootstrapped) and try to compile a C++ file with clang.
$ cat test.cpp
#include <algorithm>
#include <array>
#include <iostream>
#include <cstdint>
int main() {
std::array<std::int32_t, 4> x = { 1, 2, 3, 4 };
std::for_each(x.begin(), x.end(), [](int32_t& val) {
std::cout << "value: " << val << std::endl;
});
}
$ clang test.cpp -c -o test.o
$ clang test.o -o test -lc++
$ ./test
value: 1
value: 2
value: 3
value: 4There was a problem hiding this comment.
BTW, there’s a -stdlib++-isystem and -cxx-isystem that probably do exactly what we want here, but they’re Clang‐only.
The issue is Clang expects the headers to be in the sysroot, but they’re not there. It has to be told where to find them by the wrapper, but the wrapper only does that when it thinks you’re compiling for C++. Always making the headers available accomplishes (mostly) the same thing as having them there.
It would be so much better if we generated a sysroot that compilers could be directed use. It would even work with unwrapped compilers (provided they were set up correctly).
There was a problem hiding this comment.
My test was with Xcode Clang – I thought that was the native toolchain being compared to:
Apple clang version 17.0.0 (clang-1700.3.19.1)
Target: arm64-apple-darwin25.0.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
The issue is Clang expects the headers to be in the sysroot, but they’re not there. It has to be told where to find them by the wrapper, but the wrapper only does that when it thinks you’re compiling for C++.
-stdlib++-isystem is precisely there to tell Clang where the headers for the C++ standard library are. I think it would make -x c++ work exactly as expected. But it’s not an option with GCC.
There was a problem hiding this comment.
My test was with Xcode Clang
Is SYSROOT or DEVELOPER_DIR set and pointing to an SDK in the store? It works for me with a native toolchain.
$ command -v clang
/usr/bin/clang
$ xcrun --find clang
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
$ clang -v
Apple clang version 17.0.0 (clang-1700.3.19.1)
Target: arm64-apple-darwin25.0.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
$ clang test.cpp -c -o test.o
$ clang test.o -o test -lc++
$ ./test
value: 1
value: 2
value: 3
value: 4
-stdlib++-isystemis precisely there to tell Clang where the headers for the C++ standard library are. I think it would make-x c++work exactly as expected. But it’s not an option with GCC.
This change is leveraging the wrapper’s support for sourcing the libc++ flags in nix-support/libcxx-cxxflags. If using -stdlib++-isystem is the correct way to specify the location to the C++ headers, the wrapper should be updated to use that instead with Clang, but that’s more appropriately done in another PR.
There was a problem hiding this comment.
Is
SYSROOTorDEVELOPER_DIRset and pointing to an SDK in the store? It works for me with a native toolchain.
No, it was with the normal Xcode SDK, outside of any Nix environment. But I see what’s going on here – it’s the file extension:
shion:/v/f/1/j/T/tmp.L6mt2HOXnQ
❭ cat test.c
#include <cstdint>
int main() {}
shion:/v/f/1/j/T/tmp.L6mt2HOXnQ
❭ clang test.c
test.c:1:10: fatal error: 'cstdint' file not found
1 | #include <cstdint>
| ^~~~~~~~~
1 error generated.
shion:/v/f/1/j/T/tmp.L6mt2HOXnQ 1
❭ mv test.c test.cpp
shion:/v/f/1/j/T/tmp.L6mt2HOXnQ
❭ clang test.cpp
shion:/v/f/1/j/T/tmp.L6mt2HOXnQ
❭
So, the native toolchain does behave as I expected – it’ll use the C++ library include directory, but only for code that it thinks is C++, whether from -x c++ or file extension. With your change here, C code would be able to see C++ headers directly too, which would be a divergence from the native toolchain.
The reason I brought up -cxx-isystem and -stdlib++-isystem is because they let us solve this problem:
shion:/v/f/1/j/T/tmp.exLD7JRuOy
❭ cat test.c
#include "test.h"
int main() {}
shion:/v/f/1/j/T/tmp.exLD7JRuOy
❭ ls cxxinclude
test.h
shion:/v/f/1/j/T/tmp.exLD7JRuOy
❭ clang -cxx-isystem cxxinclude test.c
test.c:1:10: fatal error: 'test.h' file not found
1 | #include "test.h"
| ^~~~~~~~
1 error generated.
shion:/v/f/1/j/T/tmp.exLD7JRuOy 1
❭ mv test.c test.cpp
shion:/v/f/1/j/T/tmp.exLD7JRuOy
❭ clang -cxx-isystem cxxinclude test.cpp
shion:/v/f/1/j/T/tmp.exLD7JRuOy
❭
All we would need to do is use -cxx-isystem rather than -isystem in libcxx-cxxflags when the compiler is Clang, and we should match the native toolchain’s behaviour. -stdlib++-isystem would be the same except it’d respond to -nostdinc++ – so that would be even closer to native toolchain behaviour.
Unfortunately, this wouldn’t help for GCC. I suppose that passing --with-gxx-libcxx-include-dir=${lib.getInclude darwin.libcxx}/include/c++/v1 in configureFlags would probably do the trick there well enough – depending on how it interacts with -nostdinc, possibly.
There was a problem hiding this comment.
(Also I do think we should do this for all Clang, since it’s just a nice move in the direction of less wrapper logic and more telling the compiler drivers what we actually want. I’m happy to run Linux builds to test the effect there, and Darwin builds too.)
There was a problem hiding this comment.
Using -stdlib++-isystem causes xz to fail to build. Using -cxx-isystem works. (Still bootstrapping.)
clang: warning: argument unused during compilation: '-stdlib++-isystem /nix/store/sj56s86jwq7cjdy0af2f3vy24pkh3zfy-bootstrap-stage0-libcxx/include/c++/v1' [-Wunused-command-line-argument]
be81c28 to
6ace571
Compare
6ace571 to
3e63639
Compare
|
I updated the PR to use |
|
Rust built. |
2232c0b to
e639809
Compare
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
@reckenrode Yes it fixes it, thank you! |
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code. (cherry picked from commit d46fa26)
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code. (cherry picked from commit NixOS@d46fa26)
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code. (cherry picked from commit d46fa26)
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code. (cherry picked from commit d46fa26)
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code.
|
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: |
This is necessary after NixOS#445095, which moved libc++ to -cxx-isystem to improve compatibility with build systems that invoke `clang` to compile C++ code. (cherry picked from commit d46fa26)
Without this change, building with -DMP_ENABLE_IWYU=ON and newer versions of nixpkgs (after 2025-11-12) fails with mysterious errors that look like: make[2]: *** [CMakeFiles/mputil.dir/build.make:79: CMakeFiles/mputil.dir/src/mp/util.cpp.o] Error 1 with no other error messages. The are no messages because cmake -E __run_co_compile hides the output from IWYU and does not display anything itself. The actual problem is missing include directories on the compiler command line, and the fix here is to extend a workaround previously added for clang-tidy to be used for IWYU as well. Breakage seems to have been caused by NixOS/nixpkgs@76a8ffa from NixOS/nixpkgs#445095, which I found by bisecting with --first-parent to a change between the following merge commit: https://github.com/NixOS/nixpkgs/commits/de21549a840be528ef4763dd7dca2006caf9c11f (bad) https://github.com/NixOS/nixpkgs/commits/c4d1151093af5d483d1900d9214a65e68bc21560 (good) If you check out the bad commit above (or any later commit) and revert NixOS/nixpkgs@76a8ffa the problem disappears. I suspect the problem happens because cmake is not handling -cxx-isystem properly, but did not debug further.
Without this change, building with -DMP_ENABLE_IWYU=ON and newer versions of nixpkgs (after 2025-11-12) fails with mysterious errors that look like: make[2]: *** [CMakeFiles/mputil.dir/build.make:79: CMakeFiles/mputil.dir/src/mp/util.cpp.o] Error 1 with no other error messages. The are no messages because cmake -E __run_co_compile hides the output from IWYU and does not display anything itself. The actual problem is missing include directories on the compiler command line, and the fix here is to extend a workaround previously added for clang-tidy to be used for IWYU as well. Breakage seems to have been caused by NixOS/nixpkgs@76a8ffa from NixOS/nixpkgs#445095, which I found by bisecting with --first-parent to a change between the following merge commit: https://github.com/NixOS/nixpkgs/commits/de21549a840be528ef4763dd7dca2006caf9c11f (bad) https://github.com/NixOS/nixpkgs/commits/c4d1151093af5d483d1900d9214a65e68bc21560 (good) If you check out the bad commit above (or any later commit) and revert NixOS/nixpkgs@76a8ffa the problem disappears. I suspect the problem happens because cmake is not handling -cxx-isystem properly, but did not debug further. The later change NixOS/nixpkgs#462747 which followed up on NixOS/nixpkgs#445095 did not seem to have any effect on this issue in my testing.
I found this was necessary when working on the Swift 6.x update. The libc++ headers are expected to be found in the sysroot when
clangis invoked for C++ code.Always making them available improves compatibility with build systems
like Bazel and SwiftPM, which try to compile C++ code with
clang.Things done
passthru.tests.nixpkgs-reviewon this PR. See nixpkgs-review usage../result/bin/.Add a 👍 reaction to pull requests you find important.