public inbox for newlib@sourceware.org
 help / color / mirror / Atom feed
* newlib, modern C++ and dirent.h revisited
@ 2017-05-12 15:19 Pekka Seppänen
  2017-05-12 15:31 ` Joel Sherrill
  0 siblings, 1 reply; 2+ messages in thread
From: Pekka Seppänen @ 2017-05-12 15:19 UTC (permalink / raw)
  To: newlib

Hi.

As this problem has some historic weight to it, here's a short recap: 
Unless compiling for a specific host, which ships it's own 
<sys/dirent.h> (which is included by <dirent.h>), newlib's default 
behaviour since 2005 has been to simply #error, which causes tests to 
work as expected (to fail). Since the very beginning (early 1990s?), it 
used to be #include_next, but as <sys/dirent.h> is included by 
<dirent.h>, #include_next <dirent.h> at <sys/dirent.h> will include 
again <dirent.h>, thus producing no easily detectable error -- fair 
enough [1].

At the time the fix was implemented, in order to provide a proper 
<dirent.h> the way was to simply provide an include path where the file 
resides using e.g. -isystem, so that it appears before newlib's 
include/sys. It stills kinda works as of today, but not really, so 
here's why I'm reluctant to use it:

Currently, I'm using newlib for a tiny RTOS that runs on a certain ARM 
based processors. Under the hood, I've implemented dirent.h 
functionality and everything works as expected. To keep the toolchain 
side as clean and tidy as possible, I'm pretty much limiting all the 
customizations to simply running any configuration scripts with the 
options I need. So, e.g. my newlib doesn't really know that it will be 
running hosted on an OS that does dirent.h stuff -- and it really 
doesn't have to. While configure.host is not that involved, doing a 
custom job there would require me to maintain that file and any 
corresponding files under libc/machine/. While it would be nice, I 
simply don't have time for this -- every moment spent building the 
toolchain is taken away from maintaining the actual RTOS and everything 
that sits atop of that (it's not like newlib is the only link in the 
chain).

Now, the majority of application code which runs on the OS is written 
using modern C++ (17 and onwards). For the compiler I'm using GCC, but I 
guess any decent compiler would do it. Again, when (cross-)compiling the 
GCC I'm limiting myself to any options, that are settable via the 
autoconf's configure script because my time is limited and kludges have 
tendency to break. Here's where the things have have changed, not 
perhaps dramatically, but changed nevertheless since the 2005 patch was 
made.

Evolved from Boost.Filesystem, STL has had an (experimental) 
std::(experimental::)filesystem since 2015. I would like to use, as I 
don't have any necessity to reinvent those features. When using GCC, 
this will be compiled as libstdc++fs, as part of the libstdc++. So, when 
the cross-compiling GCC is built, the proper dirent.h must be available 
as filesystem is not a header-only library. To configure native system 
headers for the GCC, as of 2011 --with-native-system-header-dir options 
has been available. It sets up a builtin include location, from which 
the system headers are supposed to be pulled -- in reality, it is of 
course just an additional builtin include path. As an unfortunate 
effect, the native-system-header-dir appears after, not before, the 
include path set up by --with-sysroot prefix (it will appear as 
-isystem, before any CXXFLAGS, set up by autoconf).

So, the default <sys/dirent.h> gets included and the libstdc++fs does 
not get built (the presence of <dirent.h> is determined by autoconf). 
One could do a dirty copy-over kludge here, but I just don't see that as 
a proper thing to do as it'll always pile up. The same goes with simply 
removing the <sys/dirent.h> -- while either would would fix the problem 
for me, it wouldn't so much do it for the others (e.g. the official ARM 
GNU toolchain). Also, hammering the default <sys/dirent.h> with GCC's 
fixincludes isn't any better, as it has no external hooks so one would 
have to manually maintain yet another configuration file.

I presume the source of this problem, and the reason why the 2005 patch 
was written, is the way #include_next works. If you have just one 
<dirent.h>, the #include_next will function just like #include. However, 
things have evolved and nowadays at least both GCC and LLVM (clang) 
support __has_include_next. Unfortunately, only __has_include is part of 
the C++17, but I guess this makes an excellent use case for 
__has_include_next: i) should you not have any next include file, (a 
properly implemented) __has_include_next will return 0, ii) should you 
not have __has_include_next functionality, simply define 
__has_include_next as zero or check, if it's defined (as compilers 
should really define __has_include as __builtin_has_include etc., or 
whatever internal name the particular vendor chooses).

So, instead of simply doing an #error, I would very much like to see 
something like:

#if defined(__has_include_next) && __has_include_next(<dirent.h>)
#  include_next <dirent.h>
#else
#  error "<dirent.h> not supported"
#endif

and it would just work (given that #if would have to be likely split 
into #ifdef/#if etc.): If there's no additional dirent.h, or your 
compiler is of previous generation, you'll get the old error message. 
Should you have both, it'll be included next -- just like the original 
did (or wished to do) back in the day. This way one could also pull a 
standard, uncustomized prebuilt newlib installation and not have to 
worry about <dirent.h> include order so much, would you like to 
implement one yourself. Like I said, of course `the proper' way to do 
this would be customize newlib, but the way configure scripts are 
currently implemented it involves so much work that it's not simply 
worth it -- patching, copying, checking, working this all up as an yet 
another messy script, for every release etc. takes so much time while 
you simply wanted `not to fail so early'.


What do you think? Worth doing, at least looking into, or is there 
something this sort of approach would hinder? Obviously, this would need 
some testing, so that it's not suddenly 2005 all over again.


-- Pekka


[1] https://sourceware.org/ml/newlib/2005/msg00608.html

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

* Re: newlib, modern C++ and dirent.h revisited
  2017-05-12 15:19 newlib, modern C++ and dirent.h revisited Pekka Seppänen
@ 2017-05-12 15:31 ` Joel Sherrill
  0 siblings, 0 replies; 2+ messages in thread
