(Free) Software Building and Packaging For Windows

Creating new packages


If you haven’t already, build the packages that already exist. This will ensure you have everything needed and working; you can check the corresponding documentation.

Find a source to base your package on and copy it

Check whether a Slackware Linux build script already exists

There is a large number of existing Slackware build scripts which are split in two sets:

  • slackware holds the packages scripts of the Slackware Linux distribution;
  • holds the scripts from the community repository.

If you find an existing build script in either of these directory, you can re-use it directly.

Or, start from a similar package

Create a new directory for your package inside and copy an existing build script for that build system:

  • for autotools-based systems, copy slackware/n/libgcrypt.SlackBuild and slackware/n/libgcrypt/
  • for cmake-based systems, copy and

CMake-based build systems are much less friendly for cross-compilation and especially to cross-compilation to Windows and require a few kludges that can be difficult to avoid.

You will probably have to add package-specific bits. This is why having references in the form of native linux build scripts can help a lot.

Add a '' file (builder metadata)

  • Create a file in the package directory. You can start with the following template and customize it:
(* The code below defines a new  builder variable: libgcrypt.
 * It is the result of a call to the "add" function with 6 arguments:
 * - (name, variant): package name and variant which are defined automatically
 *   according to the path of the '' file being used
 * - ~dir: the directory containing the package; also defined automatically
 * - ~dependencies: the list of dependencies, separated by ';' and enclosed
 *   between '[' and ']'.
 * - ~version: the package version as a string
 * - ~build: the package build number, as an integer
 * - ~sources: the list of sources;
 *     - each Tarball entry is made of the filename followed by the file's SHA1
 *     - each Patch entry only contains the filename
 *     - Git entries are also possible (explained elsewhere)
 *   The strings can contain ${PACKAGE} and ${VERSION} to not repeat values.

let libgcrypt = add (name, variant)
  ~dependencies:[ libgpg_error ] (* set this *)
  ~version:"1.6.3" (* set this *) 
  ~build:1 (* increment that after each new (public) build *)
    (* set the extension and sha1sum for the current tarball *)
    Tarball ("${PACKAGE}-${VERSION}.tar.bz2", "9456e7b64db9df8360a1407a38c8c958da80bbf1");

Note the trailing in: the OCaml construct is let … in and the syntax requires that in after each new variable creation in this context.

Do the actual porting (mostly search-replace)

  • Replace all occurrences of usr with ${PREFIX} (verbatim: don’t expand the variable) in the .SlackBuild file. This means /usr/ becomes /${PREFIX}/.
  • Delete the blocks of code that set ARCH, NUMJOBS, SLKCFLAGS and LIBDIRSUFFIX; they look similar to
# Automatically determine the architecture we're building on:
if [ -z "$ARCH" ]; then
if [ "$ARCH" = "i486" ]; then
  SLKCFLAGS="-O2 -march=i486 -mtune=i686"
  • Replace the source tarball extraction:
tar xvf $CWD/$PKGNAM-$VERSION.tar.bz2 || exit 1
# becomes
yyextract "${CWD}" "${PKGNAM}-${VERSION}"
  • Use $(yyflags 'c'), $(yyflags 'cxx'), $(yyflags 'ld'); look for $SLKCFLAGS to locate places which need changes
  • Add –host=${HOST_TRIPLET} to the configure invocation. If this involves adding a newline in a configure call, don’t forget to escape that newline with \.
  • Delete the strip invocation; it looks like:
find $PKG | xargs file | grep -e "executable" -e "shared object" | grep ELF \
  | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null || true
  • Near the bottom of the script, replace:
mkdir -p $PKG/install
cat $CWD/slack-desc > $PKG/install/slack-desc

cd $PKG
/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.${PKGTYPE:-tgz}


yymakepkg_split \
  --pkg "${PKG}" \
  --cwd "${CWD}" \
  --version "${VERSION}" --build "${BUILD}" \
  --packager "Adrien Nader" --packager-mail "" \
  --host "${HOST_TRIPLET}" \
  "${PKGNAM}" # ${PRGNAM} in some scripts instead; sometimes also no variable already exists
  • If there are many source files (> 5000), replace the find + chmod commands which are used to reset file permissions to sane default with:
chmod -R u+w,go+r-w,a-s .

Download the sources

The source tarball needs to be in the same directory as your build script.

Test your package

You can now build your package like any other package, i.e. with a command similar to:

make WINDOWS=your_package WINDOWS_EXTRAS=relative/path/to/your_package/

The WINDOWS_EXTRAS variable tells the system to read this file in addition to the ones it already knows about. You can have several files listed there, separated with ','. For other series, simply replace WINDOWS with either NATIVE_TOOLCHAIN or CROSS_TOOLCHAIN.

This will build your package for windows for both 32b and 64b. The logs will be stored inside @@VERSION@@/logs/windows_??/your_package.

Remember you can build for only one architecture . This will save CPU time and let you iterate faster. The syntax is:

make WINDOWS_64=your_package WINDOWS_EXTRAS=relative/path/to/your/ # note the additional "_64".

devshell feature

While developing you might want to have a shell. To do so, simply append :devshell to your target:

make WINDOWS_64=your_package:devshell

It will give you a shell configured just like the shell used to run the SlackBuild except that it will try to use your own shell and not necessarily bash. You can then play the build script by hand to see what is going wrong.

Add your package to the list

Specifying the WINDOWS_EXTRA variable each time is useful for testing but not for publishing. For that, the should be added to the list in win-builds/build/ Simply add a line similar to:

#use "slackware/n/libgcrypt/"

Order matters and this line has to be below the ones for the dependencies listed in this file.

If you run make from the win-builds directory, the system will not build any package but will still run the builder after having checked the values that have been defined. It is a quick way to check the package descriptions are valid.