mailing list of musl libc
 help / color / mirror / code / Atom feed
* [musl] Detect qsort_r() support with preprocessor
@ 2022-04-16  8:13 Nicholas Fraser
  2022-04-16 12:01 ` Markus Wichmann
  0 siblings, 1 reply; 11+ messages in thread
From: Nicholas Fraser @ 2022-04-16  8:13 UTC (permalink / raw)
  To: musl

Hello musl devs,

qsort_r() has been added to musl 1.2.3 and it has been backported to the previous version of musl in Alpine. How can I detect whether this function is available using the preprocessor?

The community wiki advocates "testing" for feature support, which I guess means compiling a test program like an autotools configure script. Can we not just test for a macro instead? Have you considered defining something like `__HAS_QSORT_R` to tell us directly that you support it?

I am writing a cross-platform header-only library. I want my users to be able to just drop the header files of my library into their codebase. I really don't want them to have to write their own configure tests just to tell my library whether musl provides qsort_r(). I am able to detect variants of qsort_r() or qsort_s() with the preprocessor on all other platforms that support such an extension. Is there a way to detect it with musl?

Nick


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [musl] Detect qsort_r() support with preprocessor
  2022-04-16  8:13 [musl] Detect qsort_r() support with preprocessor Nicholas Fraser
@ 2022-04-16 12:01 ` Markus Wichmann
  2022-04-16 14:16   ` Quentin Rameau
  0 siblings, 1 reply; 11+ messages in thread
From: Markus Wichmann @ 2022-04-16 12:01 UTC (permalink / raw)
  To: musl

On Sat, Apr 16, 2022 at 04:13:56AM -0400, Nicholas Fraser wrote:
> Hello musl devs,
>
> qsort_r() has been added to musl 1.2.3 and it has been backported to
> the previous version of musl in Alpine. How can I detect whether this
> function is available using the preprocessor?
>
> The community wiki advocates "testing" for feature support, which I
> guess means compiling a test program like an autotools configure
> script.

Guess why that is. It is more portable to do that way than to define new
non-standard macros. The only macros musl will define are standard ones.

> Can we not just test for a macro instead? Have you considered
> defining something like `__HAS_QSORT_R` to tell us directly that you
> support it?
>

Unless qsort_r() were part of a new release of POSIX (then you could
look at _POSIX_VERSION), or a member of an option group (then you could
look at the option group macro), not really. If musl had a bespoke
symbol, it would just diverge. Then musl would have its macro, glibc
another one, OpenBSD would do a totally different thing again, and in
the end you get a leaning tower of hostname (look it up).

Plus, adding such a symbol would then basically mean it could never be
retracted again. Keep going in that direction for a decade and you get a
mess of non-standard symbols to keep track of.

> I am writing a cross-platform header-only library. I want my users to
> be able to just drop the header files of my library into their
> codebase. I really don't want them to have to write their own
> configure tests just to tell my library whether musl provides
> qsort_r().

It's not supposed to be just for musl. Doing a configure test would
correctly detect it in all configurations. Why not have a "config.h",
containing all the switches? If set wrong, it just won't compile. If set
right, it will compile on platforms you never even heard of.

In case of pure computations like qsort_r(), there is also the
possibility of the client code remedying a lacking implementation by
providing the extension itself, which a version based approach will not
detect correctly.

> I am able to detect variants of qsort_r() or qsort_s() with
> the preprocessor on all other platforms that support such an
> extension.

I highly doubt glibc for example provides a special symbol for qsort_r()
alone, so I am guessing you are querying version numbers. Which of
course fails in the face of backporting, and in case of new
implementations. Whereas just writing a compile test will not.

Ciao,
Markus

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [musl] Detect qsort_r() support with preprocessor
  2022-04-16 12:01 ` Markus Wichmann
@ 2022-04-16 14:16   ` Quentin Rameau
  2022-04-16 17:50     ` Nicholas Fraser
  0 siblings, 1 reply; 11+ messages in thread
From: Quentin Rameau @ 2022-04-16 14:16 UTC (permalink / raw)
  To: musl

Hi,

