On 20/04/20 07:01 +0200, Helmut Grohne wrote:
The <cmath> and <cstdlib> headers need their counter parts <math.h> and <stdlib.h> from the libc respectively, but libstdc++ wraps these headers. Now <cmath> and <cstdlib> include these headers using$ echo '#include <cstdlib>' | g++ -x c++ -E - -isystem /usr/include >/dev/null In file included from <stdin>:1: /usr/include/c++/9/cstdlib:75:15: fatal error: stdlib.h: No such file or directory 75 | #include_next <stdlib.h> | ^~~~~~~~~~ compilation terminated. $ What happens here is that g++ includes libstdc++-v3/include/c_global/cstdlib. That header temporarily #defines _GLIBCXX_INCLUDE_NEXT_C_HEADERS and then does #include_next <stdlib.h>. libstdc++-v3's replacement libstdc++-v3/include/c_comaptibility/stdlib.h happens to come earlier and is not considered. Unfortunately, the -isystem above inserted glibc's header before the location containing <cstdlib>, so the #include_next continues searching and fails to find <stdlib.h>. Now you are probably going to say that "-isystem /usr/include" is a bad idea and that you shouldn't do that.
Right.
I'm inclined to agree. This isn't a problem just yet. Debian wants to move /usr/include/stdlib.h to /usr/include/<multiarch>/stdlib.h. After that move, the problematic flag becomes "-isystem /usr/include/<multiarch>". Unfortunately, around 30 Debian packages[1] do pass exactly that flag. Regardless whether doing so is a bad idea, I guess we will have to support that.
Or Debian should fix what they're going to break.
I am proposing to replace those two #include_next with plain #include. That'll solve the problem described above, but it is not entirely obvious that doing so doesn't break something else. After switching those #include_next to #include, libstdc++-v3/include/c_global/cstdlib will continue to temporarily will #include <stdlib.h>. Now, it'll search all include directories. It may find libstdc++-v3/include/c_comaptibility/stdlib.h or the libc's version. We cannot tell which. If it finds the one from libstdc++-v3, the header will notice the _GLIBCXX_INCLUDE_NEXT_C_HEADERS macro and immediately #include_next <stdlib.h> skipping the rest of the header. That in turn will find the libc version. So in both cases, it ends up using the right one. Precisely what we wanted.
As Marc said, this doesn't work. If a program tries to include <stdlib.h> it needs to get the libstdc++ version, otherwise only the libc versions of certain functions are defined. That means the additional C++ overloads such as ::abs(long) and ::abs(long long) won't be defined. That is the reason why libstdc++ provides its own <stdlib.h>. And if you do -isystem /usr/include (or any other option that causes libstdc++'s <stdlib.h> to be skipped) that doesn't work. Only ::abs(int) gets defined. So -isystem /usr/include breaks code, with or without your patch.
