#!/bin/bash
# Compiling SWI-Prolog using MinGW
# --------------------------------
#
# This file provides an overview for building SWI-Prolog using MinGW, in
# particular using the cross-compilers that are distributed with most
# todays Linux distributions. This work is mostly done by Roberto
# Bagnara (initial port of the Prolog kernel), Abramo Bagnara and Keri
# Harris.
#
# USAGE
#
# The remainder of the file is an executable specification of the
# installation process. To use it, copy this file to a directory above
# the location where you want to build all components. I.e., typically
# the directory above this one and source it into the bash shell:
#
# % . README.mingw win32|win64
#
# Next, execute the functions for the parts of the process you want. The
# function build_all does everything.
#
# This script has been tested for cross-compilation on a Linux system
# with the mingw cross-compiler and wine installed.
#
# PREREQUISITES
#
# The open source libraries on which SWI-Prolog depends are downloaded
# and built using the functions download_prerequisites() and
# build_prerequisites(). In addition, the following need to be
# installed:
#
# - The Oracle Java SDK for building JPL
# - jdk-<version>-windows-i586.exe into
# /C/Program Files (x86)/... (default on 64-bit Windows)
# - jdk-<version>-windows-x64.exe into
# /C/Program Files/... (default on 64-bit Windows)
# - NSIS installer generator for generating the installer.
# - nsis-<version>-setup.exe into /C/Program Files (x86)/...
# - MSVC tools (lib.exe) for creating MSVC compatible .lib files
# - Install Microsoft Visual C++ Express on your Windows partition
# - Copy "c:/Program Files (x86)/Microsoft Visual Studio 9" into
# your ".wine/drive_c/Program Files (x86)"
# - Use "wine regedit" to add ...\VC\bin and ...\Common7\IDE to
# your wine PATH.
# - Run "wine lib.exe" to see whether it works
# (See
# http://issaris.blogspot.nl/2008/04/creating-dlls-using-visual-c-8-on.html)
#
# UBUNTU PACKAGES
#
# Tested on Ubuntu 17.10 on AMD64.
#
# - apt-get install wine-stable wine-binfmt
# - apt-get install mingw-w64
TARGETHOST="$1"
MAKE="make -j 4"
case "$TARGETHOST" in
win64) BITS=64
;;
win32) BITS=32
;;
*) echo "Please run as . $BASH_SOURCE 'win32|win64'"
return
esac
PS1=W$BITS' (\W\[\e[36m\]$(__git_ps1 "; %s")\[\e[0m\]) \!_> '
export BUILDARCH=$TARGETHOST
# Versions of prerequisite packages. Used to download the right release
# file.
GMP_VERSION=6.1.1
PTHREADS_VERSION=2-9-1-release
LIBDWARF_VERSION=20120410
SSL_VERSION=1.1.0f
JPEG_VERSION=9b
ZLIB_VERSION=1.2.8
ARCHIVE_VERSION=3.2.1
UUID_VERSION=1.6.2
BDB_VERSION=6.1.26
PCRE_VERSION=8.40
PLDIR=pl-devel
# installation prefix. This path should not have spaces in one of the
# directory names.
install="${install-$HOME/mingw$BITS}"
src="$(pwd)"
PATH=$install/swipl/bin:$PATH
# Check whether we are cross-compiling or running under MSYS in Windows.
# Note that the MSYS version has not yet been tested.
case "$(uname)" in
MINGW*)
CROSSCOMPILING=no
export PATH=$install/bin:$PATH
DRIVEC="/C"
MINGWGCC=gcc
;;
*)
export CROSSCOMPILING=yes
export WINEDEBUG=-all
DRIVEC="$HOME/.wine/drive_c"
export WINEPATH="$(winepath -w $install/bin)"
;;
esac
if [ "$CROSSCOMPILING" = yes ]; then
if [ -z "$CROSS" ]; then
case $TARGETHOST in
win64)
CROSS=x86_64-w64-mingw32
;;
win32)
if [ -r /usr/bin/i686-w64-mingw32-gcc ]; then
CROSS=i686-w64-mingw32
else
CROSS=i586-mingw32msvc
fi
;;
esac
fi
MINGWGCC=$CROSS-gcc
export WINDRES=$CROSS-windres
fi
# See whether pthread is built-in
if [ -r "$($MINGWGCC -print-file-name=libwinpthread-1.dll)" ]; then
PTHREADS_VERSION=
fi
# Java configuration
# Note that Win64 javac and javadoc crash under Wine (1.5.6). But, we
# can use the native Linux versions
if [ -z "$JAVAROOT" ]; then
case $TARGETHOST in
win64)
JAVAROOT="$DRIVEC/Program Files/Java"
if [ "$CROSSCOMPILING" = yes ]; then
export JAVAC=javac
export JAVADOC=javadoc
fi
;;
win32)
JAVAROOT="$DRIVEC/Program Files (x86)/Java"
;;
esac
fi
JAVAPREFIX="$(echo "$JAVAROOT"/jdk*)/bin"
export JAVAPREFIX
# Set some variables to find the Windows libraries and include files
# export COFLAGS=-g
export CIFLAGS="-I$install/include"
export CPPFLAGS=-I$install/include
export LDFLAGS="-L$install/lib"
export PKGLDFLAGS=-I$install/lib
################################################################
# end of gathering info about the environment; the remainder are
# functions that perform steps of the build process
################################################################
################
# Handy for running autoconf from a directory
config()
{ if [ -r ./configure ]; then
./configure --host=$CROSS --prefix=$install
elif [ -r ../src/configure ]; then
./configure --host=$CROSS --prefix=$install
fi
}
################
# Create target directories
make_mingw_dirs()
{ mkdir -p $install/include
mkdir -p $install/lib
mkdir -p $install/bin
}
###########################
# Download and install the GMP library.
download_gmp()
{ GMP_FILE=gmp-$GMP_VERSION.tar.bz2
[ -f $GMP_FILE ] || \
wget ftp://ftp.gmplib.org/pub/gmp-$GMP_VERSION/$GMP_FILE
tar jxf $GMP_FILE
}
build_gmp()
{ ( cd gmp-$GMP_VERSION
./configure --host=$CROSS --prefix=$install \
--enable-shared --disable-static
make
make install
)
}
###########################
# Download and install the Pthreads-win32 library. Only if PTHREADS_VERSION
# is set. Else we assume a recent MinGW64, which ships with
# libwinpthread
download_pthread_win32()
{ if [ ! -z "$PTHREADS_VERSION" ]; then
PTHREADS_FILE=pthreads-w32-$PTHREADS_VERSION.tar.gz
cd $src
[ -f $PTHREADS_FILE ] || \
wget ftp://sourceware.org/pub/pthreads-win32/$PTHREADS_FILE
tar xzf $PTHREADS_FILE
fi
}
build_pthread_win32()
{ if [ -d pthreads-w32-$PTHREADS_VERSION ]; then
( cd pthreads-w32-$PTHREADS_VERSION
make -f GNUmakefile CROSS=$CROSS- \
LFLAGS="-lwsock32 -Wl,--out-implib=libpthreadGC2.dll.a" GC
cp pthread.h semaphore.h sched.h $install/include/
cp pthreadGC2.dll $install/bin/
cp libpthreadGC2.dll.a $install/lib/
)
fi
}
###########################
# Download and install the DWARF debugging library.
download_libdwarf()
{ LIBDWARF_FILE=libdwarf-$LIBDWARF_VERSION.tar.gz
[ -f $LIBDWARF_FILE ] || \
wget http://www.prevanders.net/$LIBDWARF_FILE
tar xzf $LIBDWARF_FILE
}
build_libdwarf()
{ ( cd dwarf-$LIBDWARF_VERSION/libdwarf
./configure --host=$CROSS --enable-shared
sed -i -e "s|libdwarf.so|libdwarf.dll|" \
-e "s|\$(CFLAGS) -shared|\$(LDFLAGS) -shared|" \
-e "/_elf_/d" -e "/[ \t]pro_/d" -e "/dwarf_addr_finder/d" Makefile
make PRELIBS="-Wl,--out-implib=libdwarf.dll.a"
mkdir -p $install/bin
cp libdwarf.dll $install/bin/
mkdir -p $install/lib
cp libdwarf.a libdwarf.dll.a $install/lib/
mkdir -p $install/include
cp dwarf.h libdwarf.h $install/include
)
}
###########################
# Download and install ssl
download_ssl()
{ SSL_FILE=openssl-$SSL_VERSION.tar.gz
[ -f $SSL_FILE ] || wget http://www.openssl.org/source/$SSL_FILE
tar xzf $SSL_FILE
}
build_ssl()
{ ( cd openssl-$SSL_VERSION
export CC=$MINGWGCC
case $CROSS in
i?86*) MINGW=mingw
;;
x86_64*) MINGW=mingw64
;;
*) echo "SSL: Unknown CROSS: $CROSS"
exit 1
;;
esac;
./Configure $MINGW --prefix=$install shared threads
make depend
make
make install_sw
)
}
###########################
# Download and install BerkeleyDB
# http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/overview/index.html
download_libdb()
{ BDB_FILE=db-$BDB_VERSION.tar.gz
[ -f $BDB_FILE ] || \
curl http://download.oracle.com/berkeley-db/$BDB_FILE > $BDB_FILE
tar zxvf $BDB_FILE
}
build_libdb()
{ ( cd db-$BDB_VERSION/build_unix
sed -i -e "s:WinIoCtl.h:winioctl.h:" ../src/dbinc/win_db.h
../dist/configure --enable-mingw --host=$CROSS --prefix=$install \
--enable-shared --disable-static
make library_build
make install_lib install_include
( cd $install/lib
[ -f libdb.dll.a ] || ln -s libdb-*.dll.a libdb.dll.a
[ -f libdb.la ] || ln -s libdb-*.la libdb.la
)
)
}
###########################
# Download and install jpeg
download_jpeg()
{ JPEG_FILE=jpegsrc.v$JPEG_VERSION.tar.gz
[ -f $JPEG_FILE ] || wget http://www.ijg.org/files/$JPEG_FILE
tar xzf $JPEG_FILE
}
build_jpeg()
{ ( cd jpeg-$JPEG_VERSION
./configure --host=$CROSS --prefix=$install --enable-shared
make
make install
)
}
###########################
# Download and install libXpm
download_libxpm()
{ if [ -d libXpm ]; then
(cd libXpm && git pull)
else
git clone https://github.com/SWI-Prolog/libXpm.git
fi
}
build_libxpm()
{ ( cd libXpm/lib
autoconf
./configure --host=$CROSS --prefix=$install
make -f Makefile.mingw
make -f Makefile.mingw install
)
}
###########################
# Download and install zlib
download_zlib()
{ ZLIB_FILE=zlib-$ZLIB_VERSION.tar.gz
[ -f $ZLIB_FILE ] || wget http://zlib.net/$ZLIB_FILE
tar xzf $ZLIB_FILE
}
build_zlib()
{ ( cd zlib-$ZLIB_VERSION
make -f win32/Makefile.gcc PREFIX=$CROSS- BINARY_PATH=$install/bin INCLUDE_PATH=$install/include LIBRARY_PATH=$install/lib SHARED_MODE=1 IMPLIB=libz.dll.a install
)
}
#################################
# Download and install libarchive
download_libarchive()
{ ARCHIVE_FILE=libarchive-$ARCHIVE_VERSION.tar.gz
[ -f $ARCHIVE_FILE ] || \
wget http://www.libarchive.org/downloads/$ARCHIVE_FILE
tar xzf $ARCHIVE_FILE
}
# lt_cv_deplibs_check_method=pass_all works around a bug in libtool
# causing: "linker path does not have real file for library" error on MinGW
# See http://lists.cairographics.org/archives/cairo/2009-July/017686.html
build_libarchive()
{ ( cd libarchive-$ARCHIVE_VERSION
export CFLAGS="-I$install/include"
export LDFLAGS="-L$install/lib"
export lt_cv_deplibs_check_method='pass_all'
export ac_cv_func__localtime64_s='no'
export ac_cv_func__ctime64_s='no'
./configure --host=$CROSS --prefix=$install --with-pic \
--without-iconv --without-openssl --without-nettle --without-xml2 \
--without-expat --without-libregex --without-bz2lib \
--without-lzmadec --without-lzma --without-lzo2
make
make install
)
}
#################################
# Download and install libpcre
download_libpcre()
{ PCRE_FILE=pcre-$PCRE_VERSION.tar.gz
[ -f $PCRE_FILE ] || \
wget https://ftp.pcre.org/pub/pcre/$PCRE_FILE
tar xzf $PCRE_FILE
}
build_libpcre()
{ ( cd pcre-$PCRE_VERSION
./configure --host=$CROSS --prefix=$install \
--disable-static --disable-cpp --enable-utf8 --enable-unicode-properties
make pcre.dll
make install
)
}
#################################
# Download and install libuuid
download_libuuid()
{ UUID_FILE=uuid-$UUID_VERSION.tar.gz
[ -f $UUID_FILE ] || \
curl ftp://ftp.ossp.org/pkg/lib/uuid/$UUID_FILE > $UUID_FILE
tar zxvf $UUID_FILE
}
build_libuuid()
{ ( cd uuid-$UUID_VERSION
./configure --host=$CROSS --prefix=$install
make
make install
)
}
###########################
# Do the whole lot for all prerequisites
clean_prerequisites()
{ ( cd gmp-$GMP_VERSION && make distclean )
( cd openssl-$SSL_VERSION && make distclean )
( cd jpeg-$JPEG_VERSION && make distclean )
( cd libXpm/lib && make distclean )
( cd zlib-$ZLIB_VERSION && make distclean )
( cd libarchive-$ARCHIVE_VERSION && make distclean )
( cd uuid-$UUID_VERSION && make distclean )
if [ -d pthreads-w32-$PTHREADS_VERSION ]; then
( cd pthreads-w32-$PTHREADS_VERSION && make distclean )
fi
}
download_prerequisites()
{ download_gmp
download_pthread_win32
download_libdwarf
download_ssl
download_jpeg
download_libxpm
download_zlib
download_libarchive
download_libuuid
download_libdb
download_libpcre
}
build_prerequisites()
{ build_gmp
build_pthread_win32
build_libdwarf
build_ssl
build_jpeg
build_libxpm
build_zlib
build_libarchive
build_libuuid
build_libdb
build_libpcre
}
###########################
# Download and unpack a SWI-Prolog source distribution.
enter_topdir()
{ if [ ! -r build.templ ]; then
if [ -r $PLDIR/build.templ ]; then
cd $PLDIR
else
echo "ERROR: Cannot find SWI-Prolog sources"
return 1
fi
fi
}
download_swipl()
{ if [ ! -d $PLDIR -a ! -r build.templ ]; then
git clone git://www.swi-prolog.org/home/pl/git/$PLDIR.git
fi
( enter_topdir
git pull
./prepare --yes
)
}
build_swipl_core()
{ export CIFLAGS="-I$install/include"
export LDFLAGS="-L$install/lib"
( enter_topdir
wineserver || true
./configure --host=$CROSS --prefix=$install \
--disable-readline --disable-libdirversion \
--enable-shared --disable-static
$MAKE 2>&1 | tee make.out
if [ "${PIPESTATUS[0]}" != 0 ]; then exit 1; fi
make install 2>&1 | tee make-install.out
if [ "${PIPESTATUS[0]}" != 0 ]; then exit 1; fi
)
}
dist_dlls="libarchive-*.dll libgmp-*.dll libjpeg-*.dll "
dist_dlls+="*pthread*.dll zlib*.dll libdb-*.dll "
if [ "$BITS" = 64 ]; then
dist_dlls+="libcrypto-1_1-x64.dll libssl-1_1-x64.dll "
else
dist_dlls+="libcrypto-1_1.dll libssl-1_1.dll "
fi
dist_dlls+="libpcre-*.dll "
dist_dlls+="`(cd $install/bin && find . -name 'libgcc*.dll')` "
if [ -r "$install/bin/libdwarf.dll" ]; then
dist_dlls+=" libdwarf.dll"
fi
# this assumes that the required GCC dlls are copied into $install
copy_dlls()
{ (cd $install/bin && cp $dist_dlls $install/swipl/bin)
if [ -r $install/lib/libpthreadGC2.dll.a ]; then
cp $install/lib/libpthreadGC2.dll.a $install/swipl/lib
fi
}
# Usage: build_swipl_packages [pkg ...]
build_swipl_packages()
{ ( enter_topdir
cd packages
export CPPFLAGS=-I$install/include
export PKGLDFLAGS=-I$install/lib
[ -z "$1" ] || export PKG="$1"
./configure --host=$CROSS --prefix=$install
$MAKE 2>&1 | tee -a ../make.out
if [ "${PIPESTATUS[0]}" != 0 ]; then exit 1; fi
make install 2>&1 | tee -a ../make-install.out
if [ "${PIPESTATUS[0]}" != 0 ]; then exit 1; fi
make html-install || exit 1
)
}
check_build()
{ ( enter_topdir
[ -f make.out ] && scripts/check_build_log.sh make.out
)
}
build_swipl()
{ build_swipl_core
copy_dlls
build_swipl_packages
check_build
}
clean_swipl()
{ ( enter_topdir
make distclean
)
}
uninstall_swipl()
{ rm -rf $install/swipl
}
build_installer()
{ ( enter_topdir
cd ${BUILDARCH-src}
make installer
)
}
###########################
# Do the whole lot
build_all()
{ make_mingw_dirs
build_prerequisites
build_swipl
}
######################
# Create a new release
build_release()
{ clean_swipl
uninstall_swipl
download_swipl
build_swipl
build_installer
}