> > Hello musl devs,
> >
> > qsort_r() has been added to musl 1.2.3 and it has been backported to
> > the previous version of musl in Alpine. How can I detect whether this
> > function is available using the preprocessor?
> >
> > The community wiki advocates "testing" for feature support, which I
> > guess means compiling a test program like an autotools configure
> > script.
> 
> Guess why that is. It is more portable to do that way than to define new
> non-standard macros. The only macros musl will define are standard ones.
> 
> > Can we not just test for a macro instead? Have you considered
> > defining something like `__HAS_QSORT_R` to tell us directly that you
> > support it?
> >
> 
> Unless qsort_r() were part of a new release of POSIX (then you could
> look at _POSIX_VERSION), or a member of an option group (then you could
> look at the option group macro), not really.

Just as a note, qsort_r() has indeed been added to POSIX-next, so you'd
only need to ask for _POSIX_C_SOURCE with a value of 20XXXX, when it's
actually been released.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [musl] Detect qsort_r() support with preprocessor
  2022-04-16 14:16   ` Quentin Rameau
@ 2022-04-16 17:50     ` Nicholas Fraser
  2022-04-16 18:42       ` Quentin Rameau
  2022-04-17  2:04       ` Rich Felker
  0 siblings, 2 replies; 11+ messages in thread
From: Nicholas Fraser @ 2022-04-16 17:50 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 4015 bytes --]

On 2022-04-16 08:01, Markus Wichmann wrote:

 > Unless qsort_r() were part of a new release of POSIX (then you could
 > look at _POSIX_VERSION), or a member of an option group (then you could
 > look at the option group macro), not really. If musl had a bespoke
 > symbol, it would just diverge. Then musl would have its macro, glibc
 > another one, OpenBSD would do a totally different thing again, and in
 > the end you get a leaning tower of hostname (look it up).

All of those other platforms define symbols like __GLIBC__ and __OpenBSD__.
They make it easy to detect things with the preprocessor. FreeBSD in particular
publishes an exhaustive list of all possible values of __FreeBSD_version and
what symbols they change or introduce:

https://docs.freebsd.org/en/books/porters-handbook/versions/

It's pointless to use a configure script to detect qsort_r() on any other
platform because we can detect it just fine with the preprocessor by using
these symbols.

Assuming you're referring to "#ifdef Considered Harmful", sorry but a 30 year
old paper arguing against the use of #ifdef is not convincing. This paper
predates proper function inlining optimizations. It's arguing against littering
your code with #ifdefs, whereas now we know we can make zero-overhead wrapper
functions to keep the portability separate from the rest of our code.

 > Plus, adding such a symbol would then basically mean it could never be
 > retracted again. Keep going in that direction for a decade and you get a
 > mess of non-standard symbols to keep track of.

You wouldn't need a bunch of different symbols if you just defined __MUSL__.
Nobody is going to remove qsort_r() from their copy of musl so as long as we
know the minimum version in which it's available we'd know it's safe to use it.

It doesn't have to be perfect either by the way. As long as it works in most
cases we can autodetect those and let users manually configure the rest.

 > It's not supposed to be just for musl. Doing a configure test would
 > correctly detect it in all configurations. Why not have a "config.h",
 > containing all the switches? If set wrong, it just won't compile. If set
 > right, it will compile on platforms you never even heard of.

I don't need a config.h for any other platform. I can autodetect things with
the preprocessor everywhere except musl. Why should I add one just for musl?

You're not considering the growing number of simple header-only libraries for
C. Think of the stb libraries for example:

https://github.com/nothings/stb

These are single-file header-only libraries. Nobody wants to write a configure
script for them. Nobody wants to install them into /usr/include. They want to
drop the header file into their project and have it "just work". This is
possible on every platform except musl.

You know configure scripts aren't necessary in any other programming language
right? No other language requires the use test compilation to determine the
capabilities of the platform. Other programming languages have facilities to
tell you what's available within the language itself. So does C, by the way, if
you would only just *tell us* with the preprocessor what's available.

On 2022-04-16 10:16, Quentin Rameau wrote:
 > Just as a note, qsort_r() has indeed been added to POSIX-next, so you'd
 > only need to ask for _POSIX_C_SOURCE with a value of 20XXXX, when it's
 > actually been released.

