This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: RFC: handling ISO C feature test macros
- From: Joseph Myers <joseph at codesourcery dot com>
- To: Roland McGrath <roland at hack dot frob dot com>
- Cc: <libc-alpha at sourceware dot org>
- Date: Thu, 2 Jun 2016 22:29:05 +0000
- Subject: Re: RFC: handling ISO C feature test macros
- Authentication-results: sourceware.org; auth=none
- References: <alpine dot DEB dot 2 dot 20 dot 1605202135440 dot 24104 at digraph dot polyomino dot org dot uk> <20160528030332 dot E4DD12C3D10 at topped-with-meat dot com>
On Fri, 27 May 2016, Roland McGrath wrote:
> The original intent of features.h was that it and only it would ever
> need to know the complex interdependencies between feature-test sets.
> Each conditional around an actual declaration can have a very simple
> #if test on exactly one fine-grained set. In the early days, this was
> actually completely true (modulo some __FAVOR_BSD complexities). We
> have drifted away from the ideal over the years and now have over 300
> cases of "#if defined __USE_THIS || defined __USE_THAT" and the like.
I don't think "defined __USE_THIS || defined __USE_THAT" is a matter of
"complex interdependencies between feature-test sets" in the wrong place.
Rather, it accurately reflects the overlapping nature of the APIs in
different sources, "this API was added as XSI in POSIX version A, then
entered non-XSI POSIX in version B" etc.
> from the de facto API. The upshot here is that new stuff should avoid
> friendly-seeming header file names like <features-iso.h> and instead do
> something that is very hard to misconstrue as anything other than
> internal implementation details that nobody outside libc's own headers
> should ever be using.
Well, you could do e.g.
#define __GLIBC_INTERNAL_STARTING_HEADER_IMPLEMENTATION
#include <bits/glibc-header-start.h>
where <bits/glibc-header-start.h> gives an error if
__GLIBC_INTERNAL_STARTING_HEADER_IMPLEMENTATION is not defined, then
undefines it.
> Fortunately for the "test exactly one set" principle, the new ISO C
> feature-test sets seem to come in small, fine-grained, non-overlapping
> sets to begin with. This should make it easy to use something like:
>
> #if __GLIBC_USE (IEC_60559_BFP_EXT)
> declare issignaling
> #endif
That gets more complicated when you involve TS 18661-3 and TS 18661-4.
TS 18661-4 involves defining new functions (such as exp10, which glibc
already has) if __STDC_WANT_IEC_60559_FUNCS_EXT__. That's for the
existing C types of float, double, long double. For new types such as
_Float128 from TS 18661-3, both __STDC_WANT_IEC_60559_TYPES_EXT__ (the
macro from TS 18661-3) and __STDC_WANT_IEC_60559_FUNCS_EXT__ need to be
defined.
That's fairly conveniently orthogonal - the __GLIBC_USE
(IEC_60559_TYPES_EXT) conditional would go in math.h, so that it would
only ever include <bits/mathcalls.h> for _Float128 in the
__STDC_WANT_IEC_60559_TYPES_EXT__ case (like the existing __USE_ISOC99
conditional for declaring float and long double), while <bits/mathcalls.h>
would contain the __GLIBC_USE (IEC_60559_FUNCS_EXT) call around the exp10
declaration. But now bring in TS 18661-1. If
__STDC_WANT_IEC_60559_TYPES_EXT__ is defined, new-type versions of both
C11 functions *and* TS 18661-1 functions should be declared, even without
__STDC_WANT_IEC_60559_BFP_EXT__ being defined. So bits/mathcalls.h would
declare TS 18661-1 functions in either of the cases (__GLIBC_USE
(IEC_60559_BFP_EXT), *or* the type used in a new one) - similar to the
existing conditionals __MATH_DECLARING_DOUBLE in there to reflect how e.g.
POSIX does not have the float and long double versions of the Bessel
functions.
What would __GLIBC_USE look like for other cases where there are multiple
versions of a standard (e.g. POSIX)? Might it make sense to have e.g.
__GLIBC_USE_XSI_POSIX (version1, version2) for XSI functions added in one
version then moved to base POSIX in a later version, or similar
multi-argument macros for functions added in one version then obsoleted
later?
> Fortunately for generally minimizing the complexity of it all, since the
> demise of __FAVOR_BSD, I think _GNU_SOURCE really does now mean
> absolutely everything, the superset of all feature-test sets.
It certainly doesn't include gets (except for C++). There may be other
deprecated functions (supported because they're in older standard versions
that we support) that aren't in _GNU_SOURCE. (And there may be more
deprecated functions like that that are currently in _GNU_SOURCE but
*shouldn't* be, in that we agree with the deprecation in the context of
the GNU system and so want to discourage use of those APIs. Some POSIX
deprecations however are because of e.g. portability issues where we may
think the function is still appropriate for the GNU API.)
Also, there are plenty of other cases where feature test macros select
between function versions. E.g. _FILE_OFFSET_BITS=64 remapping functions,
or choice between GNU and POSIX versions of some functions, or of some
function prototypes, or C99 scanf conflicting with the older GNU scanf
%as.
> testing our internal macros. So we'd do our users a great service by
> providing a first-class, supported API to solve these problems. Perhaps
> we can design something for ourselves that can be easily extended later
> to provide a good user API with marginal additional work.
>
> For a user API it seems pretty clear that the only thing simple enough
> to use is a predicate for exactly what the user wants to know:
>
> #if LIBC_HAS (foobar)
> ... we can use foobar! ...
> #endif
I don't think users want this only for libc. I think that if someone
doesn't want to use autoconf but still want to condition on availability
of library features, they may want such a feature covering other libraries
as well. And so if we wish to support such a feature in the GNU system,
to me that suggests something at the compiler level.
For availability of headers that would presumably be Clang-compatible
__has_include. For other features, it would need to be something at the
compiler syntax level (testing "is this declared right now") rather than
the preprocessor level, including a way to condition sections of code so
they aren't parsed beyond matching {}()[] if the condition is false.
> * generate header files (be it one or many) used in the implementation
> details of __glibc_has
That would seem to mean adding a huge pile of macros (that __glibc_has
expands to using) that get defined whenever a glibc header is included.
I'm not convinced that the compile-time impact (for the common case where
headers are much bigger than the main code being compiled) is a good idea.
And cases such as <bits/mathcalls.h> where a declaration may declare
multiple functions depending on other macros would be more complicated to
fit into such a scheme (and I don't think it would really be helpful for a
separate source of truth to have to repeat similar information for all the
the double, float, long double, _Float16, _Float32, _Float32x, _Float64,
_Float64x, _Float128 versions of a function, when the present system
avoids such repetitiveness).
> * generate or cross-check that information in the manual (and make it
> easy to do the same for linux man pages, though that is not directly
> our problem)
The manual doesn't have such information in any systematic form at all at
present.
* Various functions say in free-text form where they came from.
* There are the "@comment stdio.h", "@comment ISO" etc. before definitions
in the manual, used to generate summary.texi. There is no actual defined
list of standard names used in those comments, and they sometimes e.g.
distinguish "BSD" and "SVID", a distinction no longer made in the headers.
Might the following be a desired state for the manual? The @comment
entries are replaced by macros like those used for safety information.
Those expand to a statement of what standards the function is in / headers
and feature test macros are required to use it. The standards mentioned
are limited to those relevant to feature test macros, so MISC or DEFAULT
in place of BSD / SVID for __USE_MISC functions. Those entries could be
verified automatically based on including the headers with different
macros defined - given information about which standards are relevant with
which headers (as declarations are unconditional in a header if they are
present for all standards with that header, even if not all standards
supported by glibc). (There would of course be complications for
declarations only present for some systems, but the manual ought to
indicate such cases anyway.) Free-form text about standards for
individual functions could be removed if felt not to add anything useful
to the macro calls, but that would be a separate cleanup.
--
Joseph S. Myers
joseph@codesourcery.com