Cross compiling for Win32 under Linux/zh CN

From Lazarus wiki
Revision as of 07:50, 2 July 2021 by Robsean (talk | contribs) (较新的FPC - 2.1.1及较新的版本)

English (en) français (fr) magyar (hu) italiano (it) русский (ru) 中文(中国大陆)‎ (zh_CN)

概述

介绍 - 了解你在做什么

注意 : If your FPC has come from your Linux Distribution Repository, it is likely it won't have everything needed to be turned into a cross compiler. Please see Installing the Free Pascal Compiler - Linux.

这是针对新手的一份简短介绍。下面的部分将解释如何设置一个Linux系统来交叉编译,创建Win32可执行文件(或者为FreeBSD或者为Darwin/macOS,或者为...)。为什么交叉编译?Free Pascal是一个编译器,,基本上就是将源文件转换为二进制文件(机器语言)。这些二进制文件也包含操作系统应该如何启动可执行文件的信息。所以,这些二 进制文件是特定于平台的。

Free Pascal本身不需要多少设置。它可以为很多平台创建二进制文件。只需要告诉它来做什么就行。但是编译器只是其中的一部分。

这里也有汇编器和链接器。并且这些工具不能创建交叉平台的代码。这就是为什么我们必须为每一个目标平台创建一个特 殊的链接器'ld'和汇编器'as'。这些都是二进制实用程序。

在创建交叉工具后,所有的FPC的Pascal单元也将被交叉编译。例如,针对每个目标平台都将会有一个目标系统 的.ppu文件。 接下来,你将会设置FPC的配置文件(fpc.cfg),以便交叉编译将变得很容易,这样你可以 忘记所有令人厌倦的细节。同样的事情也会发生在LCL - Lazarus组件库上。并且在这之后,你可以为Win32交叉编译Pascal程序。要么使用wine启动它们,要么将它们复制到一个Windows机 器上,并在其中测试它们。

Free Pascal

为什么是从*nix到Windows,而不是从Windows到*nix

主要原因是,在一个外部平台上(甚至是在另一个Unix或Linux系统上)生成Linux/Unix二进制文件更为复杂。 静态链接已经很复杂了,更不要说动态链接了。

你可能需要使用来自目标平台的库(gtk, glib, libc等等),以及针对ld的很多附加的配置(库路径,动态链接器路径等)。

这样已经部分完成了(针对静态情况),但是它是很难的,因为它需要对链接器文件和链接器命令行进行手动后期编辑, 并且对Unix二进制文件做出深刻的理解。

较新的FPC - 2.1.1及较新的版本

如果你正在编译FPC的一个2.1.1或者较新的版本,你只需要这样做:

$ make all OS_TARGET=win32 CPU_TARGET=i386

然后

$ su -c "make crossinstall OS_TARGET=win32 CPU_TARGET=i386"
Note-icon.png

Note:
make crossinstall by default installs all files in /usr/local/lib/fpc/$fpcversion/units directory, that's why you will need to add to /etc/fpc.cfg file a new search path:
-Fu/usr/local/lib/fpc/$fpcversion/units/$fpctarget/*.

Another option is to use INSTALL_PREFIX=/usr while performing crossinstall. In this case, you will not need to change anything in /etc/fpc.cfg file because all will be installed in /usr/lib/fpc/$fpcversion/units which is already there

Note-icon.png

Note:
To build for win64 the make command is: make all OS_TARGET=win64 CPU_TARGET=x86_64

Note-icon.png

Note: {{{1}}}

Note-icon.png

Note: {{{1}}}

之所以这么简单是因为在fpc的这个版本中已经包含了内部链接器。

在Bunsen Labs系统下的一个示例(Debian 8)

- 使用FPC 3.0.0和Lazarus 1.6.2交叉编译到Win32和Win64。

- 打开你的终端并执行下面的命令(为此非常感谢Handoko和Leledumbo,你们真是令人敬畏)。

# Navigate to the fpc source folder.
cd /usr/share/fpcsrc/3.0.0

# Compile the cross-compiler.
make all OS_TARGET=win32 CPU_TARGET=i386

# Install the cross-compiler.
sudo make crossinstall OS_TARGET=win32 CPU_TARGET=i386 INSTALL_PREFIX=/usr

# Link the cross-compiler and place the link where Lazarus can see it.
sudo ln -sf /usr/lib/fpc/3.0.0/ppcross386 /usr/bin/ppcross386

# Do the same using x64 as target
make all OS_TARGET=win64 CPU_TARGET=x86_64
sudo make crossinstall OS_TARGET=win64 CPU_TARGET=x86_64 INSTALL_PREFIX=/usr
sudo ln -sf /usr/lib/fpc/3.0.0/ppcrossx64 /usr/bin/ppcrossx64

- 确保你的交叉编译器是存在的:(注意,链接到交叉编译二进制文件出现在/usr/bin中,而不是仅出现在/usr/lib中,如下图所示)。

000-cross-compilers-compiled.png

- 确保你的交叉编译器已经正确的链接:

000-cross-compilers-linked.png

- 现在,打开Lazarus。

- 按 Ctrl+Shift+F11,或导航到 工程->工程选项->路径菜单。在弹出的"工程选项"对话框的右侧列表中找到"路径"选项。

- 针对每次构建,配置你的路径,以便所有需要的库都是可获取的,并且由Lazarus/FPC生成所有输出文件不需要重写。在"单元输出路径"和"目标文件 名称"中,我选择使用宏命令。

002-paths-win32.png

- Create builds and edit build names 在"构建模式: [BuildName]" 窗口中(单击上面的[...]按钮来打开它),创建构建模式和编辑构建模式。 001-build-modes.png

- 当你完成后,单击ok

- 现在,转到 运行->编译多种模式。按ok。一直等到Lazarus和FPC完成它们的工作。

003-build-many-modes.png

- 转到你的工程文件夹,好好享受!

Write once, compile anywhere.

较老的FPC,早于2.1.1

针对早于2.1.1的FPC版本,请查看历史链接(在2014年08月19日之前的版本)来查看需要的步骤。

Lazarus/LCL

Cross compiling the LCL and Lazarus components

The IDE automatically cross compiles all used packages when you change the target of your project and build it.

Cross compiling a project

In Project->Compiler Options->Code, set the Target OS to 'win32' and in "Additions and Overrides" click Set LCL WidgetType and select 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.

  1. The project is built for linux. The IDE compiles A for linux in <PackageDirOfA>/lib/linux/, then it compiles the project for linux.
  2. The project is built for win32. The IDE compiles A for win32 in <PackageDirOfA>/lib/win32/, then it compiles the project for win32.
  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.

So, using the macros saves a lot of time.


See also