Well that doesn't help me today. But even if it did, GCC and Clang don't define
_POSIX_C_SOURCE automatically. Under glibc it's only defined under -std=gnu*,
not -std=c*, and under musl (Alpine) it doesn't appear to be defined either
way.

Like I said, I don't control the compiler flags with which my users will
compile my library. If I can reliably detect with the preprocessor whether the
platform has a qsort_r() function, I can use it regardless of whether the
headers actually declare it because I can just declare it myself locally in a
wrapper function. This works on every platform except musl.

Nick

[-- Attachment #2: Type: text/html, Size: 5447 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [musl] Detect qsort_r() support with preprocessor
  2022-04-16 17:50     ` Nicholas Fraser
@ 2022-04-16 18:42       ` Quentin Rameau
  2022-04-16 23:59         ` Nicholas Fraser
  2022-04-17  2:04       ` Rich Felker
  1 sibling, 1 reply; 11+ messages in thread
From: Quentin Rameau @ 2022-04-16 18:42 UTC (permalink / raw)
  To: musl

Hi Nicholas,

> On 2022-04-16 10:16, Quentin Rameau wrote:
>  > Just as a note, qsort_r() has indeed been added to POSIX-next, so you'd
>  > only need to ask for _POSIX_C_SOURCE with a value of 20XXXX, when it's
>  > actually been released.  
> 
> Well that doesn't help me today. But even if it did, GCC and Clang don't define
> _POSIX_C_SOURCE automatically. Under glibc it's only defined under -std=gnu*,
> not -std=c*, and under musl (Alpine) it doesn't appear to be defined either
> way.

Indeed, that isn't something that the compiler should define for the
application, it's for the application to request it.

> Like I said, I don't control the compiler flags with which my users will
> compile my library.

You actually do, or at least should.
It's ok to have requirements about a software to work, usually
dependencies, but requiring a standard (as in POSIX) environment is
regular and totally legitimate.

If your users decide to break your application expectations, then they
must have good reasons for it and should deal with it.

> If I can reliably detect with the preprocessor whether the
> platform has a qsort_r() function

That is the point, you cannot in the way you're going at it (until
POSIX-next is released).

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [musl] Detect qsort_r() support with preprocessor
  2022-04-16 18:42       ` Quentin Rameau
@ 2022-04-16 23:59         ` Nicholas Fraser
  0 siblings, 0 replies; 11+ messages in thread
From: Nicholas Fraser @ 2022-04-16 23:59 UTC (permalink / raw)
  To: musl

On 2022-04-16 14:42, Quentin Rameau wrote:

 > > Like I said, I don't control the compiler flags with which my users will
 > > compile my library.
 >
 > You actually do, or at least should.
 > It's ok to have requirements about a software to work, usually
 > dependencies, but requiring a standard (as in POSIX) environment is
 > regular and totally legitimate.
 >
 > If your users decide to break your application expectations, then they
 > must have good reasons for it and should deal with it.

But my software doesn't actually have such a requirement in reality. Why should
I need to add a requirement about language standards just because you won't
give us any in-language way to detect qsort_r()? My users should not need to
worry about low-level things like whether they've defined _GNU_SOURCE or
_POSIX_C_SOURCE just to use my code.

Besides, why do you equate having a requirement with having to configure it
manually? Why can't it just detect automatically with the preprocessor whether
its requirements are met? Again, no manual configuration is necessary on any
other platform.

Note that my library doesn't even have qsort_r() as a requirement. I have a
fallback but I would prefer to use what's available on the platform. This is
why it's especially important for the configuration to be automatic: if the
configuration is manual and they don't configure it properly it will still work
but with suboptimal code. This is just as error-prone as any of your
hypothetical failure cases with __MUSL__.

Header-only configure-free libraries are specifically designed not to impose
compiler flags or other requirements on their users. That is in fact the whole
point, to not force users to build it in a special way and instead let them
build it the same way as the rest of their code simply by #including it. For my
libraries in particular, I go to great lengths to test that they compile
cleanly under a wide variety of compiler flags on many different platforms so
that users don't need to think about any of this stuff in order to use the
code.

 > > If I can reliably detect with the preprocessor whether the
 > > platform has a qsort_r() function
 >
 > That is the point, you cannot in the way you're going at it (until
 > POSIX-next is released).

