diff --git a/generic-linux/build-and-make-installer.sh b/generic-linux/build-and-make-installer.sh index ca753f6..ee95531 100755 --- a/generic-linux/build-and-make-installer.sh +++ b/generic-linux/build-and-make-installer.sh @@ -1,57 +1,101 @@ #!/bin/bash +############################################################################ +# Copyright (C) 2017-2018 by Keneanung # +# Copyright (C) 2025 by Stephen Lyons - # +# # +# This program is free software; you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation; either version 2 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program; if not, write to the # +# Free Software Foundation, Inc., # +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # +############################################################################ # abort script if any command fails set -e # extract program name for message -pgm=$(basename "$0") +PGM=$(basename "$0") +# Where to put the Mudlet source code: +if [ -z "${SOURCE_DIR}" ]; then + SOURCE_DIR="$(pwd)/working" + export SOURCE_DIR +fi + +if [ -n "$(echo "${SOURCE_DIR}" | cut -s -d_ -f2- )" ]; then + echo "Unfortunately the SOURCE_DIR is: \"${SOURCE_DIR}\" and it contains" + echo "one or more '_' characters and this will break something in the" + echo "make-install.sh script - aborting..." + exit 1 +fi + +echo "Working in: '${SOURCE_DIR}'" +# Used within this script AND the make-installer one and needed in the latter +# to force a Qt6 build rather than Qt5: +QMAKE="$(which qmake6)" +export QMAKE # Retrieve latest source code, keep history as it's useful to edit sometimes # if it's already there, keep it as is -if [ ! -d "source" ]; then +if [ ! -d "${SOURCE_DIR}" ]; then # check command line option for commit-ish that should be checked out - commitish="$1" - if [ -z "$commitish" ]; then - echo "No 'source' folder exists and no commit-ish given." - echo "Usage: $pgm " + COMMITISH="$1" + if [ -z "${COMMITISH}" ]; then + echo "No 'SOURCE_DIR' environmental variable exists and no commit-ish given." + echo "Usage: ${PGM} " exit 2 fi - git clone --recursive https://github.com/Mudlet/Mudlet.git source + git clone https://github.com/Mudlet/Mudlet.git "${SOURCE_DIR}" - # Switch to $commitish - (cd source && git checkout "${commitish}") + # Switch to ${COMMITISH} + (cd "${SOURCE_DIR}" && git checkout "${COMMITISH}") fi # set the commit ID so the build can reference it later -cd source -commit=$(git rev-parse --short HEAD) +# This path/location is effectively hard coded into this AND the +# make-installer.sh script: +cd "${SOURCE_DIR}" +COMMIT=$(git rev-parse --short HEAD) # linux assumes compile time dependencies are installed to make this # (hopefully) distribution independent # Add commit information to version and extract version info itself -cd src/ +cd "${SOURCE_DIR}"/src/ # find out if we do a dev or a release build -dev=$(perl -lne 'print $1 if /^BUILD = (.*)$/' < mudlet.pro) -if [ ! -z "${dev}" ]; then - MUDLET_VERSION_BUILD="-dev-$commit" +DEV=$(perl -lne 'print $1 if /^BUILD = (.*)$/' < mudlet.pro) +if [ -n "${DEV}" ]; then + MUDLET_VERSION_BUILD="-dev-${COMMIT}" export MUDLET_VERSION_BUILD fi -version=$(perl -lne 'print $1 if /^VERSION = (.+)/' < mudlet.pro) + +VERSION=$(perl -lne 'print $1 if /^VERSION = (.+)/' < mudlet.pro) + cd .. -mkdir -p build -cd build/ +BUILD_DIR="${SOURCE_DIR}"/build +export BUILD_DIR + +mkdir -p "${BUILD_DIR}" +cd "${BUILD_DIR}" # Compile using all available cores -qmake ../src/mudlet.pro +"${QMAKE}" "${SOURCE_DIR}"/src/mudlet.pro make -j "$(nproc)" # now run the actual installer creation script cd ../.. -if [ ! -z "${dev}" ]; then - ./make-installer.sh "${version}${MUDLET_VERSION_BUILD}" +if [ -n "${DEV}" ]; then + ./make-installer.sh "${VERSION}${MUDLET_VERSION_BUILD}" else - ./make-installer.sh -r "${version}" + ./make-installer.sh -r "${VERSION}" fi diff --git a/generic-linux/make-installer.sh b/generic-linux/make-installer.sh index af0cdec..eeec29a 100755 --- a/generic-linux/make-installer.sh +++ b/generic-linux/make-installer.sh @@ -1,143 +1,262 @@ #!/bin/bash +############################################################################ +# Copyright (C) 2017-2020, by Vadim Peretokin - # +# Copyright (C) 2017-2020 by Keneanung # +# Copyright (C) 2019, 2025 by Stephen Lyons - # +# Copyright (C) 2020 by Edru2 # +# - <60551052+Edru2@users.noreply.github.com> # +# # +# This program is free software; you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation; either version 2 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program; if not, write to the # +# Free Software Foundation, Inc., # +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # +############################################################################ # abort script if any command fails set -e -release="" -ptb="" +RELEASE="false" +PTB="false" -BUILD_DIR="source/build" -SOURCE_DIR="source" +if [ -n "${GITHUB_REPOSITORY}" ] ; then + SOURCE_DIR=${GITHUB_WORKSPACE} + BUILD_DIR=${BUILD_FOLDER} +fi -if [ -n "$GITHUB_REPOSITORY" ] ; then - BUILD_DIR=$BUILD_FOLDER - SOURCE_DIR=$GITHUB_WORKSPACE +if [ -z "${SOURCE_DIR}" ]; then + echo "SOURCE_DIR is not set, aborting.". + exit 1 +else + echo "Working with source code in: '${SOURCE_DIR}'". fi +# BUILD_DIR wil be ${SOURCE_DIR}/build if this script is run from +# build-and-make-installer.sh: +if [ -z "${BUILD_DIR}" ]; then + echo "BUILD_DIR is not set, aborting.". + exit 1 +else + echo "Building in: '${BUILD_DIR}'.". +fi + +APP_DIR="${SOURCE_DIR}/appDir" +export APP_DIR + # find out if we do a release build while getopts ":pr:" option; do if [ "${option}" = "r" ]; then - release="${OPTARG}" - version="${OPTARG}" + RELEASE="true" + LINUXDEPLOY_OUTPUT_VERSION="${OPTARG}" shift $((OPTIND-1)) elif [ "${option}" = "p" ]; then - ptb="yep" + PTB="true" shift $((OPTIND-1)) else echo "Unknown option -${option}" exit 1 fi done -if [ -z "${release}" ]; then - version="${1}" +if [ "${RELEASE}" != "true" ]; then + LINUXDEPLOY_OUTPUT_VERSION="${1}" fi -# setup linuxdeployqt binary if not found +# The environmental variable VERSION is used by the linuxdeploy process to +# identify the build - although we do now get warnings to use +# LINUXDEPLOY_OUTPUT_VERSION instead? +export LINUXDEPLOY_OUTPUT_VERSION + +# setup linuxdeployqt binaries if not found if [ "$(getconf LONG_BIT)" = "64" ]; then - if [[ ! -e linuxdeployqt.AppImage ]]; then - # download prepackaged linuxdeployqt. Doesn't seem to have a "latest" url yet - echo "linuxdeployqt not found - downloading one." - wget --quiet -O linuxdeployqt.AppImage https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage - chmod +x linuxdeployqt.AppImage + if [[ ! -e linuxdeploy.AppImage ]]; then + # download prepackaged linuxdeploy + echo "linuxdeploy not found - downloading it." + wget -nv -O linuxdeploy.AppImage https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage + chmod +x linuxdeploy.AppImage + fi + if [[ ! -e linuxdeploy-plugin-qt.AppImage ]]; then + # download prepackaged linuxdeploy-plugin-qt. + echo "linuxdeploy-plugin-qt not found - downloading it." + wget -nv -O linuxdeploy-plugin-qt.AppImage https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage + chmod +x linuxdeploy-plugin-qt.AppImage + fi + if [[ ! -e linuxdeploy-plugin-checkrt.sh ]]; then + # download prepackaged linuxdeploy-plugin-checkrt.sh - needed to allow an + # AppImage build with a newer CRT to run on a system with an older one: + echo "linuxdeploy-plugin-checkrt.sh not found - downloading it." + wget -nv -O linuxdeploy-plugin-checkrt.sh https://github.com/darealshinji/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt.sh + chmod +x linuxdeploy-plugin-checkrt.sh + fi + if [[ ! -e linuxdeploy-plugin-gstreamer.sh ]]; then + # download prepackaged linuxdeploy-plugin-gstreamer. + echo "linuxdeploy-plugin-gstreamer not found - downloading it." + wget -nv -O linuxdeploy-plugin-gstreamer.sh https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gstreamer/refs/heads/master/linuxdeploy-plugin-gstreamer.sh + chmod +x linuxdeploy-plugin-gstreamer.sh fi else - echo "32bit Linux is currently not supported by the AppImage." + echo "32bit Linux is no longer supported." exit 2 fi -# clean up the build/ folder -rm -rf build/ -mkdir build +if [ "${RELEASE}" != "true" ]; then + OUTPUT_NAME="Mudlet-${LINUXDEPLOY_OUTPUT_VERSION}" +else + if [ "${PTB}" == "true" ]; then + OUTPUT_NAME="Mudlet PTB" + else + OUTPUT_NAME="Mudlet" + fi +fi + +# Report variables for checking: +echo "APP_DIR is: \"${APP_DIR}\"" +echo "QMAKE is: \"${QMAKE}\"" +echo "RELEASE is: \"${RELEASE}\"" +echo "PTB is: \"${PTB}\"" +echo "LINUXDEPLOY_OUTPUT_VERSION is: \"${LINUXDEPLOY_OUTPUT_VERSION}\"" +echo "OUTPUT_NAME is: \"${OUTPUT_NAME}\"" -# delete previous appimage as well since we need to regenerate it twice +# delete any previous appimage rm -f Mudlet*.AppImage -# move the binary up to the build folder (they differ between qmake and cmake, +# clean up the "${APP_DIR}"/ folder of any previous files: +rm -rf "${APP_DIR}"/ + +# make some directories we'll need: +# For the mudlet executable: +mkdir -p "${APP_DIR}"/usr/bin/ +# For the libraries: +mkdir -p "${APP_DIR}"/usr/lib/ +# For the lua files - not needed as the translations one will make it: +# mkdir -p "${APP_DIR}"/usr/share/applications/mudlet/lua +# For the lua code formatter files: +mkdir -p "${APP_DIR}"/usr/share/applications/mudlet/lcf +# For the lua translations +mkdir -p "${APP_DIR}"/usr/share/applications/mudlet/lua/translations +# For the dictionaries we ship as a fallback +mkdir -p "${APP_DIR}"/usr/share/hunspell + + +# copy the binary into the AppDir folders (they differ between qmake and cmake, # so we use find to find the binary -find "$BUILD_DIR"/ -iname mudlet -type f -exec cp '{}' build/ \; -# get mudlet-lua in there as well so linuxdeployqt bundles it -cp -rf "$SOURCE_DIR"/src/mudlet-lua build/ -# copy Lua translations -# only copy if folder exists -mkdir -p build/translations/lua -[ -d "$SOURCE_DIR"/translations/lua ] && cp -rf "$SOURCE_DIR"/translations/lua build/translations/ +find "${BUILD_DIR}"/ -iname mudlet -type f -exec cp '{}' "${APP_DIR}"/usr/bin \; +# get the lua files in: +cp -rf "${SOURCE_DIR}"/src/mudlet-lua/lua "${APP_DIR}"/usr/share/applications/mudlet +# get the lua code formatter files in: +cp -rf "${SOURCE_DIR}"/3rdparty/lcf "${APP_DIR}"/usr/share/applications/mudlet +# copy Lua translations, only copy if folder exists +if [ -d "${SOURCE_DIR}"/translations/lua ]; then + cp -f "${SOURCE_DIR}"/translations/lua/translated/*.json "${APP_DIR}"/usr/share/applications/mudlet/lua/translations + # We also need the untranslated table for en_US locale + cp -f "${SOURCE_DIR}"/translations/lua/mudlet-lua.json "${APP_DIR}"/usr/share/applications/mudlet/lua/translations + # Change to the directory to keep the symbolic link simple + pushd "${APP_DIR}"/usr/share/applications/mudlet/lua/translations + # Make a symbolic link so that mudlet-lua_en_US.json is a meaningful file reference + ln -s ./mudlet-lua.json ./mudlet-lua_en_US.json + # Return to where we were + popd +fi + # and the dictionary files in case the user system doesn't have them (at a known # place) -cp "$SOURCE_DIR"/src/*.dic build/ -cp "$SOURCE_DIR"/src/*.aff build/ -# and the .desktop file so linuxdeployqt can pilfer it for info -cp "$SOURCE_DIR"/mudlet{.desktop,.png,.svg} build/ +cp "${SOURCE_DIR}"/src/*.dic "${APP_DIR}"/usr/share/hunspell +cp "${SOURCE_DIR}"/src/*.aff "${APP_DIR}"/usr/share/hunspell - -cp -r "$SOURCE_DIR"/3rdparty/lcf build/ +# and the .desktop and files used for icons so linuxdeploy can pilfer them +cp "${SOURCE_DIR}"/mudlet{.desktop,.png,.svg} "${APP_DIR}"/usr/share/applications/mudlet # now copy Lua modules we need in -# this should be improved not to be hardcoded -mkdir -p build/lib/luasql -mkdir -p build/lib/brimworks - -cp "$SOURCE_DIR"/3rdparty/discord/rpc/lib/libdiscord-rpc.so build/lib/ +mkdir -p "${APP_DIR}"/usr/lib/luasql +mkdir -p "${APP_DIR}"/usr/lib/brimworks -for lib in lfs rex_pcre luasql/sqlite3 brimworks/zip lua-utf8 yajl +for LIB in lfs rex_pcre luasql/sqlite3 brimworks/zip lua-utf8 yajl do - found=0 - for path in $(luarocks path --lr-cpath | tr ";" "\n") + FOUND="false" + for LIB_PATH in $(luarocks path --lr-cpath | tr ";" "\n") do - changed_path=${path/\?/${lib}}; - if [ -e "${changed_path}" ]; then - cp -rL "${changed_path}" build/lib/${lib}.so - found=1 + CHANGED_PATH=${LIB_PATH/\?/${LIB}}; + echo "For \"${LIB}\" changing path from \"${LIB_PATH}\" to \"${CHANGED_PATH}\"." + if [ -e "${CHANGED_PATH}" ]; then + # For previous linuxdeployqt + # cp -rL "${CHANGED_PATH}" "${BUILD_DIR}"/lib/${LIB}.so + if cp -vrL "${CHANGED_PATH}" "${APP_DIR}/usr/lib/${LIB}.so"; then + FOUND="true" + fi fi done - if [ "${found}" -ne "1" ]; then - echo "Missing dependency ${lib}, aborting." + if [ "${FOUND}" == "false" ]; then + echo "Missing dependency '${LIB}', aborting." exit 1 fi done -# extract linuxdeployqt since some environments (like travis) don't allow FUSE -./linuxdeployqt.AppImage --appimage-extract +# Discord library +cp -v "${SOURCE_DIR}"/3rdparty/discord/rpc/lib/libdiscord-rpc.so "${APP_DIR}"/usr/lib/ -# a hack to get the Chinese input text plugin for Qt from the Ubuntu package -# into the Qt for /opt package directory -if [ -n "${QTDIR}" ]; then - sudo cp /usr/lib/x86_64-linux-gnu/qt5/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin.so \ - "${QTDIR}/plugins/platforminputcontexts/libfcitxplatforminputcontextplugin.so" || exit -fi +# QMAKE is an extra detail (path and filename of the qmake to use) needed for +# the qt plugin - including selecting a Qt 6 make which should have been done +# by the caller of this script - this is to identify where to get the Qt plugins +# from: +QT_INSTALL_PLUGINS="$(${QMAKE} -query | grep QT_INSTALL_PLUGINS | cut -d: -f 2)" +echo "Using Qt plugins located at: '${QT_INSTALL_PLUGINS}'" +export QT_INSTALL_PLUGINS + +# In case we need any: +EXTRA_QT_MODULES="" +echo "Using extra modules: \"${EXTRA_QT_MODULES}\"" +export EXTRA_QT_MODULES # Bundle libssl.so so Mudlet works on platforms that only distribute # OpenSSL 1.1 -cp -L /usr/lib/x86_64-linux-gnu/libssl.so* \ - build/lib/ || true -cp -L /lib/x86_64-linux-gnu/libssl.so* \ - build/lib/ || true -if [ -z "$(ls build/lib/libssl.so*)" ]; then - echo "No OpenSSL libraries to copy found. Aborting..." - exit 1 +cp -Lv /usr/lib/x86_64-linux-gnu/libssl.so* "${BUILD_DIR}"/lib/ 2>/dev/null || true +cp -Lv /lib/x86_64-linux-gnu/libssl.so* "${BUILD_DIR}"/lib/ 2>/dev/null || true +if [ -z "$(ls "${BUILD_DIR}"/lib/libssl.so* 2>/dev/null)" ]; then + echo "No OpenSSL libraries to copy found. This might be a problem..." + # exit 1 fi echo "Generating AppImage" -./squashfs-root/AppRun ./build/mudlet -appimage \ - -executable=build/lib/rex_pcre.so -executable=build/lib/zip.so \ - -executable=build/lib/luasql/sqlite3.so -executable=build/lib/yajl.so \ - -executable=build/lib/libssl.so.1.1 \ - -executable=build/lib/libssl.so.1.0.0 \ - -extra-plugins=texttospeech/libqttexttospeech_flite.so,texttospeech/libqttexttospeech_speechd.so,platforminputcontexts/libcomposeplatforminputcontextplugin.so,platforminputcontexts/libibusplatforminputcontextplugin.so,platforminputcontexts/libfcitxplatforminputcontextplugin.so +# Note: the gstreamer plugin needs the patchelf utility! +./linuxdeploy.AppImage --appdir "${APP_DIR}" --plugin qt --plugin gstreamer --plugin checkrt --icon-file "${SOURCE_DIR}"/mudlet.svg --desktop-file "${SOURCE_DIR}"/mudlet.desktop --executable "${APP_DIR}"/usr/bin/mudlet --output appimage +# Unfortunately, until https://github.com/linuxdeploy/linuxdeploy-plugin-qt/issues/194 +# is resolved we have to go through the ${APP_DIR}/usr/translations/ directory +# and combine the qtbase_xx(_YY).qm and qtmultimedia_xx(_YY).qm files into +# a single qt_xx(_YY).qm file with a: +# "lconvert -o ./qt_xx(_YY).qm qtbase_xx(_YY).qm qtmultimedia_xx(_YY).qm" +# The '_' in workarea needs to be accounted for in the cut fields to index +for baseFile in "${APP_DIR}"/usr/translations/qtbase_*.qm +do + localeCode=$(echo "${baseFile}" | cut -d_ -f 2-) + # remember localeCode includes the ".qm" extension + if [ -f "${APP_DIR}"/usr/translations/qtmultimedia_${localeCode} ]; then + # This locale DOES have a qtmultimedia_*.qm file so include it: + lconvert -o "${APP_DIR}"/usr/translations/qt_${localeCode} "${APP_DIR}"/usr/translations/qtbase_${localeCode} "${APP_DIR}"/usr/translations/qtmultimedia_${localeCode} + else + # It doesn't so just convert/copy the base one: + lconvert -o "${APP_DIR}"/usr/translations/qt_${localeCode} "${APP_DIR}"/usr/translations/qtbase_${localeCode} + fi +done -# clean up extracted appimage -rm -rf squashfs-root/ +# Remove the individual files +rm "${APP_DIR}"/usr/translations/qtbase_*.qm +rm "${APP_DIR}"/usr/translations/qtmultimedia_*.qm +# Remove some files from prior run that will be regenerated - and give us a +# warning if not removed +rm "${APP_DIR}"/AppRun +rm "${APP_DIR}"/AppRun.wrapped -if [ -z "${release}" ]; then - output_name="Mudlet-${version}" -else - if [ -z "${ptb}" ]; then - output_name="Mudlet" - else - output_name="Mudlet PTB" - fi -fi +# Rerun the base linuxdeploy (still with the checkrt plugin) to regenerate a new AppImage +./linuxdeploy.AppImage --appdir "${APP_DIR}" --plugin checkrt --output appimage -echo "output_name: ${output_name}" -mv Mudlet*.AppImage "$output_name.AppImage" +mv Mudlet*.AppImage "${OUTPUT_NAME}.AppImage"