Bug 213217 - [patch] Passing -isystem <sysroot>/usr/include to clang breaks C++ compilation
Summary: [patch] Passing -isystem <sysroot>/usr/include to clang breaks C++ compilation
Status: Closed Not Accepted
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Many People
Assignee: freebsd-toolchain (Nobody)
URL:
Keywords: patch
Depends on:
Blocks:
 
Reported: 2016-10-05 01:33 UTC by Oleksandr Tymoshenko
Modified: 2016-10-07 09:30 UTC (History)
2 users (show)

See Also:


Attachments
test case (53 bytes, text/x-csrc)
2016-10-05 01:33 UTC, Oleksandr Tymoshenko
no flags Details
clang-isystem-fix.diff (689 bytes, patch)
2016-10-05 01:36 UTC, Oleksandr Tymoshenko
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Oleksandr Tymoshenko freebsd_committer freebsd_triage 2016-10-05 01:33:13 UTC
Created attachment 175436 [details]
test case

To reproduce this bug run following command:
% clang++ -isystem /usr/include test.cpp
In file included from test.cpp:1:
/usr/include/c++/v1/cstddef:43:15: fatal error: 'stddef.h' file not found
#include_next <stddef.h>
              ^
1 error generated.

File compiles fine without -isystem flag:
% clang++  test.cpp
%

The problem is that stddef.h is clang's internal header and supposed to be in /usr/bin/../lib/clang/3.8.0/include. But since it conflicts with freebsd's stddef.h we do not install it and append /usr/include to the list of include dirs:
% clang++  -v test.cpp
FreeBSD clang version 3.8.0 (tags/RELEASE_380/final 262564) (based on LLVM 3.8.0)
.. skipped ...
#include "..." search starts here:
#include <...> search starts here:
 /usr/include/c++/v1
 /usr/bin/../lib/clang/3.8.0/include
 /usr/include
End of search list.

But when we pass -isystem /usr/include, clang removes appended dir as a duplicate and search path looks like this:
% clang++ -v -isystem /usr/include test.cpp
FreeBSD clang version 3.8.0 (tags/RELEASE_380/final 262564) (based on LLVM 3.8.0)
.. skipped ..
ignoring duplicate directory "/usr/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/include
 /usr/include/c++/v1
 /usr/bin/../lib/clang/3.8.0/include
End of search list.

#include_next does not go through whole list, only from the directory where its parent file is located

Some third-party software passes -isystem for cross-compilation cases alogn with --sysroot, namely Qt does it like this:
c++ ... --sysroot=/src/FreeBSD/tftproot/rpi/ ...  -isystem /src/FreeBSD/tftproot/rpi/usr/include ...

and this bug breaks cross-compilation
Comment 1 Oleksandr Tymoshenko freebsd_committer freebsd_triage 2016-10-05 01:36:52 UTC
Created attachment 175437 [details]
clang-isystem-fix.diff

This patch fixes the problem but I am not sure if it's correct. It adds one more priority check and keeps ExtCSystem include in favor of CSystem one
Comment 2 Dimitry Andric freebsd_committer freebsd_triage 2016-10-05 10:43:11 UTC
Short answer: Don't use -isystem /usr/include.

If you do so for C++ programs, you mess up the include search path order.  If you must do it for some reason, you must also add -isystem entries for the C++ include directories, and at the front of the list.

For example, a C++ program will use the following search path by default (where x.y.z is the clang version):

#include "..." search starts here:
#include <...> search starts here:
 /usr/include/c++/v1
 /usr/bin/../lib/clang/x.y.z/include
 /usr/include
End of search list.

From libc++ 3.8.0 onwards, if you include a C standard header, such as <cstddef>, you will get libc++'s wrapper header first.  This header sets up a few things, then does #include_next<stddef.h>, and with the above search path, this finds /usr/include/stddef.h.  (We don't install clang's internal stddef.h, since it is not compatible with our system headers yet.)

However, if you add -isystem /usr/include, you force /usr/include to be the first in the list, e.g. the search path will become:

ignoring duplicate directory "/usr/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/include
 /usr/include/c++/v1
 /usr/bin/../lib/clang/x.y.z/include
End of search list.

If you now include <cstddef>, and it eventually does #include_next<stddef.h>, it will attempt to search the paths *after* /usr/include/c++/v1, and will not be able to find the header.

Summary: If for some reason you must completely rebuild the header search path from scratch, you need to add  -isystem /usr/include/c++/v1 *before* -isystem /usr/include.  But it is better not to do this at all. :)
Comment 3 O. Hartmann 2016-10-07 09:27:11 UTC
See Bug 211808
Comment 4 O. Hartmann 2016-10-07 09:30:34 UTC
I see the problem arising on two ports, graphics/opencv-core and graphics/blender. Both ports do not compile on CURRENT on several machines, while they compile on other systems, also running CURRENT. The configurations (especially /etc/src.conf and /etc/make.conf) are spread around our systems, so I consider the systems not identical, but very similar. I know this is not enough in terms of mathematical logik and approval.