You're confusing theory with practice. Of course I won't be able detect it on
some theoretically perfect POSIX libc, but I don't care, because no such libc
exists. I care about what works in practice. In practice, I can quite reliably
detect qsort_r() with the preprocessor everywhere but musl.

musl is certainly not that theoretically perfect POSIX libc by the way. For one
thing, you have qsort_r(), and it's under _GNU_SOURCE. Surely you've merged it
not for theoretical reasons, but because you actually want people to use it?

Nick


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [musl] Detect qsort_r() support with preprocessor
  2022-04-16 17:50     ` Nicholas Fraser
  2022-04-16 18:42       ` Quentin Rameau
@ 2022-04-17  2:04       ` Rich Felker
  2022-04-19  3:38         ` Nicholas Fraser
  1 sibling, 1 reply; 11+ messages in thread
From: Rich Felker @ 2022-04-17  2:04 UTC (permalink / raw)
  To: Nicholas Fraser; +Cc: musl

On Sat, Apr 16, 2022 at 01:50:06PM -0400, Nicholas Fraser wrote:
> On 2022-04-16 08:01, Markus Wichmann wrote:
> 
> > Unless qsort_r() were part of a new release of POSIX (then you could
> > look at _POSIX_VERSION), or a member of an option group (then you could
> > look at the option group macro), not really. If musl had a bespoke
> > symbol, it would just diverge. Then musl would have its macro, glibc
> > another one, OpenBSD would do a totally different thing again, and in
> > the end you get a leaning tower of hostname (look it up).
> 
> All of those other platforms define symbols like __GLIBC__ and __OpenBSD__.

Those do not tell you what you want to know: whether a particular
interface is supported. They tell you a particular implementation name
and version, which then requires you to have massive amounts of
hard-coded knowledge about every platform you support, and to fail to
support any platform you don't know about. This practice belongs back
in the 1980s, not the 2020s.

> It's pointless to use a configure script to detect qsort_r() on any other
> platform because we can detect it just fine with the preprocessor by using
> these symbols.

No, it's not. If there were a standard or widely agreed upon macro
that indicated "qsort_r is present and has the signature and semantics
you expect it to have", that would make it possible to detect. But no
such macro exists. I've tried to push forward an effort for defining
an analog of the unistd.h macros POSIX defines, but for
non-standardized but moderately to widely cross-platform extensions,
but nothing has come of that so far. The existing proposal discussion
is in the libc-coord list.

Until that happens, *detecting* in a configure-style manner is the
only way to do this. musl absolutely will not support the practice of
hard-coding assumptions about the implementation.

> [long rant of wrong stuff I did not read]

...

Rich

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [musl] Detect qsort_r() support with preprocessor
  2022-04-17  2:04       ` Rich Felker
@ 2022-04-19  3:38         ` Nicholas Fraser
  2022-04-19  6:59           ` Markus Wichmann
  2022-04-19 13:32           ` Rich Felker
  0 siblings, 2 replies; 11+ messages in thread
From: Nicholas Fraser @ 2022-04-19  3:38 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

On 2022-04-16 22:04, Rich Felker wrote:
 > On Sat, Apr 16, 2022 at 01:50:06PM -0400, Nicholas Fraser wrote:
 >> [long rant of wrong stuff I did not read]

It's very sad that you're not interested in hearing the problem, and that you
ignore the growing number of single-file and/or header-only libraries in C.
Here's a long list of them:

     https://github.com/nothings/single_file_libs

None of these libraries come with configure scripts. That is in fact the whole
point. They're distributed as just source code. There is no reason why plain C
source code can't be decently portable entirely on its own without any need
for configure scripts. You are just refusing to help us make it work. Yes, it's
great that you're trying to standardize macros for it, but what are we supposed
to do in the meantime? You seem more interested in adhering to standards than
in making working software.

I'm going to try to explain my use case in more detail to hopefully give you
some perspective on how this works everywhere else and why it doesn't work on
musl. If you truly don't care then feel free to ignore this email, but know
that you're ignoring a very real use case for a lot of people beyond me and my
little library.

Just to recap: I'm writing a header-only library. My intention is for users to
just put the headers on their include path and use it, no configuration needed.
I'd like to use any variation of qsort_r()/qsort_s() that's available on the
platform.

