This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
Re: How do I point out OS includes? -- Or how to Build My Own SDK using Newlib
I've followed this conversation with great interest. Some of the
issues I recognize from my own experiance, some of them I don't (the
latter might however very well be due to that I haven't stumbled
across them yet).
Here's my 10 cent worth of contribution:
There's a lot of cross how-to's circulating the Net and I like many
others have learned the hard way by trial-and-error over the years.
I've assembled a how-to of my own from bits and pieces from a little
bit of everywhere:
http://tinker.sourceforge.net/cgi-bin/wiki/How_to_build_a_standard_GNU_cross-compiler_tools_chain
IMO there is however an "issue" worth special attention, which is the
actual OS intricacies. In my experience building a Newlib based cross
tool-chain without having Newlib support a specific OS (or kernel) is
a bad idea. Even if one succeeds, one might end up with two different
sets of header files (one belonging to "_my_OS" and the other
belonging to Newlib – the native ones I don't mention since it's
already accurately explained by previous posts). These two are almost
certainly incompatible with each other and there is inherently a great
risk of the final application using the wrong one. One might be able
to compile applications with it this tool-chain, but sooner or later
the miss-matches will show up and the application will misbehave badly
(at best).
I.e.:
--with-newlib --with-headers=[newlib-source]/newlib/libc/include
*should* be enough. If it isn't then the OS in question is not
supported by Newlib.
So then what? Bummer! (...or not?)
IMHO there's only one *proper* way to deal with this and that is to
get "_my_OS_" integrated into the Newlib sources. This however is not
at all as smooth as it might seem. One of the reasons are that we
don't want every single OS or system (invented neither by me nor by my
grand-mother) to be part of the Newlib repository. It would pollute
the Newlib sources and only make it more difficult to maintain. The
only choice then, is for each vendor to maintain each integration
outside of Newlib (which is a lot of tedious work).
====
Alternatively there is another approach that could work. Since a while
ago I've been experimenting with a minimal Newlib patch called HIXS (
http://tinker.sourceforge.net/cgi-bin/wiki/HIXS ).
Basically it's a very simple stubbed framework for syscalls (inspired
by the RTEMS folks btw) with the added ability to modify the syscalls
dynamically *after* the whole tool-chain is built.
It has some benefits, but also some drawbacks:
Pros:
+ HIXS is generic and need not to be specially adapted to any
architecture. It should work for all.
+ It will permit a compete build of a cross tool-chain all the way
from binutils to GDB for most architectures (I've tried it on PowerPC,
Blackfin, ARM, x86 and MIPS so far).
+ It will fool most configure scripts using the produced tool-chain
and it will thereby permit a finalized GCC and GDB build (i.e. some of
the GCC_NO_EXECUTABLES nitwits will automagically go away).
Cons:
- It will not produce runnable code (read below)
- It has a slight run-time penalty
HIXS contains simple stubs for all the syscalls. For applications to
work, HIXS however requires an additional code block as part of each
applications (or kernels) boot sequence that binds the real syscalls
to specific function pointers used in each corresponding stub. The
function pointers are global and follow a simple naming convention
which makes the binding process quite pain-less.
I'm not trying to sell HIXS and I'd be happy to learn from others
that's come up with other solutions. All I'm saying is that I believe
we've stumbled across an area that is a real nightmare in all it's
aspects and an area that could be improved.
Best Regards
/Michael
On 4/18/07, Anders Lindgren <ali@df.lth.se> wrote:
Thanks for your detailed answer. I can sense the frustration you've gone
through learning all this -- I've certainly felt quit a bit of it over the
years, learning this stuff mostly by trial and error. :-)
I agree on most of your points, it's quite similar to what I typically
do.
Yes, I am working with custom OSes, for embedded systems. The situation
is typically this:
- A complete toolchain is packaged somewhere (by me), and people just
install it and add it to their $PATH. The command line challenged crowd
gets a "build_prompt.bat" file to click on, in the Wintendo case. ;-)
Moving it around is no problem because gcc etc finds its own includes,
libs and binaries relative to itself.
- The OS and the rest of the firmware source code is checked out of some
version control system, and can be located just about anywhere on a user's
hard disk. The firmware's build system uses an environment variable
($ROOT, say) and *everything* is referenced relative (under) this top
directory -- except the toolchain, which just needs to be in $PATH
somehwere. In practice, the toolchain is in a standard place, too.
Up until now, building these cross-toolchains have been simple enough
that I never felt a need to try things like crosstool. I've traditionally
just:
- Added my target to binutils, gcc and newlib configurations. Normally
this only requires some trivial changes to config.sub, config.gcc and
configure.host in newlib, plus a libc/sys/foo dir for my target for the
syscalls, if any.
- Built and installed binutils configured as --target=foo-bar-baz
--prefix=/my/tool/dir --program-prefix=foo- # Shorter to type.
- Soft-linked foo-bar-baz-$file to all of binutils' foo-$file (because gcc
is too stupid to guess that if I'm building it with program-prefix=foo,
binutils might just have been, too).
- Soft-linked newlib-v.w.0/newlib into gcc-x.y.z/, and built the lot.
The configure/build/install part of this I typically put in a script and
just go.
This has worked fine for a couple of years, because at first no syscalls
were used in my newlib and, when I first started integrating stdio
support, I got away without overriding any newlib headers. So the new
thing here is really just that my target has ended up needing to provide
it's own version of sys/lock.h -- which now depends on OS headers. These
are of course located not in a fix location, but somewhere under $ROOT,
wherever that is.
Maybe --with-sysroot + some symlinks would've accomplished what I ended
up doing: I built using --with-headers=$ROOT/foo/include, installed
everything, and then rm -rf'd $prefix/foo-bar-baz/sys-include/*. Since the
toolchain is only used within (or in combination with) the firmware build
system, there'll always be a -I pointing out the OS includes. While
changes to those OS includes (admittedly rare) may very well mean I need
to rebuild newlib, I _don't_ want to keep non-versioned copies of them
inside the gcc tree.
I had to disable libssp (its configure appeared to try to execute a
_target_ binary after a GCC_NO_EXECUTABLES token, or somesuch) and
libstdc++ (which had complaints about no native atomic operations being
available), but I didn't look further into either since I don't actually
use them.
Hrrm, I've written a rather detailed HOWTO of this whole procedure (for
my own memory), and with these include issues more or less figured out,
I'd say it's quite complete. I think I'll update it with notes on target
includes and put it on the web -- it should be a good tutorial for
beginners. I'd appreciate all feedback if any of you care to read it when
it's up.
Regards,
ali:)