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 X-(

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.

  • 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. X-(

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

??

??

??


CategoryCrossCompile

Platform/DevPlatform/CrossCompile/CrossPatching (last modified 2011-05-04 13:29:57)