From Fedora Project Wiki

Packaging Guidelines for cross compiler framework

Based on the MinGW guidelines
These draft guidelines are based on the MinGW guidelines and will obsolete them

Introduction

The Fedora MinGW project's mission is to provide an excellent development environment for Fedora users who wish to cross-compile their programs to run on Windows, minimizing the need to use Windows at all. In the past developers have had to port and compile all of the libraries and tools they have needed, and this huge effort has happened independently many times over. We aim to eliminate duplication of work for application developers by providing a range of libraries and development tools which have already been ported to the cross-compiler environment. This means that developers will not need to recompile the application stack themselves, but can concentrate just on the changes needed to their own application.

As of Fedora 15 a set of RPM macros and packages have been introduced which help packagers compile binaries for multiple targets. Initially, the targets Win32 and Win64 will be supported. However support for other targets (such as Mac OS X) will become easy to implement.

Note that when deciding to contribute a new cross compiled library to the Fedora project, it is advisable to start with our example specfile: http://hg.et.redhat.com/misc/fedora-mingw--devel/?fl=7e95a9b24e2d;file=example/mingw32-example.spec

Track Fedora native package versions

In general terms, cross-compiled versions of packages which already natively available in Fedora, should follow the native Fedora package as closely as possible. This means they should stay at the same version, include all the same patches as the native Fedora package, and be built with the same configuration options.

The MinGW SIG have written an RPM comparison tool which makes it possible to compare cross compiled packages with the Fedora native packages, in order to determine whether versions, patches and configuration are aligned.

Follow Fedora policy

Cross compiled packages must follow Fedora policy, except where noted in this document. Cross compiled packages go through the same review process, GIT admin process etc as other Fedora packages.

Package naming

Packages should be named by prefixing the upstream package name with one of the following terms:

cross- Used for packages which can be built for multiple targets
mingw- Used for packages which can be built for both Win32 and Win64 but not for other targets
mingw32- Used for packages which can only be built for Win32
mingw64- Used for packages which can only be built for Win64

Examples: The glib2 package can be built for both Win32, Win64 as well as other targets (such as Mac OS X), hence it should be named cross-glib2 The win-iconv package only supports Win32 and Win64, hence it should be named mingw-win-iconv

Base packages

The base packages provide a root filesystem, base libraries, binutils (basic programs like 'strip', 'ld' etc), the compiler (gcc) and the Win32/Win64 API. Packages may need to depend on one or more of these. In particular, almost any conceivable package should depend on cross-filesystem and cross-gcc.

cross-filesystem Core filesystem directory layout, and RPM macros for spec files. Equivalent to 'filesystem' RPM
cross-binutils Cross-compiled binutils (utilities like 'strip', 'as', 'ld') which understand Windows executables and DLLs. Equivalent to 'binutils' RPM
cross-gcc GNU compiler collection. Compilers for C and C++ which cross-compile to a Windows target. Equivalent to gcc RPM
mingw-crt Base libraries for core MinGW runtime & development environment. Equivalent to 'glibc' RPM
mingw-headers Win32 and Win64 API. A free (public domain) reimplementation of the header files required to link to the Win32 and Win64 API. No direct equivalent in base Fedora - glibc-devel is closest

Build for multiple targets

The goal of the cross compiler framework is to provide an easy way for package maintainers to build their packages for multiple targets using one .spec file. To aid developers in this several RPM macros have been developed which are part of the cross-filesystem package. These RPM macros will be explained later on in these guidelines.

Several RPM macros depend on the package name minus the prefix, so each package must contain %global _cross_pkg_name foo (where foo is the name of the package, for example glib2)

To indicate which targets should be build, the package must contain at least one of the following lines:

%global _cross_build_win32 1 Build for the Win32 target
%global _cross_build_win64 1 Build for the Win64 target

One source RPM, per-target binary RPMs

