skeeto / w64devkit

Portable C and C++ Development Kit for x64 (and x86) Windows
The Unlicense
2.66k stars 185 forks source link

Portable C and C++ Development Kit for x64 Windows

w64devkit is a Dockerfile that builds from source a small, portable development suite for creating C and C++ applications on and for x64 Windows. See "Releases" for pre-built, ready-to-use kits.

Included tools:

The toolchain includes pthreads, C++11 threads, and OpenMP. All included runtime components are static. Docker/Podman is not required to use the development kit. It's merely a reliable, clean environment for building the kit itself.

Build

First build the image, then run it to produce a distribution .zip file:

docker build -t w64devkit .
docker run --rm w64devkit >w64devkit.zip

This takes about half an hour on modern systems. You will need an internet connection during the first few minutes of the build. Note: Do not use PowerShell because it lacks file redirection.

Usage

The final .zip file contains tools in a typical unix-like configuration. Unzip the contents anywhere. Inside is w64devkit.exe, which launches a console window with the environment configured and ready to go. It is the easiest way to enter the development environment, and requires no system changes. It also sets two extra environment variables: W64DEVKIT_HOME to the installation root and W64DEVKIT to the version.

Alternatively, add the bin/ directory to your path. For example, inside a cmd.exe console or batch script:

set PATH=c:\path\to\w64devkit\bin;%PATH%

Then to start an interactive unix shell:

sh -l

Main features

Optimized for size

Runtime components are optimized for size, leading to smaller application executables. Unique to w64devkit, libmemory.a is a library of memset, memcpy, memmove, memcmp, and strlen implemented as x86 string instructions. When not linking a CRT, linking -lmemory provides tiny definitions, particularly when GCC requires them.

Also unique to w64devkit, libchkstk.a has a leaner, faster definition of ___chkstk_ms than GCC (-lgcc), as well as __chkstk, sometimes needed when linking MSVC artifacts. Both are in the public domain and so, unlike default implementations, do not involve complex licensing. When required in a -nostdlib build, link -lchkstk.

Unlike traditional toolchains, import tables are not populated with junk ordinal hints. If an explicit hint is not provided (i.e. via a DEF file), then the hint is zeroed: "no data." Eliminating this random data makes binaries more compressible and theoretically faster loading. See also: peports.

Fortran support

Only C and C++ are included by default, but w64devkit also has full support for Fortran. To build a Fortran compiler, add fortran to the --enable-languages lines in the Dockerfile.

Recommended downloadable, offline documentation

With a few exceptions, such as Vim's built-in documentation (:help), w64devkit does not include documentation. However, you need not forgo offline documentation alongside your offline development tools. This is a list of recommended, no-cost, downloadable documentation complementing w64devkit's capabilities. In rough order of importance:

Library installation

Except for the standard libraries and Win32 import libraries, w64devkit does not include libraries, but you can install additional libraries such that the toolchain can find them naturally. There are three options:

  1. Install it under the sysroot at w64devkit/$ARCH/. The easiest option, but will require re-installation after upgrading w64devkit. If it defines .pc files, the pkg-config command will automatically find and use them.

  2. Append its installation directory to your CPATH and LIBRARY_PATH environment variables. Use ; to delimit directories. You would likely do this in your .profile.

  3. If it exists, append its pkgconfig directory to the PKG_CONFIG_PATH environment variable, then use the pkg-config command as usual. Use ; to delimit directories

Both (1) and (3) are designed to work correctly even if w64devkit or the libraries have paths containing spaces.

Unique command-line programs

Cppcheck tips

Use --library=windows for programs calling the Win32 API directly, which adds additional checks. In general, the following configuration is a good default for programs developed using w64devkit:

$ cppcheck --quiet -j$(nproc) --library=windows \
           --suppress=uninitvar --enable=portability,performance .

A "strict" check that is more thorough, but more false positives:

$ cppcheck --quiet -j$(nproc) --library=windows \
      --enable=portability,performance,style \
      --suppress=uninitvar --suppress=unusedStructMember \
      --suppress=constVariable --suppress=shadowVariable \
      --suppress=variableScope --suppress=constParameter \
      --suppress=shadowArgument --suppress=knownConditionTrueFalse .

Notes

$HOME can be set through the adjacent w64devkit.ini configuration, and may even be relative to the w64devkit/ directory. This is useful for encapsulating the entire development environment, with home directory, on removable, even read-only, media. Use a .profile in the home directory to configure the environment further.

I'd love to include Git, but unfortunately Git's build system doesn't quite support cross-compilation. A decent alternative would be Quilt, but it's written in Bash and Perl.

Neither Address Sanitizer (ASan) nor Thread Sanitizer (TSan) has been ported to Mingw-w64 (also), but Undefined Behavior Sanitizer (UBSan) works perfectly under GDB. With both -fsanitize=undefined and -fsanitize-trap, GDB will break precisely on undefined behavior, and it does not require linking with libsanitizer.

Since the build environment is so stable and predicable, it would be great for the .zip to be reproducible, i.e. builds by different people are bit-for-bit identical. There are multiple reasons why this is not currently the case, the least of which are timestamps in the .zip file.

Licenses

When distributing binaries built using w64devkit, your .exe will include parts of this distribution. For the GCC runtime, including OpenMP, you're covered by the GCC Runtime Library Exception so you do not need to do anything. However the Mingw-w64 runtime has the usual software license headaches and you may need to comply with various BSD-style licenses depending on the functionality used by your program: MinGW-w64 runtime licensing and winpthreads license. To make this easy, w64devkit includes the concatenated set of all licenses in the file COPYING.MinGW-w64-runtime.txt, which should be distributed with your binaries.