blob: c2553ba6f9db48f47beec8d5ea474e4e22c57059 [file] [log] [blame]
#!/bin/bash
###############################################################################
# BRLTTY - A background process providing access to the console screen (when in
# text mode) for a blind person using a refreshable braille display.
#
# Copyright (C) 1995-2023 by The BRLTTY Developers.
#
# BRLTTY comes with ABSOLUTELY NO WARRANTY.
#
# This is free software, placed under the terms of the
# GNU Lesser General Public License, as published by the Free Software
# Foundation; either version 2.1 of the License, or (at your option) any
# later version. Please see the file LICENSE-LGPL for details.
#
# Web Page: http://brltty.app/
#
# This software is maintained by Dave Mielke <dave@mielke.cc>.
###############################################################################
. "`dirname "${0}"`/../brltty-prologue.sh"
. "${programDirectory}/mingw.sh"
set -e
umask 022
readonly defaultArchiveRoot="http://brltty.app/archive/Windows"
readonly defaultTemporaryDirectory="${TMPDIR:-/tmp}/brltty-${programName}"
havePath() {
local path="${1}"
[ -n "${path}" ] || return 1
[ -e "${path}" ] || return 2
return 0
}
verifyDirectory() {
local path="${1}"
[ -e "${path}" ] || semanticError "directory not found: ${path}"
[ -d "${path}" ] || semanticError "not a directory: ${path}"
[ -w "${path}" ] || semanticError "directory not writable: ${path}"
[ -r "${path}" ] || semanticError "directory not readable: ${path}"
[ -x "${path}" ] || semanticError "directory not searchable: ${path}"
}
findCommand() {
local variable="${1}"
shift 1
for name
do
local path="$(command -v "${name}")"
[ -n "${path}" ] && {
setVariable "${variable}" "${path}"
return 0
}
done
return 1
}
executeCommand() {
logMessage detail "executing command: ${*}"
exitStatus=0
"${@}" || exitStatus="${?}"
[ "${exitStatus}" -eq 0 ] || logWarning "command failed: ${1}: exit status ${exitStatus}"
return "${exitStatus}"
}
downloadFile() {
local source="${1}"
local target="${2}"
logNote "downloading file: ${source}"
[ -z "${target}" ] && target="${source##*/}"
executeCommand wget -nv -O "${target}" "${archiveRoot}/${source}"
}
unpackArchive() {
local path="${1}"
case "${path}"
in
*.zip) set -- unzip -q;;
*.tar.gz) set -- tar xfz;;
*) semanticError "unsupported archive: ${path}";;
esac
executeCommand "${@}" "${path}"
}
applyPatch() {
local patch="${1}"
local directory="${2}"
local file="${3}"
local pattern="${4}"
local path="${directory}/${file}"
if [ -f "${path}" ]
then
grep -q "${pattern}" "${path}" || {
local name="${patch##*/}"
logMessage task "applying patch: ${name}"
"${dryRun}" || {
downloadFile "${patch}"
executeCommand patch -N -i "${temporaryDirectory}/${name}" -d "${directory}" "${file}"
}
}
else
logWarning "file not found: ${path}"
fi
}
installFile() {
local file="${1}"
local directory="${2}"
local source="${file##*/}"
local target="${directory}/${source}"
[ -e "${target}" ] || {
logMessage task "installing file: ${target}"
"${dryRun}" || {
downloadFile "${file}"
[ -d "${directory}" ] || executeCommand mkdir -p "${directory}"
executeCommand cp "${source}" "${target}"
}
}
}
installLink() {
local to="${1}"
local directory="${2}"
local name="${3}"
[ -n "${name}" ] || name="${to##*/}"
local from="${directory}/${name}"
havePath "${from}" || {
logMessage task "installing link: ${from} -> ${to}"
[ -e "${to}" ] || semanticError "link target not found: ${to}"
"${dryRun}" || executeCommand ln -s "${to}" "${from}"
}
}
installWindowsArchive() {
local archive="${1}"
local path="${2}"
havePath "${path}" || {
logMessage task "installing Windows archive: ${archive}"
"${dryRun}" || {
downloadFile "${archive}"
local directory="content-${archive}"
executeCommand mkdir "${directory}"
executeCommand cd "${directory}"
unpackArchive "../${archive}"
set -- *
if [ "${#}" -eq 1 -a -d "${1}" ]
then
executeCommand mv "${1}" "${path}"
executeCommand cd ..
executeCommand rmdir "${directory}"
else
executeCommand cd ..
executeCommand mv "${directory}" "${path}"
fi
}
}
}
installMingwArchive() {
local archive="${1}"
local path="${2}"
havePath "${mingwDirectory}/${path}" || {
logMessage task "installing MinGW archive: ${archive}"
"${dryRun}" || {
downloadFile "MinGW/${archive}"
executeCommand cd "${mingwDirectory}"
unpackArchive "${temporaryDirectory}/${archive}"
executeCommand cd "${temporaryDirectory}"
}
}
}
installMingwPackage() {
local package="${1}"
local path="${2}"
havePath "${path}" || {
logMessage task "installing MinGW package: ${package}"
"${dryRun}" || executeCommand mingw-get --verbose=0 install "${package}"
}
}
installMicrosoftVisualCTools() {
local file
for file in lib.exe link.exe mspdb100.dll msvcr100.dll
do
installFile "MSVC/${file}" "/usr/local/bin"
done
}
installPackageConfigurationFiles() {
local package
for package in libusb libusb-1.0
do
installFile "pkgconfig/${package}.pc" "${librariesDirectory}/pkgconfig"
done
}
installBluetoothHeaders() {
local name
for name in ws2bth bthdef bthsdpdef
do
installFile "Bluetooth/${name}.h" "${headersDirectory}"
done
}
installLibUSB0() {
local directory="${windowsDirectory}/LibUSB-Win32"
installWindowsArchive libusb-win32-bin-1.2.6.0.zip "${directory}"
installLink "${directory}/include/lusb0_usb.h" "${headersDirectory}" usb.h
installLink "${directory}/lib/gcc/libusb.a" "${librariesDirectory}"
installLink "${directory}/bin/x86/libusb0_x86.dll" "${commandsDirectory}" libusb0.dll
}
installLibUSB1() {
local directory="${windowsDirectory}/LibUSB-1.0"
installWindowsArchive libusbx-1.0.18-win.tar.gz "${directory}"
installLink "${directory}/include/libusbx-1.0" "${headersDirectory}" libusb-1.0
installLink "${directory}/MinGW32/dll/libusb-1.0.dll.a" "${librariesDirectory}"
installLink "${directory}/MinGW32/dll/libusb-1.0.dll" "${commandsDirectory}"
installWindowsArchive winusb.zip "${windowsDirectory}/WinUSB"
}
installCython() {
local python
if findCommand python python py
then
export PYTHONIOENCODING="utf-8"
local directory="${python%/*}"
findCommand cython cython || {
logMessage task "installing Cython"
"${dryRun}" || executeCommand pip -q install cython
}
installFile Cython/vcruntime140.dll "${directory}/libs"
installFile Cython/distutils.cfg "${directory}/lib/distutils"
applyPatch "Cython/PythonCygwinCCompiler.patch" "${directory}/lib/distutils" "cygwinccompiler.py" "vcruntime140"
else
logWarning "Python not found"
fi
}
addProgramOption a string.URL archiveRoot "the URL for BRLTTY's Windows archive" "${defaultArchiveRoot}"
addProgramOption d flag dryRun "dry run - don't actually install anything"
addProgramOption k flag keepFiles "keep (do not remove) the temporary directory"
addProgramOption p string.directory pythonDirectory "the directory where Python has been installed"
addProgramOption t string.directory temporaryDirectory "the temporary directory to use" "${defaultTemporaryDirectory}"
parseProgramArguments "${@}"
[ -n "${archiveRoot}" ] || archiveRoot="${defaultArchiveRoot}"
[ -n "${pythonDirectory}" ] && {
[ -d "${pythonDirectory}" ] || semanticError "Python directory not found: ${pythonDirectory}"
PATH="${pythonDirectory}:${pythonDirectory}/scripts:${PATH}"
}
readonly windowsDirectory="/c"
verifyDirectory "${windowsDirectory}"
readonly mingwDirectory="/mingw"
verifyDirectory "${mingwDirectory}"
readonly commandsDirectory="${mingwDirectory}/bin"
verifyDirectory "${commandsDirectory}"
readonly librariesDirectory="${mingwDirectory}/lib"
verifyDirectory "${librariesDirectory}"
readonly headersDirectory="${mingwDirectory}/include"
verifyDirectory "${headersDirectory}"
if [ -z "${temporaryDirectory}" ]
then
temporaryDirectory="${defaultTemporaryDirectory}"
rm -f -r "${temporaryDirectory}"
elif [ -e "${temporaryDirectory}" ]
then
semanticError "directory already exists: ${temporaryDirectory}"
fi
mkdir -p "${temporaryDirectory}"
cd "${temporaryDirectory}"
temporaryDirectory="$(pwd -W)"
installMingwPackage msys-bison /bin/bison
installMingwPackage msys-dos2unix /bin/dos2unix
installMingwPackage msys-groff /bin/groff
installMingwPackage msys-m4 /bin/m4
installMingwPackage msys-tar /bin/tar
installMingwPackage msys-unzip /bin/unzip
installMingwPackage msys-wget /bin/wget
installMingwPackage msys-zip /bin/zip
installMingwPackage mingw32-libpdcurses /mingw/include/curses.h
installMingwPackage mingw32-pthreads-w32 /mingw/include/pthread.h
installMingwPackage mingw32-tcl /mingw/bin/tclsh
installMicrosoftVisualCTools
installPackageConfigurationFiles
installBluetoothHeaders
installMingwArchive pkg-config_0.28-1_win32.zip "bin/pkg-config.exe"
installMingwArchive glib_2.34.3-1_win32.zip "bin/libgobject-2.0-0.dll"
installWindowsArchive AutoHotkey104805.tar.gz "${ahkLocation}"
installWindowsArchive nsis-3.0b0.tar.gz "${nsisLocation}"
installWindowsArchive icu4c-53_1-Win32-msvc10.zip "${icuLocation}"
installLibUSB0
installLibUSB1
installCython
"${keepFiles}" || {
logMessage task "cleaning up"
cd "${initialDirectory}"
rm -f -r "${temporaryDirectory}"
}
logMessage task "done"
exit 0