https://sourceware.org/pipermail/elfutils-devel/2024q3/007281.html has a bit of prior discussion and even a has fix submitted (https://sourceware.org/git/?p=elfutils.git;a=commitdiff;h=b426c4db31e7c80d4262abdd845d2ece0c9a841c). Unfortunately the fix still fails in some scenarios: in-tree libc++ builds. The simplest way to reproduce the build on `gcc` failure is to add `#include <stack>` into `src/srcfiles.cxx`: --- a/src/srcfiles.cxx +++ b/src/srcfiles.cxx @@ -40,6 +40,7 @@ #include <cassert> #include <gelf.h> #include <memory> +#include <stack> /* simulate transitive include on libc++ */ #ifdef ENABLE_LIBDEBUGINFOD #include "debuginfod.h" Now we can fail the build on `gcc`: $ autoreconf -ifv && ./configure --enable-maintainer-mode && make && make check ... Making all in src CXX srcfiles.o In file included from srcfiles.cxx:43: ./stack:1:1: error: stray '\177' in program 1 | <U+007F>ELF<U+0002><U+0001><U+0001><U+0000>< This happens because src/Makefile still contains `-I .`: srcdir = . ... AM_CPPFLAGS = -iquote . -I$(srcdir) ... As a workaround nixpkgs now uses out-of-tree builds as: mkdir build-tree cd build-tree ../configure ... But it would be nice to fix the collision for in-tree builds. For libc++ build failure `<stack>` is included transitively via <iostream>: In file included from srcfiles.cxx:50: In file included from /nix/store/7mk6c0p1jvxm3vq2my5swi5jlidby1h7-libcxx-x86_64-unknown-linux-gnu-19.1.7-dev/include/c++/v1/iostream:43: In file included from /nix/store/7mk6c0p1jvxm3vq2my5swi5jlidby1h7-libcxx-x86_64-unknown-linux-gnu-19.1.7-dev/include/c++/v1/istream:1367: In file included from /nix/store/7mk6c0p1jvxm3vq2my5swi5jlidby1h7-libcxx-x86_64-unknown-linux-gnu-19.1.7-dev/include/c++/v1/ostream:194: In file included from /nix/store/7mk6c0p1jvxm3vq2my5swi5jlidby1h7-libcxx-x86_64-unknown-linux-gnu-19.1.7-dev/include/c++/v1/format:246: ./stack:1:1: error: expected unqualified-id 1 | <U+007F>ELF<U+0002><U+0001><U+0001>...
Do you know why libc++ does this transitive include of stack? Is this an issue with libc++ for any standard header name because they might be indirectly included in libc++ headers? Do you know why this doesn't seem to be a problem when using libstdc++?
I don't think c++ standard guarantees exact transitive headers included by other headers. I think the difference is the implementation detail of libstdc++ vs libc++. libstdc++'s <format> does not include <stack> (and also does not get enabled without -std=c++20): - https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/std/format;h=46bd5d5ee6a0e72520776ea21610e84ef5c6aca9;hb=HEAD#l45 - https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/std/ostream;h=3a0a0d35df1d69f620bfbe0e1d94a790904193f2;hb=HEAD#l44 libc++'s <format> does include it (and only does it before -std=c++20): - https://github.com/llvm/llvm-project/blob/08b8d467d4253373e77a075c03e25281dee8ad15/libcxx/include/format#L252 - https://github.com/llvm/llvm-project/blob/08b8d467d4253373e77a075c03e25281dee8ad15/libcxx/include/ostream#L201 Both implementations slowly clean their header structure up going forward.
I don't understand why this is only a problem with srcdir == builddir. But maybe we can extend the original solution to use -iquote for srcdir. And only have -I for lib and the top builddir (for <config.h>)? Does the following work for you? diff --git a/config/eu.am b/config/eu.am index 5157a34ee552..1361044804f5 100644 --- a/config/eu.am +++ b/config/eu.am @@ -31,7 +31,7 @@ ## DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -DLOCALEDIR='"${localedir}"' -AM_CPPFLAGS = -iquote . -I$(srcdir) -I$(top_srcdir)/lib -I.. +AM_CPPFLAGS = -iquote. -iquote$(srcdir) -I$(top_srcdir)/lib -I$(abs_top_builddir) # Drop the 'u' flag that automake adds by default. It is incompatible # with deterministic archives. diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 25d53d31c7c8..b77db1423fe0 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -32,8 +32,8 @@ #include <stdbool.h> #include <pthread.h> -#include <libdw.h> -#include <dwarf.h> +#include "libdw.h" +#include "dwarf.h" #include "eu-search.h"
(In reply to Mark Wielaard from comment #3) > I don't understand why this is only a problem with srcdir == builddir. AFAIU the difference in in-tree/out-of-tree is the following: in-tree: - builder process is in src/ - src/ contains freshly built 'stack' binary - clang is ran as 'clang++ -iquote . -I . srcfiles.cxx' - <stack> is looked up from '-I .' and finds ./stack ELF out-of-tree: - builder process is in build-tree/src/ - build-tree/src/ contains freshly built 'stack' binary - clang is ran as 'clang++ -iquote . -I ../../src srcfiles.cxx' - <stack> is looked up from '-I ../../src' and does not find ./stack (as it's in current ./stack build tree, source tree is clean) > But maybe we can extend the original solution to use -iquote for srcdir. And > only have -I for lib and the top builddir (for <config.h>)? > > Does the following work for you? > > diff --git a/config/eu.am b/config/eu.am > index 5157a34ee552..1361044804f5 100644 > --- a/config/eu.am > +++ b/config/eu.am > @@ -31,7 +31,7 @@ > ## > > DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -DLOCALEDIR='"${localedir}"' > -AM_CPPFLAGS = -iquote . -I$(srcdir) -I$(top_srcdir)/lib -I.. > +AM_CPPFLAGS = -iquote. -iquote$(srcdir) -I$(top_srcdir)/lib > -I$(abs_top_builddir) > > # Drop the 'u' flag that automake adds by default. It is incompatible > # with deterministic archives. > diff --git a/libdw/libdwP.h b/libdw/libdwP.h > index 25d53d31c7c8..b77db1423fe0 100644 > --- a/libdw/libdwP.h > +++ b/libdw/libdwP.h > @@ -32,8 +32,8 @@ > #include <stdbool.h> > #include <pthread.h> > > -#include <libdw.h> > -#include <dwarf.h> > +#include "libdw.h" > +#include "dwarf.h" > #include "eu-search.h" Yes, I confirm that fixes build failure for my in-tree clang setup.
(In reply to Sergei Trofimovich from comment #4) > Yes, I confirm that fixes build failure for my in-tree clang setup. Thanks for testing, I committed that fix plus some comments to hopefully make debugging these issues easier next time. commit 76bd5f6bea9bbeed68b1434455e4904d0fc22b04 Author: Mark Wielaard <mark@klomp.org> Date: Thu Jun 26 15:06:07 2025 +0200 config: Adjust AM_CPPFLAGS for srcdir and .. path includes When building with clang and libc++ some standard headers might try including <stack> even when no source file requests such include directly. When building with srcdir == builddir this might clash in the src dir since we then build a stack binary there and the src dir also has srcfiles.cxx which might include some standard c++ headers. Work around this by removing -I.. from AM_CPPFLAGS and replacing it with -I(abs_top_builddir) where the <config.h> file can be found. And use -iquote for srcdir so it doesn't get included in the search path for the system <header> includes (only for "header" includes). Note that DEFAULT_INCLUDES might add . and srcdir back. So DEFAULT_INCLUDES is disabled explicitly in src/Makefile.am (where the stack binary is build). We could also use the nostdinc automake option to completely suppress that, but that needs more auditing of various installed vs not-installed header files. * config/eu.am (AM_CPPFLAGS): Use -iquote for $(srcdir) and replace -I.. with -I$(abs_top_builddir). * libdw/libdwP.h: Include "libdw.h" and "dwarf.h" instead of the system headers <libdw.h> and <dwarf.h>. https://sourceware.org/bugzilla/show_bug.cgi?id=33103 Signed-off-by: Mark Wielaard <mark@klomp.org>
Note that a followup commit was necessary to fix building one testcase that broke make check: commit 65d383a7e653524388ff2ea382be3eac1d04061f (HEAD -> main) Author: Mark Wielaard <mark@klomp.org> Date: Thu Jun 26 21:36:04 2025 +0200 libdw: Add DEFAULT_INCLUDES to CHECK_DEF_FLAGS DEFAULT_INCLUDES includes -I. which is needed for compiling the testcases with -DMAIN_CHECK=1. This fixes make check after commit 76bd5f6bea9b "config: Adjust AM_CPPFLAGS for srcdir and .. path includes" * libdw/Makefile.am (CHECK_DEF_FLAGS): Add DEFAULT_INCLUDES. Signed-off-by: Mark Wielaard <mark@klomp.org>