From: Joel Sherrill @ 2017-05-12 15:31 UTC (permalink / raw)
  To: Pekka Seppänen, newlib



On 5/12/2017 10:19 AM, Pekka Seppänen wrote:
> Hi.
>
> As this problem has some historic weight to it, here's a short recap:
> Unless compiling for a specific host, which ships it's own
> <sys/dirent.h> (which is included by <dirent.h>), newlib's default
> behaviour since 2005 has been to simply #error, which causes tests to
> work as expected (to fail). Since the very beginning (early 1990s?), it
> used to be #include_next, but as <sys/dirent.h> is included by
> <dirent.h>, #include_next <dirent.h> at <sys/dirent.h> will include
> again <dirent.h>, thus producing no easily detectable error -- fair
> enough [1].
>
> At the time the fix was implemented, in order to provide a proper
> <dirent.h> the way was to simply provide an include path where the file
> resides using e.g. -isystem, so that it appears before newlib's
> include/sys. It stills kinda works as of today, but not really, so
> here's why I'm reluctant to use it:
>
> Currently, I'm using newlib for a tiny RTOS that runs on a certain ARM
> based processors. Under the hood, I've implemented dirent.h
> functionality and everything works as expected. To keep the toolchain
> side as clean and tidy as possible, I'm pretty much limiting all the
> customizations to simply running any configuration scripts with the
> options I need. So, e.g. my newlib doesn't really know that it will be
> running hosted on an OS that does dirent.h stuff -- and it really
> doesn't have to. While configure.host is not that involved, doing a
> custom job there would require me to maintain that file and any
> corresponding files under libc/machine/. While it would be nice, I
> simply don't have time for this -- every moment spent building the
> toolchain is taken away from maintaining the actual RTOS and everything
> that sits atop of that (it's not like newlib is the only link in the
> chain).

libc/sys not libc/machine. machine is for target architectures.

Supporting an RTOS with code in libc/sys isn't a huge burden.
RTEMS has been doing this for years. Just integrate with
newlib properly. Then gcc and all supporting libraries will
have the proper .h files and be able to build with correct
support.