GNU/musl/POSIX-next qsort_r() and C11 Annex K qsort_s() are virtually the
same; Free/Net/DragonFlyBSD and Apple qsort_r() are the same; and Windows
qsort_s() is the outlier. There are only three possible prototypes so it's
trivial for my code to permute the arguments to match what's available. All I
need to do is detect which one the platform has.

I won't say "I can detect", because then you'll say "No you can't" even though
it works fine, and we'll just go in circles telling each other we're wrong.
Instead I'll say "I am detecting".

I am detecting glibc and uClibc's qsort_r() with `#ifdef __GLIBC__`. I am
detecting Windows qsort_s() with `#ifdef WIN32`. I am detecting macOS and iOS
qsort_r() with `#ifdef __APPLE__`. I am detecting the BSDs with `#ifdef
__FreeBSD__`, `#ifdef __NetBSD__`, etc. I am detecting C11 Annex K qsort_s()
with __STDC_LIB_EXT1__ and other platform macros (e.g. __FreeBSD__.)

In cases where the headers declare it conditionally, I simply declare it myself
so that my users don't need to define _GNU_SOURCE or __STDC_WANT_LIB_EXT1__ or
whatever:

     static inline
     void mylib_qsort_r(...) {
         extern void qsort_r(...);
         qsort_r(...);
     }

This actually works in practice. It imposes no requirements or restrictions on
how users compile my code. There is zero configuration, zero scripts to run,
zero manual steps to make it work on 99.9% of platforms in existence. I don't
need it to work on some platform I've never heard of because the odds of
someone trying to use my code on such a platform are very low, but if they ever
do, the first person who tries can just send me a patch to add support for it.
We know this same strategy will work there too because every other platform in
existence declares who they are or what features they have with macros.

This strategy works everywhere *except musl*. These are the options you've
given me to make my header-only library work on musl:

a) Add a configure script to my library. Make my users run the configure
    script, possibly execute the tests on target when cross-compiling (probably
    not necessary for qsort_r() but definitely for other features), and cache or
    install the result somewhere along with my library. (Multiply this step by
    every library they use times every platform they support.)