Each cross compiled package which builds binaries for a specific target should put the binaries for that target in a separate subpackage. So if a package foo builds binaries for the Win32 and Win64 targets, then the source RPM should provide two subpackages named mingw32-foo and mingw64-foo.

The main package (cross-foo in our example) must have Requires: xxx tags for all the targets. To aid in this, the RPM macro %{?_cross_default_requires} should be added to the spec file

This means that a spec file must contains %package and %files sections for all the targets. We're still looking for methods to simplify this as it currently introduces quite an amount of duplication

If a package contains translations then all calls to the %find_lang must be replaced by %_cross_find_lang. This causes all translation filelists to be split in per-target filelists. For example: when a spec file contains something like this:

%global _cross_build_win32 1
%global _cross_build_win64 1
<snip> 
%install
<snip>
%_cross_find_lang foo

then two files will get created named mingw32-foo.lang and mingw64-foo.lang. These file lists can be included in the %files section for the targets:

%files -n mingw32-foo -f mingw32-foo.lang
<snip>
%files -n mingw64-foo -f mingw64-foo.lang

Filesystem layout

[root]
  |
  +- etc
  |   |
  |   +- rpm
  |       |
  |       +- macros.cross
  |       +- macros.mingw32
  |       +- macros.mingw64
  |
  +- usr
      |
      +- bin   - Links to cross compiler toolchain
      |   |
      |   +- i686-w64-mingw32-cpp
      |   +- i686-w64-mingw32-gcc
      |   +- i686-w64-mingw32-g++
      |   +- x86_64-w64-mingw32-cpp
      |   +- x86_64-w64-mingw32-gcc
      |   +- x86_64-w64-mingw32-g++
      |   +- ... etc..
      |
      +- lib
      |   |
      |   +- rpm
      |       |
      |       +- cross-find-debuginfo.sh - extract debug information from Win32 and Win64 binaries
      |       +- cross-find-lang.sh - generates per-target file lists containing translations
      |       +- cross-find-provides.sh - extra DLL names
      |       +- cross-find-requires.sh - discover required DLL names
      |
      +- i686-w64-mingw32  - root of mingw toolchain and binaries for the Win32 target - see next diagram
      +- x86_64-w64-mingw32  - root of mingw toolchain and binaries for the Win64 target - see next diagram


/usr/i686-w64-mingw32
/usr/x86_64-w64-mingw32
  |
  +- bin  - Binutils toolchain binaries for the target
  |   |
  |   +- ar
  |   +- as
  |   +- dlltool
  |   +- ld
  |   +- ... etc ...
  |
  +- lib  - Binutils toolchain support libraries / files for the target
  |
  +- sys-root  - root for cross compiled binaries
      |
      +- mingw
          |
          +- bin     - cross-compiled binaries & runtime DLL parts
          +- etc     - configuration files
          +- include - include files for cross compiled libs
          +- lib     - cross-compiled static libraries & linktime DLL parts
          |   |
          |   +- pkgconfig  - pkg-config definitions for libraries
          |
          +- share
              |
              +- man

Filenames of the cross-compilers and binutils

The cross-compilers and binutils are Fedora binaries and are therefore placed in %{_bindir} (ie. /usr/bin) according to the FHS and Fedora guidelines.

The cross-compilers and binutils which generate i686 binaries for Windows are named:

%{_bindir}/i686-w64-mingw32-gcc
%{_bindir}/i686-w64-mingw32-g++
%{_bindir}/i686-w64-mingw32-ld
%{_bindir}/i686-w64-mingw32-as
%{_bindir}/i686-w64-mingw32-strip
etc.

The same binaries are present in %{_prefix}/i686-w64-mingw32/bin without any prefix in the name, ie:

%{_prefix}/i686-w64-mingw32/bin/gcc
%{_prefix}/i686-w64-mingw32/bin/g++
%{_prefix}/i686-w64-mingw32/bin/ld
%{_prefix}/i686-w64-mingw32/bin/as
%{_prefix}/i686-w64-mingw32/bin/strip
etc.