>
> Now, the majority of application code which runs on the OS is written
> using modern C++ (17 and onwards). For the compiler I'm using GCC, but I
> guess any decent compiler would do it. Again, when (cross-)compiling the
> GCC I'm limiting myself to any options, that are settable via the
> autoconf's configure script because my time is limited and kludges have
> tendency to break. Here's where the things have have changed, not
> perhaps dramatically, but changed nevertheless since the 2005 patch was
> made.
>
> Evolved from Boost.Filesystem, STL has had an (experimental)
> std::(experimental::)filesystem since 2015. I would like to use, as I
> don't have any necessity to reinvent those features. When using GCC,
> this will be compiled as libstdc++fs, as part of the libstdc++. So, when
> the cross-compiling GCC is built, the proper dirent.h must be available
> as filesystem is not a header-only library. To configure native system
> headers for the GCC, as of 2011 --with-native-system-header-dir options
> has been available. It sets up a builtin include location, from which
> the system headers are supposed to be pulled -- in reality, it is of
> course just an additional builtin include path. As an unfortunate
> effect, the native-system-header-dir appears after, not before, the
> include path set up by --with-sysroot prefix (it will appear as
> -isystem, before any CXXFLAGS, set up by autoconf).
>
> So, the default <sys/dirent.h> gets included and the libstdc++fs does
> not get built (the presence of <dirent.h> is determined by autoconf).
> One could do a dirty copy-over kludge here, but I just don't see that as
> a proper thing to do as it'll always pile up. The same goes with simply
> removing the <sys/dirent.h> -- while either would would fix the problem
> for me, it wouldn't so much do it for the others (e.g. the official ARM
> GNU toolchain). Also, hammering the default <sys/dirent.h> with GCC's
> fixincludes isn't any better, as it has no external hooks so one would
> have to manually maintain yet another configuration file.
>
> I presume the source of this problem, and the reason why the 2005 patch
> was written, is the way #include_next works. If you have just one
> <dirent.h>, the #include_next will function just like #include. However,
> things have evolved and nowadays at least both GCC and LLVM (clang)
> support __has_include_next. Unfortunately, only __has_include is part of
> the C++17, but I guess this makes an excellent use case for
> __has_include_next: i) should you not have any next include file, (a
> properly implemented) __has_include_next will return 0, ii) should you
> not have __has_include_next functionality, simply define
> __has_include_next as zero or check, if it's defined (as compilers
> should really define __has_include as __builtin_has_include etc., or
> whatever internal name the particular vendor chooses).
>
> So, instead of simply doing an #error, I would very much like to see
> something like:
>
> #if defined(__has_include_next) && __has_include_next(<dirent.h>)
> #  include_next <dirent.h>
> #else
> #  error "<dirent.h> not supported"
> #endif
>
> and it would just work (given that #if would have to be likely split
> into #ifdef/#if etc.): If there's no additional dirent.h, or your
> compiler is of previous generation, you'll get the old error message.
> Should you have both, it'll be included next -- just like the original
> did (or wished to do) back in the day. This way one could also pull a
> standard, uncustomized prebuilt newlib installation and not have to
> worry about <dirent.h> include order so much, would you like to
> implement one yourself. Like I said, of course `the proper' way to do
> this would be customize newlib, but the way configure scripts are
> currently implemented it involves so much work that it's not simply
> worth it -- patching, copying, checking, working this all up as an yet
> another messy script, for every release etc. takes so much time while
> you simply wanted `not to fail so early'.
>
>
> What do you think? Worth doing, at least looking into, or is there
> something this sort of approach would hinder? Obviously, this would need
> some testing, so that it's not suddenly 2005 all over again.
>
>
> -- Pekka
>
>
> [1] https://sourceware.org/ml/newlib/2005/msg00608.html
>

--joel

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

end of thread, other threads:[~2017-05-12 15:31 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-12 15:19 newlib, modern C++ and dirent.h revisited Pekka Seppänen
2017-05-12 15:31 ` Joel Sherrill

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 read-only IMAP folder(s) and NNTP newsgroup(s).