b) Make all users of my library either write their own configure script to
    detect musl qsort_r() and emit a config.h, or make them write this config.h
    manually, and have my library include it. (But, I can't `#include
    "config.h"` only on musl because you won't tell me you're musl, so this
    config.h becomes an added requirement on *all platforms* even though on
    every other platform it will be blank.)

c) Use my fallback, which is in fact an entire implementation of `qsort_r()`,
    intended only for platforms that don't have one. This is of course the most
    attractive option because it's the only one that doesn't add a configuration
    burden on my users. Remind me, why did you bother implementing qsort_r()
    again? Because the best option you've left me with is the one where I ignore
    it.

Is this really what you want the future of C programming to be like? You want
every little piece of source code to have a configure script attached to it to
probe the platform, or have a bunch of manual configuration steps just to
figure out what the platform already knows but won't tell us? Are all of musl's
features secrets we have to tease out with these out-of-language hacks?

Nick


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [musl] Detect qsort_r() support with preprocessor
  2022-04-19  3:38         ` Nicholas Fraser
@ 2022-04-19  6:59           ` Markus Wichmann
  2022-04-19 23:10             ` Nicholas Fraser
  2022-04-19 13:32           ` Rich Felker
  1 sibling, 1 reply; 11+ messages in thread
From: Markus Wichmann @ 2022-04-19  6:59 UTC (permalink / raw)
  To: musl; +Cc: Nicholas Fraser

This will likely be pointless, but I'll try once more.

On Mon, Apr 18, 2022 at 11:38:49PM -0400, Nicholas Fraser wrote:
> It's very sad that you're not interested in hearing the problem, and that you
> ignore the growing number of single-file and/or header-only libraries in C.
> Here's a long list of them:
>
>     https://github.com/nothings/single_file_libs
>

No, YOU are not interested in hearing the reasons for why what you want
is bad and leads to technical debt. There is no reason why single
file libraries should not have a config section at the top or something.
The only alternative left to you is to use standards that are definitely
supported. Since Windows/MSVC is on the list of platforms you wish to
support, that means C89. And ONLY C89. Good luck with that.

> None of these libraries come with configure scripts. That is in fact the whole
> point. They're distributed as just source code. There is no reason why plain C
> source code can't be decently portable entirely on its own without any need
> for configure scripts. You are just refusing to help us make it work. Yes, it's
> great that you're trying to standardize macros for it, but what are we supposed
> to do in the meantime? You seem more interested in adhering to standards than
> in making working software.
>

That last one has been floated before and just does not fly. You have
been pointed in the direction of something to make it work reliably
everywhere and refuse to use that solution because apparently you think
running a script or writing a 0 or 1 into a single line of configuration
is undue burden on programmers who already cannot be arsed to do their
job. But making Rich maintain a growing list of macros somehow is not.

See, this is what I don't get: Your target audience is programmers, not
end users. Can they not be expected to fill in a configuration once?
They will already have to expend some effort integrating your library
into their programs, anyway, so it hardly changes things.

Indeed there is no reason for plain C being unportable. But the only way
to really make it portable is to refuse to use any feature beyond the
lowest common denominator, which is usually going to be C89. So, no
qsort_r() for you.

The alternative is to maintain a growing list of assumptions about
implementations, each of which may turn around next release without
warning. Or, you know, your source code can grow out of date.

> Just to recap: I'm writing a header-only library. My intention is for users to
> just put the headers on their include path and use it, no configuration needed.

Then maybe that's a bad intention. The only way to do that with the list
of platforms you added later is to not go beyond C89.

>
> I won't say "I can detect", because then you'll say "No you can't" even though
> it works fine, and we'll just go in circles telling each other we're wrong.
> Instead I'll say "I am detecting".
>

And here the boy who cried "you're not listening" goes on to not listen
himself.

> I am detecting glibc and uClibc's qsort_r() with `#ifdef __GLIBC__`. I am
> detecting Windows qsort_s() with `#ifdef WIN32`. I am detecting macOS and iOS
> qsort_r() with `#ifdef __APPLE__`. I am detecting the BSDs with `#ifdef
> __FreeBSD__`, `#ifdef __NetBSD__`, etc. I am detecting C11 Annex K qsort_s()
> with __STDC_LIB_EXT1__ and other platform macros (e.g. __FreeBSD__.)
>

And you listed all of that stuff with a straight face. didn't you? The
only standard macro in all of these is __STDC_LIB_EXT1__, an admittedly
rarely used one. What about newlib? newlib is the C implementation
underlying much of Cygwin, which last I checked was still pretty
popular. At least I use it regularly. And you can get it to define
WIN32, but it doesn't have qsort_s(). But it has both versions of
qsort_r().

Anyway, what do you want? Imagine if there was a __MUSL__ macro, and had
been there last version already. That would mean that the presence of
__MUSL__ tells you nothing about whether qsort_r() is supported. So you
would need __MUSL_VERSION__ or something.  But then Alpine went ahead
and backported it to earlier versions. So there are versions of musl
1.2.2 out there with qsort_r() and those without it. So again, the macro
you are begging for would not tell you what you want to know.

So what you would want is __MUSL_HAS_QSORT_R__, which for a growing list
of standard extensions is obviously untennable. If instead you just
tested the environment once, you could do it dynamically for all
possible C implementations.

Or you wait for the next version of POSIX to come out and test the POSIX
version macros. That means there will be C libraries with the function
you want but not declaring support for them, but then, such is life.

> In cases where the headers declare it conditionally, I simply declare it myself
> so that my users don't need to define _GNU_SOURCE or __STDC_WANT_LIB_EXT1__ or
> whatever:
>
>     static inline
>     void mylib_qsort_r(...) {
>         extern void qsort_r(...);
>         qsort_r(...);
>     }
>
> This actually works in practice. It imposes no requirements or restrictions on
> how users compile my code.

I'm pretty sure it won't work on OS-9. That would be a restriction.

> There is zero configuration, zero scripts to run,
> zero manual steps to make it work on 99.9% of platforms in existence. I don't
> need it to work on some platform I've never heard of because the odds of
> someone trying to use my code on such a platform are very low, but if they ever
> do, the first person who tries can just send me a patch to add support for it.
> We know this same strategy will work there too because every other platform in
> existence declares who they are or what features they have with macros.
>

No, they don't declare who they are. They declare who they are
emulating. clang defines __GNUC__, uclibc defines __GLIBC__, and why?
Because people like you cannot be bothered to run configure tests for
the features you want.

> c) Use my fallback, which is in fact an entire implementation of `qsort_r()`,
>    intended only for platforms that don't have one. This is of course the most
>    attractive option because it's the only one that doesn't add a configuration
>    burden on my users

