Cross Compilation Reference


In this section, you will find some help about cross compiling your app. The difficulty of cross-compîlation varies depending on the complexity of the app and its dependencies.

In the case of a single program written in C or C++, and not linking with third party libraries, cross compiling will be very straighforward.

In more complicated cases, this can require more work in order to correctly get the desired result.

Some of the existing build systems, such as GNU Automake and CMake, provide some cross-compilation support.

We will first present the Supported Architectures and Toolchains, which will allow finding out the tools you need to use for you app, depending on the NAS device you’re targetting.

You will then find here some help about cross compiling with automake , CMake or a simple Makefile.

Supported Architectures and Toolchains

NAS OS supports two architectures: ARMv7 and Intel x86_64. The toolchains for these architectures are shipped with the NAS OS SDK development environment in /opt

CPU Architecture Toolchain
Marvell Armada 370 armv7l armv7-marvell-linux-gnueabi-hard_i686_64K_201308_2123
Intel Atom D2701 x86_64 x86_64-seagate-nasos-sdk
Intel Celeron G1610T x86_64 x86_64-seagate-nasos-sdk
Intel Silvermont x86_64 x86_64-seagate-nasos-sdk

You can determine the NAS architecture with the following command:

uname -m

If the architecture is x86_64, you can examine the content of /proc/cpuinfo to get more information about the CPU:

grep 'model name' /proc/cpuinfo | head -n 1

This should return something like:

model name      : Intel(R) Atom(TM) CPU D2701   @ 2.13GHz

Using Automake

In this section, we will create a very simple C program that will be built with Automake. If you are just interested in what option to pass to a configure script, you can jump straight the configure_ step. Here is the program’s source code:

/* hello.c */
#include <stdio.h>
#include <sys/utsname.h>
int main(void)
{
        struct utsname utsname;
        uname(&utsname);
        printf("Hello, from %s\n", utsname.machine);
        return 0;
}

Autoconf is used to generate the configure script and the makefiles are generated with Automake. The configure.ac is as follows:

AC_INIT([hello], [1.0], [support@mycompany.com])
AM_INIT_AUTOMAKE([-Wall -Werror])
AC_PROG_CC
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

The Makefile.am contains the targets for our program:

hello_SOURCES = hello.c
bin_PROGRAMS = hello

We are now ready to generate the configure script. We need to create some files that are required by autoreconf:

touch NEWS README AUTHORS ChangeLog
autoreconf --install

In order to cross-compile our hello program, we have to provide the prefix of the cross-compiler to the configure script. For instance, the prefix of the cross-compiler for Marvell Armada 370 is arm-marvell-linux-gnueabi. Let’s define an environment variable for it:

export TOOLCHAIN_PREFIX=arm-marvell-linux-gnueabi

It means that the name of the tools provided by the cross-compiler start with the same identifier:

These tools are located in the cross-compiler binary directory. For instance: /opt/armv7-marvell-linux-gnueabi-hard_i686_64K_201308_2123/bin

Again, we’ll use a variable for it:

export TOOLCHAIN_DIR=/opt/armv7-marvell-linux-gnueabi-hard_i686_64K_201308_2123

The binaries in this directory need to be accessible by the configure and make tools, which means it must be reference in the $PATH environment variable.

export PATH=$PATH:$TOOLCHAIN_DIR/bin

The prefix should be passed as the --host option to the configure script:

./configure --host=$TOOLCHAIN_PREFIX
make

You can check that the hello binary is an executable for the ARM architecture with the file command:

file hello

Which should return something like:

hello: ELF 32-bit LSB  executable, ARM, EABI5 version 1 (SYSV), dynamically linked...

Finally, you can run hello on the target or use qemu-arm to emulate it:

./hello
Hello, from armv7l

The configure script provides some options that you may want to change. For instance, option --prefix defaults to /usr/local, but you probably want to set it to /usr.

The last step is to install the application with make install. Since you don’t want to install the application on your host machine, you should set the destination directory to a different location:

mkdir ./export
make install DESTDIR=$PWD/export

The export directory will contain the generated binaries.

Using CMake

CMake supports cross compilation since version 2.6. Here is a minimal CMakeLists.txt for our hello application:

project(target-isns "C")
cmake_minimum_required(VERSION 2.6)
add_executable(hello
  hello.c)
install(TARGETS hello RUNTIME DESTINATION bin)

CMake should be instructed to use a cross compiler by setting the CMAKE_C_COMPILER and CMAKE_CXX_COMPILER (for C++ projects) variables. Let’s cross-compile the hello binary using CMake:

mkdir build
cmake .. -D CMAKE_INSTALL_PREFIX=/usr -DCMAKE_C_COMPILER=$TOOLCHAIN_PREFIX-gcc
-- The C compiler identification is GNU 4.6.4
-- Check for working C compiler: /opt/armv7-marvell-.../bin/arm-marvell-linux-gnueabi-gcc
-- Check for working C compiler: /opt/armv7-marvell-.../bin/arm-marvell-linux-gnueabi-gcc -- works
...
make
file hello
hello: ELF 32-bit LSB  executable, ARM, EABI5 version 1 (SYSV), dynamically linked...
mkdir ./export
make install DESTDIR=$PWD/export

Using Make

Sometimes, the application just uses GNU Make as its build system. The Makefiles often contain some variables that you can override for cross-compilation. You should examine the Makefile and look for some variables that you can customize. Here are some commonly used variables:

The variables should be passed as arguments to make. For instance:

make CROSS_COMPILE=$TOOLCHAIN_PREFIX-