Re: Using standard C headers from LLVM/Clang

From: Brooks Davis <brooks_at_freebsd.org>
Date: Fri, 24 May 2024 23:01:26 UTC
Thank you for the prod and apologies for what I'm sure felt like a brush
off in your bug report and pull request mentioned below.  I'd like to
get this resolved in a useful way, but it's going to require some work.

On Fri, May 24, 2024 at 09:14:03AM -0700, Brendan Shanks wrote:
> Hi all,
> 
> I work for CodeWeavers, contributing to the Wine project. When building Wine on FreeBSD, I found that Wine refuses to use LLVM/clang from ports as a PE cross-compiler because the standard C/C99 headers are not present. In this case Wine uses clang in the 'x86_64-windows' mode, which understandably doesn???t use includes from /usr/include. configure tries to build a sample file in this mode which includes <stdarg.h>, and this fails.
> 
> Normally clang would have its own version of the standard C header files to use, but FreeBSD doesn???t install these: <https://github.com/freebsd/freebsd-src/blob/1d3c23676de33762fd7fc2e3d890fd14738d3ee6/lib/clang/headers/Makefile#L187>, <https://cgit.freebsd.org/ports/tree/devel/llvm18/files/patch-clang_lib_Headers_CMakeLists.txt>.
> 
> To work around this, the wine-devel FreeBSD port actually includes clang's stdarg.h to satisfy configure.
> But besides Wine???s usage, anyone trying to use ports clang to target a freestanding/bare-metal environment would not be able to use any of these standard header files.

A bit of background on these exclusions.  The patch to ports versions is
ancient and suffers from weakly justified copy and paste.  They exist
due to incompatabilities (e.g., different guards resulting in duplicate
typedefs which yields a compile error).  The list of files not being
installed needs to shrink, ideally to 0, but testing changes is a pain
(you need to rebuild the llvm package, install it, and then rebuild
FreeBSD) so I've generally just bumped the patch along and continued to
update it to delete all the std*.h files out of an abundance of caution.

I do think you're conflating two realted things in this message:
 - Installation of clang headers for use in a standalone environment
   (Mostly, but not entierly, a ports issue.)
 - Which header implementations to install in /usr/include in the base
   system.

Changing the latter might allow us to fix some issues with the former,
but I'm not convinced there's a wholesale justification for a switch.

I'm looking at stdarg.h specifically right now and I see no reason it
(and it's __stdarg*.h dependencies) couldn't be installed in clang's
internal header directory since it doesn't have an

#include_next <stdarg.h>

line to cause problems.  I'll test that now and take a look at the
others to see if I can narrow the list further.

> I filed a bug for this: <https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=274542> ("devel/llvm: C99 include files are not included???), and the advice was that either the FreeBSD or clang headers would need patches so they can coexist.
> 
> I thought I???d start on this by creating a GitHub pull request (<https://github.com/freebsd/freebsd-src/pull/915>) to use iso646.h and varargs.h from clang, and remove the FreeBSD versions. These files are very simple, and the two versions are functionally identical.
> The advice there was that this is a bigger philosophical change, and should be discussed further.
>
> My question for everyone: should the Clang C headers be used instead of FreeBSD maintaining its own?
> Is there still a philosophical reason for FreeBSD to maintain its own set of C header files?

Historically FreeBSD has maintained a BSD licensed C compilation envrionment
and runtime that is not (overly) tied to a particular compiler.  I think
that's generally good and we should be cautious about changing the
license of our headers.

I do think we're carrying historical bagage in some cases.

Our implementation of stdarg.h is probably a good example of baggage.
We have a convoluted machine-dependent (but not actually different)
implementation of va_* that used to be hand coded hackery, but is now
always implemented by the compiler.  We should at least simplify this
and maybe consider switching to a compiler provided one.

In some cases we can likely never use the compiler provided one.  For
example stdatomic.h is fine in the clang header directory, but it
likely can't be /usr/include/stdatomic.h because it's very much a
clang-specific header (maybe it works if gcc prefers it's own and the
guards prevent anything from getting defined, but I've not tested it).

> My opinion is that the Clang headers should be used when possible.
> For one, it would fix this bug which cripples Clang when cross-compiling for other architectures.
> Also, supporting new versions of C (like C23) may need changes in both the compiler and headers. FreeBSD???s headers are certainly not being updated as regularly as LLVM???s.

Yes and no.  FreeBSD hasn't, for example, updated stdalign.h for C23, but
some headers require actual implementations in libc so we need to make those
updates ourselves at our own pace.

I think the argument of switching is strongest for things that are
always implemented as compiler builtins.  We'd have to test that we
could build the resulting system with gcc and possibly do a ports
exp-run to look for fallout.

I see no reason to switch iso646.h and varargs.h unless we're making a
wholesale move as both are files that should never be updated (except
maybe to be deleted in the far future).  On it's own it's change for
change sake.

Personally, I'd like us to eventually move away from a base system
compiler so I'd rather not tie the tree to clang's headers too much, but
that's a relatively week preference since I assume we'll continue to
ship a C++ runtime.

> Lastly, I don???t know what the benefit is of FreeBSD having its own copy of these.
> In a quick survey of the other OSes I use (Gentoo Linux, macOS Xcode and Homebrew), they all use LLVM???s header files.

The latter two are both pure-Clang environments so that makes sense, not
sure about Gentoo.

> An alternate option would be to leave the system headers in-place, but also install the Clang versions (e.g. both /usr/lib/clang/16/include/stdint.h and /usr/include/stdint.h would exist). This would work, but it would be confusing to have 2 versions of these files. GCC from ports includes its own iso646.h and varargs.h, and I believe Clang would also be using its own.

I'd like to fix the ports.  I'll see if I can at least reduce the list of
headers not being installed and document what's wrong with the others
so we can look at fixes.  If we get this sorted out then perhaps we can
also install more of them in /usr/lib/clang/##/include to make the
base compiler more useful for standalone environments.

TL;DR: I'm skeptical of a migration to clang headers, but it might be
the right thing in some cases.  I do want to fix the issue of having an
unusable standalone environment.  I'll try to make some progress on that
soon.

-- Brooks