Tips & Tricks Re Cross patching
Terminology
The discussion below assumes that cross building involves producing debian binary packages to be installed on some target host by building those packages on a build host of a different architecture i.e the autoconf build/host/target convention is used.
rules below refers to <package directory>/debian/rules.
Disclaimer
- The discussion here relates to patching packages in a software stack such that they may be cross compiled using xdeb.
It is based on my attempts to cross build the alip-ael stack as target host armel on an intel Maverick build host.
Resulting patched packages are available from my PPA
Some of the configuration files (including /etc/xdeb/xdeb.cfg && /etc/dpkg-cross/cross.conf.armel) are at this link [please ping me if I've missed any]
- Patches are not necessarily optimal and/or acceptable upstream, they were intended to allow me to progress through the stack.
- The resulting armel binaries have NOT yet been tested to run.....
Patches assume that crossed packages will be installed to /usr/arm-linux-gnueabi on the build host - they may need to be revisited once multiarch is operational.
- Where new debian patches are required little effort has been made to use dpatch or quilt, unless forced by the package. Most are simple diff -purN patches.
Common Problems
Detecting cross building
The autoconf mechanisms produce configure scripts which should honour the --host == target on which cross built packages will be installed & run, --build == build host on which cross compiler is run to produce those packages. xdeb sets the environment such that these should be automatically passed to the configure script TBD - insert more detail ??DEB_EXTRA_CONFIGURE_ARGS??. However some packages ignore this mechanism. For these packages it is necessary to change debian/rules to explicitly pass host & target settings in a manner such as:-
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE)) CONF_FLAGS += --host $(DEB_HOST_GNU_TYPE) CONF_FLAGS += --build $(DEB_BUILD_GNU_TYPE) endif <configure-target>: ...... ./configure <existing arguments> $(CONF_FLAGS) .....
Determination of host properties
Some configure scripts determine the characteristics of the host by running test programs.
Well behaved scripts detect that these cannot be run during cross building & fail.
if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "cannot run test program while cross compiling See \`config.log' for more details." "$LINENO" 5; } else
Better behaved scripts provide a cache variable to allow the builder to set the correct value, allowing configuration to proceed.
if test "${ac_cv_sys_restartable_syscalls+set}" = set; then $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then
Since xdeb uses dpkg-cross the cache variables can be set in /etc/dpkg-cross/cross.conf.armel to be loaded during configuration
configure: loading site script /etc/dpkg-cross/cross-config.armel
My current policy, where necessary, is to use settings/files from build host builds e.g. iconv-detect.h.
Badly behaved configure scripts may need to be edited to conform.
Correctly, configure.ac should be amended. However some packages do not reconstruct their configure scripts
Build tools and data
Badly behaved packages may make no distinction between binaries/data to be used during the build and those to be packaged for the host target. This results in build failure as target binaries are run on the build host.
In the simpler case the tools/data are not to be packaged and the build system can be massaged to build & use a build host binary.
ifeq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE)) cd debian/detector && \ $(MAKE) else cd debian/detector && \ $(MAKE) CC=$(DEB_HOST_GNU_TYPE)-gcc STRIP=$(DEB_HOST_GNU_TYPE)-strip endif
In the more complicated case where the tool/data is both used during the build (build host required) and packaged up (target host binary required) I have taken the option of using a pre built build host directory.
ifneq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE)) BUILD_HOST_BUILD_DIR = /work/build_host_build/mono-2.6.7 RUN_MONO = LD_LIBRARY_PATH=$(BUILD_HOST_BUILD_DIR)/debian/tmp/usr/lib MONO_PATH=$(BUILD_HOST_BUILD_DIR)/debian/tmp/usr/lib/mono/2.0 $(BUILD_HOST_BUILD_DIR)/debian/tmp/usr/bin/mono BUILD_HOST_DIRS = \ mcs/class/lib/net_1_1 \ mcs/class/lib/net_3_5 \ mcs/class/lib/net_2_0 \ mcs/class/lib/net_1_1_bootstrap \ mcs/class/lib/net_2_0_bootstrap \ debian/tmp/usr/lib/monodoc/sources BUILD_HOST_FILES = \ mcs/class/RabbitMQ.Client/docs/specs/autogenerated-api-0-8.cs \ mcs/class/RabbitMQ.Client/docs/specs/autogenerated-api-0-9.cs \ mcs/class/RabbitMQ.Client/docs/specs/autogenerated-api-qpid-0-8.cs \ debian/tmp/usr/lib/monodoc/monodoc.xml endif configure: configure-stamp configure-stamp: autoreconf-stamp ifneq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE)) # Copy in the build host build config.make if [ ! -d $(BUILD_HOST_BUILD_DIR) ] ;\ then \ echo "BUILD_HOST_BUILD_DIR must be set to a build host build of mono - NOT $(BUILD_HOST_BUILD_DIR)" ;\ ls nofile ;\ else \ cp $(BUILD_HOST_BUILD_DIR)/mcs/build/config.make mcs/build/config.make ;\ fi endif ....... install-indep: install-indep-stamp install-indep-stamp: dh_testdir dh_testroot #dh_clean -k -i dh_installdirs -i ifneq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE)) @echo "Copy in host build directories" @mkdir -p debian/tmp/usr/lib/monodoc @for d in $(BUILD_HOST_DIRS) ;\ do \ if [ -d $$d ] ;\ then \ rm -fr $$d ;\ fi ;\ cp -fr $(BUILD_HOST_BUILD_DIR)/$$d ./$$d;\ done @echo "and files....." @for f in $(BUILD_HOST_FILES) ;\ do \ cp $(BUILD_HOST_BUILD_DIR)/$$f ./$$f ;\ done endif cd mcs && \ $(MAKE) install NO_DIR_CHECK=1 DESTDIR=$(CURDIR)/debian/tmp PROFILE=net_1_1 && \ $(MAKE) install NO_DIR_CHECK=1 DESTDIR=$(CURDIR)/debian/tmp PROFILE=net_2_0 && \ $(MAKE) install NO_DIR_CHECK=1 DESTDIR=$(CURDIR)/debian/tmp PROFILE=net_3_5 ......
TODO:: A mechanism for passing the location of this directory to xdeb so scripted package list builds are possible - at present the absolute location must be hard coded into rules file. TODO:: State the preferred solution from
Amend upstream package to build build host & target host binaries/data as required.
- Amend packaging to use pre-built build host build
- Other
gobject introspection
gobject introspection packages use build host binaries (g-ir-scanner) to examine the target binaries and/or libraries produced during the build and produce some target binary interface to their gobject functionality. Hence, the cross build fails, trying to dlopen a target binary on the build host. Whilst a correct solution may be found eventually , a simple way to allow me to proceed with the stack, was to disable introspection and exclude the missing files (.gir .typelib etc) from packaging.
g-ir-scanner runs the package binary which is built in order to query it for gobject data and incorporates this into the resulting .gir.
If the g-ir-scanner & g-ir-compiler are sufficiently decoupled it may be possible to skip the scanner run and provide a hand made .gir for subsequent use by the compiler. Areas to examine
In what fashion would a cross .gir & .typelib differ from that of the host? If identical we can use those from host build or host package to complete the cross package.
atk-1.0 are identical i386/armel Further Investigation
- Can g-ir-scanner br run without the --program switch to produce partial info for the .gir.
- If so is the info useful for the cross build?
- If they do differ what rules can be used to contruct suitable files?
- Can this be automated?
Affected packages will not be available with gobject introspection until native compilation is available.
The broken cross packages produce no
- API xml (.gir) files
- Compiled .gir (.typelib) files
Whilst this will mainly affect run time interaction of Gnome objects in the target GUI it is possible that some startup scripts may make use of introspection.
TODO: Check startup scripts for effects.
ifeq ($(cdbs_crossbuild),yes) DEB_CONFIGURE_EXTRA_FLAGS += --enable-introspection=no DEB_CONFIGURE_EXTRA_FLAGS += --disable-gtk-doc DEB_DH_INSTALL_ARGS+=--exclude=gtk-doc DEB_DH_INSTALL_ARGS+=--exclude=girepository-1.0 DEB_DH_INSTALL_ARGS+=--exclude=gir-1.0 endif
gtk-doc must also be excluded - it produces package documentation from the (missing) .gir files.
Note the use of the cdbs_cross build variable available in cdbs, rather than an explicit
ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE))
TODO: Modify gobject-introspection to allow cross building.
Currently libraries produced by a package are dlopen()'d thus the target dynamic loader needs to run on the build host.
Thus modifying for cross build may be non-trivial.
Packages affected
Packages affected in ALIP:
- gobject-introspection
- atk1.0
- gstreamer0.10
- gst-plugins-base0.10
- pango1.0
- udev
- gdk-pixbuf
- libsoup
Packages producing gir files in maverick:
config binaries
Some packages install configuration binaries which can be used by the configure script to determine library & header location e.g. gpg-error-config.
Well behaved configure scripts provide a variable to allow use of an alternative binary.
rules can make use of this see e.g libgcrypt11 in https://code.launchpad.net/~peter-pearse
patching dynamic files
Some packages apply patches to files which are modified later during the build.
This prevents the patches being reverted.
xdeb cleans the build tree before ??when??
Thus these patches cause the xdeb process to fail.
A crude solution is to grab the affected files immediately after patching & restore them immediately before cleaning.
This example assumes the rules file uses cdbs
post-patches:: @echo "Save some patched files - the ensuing build massages them, preventing unpatching" @echo "Save the first of each only, later ones will have been massaged" @for f in $(BADLY_PATCHED_FILES) ; \ do \ dir=`dirname $$f` ; \ if [ ! -f /tmp/cups_build/$(DEB_HOST_GNU_TYPE)/$$f ] ; \ then \ mkdir -p /tmp/cups_build/$(DEB_HOST_GNU_TYPE)/$$dir ; \ cp $$f /tmp/cups_build/$(DEB_HOST_GNU_TYPE)/$$dir ; \ fi \ done cleanbuilddir:: @echo "Restore saved files over those massaged by the build," @echo "so that patches may be unpatched" @for f in $(BADLY_PATCHED_FILES) ; \ do \ if [ -f /tmp/cups_build/$(DEB_HOST_GNU_TYPE)/$$f ] ; \ then \ mv /tmp/cups_build/$(DEB_HOST_GNU_TYPE)/$$f $$f ; \ fi \ done rm -fr /tmp/cups_build
TIP:: Get this mechanism workig before attempting to fix any other cross build problems, then you can re-run the failing xdeb command with less hassle
cdbs python
When cross building native extensions, information regarding the cross tools must be passed to python.
I couldn't ascertain how cdbs intends this to be done so I extended /usr/share/cdbs/1/class/python-distutils.mk
# These are the tool defaults used during setup.py LINARO_PYTHON_SET_ENV = \ export CC=gcc ;\ export CXX=g++ ;\ export LDSHARED='gcc -shared' ;\ export CPP=cpp ;\ export LDFLAGS='-L /usr/lib -L /lib' ;\ export BASECFLAGS=-DBASECFLAGS ;\ export OPT=-DOPT ;\ export CFLAGS='-I/usr/include -I/include';\ export CPPFLAGS=-DCPPFLAGS $(patsubst %,debian/python-module-stampdir/%,$(cdbs_python_indep_packages)) :: debian/python-module-stampdir/%: @echo "$@ in modified /usr/share/cdbs/1/class/python-distutils.mk" $(LINARO_PYTHON_SET_ENV) && \ cd $(DEB_SRCDIR) && python$(cdbs_python_nondefault_version) $(DEB_PYTHON_SETUP_CMD) build $(DEB_PYTHON_BUILD_ARGS) touch $@ $(patsubst %,debian/python-module-stampdir/%,$(cdbs_python_arch_packages)) :: debian/python-module-stampdir/%: @echo "$@ in modified /usr/share/cdbs/1/class/python-distutils.mk" set -e; for buildver in $(cdbs_python_build_versions); do \ $(LINARO_PYTHON_SET_ENV) && \ cd $(CURDIR) && cd $(DEB_SRCDIR) && $(call cdbs_python_binary,python$$buildver) $(DEB_PYTHON_SETUP_CMD) \ build $(DEB_PYTHON_BUILD_ARGS); \ done touch $@
and /usr/share/cdbs/1/class/python-sugar.mk
# LINARO_PYTHON_SET_ENV, defined in /usr/share/cdbs/1/class/python-distutils.mk, # allows e.g. cross tools to be set for use during setup.py $(patsubst %,build/%,$(DEB_PYTHON_SUGAR_PACKAGES)) :: build/%: [ ! -e $(cdbs_cursrcdir)/MANIFEST ] || [ -e $(cdbs_cursrcdir)/MANIFEST.upstream ] || mv $(cdbs_cursrcdir)/MANIFEST $(cdbs_cursrcdir)/MANIFEST.upstream [ ! -e $(cdbs_cursrcdir)/MANIFEST.upstream ] || egrep -v '^locale/.*/(.*\.mo|activity\.linfo)$$' $(cdbs_cursrcdir)/MANIFEST.upstream > $(cdbs_cursrcdir)/MANIFEST @echo "$@ in modified /usr/share/cdbs/1/class/python-sugar.mk" set -e; for buildver in $(cdbs_python_build_versions); do \ $(LINARO_PYTHON_SET_ENV);\ $(call cdbs_python_binary,python$$buildver) $(cdbs_cursrcdir)/setup.py build; \ touch /home/chroot-user/python_run ;\ done [ ! -e $(cdbs_cursrcdir)/MANIFEST.upstream ] || IFS="`printf '\n'`" find "$(cdbs_cursrcdir)/locale" -type f \( -name '*.mo' -or -name 'activity.linfo' \) | while read path; do \ echo "$$path" | sed 's!^$(cdbs_cursrcdir)/!!' >> $(cdbs_cursrcdir)/MANIFEST; \ done
The necessary setup is done in the rules file
# This requires that # /usr/share/cdbs/1/class/python-distutils.mk # be modified to export these values before calling # <python command> <setup.py script> build # TODO:: Find a better way.... LINARO_PYTHON_SET_ENV = \ export CC=$(DEB_HOST_GNU_TYPE)-gcc; \ export CXX=$(DEB_HOST_GNU_TYPE)-g++; \ export LDSHARED='$(DEB_HOST_GNU_TYPE)-gcc -shared'; \ export CPP=$(DEB_HOST_GNU_TYPE)-cpp; \ export LDFLAGS='-L /usr/$(DEB_HOST_GNU_TYPE)/lib -L /usr/$(DEB_HOST_GNU_TYPE)/usr/lib'; \ export BASECFLAGS=-DBASECFLAGS; \ export OPT=-DOPT; \ export CFLAGS='-I/usr/$(DEB_HOST_GNU_TYPE)/include -I/usr/$(DEB_HOST_GNU_TYPE)/usr/include'; \ export CPPFLAG
Other
In the standard linux, "let's invent a better wheel" way, various packages use build systems other than configure/make/install.
Whatever their other merits, several have no recognition of cross building. List
Others can be configured to cross build as follows
cmake
Pass a cross toolchain configuration to configure.
See libical package in my PPA.
qmake
For qt itself:
Supply -xplatform <cross id> to the configure
Make <qt>/mkspecs/<cross id> containing cross toolchain info
- Base qmake.conf on mkspecs/linux-g++/qmake.conf
- qplatform.defs just a straight copy of mkspecs/linux-g++/qplatform.defs
Here's some stuff I found out before realising I'd omitted some of the linux-g++/qmake.conf contents......
- Basis for Makefiles provided by the .pro .pri files
See special variable PRIVATE_LIBS used to pass internally created libraries e.g. while building QtCore libcorelib may be needed
- Where that fails try LIBS
perl
See here
python
Python mainly gets it's C toolchain configuration from the environment.
See apparmor for an example of subverting this.
apache
apparmor provides a simple example
- apparmor has it's own libtool - force apxs to use it
- Configure apxs on the command line to set CC
Useless cross packages
xdeb fails if it finds that a crossed package gives no useful output
put a skipping log here
Such packages need to be added to the cross black list in the xdeb configuration file - /etc/xdeb/xdeb.cfg
Dirty Tricks
Failure messages of the form "Try setting -r Wl,rpath"
Should binutils, the cross toolchain, multiarch & sysroot all disagree the cross system directories may be given by redirecting the linker to use a linker script.
Once the cross toolchain is installed
chroot > /usr/arm-linux-gnueabi/bin/ld --verbose > /work/armvseventhumb2/cr/usr/arm-linux-gnueabi/bin/sysroot.lds chroot > mv /usr/arm-linux-gnueabi/bin/ld /usr/arm-linux-gnueabi/bin/ld-real
Edit /usr/arm-linux-gnueabi/bin/sysroot.lds search paths as desired.
Create /usr/arm-linux-gnueabi/bin/ld with the following content:
# # Intercept ld to provide "sysroot" via linker script # /usr/arm-linux-gnueabi/bin/ld-real --script /usr/arm-linux-gnueabi/bin/sysroot.lds $*
Check permissions etc.
<chroot>/etc/dpkg-cross/cross-config.armel
Setting configure variables in this file can save having to patch the package itself.
Some packages have to be patched to make use of this mechanism
Source Package |
<chroot>/etc/dpkg-cross/cross-config.armel entries |
Package needs patch to comply |
?? |
?? |
?? |
Platform/DevPlatform/CrossCompile/CrossPatching (last modified 2011-05-04 13:29:57)