From 0f11ab8ecb4fe65f5bcdb684e253806551c4404e Mon Sep 17 00:00:00 2001 From: krcroft Date: Sat, 23 Nov 2019 19:54:19 -0800 Subject: [PATCH] Refactor the build and list-packages scripts Until now the build and package scripts have supported several architectures, compilers, build types, package-managers, and bit-depth targets. The code might be maintainable if left as-such, however we have plans to continue expanding the number of architectures (ARM, PPC, ... ), operating systems (Android, BSDs, ...), and build variations amung those. The scripts (regardless of language) would only grow in complexity as more variations are added. Thus, we needed a solution that can scale without adding complexity. To achieve this, the scripts were refactored as follows: - all "data" was moved out of code into configuration files - A back-end "Automator" engine was written to parse the data based on generic variables fed to it by a front-end script - build.sh and list-packages.sh were re-authored as thin front-end scripts that drive the automator - Their CLI's were retained so there has been very little change needed to the CI invocation lines. The only changes have been to clarify the existing arguments improved based on feedback, ie: --build-type release, --build-type debug instead of fast, small --- .gitignore | 10 + scripts/automator/build/clang-darwin_x86_64 | 8 + scripts/automator/build/clang-defaults | 16 + scripts/automator/build/clang-linux_x86_64 | 13 + scripts/automator/build/clang-msys_nt_x86_64 | 5 + scripts/automator/build/compiler-clang | 0 scripts/automator/build/compiler-defaults | 14 + scripts/automator/build/compiler-gcc | 0 scripts/automator/build/gcc-darwin_x86_64 | 15 + scripts/automator/build/gcc-defaults | 17 + scripts/automator/build/gcc-linux_x86_64 | 14 + scripts/automator/build/gcc-msys_nt_x86_64 | 3 + scripts/automator/build/machine-x86_64 | 3 + scripts/automator/build/os-darwin | 5 + scripts/automator/build/os-defaults | 57 ++ scripts/automator/build/os-linux | 2 + scripts/automator/build/os-msys_nt | 3 + scripts/automator/main.sh | 120 ++++ scripts/automator/packages/clang-brew | 3 + scripts/automator/packages/clang-defaults | 2 + scripts/automator/packages/clang-macports | 2 + scripts/automator/packages/clang-msys2 | 4 + scripts/automator/packages/clang-vcpkg | 4 + scripts/automator/packages/gcc-apt | 2 + scripts/automator/packages/gcc-defaults | 1 + scripts/automator/packages/gcc-msys2 | 3 + scripts/automator/packages/gcc-vcpkg | 4 + scripts/automator/packages/manager-apt | 2 + scripts/automator/packages/manager-brew | 3 + scripts/automator/packages/manager-defaults | 11 + scripts/automator/packages/manager-dnf | 2 + scripts/automator/packages/manager-macports | 3 + scripts/automator/packages/manager-msys2 | 7 + scripts/automator/packages/manager-pacman | 4 + scripts/automator/packages/manager-vcpkg | 2 + scripts/automator/packages/manager-zypper | 10 + scripts/build.md | 13 +- scripts/build.sh | 559 ++----------------- scripts/list-build-dependencies.sh | 229 ++------ 39 files changed, 478 insertions(+), 697 deletions(-) create mode 100644 scripts/automator/build/clang-darwin_x86_64 create mode 100644 scripts/automator/build/clang-defaults create mode 100644 scripts/automator/build/clang-linux_x86_64 create mode 100644 scripts/automator/build/clang-msys_nt_x86_64 create mode 100644 scripts/automator/build/compiler-clang create mode 100644 scripts/automator/build/compiler-defaults create mode 100644 scripts/automator/build/compiler-gcc create mode 100644 scripts/automator/build/gcc-darwin_x86_64 create mode 100644 scripts/automator/build/gcc-defaults create mode 100644 scripts/automator/build/gcc-linux_x86_64 create mode 100644 scripts/automator/build/gcc-msys_nt_x86_64 create mode 100644 scripts/automator/build/machine-x86_64 create mode 100644 scripts/automator/build/os-darwin create mode 100644 scripts/automator/build/os-defaults create mode 100644 scripts/automator/build/os-linux create mode 100644 scripts/automator/build/os-msys_nt create mode 100644 scripts/automator/main.sh create mode 100644 scripts/automator/packages/clang-brew create mode 100644 scripts/automator/packages/clang-defaults create mode 100644 scripts/automator/packages/clang-macports create mode 100644 scripts/automator/packages/clang-msys2 create mode 100644 scripts/automator/packages/clang-vcpkg create mode 100644 scripts/automator/packages/gcc-apt create mode 100644 scripts/automator/packages/gcc-defaults create mode 100644 scripts/automator/packages/gcc-msys2 create mode 100644 scripts/automator/packages/gcc-vcpkg create mode 100644 scripts/automator/packages/manager-apt create mode 100644 scripts/automator/packages/manager-brew create mode 100644 scripts/automator/packages/manager-defaults create mode 100644 scripts/automator/packages/manager-dnf create mode 100644 scripts/automator/packages/manager-macports create mode 100644 scripts/automator/packages/manager-msys2 create mode 100644 scripts/automator/packages/manager-pacman create mode 100644 scripts/automator/packages/manager-vcpkg create mode 100644 scripts/automator/packages/manager-zypper diff --git a/.gitignore b/.gitignore index 8357aa23..552a2a3a 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,16 @@ stamp-h1 # Other compile build.log +clean.log +make.log +.previous_build +.current_build # Visual Studio .vs + +# Common editor temp/backup files +*~ +*.swp +*.tmp + diff --git a/scripts/automator/build/clang-darwin_x86_64 b/scripts/automator/build/clang-darwin_x86_64 new file mode 100644 index 00000000..9b46a13b --- /dev/null +++ b/scripts/automator/build/clang-darwin_x86_64 @@ -0,0 +1,8 @@ +ld="ld" + +TYPES+=("msan" "usan") +cflags_msan=("${cflags_debug[@]}" "-fsanitize-recover=all" "-fsanitize=memory" "-fno-omit-frame-pointer") +cflags_usan=("${cflags_debug[@]}" "-fsanitize-recover=all" "-fsanitize=undefined") + +MODIFIERS+=("lto") +cflags_lto=("-flto=thin") diff --git a/scripts/automator/build/clang-defaults b/scripts/automator/build/clang-defaults new file mode 100644 index 00000000..5792c396 --- /dev/null +++ b/scripts/automator/build/clang-defaults @@ -0,0 +1,16 @@ +# Tool overrides +cc="clang${postfix}" +cxx="clang++${postfix}" + +# Flag additions +TYPES+=("debug" "profile") +cflags+=("-fcolor-diagnostics") +cflags_release=("${cflags[@]}" "-Os") +cflags_debug=("${cflags[@]}" "-g" "-Og" "-fno-omit-frame-pointer") +cflags_profile=("${cflags_debug[@]}" "-fprofile-instr-generate" "-fcoverage-mapping") + + +# Modifier additions +MODIFIERS=("fdo") +ldflags_fdo=("-fprofile-instr-generate") +cflags_fdo=("-fprofile-sample-use=${FDO_FILE:-}") diff --git a/scripts/automator/build/clang-linux_x86_64 b/scripts/automator/build/clang-linux_x86_64 new file mode 100644 index 00000000..0b37c67d --- /dev/null +++ b/scripts/automator/build/clang-linux_x86_64 @@ -0,0 +1,13 @@ +# Tool additions +ar="llvm-ar${postfix}" +ld="llvm-link${postfix}" +ranlib="llvm-ranlib${postfix}" + +# Build additions +TYPES+=("msan" "usan") +cflags_msan=("${cflags_debug[@]}" "-fsanitize-recover=all" "-fsanitize=memory" "-fno-omit-frame-pointer") +cflags_usan=("${cflags_debug[@]}" "-fsanitize-recover=all" "-fsanitize=undefined") + +# Modifier additions +MODIFIERS+=("lto") +cflags_lto=("-O2" "-flto=thin") diff --git a/scripts/automator/build/clang-msys_nt_x86_64 b/scripts/automator/build/clang-msys_nt_x86_64 new file mode 100644 index 00000000..f183a990 --- /dev/null +++ b/scripts/automator/build/clang-msys_nt_x86_64 @@ -0,0 +1,5 @@ +# Flag additions +ar="llvm-ar${postfix}" +ld="llvm-link${postfix}" +ranlib="llvm-ranlib${postfix}" +ldflags+=("-static-libgcc" "-static-libstdc++") diff --git a/scripts/automator/build/compiler-clang b/scripts/automator/build/compiler-clang new file mode 100644 index 00000000..e69de29b diff --git a/scripts/automator/build/compiler-defaults b/scripts/automator/build/compiler-defaults new file mode 100644 index 00000000..39be7a47 --- /dev/null +++ b/scripts/automator/build/compiler-defaults @@ -0,0 +1,14 @@ +# Tools and flags for all compilers +VARIABLES=("ar" "cc" "cxx" "ld" "ranlib" "cflags" "ldflags" "libs") +ar="" +cc="" +cxx="" +ld="" +ranlib="" +cflags=("-Wall" "-pipe") +ldflags=("") +libs=("") + +# Builds for all compilers +TYPES=("release") +cflags_release=("${cflags[@]}") diff --git a/scripts/automator/build/compiler-gcc b/scripts/automator/build/compiler-gcc new file mode 100644 index 00000000..e69de29b diff --git a/scripts/automator/build/gcc-darwin_x86_64 b/scripts/automator/build/gcc-darwin_x86_64 new file mode 100644 index 00000000..1a55e14d --- /dev/null +++ b/scripts/automator/build/gcc-darwin_x86_64 @@ -0,0 +1,15 @@ +# Tool overrides +ar="ar" +ranlib="ranlib" + +# Build additions +TYPES+=("asan" "uasan" "usan" "tsan") +cflags_asan=("${cflags_debug[@]}" "-fsanitize=address") +cflags_uasan=("${cflags_debug[@]}" "-fsanitize=address,undefined" "-fsanitize-recover=signed-integer-overflow") +cflags_usan=("${cflags_debug[@]}" "-fsanitize=undefined" "-fsanitize-recover=signed-integer-overflow") +cflags_tsan=("${cflags_debug[@]}" "-fsanitize=thread") + +# Modifier additions +MODIFIERS+=("lto") +cflags_lto=("-flto") +ldflags_lto=("${cflags[@]}" "-flto") diff --git a/scripts/automator/build/gcc-defaults b/scripts/automator/build/gcc-defaults new file mode 100644 index 00000000..aa9e4cff --- /dev/null +++ b/scripts/automator/build/gcc-defaults @@ -0,0 +1,17 @@ +# Tool overrides +ar="gcc-ar${postfix}" +cc="gcc${postfix}" +cxx="g++${postfix}" +ld="gcc${postfix}" +ranlib="gcc-ranlib${postfix}" + +# Flag additions +TYPES+=("debug" "profile") +cflags+=("-fstack-protector" "-fdiagnostics-color=always") +cflags_release=("${cflags[@]}" "-Ofast" "-ffunction-sections" "-fdata-sections") +cflags_debug=("${cflags[@]}" "-g" "-Og" "-fno-omit-frame-pointer") +cflags_profile=("${cflags_debug[@]}" "-pg") + +# Modifier additions +MODIFIERS=("fdo") +cflags_fdo=("-fauto-profile=${FDO_FILE:-}") diff --git a/scripts/automator/build/gcc-linux_x86_64 b/scripts/automator/build/gcc-linux_x86_64 new file mode 100644 index 00000000..4da89b92 --- /dev/null +++ b/scripts/automator/build/gcc-linux_x86_64 @@ -0,0 +1,14 @@ +# Tool additions +ldflags+=("-Wl,--as-needed") + +# Build additions +TYPES+=("asan" "uasan" "usan" "tsan") +cflags_asan=("${cflags_debug[@]}" "-fsanitize=address") +cflags_uasan=("${cflags_debug[@]}" "-fsanitize=address,undefined" "-fsanitize-recover=signed-integer-overflow") +cflags_usan=("${cflags_debug[@]}" "-fsanitize=undefined" "-fsanitize-recover=signed-integer-overflow") +cflags_tsan=("${cflags_debug[@]}" "-fsanitize=thread") + +# Modifier additions +MODIFIERS+=("lto") +cflags_lto=("-flto") +ldflags_lto=("${cflags[@]}" "-flto=$(( $(nproc) + 2 ))") diff --git a/scripts/automator/build/gcc-msys_nt_x86_64 b/scripts/automator/build/gcc-msys_nt_x86_64 new file mode 100644 index 00000000..785485f2 --- /dev/null +++ b/scripts/automator/build/gcc-msys_nt_x86_64 @@ -0,0 +1,3 @@ +# Flag additions +ldflags+=("-Wl,--as-needed" "-static-libgcc" "-static-libstdc++") + diff --git a/scripts/automator/build/machine-x86_64 b/scripts/automator/build/machine-x86_64 new file mode 100644 index 00000000..052fa22c --- /dev/null +++ b/scripts/automator/build/machine-x86_64 @@ -0,0 +1,3 @@ +# Modifier additions universal for gcc and clang, but specific to x86_64: +MODIFIERS+=("native") +cflags_native=("-march=native") diff --git a/scripts/automator/build/os-darwin b/scripts/automator/build/os-darwin new file mode 100644 index 00000000..de969cee --- /dev/null +++ b/scripts/automator/build/os-darwin @@ -0,0 +1,5 @@ +# Tool additions and overrides for Darwin, regardless of compiler +ar="ar" +ranlib="ranlib" +function make_binary() { make -j$(sysctl -n hw.physicalcpu) 2>&1 | tee build.log; } +dependencies=("otool" "-L" "${executable}") diff --git a/scripts/automator/build/os-defaults b/scripts/automator/build/os-defaults new file mode 100644 index 00000000..cf0d6028 --- /dev/null +++ b/scripts/automator/build/os-defaults @@ -0,0 +1,57 @@ +# Steps in-common to all OSes, plus some helper variables and functions. + +STEPS=("pre_build" "clean" "autogen" "configure" "make_binary" "strip_binary" "dependencies" "post_build") + +executable="src/dosbox" +dependencies=("ldd" "${executable}") + +function pre_build() { + cd ../.. + underline "Environment" + echo "[$("${CC}" --version | head -1)]" + for v in "${VARIABLES[@]}"; do + vupper=$(upper "${v}") + echo "${vupper}=\"$(eval echo \$"${vupper}")\"" + done + underline "Launching" +} + +function stamp() { + echo "${compiler}-${selected_type}-${modifiers[*]}" +} + +function autogen() { + if [[ ! -f configure || configure.ac -nt configure ]]; then + ./autogen.sh + fi +} + +function configure() { + if [[ ! -f Makefile || ! -f .previous_build || configure -nt Makefile ]]; then + export CXXFLAGS="${CFLAGS}" + ./configure --enable-core-inline + fi +} + +function strip_binary() { + if [[ "${selected_type}" == "release" ]]; then + strip "${executable}" + fi +} + +function post_build() { + underline "Binary" "-" + ls -1lh "${executable}" + stamp > .previous_build +} + +function clean() { + stamp > .current_build + if [[ -f Makefile ]]; then + if [[ ! -f .previous_build ]] || ! diff -q .previous_build .current_build &> /dev/null; then + rm -f .previous_build + echo "cleaning, this is a different build type" + make clean &> clean.log || cat clean.log + fi + fi +} diff --git a/scripts/automator/build/os-linux b/scripts/automator/build/os-linux new file mode 100644 index 00000000..a831d4d3 --- /dev/null +++ b/scripts/automator/build/os-linux @@ -0,0 +1,2 @@ +function make_binary() { make -j$(nproc) 2>&1 | tee build.log; } + diff --git a/scripts/automator/build/os-msys_nt b/scripts/automator/build/os-msys_nt new file mode 100644 index 00000000..9cfcbc5a --- /dev/null +++ b/scripts/automator/build/os-msys_nt @@ -0,0 +1,3 @@ +function make_binary() { make -j$(nproc) 2>&1 | tee build.log; } +executable="src/dosbox.exe" + diff --git a/scripts/automator/main.sh b/scripts/automator/main.sh new file mode 100644 index 00000000..19b54a77 --- /dev/null +++ b/scripts/automator/main.sh @@ -0,0 +1,120 @@ +#!/bin/bash + +# Copyright (c) 2019 Kevin R Croft +# SPDX-License-Identifier: GPL-2.0-or-later + +# Automator is a generic automation tool that helps separate data +# from logical code. It uses one or more "variables" files placed +# in a single sub-directory, that are sourced in logical succession, +# such as variables defined in earler files are either added-to or +# overridden in subsequent files. +# +# For a thorough example, see scripts/build.sh and its data files +# in scripts/automator/build. +# +# TODO: This script manages variables using eval meta-programming. +# Although the syntax is quite readable under bash 4.x, +# we have limitted our syntax to the uglier and heavier bash 3.x +# because Apple is still only shipping bash 3.x, even on their +# latest operating system (Nov-2019). +# +# Future work might involve switching this to python and using YAML +# syntax in the variables files. Python's dictionaries can be +# merged or have their values overridden, and key names can be readily +# manipulated. +# +set -euo pipefail + +function underline() { + echo "" + echo "$1" + echo "${1//?/${2:--}}" +} + +function lower() { + echo "${1}" | tr '[:upper:]' '[:lower:]' +} + +function upper() { + echo "${1}" | tr '[:lower:]' '[:upper:]' +} + +function arg_error() { + local PURPLE='\033[0;34m' + local BLACK='\033[0;30m' + local ON_WHITE='\033[47m' + local NO_COLOR='\033[0m' + >&2 echo -e "Please specify the ${BLACK}${ON_WHITE}${1}${NO_COLOR} argument with one of: ${PURPLE}${2}${NO_COLOR}" + exit 1 +} + +function import() { # arguments: category instance + category=$(lower "${1}") + instance=$(lower "${2}") + if [[ -z "$instance" ]]; then + instances=( "$(find "${data_dir}" -name "${category}-*" -a ! -name '*defaults' | sed 's/.*-//' | xargs)" ) + arg_error "--${category}" "${instances[*]}" + else for instance in defaults "${instance}"; do + varfile="${data_dir}/${category}-${instance}" + # shellcheck disable=SC1090,SC1091 + if [[ -f "$varfile" ]]; then source "$varfile" + else >&2 echo "${varfile} does not exist, skipping"; fi; done + fi +} + +function construct_environment() { + # underline "Environment" + for base_var in "${VARIABLES[@]}"; do + # First check if we have a build-specific variable + # shellcheck disable=SC2154 + if [[ -n "$(eval 'echo ${'"${base_var}_${selected_type}"'[*]:-}')" ]]; then + var_name="${base_var}_${selected_type}" + # Otherwise fallback to the default variable + else var_name="${base_var}"; fi + + # Aggregate any modifiers, which are stand-alone arguments + mod_values="" + # shellcheck disable=SC2154 + for mod_upper in "${modifiers[@]}"; do + mod=$(lower "${mod_upper}") + # Mods can only add options to existing VARs, so we check for those + if [[ -n "$(eval 'echo ${'"${base_var}_${mod}"'[*]:-}')" ]]; then + var_with_mod="${base_var}_${mod}" + # shellcheck disable=SC2034 + mod_values=$(eval 'echo ${mod_values} ${'"${var_with_mod}"'[*]}') + fi + done + + # Expand our variable array (or scalar) and combine it with our aggregated + # modification string. Echo takes care of spacing out our variables without + # explicit padding, because it either drops empty variables or adds spaces + # between them if they exist. + # shellcheck disable=SC2034 + combined=$(eval 'echo ${'"${var_name}"'[*]} ${mod_values}') + env_var=$(upper "${base_var}") + eval 'export '"${env_var}"'="${combined}"' + # echo "${env_var}=\"$(eval echo \$"${env_var}")\"" + done +} + +function perform_steps() { + # underline "Launching" + for step in "${STEPS[@]}"; do + if type -t "$step" | grep -q function; then "$step" + else + # eval 'echo ${'"${step}"'[*]}' + eval '${'"${step}"'[*]}' + fi + done +} + +function main() { + cd "$(dirname "$0")/automator" + if [[ -z "${data_dir:-}" ]]; then data_dir="$(basename "$0" '.sh')"; fi + parse_args "$@" + construct_environment + perform_steps +} + +main "$@" + diff --git a/scripts/automator/packages/clang-brew b/scripts/automator/packages/clang-brew new file mode 100644 index 00000000..03221244 --- /dev/null +++ b/scripts/automator/packages/clang-brew @@ -0,0 +1,3 @@ +# Brew does not supply "clang", so exclude it here +compiler="" + diff --git a/scripts/automator/packages/clang-defaults b/scripts/automator/packages/clang-defaults new file mode 100644 index 00000000..3e13216f --- /dev/null +++ b/scripts/automator/packages/clang-defaults @@ -0,0 +1,2 @@ +compiler=(clang${postfix}) + diff --git a/scripts/automator/packages/clang-macports b/scripts/automator/packages/clang-macports new file mode 100644 index 00000000..087b8d4a --- /dev/null +++ b/scripts/automator/packages/clang-macports @@ -0,0 +1,2 @@ +# macports doesn't supply Clang, so knock it out here +compiler="" diff --git a/scripts/automator/packages/clang-msys2 b/scripts/automator/packages/clang-msys2 new file mode 100644 index 00000000..bf1117b2 --- /dev/null +++ b/scripts/automator/packages/clang-msys2 @@ -0,0 +1,4 @@ +# Under MSYS2, only the 'default' version is available, so we don't postfix the package +compiler="mingw-w64-${pkg_type}-${selected_type}" + + diff --git a/scripts/automator/packages/clang-vcpkg b/scripts/automator/packages/clang-vcpkg new file mode 100644 index 00000000..3ec49cc7 --- /dev/null +++ b/scripts/automator/packages/clang-vcpkg @@ -0,0 +1,4 @@ +# vcpkg doesn't provide clang or gcc, because it assumes you're using MS VisualStudio. +# So we knock out the compiler. +compiler="" + diff --git a/scripts/automator/packages/gcc-apt b/scripts/automator/packages/gcc-apt new file mode 100644 index 00000000..1b851dc9 --- /dev/null +++ b/scripts/automator/packages/gcc-apt @@ -0,0 +1,2 @@ +compiler=(g++${postfix}) + diff --git a/scripts/automator/packages/gcc-defaults b/scripts/automator/packages/gcc-defaults new file mode 100644 index 00000000..99173883 --- /dev/null +++ b/scripts/automator/packages/gcc-defaults @@ -0,0 +1 @@ +compiler=(gcc${postfix}) diff --git a/scripts/automator/packages/gcc-msys2 b/scripts/automator/packages/gcc-msys2 new file mode 100644 index 00000000..fb38a352 --- /dev/null +++ b/scripts/automator/packages/gcc-msys2 @@ -0,0 +1,3 @@ +# Under MSYS2 only the 'default' version of gcc is available, so we don't postfix it with the version +compiler="mingw-w64-${pkg_type}-${selected_type}" + diff --git a/scripts/automator/packages/gcc-vcpkg b/scripts/automator/packages/gcc-vcpkg new file mode 100644 index 00000000..533ed5dc --- /dev/null +++ b/scripts/automator/packages/gcc-vcpkg @@ -0,0 +1,4 @@ +# vcpkg doesn't provide clang or gcc, because it assumes you're using MS VisualStudio. +# So we knock out the compiler. +compiler="" + diff --git a/scripts/automator/packages/manager-apt b/scripts/automator/packages/manager-apt new file mode 100644 index 00000000..6c136b28 --- /dev/null +++ b/scripts/automator/packages/manager-apt @@ -0,0 +1,2 @@ +# Package repo: https://packages.ubuntu.com/ +packages+=(xvfb libtool build-essential libsdl1.2-dev libsdl-net1.2-dev libopusfile-dev) diff --git a/scripts/automator/packages/manager-brew b/scripts/automator/packages/manager-brew new file mode 100644 index 00000000..14d21645 --- /dev/null +++ b/scripts/automator/packages/manager-brew @@ -0,0 +1,3 @@ +# Package repo: https://formulae.brew.sh/ +delim="@" +packages+=(coreutils autogen autoconf automake pkg-config libpng sdl sdl_net opusfile) diff --git a/scripts/automator/packages/manager-defaults b/scripts/automator/packages/manager-defaults new file mode 100644 index 00000000..b18fa423 --- /dev/null +++ b/scripts/automator/packages/manager-defaults @@ -0,0 +1,11 @@ +VARIABLES=(packages bits delim compiler) +TYPES=(gcc clang) + +packages=(autoconf-archive zstd) +delim="-" +compiler="" + +STEPS=(print) +function print() { + echo "${PACKAGES[*]}" "${COMPILER}" +} diff --git a/scripts/automator/packages/manager-dnf b/scripts/automator/packages/manager-dnf new file mode 100644 index 00000000..442183fd --- /dev/null +++ b/scripts/automator/packages/manager-dnf @@ -0,0 +1,2 @@ +# Package repo: https://apps.fedoraproject.org/packages/ +packages+=(xvfb libtool SDL SDL_net-devel opusfile-devel) diff --git a/scripts/automator/packages/manager-macports b/scripts/automator/packages/manager-macports new file mode 100644 index 00000000..fe0b99ad --- /dev/null +++ b/scripts/automator/packages/manager-macports @@ -0,0 +1,3 @@ +# Package repo: https://www.macports.org/ports.php?by=name +delim="" +packages+=(coreutils autogen autoconf automake pkgconfig libpng libsdl libsdl_net opusfile) diff --git a/scripts/automator/packages/manager-msys2 b/scripts/automator/packages/manager-msys2 new file mode 100644 index 00000000..d5646a7a --- /dev/null +++ b/scripts/automator/packages/manager-msys2 @@ -0,0 +1,7 @@ +# Package repo: https://packages.msys2.org/base +# MSYS2 only supports the current latest releases of Clang and GCC, so we disable version customization +packages+=(autogen autoconf base-devel automake-wrapper binutils) +pkg_type=$([[ "${bits}" == "64" ]] && echo "x86_64" || echo "i686") +for pkg in pkg-config libtool libpng zlib SDL SDL_net opusfile; do + packages+=("mingw-w64-${pkg_type}-${pkg}") +done diff --git a/scripts/automator/packages/manager-pacman b/scripts/automator/packages/manager-pacman new file mode 100644 index 00000000..7ae2cb85 --- /dev/null +++ b/scripts/automator/packages/manager-pacman @@ -0,0 +1,4 @@ +# Package repo: https://www.archlinux.org/packages/ +# Arch offers 32-bit versions of SDL (but not others) +packages+=(xvfb libtool sdl_net opusfile) +[[ "${bits}" == "32" ]] && packages+=(lib32-sdl) || packages+=(sdl) diff --git a/scripts/automator/packages/manager-vcpkg b/scripts/automator/packages/manager-vcpkg new file mode 100644 index 00000000..7cff149d --- /dev/null +++ b/scripts/automator/packages/manager-vcpkg @@ -0,0 +1,2 @@ +# Package repo: https://repology.org/projects/?inrepo=vcpkg +packages+=(libpng sdl1 sdl1-net opusfile) diff --git a/scripts/automator/packages/manager-zypper b/scripts/automator/packages/manager-zypper new file mode 100644 index 00000000..44bcdbeb --- /dev/null +++ b/scripts/automator/packages/manager-zypper @@ -0,0 +1,10 @@ +# Package repo: https://pkgs.org/ +# openSUSE offers 32-bit versions of SDL and SDL_net (but not others) +packages+=(devel_basis xvfb libtool opusfile) + +if [[ "${bits}" == "32" ]]; then + packages+=(libSDL-devel-32bit libSDL_net-devel-32bit) +else + packages+=(SDL SDL_net) +fi + diff --git a/scripts/build.md b/scripts/build.md index c2b85d73..0db2bead 100644 --- a/scripts/build.md +++ b/scripts/build.md @@ -57,7 +57,7 @@ Use of both scripts is described below. `./scripts/list-build-dependencies.sh -p msys2 | xargs pacman -S --noconfirm` 1. Launch the build script with default settings: - `./scripts/build.sh --bin-path /mingw64/bin` + `./scripts/build/run.sh --bin-path /mingw64/bin` ## MacOS Installation and Usage @@ -131,10 +131,15 @@ options to the **list-build-dependencies.sh** and **build.sh** scripts: After building, your `dosbox` or `dosbox.exe` binary will reside inside `./dosbox-staging/src/`. Build flags you might be interested in: -* `--release debug`, to build a binary containing debug symbols (instead of **fast** or **small**) * `--lto`, perform optimizations across the entire object space instead of per-file (Only available on Mac and Linux) - -The above flags are othogonal and thus can be mixed-and-matched as desired. +* `--release debug`, to build a binary containing debug symbols + * You can run the resulting binary in the GNU debugger: `gdb /path/to/dosbox`, followed by `start mygame.bat` +* `--release profile`, to generate performance statistics + * Instructions are provided after the build completes, which describe how to generate and process the profiling data +* `--release `, to build a binary that performs dynamic code-analysis at runtime (Linux and macOS) + * see `./scripts/build.sh --help` for a list of sanitizer-types that are available + * Run your binary like normal and it will generate output describing problematic behavior + * Some sanitizers accept runtime options via an environment variables, such as `ASAN_OPTIONS`, described here: https://github.com/google/sanitizers/wiki/AddressSanitizerFlags If you want to run multiple back-to-back builds from the same directory with different settings then add the `--clean` flag to ensure previous objects and binaries are removed. diff --git a/scripts/build.sh b/scripts/build.sh index 21aa3863..a2f80c48 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,518 +1,61 @@ #!/bin/bash -## -# -# Copyright (c) 2019 Kevin R. Croft -# SPDX-License-Identifier: GPL-2.0-or-later -# -# This script builds DOSBox within supported environments including -# MacOS, Ubuntu Linux, and MSYS2 using specified compilers and release types. -# -# For automation without prompts, Windows should have User Account Control (UAC) -# disabled, which matches the configuration of GitHub'Windows VMs, described here: -# https://help.github.com/en/articles/virtual-environments-for-github-actions -# -# See the usage block below for details or run it with the -h or --help arguments. -# -# In general, this script adheres to Google's shell scripting style guide -# (https://google.github.io/styleguide/shell.xml), however some deviations (such as -# tab indents instead of two-spaces) are used to fit with DOSBox's in-practice" -# coding style. -# +# Copyright (c) 2019 Kevin R Croft +# SPDX-License-Identifier: GPL-2.0-or-later +# This script builds the software for the given build-type (release, +# debug, ... ) and compiler (gcc or clang). +# +# If run without arguments, the script asks for required arguments one +# by one, which includes the above two (--compiler and --build-type). +# +# Optional arguments include the version of compiler and additional +# build modifiers such as link-time-optimizations (--modifier lto), +# feedback-directed-optimizations (--modifier fdo), and taking advantage +# of the building-machine's full instructions sets (--modifier native). +# All modifiers are available simulatenously. +# +# Usage examples: +# $ ./build.sh # asks for a compiler +# $ ./build.sh --compiler gcc # asks for a build-type +# $ ./build.sh --compiler clang --build-type debug # builds! +# $ ./build.sh -c gcc -t release -m lto -m native # builds! +# +# This script makes use of the automator package, see automator/main.sh. +# set -euo pipefail -readonly INVOCATION="${0}" -readonly IFS=$'\n\t' - -function usage() { - if [ -n "${1}" ]; then - errcho "${1}" - fi - local script - script=$(basename "${INVOCATION}") - echo "Usage: ${script} [-b 32|64] [-c gcc|clang] [-f linux|macos|msys2] [-d] [-l]" - echo " [-p /custom/bin] [-u #] [-r fast|small|debug] [-s /your/src] [-t #]" - echo "" - echo " FLAG Description Default" - echo " ----------------------- ----------------------------------------------------- -------" - echo " -b, --bit-depth Build a 64 or 32 bit binary [$(print_var "${BITS}")]" - echo " -c, --compiler Choose either gcc or clang [$(print_var "${COMPILER}")]" - echo " -f, --force-system Force the system to be linux, macos, or msys2 [$(print_var "${SYSTEM}")]" - echo " -d, --fdo Use Feedback-Directed Optimization (FDO) data [$(print_var "${FDO}")]" - echo " -l, --lto Perform Link-Time-Optimizations (LTO) [$(print_var "${LTO}")]" - echo " -p, --bin-path Prepend PATH with the one provided to find executables [$(print_var "${BIN_PATH}")]" - echo " -u, --compiler-version Customize the compiler postfix (ie: 9 -> gcc-9) [$(print_var "${COMPILER_VERSION}")]" - echo " -r, --release Build a fast, small, or debug release [$(print_var "${RELEASE}")]" - echo " -s, --src-path Enter a different source directory before building [$(print_var "${SRC_PATH}")]" - echo " -t, --threads Override the number of threads with which to compile [$(print_var "${THREADS}")]" - echo " -v, --version Print the version of this script [$(print_var "${SCRIPT_VERSION}")]" - echo " -x, --clean Clean old objects prior to building [$(print_var "${CLEAN}")]" - echo " -h, --help Print this usage text" - echo "" - echo "Example: ${script} -b 32 --compiler clang -u 8 --bin-path /mingw64/bin -r small --lto" - echo "" - echo "Note: the last value will take precendent if duplicate flags are provided." - exit 1 -} function parse_args() { - set_defaults + # Gather the parameters that define this build + postfix="" + modifiers=("") while [[ "${#}" -gt 0 ]]; do case ${1} in - -b|--bit-depth) BITS="${2}"; shift;shift;; - -c|--compiler) COMPILER="${2}"; shift;shift;; - -d|--fdo) FDO="true"; shift;; - -f|--force-system) SYSTEM="${2}"; shift;shift;; - -l|--lto) LTO="true"; shift;; - -p|--bin-path) BIN_PATH="${2}"; shift;shift;; - -u|--compiler-version) COMPILER_VERSION="${2}";shift;shift;; - -r|--release) RELEASE="${2}"; shift;shift;; - -s|--src-path) SRC_PATH="${2}"; shift;shift;; - -t|--threads) THREADS="${2}"; shift;shift;; - -v|--version) print_version; shift;; - -x|--clean) CLEAN="true"; shift;; - -h|--help) usage "Show usage"; shift;; - *) usage "Unknown parameter: ${1}"; shift;shift;; + -c|--compiler) compiler="${2}"; shift 2;; + -v|--version-postfix) postfix="-${2}"; shift 2;; + -t|--build-type) selected_type="${2}"; shift 2;; + -m|--modifier) modifiers+=("${2}"); shift 2;; + -p|--bin-path) PATH="${2}:${PATH}"; shift 2;; + *) >&2 echo "Unknown parameter: ${1}"; exit 1; shift 2;; esac; done + + # Import our settings and report missing values + machine="$(uname -m | sed 's/-.*//')"; import machine "${machine}" + os="$(uname -s | sed 's/-.*//')"; import os "${os}" + import compiler "${compiler:-}" + import "${compiler:-}" "${os}_${machine}" + if [[ -z "${selected_type:-}" ]]; then arg_error "--build-type" "${TYPES[*]}"; fi + + # Create a pretty modifier string that we can add to our build-type + printf -v mod_string '+%s' "${modifiers[@]:1}" + if [[ "${mod_string}" == "+" ]]; then mod_string=""; fi + + # Print a summary of our build configuration + underline "Compiling a ${selected_type}${mod_string} build using "` + `"${compiler}${postfix} on ${os}-${machine}" "=" + + # Ensure our selected_type is lower-case before proceeding + selected_type=$(lower "${selected_type}") } -function set_defaults() { - # variables that are directly set via user arguments - BITS="64" - CLEAN="false" - COMPILER="gcc" - COMPILER_VERSION="unset" - FDO="false" - LTO="false" - BIN_PATH="unset" - RELEASE="fast" - SRC_PATH="unset" - SYSTEM="auto" - THREADS="auto" - - # derived variables with initial values - EXECUTABLE="unset" - VERSION_POSTFIX="" - MACHINE="unset" - CONFIGURE_OPTIONS=("--enable-core-inline") - CFLAGS_ARRAY=("-Wall" "-pipe") - LDFLAGS_ARRAY=("") - LIBS_ARRAY=("") - CALL_CACHE=("") - - # read-only strings - readonly SCRIPT_VERSION="1.0" - readonly REPO_URL="https://github.com/dreamer/dosbox-staging" - - # environment variables passed onto the build - export CC="CC_is_not_set" - export CXX="CXX_is_not_set" - export LD="LD_is_not_set" - export AR="AR_is_not_set" - export RANLIB="RANLIB_is_not_set" - export CFLAGS="" - export CXXFLAGS="" - export LDFLAGS="" - export LIBS="" - export GCC_COLORS="error=01;31:warning=01;35:note=01;36:range1=32:range2=34:locus=01:\ -quote=01:fixit-insert=32:fixit-delete=31:diff-filename=01:\ -diff-hunk=32:diff-delete=31:diff-insert=32:type-diff=01;32" -} - -function errcho() { - local CLEAR='\033[0m' - local RED='\033[0;91m' - >&2 echo "" - >&2 echo -e " ${RED}👉 ${*}${CLEAR}" "\\n" -} -function bug() { - local CLEAR='\033[0m' - local YELLOW='\033[0;33m' - >&2 echo -e " ${YELLOW}Please report the following at ${REPO_URL}${CLEAR}" - errcho "${@}" - exit 1 -} - -function error() { - errcho "${@}" - exit 1 -} - -function exists() { - command -v "${1}" &> /dev/null -} - -function print_var() { - if [[ -z "${1}" ]]; then - echo "unset" - else - echo "${1}" - fi -} - -## -# Uses -# ---- -# Alows function to indicate which other functions they depend on. -# For example: "uses system" indicates a function needs the system -# to be defined prior to running. -# This uses function acts like a call cache, ensuring each used function -# is only actually called once. This allows all functions to thoroughly -# employ the 'uses' mechanism without the performance-hit of repeatedly -# executing the same function. Likely, functions that are 'used' are -# atomic in that they will only be called once per script invocation. -# -function uses() { - # assert - if [[ "${#}" != 1 ]]; then - bug "The 'uses' function was called without an argument" - fi - - # only operate on functions in our call-scope, otherwise fail hard - func="${1}" - if [[ "$(type -t "${func}")" != "function" ]]; then - bug "The 'uses' function was passed ${func}, which isn't a function" - fi - - # Check the call cache to see if the function has already been called - local found_in_previous="false" - for previous_func in "${CALL_CACHE[@]}"; do - if [[ "${previous_func}" == "${func}" ]]; then - found_in_previous="true" - break - fi - done - - # if it hasn't been called then record it and run it - if [[ "${found_in_previous}" == "false" ]]; then - CALL_CACHE+=("${func}") - "${func}" - fi -} - - -function print_version() { - echo "${SCRIPT_VERSION}" - exit 0 -} - -function system() { - if [[ "${MACHINE}" == "unset" ]]; then MACHINE="$(uname -m)"; fi - if [[ "${SYSTEM}" == "auto" ]]; then SYSTEM="$(uname -s)"; fi - case "$SYSTEM" in - Darwin|macos) SYSTEM="macos" ;; - MSYS*|msys2) SYSTEM="msys2" ;; - Linux|linux) SYSTEM="linux" ;; - *) error "Your system, $SYSTEM, is not currently supported" ;; - esac -} - -function bits() { - if [[ "${BITS}" != 64 && "${BITS}" != 32 ]]; then - usage "A bit-depth of ${BITS} is not allowed; choose 64 or 32" - fi -} - -function compiler_type() { - if [[ "${COMPILER}" != "gcc" && "${COMPILER}" != "clang" ]]; then - usage "The choice of compiler (${COMPILER}) is not valid; choose gcc or clang" - fi -} - -function tools_and_flags() { - uses compiler_type - uses compiler_version - uses system - - # GCC universal - if [[ "${COMPILER}" == "gcc" ]]; then - CC="gcc${VERSION_POSTFIX}" - LD="gcc${VERSION_POSTFIX}" - CXX="g++${VERSION_POSTFIX}" - CFLAGS_ARRAY+=("-fstack-protector" "-fdiagnostics-color=always") - - # Prioritize versioned lib-tools over generics - AR="gcc-ar${VERSION_POSTFIX}" - RANLIB="gcc-ranlib${VERSION_POSTFIX}" - if ! exists "${AR}"; then AR="ar"; fi - if ! exists "${RANLIB}"; then RANLIB="ranlib"; fi - - # CLANG universal - elif [[ "${COMPILER}" == "clang" ]]; then - CC="clang${VERSION_POSTFIX}" - CXX="clang++${VERSION_POSTFIX}" - CFLAGS_ARRAY+=("-fcolor-diagnostics") - - # CLANG on Linux and MSYS2 - if [[ "${SYSTEM}" == "linux" || "${SYSTEM}" == "msys2" ]]; then - LD="llvm-link${VERSION_POSTFIX}" - AR="llvm-ar${VERSION_POSTFIX}" - RANLIB="llvm-ranlib${VERSION_POSTFIX}" - - # CLANG on MacOS - elif [[ "${SYSTEM}" == "macos" ]]; then LD="ld"; fi - fi - - # macOS universal - if [[ "${SYSTEM}" == "macos" ]]; then - AR="ar" - RANLIB="ranlib" - fi -} - -function src_path() { - if [[ "${SRC_PATH}" == "unset" ]]; then - SRC_PATH="$(cd "$(dirname "${INVOCATION}")" && cd .. && pwd -P)" - elif [[ ! -d "${SRC_PATH}" ]]; then - usage "The requested source directory (${SRC_PATH}) does not exist, is not a directory, or is not accessible" - fi - cd "${SRC_PATH}" -} - -function bin_path() { - uses system - uses compiler_type - - # By default, if we're on macOS and using GCC then always include /usr/local/bin, because - # that's where brew installs all the binaries. If the user adds their own --bin-path, - # that will be prefixed ahead of /usr/local/bin and take precedent. - if [[ "${SYSTEM}" == "macos" && "${COMPILER}" == "gcc" ]]; then - PATH="/usr/local/bin:${PATH}" - fi - - if [[ "${BIN_PATH}" != "unset" ]]; then - if [[ ! -d "${BIN_PATH}" ]]; then - usage "The requested PATH (${BIN_PATH}) does not exist, is not a directory, or is not accessible" - else - PATH="${BIN_PATH}:${PATH}" - fi - fi -} - -function check_build_tools() { - for tool in "${CC}" "${CXX}" "${LD}" "${AR}" "${RANLIB}"; do - if ! exists "${tool}"; then - error "${tool} was not found in your PATH or is not executable. If it's in a custom path, use --bin-path" - fi - done -} - -function compiler_version() { - if [[ "${COMPILER_VERSION}" != "unset" ]]; then - VERSION_POSTFIX="-${COMPILER_VERSION}" - fi -} - -function release_flags() { - uses compiler_type - - if [[ "${RELEASE}" == "fast" ]]; then CFLAGS_ARRAY+=("-Ofast") - elif [[ "${RELEASE}" == "small" ]]; then - CFLAGS_ARRAY+=("-Os") - if [[ "${COMPILER}" == "gcc" ]]; then - CFLAGS_ARRAY+=("-ffunction-sections" "-fdata-sections") - - # ld on MacOS doesn't understand --as-needed, so exclude it - uses system - if [[ "${SYSTEM}" != "macos" ]]; then LDFLAGS_ARRAY+=("-Wl,--as-needed"); fi - fi - elif [[ "${RELEASE}" == "debug" ]]; then CFLAGS_ARRAY+=("-g" "-O1") - else usage "The release type of ${RELEASE} is not allowed. Choose fast, small, or debug" - fi -} - -function threads() { - if [[ "${THREADS}" == "auto" ]]; then - if exists nproc; then THREADS="$(nproc)" - else THREADS="$(sysctl -n hw.physicalcpu || echo 4)"; fi - fi - # make presents a descriptive error message in the scenario where the user overrides - # THREADS with an illegal value: the '-j' option requires a positive integer argument. -} - -function fdo_flags() { - if [[ "${FDO}" != "true" ]]; then - return - fi - - uses compiler_type - uses src_path - local fdo_file="${SRC_PATH}/scripts/profile-data/${COMPILER}.profile" - if [[ ! -f "${fdo_file}" ]]; then - error "The Feedback-Directed Optimization file provided (${fdo_file}) does not exist or could not be accessed" - fi - - if [[ "${COMPILER}" == "gcc" ]]; then - # Don't let GCC 6.x and under use both FDO and LTO - uses compiler_version - if [[ ( "${COMPILER_VERSION}" == "unset" - && "$(2>&1 gcc -v | grep -Po '(?<=version )[^.]+')" -lt "7" - || "${COMPILER_VERSION}" -lt "7" ) - && "${LTO}" == "true" ]]; then - error "GCC versions 6 and under cannot handle FDO and LTO simultaneously; please change one or more these." - fi - CFLAGS_ARRAY+=("-fauto-profile=${fdo_file}") - - elif [[ "${COMPILER}" == "clang" ]]; then - CFLAGS_ARRAY+=("-fprofile-sample-use=${fdo_file}") - fi -} - -function lto_flags() { - if [[ "${LTO}" != "true" ]]; then - return - fi - - uses system - # Only allow LTO on Linux and MacOS; it currently fails under Windows - if [[ "${SYSTEM}" == "msys2" ]]; then - usage "LTO currently does not link or build on Windows with GCC or Clang" - fi - - uses compiler_type - if [[ "${COMPILER}" == "gcc" ]]; then - CFLAGS_ARRAY+=("-flto") - - # The linker performs the code optimizations across all objects, and therefore - # needs the same flags as the compiler would normally get - LDFLAGS_ARRAY+=("${CFLAGS_ARRAY[@]}") - - # GCC on MacOS fails to parse the thread flag, so we only provide it under Linux - # (error: unsupported argument 4 to option flto=) - if [[ "${SYSTEM}" == "linux" ]]; then - uses threads - LDFLAGS_ARRAY+=("-flto=$THREADS") - fi - - elif [[ "${COMPILER}" == "clang" ]]; then - CFLAGS_ARRAY+=("-flto=thin") - - # Clang LTO on Linux is incompatible with -Os so replace them with -O2 - # (ld: error: Optimization level must be between 0 and 3) - if [[ "${SYSTEM}" == "linux" ]]; then - CFLAGS_ARRAY=("${CFLAGS_ARRAY[@]/-Os/-O2}") - fi # clang-linux-lto-small exclusion - fi # gcc & clang -} - -function configure_options() { - uses system - if [[ "${MACHINE}" != *"86"* ]]; then - CONFIGURE_OPTIONS+=("--disable-dynamic-x86" "--disable-fpu-x86" "--disable-fpu-x64") - fi -} - -function do_autogen() { - uses src_path - if [[ ! -f autogen.sh ]]; then - error "autogen.sh doesn't exist in our current directory $PWD. If your DOSBox source is somewhere else set it with --src-path" - fi - - # Only autogen if needed .. - if [[ ! -f configure ]]; then - uses bin_path - ./autogen.sh - fi -} - -function do_configure() { - uses bin_path - uses src_path - uses tools_and_flags - uses release_flags - uses fdo_flags - uses lto_flags - uses check_build_tools - uses configure_options - - # Convert our arrays into space-delimited strings - LIBS=$( printf "%s " "${LIBS_ARRAY[@]}") - CFLAGS=$( printf "%s " "${CFLAGS_ARRAY[@]}") - CXXFLAGS=$(printf "%s " "${CFLAGS_ARRAY[@]}") - LDFLAGS=$( printf "%s " "${LDFLAGS_ARRAY[@]}") - - local lto_string="" - local fdo_string="" - if [[ "${LTO}" == "true" ]]; then lto_string="-LTO"; fi - if [[ "${FDO}" == "true" ]]; then fdo_string="-FDO"; fi - - echo "" - echo "Launching with:" - echo "" - echo " CC = ${CC}" - echo " CXX = ${CXX}" - echo " LD = ${LD}" - echo " AR = ${AR}" - echo " RANLIB = ${RANLIB}" - echo " CFLAGS = ${CFLAGS}" - echo " CXXFLAGS = ${CXXFLAGS}" - echo " LIBS = ${LIBS}" - echo " LDFLAGS = ${LDFLAGS}" - echo " THREADS = ${THREADS}" - echo "" - echo "Build type: ${SYSTEM}-${MACHINE}-${BITS}bit-${COMPILER}-${RELEASE}${lto_string}${fdo_string}" - echo "" - "${CC}" --version - sleep 5 - - if [[ ! -f configure ]]; then - error "configure script doesn't exist in $PWD. If the source is somewhere else, set it with --src-path" - - elif ! ./configure "${CONFIGURE_OPTIONS[@]}"; then - >&2 cat "config.log" - error "configure failed, see config.log output above" - fi -} - -function executable() { - uses src_path - EXECUTABLE="src/" - if [[ "${SYSTEM}" == "msys2" ]]; then EXECUTABLE+="dosbox.exe" - else EXECUTABLE+="dosbox" - fi - - if [[ ! -f "${EXECUTABLE}" ]]; then - error "${EXECUTABLE} does not exist or hasn't been created yet" - fi -} - -function build() { - uses src_path - uses bin_path - uses threads - - if [[ "${CLEAN}" == "true" && -f "Makefile" ]]; then - make clean 2>&1 | tee -a build.log - fi - do_autogen - do_configure - make -j "${THREADS}" 2>&1 | tee -a build.log -} - -function strip_binary() { - if [[ "${RELEASE}" == "debug" ]]; then - echo "[skipping strip] Debug symbols will be left in the binary because it's a debug release" - else - uses bin_path - uses executable - strip "${EXECUTABLE}" - fi -} - -function show_binary() { - uses bin_path - uses system - uses executable - - if [[ "$SYSTEM" == "macos" ]]; then otool -L "${EXECUTABLE}" - else ldd "${EXECUTABLE}"; fi - ls -1lh "${EXECUTABLE}" -} - -function main() { - parse_args "$@" - build - strip_binary - show_binary -} - -main "$@" +# shellcheck source=scripts/automator/main.sh +source "$(dirname "$0")/automator/main.sh" diff --git a/scripts/list-build-dependencies.sh b/scripts/list-build-dependencies.sh index 1fa311d4..a929077d 100755 --- a/scripts/list-build-dependencies.sh +++ b/scripts/list-build-dependencies.sh @@ -1,196 +1,55 @@ #!/bin/bash -## -# Copyright (c) 2019 Kevin R. Croft -# SPDX-License-Identifier: GPL-2.0-or-later -# -# This script lists development packages and DOSBox dependencies needed to build DOSBox. -# This package names provided are tailor based on the provided package manager, -# choice of compiler, and optionally its bit-depth. -# -# See the usage arguments below for details or run it with the -h or --help. -# -# In general, this script adheres to Google's shell scripting style guide -# (https://google.github.io/styleguide/shell.xml), however some deviations (such as -# tab indents instead of two-spaces) are used to fit DOSBox's in-practice coding style. -# +# Copyright (c) 2019 Kevin R Croft +# SPDX-License-Identifier: GPL-2.0-or-later +# This script prints package dependencies for a given package manmager, +# compiler (gcc or clang), and bit-depth (32 or 64). +# +# If run without arguments, the script asks for required arguments one +# by one, which includes the package manager (--manager) and --compiler. +# +# Optional arguments include the bit-depth, defaults to 64-bit; +# and the compiler version, which defaults to the package manager's +# default version. +# +# Usage examples: +# $ ./list-build-dependencies.sh # asks for --manager +# $ ./list-build-dependencies.sh --manager apt # asks for --compiler +# $ ./list-build-dependencies.sh --manager apt --compiler gcc -v 9 +# $ ./list-build-dependencies.sh --manager zypper --compiler clang +# $ ./list-build-dependencies.sh --manager msy2 --compiler gcc -b 32 +# +# This script makes use of the automator package, see automator/main.sh. +# set -euo pipefail -IFS=$'\n\t' -function usage() { - if [ -n "${1}" ]; then - errcho "${1}" - fi - local script - script=$(basename "${0}") - echo "Usage: ${script} -p apt|xcode|brew|macports|msys2|vcpkg [-b 32|64] [-c gcc|clang] [-o FILE] [-u #]" - echo "" - echo " FLAG Description Default" - echo " ----------------------- --------------------------------------------------- -------" - echo " -b, --bit-depth Choose either a 64 or 32 bit compiler [$(print_var "${BITS}")]" - echo " -c, --compiler Choose either gcc or clang [$(print_var "${COMPILER}")]" - echo " -u, --compiler-version <#> Customize the compiler version (if available) [$(print_var "${COMPILER_VERSION}")]" - echo " -v, --version Print the version of this script [$(print_var "${SCRIPT_VERSION}")]" - echo " -h, --help Print this usage text" - echo " -p, --package-manager Choose one of the following:" - echo " - apt (Linux: Debian, Ubuntu, Raspbian)" - echo " - dnf (Linux: Fedora, RedHat, CentOS)" - echo " - pacman (Linux: Arch, Manjaro)" - echo " - zypper (Linux: SuSE, OpenSUSE)" - echo " - xcode (OS X: Apple-supported)" - echo " - brew (OS X: Homebrew community-supported)" - echo " - macports (OS X: MacPorts community-supported)" - echo " - msys2 (Windows: Cygwin-based, community-support)" - echo " - vcpkg (Windows: Visual Studio builds)" - echo " ----------------------- --------------------------------------------------- -------" - echo "" - echo "Example: ${script} --package-manager apt --compiler clang --compiler-version 8" - echo "" - echo "Note: the last value will take precendent if duplicate flags are provided." - exit 1 -} - -function defaults() { - BITS="64" - COMPILER="gcc" - COMPILER_VERSION="" - PACKAGE_MANAGER="unset" - readonly SCRIPT_VERSION="0.2" -} - -# parse params function parse_args() { - defaults + # Gather the parameters that define this build + bits="64" + modifiers=("") + # shellcheck disable=SC2034 while [[ "${#}" -gt 0 ]]; do case ${1} in - -b|--bit-depth) BITS="${2}"; shift;shift;; - -c|--compiler) COMPILER="${2}"; shift;shift;; - -p|--package-manager) PACKAGE_MANAGER="${2}"; shift;shift;; - -u|--compiler-version) COMPILER_VERSION="${2}"; shift;shift;; - -v|--version) print_version; shift;; - -h|--help) usage "Show usage"; shift;; - *) usage "Unknown parameter: ${1}"; shift;shift;; + -m|--manager) manager="${2}"; shift 2;; + -c|--compiler) selected_type=$(lower "${2}"); shift 2;; + -b|--bit-depth) bits="${2}"; shift 2;; + -v|--compiler-version) version="${2}"; shift 2;; + -a|--addon) modifiers+=("${2}"); shift 2;; + *) >&2 echo "Unknown parameter: ${1}"; exit 1; shift 2;; esac; done - # Check mandatory arguments - if [[ "${PACKAGE_MANAGER}" == "unset" ]]; then - usage "A choice of package manager must be provided; use '-p ' or '--package-manager '" - fi + # Import our settings and report missing values + import manager "${manager:-}" + if [[ -z "${selected_type:-}" ]]; then arg_error "--compiler" "${TYPES[*]}"; fi + + # If a version was provided then construct a postfix string given the manager's + # potential unique delimeter (ie: gcc@9 for brew, gcc-9 for apt). + # shellcheck disable=SC2034,SC2154 + postfix=$([[ -n "${version:-}" ]] && echo "${delim}${version}" || echo "") + import "${selected_type:-}" "${manager:-}" } +# shellcheck disable=SC2034 +data_dir="packages" -function errcho() { - local CLEAR='\033[0m' - local RED='\033[0;91m' - >&2 echo "" - >&2 echo -e " ${RED}👉 ${*}${CLEAR}" "\\n" -} - -function print_var() { - if [[ -z "${1}" ]]; then - echo "unset" - else - echo "${1}" - fi -} - -function list_packages() { - VERSION_DELIM="" - case "$1" in - - apt) - # Apt separates GCC into the gcc and g++ pacakges, the latter which depends on the prior. - # Therefore, we provide g++ in-place of gcc. - VERSION_DELIM="-" - if [[ "${COMPILER}" == "gcc" ]]; then - COMPILER="g++" - fi - PACKAGES=(libtool build-essential autoconf-archive libsdl1.2-dev libsdl-net1.2-dev libopusfile-dev) - ;; - - dnf) - VERSION_DELIM="-" - PACKAGES=(libtool autoconf-archive SDL SDL_net-devel opusfile-devel) - ;; - - pacman) - # Arch offers 32-bit versions of SDL (but not others) - PACKAGES=(libtool autoconf-archive sdl_net opusfile) - if [[ "${BITS}" == 32 ]]; then - PACKAGES+=(lib32-sdl) - else - PACKAGES+=(sdl) - fi - ;; - - zypper) - # OpenSUSE offers 32-bit versions of SDL and SDL_net (but not others) - PACKAGES=(devel_basis libtool autoconf-archive opusfile) - if [[ "${BITS}" == 32 ]]; then - PACKAGES+=(libSDL-devel-32bit libSDL_net-devel-32bit) - else - PACKAGES+=(SDL SDL_net) - fi - ;; - - xcode) - # If the user doesn't want to use Homebrew or MacPorts, then they are limited to - # Apple's Clang plus the provided command line development tools provided by Xcode. - COMPILER="" - echo "Execute the following:" - echo " xcode-select --install # to install command line development tools" - echo " sudo xcodebuild -license # to accept Apple's license agreement" - echo "" - echo "Now download, build, and install the following manually to avoid using Homebrew or MacPorts:" - echo " - coreutils autogen autoconf automake pkg-config libpng sdl sdl_net opusfile" - ;; - - brew) - # If the user wants Clang, we knock it out because it's provided provided out-of-the-box - VERSION_DELIM="@" - if [[ "${COMPILER}" == "clang" ]]; then - COMPILER="" - fi - PACKAGES=(coreutils autogen autoconf autoconf-archive automake pkg-config libpng sdl sdl_net opusfile) - ;; - - macports) - PACKAGES=(coreutils autogen automake autoconf autoconf-archive pkgconfig libpng libsdl libsdl_net opusfile) - ;; - - msys2) - # MSYS2 only supports the current latest releases of Clang and GCC, so we disable version customization - COMPILER_VERSION="" - local pkg_type - pkg_type="x86_64" - if [[ "${BITS}" == 32 ]]; then - pkg_type="i686" - fi - PACKAGES=(autogen autoconf autoconf-archive base-devel automake-wrapper) - for pkg in pkg-config libtool libpng zlib SDL SDL_net opusfile; do - PACKAGES+=("mingw-w64-${pkg_type}-${pkg}") - done - COMPILER="mingw-w64-${pkg_type}-${COMPILER}" - ;; - - vcpkg) - # VCPKG doesn't provide Clang or GCC, so we knock out the compiler and just give packages - COMPILER="" - PACKAGES=(libpng sdl1 sdl1-net opusfile) - ;; - *) - usage "Unknown package manager ${1}" - ;; - esac - - if [[ -n "${COMPILER_VERSION}" && -n "${COMPILER}" ]]; then - COMPILER+="${VERSION_DELIM}${COMPILER_VERSION}" - fi - echo "${COMPILER} ${PACKAGES[*]}" -} - -function main() { - parse_args "$@" - list_packages "${PACKAGE_MANAGER}" -} - -main "$@" +# shellcheck source=scripts/automator/main.sh +source "$(dirname "$0")/automator/main.sh"