The same also applies for the x86_64 target. This target uses 'x86_64-w64-mingw32' as prefix instead of 'i686-w64-mingw32'

Naming of the root filesystem

The root filesystem contains Windows executables and DLLs and any other Windows-only files. It is necessary both because we need to store Windows libraries in order to link further libraries which depend on them, and also because MinGW requires a root filesystem location.

The location for Win32 target is provided by the macro:

%{_mingw32_sysroot}   %{_prefix}/i686-w64-mingw32/sys-root

And the Win64 target is provided by the macro:

%{_mingw64_sysroot}   %{_prefix}/x86_64-w64-mingw32/sys-root

Standard mingw RPM macros

The cross-filesystem package provides a number of convenience macros for the cross compiled sysroot directories, and toolchain. It is mandatory to use these macros in all cross compiled packages submitted to Fedora.

Toolchain macros

The following macros are for the %build and %install section of the spec

Generic macros:

_cross_cmake Call the cmake binary for all the configured targets (_cross_build_win32/_cross_build_win64)
_cross_configure Call the configure command for all the configured targets (_cross_build_win32/_cross_build_win64)
_cross_make Call the 'make' command for all the configured targets (_cross_build_win32/_cross_build_win64)
_cross_make_install Call the 'make install' command for all the configured targets (_cross_build_win32/_cross_build_win64)
_cross_objcopy mingw-objcopy cross compiler 'objcopy' binary (which supports both Win32 and Win64 binaries)
_cross_objdump mingw-objdump cross compiler 'objdump' binary (which supports both Win32 and Win64 binaries)
_cross_strip mingw-strip cross compiler 'strip' binary (which supports both Win32 and Win64 binaries)


Win32 specific macros:

_mingw32_ar i686-w64-mingw32-ar cross compiler 'ar' binary
_mingw32_cc i686-w64-mingw32-gcc cross compiler 'gcc' binary
_mingw32_cflags -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions --param=ssp-buffer-size=4 -mms-bitfields Default compiler flags for C/C++ binaries
_mingw32_cmake Call the cmake binary for the Win32 target
_mingw32_configure standard invocation for autotools 'configure' scripts
_mingw32_cpp i686-w64-mingw32-gcc -E cross compiler 'cpp' binary
_mingw32_env Set the correct environment variables for the Win32 target
_mingw32_host i686-w64-mingw32 Host platform for build
_mingw32_objcopy i686-w64-mingw32-objcopy cross compiler 'objcopy' binary
_mingw32_objdump i686-w64-mingw32-objdump cross compiler 'objdump' binary
_mingw32_pkg_config Call the pkg-config command for the Win32 target
_mingw32_ranlib i686-w64-mingw32-ranlib cross compiler 'ranlib' binary
_mingw32_strip i686-w64-mingw32-strip cross compiler 'strip' binary
_mingw32_target i686-w64-mingw32 Target platform for build


Win64 specific macros:

_mingw64_ar x86_64-w64-mingw32-ar cross compiler 'ar' binary
_mingw64_cc x86_64-w64-mingw32-gcc cross compiler 'gcc' binary
_mingw64_cflags -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions --param=ssp-buffer-size=4 -mms-bitfields Default compiler flags for C/C++ binaries
_mingw64_cmake Call the cmake binary for the Win64 target
_mingw64_configure standard invocation for autotools 'configure' scripts
_mingw64_cpp x86_64-w64-mingw32-gcc -E cross compiler 'cpp' binary
_mingw64_env Set the correct environment variables for the Win64 target
_mingw64_host x86_64-w64-mingw32 Host platform for build
_mingw64_objcopy x86_64-w64-mingw32-objcopy cross compiler 'objcopy' binary
_mingw64_objdump x86_64-w64-mingw32-objdump cross compiler 'objdump' binary
_mingw64_pkg_config Call the pkg-config command for the Win64 target
_mingw64_ranlib x86_64-w64-mingw32-ranlib cross compiler 'ranlib' binary
_mingw64_strip x86_64-w64-mingw32-strip cross compiler 'strip' binary
_mingw64_target x86_64-w64-mingw32 Target platform for build

