Getting Started
Cross compilation with Autoconf/Libtool
|
|
Introduction
Cross compiling for LinuxSH programs that use the Autoconf/Libtool system
can be a little tricky because package authors don't always consider the
issues involved in cross-development and the resulting
configure script and Makefiles are often
not suited to be used in a mixed environment.
I often found useful to collect all the commands and environment variables
needed to reach a successful configuration in a simple shell script for
future reference. This shell script may also form the base of the SPEC
file needed to build an RPM version of the package. In the following
sections I will show examples of commands or definitions that will go into
this script.
Configuration
The configure script has a number of
default command-line options that are available regardless of the package
and some of them are meant to support cross-compilation. The availability
of such options does not mean that the specific package can be easily
cross-compiled without some tweaking of the whole process.
The configure script is generated
automatically by the package maintainer using the Autoconf system. The
recent release of Autoconf 2.5x changed the meaning of some of the
options. To discover which version of Autoconf generated the
configure script, run it with the
--version option:
$ ./configure --version
configure generated by autoconf version 2.13
|
|
|
The most important options are:
--build
- This option defines the architecture of the computer where you are
building the program. It is usually an Intel PC running Linux. In this
case the argument of the option should be something like:
i686-pc-linux-gnu.
--build="i686-pc-linux-gnu"
|
|
|
If the program has a config.guess script
available in its top-level directory, its output should be used to get
the exact definition:
--build="`./config.guess`"
|
|
|
This solution is the preferred one. The example assumes that you are
configuring the package from its top level directory.
--host
- This option defines the architecture of the system that will
host the program once compiled. This is more generally known as
the target architecture but in Autoconf lingo this name can be
misleading and host must be used. (See next option.)
For LinuxSH the definition string will be: sh4-linux.
--target
- This option should only be used when building
development tools like compilers, assemblers and linkers, e.g.
Gcc or Binutils. Normal programs should not use it.
It defines the microprocessor architecture for which code will be generated
by the tool.
--prefix
- This is used to define the final installation directory for the
package. Note that this is where the program will find itself when
running on the actual target. It is not the directory
where you are installing it on your host machine. In order to install the
software on the development host, the prefix variable will be overridden
at install time on the make command line.
Environment variables
Configure behavior is often controlled by setting some environment
variables. The following variables should always be defined (the examples
are in Bourne shell syntax):
CROSS_COMPILE
- This is sometimes used by configure to detect a cross development
environment. It is not needed by
configure
scripts generated by Autoconf 2.5x.
CC and CXX
- These are used to define the C and C++ compiler commands. For the SH cross
development environment they usually are
sh4-linux-gcc
and sh4-linux-g++.
export CC="sh4-linux-gcc"
export CXX="sh4-linux-g++"
|
|
|
-
Some other environment variables will be needed according to the particular
package being built.
Invoking configure
Before proceeding any further, run configure --help
to see all the available options and check the dependencies of the package
by reading the documentation: it is very important that all the required
libraries are already in place. If some of them are also available on the
development host as part of your linux distribution, be aware that later
in the process you may discover that these are the ones being used and not
those from your cross development environment.
Some packages compile and run small test programs at configure time to
test the availability or the presence of some features in other software.
These programs won't run on your host when cross compiling so these tests
must be disabled. The configure options that control this behavior often
end with the string test. Here is an example from gdk-pixbuf:
This behavior is also controlled by the --host and
--build options in scripts generated by Autoconf 2.5x.
Supplying both options puts the script in cross-compile mode and
disables all tests that require compiling and running a small test program.
Note that this mode does not disable the tests that are
controlled by command-line options like --disable-glibtest.
Use all the available options of this kind but remember that you then have
to be sure that the correct versions of the required packages are already
installed.
Some recent libraries come with a configuration script whose name ends in
-config like gtk-config. Its
purpose is, when invoked with the --cflags
and--libs options, to print the correct
compiler options that must be used by programs using that library.
The cross development versions of these programs should not usually be
available on the path, otherwise it wouldn't be possible to compile normal
applications on the host computer. The best way to let
configure find and use the ones provided
by the cross development package is setting some environment variables to
the full path of the SH version. Here is an example for a program that
needs gtk-config:
export GTK_CONFIG="/opt/STM/ST40Linux-1.0/devkit/sh4/sh4-linux/bin/gtk-config"
|
|
|
The variable name is always the name of the program in upper case with an
underscore replacing the hyphen.
If, instead, you are building a library that will install a
-config script check what it prints when invoked using the
--cflags and --libs
options. The paths must point to your target environment. This is what
the SH version of glib-config prints
(line wrapped for readability):
$ /opt/STM/ST40Linux-1.0/devkit/sh4/sh4-linux/bin/glib-config --cflags
-I/opt/STM/ST40Linux-1.0/devkit/sh4/sh4-linux/include/glib-1.2
-I/opt/STM/ST40Linux-1.0/devkit/sh4/sh4-linux/lib/glib/include
|
|
|
This command is part of the development environment belonging to the host
and shouldn't be installed on the target. This is why the directories it
prints should be relative to the development host and not to the embedded
target. As the output strings are built at compile time using the argument
of the --prefix option, you need to change
them before installing the script
The best way to change these directories is by using a simple
sed script (the example assumes a package
configured for /usr) (backslash added
for readability):
$ mv gdk-pixbuf-config gdk-pixbuf-config.orig
$ sed -e "s#/usr#/opt/STM/ST40Linux-1.0/devkit/sh4/sh4-linux#g" \
< gdk-pixbuf-config.orig > gdk-pixbuf-config
|
|
|
Libtool
Quoting from the user manual:
In the past, if a source code package developer wanted to take advantage
of the power of shared libraries, he needed to write custom support code
for each platform on which his package ran. He also had to design a
configuration interface so that the package installer could choose what
sort of libraries were built.
GNU Libtool simplifies the developer's job by encapsulating both the
platform-specific dependencies, and the user interface, in a single
script. GNU Libtool is designed so that the complete functionality of
each host type is available via a generic interface, but nasty quirks are
hidden from the programmer.
Well, nasty quirks are a little more visible when cross
compiling.
If the package you are cross compiling uses the libtool
script to build a library, you need to rebuild it using the
ltconfig command from the package itself
if available. The libtool script must be
rebuilt with knowledge of the target architecture. This can be achieved
with the following script (Bourne shell syntax):
#! /bin/sh
PREFIX=$1
export CC="${PREFIX}-gcc"
export LD="${PREFIX}-ld"
export NM="${PREFIX}-nm -B"
export AR="${PREFIX}-ar"
export RANLIB="${PREFIX}-ranlib"
export LN_S="ln -s"
export CFLAGS="-g -O2"
echo "Rebuilding libtool for \"$PREFIX\" ..."
./ltconfig --cache-file="./config.cache" --with-gcc --with-gnu-ld --no-verify \
./ltmain.sh $PREFIX
echo "Done."
|
|
|
Call it makelibtool and invoke it with a
single argument: the name of the target architecture as in:
$ makelibtool sh-linux-gnu
Rebuilding libtool for "sh-linux-gnu" ...
Done.
|
|
|
The variable definitions and the ltconfig
command can also be embedded in a larger script that takes care of the
configuration process. The CFLAGS varible
defined in this script is only the default value used by libtool. This
will be overridden by the definition seen by configure.
If you are embedding these commands in a larger Bourne shell script, you
can redefine CFLAGS for the
ltconfig invocation only in this way:
$ CFLAGS="-g -O2" ./ltconfig --cache-file="./config.cache" ...
|
|
|
If the ltconfig command should not be
present if the configuration scripts have been generated by Autoconf 2.5x.
In this case the same configure will
generate a new libtool command.
X11
The use of X11 can be controlled using the --x-includes
and --x-libraries options as in:
--x-includes="/opt/STM/ST40Linux-1.0/devkit/sh4/target/usr/X11R6/include"
--x-libraries="/opt/STM/ST40Linux-1.0/devkit/sh4/target/usr/X11R6/lib"
|
|
|
Where /opt/STM/ST40Linux-1.0/devkit/sh4/target/usr/X11R6 is
the full path to the SH version of X11.
Compilation
Once configure has run without errors, you can finally build
the package. But just typing make isn't enough: some old packages need the
compilers to be specified again on the make command line as in:
make CC="sh4-linux-gcc" CXX="sh4-linux-g++"
|
|
|
If you need to define some other preprocessor symbols, you can define them
at compile time adding them to the AM_CPPFLAGS
variable on the make command line:
make AM_CPPFLAGS="-DSTDC_HEADERS"
|
|
|
Hints and tips
Here are some hints and tips about the whole process:
-
During its tests
configure writes a
detailed log of all its activity in the file config.log.
If you find yourself in troubles, this is the first place to look for
errors.
When configure runs, it first checks if
a file called config.cache is available
in the current directory. If it is, the file is loaded before all the
tests are executed, preloading many autoconf variables with the cached
values.
If configure is guessing something wrong
and you can't find a way to change its behavior, you can edit the
config.cache file deleting everything but
the variable definition that needs to be changed. The next time
configure is run, it will skip the
faulty test loading your custom defined value from the cache file.
A simple example
Here is a simple example of a shell script that configure and build the
gdk-pixbuf shared library that depends on GTK+ and X11.
#! /bin/sh
# base directory of the cross development environment
devkit_base="/opt/STM/ST40Linux-1.0/devkit/sh4"
devkit_dir="${devkit_base}/sh4-linux"
x_dir="${devkit_base}/target/usr/X11R6"
# local directory with target files
target_dir="${devkit_base}/target"
# architecture prefix
arch="sh4-linux"
# environment variables
export CC="${arch}-gcc"
export LD="${arch}-ld"
export NM="${arch}-nm -B"
export AR="${arch}-ar"
export RANLIB="${arch}-ranlib"
export LN_S="ln -s"
export CFLAGS="-O2"
export CROSS_COMPILE=1
# configuration commands for GTK+
export GLIB_CONFIG="${devkit_dir}/bin/glib-config"
export GTK_CONFIG="${devkit_dir}/bin/gtk-config"
# configuration
./configure --build="`./config.guess`" --host="${arch}" --prefix="/usr" \
--disable-glibtest --disable-gtktest --disable-mmx --disable-modules \
--x-includes="${x_dir}/include" --x-libraries="${x_dir}/lib"
# rebuild libtool
CFLAGS="-g -O2" ./ltconfig --cache-file=./config.cache --with-gcc --with-gnu-ld \
--no-verify ./ltmain.sh ${arch}
# build library
make CC="${CC}" pixbuf_demo_LDFLAGS="\"-lpng -ltiff -ljpeg -lz\""
# Change gdk-pixbuf-config path
mv gdk-pixbuf-config gdk-pixbuf-config.orig
sed -e "s#/usr#${devkit_dir}#g" < gdk-pixbuf-config.orig > gdk-pixbuf-config
# install
make prefix="${target_dir}/usr" install
|
|
|
|