August 13

Hi all --

In writing my new script to make it easy to bootstrap GDC on any platform (https://github.com/ibara/gcc-bootstrap), I discovered that GDC does not build on FreeBSD 14. It's a bit too long to explain in a post, so here's the link to my blog post on the topic: https://briancallahan.net/blog/20250813.html

I don't think there's anything the D team can do about this one; the FreeBSD people will need to implement a proper solution. But it was interesting nonetheless, so I'm sharing it.

~Brian

August 14

On Wednesday, 13 August 2025 at 14:58:16 UTC, Brian Callahan wrote:

>

Hi all --

In writing my new script to make it easy to bootstrap GDC on any platform (https://github.com/ibara/gcc-bootstrap), I discovered that GDC does not build on FreeBSD 14. It's a bit too long to explain in a post, so here's the link to my blog post on the topic: https://briancallahan.net/blog/20250813.html

I don't think there's anything the D team can do about this one; the FreeBSD people will need to implement a proper solution. But it was interesting nonetheless, so I'm sharing it.

~Brian

You could fix it by removing pragma(mangle), as that is an abuse of the pragma. It's unlikely there's going to be any third party users of this internal module anyway.

If keeping a backwards compat version is really a must, I reckon you could implement it with a shim thunk/function instead.

static if (__FreeBSD_version >= 1400000)
{
    alias extern (C) int function(scope const void*, scope const void*, scope void*) Cmp;
    extern (C) void qsort_r(scope void* base, size_t nmemb, size_t size, Cmp cmp, scope void* thunk);

    // https://cgit.freebsd.org/src/tree/include/stdlib.h?h=stable/14#n350
    alias extern (C) int function(scope void*, scope const void*, scope const void*) OldCmp;

    deprecated("In FreeBSD 14, qsort_r's signature was fixed to match POSIX. This extern(D) overload has been " ~
               "provided to avoid breaking code, but code should be updated to use the POSIX version.")
    extern (D) void qsort_r(scope void* base, size_t nmemb, size_t size, scope void* thunk, OldCmp oldcmp)
    {
        static struct Wrap
        {
            void* thunk;
            OldCmp oldcmp;
        }
        auto wrap = Wrap(thunk, oldcmp);

        extern (C) int cmp(scope const void* p1, scope const void* p2, scope void* pwrap)
        {
            auto wrap = cast(Wrap*)pwrap;
            return wrap.oldcmp(wrap.thunk, p1, p2);
        }
        qsort_r(base, nmemb, size, &cmp, &wrap);
    }

    extern (C) void[] _adSort(return scope void[] a, TypeInfo ti)
    {
        extern (C) int cmp(scope const void* p1, scope const void* p2, scope void* ti)
        {
            return (cast(TypeInfo)ti).compare(p1, p2);
        }
        qsort_r(a.ptr, a.length, ti.tsize, &cmp, cast(void*)ti);
        return a;
    }
}