Cross Linux Topics

This appendix describes topics that are specific to the GNAT for Cross Linux.

Building a Cross Linux Application

This section is the starting point for building an Ada application targeting a Cross Linux system.

To be able to build a program for Cross Linux, the build toolchain will need to know where to find includes and libraries for this target. GCC provides the option --sysroot for that purpose. This option takes as a parameter the logical root directory for headers and libraries.

For example, if the compiler normally searches for headers in /usr/include and libraries in /lib and /usr/lib, --sysroot=dir instead searches dir/usr/include and dir/usr/lib. On 64-bit targets, this would also include dir/usr/lib64 and dir/lib64.

GNAT also provides an alternative way to set the path to sysroot which allows you to use the compiler without having to pass --sysroot each and every time. This is done by setting the ENV_PREFIX environment variable. Having ENV_PREFIX in the environment is equivalent to passing --sysroot=$ENV_PREFIX to the compiler.

These libraries in your sysroot should match exactly the ones that the target provides; this is why they cannot be provided in the GNAT package.

On Linux host only, depending on your host distribution, you may have a package for cross development that matches your target setup. An example of such a case is Ubuntu 16.10 providing a package for cross development on ppc64-linux, named lib32gcc-6-dev-ppc64-cross.

Such a package would provide the target libc. But not all distributions would have such packages, and certainly not for all target architectures, distributions, versions; in particular if the target does not run the same distribution as the host, you most certainly won’t have a package for it.

In such a case, a more general way to build a sysroot is to copy the target libraries on host. For instance, on an x86_64-linux host, if you are developing with a ppc64-linux target, you could do the following to build a sysroot directory:

$ mkdir ./sysroot
$ mkdir ./sysroot/usr
$ scp -rp my-ppc64-linux-target:/usr/include ./sysroot/usr/
$ scp -rp my-ppc64-linux-target:/usr/lib ./sysroot/usr/
$ scp -rp my-ppc64-linux-target:/usr/lib64 ./sysroot/usr/
$ scp -rp my-ppc64-linux-target:/lib ./sysroot/
$ scp -rp my-ppc64-linux-target:/lib64 ./sysroot/

To use that sysroot, you can then export ENV_PREFIX as follow.

$ export ENV_PREFIX=`pwd`/sysroot

As indicated earlier, this allows you to use GNAT without having to pass the sysroot on each command.

To build the basic Hello world example on ppc64-linux, you can then invoke gnatmake with the default options:

$ powerpc64-generic-linux-gnu-gnatmake hello
powerpc64-generic-linux-gnu-gcc -c hello.adb
powerpc64-generic-linux-gnu-gnatbind -x hello.ali
powerpc64-generic-linux-gnu-gnatlink hello.ali

WARNING: Some Linux systems provide linker scripts, e.g. libc.so, that may point to other shared libraries using a full path that starts with a double-slash ‘//’. While this does not cause any problem on GNU/Linux hosts, on Windows hosts, such paths are interpreted as UNC path. This should not prevent sysroot to be expanded, however Windows users creating sysroots from a live target system may want to fix them to avoid the latency of a network search.

Debugging an Application on Cross Linux

This section describes the steps needed to run the Cross Linux debugger.

The debugging solution that GNAT provides on this target consists of three tools:

  • gdbserver: A debugging server on target, which provides a low-level interface to control the debugged program.
  • gdb: The debugger itself, run on the host; it connects to GDBserver and allows the user to control the debugged program through a command-line interface.
  • gps: The GNAT Programming Studio, which provides a graphical front-end on top of gdb.

To start a debugging session, you first need to start the program under control of GDBserver. For example, if the board has an internet connection to the development host, and assuming the Internet hostname of the board is myboard, your application is named myapp, and the port on which GDBserver will wait for requests is port 2345, the command would be:

myboard> gdbserver myboard:2345 myapp

This starts the execution of your program on the target, and then suspends it at the very beginning. Once this is done, GDBserver then waits for the debugger to connect.

You can now start the debugger. In GPS, in the Languages tab of the project properties page, you would specify the name of the debugger (e.g. powerpc64-generic-linux-gnu-gdb). You would then be able to start this debugger with the command: Debug => Initialize => <No Main Program>. Alternatively, you can run the debugger gdb from the command line.

You are now ready to connect the debugger to the GDB server:

(gdb) target remote myboard:2345

Once the debugger is connected to the GDBserver, you can debug your program as usual (insert breakpoints, inspect variables and memory, etc); remember that the program’s execution has already been started by GDBserver, and thus use “continue” to resume the program’s execution, rather than “run”. Below is an example of a debugging session where the user is interested in debugging a function called some_function, and therefore, after connecting to the target, inserts a breakpoint and then resumes his program until reaching that breakpoint:

(gdb) target remote myboard:2345
   ...
(gdb) break some_function
   ...
(gdb) continue
   ...

Note that the debugger needs access to the exact shared libraries being used by your program. By default, what the debugger does is automatically download from the target a copy of each shared library the program uses. It is recommended to keep the default, as this ensures that the debugger’s knowledge of the shared libraries matches exactly the libraries actually installed on the target, which is crucial. However, if you are debugging on a target with a slow connection, the download may be taking long enough that you would prefer to maintain on the host a copy of the target system’s shared library (the sysroot described above), and then tell the debugger to use your sysroot instead. For this, before connecting to GDBserver, use the following debugger command (where SYSROOT_PATH should be replaced by the path where the sysroot is located on the host):

(gdb) set sysroot SYSROOT_PATH
   ...

For further information about the debugger or the GDB server, please refer to the GDB User’s Manual.