Well, you took the long way around, but arrived at the correct
conclusion. Especially in the case of qsort_r(), the only thing that
reliably works on all platforms is to implement it yourself in the
absence of standard macros. Since you are already doing that, just
always using that implementation is less code than whatever harnesses
around qsort_r() and qsort_s() you have built. And less code is usually
less bad.

>. Remind me, why did you bother implementing qsort_r()
>    again? Because the best option you've left me with is the one where I ignore
>    it.
>

The best option for you and your highly specific and, frankly,
counterintuitive requirements, that have programmers integrate a library
but not able to write a config header.

> Is this really what you want the future of C programming to be like? You want
> every little piece of source code to have a configure script attached to it to
> probe the platform, or have a bunch of manual configuration steps just to
> figure out what the platform already knows but won't tell us? Are all of musl's
> features secrets we have to tease out with these out-of-language hacks?
>

What do you mean "future"? At this time you already only have two
sort-of reliable ways to detect standard extensions: Either test for
them, and due to the fluid nature of many libraries, that means test for
the actual interface, not implementation name and version, or else wait
for it to be standardized and test for standard macros. The former finds
all implementations but requires compile-time configuration, the always
works but fails to find some implementations. You have to die some way,
so choose.

Ciao,
Markus

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [musl] Detect qsort_r() support with preprocessor
  2022-04-19  3:38         ` Nicholas Fraser
  2022-04-19  6:59           ` Markus Wichmann
@ 2022-04-19 13:32           ` Rich Felker
  1 sibling, 0 replies; 11+ messages in thread
From: Rich Felker @ 2022-04-19 13:32 UTC (permalink / raw)
  To: Nicholas Fraser; +Cc: musl

On Mon, Apr 18, 2022 at 11:38:49PM -0400, Nicholas Fraser wrote:
> Just to recap: I'm writing a header-only library. My intention is for users to
> just put the headers on their include path and use it, no configuration needed.
> I'd like to use any variation of qsort_r()/qsort_s() that's available on the
> platform.
> 
> GNU/musl/POSIX-next qsort_r() and C11 Annex K qsort_s() are virtually the
> same; Free/Net/DragonFlyBSD and Apple qsort_r() are the same; and Windows
> qsort_s() is the outlier. There are only three possible prototypes so it's
> trivial for my code to permute the arguments to match what's available. All I
> need to do is detect which one the platform has.

This would be a great usage case for the "Macro-based advertisement of
libc extensions" proposal on libc-coord. The right thing to do here is
to try to move that forward, explaining how it solves your problem.
I'll try to revitalize that.

> In cases where the headers declare it conditionally, I simply declare it myself
> so that my users don't need to define _GNU_SOURCE or __STDC_WANT_LIB_EXT1__ or
> whatever:

You cannot #define _GNU_SOURCE or __STDC_WANT_LIB_EXT1__ after any
standard header has already been included. The only place they can
safely be defined is at the top of the source file before any headers,
or on the command line with -D. There are two reasons for this: one is
that the rules say so (both POSIX and glibc document this, in addition
to musl). The other more mechanical reason is that the header you're
trying to get the definitions from might already have been included
(directly or indirectly) earlier, whereby the multiple-inclusion guard
prevents it from exposing anything else the second time it's included.
This extends to the case where the FTMs are actually processed by a
unified file (like features.h) into internal-use-only macros on the
first inclusion of any standard heaader. For this reason, it's
possible that even headers which weren't already included once will
still fail to see the updated FTMs.

So, defining these from a header-only library is an on-starter unless
you impose a requirement on the caller that they must include your
header absolute-first (and then they can only use one such header-only
library). An approach that actually works is just documenting that the
caller must ensure they're defined appropriately for features they
want your library to be able to use. Or, just being compatible with
whatever choice the caller made (so using your own fallback or
whatever if it's not exposed).

Rich

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [musl] Detect qsort_r() support with preprocessor
  2022-04-19  6:59           ` Markus Wichmann
