Since working with building an embedded Linux image with Gentoo, I have been learning stuff at such an incredible rate of speed that it’s hard for me to keep up the pace. I’m going to try to document some of the stuff I’ve learned.
The first thing before starting is to know how Gentoo (portage in particular) works, in making this a possible reality. The ebuilds, as you know, determine the dependencies for each package that is installed onto your system. Those dependencies fall into two categories: the ones that you need to build the package (compiler, header files, etc.) and the ones that you need to run the package on your system (libraries, binaries, etc.). In the ebuild they are set as the DEPEND and RDEPEND variables, respectively. Build-time and run-time deps.
On top of that, portage can also build a binary package of each program that install using emerge. You can have this happen by default or do it manually for a package. Automatically would be to add “quickpkg” to your FEATURES set in make.conf. Then, everytime you emerge something, it will tar up the installed package and save it into /usr/portage/packages. Alternatively, you can emerge a program and only build a binary instead of installing it to your root filesystem, by using emerge -B. If you already have the package installed, you can use ‘quickpkg’ to build a binary package.
Anyway, the point is, by building a system using the packages, you can save lots of space (and time) by installing only the applications you need. If you’re going to develop a system to use the binary packages, you want to install them to another location. The simplest way to do that is to use the ROOT variable, and then emerge something. That will only suck in the binary packages, giving you the bare bones that you need. ‘ROOT=”/tmp/tiny” emerge -B foo’ would pull in package ‘foo’ along with all its runtime dependencies.
If you’re going to develop a complex image though, you’re going to need more variables than just what the ROOT directory provides. Fortunately, portage accounts for that as well, and you can use an entirely different make.conf file for your target destination using the PORTAGE_CONFIGROOT variable. Using that with portage will look for /etc/make.conf from that starting point … using /tmp/tiny as an example, it would read from /tmp/tiny/etc/make.conf. There are a few things you should put in that make.conf file, though. The most important one being the new ROOT variable for your target directory, ROOT=/tmp/tiny. Otherwise, everything would end up being installed to your current setup. You’ll also need to copy make.globals to the new /etc directory as well, plus setup the portage profiles … a symlink should work nicely. You’ll also need to set PORTDIR, DISTDIR and PKGDIR to point to your development’s root filesystem.
I don’t want to get into more details here … I’d rather do that on a wiki. If anything, I just want to show how it can be done.
Something else that comes in handy with portage is that you can tell it not to install certain files when the package is emerged into your target directory. Since you’re not going to be doing any compiling on the system, we can strip out all header and development files that packages normally need when building against another package. Portage has an INSTALL_MASK variable that will let you ignore those files when installed. Here’s a trimmed down version of what mine looks like in the make.conf for my target install: INSTALL_MASK=’*.a *.h *.ac *.pc *.la *.mo *.m4 Makefile*’ There’s a lot more you could add, but that will catch most of it.
Another easy fix you can add to ignore unnecessary files on your deployed image is by adding ‘noman’, ‘noinfo’, and ‘nodoc’ to the FEATURES set.
There’s a lot more to it than that, such as deciding which init system to use, using and configuring busybox, picking a libc, etc., but thanks to Portage, building an image for embedded use is actually incredibly easy. So far I’m enjoying it.
If you need any help, feel free to pop your head into #gentoo-embedded on Freenode.