When the Raspberry Pi first came out, I spent several days trying to figure out how to build a cross compiler. I managed to do it, but there was an issue with writing GUI based apps (I can’t recall exactly what was failing now). I wasn’t planning to write any GUI apps at that time, so I wasn’t too worried about it.
Update: Turns out this bug has not been fixed which limits the usefulness of cross comping. See update at end of post.
Advance forward a couple of years, and I’m looking at building a cross compiler again for two reasons.
First, I just got a recent version of Lazarus running on my Raspberry Pi Model 2 and I was hoping it was fast enough it would become my development platform. It is a lot faster, but still nowhere near as fast as my PC. I’d really like to be able to cross compile on the same new version of the Lazarus compiler.
Second, the project I’ve been working on is going to need to use an Adafruit Touchscreen to manipulate controls during the early development phase. That way I can easily change how I want the display to work. Once I have everything worked out, then I’ll look at going to a cheaper LCD screen. So now I need GUI access.
As I said, I managed to get the cross compiler working a few years ago but it took a lot of research and experimenting. I know I spent at least a week messing with it until I found the magic combination. After I had it running, I carefully backed up the VirtualBox it ran from so I would never have to go thru that painful process again.
Fortunately, I wrote down the steps I took to build the cross compiler. Of course enough time has went by that the instructions no longer work verbatim, but at least I had a good procedure to start from.
I worked the procedure out again (this time only taking 2 days) and I’ll share what the procedure here. For the most part, the instructions are precise. Only building the cross library is messy.
This procedure ONLY works for a linux source system. The first time through, I tried to get the cross compiler running under windows and had absolutely no luck. I’m not going to even try that path again. Windows really isn’t buying me anything as a RPI development platform anyway.
My RPI dev box is a VirtualBox virtual machine running Linux Mint 17.1. I would expect this procedure to work on any debian O/S just fine. I would assume it would work w/ few additional changes on other Linux distributions as well.
Once nice thing about using a VM is I can back it up prior to attempting to build the cross compiler and then just quickly restore it if I mess up. Backing out of a failed procedure seems a bit iffy (I don’t know exactly where everything is placed).
OK, that’s more than enough intro, here is the procedure.
Prep the Raspberry Pi
Install Lazarus on your RPI. You are going to need to copy libraries from the RPI to the Linux Mint (or other) system. Most of my time was wasted in trying to obtain the proper libraries, so you want to make sure everything possible is on the RPI.
You can follow the normal apt-get install or if you want a recent version of Lazarus, take a look at this procedure (which covers both actually):
Compiling the Latest Lazarus/Free Pascal for Raspberry Pi
Install the Necessary Packages
I find gedit usefully for doing cutting and pasting into files being edited. Install it as desired (I will be using the gedit command in this procedure).
sudo apt-get install -y subversion sudo apt-get install -y gedit sudo apt-get install -y fpc
Download FPC Compiler
Login to the user you expect to be compiling from. Nearly everything will end up being installed in that user’s home directory.
Create the Directory structure:
mkdir ~/fpc_tools mkdir ~/fpc_tools/fpc_setup mkdir ~/fpc_tools/binutils mkdir ~/lazarus mkdir ~/lazarus/fpc mkdir ~/lazarus/fpc/2.6.4 mkdir ~/lazarus/fpc/binutils
Obtain source to the FPC compiler. Note that I am using 2.6.4, here, which is the current version at time of writing.
cd ~/fpc_tools/ svn checkout http://svn.freepascal.org/svn/fpc/tags/release_2_6_4 fpc cd ~/fpc_tools/fpc/ svn update sudo rm -r -f ~/lazarus/fpc/2.6.4/* svn export --force ~/fpc_tools/fpc/ ~/lazarus/fpc/2.6.4/
Create the Cross Compiler Library
Copy libraries from your RPI to your Linux Mint system, into the ~/lazarus/fpc/libcross directory. This procedure assumes the DNS name of your system is ‘rpi’:
cd ~/lazarus/fpc mkdir libcross cd libcross scp -p rpi:/lib/* . scp -p rpi:/lib/arm-linux-gnueabihf/* . scp -p rpi:/usr/lib/* . scp -p rpi:/usr/lib/arm-linux-gnueabihf/* .
Note: scp will complain with ‘scp: <filename>: not a regular file’ when it hits a directory. You do not need the contents of the subdirectories so you can disregard these warnings.
Fixup ld scripts
A few of the binaries in libcross are actually scripts that determine which library to load. Evidently, this doesn’t work with FPC so they need to be fixed. As of this writing there are only two, but to verify exactly how many are there, use:
cd ~/lazarus/fpc/libcross grep -i 'ld script' * libc.so:/* GNU ld script libpthread.so:/* GNU ld script
If you take a look at libc.so, you will see:
cat libc.so /* GNU ld script Use the shared library, but some functions are only in the static library, so try that secondarily. */ OUTPUT_FORMAT(elf32-littlearm) GROUP ( /lib/arm-linux-gnueabihf/libc.so.6 /usr/lib/arm-linux-gnueabihf/libc_nonshared.a AS_NEEDED ( /lib/arm-linux-gnueabihf/ld-linux-armhf.so.3 ) )
libc.so is going to actually call libc.so.6, so we just copy that on top of libc.so. The same is true for libpthread.so:
cp libc.so.6 libc.so cp libpthread.so.0 libpthread.so
Download Binutils
Download version 2.23.2 of binutils from ftp.gnu.org/gnu/binutils. As of this time, version 2.25 is the most recent; however, code generated by this version of the assembler was getting segmentation faults. I found that 2.23.2 does not have this issue. Here is a direct link.
Unzip the binutils-2.23.2 directory into ~/fpc_tools/binutils/binutils-2.23.2.
Download Lazarus Source
This will download version 1.4 of Lazarus, which is current as of time of writing.
cd ~/ svn checkout http://svn.freepascal.org/svn/lazarus/tags/lazarus_1_4 lazarus cd ~/lazarus/ svn update
Install Binutils
cd ~/fpc_tools/binutils/binutils-2.23.2 ./configure --target=arm-linux --disable-werror make sudo make install sudo rm -f ~/lazarus/fpc/binutils/* ln -s /usr/local/bin/arm-linux-ar ~/lazarus/fpc/binutils/ar ln -s /usr/local/bin/arm-linux-ld ~/lazarus/fpc/binutils/ld ln -s /usr/local/bin/arm-linux-as ~/lazarus/fpc/binutils/as
Now we fixup the assembler by moving it to a different location, then creating a script in the original location that will call the assembler with the proper parameters
Move the assembler:
sudo mv /usr/local/bin/arm-linux-as /usr/local/bin/arm-linux-as_org
Now create script file with gedit and use the content shown:
sudo gedit /usr/local/bin/arm-linux-as #!/bin/sh echo calling assembler with parms $@ /usr/local/bin/arm-linux-as_org -meabi=5 $@
Fix script to be executable:
sudo chmod 755 /usr/local/bin/arm-linux-as
Verify the assembler works:
arm-linux-as --version calling assembler with parms --version GNU assembler (GNU Binutils) 2.23.2 Copyright 2012 Free Software Foundation, Inc. This program is free software; you may redistribute it under the terms of the GNU General Public License version 3 or later. This program has absolutely no warranty. This assembler was configured for a target of `arm-linux'.
Compile FPC
cd ~/lazarus/fpc/2.6.4 make all OPT='-gl -O3p3' PP=/usr/bin/ppc386 sudo make install PP=/usr/bin/ppc386 PREFIX=/usr/ sudo rm /usr/bin/ppc386 sudo ln -sf /usr/lib/fpc/2.6.4/ppc386 /usr/bin/ppc386 sudo mkdir /usr/share/fpcsrc/ sudo ln -sf ~/lazarus/fpc/2.6.4/ /usr/share/fpcsrc/ sudo /usr/lib/fpc/2.6.4/samplecfg /usr/lib/fpc/2.6.4/ /etc
Compile The Cross Compiler
cd ~/lazarus/fpc/2.6.4/ sudo make crossinstall CPU_TARGET=arm OS_TARGET=linux CROSSBINDIR=~/lazarus/fpc/binutils/ OPT=-dFPC_ARMEL INSTALL_PREFIX=/usr
Test the Compiler
Create a test program:
cd ~/lazarus/fpc/2.6.4/compiler/ gedit test.pas program test; begin writeln('DATE ',{$i %DATE%}); writeln('FPCTARGET ',{$i %FPCTARGET%}); writeln('FPCTARGETCPU ',{$i %FPCTARGETCPU%}); writeln('FPCTARGETOS ',{$i %FPCTARGETOS%}); writeln('FPCVERSION ',{$i %FPCVERSION%}); end.
Compile it:
./ppcrossarm -XParm-linux- -Tlinux -Parm test.pas Free Pascal Compiler version 2.6.4 [2015/06/29] for arm Copyright (c) 1993-2014 by Florian Klaempfl and others Target OS: Linux for ARMEL Compiling test.pas Assembling test calling assembler with parms -mfpu=softvfp -o test.o test.s Linking test /usr/local/bin/arm-linux-ld: warning: link.res contains output sections; did you forget -T? 8 lines compiled, 0.1 sec
This program will only run on your Raspberry Pi, so you must copy it to your RPI to test it:
scp test rpi:~ xxx@rpi's password: ssh rpi xxx@rpi's password: Linux rpi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l Welcome to rpi. Last login: Mon Jun 29 08:59:39 2015 from 192.8.50.217 rpi/~:./test DATE 2015/06/29 FPCTARGET arm FPCTARGETCPU arm FPCTARGETOS Linux FPCVERSION 2.6.4
Create ~/.fpc.cfg
Run gedit and paste the following into .fpc.cfg
gedit ~/.fpc.cfg #INCLUDE /etc/fpc.cfg #DEFINE DEMOTEST #DEFINE DEMOTEST1 #DEFINE LAZARUS -Fu/usr/lib/fpc/2.6.4/units/$fpctarget/* -Fl/usr/lib/fpc/2.6.4/units/$fpctarget/rtl/ -a -Sd -Xd -Xs -O- #IFDEF CPUARM # -Fl/usr/lib/arm-linux-gnueabihf/ # -Fl/lib/arm-linux-gnueabihf/ -Fl~/lazarus/fpc/libcross/ -XParm-linux- -Xr/usr/lib/fpc/2.6.4/units/arm-linux/rtl/ -Xr~/lazarus/fpc/libcross/ -XR~/lazarus/fpc/ -darm -Tlinux #ENDIF
Create link to Cross Compiler in /usr/local/bin
sudo ln -sf ~/lazarus/fpc/2.6.4/compiler/ppcrossarm /usr/local/bin/ppcarm
Compile Lazarus
cd ~/lazarus make clean bigide ln -s ~/lazarus/startlazarus ~/Desktop/Lazarus
Start Lazarus
There will be a link to Lazarus on your desktop. Double click that to start Lazarus.
Set Lazarus Options
The first time you start Lazarus, you get a Configuration Dialog. Check the Lazarus, Compiler, and FPC Sources to make sure they are correct:
If you don’t see this dialog, you can use In Tools -> Options -> Environment -> Files to check these settings.
In Project | Project Options | Compiler Options | Config and Target, set Target OS and Target CPU family to Linux / Arm
In Compiler Options | Compilation and Linking, add this linker option, ‘-L~/lazarus/fpc/libcross’:
Next, in Compiler Options | Other, add the custom option, ‘-XParm-linux-‘:
Before clicking on OK, select ‘Set Compiler Options as default’:
Test Lazarus
At this point, I put some controls on the blank form:
I then save the project and compile it with ctl-f9. I copy the executable to the RPI and then VNC there to run the GUI application:
Easily Compiling Locally and for the RPI
If you followed my settings for the compiler above, any new project will be set up to compile for the RPI. If you aren’t doing anything that requires specific RPI hardware (such as accessing GPIO pins), it can be very convenient to compile and test the program on the I386 platform. Then when you are happy with your changes, cross compile.
This can be done simply using Lazarus’ build modes. Here is how to add the ability to compile both to the i386 and RPI platforms. Open a new project to get the default project settings. Now go to Project | Project Options | Compiler Options and enable build modes:
To start with the ‘default’ build mode is ARM (RPI) because we set that initially. First, let’s rename ‘default’ to ‘ARM’.
Click on the ‘…’ button to the right of the current build mode (e.g. ‘default’). This brings up the build mode dialog box. Here I have already changed ‘default’ to ‘ARM’:
Now click the ‘+’ button and add the entry for i386 and make it active:
Now that you are in i386 mode, you need to get rid of the ARM compilation options. These are:
- Project | Project Optinos | Compile | Config and Target – set OS to linux and CPU family to i386.
- In compilation and linking disable ‘Pass Options to Linker’.
- In Other, remove ‘-XParm-linux-‘.
- In compiler commands, remove scp if you were using it to transfer the object code.
Before clicking on OK, make sure to set ‘Set compiler options as default’ so the new build mode will be available in all new project.
Automatically transferring the binary to the RPI
Usually my work flow is to simply edit and compile the program on the Linux i386 system. I then copy the executable to the Raspberry Pi and test it there.
The transfer can be automated. I use scp to transfer the executable. So if I’m working on ‘project1’, I need the command
scp project1 rpi:~
to transfer the executable to my rpi into my home directory.
The problem with this scp command is it wants a password. You can get around this by installing sshpass:
sudo apt-get install sshpass
If my password were xyzzy, then to transfer my file using sshpass/scp I would type:
sshpass -p 'xyzzy' scp project1 rpi:~
The obvious downside to using sshpass is the fact that the RPI password is going to be imbedded in the pascal project.
Once you have the command working, you only need to add it to the Pascal project. Go to Project | Project Options | Compiler Options | Compiler Commands, and enter the command into the Execute After command box:
The Cross Compile Font issue continues to be a problem. This has been reported in several places and there has never been a resolution. As such, at least in my opinion, this bug greatly limits the usefulness of cross-compiling. Really, if you are trying to write a GUI application, it eliminates the option.
The problem is simple. If you select any font size other than 0 (which is the default size I guess), the text will not show up on the Raspberry Pi. It doesn’t matter what other font characteristic is set (I’ve changed them all).
As an example, here is my airport time program, originally written for windows, recompiled on Linux i386. The fonts show up fine:
Now I cross compile w/o modifications to RPI and the fonts are gone:
If I change the size of the fonts to 0, then they will appear but look horrible:
If I move the source file to the RPI and compile, the fonts will look proper:
I have spent hours trying to resolve this problem to no avail. It seems the problem must be with a library, yet I have copied all of the libraries from the exact same raspberry pi. It just makes no sense to me.
Sir could i just copy all my project files which was written on Windows platform and run this project files with the raspberry pi
Generally, Yes. There are usually only issues when you try to directly access the Windows operating system or windows hardware. In the following post, I take a program I wrote for lazarus/windows, move it to RPI unchanged and it compiles and runs fine:
https://bigdanzblog.wordpress.com/wp-admin/post.php?post=1023&action=edit
Hi!
I have got a Raspberry Pi 3. I don’t have /usr/bin/ppc386 just ppcarm, but it doesn’t works. (e.g.: /home/pi/lazarus/fpc/2.6.4/rtl/units/arm-linux/system.s:89605: Error: selected processor does not support ARM mode `lfm f4,1,[r11,#-316]’ )
What should I do?
Thanx!
sorry I have no experience with RPI 3. Don’t even own one yet.
Pingback: Cross-compiling to Pi Zero | Michell Computing News
Hi Dan, have you checked out Ultibo yet? It might be to your liking….
Interesting!