@ 2022-04-19 23:10             ` Nicholas Fraser
  0 siblings, 0 replies; 11+ messages in thread
From: Nicholas Fraser @ 2022-04-19 23:10 UTC (permalink / raw)
  To: musl

Thanks for the replies. I'm a bit surprised to hear you agree that, given my
requirements, I should ignore your features and re-implement them myself.
Beyond that it looks like we won't find common ground.

I'll just take the opportunity to clarify a few things:

On 2022-04-19 02:59, Markus Wichmann wrote:
 > Since Windows/MSVC is on the list of platforms you wish to
 > support, that means C89. And ONLY C89. Good luck with that.

You may be interested to learn that Microsoft has had full C99 support (minus
those features made optional in C11) since VS 2015. This is the oldest version
of the VS tools still supported. More recently, VS 2019 supports nearly all
of C11 (including a conforming preprocessor.)

Even before that, it was easy to make well-written C99 compile as C++ to work
under Microsoft's compiler. Compiling as C++ is a virtual necessity for a
header-only library anyway.

 > I'm pretty sure it won't work on OS-9. That would be a restriction.

I think this is the main source of our disagreement. You seem very concerned
that my strategy won't work on platforms I've never heard of, and that if it's
not perfect, it's useless.

I do provide my users the option to manually override whatever I detect in case
it's wrong. I'm just trying to detect as much as I can to make it easier for
them. It's okay if it only works 90% of the time, and the remaining 10%
requires manual configuration. I believe it will be more like >99% though, and
I had hoped musl would want to be part of that >99%.

 > So you
 > would need __MUSL_VERSION__ or something.  But then Alpine went ahead
 > and backported it to earlier versions. So there are versions of musl
 > 1.2.2 out there with qsort_r() and those without it. So again, the macro
 > you are begging for would not tell you what you want to know.

For the record I didn't ask for __MUSL_VERSION__. I asked for __HAS_QSORT_R.

I asked this for exactly this reason, because I've been testing on Alpine and
noticed they backported it. I only brought up __MUSL__ in comparison to what
works for me on other platforms. We all agree that a standard macro like
__HAS_QSORT_R would be a better solution but it will take a decade for this to
get standardized.

In any case, even if a version macro doesn't detect backported features, that's
not a big deal. It's a temporary problem that will solve itself. This is
another case of perfect being the enemy of good.

 > So what you would want is __MUSL_HAS_QSORT_R__, which for a growing list
 > of standard extensions is obviously untennable.

This isn't obvious at all. I can't imagine what is so untenable about putting
a simple #define next to each extension function you support.

 From my perspective, I think what is obvious is that you want to hide the fact
that the implementation is musl, and you are opposed to macros like this simply
because they could be used to reveal that you're musl.

On 2022-04-19 09:32, Rich Felker wrote:
 > You cannot #define _GNU_SOURCE or __STDC_WANT_LIB_EXT1__ after any
 > standard header has already been included.

Yes, I know that of course (give me a little credit here.) Maybe I was unclear.
I'm not defining _GNU_SOURCE or whatever. I'm declaring the actual libc
function I want to link against within the scope of my wrapper function that
calls it. That's what the snippet of code I showed does. Ultimately I'm
targeting the ABI, not the headers, which is why I make it work regardless of
_GNU_SOURCE and such.

Nick


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2022-04-19 23:10 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-16  8:13 [musl] Detect qsort_r() support with preprocessor Nicholas Fraser
2022-04-16 12:01 ` Markus Wichmann
2022-04-16 14:16   ` Quentin Rameau
2022-04-16 17:50     ` Nicholas Fraser
2022-04-16 18:42       ` Quentin Rameau
2022-04-16 23:59         ` Nicholas Fraser
2022-04-17  2:04       ` Rich Felker
2022-04-19  3:38         ` Nicholas Fraser
2022-04-19  6:59           ` Markus Wichmann
2022-04-19 23:10             ` Nicholas Fraser
2022-04-19 13:32           ` Rich Felker

Code repositories for project(s) associated with this inbox:

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).