summaryrefslogtreecommitdiffstats
path: root/buildtools
diff options
context:
space:
mode:
authorEduard Braun <eduard.braun2@gmx.de>2017-07-17 21:45:08 +0000
committerEduard Braun <eduard.braun2@gmx.de>2017-07-17 21:45:08 +0000
commite9d20e9e485656ad0124a6525b211abb22ca75b6 (patch)
treef7bb56db2a67d23b50e1e0427a907e35e862482f /buildtools
parentCleanup: eliminate version from config.h (diff)
downloadinkscape-e9d20e9e485656ad0124a6525b211abb22ca75b6.tar.gz
inkscape-e9d20e9e485656ad0124a6525b211abb22ca75b6.zip
root dir tidying: MSYS2 & AppVeyor CI
- move build scripts and related tools to buildtools folder - rename appveyor.yml -> .appveyor.yml
Diffstat (limited to 'buildtools')
-rw-r--r--buildtools/appveyor.sh78
-rw-r--r--buildtools/msys2checkdeps.py163
-rw-r--r--buildtools/msys2installdeps.sh101
3 files changed, 342 insertions, 0 deletions
diff --git a/buildtools/appveyor.sh b/buildtools/appveyor.sh
new file mode 100644
index 000000000..62941b2a1
--- /dev/null
+++ b/buildtools/appveyor.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+### functions
+message() { echo -e "\e[1;32m\n${1}\n\e[0m"; }
+warning() { echo -e "\e[1;33m\nWarning: ${1}\n\e[0m"; }
+error() { echo -e "\e[1;31m\nError: ${1}\n\e[0m"; exit 1; }
+
+
+
+### setup
+
+# do everything in /build
+cd "$(cygpath ${APPVEYOR_BUILD_FOLDER})"
+mkdir build
+cd build
+
+# write an empty fonts.conf to speed up fc-cache
+export FONTCONFIG_FILE=/dummy-fonts.conf
+cat >"$FONTCONFIG_FILE" <<EOF
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<fontconfig></fontconfig>
+EOF
+
+# install dependencies
+message "--- Installing dependencies"
+source ../buildtools/msys2installdeps.sh
+pacman -S $MINGW_PACKAGE_PREFIX-{ccache,gtest,ntldd-git} --needed --noconfirm --noprogressbar
+ccache --max-size=200M
+
+
+
+### build / test
+
+message "\n\n##### STARTING BUILD #####"
+
+# configure
+message "--- Configuring the build"
+cmake .. -G Ninja \
+ -DCMAKE_C_COMPILER_LAUNCHER="ccache" \
+ -DCMAKE_CXX_COMPILER_LAUNCHER="ccache" \
+ -DCMAKE_INSTALL_MESSAGE="NEVER" \
+ || error "cmake failed"
+
+# build
+message "--- Compiling Inkscape"
+ccache --zero-stats
+ninja || error "compilation failed"
+ccache --show-stats
+appveyor SetVariable -Name APPVEYOR_SAVE_CACHE_ON_ERROR -Value true # build succeeded so it's safe to save the cache
+
+# install
+message "--- Installing the project"
+ninja install || error "installation failed"
+python ../buildtools/msys2checkdeps.py check inkscape/ || error "missing libraries in installed project"
+
+# test
+message "--- Running tests"
+# check if the installed executable works
+inkscape/inkscape.exe -V || error "installed executable won't run"
+PATH= inkscape/inkscape.exe -V >/dev/null || error "installed executable won't run with empty PATH (missing dependecies?)"
+err=$(PATH= inkscape/inkscape.exe -V 2>&1 >/dev/null)
+if [ -n "$err" ]; then warning "installed executable produces output on stderr:"; echo "$err"; fi
+# check if the uninstalled executable works
+INKSCAPE_DATADIR=../share bin/inkscape.exe -V >/dev/null || error "uninstalled executable won't run"
+err=$(INKSCAPE_DATADIR=../share bin/inkscape.exe -V 2>&1 >/dev/null)
+if [ -n "$err" ]; then warning "uninstalled executable produces output on stderr:"; echo "$err"; fi
+# run tests (don't fail yet as most tests SEGFAULT on exit)
+#ninja check || warning "tests failed" # disabled because of sporadic deadlocks :-(
+
+message "##### BUILD SUCCESSFULL #####\n\n"
+
+
+### package
+BRANCH=$(git branch | tail -n 1 | tr -d ' ')
+DATE=$(git log -n 1 --pretty=%cd --date=short)
+HASH=$(git rev-parse --short HEAD)
+7z a "inkscape-${BRANCH}-(${DATE}_${HASH})-${MSYSTEM_CARCH}.7z" inkscape
diff --git a/buildtools/msys2checkdeps.py b/buildtools/msys2checkdeps.py
new file mode 100644
index 000000000..d64d9bcbc
--- /dev/null
+++ b/buildtools/msys2checkdeps.py
@@ -0,0 +1,163 @@
+#!/usr/bin/env python
+# ------------------------------------------------------------------------------------------------------------------
+# list or check dependencies for binary distributions based on MSYS2 (requires the package mingw-w64-ntldd)
+#
+# Usage:
+# python msys2checkdeps.py MODE PATH
+#
+# MODE
+# list - list dependencies in human-readable form with full path and list of dependents
+# list-compact - list dependencies in compact form (as a plain list of filenames)
+# check - check for missing or unused dependecies (see below for details)
+# check-missing - check if all required dependecies are present in PATH
+# exits with error code 2 if missing dependecies are found and prints the list to stderr
+# check-unused - check if any of the libraries in the root of PATH are unused and prints the list to stderr
+#
+# PATH
+# full or relative path to a single file or a directory to work on (directories will be checked recursively)
+# ------------------------------------------------------------------------------------------------------------------
+
+from __future__ import print_function
+
+
+import os
+import subprocess
+import sys
+
+
+SYSTEMROOT = os.environ['SYSTEMROOT']
+
+
+class Dependency:
+ def __init__(self):
+ self.location = None
+ self.dependents = set()
+
+
+def warning(msg):
+ print("Warning: " + msg, file=sys.stderr)
+
+
+def error(msg):
+ print("Error: " + msg, file=sys.stderr)
+ exit(1)
+
+
+def call_ntldd(filename):
+ try:
+ output = subprocess.check_output(['ntldd', '-R', filename], stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as e:
+ error("'ntldd' failed with '" + str(e) + "'")
+ except WindowsError as e:
+ error("Calling 'ntldd' failed with '" + str(e) + "' (have you installed 'mingw-w64-ntldd-git'?)")
+ except Exception as e:
+ error("Calling 'ntldd' failed with '" + str(e) + "'")
+ return output.decode('utf-8')
+
+
+def get_dependencies(filename, deps):
+ raw_list = call_ntldd(filename)
+
+ skip_indent = float('Inf')
+ parents = {}
+ parents[0] = os.path.basename(filename)
+ for line in raw_list.splitlines():
+ line = line[1:]
+ indent = len(line) - len(line.lstrip())
+ if indent > skip_indent:
+ continue
+ else:
+ skip_indent = float('Inf')
+
+ # if the dependency is not found in the working directory ntldd tries to find it on the search path
+ # which is indicated by the string '=>' followed by the determined location or 'not found'
+ if ('=>' in line):
+ (lib, location) = line.lstrip().split(' => ')
+ if location == 'not found':
+ location = None
+ else:
+ location = location.rsplit('(', 1)[0].strip()
+ else:
+ lib = line.rsplit('(', 1)[0].strip()
+ location = os.getcwd()
+
+ parents[indent+1] = lib
+
+ # we don't care about Microsoft libraries and their dependencies
+ if location and SYSTEMROOT in location:
+ skip_indent = indent
+ continue
+
+ if lib not in deps:
+ deps[lib] = Dependency()
+ deps[lib].location = location
+ deps[lib].dependents.add(parents[indent])
+ return deps
+
+
+def collect_dependencies(path):
+ # collect dependencies
+ # - each key in 'deps' will be the filename of a dependency
+ # - the corresponding value is an instance of class Dependency (containing full path and dependents)
+ deps = {}
+ if os.path.isfile(path):
+ os.chdir(os.path.dirname(path))
+ deps = get_dependencies(path, deps)
+ elif os.path.isdir(path):
+ os.chdir(path)
+ extensions = ['.exe', '.pyd', '.dll']
+ exclusions = ['python2.7/distutils/command/wininst']
+ for base, dirs, files in os.walk(path):
+ for f in files:
+ filepath = os.path.join(base, f)
+ (_, ext) = os.path.splitext(f)
+ if (ext.lower() not in extensions) or any(exclusion in filepath for exclusion in exclusions):
+ continue
+ deps = get_dependencies(filepath, deps)
+ return deps
+
+
+if __name__ == '__main__':
+
+ # get mode from command line
+ mode = sys.argv[1]
+ modes = ['list', 'list-compact', 'check', 'check-missing', 'check-unused']
+ if mode not in modes:
+ error("First argument needs to be a valid mode (" + (', ').join(modes) + ").")
+
+ # get path from command line
+ path = sys.argv[2]
+ path = os.path.abspath(path)
+ if not os.path.exists(path):
+ error("Can't find file/folder '" + path + "'")
+ root = path if os.path.isdir(path) else os.path.dirname(path)
+
+ # get dependencies for path recursively
+ deps = collect_dependencies(path)
+
+ # print output / prepare exit code
+ exit_code = 0
+ for dep in sorted(deps):
+ location = deps[dep].location
+ dependents = deps[dep].dependents
+
+ if mode == 'list':
+ if (location is None):
+ location = '---MISSING---'
+ print(dep + " - " + location + " (" + ", ".join(dependents) + ")")
+ elif mode == 'list-compact':
+ print(dep)
+ elif mode in ['check', 'check-missing']:
+ if ((location is None) or (root not in os.path.abspath(location))):
+ warning("Missing dependency " + dep + " (" + ", ".join(dependents) + ")")
+ exit_code = 2
+
+ # check for unused libraries
+ if mode in ['check', 'check-unused']:
+ installed_libs = [file for file in os.listdir(root) if file.endswith(".dll")]
+ deps_lower = [dep.lower() for dep in deps]
+ top_level_libs = [lib for lib in installed_libs if lib.lower() not in deps_lower]
+ for top_level_lib in top_level_libs:
+ warning("Unused dependency " + top_level_lib)
+
+ exit(exit_code)
diff --git a/buildtools/msys2installdeps.sh b/buildtools/msys2installdeps.sh
new file mode 100644
index 000000000..e400a9e7b
--- /dev/null
+++ b/buildtools/msys2installdeps.sh
@@ -0,0 +1,101 @@
+#!/usr/bin/env bash
+# -------------------------------------------------------------------------------
+# This script installs all dependencies required for building Inkscape with MSYS2
+# execute it once on an MSYS shell, i.e.
+# - use the "MSYS2 MSYS" shortcut in the start menu or
+# - run "msys2.exe" in MSYS2's installation folder
+#
+# MSYS2 and installed libraries can be updated later by executing
+# pacman -Syu --ignore=mingw-w64-*-imagemagick
+# in an MSYS shell
+# -------------------------------------------------------------------------------
+
+# select if you want to build 32-bit (i686), 64-bit (x86_64), or both
+case "$MSYSTEM" in
+ MINGW32)
+ ARCH=mingw-w64-i686
+ ;;
+ MINGW64)
+ ARCH=mingw-w64-x86_64
+ ;;
+ *)
+ ARCH={mingw-w64-i686,mingw-w64-x86_64}
+ ;;
+esac
+
+# sync package databases
+pacman -Sy
+
+# install basic development system, compiler toolchain and build tools
+eval pacman -S --needed --noconfirm \
+bzr \
+intltool \
+base-devel \
+$ARCH-toolchain \
+$ARCH-cmake \
+$ARCH-ninja
+
+# install Inkscape dependecies (required)
+eval pacman -S --needed --noconfirm \
+$ARCH-gc \
+$ARCH-gsl \
+$ARCH-popt \
+$ARCH-libxslt \
+$ARCH-boost \
+$ARCH-gtk2 \
+$ARCH-gtkmm \
+$ARCH-gtk3 \
+$ARCH-gtkmm3 \
+$ARCH-gdl \
+$ARCH-libsoup
+
+# install Inkscape dependecies (optional)
+eval pacman -S --needed --noconfirm \
+$ARCH-poppler \
+$ARCH-potrace \
+$ARCH-libcdr \
+$ARCH-libvisio \
+$ARCH-libwpg \
+$ARCH-aspell \
+$ARCH-aspell-en \
+$ARCH-gtkspell \
+$ARCH-gtkspell3 \
+$ARCH-libyaml
+
+# install ImageMagick (as Inkscape requires old version ImageMagick 6 we have to specify it explicitly)
+# to prevent future updates:
+# add the line
+# "IgnorePkg = mingw-w64-*-imagemagick"
+# to
+# "C:\msys64\etc\pacman.conf"
+# or (always!) run pacman with the additional command line switch
+# --ignore=mingw-w64-*-imagemagick
+for arch in $(eval echo $ARCH); do
+ case ${arch} in
+ mingw-w64-i686)
+ pacman -U --needed --noconfirm https://downloads.sourceforge.net/project/msys2/REPOS/MINGW/i686/mingw-w64-i686-imagemagick-6.9.3.7-1-any.pkg.tar.xz
+ ;;
+ mingw-w64-x86_64)
+ pacman -U --needed --noconfirm https://downloads.sourceforge.net/project/msys2/REPOS/MINGW/x86_64/mingw-w64-x86_64-imagemagick-6.9.3.7-1-any.pkg.tar.xz
+ ;;
+ esac
+done
+
+
+# install Python and modules used by Inkscape
+eval pacman -S --needed --noconfirm \
+$ARCH-python2 \
+$ARCH-python2-pip \
+$ARCH-python2-lxml \
+$ARCH-python2-numpy \
+$ARCH-python2-pillow
+for arch in $(eval echo $ARCH); do
+ case ${arch} in
+ mingw-w64-i686)
+ /mingw32/bin/pip install coverage pyserial scour
+ ;;
+ mingw-w64-x86_64)
+ /mingw64/bin/pip install coverage pyserial scour
+ ;;
+ esac
+done