Live data from Hacker News

C extensions, portability, and alternative compilers

lemon.rip

11–20 of 97 posts

Re: C extensions, portability, and alternative compilers

#11
post #2

One of my pet-peeves with C projects is that it's so often more or less "works on my machine" when written by Linux users (as a Windows and FreeBSD user it often hits you on both those platforms). The article highlights a typical piece: #if !(defined __GNUC__ || defined __clang__ || defined __TINYC__) # define __attribute__(xyz) /* Ignore */ #endif There is no reason that !defined check to not include a check for __a…

>One of my pet-peeves with C projects is that it's so often more or less "works on my machine"

“All the world's a VAX”

https://groups.google.com/g/comp.lang.c/c/CYgWkWdWCcQ/m/thMt...

https://www.lysator.liu.se/c/ten-commandments.html

Re: C extensions, portability, and alternative compilers

#12
post #2

One of my pet-peeves with C projects is that it's so often more or less "works on my machine" when written by Linux users (as a Windows and FreeBSD user it often hits you on both those platforms). The article highlights a typical piece: #if !(defined __GNUC__ || defined __clang__ || defined __TINYC__) # define __attribute__(xyz) /* Ignore */ #endif There is no reason that !defined check to not include a check for __a…

The preceding comment indicates that the intent is to support other compilers. I think a better approach is to define __glibc_attribute__ based on compiler support and to stick to that within glibc since there's no reason to think that another compiler's attributes have the same semantics as GNU C's.

Re: C extensions, portability, and alternative compilers

#13
post #7

What is the feasible way to test code against the matrix of compilers/oses?

And architectures. Probably a bunch of build servers or a swarm of docker, qemu, and VMs, with a good test coverage to detect behaviour differences.

In practice, the compiler is an often an omitted dependency of any c code.

Re: C extensions, portability, and alternative compilers

#14
For those who are making indie C compilers that don't pretend to be __GNUC__ but want to compile real world projects, slimcc's test script[1] and platform header hacks[2] might save you some time. [1] https://github.com/fuhsnn/slimcc/blob/main/scripts/linux_thi...

[2] https://github.com/fuhsnn/slimcc/blob/main/slimcc_headers/pl...

Some more fun stories:

- Game projects default to using SIMD so for example SDL and STB you always need to pass -DSDL_DISABLE_IMMINTRIN_H and -DSTB_NO_SIMD

- math.h's NAN usually fall back to (0.0f / 0.0f), which will print "-nan" with printf, some projects test suite fail because of it (they expected "nan").

- NetBSD's sys/cdefs.h straight up #error's if you don't pretend to be GCC or PCC.

- Some projects can't compile without __attribute__((always_inline)) because they use it on non-static functions.

- Many projects probe -fvisibility in the build system and pass -fvisibility=hidden to compile, but in the headers they gate __attribute__((visibility(default))) behind __GNUC__ checks, so you'll get missing symbols.

- Some projects use if(0) { undefined_function() } to fake static_assert(), there is even a bug report from QEMU to Clang because it failed to optimize in -O0 a certain `if` written this way.

- Even if you define __STDC_NO_VLA__, projects might fall back to alloca() code path that's untested and broken (python and jemalloc both had this problem, already reported)

- Valkey has broken __builtin_ctzll fallback nobody noticed (reported).

- Zig's C bootstrap path expects the compiler to have GCC/Clang-tier optimization and stack overflows if you don't (reported).

- I contributed stdatomic.h code path for Ruby just to compile it with slimcc, pretty sure it's still the only user of the code path.

- I implemented __has_extension in the hope that projects can use it to query gnu_asm; but SQLite broke because they use __has_extension(c_atomic) to query GNU atomics builtin, but c_atomic actually is meant for C11 _Atomic (IMO they should use __has_builtin)

Re: C extensions, portability, and alternative compilers

#15
Why would they not do something like?

  + #if !(defined __GLIBC_COMPILER_SUPPORTS_ATTRIBUTES__)
  - #if !(defined __GNUC__ || defined __clang__ || defined __TINYC__)
  # define __attribute__(xyz)     /* Ignore */
  #endif
(or probably a more fine grained for each attribute they try to use)

Considering such checks are fairly conventional in downstream C++ libraries based on compilers (for example checking OS platform or compiler, e.g. [Boost.Config](https://www.boost.org/doc/libs/latest/libs/config/). Modern C++ even went ahead and standardized this somewhat https://en.cppreference.com/cpp/utility/feature_test )

Re: C extensions, portability, and alternative compilers

#16
I just implemented a fast small compiler rcc to compete against tcc, and these glibc header quirks were simply fixed in the same way clang does it. By defining all gcc predefines and implementing all gcc extensions. Needed a day. And my headers are clean compared to glibc. The others in this league are slimcc, kefir and cproc. No other compilers can parse glibc headers. tcc has this special exception.

Re: C extensions, portability, and alternative compilers

#17
post #7

What is the feasible way to test code against the matrix of compilers/oses?

And architectures. Probably a bunch of build servers or a swarm of docker, qemu, and VMs, with a good test coverage to detect behaviour differences. In practice, the compiler is an often an omitted dependency of any c code.

I think I did not get to that level yet where I trust Claude to create its own VMs. But one day I will.

Re: C extensions, portability, and alternative compilers

#18
post #7

What is the feasible way to test code against the matrix of compilers/oses?

One approach for testing with multiple compilers that I use on some Fortran projects (where testing against multiple compilers seems more common than in C) is to use a variable from the command line to specify the compiler, for example:

    make FC=ifx check
On my Fortran projects, that will run the tests with Intel's Fortran compiler. The Makefile has logic to automatically change compiler flags as appropriate. I default to the GNU Fortran compiler, so `FC` isn't required.

I have made a script to run through a series of compilers by alternating between `make check` and `make clean`.

I have separate Makefiles for GNU Make and NMAKE/jom. My Fortran code works fine on various Linux distributions and Windows, though I'll add that achieving that is probably easier with Fortran than C. I've also tried a BSD Make that worked (on Ubuntu at least). My Makefiles are pretty close to the intersection of POSIX and NMAKE, so the main differences between the different Make versions are the conditional statements needed to handle the different compiler flags and the include statements (as I put the compiler flags in separate files).

Re: C extensions, portability, and alternative compilers

#19

Earlier quoted context omitted.

For a bunch of software categories there isn't really much point to support Windows at all these days. We've had "developed for unix, ported to Windows" software for a long time and it often doesn't work that well, because the agreement even for fairly basic stuff is not that large between the two.

1: My point isn't "developer on unix, ported to Windows", it's "developed on linux, maybe works elsewhere". 2: You could easily compile Samba yourself for FreeBSD in the past, last time I tried a new version it broke in what I remember being due to linux-isms (yes there is ports, but being reliant on older versions if ports maintainers can't keep up isn't a good thing). 3: The only "fairly basic" stuff that's hugely…

Exactly, the amount of patches needed in many FreeBSD or other BSD ports just to appease the Linux-centricity is bonkers. And many times the changes aren't even that grave.

Re: C extensions, portability, and alternative compilers

#20
post #7

What is the feasible way to test code against the matrix of compilers/oses?

Realistically, you don't aim to support every platform. You have a finite set of platforms you want to support. As the size of that set goes up, so does the probability it'll work on platforms unknown to you, but it's never 100%. Did you know some platforms have 32-bit char?
Post reply on HN