Cross-compilation
Lely CANopen can be cross-compiled for a variety of target architectures and operating systems. This page documents the process for the supported targets. Other targets may also work, but they are not tested in our CI/CD pipeline.
MinGW on Linux
Requirements
To cross-compile Lely CANopen for Windows under Linux, you first need to install the dependencies required for native builds.
MinGW
We will use Mingw-w64 instead of the original MinGW. It is available in the repositories of most Linux distributions. If not, download it from http://mingw-w64.org/doku.php/download.
On Debian/Ubuntu-based distributions, you can install the compiler with
sudo apt-get install mingw-w64
Wine
To run the Windows tests under Linux, you need to install Wine 3.18 or newer.
Wine 3.17 and older do not implement the GetQueuedCompletionStatusEx() function, which is used by the asynchronous I/O library.
To install Wine, follow the instructions at https://wiki.winehq.org/Download. In case of Ubuntu 18.04 LTS:
curl -L https://dl.winehq.org/wine-builds/winehq.key | sudo apt-key add -
sudo apt-add-repository 'deb https://dl.winehq.org/wine-builds/ubuntu/ bionic main'
curl -L https://download.opensuse.org/repositories/Emulators:/Wine:/Debian/xUbuntu_18.04/Release.key | sudo apt-key add -
sudo apt-add-repository 'deb https://download.opensuse.org/repositories/Emulators:/Wine:/Debian/xUbuntu_18.04/ ./'
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install winehq-stable
The OBS (openSUSE Build Service) repository contains libfaudio0, which is a dependency of Wine 4.5 and later.
Initialize your local Wine environment with
wineboot -i
Wine needs to be able to find some runtime DLLs from MinGW. Add their locations
to WINEPATH
with
export WINEPATH=Z:\\usr\\lib\\gcc\\i686-w64-mingw32\\7.3-posix\;Z:\\usr\\i686-w64-mingw32\\lib
for 32-bit Windows or
export WINEPATH=Z:\\usr\\lib\\gcc\\x86_64-w64-mingw32\\7.3-posix\;Z:\\usr\\x86_64-w64-mingw32\\lib
for 64-bit Windows. For convenience, you can add one of these lines to your
~/.bashrc
.
Note: The GCC version number (7.3) may be different on your platform. Change it accordingly.
IXXAT VCI
Lely CANopen supports IXXAT CAN controllers on Windows via the Virtual Communication Interface (VCI).
To build the stack with IXXAT support, you need the VCI SDK. Download and
install the
VCI V4 Driver
on a Windows machine, and copy the
C:\Program Files\HMS\IXXAT VCI 4.0\sdk\vci
folder to the Linux machine on
which you will cross-compile the stack.
Note: Make sure the C SDK is selected during install.
At runtime, the stack will try to load vcinpl2.dll
(or vcinpl.dll
if CAN FD
support is disabled).
Build instructions
As with native builds, clone the repository and prepare the build environment:
git clone https://gitlab.com/lely_industries/lely-core.git
cd lely-core
autoreconf -i
mkdir -p build
cd build
Configure the project with
../configure --host=i686-w64-mingw32 --disable-python
for 32-bit Windows, or
../configure --host=x86_64-w64-mingw32 --disable-python
for 64-bit Windows.
--disable-python
implies --disable-cython
. Additionally, it disables the
DCF tools.
If you have the IXXAT VCI SDK installed, add --with-ixxat=DIR
to
configure
; it will look for vcinpl2.h
(or vcinpl.h
if CAN FD support is
disabled) under DIR/inc
.
DIR
is the copy of C:\Program Files\HMS\IXXAT VCI 4.0\sdk\vci
.
Build the libraries and tools with
make
If you have Wine installed, you can run the test suite with
make check
Although it does not make much sense to install the Windows tools and libraries
on Linux, it is useful to run make install
to collect the build artifacts:
make install DESTDIR=$(pwd)/../install
You will find the tools and libraries in ../install/usr/local/bin
and the
headers in ../install/usr/local/include
.
Note: When you copy the artifacts to your target platform, make sure to also
include libwinpthread-1.dll
from
/usr/i686-w64-mingw32/lib
(or /usr/x86_64-w64-mingw32/lib
) and
libgcc_s_seh-1.dll
and libstdc++-6.dll
from
/usr/lib/gcc/i686-w64-mingw32/7.3-posix
(or
/usr/lib/gcc/x86_64-w64-mingw32/7.3-posix
).
ARM on Linux
Cross-compiling Lely CANopen for ARM systems running Linux, such as a Raspberry Pi, is quite straightforward.
Requirements
First, install the dependencies required for native builds. Then, install the cross-compiler and binutils for the desired target triplet:
Target triplet | ARM architecture |
---|---|
arm-linux-gnueabi | 32-bit ARMv6, ARMv5 or ARMv4T |
arm-linux-gnueabihf | 32-bit ARMv7, hard-float |
armv8l-linux-gnueabihf | 32-bit ARMv8, hard-float |
aarch64-linux-gnu | 64-bit ARMv8 |
If your distribution does not provide the required cross-compiler, you can download the toolchain from Linaro.
On Debian/Ubuntu-based systems, run
sudo apt-get install crossbuild-essential-armel
for arm-linux-gnueabi
,
sudo apt-get install crossbuild-essential-armhf
for arm-linux-gnueabihf
, or
sudo apt-get install crossbuild-essential-arm64
for aarch64-linux-gnu
.
If you want to run the tests, you’ll also need to install the QEMU user-mode emulation tools.
On Debian/Ubuntu, run
sudo apt-get install qemu-user
or
sudo apt-get install qemu-user-static
Build instructions
The steps for cloning the repository and preparing the build environment are the same as for native builds:
git clone https://gitlab.com/lely_industries/lely-core.git
cd lely-core
autoreconf -i
mkdir -p build
cd build
Configure the project for the desired target architecture with
../configure --host=HOST --disable-python
where HOST
is the target triplet.
To prevent overwriting the native libraries during make install
, you might
want to provide an installation prefix with the --prefix
or --exec-prefix
option. For multiarch-capable systems, at
least add the --libdir=${prefix}/lib/HOST
option.
Build the libraries and tools with
make
If you have QEMU installed, you can run the test suite with
make check
It may be useful to install the cross-compiled libraries on your build system so you can use them to cross-compile other applications. If you configured an installation prefix, simply run
make install
If you only want to collect the build artifacts, do not configure a prefix, but run
make install DESTDIR=$(pwd)/../install
Bare-metal ARM
Compiling and using Lely CANopen on a bare-metal platform is necessarily a custom process that needs to be tailored to each platform. In this section we will describe the general process.
You can find a specific example — an Eclipse project building a CANopen slave for the NXP LPC1700 series (ARM Cortex-M3) — at https://gitlab.com/lely_industries/lpc17xx.
Requirements
For bare-metal platforms it is generally more convenient to include the stack as a Git submodule and use the build system of the project instead of the stack (see the Eclipse example). However, you can use the build system of the stack to build a set of static libraries and link them with your project. In that case, you first need to install the dependencies for native builds.
Compiler
Install the cross-compiler and
binutils for the
target triplet, typically
arm-none-eabi
or aarch64-none-elf
. If your distribution does not provide the
toolchain, download it from Linaro.
On Debian/Ubuntu, run
sudo apt-get install gcc-arm-none-eabi
for arm-none-eabi
.
Standard library
Bare-metal platforms are freestanding environments that typically lack full support for the C standard library. Newlib is a popular implementation that provides all the functionality required by Lely CANopen.
On Debian/Ubuntu you can install it with
sudo apt-get install libnewlib-arm-none-eabi
or
sudo apt-get install libstdc++-arm-none-eabi-newlib
if you also need the C++ standard library.
Note: You need to compile the stack with -D__NEWLIB__
to use it without
errors. Newlib provides some POSIX definitions without advertising it properly,
which may cause multiple-definition errors. If __NEWLIB__
is defined, the
stack omits the definitions already provided.
When linking with -lnosys
, you’ll need to implement a few functions to get the
stack to work correctly:
Function | Notes |
---|---|
_exit() |
Call NVIC_SystemReset() . |
_gettimeofday() |
Needed for clock() and time() . |
_read() |
Perform a UART read in case of STDIN_FILENO to enable standard input over a serial port. |
_sbrk() |
Needed for malloc() . |
_times() |
Can be implemented in terms of gettimeofday() . |
_write() |
Perform a UART write in case of STDOUT_FILENO or STDERR_FILENO to enable standard output over a serial port. |
Additionally, liblely-libc
needs clock_gettime()
for its implementation of
timespec_get()
; liblely-io2
also needs clock_getres()
and
clock_settime()
for its standard system clock interface.
Build instructions
To build the static libraries, clone the repository and prepare the build environment:
git clone https://gitlab.com/lely_industries/lely-core.git
cd lely-core
autoreconf -i
mkdir -p build
cd build
and configure the project:
CFLAGS="-g -fno-builtin -O2 -mcpu=cortex-m3 -D__NEWLIB__" \
CXXFLAGS="-g -fno-builtin -O2 -mcpu=cortex-m3 -D__NEWLIB__" \
LDFLAGS="--specs=nosys.specs" \
../configure --host=arm-none-eabi \
--disable-shared \
--disable-tools \
--disable-tests \
--disable-python \
--disable-threads \
--disable-daemon
Replace cortex-m3
with the desired target ARM processor.
If you plan on using threads, you probably want to omit the --disable-threads
option. However, in that case you will need to provide your own implementation
of the C11 threads functions.
To reduce the size of the libraries, it may be useful to disable assertions and
tracing by specifying -DNDEBUG
to the C/C++ flags. Also, the size of the final
binary (but not the libraries) can be reduced by specifying
-ffunction-sections
and -fdata-sections
. Use -Wl,--gc-sections
when
linking the binary to remove all unused functions.
Many features provided by Lely CANopen can be disabled at compile time to reduce the size of the binary. See the build configuration options for an overview.
Collect the libraries by running
make install DESTDIR=$(pwd)/../install
and copying the .a
files from ../install/usr/local/lib
.