diff options
| author | Eduard Braun <eduard.braun2@gmx.de> | 2017-07-17 21:45:08 +0000 |
|---|---|---|
| committer | Eduard Braun <eduard.braun2@gmx.de> | 2017-07-17 21:45:08 +0000 |
| commit | e9d20e9e485656ad0124a6525b211abb22ca75b6 (patch) | |
| tree | f7bb56db2a67d23b50e1e0427a907e35e862482f /buildtools | |
| parent | Cleanup: eliminate version from config.h (diff) | |
| download | inkscape-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.sh | 78 | ||||
| -rw-r--r-- | buildtools/msys2checkdeps.py | 163 | ||||
| -rw-r--r-- | buildtools/msys2installdeps.sh | 101 |
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 |