Filesystem location macros

The following macros are for use in %build, %install and %files sections of the RPM spec

For the Win32 target:

_mingw32_bindir %{_mingw32_prefix}/bin Location of Windows executables.
_mingw32_datadir %{_mingw32_prefix}/share Shared data used under Windows.
_mingw32_docdir %{_mingw32_prefix}/share/doc Documentation.
_mingw32_infodir %{_mingw32_prefix}/share/info Info files (see note below).
_mingw32_includedir %{_mingw32_prefix}/include Header files used when cross-compiling for Windows.
_mingw32_libdir %{_mingw32_prefix}/lib Windows libraries (see sections below).
_mingw32_libexecdir %{_mingw32_prefix}/libexec
_mingw32_mandir %{_mingw32_prefix}/share/man Man pages (see note below).
_mingw32_prefix %{_mingw32_sysroot}/mingw Windows equivalent of %{_prefix}, required by MinGW.
_mingw32_sbindir %{_mingw32_prefix}/sbin
_mingw32_sysconfdir %{_mingw32_prefix}/etc Configuration files used when running under Windows.
_mingw32_sysroot %{_prefix}/i686-w64-mingw32/sys-root Windows system root.


For the Win64 target:

_mingw64_bindir %{_mingw64_prefix}/bin Location of Windows executables.
_mingw64_datadir %{_mingw64_prefix}/share Shared data used under Windows.
_mingw64_docdir %{_mingw64_prefix}/share/doc Documentation.
_mingw64_infodir %{_mingw64_prefix}/share/info Info files (see note below).
_mingw64_includedir %{_mingw64_prefix}/include Header files used when cross-compiling for Windows.
_mingw64_libdir %{_mingw64_prefix}/lib Windows libraries (see sections below).
_mingw64_libexecdir %{_mingw64_prefix}/libexec
_mingw64_mandir %{_mingw64_prefix}/share/man Man pages (see note below).
_mingw64_prefix %{_mingw64_sysroot}/mingw Windows equivalent of %{_prefix}, required by MinGW.
_mingw64_sbindir %{_mingw64_prefix}/sbin
_mingw64_sysconfdir %{_mingw64_prefix}/etc Configuration files used when running under Windows.
_mingw64_sysroot %{_prefix}/x86_64-w64-mingw32/sys-root Windows system root.

Compilation of binaries

In order to build binaries for multiple targets we have to call commands like ./configure and make multiple times (once for each target). If one has to write this all out in a spec file then it will lead to duplicate code. To reduce the amount of duplication, several RPM macros have been introduced to help with the compilation. These macros are %{_cross_configure}, %{_cross_cmake}, %{_cross_make} and %{_cross_make_install}

These macros use out of source compilation to build binaries for all the targets. Almost all packages support out of source compilation or require slight patching. The only known exceptions to date are zlib and openssl. Packages which don't support out of source compilation may require a different approach like performing everything in the %install phase. If you happen to stumble across a package which requires a different approach feel free to contact us on the Fedora MinGW mailing list

There's a difference in the behavior between these macros and the original %{_mingw32_xxx} macros. As all commands will get executed multiple times (once for each target) one has to indicate what arguments should be used. For example, with the original Fedora MinGW toolchain you could do:

%{_mingw32_configure} --disable-xlib --enable-win32

This has to be changed to something like this:

%{_cross_configure "--disable-xlib" "--enable-win32"}

The quotes mentioned above are mandatory! If you forget them then rpmbuild will fail or the arguments might not get passed to the ./configure calls. Also note that the '}' character needs to be placed after all the arguments

