Packaging Guidelines for MinGW Cross Compilers

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 MinGW 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.

The targets Win32 and Win64 are supported with the MSVCRT runtime. The target Win64 with the UCRT runtime is also supported, however, only for the base toolchain. Builds for UCRT are not enabled for packages above the toolchain at this time.

Separate vs integrated MinGW source packages

There are two permitted ways to provide MinGW builds of software in Fedora:

  • Separate source packages: There are distinct RPM spec files for the native and MinGW builds, maintained as independent components of Fedora. This is the traditional approach to MinGW packaging in Fedora

  • Integrated source packages: There is a single RPM spec file for the native and MinGW builds, as a single component of Fedora. The MinGW builds are emitted as binary sub-RPMs. This is the modern, preferred, approach to MinGW packaging in Fedora.

The traditional approach of completely separated source packages was adopted initially because of concerns that instability in the MinGW toolchain or Windows builds may prevent timely updates to the native package. Experience in Fedora since then has shown that is not generally a problem that impacts most packages, especially where Windows support is an explicitly tested deliverable of the upstream project.

Using the separate packaging approach has a significantly higher overhead:

  • The addition of MinGW support must go through the full Fedora review process for new packages, largely duplicating review already performed on the native package.

  • There is an ongoing burden for the maintainer to ensure the MinGW source package tracks changes to the corresponding native source package as it rebases to new releases.

  • There is additional work in handling patches/updates in response to bug reports. Bug reports are often only reported against one of the two components not both, but with security vulnerabilities there are twice the number of bug reports created. There are then also multiple koji builds and updates to handle.

With the integrated packaging approach there is a small extra overhead on the native package maintainer to ensure MinGW builds keep working and a small additional load of MinGW specific bug reports. This is usually negligible compared to the overhead of maintaining separated packages.

With this in mind, the recommendation of the MinGW SIG is thus:

  • Where the same Fedora contributor intends to maintain both the native and MinGW builds of a package, they MUST use the integrated packaging approach.

  • Where the upstream project explicitly supports the Windows platform as a build target and has automated CI, contributors SHOULD prefer the integrated MinGW packaging approach. Native package maintainers SHOULD ordinarily accept addition of integrated MinGW support. If declining the request the native maintainer should give a rationale for their decision.

  • Where the upstream project does not have automated testing of Windows builds, the MinGW package support MAY use either packaging approach. The native maintainer may decline the request for integrated packaging at their discretion.

  • Where the upstream project only supports Windows builds, the separate packaging approach MUST be used. There will be no corresponding native package in Fedora expected. This situation is very rare.

  • When a contributor proposes a new native package to Fedora that provides libraries that are known to support Windows, the reviewer SHOULD inquire whether the contributor would like to add MinGW builds at the same time. The contributor may decline this request at their discretion.

Adding MinGW support alongside a new native package

When a corresponding native package does not already exist, it will always be required to go through the standard Fedora new package review process. The proposed MinGW support MUST follow the integrated packaging approach to provide both the MinGW and native builds, where technically possible. As noted in the previous section, in some rare situations there will be no corresponding native package, thus requiring the separate pacakaging approach to be taken.

Adding MinGW support to an existing native package

When a corresponding native package is already present in Fedora, the preference is to add MinGW support to the native source package.

Where the source package changes are simple, the contributor SHOULD:

  • Make the required spec file additions in their fork of the package

  • Submit a koji scratch-build to prove the changes have the expected effect

  • Open a merge request against the native package with the spec changes, adding a link to the koji scratch-build results as a comment.

The existing native package maintainer thus gets clear view of the impact of the MinGW additions to their package, to evaluate the viability of following the integrated packaging approach.

Where there is doubt about the viability of following the integrated package approach, a bug MAY be opened against the package ahead of starting work to discuss the two packaging options with the native package maintainer.

If the native maintainer declines the proposal to add MinGW support to the existing package, the regular Fedora new package process MUST be followed to introduce MinGW support following the separate packaging approach.

Track Fedora native package versions

