Cross compiling LibreOffice for the Raspberry Pi3

https://ray-v.github.io/LO-aarch64-gui.png... cross compiled for aarch64, running in a TDE desktop, on a RPi3.

These builds are done on an x86_64 machine for the RPi3 running Slackware arm-current [armv7_hf] or Slarm64 [aarch64][history][download from a Slackware mirror - for example slackware.uk where rsync is available].
Although this page is primarily about cross compiling LibreOffice for the RPi3, that setup is an addition to a native x86_64 build, and so cross compiling is shown as an addition to the native build. An i686 cross build option is included as it's an identical setup to the arm cross builds.
There are therefore four build options - native x86_64; cross armv7, aarch64, or i686.
The page has been laid out so that the contents can be copied and pasted into a console allowing a step-by-step build to aid troubleshooting.


LO build environment
/LO_build ├── libreoffice-x.x.x.x build from source tarballs ├── external_tarballs source archives for non-system build requirements ├── pkg-$Arch DESTDIR for packaging installation └── LO-$Arch-sysroot installation directory for HOST libs and headers

With the exception of these initial downloads, the non-system sources will be downloaded during 'make'.

cd /LO_build/ export LO_VERSION=6.3.3.2


Build from tarballs
  download
(cd external_tarballs SRC_URL=https://download.documentfoundation.org/libreoffice/src DIR=$(echo $LO_VERSION | cut -d "." -f1-3) wget $SRC_URL/$DIR/libreoffice-$LO_VERSION.tar.xz wget $SRC_URL/$DIR/libreoffice-dictionaries-$LO_VERSION.tar.xz wget $SRC_URL/$DIR/libreoffice-help-$LO_VERSION.tar.xz wget $SRC_URL/$DIR/libreoffice-translations-$LO_VERSION.tar.xz)
  extract
tar xf external_tarballs/libreoffice-$LO_VERSION.tar.xz ## uncompress any of the submodule tarballs now if they need patching - for example: tar xf external_tarballs/libreoffice-translations-$LO_VERSION.tar.xz ## apply patch (cd libreoffice-$LO_VERSION/translations/source/en-GB/helpcontent2/source/text/scalc/ line_no=$(grep -n "msgstr.*COLOR function" 01.po | cut -d: -f1) sed -i "${line_no}s|COLOR|COLOUR|" 01.po) ## let the build know that the submodule has been unpacked … mkdir -p libreoffice-$LO_VERSION/src/libreoffice-translations-$LO_VERSION cd libreoffice-$LO_VERSION


Native build - variables will be overwritten if cross compiling
Set the configure option --host == --build [using the autotools definition of host - the machine the compiled code will run on]
export HOST=$(bash ./config.guess) export Arch=x86_64 export STRIP=strip
Gcc optimization ## for build machine, for native x86_64 or cross i686 builds, for LO to run on same machine architecture export OPTM=$(echo $(gcc -Q -O2 -march=native --help=target | grep -E "^ -march=|^ -mtune=|^ -mfpmath=" | tr -d [:blank:])) ## or set manually for the intended x86 host machine ## export OPTM= export CC="gcc ${OPTM:-}" export CXX="g++ ${OPTM:-}"

Cross compiling  setting up for cross compiling

close The toolchain used is the custom built gcc cross compiler here, which includes some compiler optimizations, and creating a kernel headers package. This is the installtion tree for that cross-compiler and sysroot. The intention is that the cross tools are contained within one directory and can be installed/mounted only when required. sysroot libs and headers can be permanently installed within the cross-compiler tree or bind mounted from another media or directory. /opt └── cross-pi-gcc cross tools    └── sysroot location defined in x-tools build Set the cross tools directories export XGCC_DIR=/opt/cross-pi-gcc export SYSROOT=$XGCC_DIR/sysroot [1] Set variables for an armv7, aarch64, or i686 build. 32-bit armv7_hf export HOST=arm-linux-gnueabihf export Arch=armv7 export STRIP=$HOST-strip ## the cross compiler has been built with arm_hf optimizations export CC=$HOST-gcc export CXX=$HOST-g++ export LIBDIRSUFFIX="" ## Slack_base = where the Slackware packages a-y directories are export Slack_base=/path_to_Slackware_arm_current Error: /LO_build/libreoffice-6.3.3.2/sal/osl/unx/process_impl.cxx:108:14: error: ‘PATH_MAX’ was not declared in this scope … and others … Add linux/limits.h which defines PATH_MAX: sed -i 's|limits.h>|&\n#include <linux/limits.h>|' {sal/osl/unx/process_impl.cxx,cppuhelper/source/findsofficepath.c,desktop/unx/source/start.c,vcl/unx/generic/fontmanager/helper.cxx,uui/source/logindlg.cxx} sed -i 's|MSVC|&\n#include <linux/limits.h>|' pyuno/source/loader/pyuno_loader.cxx OR: 64-bit aarch64 export HOST=aarch64-linux-gnu export Arch=aarch64 export STRIP=$HOST-strip ## -march=armv8-a+crc is the default compiler optimization, so just add -mtune=cortex-a53 export CC="$HOST-gcc -mtune=cortex-a53" export CXX="$HOST-g++ -mtune=cortex-a53" export LIBDIRSUFFIX=64 ## Slack_base = where the Slarm64 packages a-y directories are export Slack_base=/path_to_Slarm64 OR: 32-bit x86 - i686 export HOST=i686-linux-gnu export Arch=i686 export STRIP=$HOST-strip export CC="$HOST-gcc ${OPTM:-}" export CXX="$HOST-g++ ${OPTM:-}" export LIBDIRSUFFIX="" ## build can't find 'libssp.so.0', which Slackware doesn't include export LD_LIBRARY_PATH=$XGCC_DIR/$HOST/lib ## Slack_base = where the Slackware packages a-y directories are export Slack_base=/path_to_Slackware32_current [2] Cross compiler Install cross tools installpkg /tmp/xgcc910-glibc2.29-<for_Arch>.txz To avoid any issues with the different limits.h priorities producing this error: .../include/bits/stdlib.h:90:3: error: #error "Assumed value of MB_LEN_MAX wrong" use the work-around as detailed here. (cd $XGCC_DIR/lib/gcc/*-linux-gnu*/9.1.0/plugin/include/ cat limitx.h glimits.h limity.h > ../../include-fixed/limits.h) Location of installed HOST libs and headers export HOST_INSTN=/LO_build/LO-$Arch-sysroot [3] Set up a sysroot for the HOST libs and headers needed for the LibreOffice build. OR skip this and just mount the media containing the HOST installation to $SYSROOT My preference is to set this up in a separate directory and bind-mount it to the cross compiler sysroot directory. This enables me to set up different sysroots for whatever is being cross compiled. Install kernel headers and Slackware or Slarm64 libs/headers to a HOST_installation directory export ROOT=$HOST_INSTN installpkg /tmp/kernel-headers-<for_Arch>.txz cd $Slack_base installpkg a/bzip2-*.txz installpkg a/dbus-*.txz installpkg a/util-linux-*.txz installpkg a/xz-*.txz installpkg ap/cups-*.txz installpkg ap/sqlite-*.txz installpkg d/gcc-9.1.0-*.txz installpkg d/gcc-g++-9.1.0-*.txz installpkg d/python-2.*.txz installpkg d/python3-*.txz installpkg l/at-spi2-atk-*.txz installpkg l/at-spi2-core-*.txz installpkg l/atk-*.txz installpkg l/cairo-*.txz installpkg l/expat-*.txz installpkg l/freetype-*.txz installpkg l/fribidi-*.txz installpkg l/gdk-pixbuf2-*.txz installpkg l/glib2-*.txz installpkg l/gmp-*.txz installpkg l/graphite2-*.txz installpkg l/gtk+2-*.txz installpkg l/gtk+3-*.txz installpkg l/harfbuzz-*.txz installpkg l/icu4c-*.txz installpkg l/libffi-*.txz installpkg l/libidn2-*.txz installpkg l/libpng-1.6.*.txz installpkg l/libunistring-0.9.*.txz installpkg l/libxml2-*.txz installpkg l/libxslt-*.txz installpkg l/mozilla-nss-*.txz installpkg l/pango-*.txz installpkg l/pcre-*.txz installpkg l/shared-mime-info-*.txz installpkg l/zlib-*.txz installpkg n/gnutls-*.txz installpkg n/nettle-*.txz installpkg n/p11-kit-*.txz installpkg x/fontconfig-*.txz installpkg x/libICE-*.txz installpkg x/libSM-*.txz installpkg x/libX11-*.txz installpkg x/libXau-*.txz installpkg x/libXcomposite-*.txz installpkg x/libXcursor-*.txz installpkg x/libXdamage-*.txz installpkg x/libXdmcp-*.txz installpkg x/libXext-*.txz installpkg x/libXfixes-*.txz installpkg x/libXi-*.txz installpkg x/libXinerama-*.txz installpkg x/libXrandr-*.txz installpkg x/libXrender-*.txz installpkg x/libXtst-*.txz installpkg x/libXxf86vm-*.txz installpkg x/libdrm-*.txz installpkg x/libepoxy-*.txz installpkg x/libglvnd-*.txz installpkg x/libpthread-stubs-*.txz installpkg x/libxcb-*.txz installpkg x/mesa-*.txz installpkg x/pixman-*.txz installpkg x/xorgproto-*.txz ## move ldconfig out of the way - links will be set up by doinst.sh mv /sbin/ldconfig /sbin/ldconfig-bak installpkg l/glibc-2.29*.txz mv /sbin/ldconfig-bak /sbin/ldconfig unset ROOT cd - [4] Mount HOST_installation directory to SYSROOT mount -B $HOST_INSTN $SYSROOT [5] Set up shell variables Create a wrapper script for pkg-config which needs to access the libs and headers for the host system. This script sets it up to prefix $SYSROOT to the -L and -I paths in the .pc files. Exclude coinmp which uses <tuple>-pkg-config in its configure script to define paths in its source code and hence prefixes SYSROOT to those paths. This script will then run with the native PKG_CONFIG_* variables for coinmp. echo $"[[ ! \$PKG_CONFIG_PATH == *CoinUtils* ]] && { export PKG_CONFIG_PATH= export PKG_CONFIG_SYSROOT_DIR=$SYSROOT export PKG_CONFIG_LIBDIR=$SYSROOT/usr/lib$LIBDIRSUFFIX/pkgconfig } exec pkg-config \"\$@\"" > $XGCC_DIR/bin/$HOST-pkg-config chmod 700 $XGCC_DIR/bin/$HOST-pkg-config Ref: README.cross - set PYTHON_CFLAGS [Python2] export PY_INC=$(python -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('INCLUDEPY'));") export PYTHON_CFLAGS=-I$SYSROOT$PY_INC export PYTHON_LIBS=-l$(echo $PY_INC | rev | cut -d "/" -f 1 | rev ) ## Check: echo $PYTHON_CFLAGS echo $PYTHON_LIBS Add cross tools binaries to the PATH export PATH=$XGCC_DIR/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin [6] Replace RepositoryModule_build.mk module list with that from RepositoryModule_host.mk. This probably increases the build time by including unnecessary BUILD platform modules in the build, but to-date I haven't found an alternative to avoid the string of errors, for example: .../libreoffice-6.3.0.4/solenv/gbuild/ComponentTarget.mk:50: *** No LIBFILENAME set at component target: .../libreoffice-6.3.0.4/workdir_for_build/ComponentTarget/animations/source/animcore/animcore.component. Stop. … and … .../libreoffice-6.3.0.4/solenv/gbuild/LinkTarget.mk:687: *** used LinkTarget Library/libopencllo.so not defined. Stop. etc … The build time on a dual core 2.2GHz machine is 15+ hours for the cross compilation. ## Test for this having been done already if this is a second build: [[ ! -s RepositoryModule_build.mk-original ]] && { mv RepositoryModule_build.mk RepositoryModule_build.mk-original ## .. delete from .. sed '/add_moduledirs/q' RepositoryModule_build.mk-original > RepositoryModule_build.mk ## .. print section (inclusive) sed -n '/accessibility/,/xmlsecurity/p' RepositoryModule_host.mk >> RepositoryModule_build.mk ## .. print from (inclusive) sed -n '/^))/,$p' RepositoryModule_build.mk-original >> RepositoryModule_build.mk }
  • To cross compile for the other architectures after this build, see Cross compiling 2
  • close

    Configure options are set with CONFIGURE_OPTS, rather than in an autogen.input file, for inclusion in the cross compilation -⁠-⁠with-⁠build-⁠platform-⁠configure-⁠options parameter. The vcl plugins gen, gtk[2], and gtk3 are included in the build.
    Installation is to $DESTDIR for packaging where the prefix for the installed package is set.

    NUMJOBS=6 && [[ $(getconf _NPROCESSORS_ONLN) -ge 4 ]] && export NUMJOBS=$[$(getconf _NPROCESSORS_ONLN)*2] LOCN=en-GB --with-lang=$LOCN => includes translations submodule --with-help => includes helpcontent2 submodule => adds $LOCN to off-line help --with-myspell-dicts => includes dictionaries submodule for spellcheck export CONFIGURE_OPTS=" --prefix=/ --disable-postgresql-sdbc --without-java --without-junit --disable-odk --without-krb5 --without-gssapi --disable-gstreamer-0-10 --disable-gstreamer-1-0 --disable-epm --enable-release-build --with-parallelism=$NUMJOBS --with-locales=$LOCN --with-lang=$LOCN --with-help --with-myspell-dicts --with-external-tar=/LO_build/external_tarballs --with-system-libatomic_ops --with-system-nss --with-system-libpng --with-theme=colibre"

    Patch for error:
    .../RepositoryModule_build.mk:12: *** Module does not exist: .../mysqlc/Module_mysqlc.mk. Stop.
    sed -i '/mysqlc/d ' RepositoryModule_build.mk

    The build needs plenty of ram and the only way to avoid freezing the build machine may be to enable an additional chunk of swap …
    swapon <additional-swap-partition>


    Building
    When running ./autogen.sh …

    Native:
    host_alias == build_alias, which is set by config.guess; the cross-compiling check will be 'no'; and -⁠-⁠with-⁠build-⁠platform-⁠configure-⁠options will be ignored.

    Cross:
    host_alias != build_alias; the cross-compiling check will be 'yes'; and -⁠-⁠with-⁠build-⁠platform-⁠configure-⁠options will be used, using or overriding any set for the host platform.

    b] For an armv7 cross build, with PYTHON_CFLAGS for the HOST building environment pointing to SYSROOT, this error occurs:
    pyport.h ... #error "LONG_BIT definition appears wrong for platform (bad gcc/glibc config?)." PYTHON_CFLAGS needs to be set separately for the BUILD platform headers.

    c] -⁠-⁠with-⁠build-⁠platform-⁠configure-⁠options
    This extract is the section in ./configure which determines the options applying to the BUILD platform build.
    They are hard-coded and override any set in CONFIGURE_OPTS and will in turn be overridden by any that follow in -⁠-⁠with-⁠build-⁠platform-⁠configure-⁠options ⇒ sub_conf_opts
    sub_conf_opts="$sub_conf_opts $with_build_platform_configure_options" # Don't bother having configure look for stuff not needed for the build platform anyway ./configure \ --disable-cups \ --disable-gstreamer-1-0 \ --disable-gstreamer-0-10 \ --disable-gtk \ --disable-gtk3 \ --disable-pdfimport \ --disable-postgresql-sdbc \ --with-parallelism="$with_parallelism" \ --without-doxygen \ --without-java \ $sub_conf_opts \ --srcdir=$srcdir \ 2>&1
    ./autogen.sh $CONFIGURE_OPTS --host=$HOST --with-build-platform-configure-options="$CONFIGURE_OPTS PYTHON_CFLAGS=-I$PY_INC --without-help --without-system-dicts" | tee /LO_build/autogen-log-$Arch--$(date +%h_%d_%H:%M) sed -i 's|check-if-root ||' Makefile make build-nocheck | tee /LO_build/make-log-$Arch--$(date +%h_%d_%H:%M)
    Install to packaging area
    DESTDIR=/LO_build/pkg-$Arch make install | tee /LO_build/install-log-$Arch--$(date +%h_%d_%H:%M)
    Remove unwanted dictionaries and help files, leaving just $LOCN
    rm -rf /LO_build/pkg-$Arch/lib/libreoffice/share/extensions/dict-es rm -rf /LO_build/pkg-$Arch/lib/libreoffice/share/extensions/dict-fr rm -rf /LO_build/pkg-$Arch/lib/libreoffice/help/en-US
    Remove more unwanted stuff, leaving just en
    ls /LO_build/pkg-$Arch/lib/libreoffice/share/{autocorr/*.dat,fingerprint/*lm,numbertext/*sor} | grep -vE "$LOCN|en.lm|en.sor|Roman" \ | while read line do rm $line done
    Strip binaries
    find /LO_build/pkg-$Arch | xargs file | grep -e "executable" -e "shared object" | grep ELF | cut -f 1 -d : | xargs $STRIP --strip-unneeded
    Create package to install to /opt/libreoffice
    mkdir -p /LO_build/pkg-$Arch/pkg/opt mv /LO_build/pkg-$Arch/lib/libreoffice /LO_build/pkg-$Arch/pkg/opt cd /LO_build/pkg-$Arch/pkg [[ $Arch == i686 ]] && cp $XGCC_DIR/$HOST/lib/libssp.so.0.0.0 opt/libreoffice/program/libssp.so.0 makepkg -l y -c n /LO_build/libreoffice-$LO_VERSION-$Arch-1.txz


    Cross compiling 2  continuing for the other architectures …

    close The cross compilation builds for the BUILD platform as well as the HOST platform. /LO_build ├── libreoffice-6.3.3.2 │   ├── workdir_for_build ├── workdir # for host build . ├── instdir_for_build ├── instdir # for host build That BUILD platform data can be used for a further HOST platform build, for example build for aarch64 after an armv7 build. x86_64 BUILD platform build ⇒ armv7 HOST platform build ⇒ armv7 package ↳ remove HOST compiled data … ↳ aarch64 HOST platform build ⇒ aarch64 package ↳ remove HOST compiled data … ↳ i686 HOST platform build ⇒ i686 package This can result in a significant time saving - built on a 2x quad-core 3GHz machine, the initial armv7 build was ~196 minutes, and by retaining the 'workdir_for_build' and the 'instdir_for_build', the build time was halved for an aarch64 build to ~103 minutes. An x86_64 native only build was ~107 minutes. [1] (Re)move previous host data: cd /LO_build/libreoffice-$LO_VERSION mv workdir workdir-$Arch mv instdir instdir-$Arch umount $SYSROOT mv $XGCC_DIR $XGCC_DIR-$Arch [2] Set up cross compile for the other architecture and continue through to 'makepkg' close

    Usage options
    To show Tip-of-the-Day each time LO is started,
    run with gtk2 vcl plugin,
    start with Calc,
    and avoid the banners for Release Notes and Donate links which are at:
    https://hub.libreoffice.org/ReleaseNotes/?LOvers=6.3&LOlocale=en https://hub.libreoffice.org/donation/?BCP47=en-GB&LOlang=en
    Initially, before running LO for the first time, … mkdir -p ~/.config/libreoffice/4/user/ echo '<?xml version="1.0" encoding="UTF-8"?> <oor:items xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <item oor:path="/org.openoffice.Office.Common/Misc"><prop oor:name="FirstRun" oor:op="fuse"><value>false</value></prop></item> <item oor:path="/org.openoffice.Office.Common/Misc"><prop oor:name="LastTipOfTheDayShown" oor:op="fuse"><value>0</value></prop></item> <item oor:path="/org.openoffice.Setup/Product"><prop oor:name="LastTimeDonateShown" oor:op="fuse"><value>0</value></prop></item> <item oor:path="/org.openoffice.Setup/Product"><prop oor:name="ooSetupLastVersion" oor:op="fuse"><value>6.3</value></prop></item> </oor:items>' > ~/.config/libreoffice/4/user/registrymodifications.xcu then for each new start … sed -i 's|LastTipOfTheDayShown.*$|LastTipOfTheDayShown" oor:op="fuse"><value>0</value></prop></item>|;s|LastTimeDonateShown.*$|LastTimeDonateShown" oor:op="fuse"><value>0</value></prop></item>|' ~/.config/libreoffice/4/user/registrymodifications.xcu SAL_USE_VCLPLUGIN=gtk /opt/libreoffice/program/soffice --calc

    When running LO 6.3.3.2 with the gen or gtk vcl plugin, the Tip of the Day text doesn't wrap in the dialog box if the text is selectable - my preference is wrapping text, so until bug 128524 is resolved:
    sed -i 's|selectable">True|selectable">False|' /opt/libreoffice/share/config/soffice.cfg/cui/ui/tipofthedaydialog.ui


    To clone this page from Github:
    git clone https://github.com/Ray-V/LOcrossbuild.git cd LOcrossbuild git checkout gh-pages