Some packages need to be built multiple times for each target. Examples of this are packages which have to be built once for a static version and once for a shared version. Such packages can add a custom suffix to the build directory used. Say you've got something like below:

mkdir build_shared
pushd build_shared
%{_mingw32_configure} --enable-shared
popd
mkdir build_static
pushd build_static
%{_mingw32_configure} --enable-static
popd

This can be rewritten to something like this:

%{_cross_configure -s shared "--enable-shared"}
%{_cross_configure -s static "--enable-static"}

Most packages used the command make %{?_smp_mflags} to build the package. In the cross compiler framework you have to use %{_cross_make %{?_smp_mflags}} to build the package for all configured targets As with the %{_cross_configure} macro you can also use the -s argument to indicate a custom suffix to the build directory used

To install the package the command make install DESTDIR=$RPM_BUILD_ROOT was used in almost all cases. This can be rewritten to %{_cross_make_install DESTDIR=$RPM_BUILD_ROOT} to install the package for all configured targets The -s argument can also be used here

Some packages require some custom instructions before the files are ready to be packaged. Such code can remain as is. However, you may need to duplicate these instructions multiple times (for all configured targets).

Dependencies

If a package contains binaries which depend on a DLL provided by another package, these dependencies should be expressed in the form:

mingw32(foo.dll)

where foo.dll is the name of the DLL. The name must be converted to lowercase because Windows binaries contain case insensitive dependencies. The form 'mingw32(foo.dll)' should be used for Win32 binaries and the form 'mingw64(foo.dll)' for Win64 binaries

Correct dependency generation is done automatically. Packagers should include these lines in all library packages:

%global _use_internal_dependency_generator 0
%global __find_requires %{_cross_findrequires}
%global __find_provides %{_cross_findprovides}

All binary packages should depend on mingw32-filesystem or mingw64-filesystem (depending on the files in the package). If the lines mentioned above are used then it will be added automatically, so you don't have to add it yourself

All specfiles should BuildRequire at least:

BuildRequires:  cross-filesystem >= minimum-version

and any other BuildRequires that they need.

Build architecture

All packages should have:

BuildArch: noarch

unless they contain Fedora native executables.

Libraries (DLLs)

All libraries must be built as DLLs.

Because of the peculiarity of Windows, DLLs are stored in the %{_mingw32_bindir} directory, along with a control file in the %{_mingw32_libdir} directory. For example, for a library called foo there would be:

%{_mingw32_bindir}/foo.dll
%{_mingw32_libdir}/foo.dll.a
%{_mingw32_libdir}/foo.la

All files are required in those locations in order to link successfully. The .dll may contain a version number although not always (eg. foo-0.dll).

Do not use %{_mingw32_bindir}/* or %{_mingw32_libdir}/* in %files section

The %files section must list DLLs separately. Packages must NOT use %{_mingw32_bindir}/* or %{_mingw32_libdir}/*

The reason for this is that libtool is very fragile and will give up on building a DLL very easily. Therefore we force the name of the DLL to be listed explicitly in the %files section in order to catch this during RPM builds.

Manpages and info files

If manpages or info files are simply duplicates of equivalent documentation found in Fedora native packages, then they should not be packaged in the MinGW package.

Static libraries

In accordance with ordinary Fedora policy, static libraries should not be built, and if they are then they should be placed in a -static subpackage.

Stripping

Libraries and executables should be stripped. This is done correctly and automatically if the spec file includes these lines:

%global __strip %{_cross_strip}
%global __objdump %{_cross_objdump}

(Note that if __strip and __objdump are not overridden in the specfile then this can sometimes cause Windows binaries to be corrupted).

Debuginfo subpackage

Most binaries contain debugging symbols when the package gets built. To split the debugging symbols to a separate debuginfo package (as is done with native Fedora packages) the spec file must include these lines:

%define __debug_install_post %{_cross_debug_install_post}
%{?_cross_debug_package}

Note that %define really must be used here. If you use %global then the automatic generation of a debuginfo subpackage won't work