Difference between revisions of "Cross compiling"
Windsurferme (talk | contribs) |
Windsurferme (talk | contribs) |
||
Line 15: | Line 15: | ||
==Assembler and linker== | ==Assembler and linker== | ||
− | The compiler is only one part. We also need the assembler and the linker. FPC provides internal assembler and/or linker for | + | The compiler is only one part. We also need the assembler and the linker. FPC provides an internal assembler and/or linker for some platforms, but other platforms need external tools. Usually these tools are not able to create binaries for different platforms. That's why we have to use different special linker 'ld' and assembler 'as' for every target platform. These are the binutils. |
See [[Binutils]] | See [[Binutils]] |
Revision as of 16:00, 16 February 2016
│
Deutsch (de) │
English (en) │
español (es) │
français (fr) │
magyar (hu) │
português (pt) │
русский (ru) │
中文(中国大陆) (zh_CN) │
中文(台灣) (zh_TW) │
Foreword
This is a short introduction for newbies. The following sections describe how to setup a system to cross compile, that means creating binaries (executables) for a platform different from the one used for compilation - e.g. working under Linux and creating Win32 executables (or those for FreeBSD or Darwin, etc.). In this case, the platform used for compilation is usually referred to as "host" (Linux in the example above) and the platform where you want to run your created binaries is your "target". FreePascal is a compiler and basically converts source into binaries (machine language). These binaries also contain information on how the operating system starts the executables. Moreover, the binaries refer to the APIs provided by the particular operating system, that's why a different implementation of our Run-Time Library is necessary for different operating systems. Therefore these binaries are platform specific. FreePascal itself does not need much setup. It can create binaries for many platforms. Just tell it to do so.
Host and target on the same CPU
FPC is designed so that the distributed compiler can create machine code for a certain CPU (because different CPUs need different machine code) and it knows specific requirements for all supported platforms (operating systems) available on that particular CPU. This means that you can perform cross-compilation with the same compiler used for native compilation as long as you stick to the same CPU.
Host and target on different CPUs
If you need to create binaries for a different CPU, you need a special cross-compiler, i.e. compiler running on the host platform, but able to create machine code for a different CPU (in the case of FPC, such a cross-compiler would be again able to target all supported platforms available on the _target_ CPU). This cross-compiler is then usually stored in the same directory as the native compiler. Such a cross-compiler may be either compiled by yourself, or you can use a ready made distributed cross-compiler provided for some platforms directly by the FPC team (usually platforms mostly used in portable devices like arm-linux or arm-wince, because these are usually not used as host platforms). Fpc binary can then select the right compiler (either the native compiler or the cross-compiler) for the target CPU selected using the -P parameter.
Assembler and linker
The compiler is only one part. We also need the assembler and the linker. FPC provides an internal assembler and/or linker for some platforms, but other platforms need external tools. Usually these tools are not able to create binaries for different platforms. That's why we have to use different special linker 'ld' and assembler 'as' for every target platform. These are the binutils.
See Binutils
Units for target
After creating (or having/installing) the cross tools, one needs FPC RTL and other units compiled for the chosen target platform. For example, every target platform needs a different file system.ppu (System unit), etc. These units may be either compiled using your compiler set up for compilation to the target platform, or you may potentially use officially distributed units compiled (and distributed) with exactly the same FPC version (if available in format useable under the particular host platform).
Configuration
Then your fpc config file will be setup, so that cross compilation becomes so easy, that you can forget all the boring details. The same will be done for the LCL - the lazarus component library (if using Lazarus). And after this you can cross compile pascal programs for the (different) target platform. The resulting binaries may then be copied to a machine running the target platform, or run under an emulator (e.g. Wine for Win32 binaries under Linux, etc.).
Basic Steps
There are a few common steps involved in crosscompiling that you must do in every case:
- Have already a FreePascal compiler for the platform you wish to compile from.
- You need to have the FreePascal source code (except for the special case of having everything prepared by someone else).
- You need to either build from source or obtain binaries of the cross-binutils that run on the platform you are on and are designed to build programs for your desired target platform.
- Sometimes you will need some files from the target you are compiling to.
From Linux
From Linux x64 to Linux i386
Chances are that your 64 bit linux distrubution is already capable of compiling 32 bit programs but due to the way the fpc build process is designed there are a couple of things you might have to do.
- First check if you already have the files i386-linux-ld and i386-linux-as:
$ which i386-linux-ld
$ which i386-linux-as
If you have these files skip to the "Compile FPC" heading.
I did not have these files so I made a couple of scripts:
#!/bin/bash
# name this file /usr/bin/i386-linux-ld
ld -A elf32-i386 $@
#!/bin/bash
# name this file /usr/bin/i386-linux-as
as --32 $@
- Make them executable:
$ chmod +x /usr/bin/i386-linux-as
$ chmod +x /usr/bin/i386-linux-ld
- Compile FPC:
cd /usr/share/fpcsrc/<version>
sudo make all CPU_TARGET=i386
then:
sudo make crossinstall CPU_TARGET=i386
That's it. Edit your /etc/fpc.cfg file if needed.
From Linux to ARM Linux
Information about targeting Linux running on ARM (e.g. Zaurus) may be found in Setup Cross Compile For ARM.
From Linux to Windows
Information on cross-compilation with Lazarus can be found in Cross compiling for Win32 under Linux
From Linux to Darwin or Mac OS X
Please see here.
From Windows
From Windows to Linux
This is less trivial, there is some info in the buildfaq
See also fpcup for descriptions on which binutils work and what libraries/files to copy.
As the Build FAQ explains, you will need libs (.so files) from the target system, e.g. from /lib and /user/lib (but could be more locations). On some systems, some .so files are actually scripts; check with
grep -i "ld script" *
Remove those .so and copy over (or symlink) the .so.x files that you should have to .so in order for the linker to find them.
From Windows to GO32v2
Detailed information may be found in Cross-compilation from Win32 to GO32v2.
From Windows to wince
arm-wince describes how to setup a crosscompiler for arm CPU
i386-wince describes how to setup compiling for i386 CPU (no crosscompiling)
![Note icon Light bulb](https://upload.wikimedia.org/wikipedia/commons/d/d8/Nuvola_apps_ktip.png)
From win32 to win64
If you are compiling the 2.1.1 or greater branch of fpc you can just do:
$ make all OS_TARGET=win64 CPU_TARGET=x86_64
and then
$ make crossinstall OS_TARGET=win64 CPU_TARGET=x86_64
From Darwin (Mac OS X) i386
From Darwin i386 to powerpc
The official FPC installer for Mac OS X/i386 includes a PowerPC cross-compiler and all units necessary to compile PowerPC programs (use ppcppc instead of ppc386 to compile your programs). The instructions below are only necessary if you want to compile and install a new version from svn.
- Compile FPC:
$ cd fpc
$ make all CPU_TARGET=powerpc -j 2
This creates the powerpc cross-compiler compiler (fpc/compiler/ppcrosspcc) and all units. You can install them using the following commands:
$ sudo make FPC=`pwd`/compiler/ppc386 install CPU_TARGET=powerpc CROSSINSTALL=1
$ INSTALLED_VERSION=`./compiler/ppc386 -iV`
$ sudo mv /usr/local/lib/fpc/$INSTALLED_VERSION/ppcrossppc /usr/local/lib/fpc/$INSTALLED_VERSION/ppcppc
Reminder: Universal binaries are created from the individual (i386 and powerpc) binaries using lipo.
From Darwin i386 to x86_64
The official FPC installer for Mac OS X/i386 includes a x86_64 compiler and all units necessary to compile x86_64 programs (use ppcx64 instead of ppc386 to compile your programs or use fpc -Px86_64). The instructions below are only necessary if you want to compile and install a new version from svn.
- Compile FPC:
$ cd fpc
$ make all CPU_TARGET=x86_64
This creates the x86_64 cross-compiler (fpc/compiler/ppcrossx64) and all units. You can install them using the following commands:
$ sudo make crossinstall CPU_TARGET=x86_64
$ sudo mv /usr/local/lib/fpc/2.7.1/ppcrossx64 /usr/local/lib/fpc/2.7.1/ppcx64
If you want to make this newly installed compiler the default version (this is not recommended, and will break your ability to build new FPC 2.7.1 versions without explicitly specifying the path to the latest official FPC release), also execute the following command:
$ sudo ln -sf /usr/local/lib/fpc/2.7.1/ppcx64 /usr/local/bin/ppcx64
Assuming all of the LCL components your project uses are supported by the Cocoa widgetset, you can compile a Lazarus project from the command line, using a command like this (full path to the compiler seems required):
$ lazbuild -B project1.lpr --ws=cocoa --cpu=x86_64 --os=darwin --compiler=/usr/local/bin/ppcx64
You can check that your executable is 64-bit uses the "file" command:
$ file ./project1
$ ./project1: Mach-O 64-bit executable x86_64
Alternatively, you can set your project to compile as 64-bit using the Lazarus graphical interface:
a.) Choose the Project/ProjectOptions menu item b.) In the CompilerOptions/CompilerCommands set the Compiler Command field to "/usr/local/bin/ppcx64" c.) For CompilerOptions/ConfigAndTarget set the "Target CPU family" to "x86_64" d.) For CompilerOptions/AdditionsAndOverrides store the "LCLWidgetType := cocoa" in the LPI
Note that a 64-bit OS X computer can run 32-bit executables just fine. However, if you want to create a universal binary that executes on a 32-bit Intel as well as in 64-bit mode on a 64-bit intel computer you can use the "lipo" command. This would allow the 64-bit computer to access more memory and in theory might perform a bit better (e.g. different compiler optimizations, more registers though with larger pointers). Assuming you have generated separate 32-bit ("project32") and 64-bit ("project64") executables with Lazarus.
$ lipo -create project32 project64 -o projectUniversal
From Darwin to Windows, Linux and others
The package manager fink has packages for crosscompiling to windows, linux, freebsd mainly for Intel Macs, but some for PowerPC Macs, too.
$ fink install fpc-cross-i386-win32
or
$ fink install fpc-cross-arm-linux
install the crosscompilers.
To compile use these commands:
fpc -Twin32 FILENAME
fpc -Parm -Tlinux FILENAME
The current list with fpc 2.6.4 is:
fpc-cross-arm-gba
fpc-cross-arm-linux
fpc-cross-arm-nds
fpc-cross-arm-wince
fpc-cross-arm-armv4t-embedded
fpc-cross-arm-armv7m-embedded
fpc-cross-i386-darwin
fpc-cross-i386-freebsd
fpc-cross-i386-go32v2
fpc-cross-i386-linux
fpc-cross-i386-solaris
fpc-cross-i386-win32
fpc-cross-i386-wince
fpc-cross-powerpc-darwin
fpc-cross-powerpc-linux
fpc-cross-sparc-linux
fpc-cross-x86-64-darwin
fpc-cross-x86-64-freebsd
fpc-cross-x86-64-linux
fpc-cross-x86-64-win64
For other platforms (processors and systems) you have to do the setup by yourself. It is basically always the same scheme: First, you need the corresponding binutils and second, the crosscompiler and the run time library. Some more details of the building procedure can be learned from the fink package description files of the crosscompilers from above.
From FreeBSD
FreeBSD to SPARC
Warning: This section appears to date from around 2005 and may not be relevant anymore. Updates are welcome.
I managed to crosscompile from x86 to Sparc Solaris 9. However the result doesn't work very well, but here is my cmdline:
in compiler/ execute:
gmake cycle CPU_TARGET=sparc OS_TARGET=solaris CROSSBINUTILPREFIX=solaris-sparc- CROSSOPT='-Xd -Fl~/src/sollib'
~/src/sollib is a directory that contains:
- a set of .o's from /usr/local/gcc-3.3-32bit/lib/gcc-lib/sparc-sun-solaris/3.3
- libgcc.a from /usr/local/gcc-3.3-32bit/lib/gcc-lib/sparc-sun-solaris/3.3
- a set of lib*.so from /usr/lib: libaio.so libmd5.so libc.so libelf.so librt.so libdl.so libm.so
Problem is illustrated by the following binary.
Free Pascal Compiler version 2.1.1 [2006/03/17] for sparc Copyright (c) 1993-2005 by Florian Klaempfl Target OS: Solaris for SPARC Compiling system.pp system.pp(15,1) Fatal: Syntax error, "BEGIN" expected but "identifier UNIT" found
I suspect wrong .o's are taken.
General Unix/Linux notes
Option -XLA is used to rename library dependencies specified in pascal units. Format is -XLAold=new, to modify ld link option -l<old> to -l<new>.
Option -XR<sysroot> (recent trunk) that can be used to specify the target system root. It's used for:
- adding a prefix to the default added library paths; in the past you used to specify -Xd and these paths manually. E.g. for i386-linux instead of passing /lib, /usr/lib, and /usr/X11R6/lib to ld, it will pass <sysroot>/lib, <sysroot>/usr/lib, and <sysroot>/usr/X11R6/lib to ld.
- detecting the C library (linux specific): glibc or uclibc. E.g. for uclibc detection '<sysroot>/lib/ld-uClibc.so.0' is tried.
Cross compiling the LCL
Since 0.9.31 the LCL is a normal Lazarus package and the IDE will automatically cross compile all needed packages, when you change the target platform of your project.
If something goes wrong, here are some hints that might help to find out why:
Test cross compiler
Test if you have installed the cross compiled fpc correctly:
Create a hello world program 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.
And compile it with your source/original platform. Example for x86 Windows:
fpc -Twin32 -Pi386 test.pas
Then test source compiler:
test
Replace win32 and i386 with your targets. Example for target Windows 64 bit:
fpc -Twin64 -Px86_64 test.pas
Then test cross compiler:
test
The program fpc is a wrapper that searches the right compiler (e.g. ppcrossx64) for the target and executes it.
If this does not work, your cross compiler was not installed correctly. When this works you can cross compile the LCL.
Cross compiling the LCL in Lazarus 0.9.30 and below
If you are sure your cross compiler works, you can do the actual cross compile.
Perform the following steps in the Lazarus IDE to do an LCL cross compile: In older IDEs:
- Set in Tools -> Options -> Environment -> Files the Compiler path to the path to fpc. Normally this is already done.
- Then open Tools -> Configure Build Lazarus.
- Set Target OS (e.g. to Win64) and Target CPU (e.g. to x86_64)
- Click the Build button.
Command line
Apart from the IDE, the command line also allows you to build a cross compiled LCL.
![Note icon Light bulb](https://upload.wikimedia.org/wikipedia/commons/d/d8/Nuvola_apps_ktip.png)
An example: you would cross compile a Windows 64 cross compiler using: First thoroughly clean any 64 bit leftovers. This does not touch your 32 bit environment:
make distclean LCL_PLATFORM=win32 CPU_TARGET=x86_64 OS_TARGET=win64
Then build LCL and its required dependencies. We're using LCL_PLATFORM as that presumably corresponds to the widgetset, which is still Windows 32 even on Windows 64 (the widgetsets are the same).
make packager/registration lazutils lcl LCL_PLATFORM=win32 CPU_TARGET=x86_64 OS_TARGET=win64
As in the previous section, the LCL for your normal OS is untouched.
Cross compiling LCL applications
You first need to cross compile the LCL. See above.
Cross compiling applications means: compiling plus linking. When you have cross compiled the LCL the compilation part is easy. Just set in the compiler options of the IDE the Target OS and Target CPU. The tricky part is the linking. If you cross compile a project you may see something like this:
/usr/local/bin/arm-linux-ld: cannot find -lX11
This means you have to install the graphical libraries of the target system. This has nothing to do with FPC/Lazarus, but with cross compiling a library. Some distributions provides pre compiled packages for this. For example Microsoft provides cross compiled libraries for WinCE for Windows. Under Linux you can install Wine to cross compile from Linux to Windows. Some Linux distributions provide 64bit libraries for 32bit systems.
Cross compile FAQ
Why cross compile?
So you can develop a program for one OS/CPU and compile it for another OS/CPU without rebooting or switching computers.
Why not cross compile?
In many cases, you want to test the resulting program on the native platform. Compiling the application on that platform may be easier to set up.
Why cross compile from Unix to Windows and not the other way around?
See Cross compiling for Win32 under Linux
I want more information on building Freepascal. Where is it?
There is a general FAQ in pdf format about how to build and configure FPC: buildfaq
Errors like compiler "/usr/bin/fpc" does not support target arm-linux
Apart from other causes, this error may occur if you edited fpc.cfg with incorrect options for the cross compiler (e.g. specifying parameters all on one line instead of one per line).
See also
- crossnotes Notes about cross compiling
- Cross compiling for Win32 under Linux