In general terms, cross-compiled MinGW versions of packages which are 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 preferred way to achieve this goal is for the MinGW support to use the integrated packaging approach.

Follow Fedora policy

Cross compiled MinGW 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

MinGW packages require special naming to denote the appropriate CPU architecture the binaries have been built for. There should never be a package prefixed with mingw- output during a build. The mingw- prefix is exclusive for RPM spec file names and the source RPM file name. The CPU architecture specific packages are created by sections with %files -n mingw32-foo, %files -n mingw64-foo or %files -n ucrt64-foo.

mingw-

Used for source package and RPM spec name (only where the separate packaging approach is chosen)

mingw32-

Used for packages which are built for Win32 with the MSVCRT runtime

mingw64-

Used for packages which are built for Win64 with the MSVCRT runtime

ucrt64-

Used for packages which are built for Win64 with the UCRT runtime

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 all packages should BuildRequire mingw32-filesystem, mingw64-filesystem, mingw32-gcc and mingw64-gcc.

mingw32-filesystem / mingw64-filesystem / ucrt64-filesystem

Core filesystem directory layout, and RPM macros for spec files. Equivalent to 'filesystem' RPM

mingw32-binutils / mingw64-binutils / ucrt64-binutils

Cross-compiled binutils (utilities like 'strip', 'as', 'ld') which understand Windows executables and DLLs. Equivalent to 'binutils' RPM

mingw32-gcc / mingw64-gcc / ucrt64-gcc

GNU compiler collection. Compilers for C and C++ which cross-compile to a Windows target. Equivalent to gcc RPM

mingw32-crt / mingw64-crt / ucrt64-crt

Base libraries for core MinGW runtime & development environment. Equivalent to 'glibc' RPM

mingw32-headers / mingw64-headers / ucrt64-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 MinGW 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 mingw-filesystem package. These RPM macros will be explained later on in these guidelines.

By default MinGW support will be built for both the Win32 and Win64 targets with the MSVCRT runtime. Building of the Win64 target with the UCRT64 runtime is not yet enabled by default.

When a package can only be built for a subset of these targets this can be indicated by setting one or more of these:

%global mingw_build_win32 0

Don’t build for the Win32 target with the MSVCRT runtime

%global mingw_build_win64 0

Don’t build for the Win64 target with the MSVCRT runtime

%global mingw_build_ucrt64 0

Don’t build for the Win64 target with the UCRT runtime

One source RPM, separate binary RPMs per-target

Each cross compiled MinGW package which builds binaries for a specific target should put the binaries for that target in a separate subpackage. So if a package mingw-foo or foo builds binaries for the Win32 and Win64 targets with the MSVCRT runtime, then the source RPM should provide two subpackages named mingw32-foo and mingw64-foo. If a package builds for the UCRT runtime, it will also have a ucrt64-foo subpackage.

This means that a spec file must contains %package and %files sections for all the targets.

When using the separate packaging approach, packages containing translations must use %mingw_find_lang instead of %find_lang.

When using the integrated packaging approach, packages containing translations must use +%find_lang followed by %mingw_find_lang.

This causes all translation filelists to be split in per-target filelists. For example: when a spec file contains something like this:

 %install
 <snip>
 %mingw_find_lang foo

then one file per mingw target will get created named mingw32-foo.lang, mingw64-foo.lang, and ucrt64-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
 <snip>
 %files -n ucrt64-foo -f ucrt64-foo.lang

Filesystem layout

Integration into the main root filesystem layout is as follows:

