From 0e45f3c0ee556d4dee3bc81a577e4998232f491a Mon Sep 17 00:00:00 2001 From: OmniTroid Date: Wed, 31 Jul 2024 13:40:43 +0200 Subject: Universal configure script (#1022) * Init configure.sh * echo detected platform * Implement check_command * Implement install_bass_macos, plus checks * Ignore tmp * Add configure main function and bass installs * Less functions * Reformat file, add some stuff * Start adding automatic qt detection * Curl is more portable it seems * Try finding Qt's bundled cmake * fix cmake command checking * Reorder to windows first * do not download deps if already present * Add configure clean * Fix basic command checks * cmd fixes * thank you bash, very cool! * fix file shenanigans * unneccessary comment * Use qt_path instead of qt_cmake * Ignore apng folder * Rework with QT_PATH * Move find_qt to the top * move check_command near the top * Tidy up command checking * Rename QT_PATH to QT_ROOT and call the qt installation path QT_PATH instead * only clone qtapng if no dir * Cmake shenanigans * Fix build with ninja * Fix apng cp cmd * Fix apng check * Just call it cmake * Run cmake in configure.sh * Ignore generated files * Comment out mega cmake command * Fix apng check * more cmake stuff * make the cmake command we use very clear * ignore cmake_cmd.txt * Note that linux and macos is not supported * Update README * Add some stuff to windeployqt * Clone themes * macos fixes * Only call windeployqt on windows * Linux fixes * Remove linux todo comment * Remove git stuff from themes checkout * Note about vanilla content.. * Add note about formatting in readme * Remove e flag so script doesn't stop with no error messages * Note about toolchains on unix-likes * Fix cmake path on linux * Rework get_zip for better error handling and less unzipping unnecessary files * Adjust get_zip calls * Hopefully make error handling more robust * Fix bassopus on linux * linux bassopus pathing fix * Fix discord rpc linux * Add note about opengl * Ignore test_aopacket * Tidy up readme a bit again * Remove old configure scripts --- configure.sh | 500 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 500 insertions(+) create mode 100755 configure.sh (limited to 'configure.sh') diff --git a/configure.sh b/configure.sh new file mode 100755 index 00000000..3ec2dc24 --- /dev/null +++ b/configure.sh @@ -0,0 +1,500 @@ +#!/bin/bash + +set -euo pipefail + +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +cd "${SCRIPT_DIR}" || { echo "Failed to cd to pwd"; exit 1; } + +detect_platform() { + unameOut="$(uname -s)" + case "${unameOut}" in + CYGWIN*|MINGW*|MSYS*) platform=windows;; + Linux*) platform=linux;; + Darwin*) platform=macos;; + *) platform=unknown;; + esac + echo "${platform}" +} + +# Basic data such as platform can be global +PLATFORM=$(detect_platform) +BUILD_CONFIG="Debug" +QT_VERSION="6.5.3" + +print_help() { + echo "Usage: $0 [options]" + echo "Options:" + echo " -h, --help: Print this help message" + echo " clean: Remove all files from lib, bin and tmp" + echo " QT_ROOT=path: Specify the root path to where Qt is installed (eg. /c/Qt/)" +} + +# Check if a given command returns a non-zero exit code +check_command() { + # Hack to not make the whole script exit.. + set +e + if ! "$@" &> /dev/null; then + set -e + return 1 + fi + set -e + return 0 +} + +find_qt() { + local qt_root="" + + # Function to check if a dir exists + check_path() { + if [[ -d "$1" ]]; then + qt_root="$1" + return 0 + else + return 1 + fi + } + + # Check common Qt installation paths on different OSes + if [[ "$PLATFORM" == "windows" ]]; then + # Windows paths, maybe check for more in the future + check_path "/c/Qt" + elif [[ "$PLATFORM" == "linux" ]]; then + check_path "$HOME/Qt" + elif [[ "$PLATFORM" == "macos" ]]; then + check_path "$HOME/Qt" + fi + + # If qt-cmake is found, print the path + if [[ -n "$qt_root" ]]; then + echo "$qt_root" + else + echo "" + return 1 + fi +} + +find_qtpath() { + local qt_path="" + + check_path() { + if [[ -d "$1" ]]; then + qt_path="$1" + return 0 + else + return 1 + fi + } + + if [[ "$PLATFORM" == "windows" ]]; then + check_path "${QT_ROOT}/${QT_VERSION}/mingw_64" + elif [[ "$PLATFORM" == "linux" ]]; then + check_path "${QT_ROOT}/${QT_VERSION}/gcc_64" + elif [[ "$PLATFORM" == "macos" ]]; then + check_path "${QT_ROOT}/${QT_VERSION}/macos" + fi + + echo "$qt_path" +} + +find_cmake() { + local cmake_path="" + + # Function to check if a file exists + check_path() { + if [[ -f "$1" ]]; then + cmake_path="$1" + return 0 + else + return 1 + fi + } + + # See if we can find the cmake bundled with Qt + if [[ "$PLATFORM" == "windows" ]]; then + check_path "${QT_ROOT}/Tools/CMake_64/bin/cmake.exe" + elif [[ "$PLATFORM" == "linux" ]]; then + check_path "${QT_ROOT}/Tools/CMake/bin/cmake" + elif [[ "$PLATFORM" == "macos" ]]; then + check_path "${QT_ROOT}/Tools/CMake/CMake.app/Contents/bin/cmake" + else + echo "Unsupported platform: ${PLATFORM}" + return 1 + fi + + # If cmake is found, print the path + if [[ -n "$cmake_path" ]]; then + echo "$cmake_path" + return 0 + else + echo "" + return 1 + fi +} + +find_mingw() { + # Find a mingw installation bundled with Qt + + QT_TOOLS_PATH="${QT_ROOT}/Tools" + + mingw_dir=$(find "${QT_TOOLS_PATH}" -maxdepth 1 -type d -name "mingw*" -print0 | xargs -0 ls -td | head -n 1) + + # Find returns . if the directory is not found + if [[ "$mingw_dir" == "." ]]; then + mingw_dir="" + fi + + echo "$mingw_dir" +} + +find_ninja() { + # Find a ninja installation bundled with Qt + QT_TOOLS_PATH="${QT_ROOT}/Tools" + + local ninja_path="" + + if [[ "$PLATFORM" == "windows" ]]; then + ninja_path="${QT_TOOLS_PATH}/Ninja/ninja.exe" + else + ninja_path="${QT_TOOLS_PATH}/Ninja/ninja" + fi + + echo "$ninja_path" +} + +get_zip() { + # Check if at least two arguments are provided + if [ "$#" -lt 2 ]; then + echo "Usage: get_zip [ ...]" + return 1 + fi + + mkdir -p ./tmp + + # URL of the zip file + url="$1" + shift + + zip_filename=$(basename "$url") + + # Temporary file to store the downloaded zip + tmp_zip=./tmp/"$zip_filename" + + # Download the zip file + curl -L "$url" -o "$tmp_zip" + if [ $? -ne 0 ]; then + echo "Failed to download the zip file from $url" + rm -f "$tmp_zip" + return 1 + fi + + # Sanity check: zip file is there + if [ ! -f "$tmp_zip" ]; then + echo "Error: The zip file '$tmp_zip' does not exist." + return 1 + fi + + # First, check that all the specified files exist in the zip archive + for arg in "$@" ; do + src_file="${arg%%:*}" + if ! unzip -l "$tmp_zip" | grep -q "$src_file"; then + echo "Error: The file '$src_file' does not exist in the zip archive $tmp_zip." + return 1 + fi + done + + # Extract the specified files to their destinations + while [ "$#" -gt 0 ]; do + src_dst="$1" + src_file="${src_dst%%:*}" + dst_dir="${src_dst##*:}" + + # Create the destination directory if it doesn't exist + mkdir -p "$dst_dir" + + unzip -j "$tmp_zip" "$src_file" -d "$dst_dir" + + shift + done + + # Clean up the temporary zip file + rm -rf "$tmp_zip" +} + +get_bass() { + echo "Checking for BASS..." + # If lib/bass.h exists, assume that BASS is already present + if [ -f "./lib/bass.h" ]; then + echo "BASS is installed." + return 0 + fi + + echo "Downloading BASS..." + if [[ "$PLATFORM" == "windows" ]]; then + get_zip https://www.un4seen.com/files/bass24.zip \ + c/bass.h:./lib \ + c/x64/bass.lib:./lib \ + x64/bass.dll:./bin + elif [[ "$PLATFORM" == "linux" ]]; then + get_zip https://www.un4seen.com/files/bass24-linux.zip \ + bass.h:./lib \ + libs/x86_64/libbass.so:./lib \ + libs/x86_64/libbass.so:./bin + elif [[ "$PLATFORM" == "macos" ]]; then + get_zip https://www.un4seen.com/files/bass24-osx.zip \ + bass.h:./lib \ + libbass.dylib:./lib + fi +} + +get_bassopus() { + echo "Checking for BASSOPUS..." + # If lib/bassopus.h exists, assume that BASSOPUS is already present + if [ -f "./lib/bassopus.h" ]; then + echo "BASSOPUS is installed." + return 0 + fi + + echo "Downloading BASSOPUS..." + if [[ "$PLATFORM" == "windows" ]]; then + get_zip https://www.un4seen.com/files/bassopus24.zip \ + c/bassopus.h:./lib \ + c/x64/bassopus.lib:./lib \ + x64/bassopus.dll:./bin + elif [[ "$PLATFORM" == "linux" ]]; then + get_zip https://www.un4seen.com/files/bassopus24-linux.zip \ + bassopus.h:./lib \ + libs/x86_64/libbassopus.so:./lib \ + libs/x86_64/libbassopus.so:./bin + elif [[ "$PLATFORM" == "macos" ]]; then + get_zip https://www.un4seen.com/files/bassopus24-osx.zip \ + bassopus.h:./lib \ + libbassopus.dylib:./lib + fi +} + +get_discordrpc() { + echo "Checking for Discord RPC..." + # If lib/discord_rpc.h exists, assume that Discord RPC is already present + if [ -f "./lib/discord_rpc.h" ]; then + echo "Discord RPC is installed." + return 0 + fi + + echo "Downloading Discord RPC..." + if [[ "$PLATFORM" == "windows" ]]; then + get_zip https://github.com/discordapp/discord-rpc/releases/download/v3.4.0/discord-rpc-win.zip \ + discord-rpc/win64-dynamic/lib/discord-rpc.lib:./lib \ + discord-rpc/win64-dynamic/bin/discord-rpc.dll:./bin \ + discord-rpc/win64-dynamic/include/discord_rpc.h:./lib \ + discord-rpc/win64-dynamic/include/discord_register.h:./lib + elif [[ "$PLATFORM" == "linux" ]]; then + get_zip https://github.com/discordapp/discord-rpc/releases/download/v3.4.0/discord-rpc-linux.zip \ + discord-rpc/linux-dynamic/lib/libdiscord-rpc.so:./lib \ + discord-rpc/linux-dynamic/lib/libdiscord-rpc.so:./bin \ + discord-rpc/linux-dynamic/include/discord_rpc.h:./lib \ + discord-rpc/linux-dynamic/include/discord_register.h:./lib + elif [[ "$PLATFORM" == "macos" ]]; then + get_zip https://github.com/discord/discord-rpc/releases/download/v3.4.0/discord-rpc-osx.zip \ + discord-rpc/osx-dynamic/lib/libdiscord-rpc.dylib:./lib \ + discord-rpc/osx-dynamic/include/discord_rpc.h:./lib \ + discord-rpc/osx-dynamic/include/discord_rpc.h:./lib + fi +} + +get_qtapng() { + echo "Checking for Qt apng plugin..." + apng_build_dir="./qtapng/plugins/imageformats" + imageformats_dir="./bin/imageformats" + APNG_LIB="" + if [[ "$PLATFORM" == "windows" ]]; then + APNG_LIB="qapng.dll" + elif [[ "$PLATFORM" == "linux" ]]; then + APNG_LIB="libqapng.so" + elif [[ "$PLATFORM" == "macos" ]]; then + APNG_LIB="libqapng.dylib" + else + echo "Unsupported platform: ${PLATFORM}" + return 1 + fi + + apng_dst_path="${imageformats_dir}/${APNG_LIB}" + + if [ -f "$apng_dst_path" ]; then + echo "Qt apng plugin is installed." + return 0 + fi + + if [ ! -d "./qtapng" ]; then + git clone git@github.com:jurplel/QtApng.git ./qtapng + fi + + cd ./qtapng + + $CMAKE . \ + -G Ninja \ + -DCMAKE_MAKE_PROGRAM="$NINJA" \ + -DCMAKE_PREFIX_PATH="$QT_PATH" \ + -DCMAKE_C_COMPILER="$CC" \ + -DCMAKE_CXX_COMPILER="$CXX" + + $NINJA + + cd "${SCRIPT_DIR}" + + mkdir -p "$imageformats_dir" + + apng_src_path="${apng_build_dir}/${APNG_LIB}" + + cp "$apng_src_path" "$apng_dst_path" +} + +get_themes() { + echo "Checking for themes..." + if [ -d "./bin/base/themes" ]; then + echo "Themes are installed." + return 0 + fi + + echo "Downloading themes..." + git clone git@github.com:AttorneyOnline/AO2-Themes.git ./bin/base/themes + + rm -rf ./bin/base/themes/.gitignore + rm -rf ./bin/base/themes/.gitattributes + rm -rf ./bin/base/themes/.git +} + +configure() { + # If -h is passed, print help + if [ "$#" -gt 0 ] && { [ "$1" = "-h" ] || [ "$1" = "--help" ]; }; then + print_help + exit 0 + fi + + # If clean is passed, remove all files from lib, bin and tmp + if [ "$#" -gt 0 ] && { [ "$1" = "clean" ]; }; then + echo "Cleaning up... removing lib, bin and tmp" + rm -rf ./lib/* + rm -rf ./bin/* + rm -rf ./tmp/* + rm -rf ./qtapng/ + exit 0 + fi + + echo "Platform: ${PLATFORM}" + + # If platform is unknown, terminate + if [ "$PLATFORM" == "unknown" ]; then + echo "Unknown platform. Aborting." + exit 1 + fi + + # Now we look for qt + QT_ROOT="" + + # If QT_ROOT=path is passed, use that + if [ "$#" -gt 0 ] && [ "${1%%=*}" = "QT_ROOT" ]; then + QT_ROOT="${1#*=}" + shift + # Try to find it otherwise + else + QT_ROOT=$(find_qt) + if [ -z "$QT_ROOT" ]; then + echo "Qt not found. Aborting."; exit 1; + fi + fi + if [ ! -d "$QT_ROOT" ]; then + echo "$QT_ROOT is not a directory. Aborting." + exit 1 + fi + echo "Using Qt root: $QT_ROOT" + + QT_PATH=$(find_qtpath) + if [ ! -d "$QT_PATH" ]; then + echo "$QT_PATH is not a directory. Aborting." + exit 1 + fi + echo "Using Qt installation: $QT_PATH" + + # Check for cmake, and prefer the one bundled with Qt + CMAKE=$(find_cmake) + if [ -z "$CMAKE" ]; then + echo "No cmake bundled with Qt found. Trying path..." + if ! check_command cmake ; then + echo "CMake not found. Aborting." + exit 1 + fi + CMAKE="cmake" + fi + + check_command "$CMAKE" --version || { echo "cmake not working. Aborting."; exit 1; } + echo "Using cmake: $CMAKE" + + # Find the compiler bundled in Qt + CC="" + CXX="" + # If we're on Windows, find mingw + if [[ "$PLATFORM" == "windows" ]]; then + MINGW_PATH=$(find_mingw) + if [ -z "$MINGW_PATH" ]; then + echo "MinGW not found. Aborting." + exit 1 + fi + CC="${MINGW_PATH}/bin/gcc.exe" + CXX="${MINGW_PATH}/bin/g++.exe" + else + # On non-Windows platforms, use the system compiler, as it's usually safe + CC="gcc" + CXX="g++" + fi + check_command "$CC" --version || { echo "CC not working. Aborting"; exit 1; } + echo "Using CC: $CC" + + check_command "$CXX" --version || { echo "CXX not working. Aborting"; exit 1; } + echo "Using CXX: $CXX" + + NINJA="" + NINJA=$(find_ninja) + check_command "$NINJA" --version || { echo "Ninja not working. Aborting"; exit 1; } + echo "Using Ninja: $NINJA" + + # Check basic dependencies + check_command curl --help || { echo "Command curl not found. Aborting"; exit 1; } + check_command unzip --help || { echo "Command unzip not found. Aborting"; exit 1; } + + # Make sure key folders exist + mkdir -p ./tmp/ + mkdir -p ./lib/ + mkdir -p ./bin/ + + # Get the dependencies + get_bass + get_bassopus + get_discordrpc + get_qtapng + get_themes + + # Typically, IDEs like running cmake themselves, but we need the binary to fix dependencies correctly + FULL_CMAKE_CMD="\ +$CMAKE . \ +-G Ninja \ +-DCMAKE_MAKE_PROGRAM=${NINJA} \ +-DCMAKE_PREFIX_PATH=${QT_PATH} \ +-DCMAKE_BUILD_TYPE=${BUILD_CONFIG} \ +-DCMAKE_C_COMPILER=${CC} \ +-DCMAKE_CXX_COMPILER=${CXX}" + + $FULL_CMAKE_CMD + $NINJA + + if [[ "$PLATFORM" == "windows" ]]; then + echo "Fixing dependencies..." + windeployqt="${QT_PATH}/bin/windeployqt.exe" + "$windeployqt" --no-quick-import --no-translations --no-compiler-runtime --no-opengl-sw ./bin/Attorney_Online.exe + fi + + echo "Configuration and build complete." + echo "Full cmake cmd: $FULL_CMAKE_CMD" + echo "$FULL_CMAKE_CMD" > cmake_cmd.txt +} + +configure "$@" -- cgit