Difference between revisions of "Cross compiling for Windows under Linux"
(Layout, grammar, categories (apply to both FPC and Lazarus)) |
|||
Line 7: | Line 7: | ||
It does not contain the cross compiled LCL .ppu files. You need to compile them yourself, after installing fpc-crosswin32. | It does not contain the cross compiled LCL .ppu files. You need to compile them yourself, after installing fpc-crosswin32. | ||
− | == | + | == General == |
− | === | + | === Introduction - knowing, what you are doing === |
This is a short introduction for newbies. | This is a short introduction for newbies. | ||
− | The following sections describe how to set up a system to cross compile | + | The following sections describe how to set up a Linux system to cross compile, creating Win32 executables (or FreeBSD or Darwin/OSX, or ...). |
− | Why cross compiling? FreePascal is a compiler and basically converts source into binaries (machine language). These binaries also contain information | + | Why cross compiling? FreePascal is a compiler and basically converts source into binaries (machine language). These binaries also contain information about how the operating system should start the executable. 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. But the compiler is only one part. There is also the assembler and the linker. And these tools are not able to create crossplatform code. | + | |
− | That's why we have to create a special linker 'ld' and assembler 'as' for every target platform. These are the binutils. | + | FreePascal itself does not need much setup. It can create binaries for many platforms. Just tell it to do so. But the compiler is only one part. |
+ | |||
+ | There is also the assembler and the linker. And these tools are not able to create crossplatform code. That's why we have to create a special linker 'ld' and assembler 'as' for every target platform. These are the binutils. | ||
After creating the cross tools, all the FPC Pascal units will be cross compiled. For example, there will then be one system.ppu file for every target platform. | After creating the cross tools, all the FPC Pascal units will be cross compiled. For example, there will then be one system.ppu file for every target platform. | ||
Line 22: | Line 24: | ||
And after this you can cross compile Pascal programs for Win32. Either start them with wine or copy them to a Windows machine and test them there. | And after this you can cross compile Pascal programs for Win32. Either start them with wine or copy them to a Windows machine and test them there. | ||
− | === Why *nix to | + | == Free Pascal == |
+ | === Why *nix to Windows and not the other way around === | ||
The main reason for this is that generating Unix binaries on a foreign platform (even another Unix or Linux system) is more complicated. Static linking is already complicated, let alone shared. | The main reason for this is that generating Unix binaries on a foreign platform (even another Unix or Linux system) is more complicated. Static linking is already complicated, let alone shared. | ||
Line 33: | Line 36: | ||
The binaries are not enough, you need the complete fpc sources. | The binaries are not enough, you need the complete fpc sources. | ||
− | See www.freepascal.org. You can use SVN or a daily snapshot([http://svn.freepascal.org/svn/fpc/ HERE]). | + | See www.freepascal.org. You can use SVN or a daily snapshot ([http://svn.freepascal.org/svn/fpc/ HERE]). |
− | For the following examples the | + | For the following examples the FPC sources were downloaded to ~/sources/fpc. |
− | You can download those files from[http://freepascal.org/down/source/sources.var HERE] | + | You can download those files from [http://freepascal.org/down/source/sources.var HERE] |
− | === Download the gnu binutils | + | === Download the gnu binutils === |
For example binutils-2.18.tar.gz downloaded to | For example binutils-2.18.tar.gz downloaded to | ||
Line 50: | Line 53: | ||
cross platforms: install/cross/buildcrossbinutils | cross platforms: install/cross/buildcrossbinutils | ||
− | Download install of fpcbuild: | + | Download install of fpcbuild, e.g something like (adjust version): |
− | + | <syntaxhighlight lang=bash> | |
− | + | cd ~ | |
+ | svn co http://svn.freepascal.org/svn/fpcbuild/branches/fixes_2_4/install install | ||
+ | </syntaxhighlight> | ||
Create a copy of the script: | Create a copy of the script: | ||
− | + | <syntaxhighlight lang=bash> | |
− | + | cd ~/install/cross/ | |
− | + | cp buildcrossbinutils buildcrossbinutils.sh | |
+ | </syntaxhighlight> | ||
Edit the variables at the start of the new script. | Edit the variables at the start of the new script. | ||
Line 72: | Line 78: | ||
The script will automatically combine this to ~/download/binutils-2.18.tar.gz. | The script will automatically combine this to ~/download/binutils-2.18.tar.gz. | ||
− | The rest variables define what target platforms you have. The default is to | + | |
+ | The rest of the variables define what target platforms you have. The default is to | ||
build quite a lot, so compilation will take some time (hours on slow machines). | build quite a lot, so compilation will take some time (hours on slow machines). | ||
For cross compile to windows, you need only | For cross compile to windows, you need only | ||
Line 78: | Line 85: | ||
TARGETS_WIN="mingw32" | TARGETS_WIN="mingw32" | ||
− | and | + | and comment out all others: |
#BSD="freebsd netbsd openbsd" | #BSD="freebsd netbsd openbsd" | ||
Line 89: | Line 96: | ||
Then run the script: | Then run the script: | ||
+ | <syntaxhighlight lang=bash> | ||
+ | sh buildcrossbinutils.sh | ||
+ | </syntaxhighlight> | ||
− | |||
− | |||
The script creates a subdirectory 'logs' full of log files. If something goes | The script creates a subdirectory 'logs' full of log files. If something goes | ||
wrong, start looking there. | wrong, start looking there. | ||
− | Note that for several platforms (Linux,FreeBSD, win32) these are available in compiled | + | Note that the cross binutils for several platforms (Linux,FreeBSD, win32) these are available in compiled form already. See ftp://freepascal.stack.nl/pub/fpc/contrib/cross/ |
− | form already. See ftp://freepascal.stack.nl/pub/fpc/contrib/cross/ | ||
=== Cross build FPC === | === Cross build FPC === | ||
− | In the fpcbuild repository there is a script to build the fpc snapshot for | + | In the fpcbuild repository there is a script to build the fpc snapshot for all cross platforms: install/cross/buildcrosssnapshot |
− | all cross platforms: install/cross/buildcrosssnapshot | ||
Create a copy of the script: | Create a copy of the script: | ||
− | + | <syntaxhighlight lang=bash> | |
− | + | cd ~/install/cross/ | |
+ | cp buildcrosssnapshot buildcrosssnapshot.sh | ||
+ | </syntaxhighlight> | ||
Edit the variables at the start of the new script. | Edit the variables at the start of the new script. | ||
Line 120: | Line 128: | ||
Then run the script: | Then run the script: | ||
− | + | <syntaxhighlight lang=bash> | |
+ | sh buildcrosssnapshot.sh | ||
+ | </syntaxhighlight> | ||
After this you got cross compiled units in ~/cross_fpc/ | After this you got cross compiled units in ~/cross_fpc/ | ||
Line 126: | Line 136: | ||
=== Configure your fpc.cfg === | === Configure your fpc.cfg === | ||
− | + | As root, open your /etc/fpc.cfg or copy /etc/fpc.cfg to ~/fpc.cfg and edit this file. Search in the config for the unit search paths. | |
Note: On older versions of FPC $version and $target are used instead of $fpcversion and $fpctarget | Note: On older versions of FPC $version and $target are used instead of $fpcversion and $fpctarget | ||
Line 133: | Line 143: | ||
-Fu/usr/lib/fpc/$fpcversion/units/$fpctarget/rtl | -Fu/usr/lib/fpc/$fpcversion/units/$fpctarget/rtl | ||
− | Replace them with special paths for other platforms. For example for normal linux and cross compiled win32: | + | Replace them with special paths for other platforms. For example, for normal linux and cross compiled win32: |
#IFDEF win32 | #IFDEF win32 | ||
-Fu~/cross_fpc/lib/fpc/$fpcversion/cross/units/i386-win32/ | -Fu~/cross_fpc/lib/fpc/$fpcversion/cross/units/i386-win32/ | ||
Line 148: | Line 158: | ||
ToDo: Test and troubleshooting | ToDo: Test and troubleshooting | ||
+ | |||
+ | == Lazarus/LCL == | ||
=== Cross compiling the LCL and lazarus components === | === Cross compiling the LCL and lazarus components === | ||
− | At | + | At the command line: |
− | + | <syntaxhighlight lang=bash> | |
− | + | cd lazarus; make clean all OS_TARGET=win32 | |
+ | cd lazarus/lcl; make clean all | ||
+ | </syntaxhighlight> | ||
− | This will first cross compile everything for win32 (including the IDE, which is unecessary, but | + | This will first cross compile everything for win32 (including the IDE, which is unecessary, but this way is the easiest to explain). |
Or in the IDE: Set LCL, Synedit, Codetools, Package Registration and IDE Interface to Clean+Build, set LCL interface to win32/win64 and set 'Target OS' to win32. Then 'build lazarus'. | Or in the IDE: Set LCL, Synedit, Codetools, Package Registration and IDE Interface to Clean+Build, set LCL interface to win32/win64 and set 'Target OS' to win32. Then 'build lazarus'. | ||
− | These four parts have | + | These four parts have split output directories, so your linux .ppu/.o files are *not* overwritten and you don't need to recompile them. |
=== Cross compiling a project === | === Cross compiling a project === | ||
− | + | In Project->Compiler Options->Code, set the Target OS to 'win32' and in Paths the 'LCL Widget Type' to win32. That's all. The next time you build, you will create a win32 executable. | |
− | 'LCL Widget Type' to win32. That's all. The next time you build, you will | + | |
− | create a win32 executable. | + | The IDE will rescan for win32 units, so that 'Find declaration' and code completion features will now work with the win32 rtl instead of the linux rtl. |
− | The IDE will rescan for win32 units, so that 'Find declaration' and code | + | When you open another project or reopen this project the IDE will automatically switch. |
− | completion features will now work with the win32 rtl instead of the linux rtl. | ||
− | When you open another project or reopen this project the IDE will automatically | ||
− | switch. | ||
=== Hints for Cross compiling and Lazarus === | === Hints for Cross compiling and Lazarus === | ||
− | If you create an application/package for multiple targets, you will often do the following: Fix a bug, compile and test it under | + | If you create an application/package for multiple targets, you will often do the following: Fix a bug, compile and test it under Linux, then compile and test it under win32, .. . Because normally you overwrite your .ppu files, you have to recompile everything, everytime you switch. This is not necessary. |
The Lazarus IDE supports macros. | The Lazarus IDE supports macros. | ||
Line 179: | Line 190: | ||
Set Project -> Compiler Options -> Paths -> Unit Output directory to $(TargetOS). This macro will be replaced by the value in Code -> TargetOS in lowercase (i.e. "linux" for Linux and "win32" for Win32). | Set Project -> Compiler Options -> Paths -> Unit Output directory to $(TargetOS). This macro will be replaced by the value in Code -> TargetOS in lowercase (i.e. "linux" for Linux and "win32" for Win32). | ||
The output directory is relative to your project directory (the directory where your .lpi is). Create a linux and win32 directory in your project directory. | The output directory is relative to your project directory (the directory where your .lpi is). Create a linux and win32 directory in your project directory. | ||
+ | |||
When you click on the "Show Options" button at the bottom of the compiler options, you will see a -FElinux/ or -FEwin32/. This option tells the compiler where to write the output (e.g. .ppu/.o files). | When you click on the "Show Options" button at the bottom of the compiler options, you will see a -FElinux/ or -FEwin32/. This option tells the compiler where to write the output (e.g. .ppu/.o files). | ||
Line 187: | Line 199: | ||
$(TargetCPU)/$(TargetOS)/$(LCLWidgetType) | $(TargetCPU)/$(TargetOS)/$(LCLWidgetType) | ||
and create the sub directories for all targets. This path construction is also used by the LCL. | and create the sub directories for all targets. This path construction is also used by the LCL. | ||
− | |||
− | |||
The same can be done for packages. | The same can be done for packages. | ||
Line 195: | Line 205: | ||
Lazarus packages are not limited to libraries. They can be used to compile nearly everything. And the IDE automatically recompiles them if needed. | Lazarus packages are not limited to libraries. They can be used to compile nearly everything. And the IDE automatically recompiles them if needed. | ||
+ | |||
Packages can inherit compiler options. For example: A project that uses a package inherits the output directory of the package. In other words: the output directory of the package is added to unit search path of the project. See in the IDE: Project -> Compiler options -> Inherited. | Packages can inherit compiler options. For example: A project that uses a package inherits the output directory of the package. In other words: the output directory of the package is added to unit search path of the project. See in the IDE: Project -> Compiler options -> Inherited. | ||
− | Inheritance normally works only one way | + | |
− | + | Inheritance normally works only one way, but there are exceptions: | |
The target platform (OS and CPU) of the project overrides the target for all used packages. That means, if you set the Target OS of the project to "win32" and compile the project, the IDE will check if the used packages need to be recompiled for this Target OS. | The target platform (OS and CPU) of the project overrides the target for all used packages. That means, if you set the Target OS of the project to "win32" and compile the project, the IDE will check if the used packages need to be recompiled for this Target OS. | ||
Line 227: | Line 238: | ||
in compiler/ execute: | in compiler/ execute: | ||
− | + | <syntaxhighlight lang=bash> | |
− | + | gmake cycle CPU_TARGET=sparc OS_TARGET=solaris CROSSBINUTILPREFIX=solaris-sparc- CROSSOPT='-Xd -Fl~/src/sollib' | |
+ | </syntaxhighlight> | ||
~/src/sollib is a directory that contains: | ~/src/sollib is a directory that contains: | ||
Line 254: | Line 266: | ||
[[Category:Cross compilation]] | [[Category:Cross compilation]] | ||
+ | [[Category:FPC]] | ||
+ | [[Categor:Lazarus]] |
Revision as of 21:48, 17 March 2013
Hints to Cross Compile Win32 binaries under Linux
Since 0.9.10 there is an rpm 'fpc-crosswin32', that installs the needed binutils (e.g. cross assembler, cross linker), the fpc .ppu files cross compiled for win32 and modifies /etc/fpc.cfg.
It does not contain the cross compiled LCL .ppu files. You need to compile them yourself, after installing fpc-crosswin32.
General
Introduction - knowing, what you are doing
This is a short introduction for newbies. The following sections describe how to set up a Linux system to cross compile, creating Win32 executables (or FreeBSD or Darwin/OSX, or ...). Why cross compiling? FreePascal is a compiler and basically converts source into binaries (machine language). These binaries also contain information about how the operating system should start the executable. 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. But the compiler is only one part.
There is also the assembler and the linker. And these tools are not able to create crossplatform code. That's why we have to create a special linker 'ld' and assembler 'as' for every target platform. These are the binutils.
After creating the cross tools, all the FPC Pascal units will be cross compiled. For example, there will then be one system.ppu file for every target platform. Next, your FPC config file (fpc.cfg) will be set up, 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. And after this you can cross compile Pascal programs for Win32. Either start them with wine or copy them to a Windows machine and test them there.
Free Pascal
Why *nix to Windows and not the other way around
The main reason for this is that generating Unix binaries on a foreign platform (even another Unix or Linux system) is more complicated. Static linking is already complicated, let alone shared.
You would need the used libraries from the target platform (gtk, glib, libc etc), and a lot of additional configuring for ld (library paths, dynlinker path etc).
This has been partially done (for the static case), but it is hard since it needs manual postediting of linker files and linker commandline, and a deep understanding about what makes Unix binaries tick.
Download the FPC Sources
The binaries are not enough, you need the complete fpc sources. See www.freepascal.org. You can use SVN or a daily snapshot (HERE). For the following examples the FPC sources were downloaded to ~/sources/fpc.
You can download those files from HERE
Download the gnu binutils
For example binutils-2.18.tar.gz downloaded to ~/download/binutils-2.18.tar.gz.
You can download those files from HERE
Cross build binutils
In the fpcbuild repository there is a script to build the binutils for all cross platforms: install/cross/buildcrossbinutils
Download install of fpcbuild, e.g something like (adjust version):
cd ~
svn co http://svn.freepascal.org/svn/fpcbuild/branches/fixes_2_4/install install
Create a copy of the script:
cd ~/install/cross/
cp buildcrossbinutils buildcrossbinutils.sh
Edit the variables at the start of the new script.
The BASE variable points to a building and installation directory. So, it should be an empty directory. For example:
BASE=~/cross_fpc
Now the downloaded binutils file. If for instance you downloaded ~/download/binutils-2.18.tar.gz then set
BINUTILSPATH=~/download/ BINUTILSBASE=binutils BINUTILSVERSION=2.18 BINUTILS_GZIP=yes
The script will automatically combine this to ~/download/binutils-2.18.tar.gz.
The rest of the variables define what target platforms you have. The default is to build quite a lot, so compilation will take some time (hours on slow machines). For cross compile to windows, you need only
TARGETS_WIN="mingw32"
and comment out all others:
#BSD="freebsd netbsd openbsd" #TARGETS_WIN="cygwin mingw32 msdosdjgpp" #TARGETS_I386="${BSD} linux solaris darwin" #TARGETS_POWERPC="${BSD} linux darwin" #TARGETS_SPARC="${BSD} linux solaris" #TARGETS_M68k=
Then run the script:
sh buildcrossbinutils.sh
The script creates a subdirectory 'logs' full of log files. If something goes wrong, start looking there.
Note that the cross binutils for several platforms (Linux,FreeBSD, win32) these are available in compiled form already. See ftp://freepascal.stack.nl/pub/fpc/contrib/cross/
Cross build FPC
In the fpcbuild repository there is a script to build the fpc snapshot for all cross platforms: install/cross/buildcrosssnapshot Create a copy of the script:
cd ~/install/cross/
cp buildcrosssnapshot buildcrosssnapshot.sh
Edit the variables at the start of the new script.
Normally you will change at least CROSSTOOLSROOT, FPCCVS, DESTDIR, TARGETS_OS and TARGETS_CPU. For example:
CROSSTOOLSROOT=~/cross_fpc/cross FPCCVS=~/sources/fpc TARGETS_OS="win32" TARGETS_CPU="i386" DESTDIR=~/cross_fpc/
Then run the script:
sh buildcrosssnapshot.sh
After this you got cross compiled units in ~/cross_fpc/
Configure your fpc.cfg
As root, open your /etc/fpc.cfg or copy /etc/fpc.cfg to ~/fpc.cfg and edit this file. Search in the config for the unit search paths.
Note: On older versions of FPC $version and $target are used instead of $fpcversion and $fpctarget
-Fu/usr/lib/fpc/$fpcversion/units/$fpctarget -Fu/usr/lib/fpc/$fpcversion/units/$fpctarget/* -Fu/usr/lib/fpc/$fpcversion/units/$fpctarget/rtl
Replace them with special paths for other platforms. For example, for normal linux and cross compiled win32:
#IFDEF win32 -Fu~/cross_fpc/lib/fpc/$fpcversion/cross/units/i386-win32/ -Fu~/cross_fpc/lib/fpc/$fpcversion/cross/units/i386-win32/* -Fu~/cross_fpc/lib/fpc/$fpcversion/cross/units/i386-win32/rtl -XPi686-mingw32- -FD~/cross_fpc/cross/bin #ELSE linux -Fu/usr/lib/fpc/$fpcversion/units/$fpctarget -Fu/usr/lib/fpc/$fpcversion/units/$fpctarget/* -Fu/usr/lib/fpc/$fpcversion/units/$fpctarget/rtl #-Fu~/fpc/packages/*;~/fpc/rtl/linux #ENDIF
ToDo: Test and troubleshooting
Lazarus/LCL
Cross compiling the LCL and lazarus components
At the command line:
cd lazarus; make clean all OS_TARGET=win32
cd lazarus/lcl; make clean all
This will first cross compile everything for win32 (including the IDE, which is unecessary, but this way is the easiest to explain).
Or in the IDE: Set LCL, Synedit, Codetools, Package Registration and IDE Interface to Clean+Build, set LCL interface to win32/win64 and set 'Target OS' to win32. Then 'build lazarus'. These four parts have split output directories, so your linux .ppu/.o files are *not* overwritten and you don't need to recompile them.
Cross compiling a project
In Project->Compiler Options->Code, set the Target OS to 'win32' and in Paths the 'LCL Widget Type' to win32. That's all. The next time you build, you will create a win32 executable.
The IDE will rescan for win32 units, so that 'Find declaration' and code completion features will now work with the win32 rtl instead of the linux rtl. When you open another project or reopen this project the IDE will automatically switch.
Hints for Cross compiling and Lazarus
If you create an application/package for multiple targets, you will often do the following: Fix a bug, compile and test it under Linux, then compile and test it under win32, .. . Because normally you overwrite your .ppu files, you have to recompile everything, everytime you switch. This is not necessary. The Lazarus IDE supports macros.
Example 1: Cross compiling a project for linux and win32.
Set Project -> Compiler Options -> Paths -> Unit Output directory to $(TargetOS). This macro will be replaced by the value in Code -> TargetOS in lowercase (i.e. "linux" for Linux and "win32" for Win32). The output directory is relative to your project directory (the directory where your .lpi is). Create a linux and win32 directory in your project directory.
When you click on the "Show Options" button at the bottom of the compiler options, you will see a -FElinux/ or -FEwin32/. This option tells the compiler where to write the output (e.g. .ppu/.o files).
Example 2: Cross compiling a project for various platforms and widget sets.
Set the Unit output directory to $(TargetCPU)/$(TargetOS)/$(LCLWidgetType) and create the sub directories for all targets. This path construction is also used by the LCL.
The same can be done for packages.
Cross compiling and Lazarus Packages
Lazarus packages are not limited to libraries. They can be used to compile nearly everything. And the IDE automatically recompiles them if needed.
Packages can inherit compiler options. For example: A project that uses a package inherits the output directory of the package. In other words: the output directory of the package is added to unit search path of the project. See in the IDE: Project -> Compiler options -> Inherited.
Inheritance normally works only one way, but there are exceptions: The target platform (OS and CPU) of the project overrides the target for all used packages. That means, if you set the Target OS of the project to "win32" and compile the project, the IDE will check if the used packages need to be recompiled for this Target OS.
For example:
Package A has as output directory: lib/$(TargetOS) Project uses A.
- The project is built for linux. The IDE compiles A for linux in <PackageDirOfA>/lib/linux/, then it compiles the project for linux.
- The project is built for win32. The IDE compiles A for win32 in <PackageDirOfA>/lib/win32/, then it compiles the project for win32.
- The project is built again for linux. The IDE checks A for linux and does not recompile it. Then it compiles the project for linux.
So, using the macros saves a lot of time.
For Unix (general)
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.
For Linux under Win32
This is less trivial, there is some info in the buildfaq
FreeBSD to sparc
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.
For Mac OS X
See this forum post.