Sign in Join
Wiki copytemporary

Cross compiling for Windows under Linux: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11> **Note:** Rewrite in progress, original content is retained inside comment tags; will pop up here again as it's reviewed and updated as necessary.
22
33## General
44
55One of the FPC's features is its ability to cross-compile. It's very useful to be able to make Windows (32-bit and 64-bit) from your Linux workstation. Everything we do here relates to FPC, no changes are needed to Lazarus.
66
77It's very important to note that these instructions apply to a FPC that was installed from packages from SourceForge; if you are using packages from your Linux distribution then they will almost certainly not work. In fact, in many cases, Linux distribution repository packages may not support building cross-compiles. Please consider uninstalling the distribution's packages and replacing them with ones from the [official FPC/Lazarus SourceForge repository](https://sourceforge.net/projects/lazarus/files/Lazarus).
88
99These instructions have been tested on Ubuntu Linux 21.04 "The Hirsute Hippo" and openSUSE Leap 15.3.
1010
1111### Install FPC/Lazarus
1212
1313If you already have a working FPC/Lazarus install obtained from SourceForge, then skip this step. Install FPC and Lazarus using the SourceForge method as detailed in [[Installing Lazarus on Linux|Installing Lazarus on Linux § Build Lazarus from Source]] It's a good idea to fire it up and make sure you can build and compile a simple app first.
1414
1515### Setting up x86_64 Linux to Windows Cross-compile
1616
1717Note, we assume the use of FPC 3.2.2, if you're using a different version, put the right numbers in yourself!
1818
1919The process here is to build the pre-compiled FPC units to suit Windows (both 32-bit and 64-bit) and, of course, the Windows compilers, ppcross386 and ppcross64. We then put a symlink to the compilers in the right place and make sure your FPC config files know about the Windows pre-compiled units.
2020
2121Now to make a cross-compiler, the following needs to be done as root. It's easier (but slightly riskier) to `sudo` (or `su`) and stay as root for the whole process, so please be careful. We will set a temporary environment variable containing the FPC version number to make copy and pasting easy (assuming you are using FPC 3.2.2).
2222
2323```shell
2424sudo -i
2525export FPCVER="3.2.2"
2626cd "/usr/share/fpcsrc/${FPCVER}"
2727make clean all OS_TARGET=win64 CPU_TARGET=x86_64
2828make clean all OS_TARGET=win32 CPU_TARGET=i386
2929```
3030
3131Those steps take awhile each. Watch for errors as the compile report scrolls by. It builds Windows versions of the units in the FPC-SRC tree. The next lines are pretty quick; they copy the units to `/usr/lib/fpc/${FPCVER}/units` and the ones after that make symlinks to the cross-compilers.
3232
3333``` bash
3434make crossinstall OS_TARGET=win64 CPU_TARGET=x86_64 INSTALL_PREFIX=/usr
3535make crossinstall OS_TARGET=win32 CPU_TARGET=i386 INSTALL_PREFIX=/usr
3636ln -sf "/usr/lib/fpc/${FPCVER}/ppcrossx64" /usr/bin/ppcrossx64
3737ln -sf "/usr/lib/fpc/${FPCVER}/ppcross386" /usr/bin/ppcross386
3838```
3939
4040Assuming you did not see any errors, does your `fpc.cfg` file need attention?
4141
4242``` bash
4343grep 'Fu' /etc/fpc.cfg
4444```
4545
4646Does the result listed include `-Fu/usr/lib/fpc/${fpcversion}/units/${fpctarget}/*`? If not, you need to fire up your favorite editor and add it. Look for the first line in the sample below, and when you find it, add the second line as shown.
4747
4848```text
4949# searchpath for units and other system dependent things
5050-Fu/usr/lib/fpc/${fpcversion}/units/${fpctarget}/*
5151```
5252
53-That's it, press <span class="kbd">Ctrl</span>+<span class="kbd">D</span> to get out of the risky root mode, and test it out.
53+That's it, press Ctrl+D to get out of the risky root mode, and test it out.
5454
5555### Testing
5656
5757Fire up Lazarus and open a new project, then:
5858
5959- Project ⇒ ProjectOptions ⇒ ConfigAndTarget, and set Target OS (-T) to Win64
6060- Project ⇒ ProjectOptions ⇒ ConfigAndTarget, and set LCLWidgetType to Win32
6161- Run ⇒ Build
6262- Project ⇒ ProjectOptions ⇒ ConfigAndTarget, and set Target OS (-T) to Win32
6363- Project ⇒ ProjectOptions ⇒ ConfigAndTarget, and set Target CPU Family (-P) to i386
6464- Project ⇒ ProjectOptions ⇒ AdditionsAndOverRides, and set LCLWidgetType to Win32
6565- Run ⇒ Build
6666
6767Obviously, you cannot 'run' that binary, but if one is made, it's almost certainly okay.
6868
6969## Lazarus/LCL
7070
7171### Cross-compiling the LCL and Lazarus components
7272
7373The IDE automatically cross-compiles all used packages when you change the target of your project and build it.
7474
7575### Cross-compiling a project
7676
7777Lazarus projects can have 'Modes', and it's convenient to set a mode for each compilation you want to perform. Here you can make Linux64 binaries and Windows 32-bit and 64-bit executables, so make a mode for each and apply the appropriate settings to each mode.
7878
7979In Project ⇒ ProjectOptions ⇒ ConfigAndTarget, set the Target OS to 'win64' and in "Additions and Overrides" click "Set LCL WidgetType" and select win32. That's all. The next time you build, you will create a win64 executable.
8080
8181Similarly, to make a Win32 executable, do the above but also set Project ⇒ ProjectOptions ⇒ ConfigAndTarget and set Target CPU Family (-P) to i386.
8282
8383The IDE will rescan for the Windows units, so that 'Find declaration' and code completion features will now work with the win32 rtl instead of the Linux rtl.
8484
8585### Hints for cross-compiling with Lazarus
8686
8787If you create an application/package for multiple targets, you will often do the following:
8888
8989- Fix a bug
9090- Compile and test it under Linux, then
9191- Compile and test it under Win32
9292
9393Because normally you overwrite your .ppu files you have to recompile everything, every time you switch. However, this is not necessary; the Lazarus IDE supports macros.
9494
9595#### Example 1: Cross-compiling a project for Linux and Win32
9696
9797Set 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 file is). Create `linux` and `win32` directories in your project directory.
9898
9999When 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).
100100
101101#### Example 2: Cross-compiling a project for various platforms and widget sets
102102
103103Set 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.
104104
105105The same can be done for packages.
106106
107107### Cross-compiling and Lazarus packages
108108
109109Lazarus packages are not limited to libraries, they can be used to compile nearly everything and the IDE automatically recompiles them, if needed.
110110
111111Packages 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 the unit search path of the project. See for yourself in IDE: Project ⇒ Compiler options ⇒ Inherited.
112112
113113Inheritance normally works only one way, but there are exceptions:
114114
115115- The target platform (OS and CPU) of the project override 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:
116116 - Package A has as output directory: lib/\$(TargetOS). Project uses A.
117117
118118 1. The project is built for linux. The IDE compiles A for linux in \<PackageDirOfA\>/lib/linux/, then it compiles the project for linux.
119119 2. The project is built for win32. The IDE compiles A for win32 in \<PackageDirOfA\>/lib/win32/, then it compiles the project for win32.
120120 3. 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.
121121
122122So using the macros saves a lot of time.
123123
124124## See also
125125
126126- [[Cross compiling]]
127127- [[buildfaq]]
128128
129129---
130130*From the Free Pascal wiki, page "Cross compiling for Windows under Linux", as it stood on 2023-09-20 after a change by RogueScholar, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
131131Category: Cross compilation
132132Category: FPC
133133Category: Lazarus

Back to history