summaryrefslogtreecommitdiffstats
path: root/doc/devel/cross-compile.dox
blob: cc7685ebabd22cf3ccc6bceedea7b30b2b2ccb1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
// Copyright (C) 2020-2022 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

/**

 @page crossCompile Kea Cross-Compiling Example

The idea is to install Kea on a Raspberry Pi 4 Model B running Raspbian
operation system (e.g. the
<a href="https://www.raspberrypi.org/software/operating-systems/">
Raspbian Buster with desktop and recommended software</a> distribution)
without having to compile Kea on the Raspberry Pi box itself as it
takes some hours so using a standard Linux box with a x86_64 processor.

To cross-compile anything for Raspbian you need:
 - a cross-compiler running on x86_64 producing arm binaries
 - either an image of system copied from a Raspberry disk or extracted
  from a Raspbian repository.

@section toolChain Cross-Compile Tool Chain

A priori it is possible to compile your own tool chain or to use
a package as the arm-linux-gnueabihf one on Ubuntu. But there is
reported compatibility issue with old Raspberry Pi versions) so
we recommend a pre-built dedicated tool chain for this purpose:
<a href="https://github.com/Pro/raspi-toolchain">RaspberryPi toolchain on github</a>.

The documentation of this tool chain gives a rsync command which
copies selected parts of the Raspberry Pi root filesystem ("rootfs").
If you have no access to a running Raspberry Pi it is still possible
to get them following next section instructions. If you have, simply
skip this part.

@section noRaspberry How to get system and packages without a running Raspberry Pi

It is not required to have access to a running Raspberry Pi.
The system disk image is available at the Raspbian URL.
Packages are in the Raspian repository which is given in
sources list files in this disk image or below.

The /etc/apt/sources.list file content is:
@verbatim
deb http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
# deb-src http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi
@endverbatim

and the /etc/apt/sources.list.d/raspi.list file content is:
@verbatim
deb http://archive.raspberrypi.org/debian/ buster main
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
# deb-src http://archive.raspberrypi.org/debian/ buster main
@endverbatim

The disk image is a zipped image of a 4GB disk with a standard MSDOS
boot block with two volumes:
 - boot (useless for this purpose)
 - rootfs (the Raspberry Pi root filesystem)

The idea is to mount the rootfs on the Linux box (it can work on another
system as soon as it supports the ext4 file system type):
 - first use fdisk or similar tool to get the offset of the first block
  of the rootfs (second) volume
 - if the offset is in block unit multiply by 512 (block size)
 - mount as root (sudo mount ...) with the loop option, the offset option,
  the unzipped image file name and a mount point (absolute path of
  a directory)
If you have a SD card with Raspbian installed on it and a SD reader
you can directly mount the rootfs from it.

If a dependency (i.e. the Raspbian version of a library) is not in the
rootfs image you need to simulate its installation:
 - get the .deb file from a Raspbian repository
 - extract files using the dpkg-deb -R tool on the .deb file
 - install the files (usually in the "rootfs"/usr directory)
The idea is the files (includes and libraries) can be found by
the cross-compiling tool chain.

It is possible to emulate a Raspberry Pi using qemu even I do not think
it can run Kea. But at least it can run some tests as the hello world sample
of the tool chain. Required qemu kernels can be found in
<a href="https://github.com/dhruvvyas90/qemu-rpi-kernel">this github repo</a> with
a documentation, which is well worth reading.

@section crossCompilePitfalls Usual problems

There are two usual problems when cross-compiling:
 - have a binary for the wrong processor, e.g. either trying to run
  an arm binary on the x86_64 box or building a x86_64 binary when
  it will be run by the Raspberry Pi
 - use the x86_64 system include or library instead of the Raspberry Pi
  one from the rootfs image. Usually it gives a direct error for a library
  but a wrong include is more subtle.
Note that Kea has a build tool (kea-msg-compiler) but its use is optional
so it should not be a problem. If anyway you need it simply copy it from
a native (i.e. not cross-compiled) Kea build.

@section raspbianDependencies Usual Kea Dependencies

Required and optional Kea dependencies, usually available as packages:
 - Python (built-in)
 - libssl-dev (built-in in the full image)
 - liblog4cplus-dev (in liblog4cplus package, load both the library and
  the development part)
 - libboost-system-dev (in boost-xxx, load both the boost-system and
  the boost-libraries packages, the second includes header files)
 - googletest (download the last release from github)
 - doc (sphinx, texlive, etc: just generate docs on the build system)
 - MySQL (in mysql-defaults and mariadb-* packages?)
 - PostgreSQL (in postgresql-12?)

@section prepareCrossCompile Prepare Cross Compiling

This script was used with success: it sets the environment variables
before calling ./configure.
@code
# change when at another location
export ROOTFS="$HOME/rpi/rootfs"

# build commands
export BUILD=x86_64-pc-linux-gnu
export HOST=arm-linux-gnueabihf
export CC="${HOST}-gcc"
export CXX="${HOST}-g++"
export LD="${HOST}-ld"
export AR="${HOST}-ar"
export RANLIB="${HOST}-ranlib"
export STRIP="${HOST}-strip"
export NM="${HOST}-nm"

# g++ flags
CXXFLAGS="-O2 -g -isysroot ${ROOTFS} -I${ROOTFS}/usr/include"
CXXFLAGS+=" -I${ROOTFS}/usr/include/${HOST}"

# ld flags
LDFLAGS="--sysroot=${ROOTFS}"
LDFLAGS+=" -L/opt/cross-pi-gcc/arm-linux-gnueabihf/lib -Wl,-rpath-link,/opt/cross-pi-gcc/arm-linux-gnueabihf/lib"
LDFLAGS+=" -L/opt/cross-pi-gcc/lib -Wl,-rpath-link,/opt/cross-pi-gcc/lib"
LDFLAGS+=" -L${ROOTFS}/opt/vc/lib -Wl,-rpath-link,${ROOTFS}/opt/vc/lib"
LDFLAGS+=" -L${ROOTFS}/lib/${HOST} -Wl,-rpath-link,${ROOTFS}/lib/${HOST}"
LDFLAGS+=" -L${ROOTFS}/usr/local/lib -Wl,-rpath-link,${ROOTFS}/usr/local/lib"
LDFLAGS+=" -L${ROOTFS}/usr/lib/${HOST} -Wl,-rpath-link,${ROOTFS}/usr/lib/${HOST}"
LDFLAGS+=" -L${ROOTFS}/usr/lib -Wl,-rpath-link,${ROOTFS}/usr/lib"
LDFLAGS+=" -L${ROOTFS}/usr/lib/${HOST}/blas -Wl,-rpath-link,${ROOTFS}/usr/lib/${HOST}/blas"
LDFLAGS+=" -L${ROOTFS}/usr/lib/${HOST}/lapack -Wl,-rpath-link,${ROOTFS}/usr/lib/${HOST}/lapack"

# CPU tuning (use the most generic one)
# PI 4 (not sure for the FPU)
# CXXFLAGS+=" -mcpu=cortex-a72 -mfpu=neon-vfpv4 -mfloat-abi=hard"
# PI 3
# CXXFLAGS+=" -mcpu=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard"
# PI 2
# CXXFLAGS+=" -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard"
# PI 1, zero, ...
CXXFLAGS+=" -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard"

export CXXFLAGS
export LDFLAGS

export PKG_CONFIG_PATH="${ROOTFS}/usr/lib/pkgconfig"

export PATH=/opt/cross-pi-gcc/bin:/opt/cross-pi-gcc/libexec/gcc/arm-linux-gnueabihf/8.3.0:$PATH

# libraries are in fact in ${ROOTFS}/usr/lib/${HOST} but
# the library path can be set only for boost.
CONF_CMD="./configure --build=${BUILD} --host=${HOST}"
CONF_CMD+=" --with-sysroot=${ROOTFS}"
CONF_CMD+=" --with-openssl=${ROOTFS}/usr"
CONF_CMD+=" --with-log4cplus=${ROOTFS}/usr"
CONF_CMD+=" --with-boost-include=${ROOTFS}/usr/include"
CONF_CMD+=" --with-boost-lib-dir=${ROOTFS}/usr/lib/${HOST}"
@endcode

Some explanations:
 - the rootfs was copied or mounted in rpi/rootfs in the home directory.
 - the build system triplet is x86_64-pc-linux-gnu (processor,
  system, application binary interface). It is returned by the config.guess
  script so please verify.
 - the host system triplet is arm-linux-gnueabihf. It is used as the prefix
  for cross-compiling tools so this value is critical.
 - all tool variables are set to the cross-compiling tool name
 - CXXFLAGS is defined to use the rootfs image for includes. It is critical
  it does not use any build system include.
 - LDFLAGS is defined to use the rootfs, all cross-compiler support libraries
  and libraries from the rootfs image. It is critical it does not use
  any build system library.
 - CXXFLAGS can be tuned for a specific Raspberry Pi version. Proposed
  tuning supports all versions.
 - even if Kea ./configure does not depends on pkgconfig its path is set.
 - PATH is updated to find first cross-compiling tools.
 - I did not try yet database config scripts: perhaps they detect
  cross-compiling and produce correct paths.
 - CONF_CMD contains the ./configure common arguments.

The script can be used by:
 - eventually run "autoreconf -i" (if sources are from git)
 - put its content in a file, e.g. ccenv
 - load the file by ". ccenv"
 - configure Kea build by "$CONF_CMD <your arguments>"

Known problems:
 - AC_TRY_RUN and AC_CHECK_FILE[S] autoconf macros do not support
  cross-compiling. They were removed from ./configure.ac in Kea 1.7.10.
 - libtool is a disaster for cross-compiling, in particular it produces
  silly libtool archive (.la) files. Fortunately they are useless.
 - bad paths for mkdir or sed on Raspbian.
 - recent Debian systems including recent Ubuntu modified libtool to
  not accept indirect dependencies. Makefiles were updated to have no
  such indirect dependencies in common cases as it is in Kea Makefile
  writing guidelines.
 - the libtool variable managing this is link_all_deplibs. You can
  edit the libtool script to set it to unknown or yes. Or simply
  use another Linux distrib.
 - there is no ldd in cross-compiling tools. The table of used
  shared libraries in available by readelf -d which is in the
  cross-compiling tools.

Final words: this is still highly experimental and does not cover
everything. New ways to offload almost everything outside the Raspberry
Pi are still to be found. Currently to provide Raspbian Kea packages
is not possible for ISC.

*/