[root]
  |
  +- etc
  |   |
  |   +- rpm
  |       |
  |       +- macros.mingw
  |       +- macros.mingw32
  |       +- macros.mingw64
  |
  +- usr
      |
      +- bin   - Links to MinGW 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++
      |   +- x86_64-w64-mingw32ucrt-cpp
      |   +- x86_64-w64-mingw32ucrt-gcc
      |   +- x86_64-w64-mingw32ucrt-g++
      |   +- ... etc..
      |
      +- lib
      |   |
      |   +- rpm
      |       |
      |       +- mingw-find-debuginfo.sh - extract debug information from Win32 and Win64 binaries
      |       +- mingw-find-lang.sh - generates per-target file lists containing translations
      |       +- mingw-find-provides.sh - extra DLL names
      |       +- mingw-find-requires.sh - discover required DLL names
      |
      +- i686-w64-mingw32  - root of mingw toolchain and binaries for the Win32 target with MSVCRT runtime - see next diagram
      +- x86_64-w64-mingw32  - root of mingw toolchain and binaries for the Win64 target with MSVCRT runtime - see next diagram+`
      +- x86_64-w64-mingw32urt  - root of mingw toolchain and binaries for the Win64 target with UCRT runtime - see next diagram+`

The bulk of the packaged content is located under the respective MinGW root, one of /usr/i686-w64-mingw32, /usr/x86_64-w64-mingw32 and /usr/x86_64-w64-mingw32ucrt:

[mingw-root]
  |
  +- 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 MinGW binaries
      |
      +- mingw
          |
          +- bin     - cross-compiled MinGW binaries & runtime DLL parts
          +- etc     - configuration files
          +- include - include files for cross compiled MinGW libs
          +- lib     - cross-compiled static MinGW libraries & linktime DLL parts
          |   |
          |   +- pkgconfig  - pkg-config definitions for libraries
          |
          +- share
              |
              +- man

Filenames of the cross-compilers and binutils

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

