Debugging a failed Openembedded build with devshell
devshell is a great feature implemented in Openembedded that allows to spawn a cross-compilation terminal session that replicates the build time environment used by bitbake. It allows to save a lot of time and headaches when packages fail to compile. Here I have collected some notes on how devshell helped debug a failure I came across when integrating lighttpd in my Raspberry Pi layer.
Spawning a development shell
Spawning a development shell is as simple as calling devshell
task on the desired
package.
The feature is implemented in openembedded-core/meta/classes/terminal.bbclass
and openembedded-core/meta/classes/devshell.bbclass
. These class files define
functions that set up the cross compilation environment by exporting environment
variables that point to the cross development tools (e.g. PATH
, PKG_CONFIG_DIR
,
CFLAGS
, LDFLAGS
, CC
, etc). Function emit_terminal_func
in terminal.bbclass
creates
an initialization script executed by the shell pointed by DEVSHELL
that sets
all the aforementioned variables. The shell is executed within the terminal emulator
of choice (OE_TERMINAL
or the one currently being used, i.e. if you are using tmux,
another tmux pane will pop up) by the code in module openembedded-core/meta/lib/oe/terminal.py
.
Supported terminal emulators are, for instance, xterm, gnome-terminal, tmux, screen, konsole, etc.
To bear in mind that when a new shell is spawn, the relative rc
script is executed,
e.g. .zshrc
or .bashrc
. If this exports variables that are part of the cross-compilation
environment, e.g. PATH
, then there will necessarily be a conflict and the cross-toolchain
will not be setup correctly.
Building lighttpd
Let’s consider a compilation failure I came across when building lighttpd
for
the Raspberry Pi. When running do_configure
task, bitbake fails with the following errors:
devshell
opens the new terminal emulator session and, not surprisingly after all,
./configure
breaks straight away with the following error:
Indeed, there is more than simply environment variables in a cross-compilation environment.
The GNU conding standard defines at least --host
and --build
configure flags when building for another architecture. In case a cross-compiler
is being built, then --target
is also necessary. As a matter of fact, autotools.bbclass
invokes ./configure
with a relatively large set of arguments:
The only relevant variables for the build process are build
, host
, includedir
and
--with-libtool-sysroot
, the last being necessary only when compiling shared objects.
The toolchain sysroot
is already defined as part of $CC
environment variable.
The value to be assigned to the aforementioned flags can be retrieved by invoking bitbake
with --verbose
option: this will generate a large amount of debug messages,
including a dump of the complete commands that are begin executed, so that it is
then a simple matter of copy paste. In this case, the following command invoked
in the development shell generates the same failure we are after.
A quick look at config.log
confirms that the test program used to assess
deflate support fails with a pcre-config
related error:
Indeed, pcre-config
, which is supposed to return the configuration of the installed
Perl Compatible Regular Expressions library, generates that funny flag that would
probably make any tool complain. The recommendation is to use pkg-config
instead or compiling
the package with --without-pcre
. This latter solution, rather a workaround I would say,
would be a shame, considering that the only piece of information
that the configure script is missing is the include and lib path for libpcre:
So, let’s try again, this time setting --with-pcre
. Note that any path specified
on the command line must point to the cross-compiled libraries and headers. In order
to do so, an additional =
must be prepended so that the path is interpreted as
relative to the sysroot
. On the contrary, if an absolute path is specified, the
configure run will not break, but a warning
will appear in resulting log file and do_qa_configure
will catch it and raise
an error.
It works, Makefile is created! Now it is time to automate the build by applying the corrective actions to the recipe.
Conclusions
Simply adding EXTRA_OECONF="--with-pcre==/usr"
leads to a successful build.
This was a simple example of how devshell
comes in handy when a bit of digging is
required to fix a failure in the build. There are several other use cases that
can be addressed by this feature, but I wiLL leave them for another post.