The trivial code ``` #include <inttypes.h> #include <stdint.h> #include <stdio.h> int main(const int argc, const char *argv[]) { uint32_t answer = 42; printf("%" PRId32 "\n", answer); return 0; } ``` fails to compile with clang17, clang18, clang19, when -ffreestanding is set ``` # env CC=clang19 CFLAGS=-ffreestanding make hello clang19 -ffreestanding hello.c -o hello In file included from hello.c:2: /usr/local/llvm19/lib/clang/19/include/stdint.h:261:25: error: typedef redefinition with different types ('int16_t' (aka 'short') vs '__int_fast16_t' (aka 'int')) 261 | typedef __int_least16_t int_fast16_t; | ^ /usr/include/sys/stdint.h:51:25: note: previous definition is here 51 | typedef __int_fast16_t int_fast16_t; | ^ In file included from hello.c:2: /usr/local/llvm19/lib/clang/19/include/stdint.h:262:26: error: typedef redefinition with different types ('uint16_t' (aka 'unsigned short') vs '__uint_fast16_t' (aka 'unsigned int')) 262 | typedef __uint_least16_t uint_fast16_t; | ^ /usr/include/sys/stdint.h:56:26: note: previous definition is here 56 | typedef __uint_fast16_t uint_fast16_t; | ^ In file included from hello.c:2: /usr/local/llvm19/lib/clang/19/include/stdint.h:280:24: error: typedef redefinition with different types ('int8_t' (aka 'signed char') vs '__int_fast8_t' (aka 'int')) 280 | typedef __int_least8_t int_fast8_t; | ^ /usr/include/sys/stdint.h:50:24: note: previous definition is here 50 | typedef __int_fast8_t int_fast8_t; | ^ In file included from hello.c:2: /usr/local/llvm19/lib/clang/19/include/stdint.h:281:25: error: typedef redefinition with different types ('uint8_t' (aka 'unsigned char') vs '__uint_fast8_t' (aka 'unsigned int')) 281 | typedef __uint_least8_t uint_fast8_t; | ^ /usr/include/sys/stdint.h:55:25: note: previous definition is here 55 | typedef __uint_fast8_t uint_fast8_t; | ^ 4 errors generated. *** Error code 1 ``` Other environments (e.g. Linux, Darwin) compile this code just fine with -ffreestanding. A real life project affected by this is e.g. libecc (https://github.com/libecc/libecc)
FreeBSD libc is by definition a provider of ANSI C/POSIX library interfaces for the hosted environment. It cannot work this way. If you want to use -ffreestanding, you at least must disallow use of the standard system compilation environment (includes etc), perhaps by using the -nostdinc option, at least.
Hi Konstantin, thank you for looking at this. I tend to read it differently: The ISO C standard defines (in clause 4) two classes of conforming implementation. A conforming hosted implementation supports the whole standard including all the library facilities; a conforming freestanding implementation is only required to provide certain library facilities: those in <float.h>, <limits.h>, <stdarg.h>, and <stddef.h>; since AMD1, also those in <iso646.h>; since C99, also those in <stdbool.h> and <stdint.h>; and since C11, also those in <stdalign.h> and <stdnoreturn.h>. In addition, complex types, added in C99, are not required for freestanding implementations. So since C99 it is ok to assume presence of and include stdint.h even with -ffreestanding. Clang starting with 17 implements C99. Also the standard says that a freestanding implementation _may_ not implement these headers, it does not say anything about it _must_ not implement them. Btw. just confirmed that NetBSD 10.1 can compile this as well. -nostdinc is unfortunately not a viable workaround. Please reconsider your assessment whether this is an issue with FreeBSD libc, or not. Thank you!
What do you propose to reconsider? The project goals? The project aims to provide the environment for executing unix programs, which are hosted by C std definition. That said, you do get the clang' project idea of freestanding environment when you specify -ffreestanding. But your 'trivial code' is not trivial, it uses a lot of facilities from the FreeBSD hosted environment which surprisingly to you do not mix with the clang' freestanding implementation. Either use only clang freestanding bits, or use only FreeBSD hosted env.
Looking at LLVM's stdint.h, it does an #include_next <stdint.h>, which presumably pulls in the FreeBSD header, causing the failure. Isn't that incorrect behaviour from LLVM when -ffreestanding is configured? Which toolchain(s) are you using on other systems?