The MinGW cross-compilers and binutils which generate i686 binaries for Windows with the MSVCRT runtime 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, i.e.,

 %{_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 with both MSVCRT and UCRT runtimes. The target with MSVCRT uses 'x86_64-w64-mingw32' as prefix instead of 'i686-w64-mingw32', while UCRT uses 'x86_64-w64-mingw32ucrt'.

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 with MSVCRT runtime is provided by the macro:

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

The Win64 target with MSVCRT runtime is provided by the macro:

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

The Win64 target with UCRT runtime is provided by the macro:

 %{ucrt64_sysroot}   %{_prefix}/x86_64-w64-mingw32ucrt/sys-root

Standard mingw RPM macros

The mingw-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 MinGW cross compiled packages submitted to Fedora.

Toolchain macros

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

Generic macros:

Macro

Available in mingw-filesystem

Explanation

mingw_cmake

>= 95

Call the 'cmake' binary for all the configured targets

mingw_cmake_kde4

>= 95

Call the 'cmake' binary for all the configured targets with KDE4 specific parameters set

mingw_configure

>= 95

Call the configure command for all the configured targets

mingw_make

>= 95

Call the 'make' command for all the configured targets

mingw_make_build

>= 113

Call 'make -O -j<nprocs> V=1 VERBOSE=1' command for all configured targets

mingw_make_install

>= 113

Call 'make install DESTDIR=$RPM_BUILD_ROOT 'INSTALL=/usr/bin/install -p' for all configured targets

mingw_meson

>= 104

Call the meson binary for all the configured targets

mingw_ninja

>= 104

Call the ninja binary for all the configured targets

mingw_objcopy

>= 95

cross compiler 'objcopy' binary (which supports both Win32 and Win64 binaries)

mingw_objdump

>= 95

cross compiler 'objdump' binary (which supports both Win32 and Win64 binaries)

mingw_qmake_qt4

>= 95

Call the Qt4 qmake binary for all configured targets (requires mingw32-qt-qmake and/or mingw64-qt-qmake to be installed)

mingw_qmake_qt5

>= 96

Call the Qt5 qmake binary for all configured targets (requires mingw32-qt5-qmake and/or mingw64-qt5-qmake to be installed)

mingw_strip

>= 95

cross compiler 'strip' binary (which supports both Win32 and Win64 binaries)

Win32 with MSVCRT runtime specific macros:

Macro

Available in mingw32-filesystem

Value

Explanation

mingw32_ar

>= 95

i686-w64-mingw32-ar

cross compiler 'ar' binary

mingw32_cc

>= 95

i686-w64-mingw32-gcc

cross compiler 'gcc' binary

mingw32_cflags

>= 95

-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions --param=ssp-buffer-size=4

Default compiler flags for C/C++ binaries

mingw32_cmake

>= 95

Call the 'cmake' binary for the Win32 target

mingw32_configure

>= 95

standard invocation for autotools 'configure' scripts

mingw32_cpp

>= 95

i686-w64-mingw32-gcc -E

cross compiler 'cpp' binary

mingw32_env

>= 95

Set the correct environment variables for the Win32 target

mingw32_host

>= 95

i686-w64-mingw32

Host platform for build

mingw32_meson

>= 104

Call the meson binary for the Win32 target

mingw32_ninja

>= 104

Call the ninja binary for the Win32 target

mingw32_objcopy

>= 95

i686-w64-mingw32-objcopy

cross compiler 'objcopy' binary

mingw32_objdump

>= 95

i686-w64-mingw32-objdump

cross compiler 'objdump' binary

mingw32_pkg_config

>= 95

i686-w64-mingw32-pkg-config

Call the pkg-config command for the Win32 target

mingw32_qmake_qt4

>= 95

mingw32-qmake-qt4

Call the Qt4 qmake command for the Win32 target

mingw32_qmake_qt5

>= 96

mingw32-qmake-qt5

Call the Qt5 qmake command for the Win32 target

mingw32_ranlib

>= 95

i686-w64-mingw32-ranlib

cross compiler 'ranlib' binary

mingw32_strip

>= 95

i686-w64-mingw32-strip

cross compiler 'strip' binary

mingw32_target

>= 95

i686-w64-mingw32

Target platform for build

Win64 with MSVCRT runtime specific macros:

Macro

Available in mingw64-filesystem

Value

Explanation

mingw64_ar

>= 95

x86_64-w64-mingw32-ar

cross compiler 'ar' binary

mingw64_cc

>= 95

x86_64-w64-mingw32-gcc

cross compiler 'gcc' binary

mingw64_cflags

>= 95

-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions --param=ssp-buffer-size=4

Default compiler flags for C/C++ binaries

mingw64_cmake

>= 95

Call the 'cmake' binary for the Win64 target

mingw64_configure

>= 95

standard invocation for autotools 'configure' scripts

mingw64_cpp

>= 95

x86_64-w64-mingw32-gcc -E

cross compiler 'cpp' binary

mingw64_env

>= 95

Set the correct environment variables for the Win64 target

mingw64_host

>= 95

x86_64-w64-mingw32

Host platform for build

mingw64_meson

>= 104

Call the meson binary for the Win64 target

mingw64_ninja

>= 104

Call the ninja binary for the Win64 target

mingw64_objcopy

>= 95

x86_64-w64-mingw32-objcopy

cross compiler 'objcopy' binary

mingw64_objdump

>= 95

x86_64-w64-mingw32-objdump

cross compiler 'objdump' binary

mingw64_pkg_config

>= 95

x86_64-w64-mingw32-pkg-config

Call the pkg-config command for the Win64 target

mingw64_qmake_qt4

>= 95

mingw64-qmake-qt4

Call the Qt4 qmake command for the Win64 target

mingw64_qmake_qt5

>= 96

mingw64-qmake-qt5

Call the Qt5 qmake command for the Win64 target

mingw64_ranlib

>= 95

x86_64-w64-mingw32-ranlib

cross compiler 'ranlib' binary

mingw64_strip

>= 95

x86_64-w64-mingw32-strip

cross compiler 'strip' binary

mingw64_target

>= 95

x86_64-w64-mingw32

Target platform for build

Win64 with UCRT runtime specific macros:

Macro

Available in ucrt64-filesystem

Value

Explanation

ucrt64_ar

>= 133

x86_64-w64-mingw32ucrt-ar

cross compiler 'ar' binary

ucrt64_cc

>= 133

x86_64-w64-mingw32ucrt-gcc

cross compiler 'gcc' binary

ucrt64_cflags

>= 133

-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions --param=ssp-buffer-size=4

Default compiler flags for C/C++ binaries

ucrt64_cmake

>= 133

Call the 'cmake' binary for the Win64 target

ucrt64_configure

>= 133

standard invocation for autotools 'configure' scripts

ucrt64_cpp

>= 133

x86_64-w64-mingw32ucrt-gcc -E

cross compiler 'cpp' binary

ucrt64_env

>= 133

Set the correct environment variables for the Win64 target

ucrt64_host

>= 133

x86_64-w64-mingw32

Host platform for build

ucrt64_meson

>= 104

Call the meson binary for the Win64 target

ucrt64_ninja

>= 104

Call the ninja binary for the Win64 target

ucrt64_objcopy

>= 133

x86_64-w64-mingw32ucrt-objcopy

cross compiler 'objcopy' binary

ucrt64_objdump

>= 133

x86_64-w64-mingw32ucrt-objdump

cross compiler 'objdump' binary

ucrt64_pkg_config

>= 133

x86_64-w64-mingw32ucrt-pkg-config

Call the pkg-config command for the Win64 target

ucrt64_qmake_qt4

>= 133

ucrt64-qmake-qt4

Call the Qt4 qmake command for the Win64 target

ucrt64_qmake_qt5

>= 133

ucrt64-qmake-qt5

Call the Qt5 qmake command for the Win64 target

ucrt64_ranlib

>= 133

x86_64-w64-mingw32ucrt-ranlib

cross compiler 'ranlib' binary

ucrt64_strip

>= 133

x86_64-w64-mingw32ucrt-strip

cross compiler 'strip' binary

ucrt64_target

>= 133

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 with MSVCRT runtime 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 with MSVCRT runtime 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.

For the Win64 with UCRT runtime target:

ucrt64_bindir

%{ucrt64_prefix}/bin

Location of Windows executables.

ucrt64_datadir

%{ucrt64_prefix}/share

Shared data used under Windows.

ucrt64_docdir

%{ucrt64_prefix}/share/doc

Documentation.

ucrt64_infodir

%{ucrt64_prefix}/share/info

Info files (see note below).

ucrt64_includedir

%{ucrt64_prefix}/include

Header files used when cross-compiling for Windows.

ucrt64_libdir

%{ucrt64_prefix}/lib

Windows libraries (see sections below).

ucrt64_libexecdir

%{ucrt64_prefix}/libexec

ucrt64_mandir

%{ucrt64_prefix}/share/man

Man pages (see note below).

ucrt64_prefix

%{ucrt64_sysroot}/mingw

Windows equivalent of %{_prefix}, required by MinGW.

ucrt64_sbindir

%{ucrt64_prefix}/sbin

ucrt64_sysconfdir

%{ucrt64_prefix}/etc

Configuration files used when running under Windows.

ucrt64_sysroot

%{_prefix}/x86_64-w64-mingw32ucrt/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 %mingw_configure, %mingw_cmake, %mingw_cmake_kde4, %mingw_qmake_qt4, %mingw_qmake_qt5 and %mingw_make

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

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:

 MINGW_BUILDDIR_SUFFIX=shared %mingw_configure --enable-shared
 MINGW_BUILDDIR_SUFFIX=static %mingw_configure --enable-static

Most packages used the command make %{?_smp_mflags} to build the package. In the MinGW cross compiler framework you have to use %mingw_make %{?_smp_mflags} to build the package for all configured targets. As with the %mingw_configure macro you can also use the MINGW_BUILDDIR_SUFFIX environment variable 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 %mingw_make install DESTDIR=$RPM_BUILD_ROOT to install the package for all configured targets. The environment variable MINGW_BUILDDIR_SUFFIX 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 start their spec files with this line:

 %{?mingw_package_header}

All binary packages should depend on mingw32-filesystem or mingw64-filesystem (depending on the files in the package).

All specfiles should BuildRequire at least one of these (depending on the targets for which you want to build):

 BuildRequires:  mingw32-filesystem
 BuildRequires:  mingw64-filesystem

and any other BuildRequires that they need.

Most mingw RPM macros can be assumed to exist in all non-EOL Fedora releases. If the package does, however, rely on a newly introduced macro, a versioned dependancy on the mingw-XX-filesystem packages should be used.

Build architecture

All packages should have:

 BuildArch: noarch

unless they contain Fedora native executables. Where using the separate packaging approach, the BuildArch tag must be present in the common spec file header. Where using the integrated packaging approach, the BuildArch tag must be present under the %package header for each MinGW sub-RPM that is present.

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

The foo.dll file is the main library, foo.dll.a is a stub linked to applications so they can find the library at runtime. All of these files are required in those locations in order to link successfully. The .dll may contain a version number although not always (e.g., foo-0.dll).

Do not use %{mingw32_bindir}/* or %{mingw32_libdir}/* in %files section

The %files section must list DLLs and import libraries 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.

Stripping

Libraries and executables should be stripped. This is done correctly and automatically if the spec file starts with this line:

 %{?mingw_package_header}

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:

 %{?mingw_package_header}
 [...]
 %{?mingw_debug_package}

The %{?mingw_debug_package} line must be placed after the %description tag. Otherwise spectool and other RPM tools may fail to function.

When using the integrated packaging approach the %install section must also contain a call to the %{mingw_debug_install_post} macro after any binary files have been installed to the virtual root:

 %install
 [...]
 %{?mingw_debug_install_post}

File listing

The MinGW packages are intended to allow developers to compile and test the Windows support of their applications. It is furthermore expected that developers will build Windows installers (MSIs) for their applications using the MinGW package content.

Thus the Fedora MinGW package file listing must include content needed to satisfy either build/test usage or the creation of Windows installers.

Executables (EXEs)

Most libraries also provide executables. These can include executables which can be used to test or showcase the library in question (for example gtk3-demo.exe in mingw-gtk3). Other examples are helper executables which are used by the library itself internally (for example gspawn-win32-helper.exe in mingw-glib2).

Executables which are required for proper functionality of the libraries must be packaged in the matching mingw32/mingw64 subpackage. Other optional executables targetted at end users should be packaged (for example certtool.exe in GNUTLS). Executables targetted at developers are discouraged, but may be packaged in optional (dependent) subpackages at a packager’s discretion.

Files which are already part of native packages

There are various types of files which are simply duplicates of equivalent files found in Fedora native packages. These files should not be packaged in the MinGW package. The following files don’t need to be packaged in the MinGW package when their native counterpart already contains them:

  • Man pages (%{mingw32_mandir} / %{mingw64_mandir} / %{ucrt64_mandir})

  • Info files (%{mingw32_infodir} / %{mingw64_infodir} / %{ucrt64_infodir})

  • Generic documentation (%{mingw32_docdir} / %{mingw64_docdir} / %{ucrt64_docdir})

  • Autoconf files (%{mingw32_datadir}/aclocal / %{mingw64_datadir}/aclocal / %{ucrt64_datadir}/aclocal)

  • gtk-doc files (%{mingw32_datadir}/gtk-doc / %{mingw64_datadir}/gtk-doc / %{ucrt64_datadir}/gtk-doc)

Note, generic Documentation aimed at end users, as opposed to developers, should be included where it is likely that application developers will want to bundle it with their Windows installers.

Converting between separate and integrated packaging

In general it it possible to convert in either direction between the separate and integrated packaging approaches. Both approaches result in the exact same binary RPMs for MinGW content, only differing in their source RPM specfile.

To convert from separate to integrated packaging

  • Ensure the existing native software package has either the same (or newer) version number as the existing MinGW package.

  • Add MinGW support to the existing native package spec file

  • If both the native and existing MinGW packages were at the same version, ensure the release number of the native package is newer than any previous build of the MinGW package.

  • Build the new native package with MinGW support

  • Retire the separate MinGW package

To convert from integrated to separate packaging

  • Go through the new package review process for the separate MinGW package, ensuring it is the same version number as the existing integrated package

  • Import the separate MinGW package to dist-git but don’t build it.

  • Drop MinGW support from the existing native package spec file

  • Build the native package without MinGW support

  • Ensure the separate MinGW package has a newer release number than any existing MinGW binary sub-RPMs built from the native package

  • Build the separate MinGW package

In both cases the upgrade experience should be transparent to users installing and updating Fedora deployments.

It is recommended that such conversions only be performed in Rawhide. If there is need to do a conversion from integrated to separate packaging in a stable release stream, a single Bohdi update must include both the native and mingw package builds.

Disabling MinGW packages

When using the integrated packaging approach it MUST be possible to disable the build of MinGW sub-RPMs, and the build MUST be disabled by default except for the Fedora distribution target. This ensures that the native package can still be built in derivative distros, such as RHEL, where the MinGW toolchains not included. This is achieved by including a conditional near the top of the specfile:

%if 0%{?fedora}
%bcond_without mingw
%else
%bcond_with mingw
%endif

and then wrapping all MinGW related %package / +%files definitions and relevant %build or %install commands in a conditional check:

%if %{with mingw}
%package -n mingw32-example
Summary: %{summary}
BuildArch: noarch
[...]
%endif

Example Integrated Package Specfile

%if 0%{?fedora}
%bcond_without mingw
%else
%bcond_with mingw
%endif

Name: example
Version: 1.0.0
Release: 1%{?dist}
Summary: Example library

License: LGPL-2.1-or-later
URL: https://fedoraproject.org
Source: https://fedoraproject.org/example-%{version}.tar.bz2

BuildRequires: gcc
BuildRequires: binutils
BuildRequires: gettext
BuildRequires: zlib

%if %{with mingw}
BuildRequires: mingw32-filesystem
BuildRequires: mingw32-gcc
BuildRequires: mingw32-binutils
BuildRequires: mingw32-gettext
BuildRequires: mingw32-win-iconv
BuildRequires: mingw32-zlib

BuildRequires: mingw64-filesystem
BuildRequires: mingw64-gcc
BuildRequires: mingw64-binutils
BuildRequires: mingw64-gettext
BuildRequires: mingw64-win-iconv
BuildRequires: mingw64-zlib
%endif

%description
Example library.

%package devel
Summary: Example library development package
...

%description devel
Example library development headers and library.

%if %{with mingw}
# If a package maintainer wishes to bundle static libraries then they
# can be placed in -static subpackages. Otherwise, the -static subpackages
# can be dropped

# Win32
%package -n mingw32-example
Summary: MinGW compiled example library for the Win32 target
BuildArch: noarch

%description -n mingw32-example
MinGW compiled example library for the Win32 target.

%package -n mingw32-example-static
Summary: Static version of the MinGW Win32 compiled example library
Requires: mingw32-example = %{version}-%{release}

%description -n mingw32-example-static
Static version of the MinGW Win32 compiled example library.

# Win64
%package -n mingw64-example
Summary: MinGW compiled example library for the Win64 target

%description -n mingw64-example
MinGW compiled example library for the Win64 target.
BuildArch: noarch

%package -n mingw64-example-static
Summary: Static version of the MinGW Win64 compiled example library
Requires: mingw64-example = %{version}-%{release}

%description -n mingw64-example-static
Static version of the MinGW Win64 compiled example library.

%{?mingw_debug_package}
%endif


%prep
%autosetup -p1 -n example-%{version}


%build

%define _configure ../../configure

mkdir -p build/native
cd build/native
%configure ...
%make_build
cd ../..

%if %{with mingw}
%mingw_configure --enable-static --enable-shared --enable-foo
%mingw_make_build
%endif

%install
cd build/native
%make_install

%find_lang example
cd ../..

%if %{with mingw}
%mingw_make_install

%mingw_find_lang example
%endif

%files
%{_libdir}/libexample.so.*

%files devel
%{_libdir}/libexample.so
%{_libdir}/pkgconfig/example.pc
%{_includedir}/example/

# Static subpackages are optional (as mentioned earlier)

%if %{with mingw}
# Win32
%files -n mingw32-example -f mingw32-example.lang
%{mingw32_bindir}/libexample-0.dll
%{mingw32_includedir}/example/
%{mingw32_libdir}/libexample.dll.a
%{mingw32_libdir}/pkgconfig/example.pc

%files -n mingw32-example-static
%{mingw32_libdir}/libexample.a

# Win64
%files -n mingw64-example -f mingw64-example.lang
%{mingw64_bindir}/libexample-0.dll
%{mingw64_includedir}/example/
%{mingw64_libdir}/libexample.dll.a
%{mingw64_libdir}/pkgconfig/example.pc

%files -n mingw64-example-static
%{mingw64_libdir}/libexample-0.a
%endif

%changelog
* Sun Apr 15 2012 Erik van Pienbroek <epienbro@fedoraproject.org> - 1.0.0-1
- Initial release

Example Separate Package Specfile

The separate package specfile essentially extracts all the content within the %{with mingw} conditionals from the previous example, and puts it into a standalone specfile.

%{?mingw_package_header}

Name: mingw-example
Version: 1.0.0
Release: 1%{?dist}
Summary: MinGW compiled example library

License: LGPL-2.1-or-later
URL: https://fedoraproject.org
Source: https://fedoraproject.org/example-%{version}.tar.bz2

BuildArch: noarch

BuildRequires: mingw32-filesystem
BuildRequires: mingw32-gcc
BuildRequires: mingw32-binutils
BuildRequires: mingw32-gettext
BuildRequires: mingw32-win-iconv
BuildRequires: mingw32-zlib

BuildRequires: mingw64-filesystem
BuildRequires: mingw64-gcc
BuildRequires: mingw64-binutils
BuildRequires: mingw64-gettext
BuildRequires: mingw64-win-iconv
BuildRequires: mingw64-zlib


%description
MinGW compiled example library.


# If a package maintainer wishes to bundle static libraries then they
# can be placed in -static subpackages. Otherwise, the -static subpackages
# can be dropped

# Win32
%package -n mingw32-example
Summary: MinGW compiled example library for the Win32 target

%description -n mingw32-example
MinGW compiled example library for the Win32 target.

%package -n mingw32-example-static
Summary: Static version of the MinGW Win32 compiled example library
Requires: mingw32-example = %{version}-%{release}

%description -n mingw32-example-static
Static version of the MinGW Win32 compiled example library.

# Win64
%package -n mingw64-example
Summary: MinGW compiled example library for the Win64 target

%description -n mingw64-example
MinGW compiled example library for the Win64 target.

%package -n mingw64-example-static
Summary: Static version of the MinGW Win64 compiled example library
Requires: mingw64-example = %{version}-%{release}

%description -n mingw64-example-static
Static version of the MinGW Win64 compiled example library.


%{?mingw_debug_package}


%prep
%autosetup -p1 -n example-%{version}


%build
%mingw_configure --enable-static --enable-shared --enable-foo
%mingw_make_build


%install
%mingw_make_install

# Libtool files don't need to be bundled
find %{buildroot} -name "*.la" -delete

%mingw_find_lang example


# Note: there should be no %%files section for the main package!

# Static subpackages are optional (as mentioned earlier)

# Win32
%files -n mingw32-example -f mingw32-example.lang
%{mingw32_bindir}/libexample-0.dll
%{mingw32_includedir}/example/
%{mingw32_libdir}/libexample.dll.a
%{mingw32_libdir}/pkgconfig/example.pc

%files -n mingw32-example-static
%{mingw32_libdir}/libexample.a

# Win64
%files -n mingw64-example -f mingw64-example.lang
%{mingw64_bindir}/libexample-0.dll
%{mingw64_includedir}/example/
%{mingw64_libdir}/libexample.dll.a
%{mingw64_libdir}/pkgconfig/example.pc

%files -n mingw64-example-static
%{mingw64_libdir}/libexample-0.a


%changelog
* Sun Apr 15 2012 Erik van Pienbroek <epienbro@fedoraproject.org> - 1.0.0-1
- Initial release