diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c3b7c433c..3b33b3cb4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -144,7 +144,7 @@ jobs: wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh sudo ./llvm.sh 21 - sudo apt-get install libc++-21* libc++abi*21* -y --no-install-recommends + sudo apt-get install libc++-21* libc++abi-*21* -y --no-install-recommends echo "CC=clang-21" >> "$GITHUB_ENV" echo "CXX=clang++-21" >> "$GITHUB_ENV" echo "OBJC=clang-21" >> "$GITHUB_ENV" @@ -166,16 +166,6 @@ jobs: version: 15 platform: x64 - - name: Unbreak Python in GHA (MacOS 13 image) - if: matrix.config.os == 'macos' && matrix.config.os-version == 13 - run: | - # TODO: remove this, after it works again - # A workaround for "The `brew link` step did not complete successfully" error. - # See e.g. https://github.com/Homebrew/homebrew-core/issues/165793#issuecomment-1991817938 - find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete - sudo rm -rf /Library/Frameworks/Python.framework/ - brew install --force python3 && brew unlink python3 && brew unlink python3 && brew link --overwrite python3 - - name: Setup Clang (MacOS) if: matrix.config.os == 'macos' run: | diff --git a/io.github.openbrickprotocolfoundation.oopetris.yml b/io.github.openbrickprotocolfoundation.oopetris.yml index 60a4e3d12..06f3fdec4 100644 --- a/io.github.openbrickprotocolfoundation.oopetris.yml +++ b/io.github.openbrickprotocolfoundation.oopetris.yml @@ -12,7 +12,6 @@ modules: - -Dbuild_installer=true - --libdir=lib - -Dtests=true - - -Dsdl2_image:test=false - --fatal-meson-warnings - -Drun_in_ci=true # note we always want the CI checks in the case we built the flatpak - --force-fallback-for=fmt # note, the freedesktop sdk has this installed, but it is not copiable into the runtime, so we need to build it ourself, to be able to install it correctly diff --git a/platforms/.gitignore b/platforms/.gitignore index dd2bbd75c..1ba8225c2 100644 --- a/platforms/.gitignore +++ b/platforms/.gitignore @@ -1,5 +1,6 @@ crossbuild.ini crossbuild/*.ini +crossbuild/uefi*.json *.elf *.nacp diff --git a/platforms/android/app/build.gradle b/platforms/android/app/build.gradle index f6e0d140d..3df25ac1b 100644 --- a/platforms/android/app/build.gradle +++ b/platforms/android/app/build.gradle @@ -130,7 +130,7 @@ List getAndroidABIs() { /** * Determine the version * if you specify it explicitly, that will be used, otherwise meson introspect will be called - * @return String + * @returns String */ String getVersion() { String property = project.findProperty('VERSION') @@ -320,7 +320,7 @@ android { } compileSdkVersion 35 - ndkVersion = "29.0.14206865" + ndkVersion = "29.0.14033849" defaultConfig { if (buildAsApplication) { applicationId "com.github.oopetris" diff --git a/platforms/build-3ds.sh b/platforms/build-3ds.sh index 5c167886b..461f60277 100755 --- a/platforms/build-3ds.sh +++ b/platforms/build-3ds.sh @@ -32,7 +32,7 @@ elif [ "$#" -eq 3 ]; then RUN_IN_CI="true" fi else - echo "Too many arguments given, expected 1, 2 or 3" + echo "Too many arguments given, expected 1, 2 or 3" >&2 exit 1 fi @@ -41,7 +41,7 @@ if [ "$COMPILE_TYPE" == "smart" ]; then elif [ "$COMPILE_TYPE" == "complete_rebuild" ]; then : # noop else - echo "Invalid COMPILE_TYPE, expected: 'smart' or 'complete_rebuild'" + echo "Invalid COMPILE_TYPE, expected: 'smart' or 'complete_rebuild'" >&2 exit 1 fi @@ -67,7 +67,6 @@ export BUILD_DIR="build/3ds" export TOOL_PREFIX="arm-none-eabi" - export BIN_DIR="$PORTLIBS_PATH_3DS/bin" export PKG_CONFIG_EXEC="$BIN_DIR/$TOOL_PREFIX-pkg-config" export CMAKE="$BIN_DIR/$TOOL_PREFIX-cmake" diff --git a/platforms/build-android.sh b/platforms/build-android.sh index 065dd9bd6..988311496 100755 --- a/platforms/build-android.sh +++ b/platforms/build-android.sh @@ -41,14 +41,14 @@ fi if [ ! -e "$BASE_PATH/meta/abis.json" ]; then - echo "no abis.json file found, to determine supported abis" + echo "no abis.json file found, to determine supported abis" >&2 exit 2 fi if [ ! -e "$BASE_PATH/meta/platforms.json" ]; then - echo "no platforms.json file found, to determine supported platforms and SDKs" + echo "no platforms.json file found, to determine supported platforms and SDKs" >&2 exit 2 fi @@ -56,7 +56,7 @@ fi SDK_VERSION=$(jq '.max' -M -r -c "$BASE_PATH/meta/platforms.json") export SDK_VERSION -mapfile -t ARCH_KEYS < <(jq 'keys' -M -r -c "$BASE_PATH/meta/abis.json" | tr -d '[]"' | sed 's/,/\n/g') +mapfile -t ARCH_KEYS < <(jq 'keys[]' -M -r -c "$BASE_PATH/meta/abis.json") export ARCH_KEYS_INDEX=("${!ARCH_KEYS[@]}") @@ -82,7 +82,7 @@ elif [ "$#" -eq 1 ] || [ "$#" -eq 2 ] || [ "$#" -eq 3 ] || [ "$#" -eq 4 ]; then done if [ -z "$FOUND" ]; then - echo "Invalid arch: '${ARCH}', supported archs are:" "${ARCH_KEYS[@]}" + echo "Invalid arch: '${ARCH}', supported archs are:" "${ARCH_KEYS[@]}" >&2 exit 2 fi @@ -106,7 +106,7 @@ elif [ "$#" -eq 1 ] || [ "$#" -eq 2 ] || [ "$#" -eq 3 ] || [ "$#" -eq 4 ]; then fi else - echo "Too many arguments given, expected 1, 2, 3 or 4" + echo "Too many arguments given, expected 1, 2, 3 or 4" >&2 exit 1 fi @@ -115,11 +115,10 @@ if [ "$COMPILE_TYPE" == "smart" ]; then elif [ "$COMPILE_TYPE" == "complete_rebuild" ]; then : # noop else - echo "Invalid COMPILE_TYPE, expected: 'smart' or 'complete_rebuild'" + echo "Invalid COMPILE_TYPE, expected: 'smart' or 'complete_rebuild'" >&2 exit 1 fi - for INDEX in "${ARCH_KEYS_INDEX[@]}"; do export KEY=${ARCH_KEYS[$INDEX]} @@ -148,7 +147,6 @@ for INDEX in "${ARCH_KEYS_INDEX[@]}"; do if [ "$COMPILE_TYPE" == "complete_rebuild" ] || ! [ -e "$SYS_ROOT" ]; then - if [ -d "${SYS_ROOT:?}/" ]; then rm -rf "${SYS_ROOT:?}/" @@ -249,7 +247,6 @@ for INDEX in "${ARCH_KEYS_INDEX[@]}"; do ## build flac with cmake (meson port doesn't work for 32 bits machines atm) (we need to check for fseeko and ftello correctly in there) - pushd "$SYS_ROOT" BUILD_DIR_FLAC="build-flac" @@ -377,7 +374,6 @@ for INDEX in "${ARCH_KEYS_INDEX[@]}"; do validate_parent_dir "$CROSS_FILE" - cat <"$CROSS_FILE" [host_machine] system = 'android' @@ -477,7 +473,7 @@ EOF done -# TODO only copy the supported music ones (atm we need both for i686 flac is needed!) +# TODO only copy the supported music ones (atm we need both, for i686 flac is needed!) cp -r ./assets/ platforms/android/app/src/main diff --git a/platforms/build-switch.sh b/platforms/build-switch.sh index bf30ab0d1..b7e4953d6 100755 --- a/platforms/build-switch.sh +++ b/platforms/build-switch.sh @@ -32,7 +32,7 @@ elif [ "$#" -eq 3 ]; then RUN_IN_CI="true" fi else - echo "Too many arguments given, expected 1, 2 or 3" + echo "Too many arguments given, expected 1, 2 or 3" >&2 exit 1 fi @@ -41,7 +41,7 @@ if [ "$COMPILE_TYPE" == "smart" ]; then elif [ "$COMPILE_TYPE" == "complete_rebuild" ]; then : # noop else - echo "Invalid COMPILE_TYPE, expected: 'smart' or 'complete_rebuild'" + echo "Invalid COMPILE_TYPE, expected: 'smart' or 'complete_rebuild'" >&2 exit 1 fi @@ -55,7 +55,6 @@ source "$SCRIPT_DIR/versions.sh" # shellcheck source=./platforms/helper.sh source "$SCRIPT_DIR/helper.sh" - export DEVKITPRO="/opt/devkitpro" export ARCH_DEVKIT_FOLDER="$DEVKITPRO/devkitA64" export COMPILER_BIN="$ARCH_DEVKIT_FOLDER/bin" diff --git a/platforms/build-uefi.sh b/platforms/build-uefi.sh new file mode 100755 index 000000000..9a5f6b373 --- /dev/null +++ b/platforms/build-uefi.sh @@ -0,0 +1,429 @@ +#!/usr/bin/env bash + +# Exit immediately if a command exits with a non-zero status. +set -e +## Treat undefined variables as an error +set -u +# fails if any part of a pipeline (|) fails +set -o pipefail + +## options: "smart, complete_rebuild" +export COMPILE_TYPE="smart" + +export BUILDTYPE="debug" + +export RUN_IN_CI="false" + +export RUNTIME_TARGET="emulator" + +if [ "$#" -eq 0 ]; then + # nothing + echo "Using compile type '$COMPILE_TYPE'" +elif [ "$#" -eq 1 ]; then + COMPILE_TYPE="$1" +elif [ "$#" -eq 2 ]; then + COMPILE_TYPE="$1" + BUILDTYPE="$2" +elif [ "$#" -eq 3 ]; then + COMPILE_TYPE="$1" + BUILDTYPE="$2" + + if [ -z "$3" ]; then + RUN_IN_CI="false" + else + RUN_IN_CI="true" + fi +elif [ "$#" -eq 4 ]; then + COMPILE_TYPE="$1" + BUILDTYPE="$2" + + if [ -z "$3" ]; then + RUN_IN_CI="false" + else + RUN_IN_CI="true" + fi + RUNTIME_TARGET="$4" +else + echo "Too many arguments given, expected 1, 2 or 3" >&2 + exit 1 +fi + +if [ "$COMPILE_TYPE" == "smart" ]; then + : # noop +elif [ "$COMPILE_TYPE" == "complete_rebuild" ]; then + : # noop +else + echo "Invalid COMPILE_TYPE, expected: 'smart' or 'complete_rebuild'" >&2 + exit 1 +fi + +if [ "$RUNTIME_TARGET" == "emulator" ]; then + : # noop +elif [ "$RUNTIME_TARGET" == "hardware" ]; then + : # noop +else + echo "Invalid RUNTIME_TARGET, expected: 'emulator' or 'hardware'" >&2 + exit 1 +fi + +# source dependency version information + +SCRIPT_DIR="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" + +# shellcheck source=./platforms/versions.sh +source "$SCRIPT_DIR/versions.sh" + +# shellcheck source=./platforms/helper.sh +source "$SCRIPT_DIR/helper.sh" + +TOOLCHAIN_DIR="$(pwd)/toolchains" +export TOOLCHAIN_DIR + +if [ ! -d "$TOOLCHAIN_DIR" ]; then + mkdir -p "$TOOLCHAIN_DIR" +fi + +export EDK2_TOOLS_DIR="$TOOLCHAIN_DIR/EDK2_TOOLS" + +if [ ! -d "$EDK2_TOOLS_DIR" ]; then + mkdir -p "$EDK2_TOOLS_DIR" +fi + +export EDK2_ROOT="$EDK2_TOOLS_DIR/edk2" + +export WORKSPACE="$EDK2_TOOLS_DIR/workspace" + +if [ ! -d "$WORKSPACE" ]; then + mkdir -p "$WORKSPACE" +fi + +# needed by the setup script +mkdir -p "$WORKSPACE/Conf/" + +if [ ! -d "$EDK2_ROOT" ]; then + git clone https://github.com/tianocore/edk2 "$EDK2_ROOT" +else + git -C "$EDK2_ROOT" fetch +fi + +git -C "$EDK2_ROOT" checkout "$EDK2_RELEASE_TAG" +git -C "$EDK2_ROOT" submodule update --init + +export EDK2_LIBC_ROOT="$EDK2_TOOLS_DIR/edk2-libc" + +if [ ! -d "$EDK2_LIBC_ROOT" ]; then + git clone https://github.com/tianocore/edk2-libc "$EDK2_LIBC_ROOT" +else + git -C "$EDK2_LIBC_ROOT" fetch +fi + +git -C "$EDK2_LIBC_ROOT" checkout "$EDK2_LIBC_COMMIT_HASH" + +export EDK2_GENERATED_PACKAGES_ROOT="$EDK2_TOOLS_DIR/GeneratedPackages" + +export LIBRARY_PKG_ROOT="$EDK2_TOOLS_DIR/LibraryPkg" + +export EDK_TOOLS_PATH="$EDK2_ROOT/BaseTools" +export PACKAGES_PATH="$EDK2_ROOT:$EDK2_LIBC_ROOT:$EDK2_GENERATED_PACKAGES_ROOT:$LIBRARY_PKG_ROOT" + +PLATFORMS_DIR="$(pwd)/platforms/uefi" + +PATCH_DIR="$PLATFORMS_DIR" + +EDK2_PATCH_FILE="$EDK2_ROOT/.patched_manually.meta" + +if ! [ -e "$EDK2_PATCH_FILE" ]; then + ##TODO: upstream those patches + + mapfile -d "" -t PATCH_FILES < <(find "$PATCH_DIR/edk2" -name "*.patch" -print0 | sort -z) + + for PATCH_FILE in "${PATCH_FILES[@]}"; do + git apply --unsafe-paths -p1 --directory="$EDK2_ROOT" "$PATCH_FILE" + done + + touch "$EDK2_PATCH_FILE" +fi + +EDK2_LIBC_PATCH_FILE="$EDK2_LIBC_ROOT/.patched_manually.meta" + +if ! [ -e "$EDK2_LIBC_PATCH_FILE" ]; then + ##TODO: upstream those patches + + mapfile -d "" -t PATCH_FILES < <(find "$PATCH_DIR/edk2-libc" -name "*.patch" -print0 | sort -z) + + for PATCH_FILE in "${PATCH_FILES[@]}"; do + git apply --unsafe-paths -p1 --directory="$EDK2_LIBC_ROOT" "$PATCH_FILE" + done + + touch "$EDK2_LIBC_PATCH_FILE" +fi + +export BUILD_DIR="build/uefi" + +pushd "$EDK2_ROOT" + +make -C BaseTools --quiet >/dev/null 2>&1 + +set +u + +# shellcheck disable=SC1091 +source "$EDK2_ROOT/edksetup.sh" "--reconfig" + +set -u + +export EDK2_CONF_TARGET="$WORKSPACE/Conf/target.txt" + +EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM_NAME="Platforms/OOPetrisPlatform.dsc" + +EDK2_TARGET_PROPERTIES_BUILDTYPE="$(echo "$BUILDTYPE" | tr "[:lower:]" "[:upper:]")" + +EDK2_TARGET_PROPERTIES_ARCH="X64" +EDK2_TARGET_PROPERTIES_TOOLCHAIN="GCC" + +declare -A EDK2_TARGET_PROPERTIES=(["ACTIVE_PLATFORM"]="$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM_NAME" ["TARGET"]="$EDK2_TARGET_PROPERTIES_BUILDTYPE" ["TARGET_ARCH"]="$EDK2_TARGET_PROPERTIES_ARCH" ["TOOL_CHAIN_TAG"]="$EDK2_TARGET_PROPERTIES_TOOLCHAIN") + +for EDK2_TARGET_PROPERTY in "${!EDK2_TARGET_PROPERTIES[@]}"; do + EDK2_TARGET_PROPERTY_VALUE="${EDK2_TARGET_PROPERTIES[$EDK2_TARGET_PROPERTY]}" + + sed -i "s|^${EDK2_TARGET_PROPERTY}[[:space:]]*=.*\$|${EDK2_TARGET_PROPERTY} = $EDK2_TARGET_PROPERTY_VALUE|" "$EDK2_CONF_TARGET" +done + +export EDK2_LINUX_BIN_PATH="$EDK_TOOLS_PATH/Bin/Linux-x86_64" +export EDK2_POSIX_BIN_PATH="$EDK_TOOLS_PATH/BinWrappers/PosixLike" + +export EDK2_BUILD_COMMAND="$EDK2_POSIX_BIN_PATH/build" + +# add links to needed packages + +mkdir -p "$LIBRARY_PKG_ROOT" + +EDK2_PORT_NAMES=("SDL2Pkg" "SDL2MixerPkg" "SupportLib") +EDK2_PORT_URLS=("https://github.com/Totto16/SDL2_UEFI" "https://github.com/Totto16/SDL2_mixer_UEFI" "https://github.com/Totto16/UefiEdk2SupportLib.git") +EDK2_PORT_TAGS=("uefi_port" "uefi_port" "main") + +for EDK2_PORT_KEY in "${!EDK2_PORT_NAMES[@]}"; do + + EDK2_PORT_NAME="${EDK2_PORT_NAMES[$EDK2_PORT_KEY]}" + EDK2_PORT_URL="${EDK2_PORT_URLS[$EDK2_PORT_KEY]}" + EDK2_PORT_TAG="${EDK2_PORT_TAGS[$EDK2_PORT_KEY]}" + + EDK2_PORT_ROOT="$LIBRARY_PKG_ROOT/$EDK2_PORT_NAME" + + if [ ! -d "$EDK2_PORT_ROOT" ]; then + git clone "$EDK2_PORT_URL" "$EDK2_PORT_ROOT" + else + git -C "$EDK2_PORT_ROOT" fetch + fi + + git -C "$EDK2_PORT_ROOT" checkout "$EDK2_PORT_TAG" + +done + +export EDK2_LLVM_ROOT="$LIBRARY_PKG_ROOT/LLVM" + +if [ ! -d "$EDK2_LLVM_ROOT" ]; then + + git clone --filter=blob:none --sparse https://github.com/Totto16/llvm-project.git "$EDK2_LLVM_ROOT" + git -C "$EDK2_LLVM_ROOT" sparse-checkout set libcxx libc libcxxabi libunwind +else + git -C "$EDK2_LLVM_ROOT" fetch +fi + +git -C "$EDK2_LLVM_ROOT" checkout "$EDK2_LLVM_PORT_BRANCH" + +popd + +export CC="$SCRIPT_DIR/uefi/gcc-wrapper.sh" +export CXX="$SCRIPT_DIR/uefi/g++-wrapper.sh" + +export AR="$SCRIPT_DIR/uefi/ar-wrapper.sh" +export RANLIB="" +export STRIP="false" +export NM="nm" + +export PKG_CONFIG_EXEC="$SCRIPT_DIR/uefi/pkg-config-wrapper.sh" + +export ARCH="x86_64" +export CPU_ARCH="x86_64" +export ENDIANESS="little" + +export ROMFS="platforms/romfs" + +export COMMON_FLAGS="'-m64', '-march=x86-64', '-maccumulate-outgoing-args', '-mno-red-zone', '-mcmodel=small'" + +export SYS_ROOT="$WORKSPACE" + +export PKG_CONFIG_PATH="$SYS_ROOT/lib/pkgconfig" + +export LINK_FLAGS="$COMMON_FLAGS" +export COMPILE_FLAGS="$COMMON_FLAGS ,'--sysroot=${SYS_ROOT}', '-D__UEFI__', '-DEFIAPI=__attribute__((ms_abi))', '-fshort-wchar', '-fno-builtin', '-fno-strict-aliasing', '-fno-common', '-fstack-protector', '-ffunction-sections', '-fdata-sections', '-fno-asynchronous-unwind-tables', '-fno-omit-frame-pointer', '-DAUDIO_PREFER_MP3'" + +export CC_COMPILE_FLAGS="'-nostdinc', '-I$EDK2_LIBC_ROOT/StdLib/Include', '-I$EDK2_LIBC_ROOT/StdLib/Include/$EDK2_TARGET_PROPERTIES_ARCH', '-I$EDK2_ROOT/MdePkg/Include', '-I$EDK2_ROOT/MdePkg/Include/$EDK2_TARGET_PROPERTIES_ARCH','-I$EDK2_LIBC_ROOT'" + +export CXX_COMPILE_FLAGS="'-fno-exceptions', '-fno-threadsafe-statics', '-fno-use-cxa-atexit', '-fno-unwind-tables', '-fno-asynchronous-unwind-tables', '-nostdinc++', '-nodefaultlibs', '-I$EDK2_LLVM_ROOT/libcxx/include', $CC_COMPILE_FLAGS" + +export CROSS_FILE="./platforms/crossbuild/uefi.ini" + +validate_parent_dir "$CROSS_FILE" + +## note: UEFI_USE_GDB can be set via environment variables, to use gdb + +cat <"$CROSS_FILE" +[host_machine] +system = 'uefi' +cpu_family = '$ARCH' +cpu = '$CPU_ARCH' +endian = '$ENDIANESS' + +[target_machine] +system = 'uefi' +cpu_family = '$ARCH' +cpu = '$CPU_ARCH' +endian = '$ENDIANESS' + +[constants] +edk2_root = '$EDK2_ROOT' + +[binaries] +c = '$CC' +cpp = '$CXX' +ar = '$AR' +ranlib = '$RANLIB' +strip = '$STRIP' +nm = '$NM' + + +pkg-config = '$PKG_CONFIG_EXEC' +cmake = '' + +[built-in options] +c_std = 'c11' +cpp_std = 'c++23' +c_args = [$COMPILE_FLAGS, $CC_COMPILE_FLAGS] +cpp_args = [$COMPILE_FLAGS, $CXX_COMPILE_FLAGS] +c_link_args = [$LINK_FLAGS] +cpp_link_args = [$LINK_FLAGS] + +prefix = '$SYS_ROOT' + +[properties] +pkg_config_libdir = '$PKG_CONFIG_PATH' +sys_root = '${SYS_ROOT}' +needs_exe_wrapper = true + +APP_ROMFS='$ROMFS' +RUNTIME_TARGET='$RUNTIME_TARGET' +USE_GDB='${UEFI_USE_GDB:-false}' + +[cmake] + +CMAKE_FIND_ROOT_PATH_MODE_PROGRAM = 'BOTH' +CMAKE_FIND_ROOT_PATH_MODE_LIBRARY = 'ONLY' +CMAKE_FIND_ROOT_PATH_MODE_INCLUDE = 'ONLY' +CMAKE_FIND_ROOT_PATH_MODE_PACKAGE = 'ONLY' + +CMAKE_FIND_ROOT_PATH = '$SYS_ROOT/usr/lib/cmake' + +EOF + +if [ ! -d "$ROMFS" ]; then + + mkdir -p "$ROMFS" + + cp -r "./assets" "$ROMFS/" + + # no need for music + rm -rf "$ROMFS/assets/music/" + +fi + +export EDK2_INFO_FILE="./platforms/crossbuild/uefi_info.json" + +validate_parent_dir "$EDK2_INFO_FILE" + +EDK2_GENERATED_PACKAGES="$(pwd)/$BUILD_DIR/GeneratedPackages" +export EDK2_GENERATED_PACKAGES + +export EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM="$LIBRARY_PKG_ROOT/$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM_NAME" + +cat <"$EDK2_INFO_FILE" +{ + "build": "$EDK2_BUILD_COMMAND", + "arch": "$EDK2_TARGET_PROPERTIES_ARCH", + "workspace": "$WORKSPACE", + "edk2_tools_dir": "$EDK2_TOOLS_DIR", + "edk2_root": "$EDK2_ROOT", + "edk2_libc_root": "$EDK2_LIBC_ROOT", + "edk2_llvm_root": "$EDK2_LLVM_ROOT", + "platform": "$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM", + "platform_name": "$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM_NAME", + "buildtype": "$EDK2_TARGET_PROPERTIES_BUILDTYPE", + "toolchain": "$EDK2_TARGET_PROPERTIES_TOOLCHAIN", + "generated_packages": "$EDK2_GENERATED_PACKAGES", + "runtime_target": "$RUNTIME_TARGET" +} +EOF + +if [ "$COMPILE_TYPE" == "complete_rebuild" ] || [ ! -e "${EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM:?}" ]; then + rm -f "${EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM:?}" + + # copy template for oopetris platform + + mkdir -p "$(dirname "${EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM:?}")" + + cp "$PLATFORMS_DIR/OOPetrisPlatform.template.dsc" "${EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM:?}" + + # add stdlib to active platform + + STDLIB_PACKAGE_INCLUDE="!include StdLib/StdLib.inc" + + if grep -q "$STDLIB_PACKAGE_INCLUDE" "$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM"; then + : # found already, do nothing + else + echo -e "$STDLIB_PACKAGE_INCLUDE\n" >>"$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM" + fi + + # add llvm to active platform + + LLVM_PACKAGE_INCLUDE="!include LLVM/LLVMPkg.inc" + + if grep -q "$LLVM_PACKAGE_INCLUDE" "$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM"; then + : # found already, do nothing + else + echo -e "$LLVM_PACKAGE_INCLUDE\n" >>"$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM" + fi + +fi + +if [ "$COMPILE_TYPE" == "complete_rebuild" ] || [ ! -e "$BUILD_DIR" ]; then + rm -rf "$WORKSPACE/Build/" + + meson setup "$BUILD_DIR" \ + "--prefix=$SYS_ROOT" \ + "--wipe" \ + --cross-file "$CROSS_FILE" \ + "-Dbuildtype=$BUILDTYPE" \ + -Ddefault_library=shared \ + -Dtests=false \ + --force-fallback-for="fmt,nlohmann_json,magic_enum,utf8cpp,sdl2_ttf,freetype2,spdlog,argparse,sdl2_image,c-embed" \ + --wrap-mode=nofallback \ + "-Drun_in_ci=$RUN_IN_CI" \ + -Dstrip=false \ + --fatal-meson-warnings + + if ! [ -L "$EDK2_GENERATED_PACKAGES_ROOT" ]; then + + mkdir -p "$EDK2_GENERATED_PACKAGES" + link_files_checked "$EDK2_GENERATED_PACKAGES" "$EDK2_GENERATED_PACKAGES_ROOT" + + fi + +fi + +meson compile -C "$BUILD_DIR" + +if [ -n "${ENABLE_TESTING:-}" ]; then + + meson test -C "$BUILD_DIR" + +fi diff --git a/platforms/build-web.sh b/platforms/build-web.sh index 8b05e3670..96bf1ac3c 100755 --- a/platforms/build-web.sh +++ b/platforms/build-web.sh @@ -32,7 +32,7 @@ elif [ "$#" -eq 3 ]; then RUN_IN_CI="true" fi else - echo "Too many arguments given, expected 1, 2 or 3" + echo "Too many arguments given, expected 1, 2 or 3" >&2 exit 1 fi @@ -41,7 +41,7 @@ if [ "$COMPILE_TYPE" == "smart" ]; then elif [ "$COMPILE_TYPE" == "complete_rebuild" ]; then : # noop else - echo "Invalid COMPILE_TYPE, expected: 'smart' or 'complete_rebuild'" + echo "Invalid COMPILE_TYPE, expected: 'smart' or 'complete_rebuild'" >&2 exit 1 fi @@ -64,12 +64,12 @@ export EMSCRIPTEN_ROOT if [ ! -d "$EMSCRIPTEN_ROOT" ]; then git clone https://github.com/emscripten-core/emsdk.git "$EMSCRIPTEN_ROOT" - git -C "$EMSCRIPTEN_ROOT" checkout "$EMSCRIPTEN_RELEASE_TAG" else git -C "$EMSCRIPTEN_ROOT" fetch - git -C "$EMSCRIPTEN_ROOT" checkout "$EMSCRIPTEN_RELEASE_TAG" fi +git -C "$EMSCRIPTEN_ROOT" checkout "$EMSCRIPTEN_RELEASE_TAG" + export EMSDK_NODE_TOOL="node-$EMSDK_EXECUTE_NODE_VERSION-64bit" "$EMSCRIPTEN_ROOT/emsdk" install "$EMSCRIPTEN_RELEASE_TAG" "$EMSDK_NODE_TOOL" @@ -77,18 +77,18 @@ export EMSDK_NODE_TOOL="node-$EMSDK_EXECUTE_NODE_VERSION-64bit" EMSCRIPTEN_UPSTREAM_ROOT="$EMSCRIPTEN_ROOT/upstream/emscripten" -EMSCRIPTEN_PACTH_FILE="$EMSCRIPTEN_UPSTREAM_ROOT/.patched_manually.meta" +EMSCRIPTEN_PATCH_FILE="$EMSCRIPTEN_UPSTREAM_ROOT/.patched_manually.meta" PATCH_DIR="platforms/emscripten" -if ! [ -e "$EMSCRIPTEN_PACTH_FILE" ]; then +if ! [ -e "$EMSCRIPTEN_PATCH_FILE" ]; then ##TODO: upstream those patches # see: https://github.com/emscripten-core/emscripten/pull/18379 # and: https://github.com/emscripten-core/emscripten/pull/22946 git apply --unsafe-paths -p1 --directory="$EMSCRIPTEN_UPSTREAM_ROOT" "$PATCH_DIR/sdl2_image_port.diff" - touch "$EMSCRIPTEN_PACTH_FILE" + touch "$EMSCRIPTEN_PATCH_FILE" fi # git apply path @@ -145,7 +145,7 @@ cpu = '$CPU_ARCH' endian = '$ENDIANESS' [constants] -emscripten_root = '$(pwd)/emsdk' +emscripten_root = '$EMSCRIPTEN_ROOT' [binaries] c = '$CC' diff --git a/platforms/build.sh b/platforms/build.sh index 874576f06..ffe4ceb90 100755 --- a/platforms/build.sh +++ b/platforms/build.sh @@ -17,7 +17,7 @@ SCRIPT_DIR="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" PLATFORM="$1" shift -SUPPORTED_PLATFORMS=("3ds" "android" "switch" "web") +SUPPORTED_PLATFORMS=("3ds" "android" "switch" "uefi" "web") for PLTFRM in "${SUPPORTED_PLATFORMS[@]}"; do if [ "$PLATFORM" == "$PLTFRM" ]; then @@ -28,5 +28,5 @@ for PLTFRM in "${SUPPORTED_PLATFORMS[@]}"; do done -echo "Invalid PLATFORM, expected one of: ${SUPPORTED_PLATFORMS[*]}" +echo "Invalid PLATFORM, expected one of: ${SUPPORTED_PLATFORMS[*]}" >&2 exit 1 diff --git a/platforms/helper.sh b/platforms/helper.sh index c766ce2cd..b22f462cd 100755 --- a/platforms/helper.sh +++ b/platforms/helper.sh @@ -1,7 +1,5 @@ #!/usr/bin/env bash -## 3ds section - validate_parent_dir() { local FILE="$1" local PARENT_DIR @@ -11,3 +9,24 @@ validate_parent_dir() { mkdir -p "$PARENT_DIR" fi } + +validate_abs() { + local FILE="$1" + + if [[ "${FILE:0:1}" != "/" ]]; then + echo "Not an absolute path: $FILE" >&2 + exit 7 + fi + +} + +link_files_checked() { + local SOURCE="$1" + local DEST="$2" + + validate_abs "$SOURCE" + validate_abs "$DEST" + + ln -s "$SOURCE" "$DEST" + +} diff --git a/platforms/uefi/OOPetrisPlatform.template.dsc b/platforms/uefi/OOPetrisPlatform.template.dsc new file mode 100644 index 000000000..0c6852b67 --- /dev/null +++ b/platforms/uefi/OOPetrisPlatform.template.dsc @@ -0,0 +1,277 @@ +[Defines] + PLATFORM_NAME = OOPetrisModule + PLATFORM_GUID = 6e7aa053-beda-40a8-b729-375bd9c71e2c + PLATFORM_VERSION = 1.0 + DSC_SPECIFICATION = 0x0001001B + OUTPUT_DIRECTORY = Build/OOPetrisModule + SUPPORTED_ARCHITECTURES = X64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + + +!ifndef OOPETRIS_RUNTIME_TARGET + !error "OOPETRIS_RUNTIME_TARGET must be set" +!endif + + # + # RUNTIME TARGET related defintions + # + +!if $(OOPETRIS_RUNTIME_TARGET) == "hardware" + DEFINE PLAT_QEMU = FALSE + DEFINE QEMU_PV_VARS = FALSE + DEFINE DEBUG_ON_SERIAL_PORT = FALSE +!elseif $(OOPETRIS_RUNTIME_TARGET) == "emulator" + DEFINE PLAT_QEMU = TRUE + DEFINE QEMU_PV_VARS = FALSE + DEFINE DEBUG_ON_SERIAL_PORT = TRUE +!else + !error "OOPETRIS_RUNTIME_TARGET has invalid value" +!endif + + # + # Default definitions + # + + DEFINE TTY_TERMINAL = FALSE + DEFINE DEBUG_TO_MEM = FALSE + + # + # Network definition + # + DEFINE NETWORK_SNP_ENABLE = FALSE + DEFINE NETWORK_IP6_ENABLE = TRUE + DEFINE NETWORK_TLS_ENABLE = TRUE + DEFINE NETWORK_HTTP_BOOT_ENABLE = FALSE + DEFINE NETWORK_ALLOW_HTTP_CONNECTIONS = TRUE + DEFINE NETWORK_HTTP_ENABLE = TRUE + DEFINE NETWORK_ISCSI_ENABLE = FALSE + DEFINE SECURE_BOOT_ENABLE = FALSE + DEFINE NETWORK_PXE_BOOT_ENABLE = FALSE + + # + # Other defintions + # + + DEFINE CUSTOM_STACK_CHECK_LIB = "STATIC" + + + + # + # Redfish definition + # + DEFINE REDFISH_ENABLE = FALSE + +!include MdePkg/MdeLibs.dsc.inc + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + # + # Entry point + # + PeiCoreEntryPoint|MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf + PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf + DxeCoreEntryPoint|MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + + # + # Basic + # + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf + PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf + PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf + PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf + CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf + PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + SortLib|MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf + + # + # UEFI & PI + # + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf + HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf + UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf + VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf + + # + # Generic Modules + # + UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf + UefiScsiLib|MdePkg/Library/UefiScsiLib/UefiScsiLib.inf + SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf + ## see below: TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf + +!if $(OOPETRIS_RUNTIME_TARGET) == "hardware" + # DebugLib + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf-TODO-not-implemented-and-checked-yet + + TODO|not implemented and checked yet + # SupportLib and TimerLib + #TODO: doesn't work on qemu, but maybe on CPU?? + TimerLib|UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf + LibUEfiSupportNanosleep|SupportLib/Library/Default/SupportLibDefaultNanosleep.inf + LibUEfiSupportClock|SupportLib/Library/TimerLib/SupportLibTimerClock.inf +!else + # DebugLib + DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf + MemDebugLogLib|OvmfPkg/Library/MemDebugLogLib/MemDebugLogLibNull.inf + + # Support and TimerLib + LibUEfiSupportNanosleep|SupportLib/Library/Default/SupportLibDefaultNanosleep.inf + LibUEfiSupportClock|SupportLib/Library/TimerLib/SupportLibTimerClock.inf + #LibUEfiSupportClock|LibraryPkg/SupportLib/Library/Default/SupportLibDefaultClock.inf + #LibUEfiSupportClock|LibraryPkg/SupportLib/Library/Null/SupportLibNullClock.inf + + ## doesn't work on qemu, setup (cpuid leaf 0x15) error + ## TimerLib|UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf + + ## not supported for DXE or UEFI_APPLICATION: + ## TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf + + ## NOT WORKING on some machines, works with q35, but not the default (pc?), + ## the reason is Pmba reading is incorrect in the timerlib Constructor :( + ## TimerLib|OvmfPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf + + ## not working: need special emulator? + ## TimerLib|EmulatorPkg/Library/DxeTimerLib/DxeTimerLib.inf + + TimerLib|OvmfPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf + +!endif + + ShellCEntryLibDynamical|SupportLib/Library/UefiShellCEntryLibDynamical/UefiShellCEntryLibDynamical.inf + + + CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf + FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf + + # + # Misc + # + ## see above: DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf + PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf + DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf + PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf + ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf + SmbusLib|MdePkg/Library/DxeSmbusLib/DxeSmbusLib.inf + S3BootScriptLib|MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf + CpuExceptionHandlerLib|MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf + PlatformBootManagerLib|MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf + PciHostBridgeLib|MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.inf + TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf + TdxMeasurementLib|MdeModulePkg/Library/TdxMeasurementLibNull/TdxMeasurementLibNull.inf + AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf + VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf + FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf + NonDiscoverableDeviceRegistrationLib|MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.inf + ImagePropertiesRecordLib|MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf + + FmpAuthenticationLib|MdeModulePkg/Library/FmpAuthenticationLibNull/FmpAuthenticationLibNull.inf + BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf + SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf + DisplayUpdateProgressLib|MdeModulePkg/Library/DisplayUpdateProgressLibGraphics/DisplayUpdateProgressLibGraphics.inf + VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf + MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf + VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf + IpmiCommandLib|MdeModulePkg/Library/BaseIpmiCommandLibNull/BaseIpmiCommandLibNull.inf + SpiHcPlatformLib|MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.inf + +[LibraryClasses.common.DXE_CORE] + HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf + MemoryAllocationLib|MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf + ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf + +[LibraryClasses.common.DXE_DRIVER] + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf + CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf + +[LibraryClasses.common.UEFI_DRIVER] + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + #see above: DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf + LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf + + +[LibraryClasses.common.UEFI_APPLICATION] + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + #see above: DebugLib|MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf + FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf + +#start crypto related libs +[LibraryClasses] + ## TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf + RngLib|MdePkg/Library/BaseRngLibNull/BaseRngLibNull.inf + OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf + HashApiLib|CryptoPkg/Library/BaseHashApiLib/BaseHashApiLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + +[LibraryClasses.IA32, LibraryClasses.X64, LibraryClasses.AARCH64] + RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf + +[LibraryClasses.AARCH64] + ArmLib|MdePkg/Library/ArmLib/ArmBaseLib.inf + +[LibraryClasses.common] + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf + TlsLib|CryptoPkg/Library/TlsLib/TlsLib.inf + +#end crypto related libs + + + +[PcdsFixedAtBuild] +!if $(OOPETRIS_RUNTIME_TARGET) == "hardware" +# nothing +!else +#define DEBUG_WARN 0x00000002 // Warnings +#define DEBUG_INFO 0x00000040 // Informational debug messages +#define DEBUG_VERBOSE 0x00400000 // Detailed debug messages that may +#define DEBUG_ERROR 0x80000000 // Error + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80400042 + +## This flag is used to control the destination port for PlatformDebugLibIoPort +# this is the same address as QEMU uses + gUefiOvmfPkgTokenSpaceGuid.PcdDebugIoPort|0x402 + +#define DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED 0x01 +#define DEBUG_PROPERTY_DEBUG_PRINT_ENABLED 0x02 +#define DEBUG_PROPERTY_DEBUG_CODE_ENABLED 0x04 +#define DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED 0x08 +#define DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED 0x10 +#define DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED 0x20 + + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x3F + +!endif + + # disable auto initialize, initialize manually, and if it fails, use backup non shell code backup + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE + + +# inserted components / includes after that + diff --git a/platforms/uefi/ar-wrapper.sh b/platforms/uefi/ar-wrapper.sh new file mode 100755 index 000000000..67553780e --- /dev/null +++ b/platforms/uefi/ar-wrapper.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash + +# Exit immediately if a command exits with a non-zero status. +set -e +## Treat undefined variables as an error +set -u +# fails if any part of a pipeline (|) fails +set -o pipefail + +SCRIPT_DIR="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" + +# shellcheck source=./platforms/helper.sh +source "$SCRIPT_DIR/../helper.sh" + +TOOL="AR" +AR="gcc-ar-15" + +# shellcheck source=./platforms/uefi/base.sh +source "$SCRIPT_DIR/base.sh" + +# Capture all args +ARGS=("$@") + +OUTPUT_FILE="" +DEPENDENCIES=() + +for ARG in "${ARGS[@]}"; do + case "$ARG" in + --version) + change_mode "pass" + ;; + csr) + change_mode "create" + change_next_type "output" + ;; + *) + if [[ "$NEXT_TYPE" == "output" ]]; then + OUTPUT_FILE="$(normalize_file "$ARG")" + reset_next_type + elif [[ "$NEXT_TYPE" == "ignore" ]]; then + reset_next_type + elif [[ "$NEXT_TYPE" == "unknown" ]]; then + case "$ARG" in + *.o) + DEPENDENCIES+=("$(resolve_file "$ARG")") + ;; + *.a | *.so) + echo "Invalid file detected: '$ARG'" >&2 + exit 5 + ;; + *) + echo "Invalid argument detected: '$ARG'" >&2 + exit 6 + ;; + esac + else + echo "Not recognized next type: $NEXT_TYPE" >&2 + exit 11 + fi + ;; + esac +done + +if [[ "$MODE" == "pass" ]]; then + exec "$AR" "${ARGS[@]}" +elif [[ "$MODE" == "create" ]]; then + if [ -z "$OUTPUT_FILE" ]; then + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Missing output file" >&2 + exit 2 + fi + + validate_parent_dir "$OUTPUT_FILE" + + validate_dependencies "${DEPENDENCIES[@]}" + + cat <"$OUTPUT_FILE" +{ + "cwd": "$(pwd)", + "args": $(to_json_array "${ARGS[@]}"), + "language": "ar", + "type": "archive", + "dependencies": { + "output": "$OUTPUT_FILE", + "files": $(to_json_array "${DEPENDENCIES[@]}") + } +} +EOF + +else + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Not recognized intent: $MODE" >&2 + exit 2 +fi diff --git a/platforms/uefi/base.sh b/platforms/uefi/base.sh new file mode 100755 index 000000000..b7868784e --- /dev/null +++ b/platforms/uefi/base.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env bash + +validate_dependencies() { + local DEPENDENCIES=("$@") + + for DEPENDENCY in "${DEPENDENCIES[@]}"; do + FILE="$(realpath "$DEPENDENCY")" + + if ! (jq -e "." "$FILE" >/dev/null); then + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Dependency '$FILE' is not a valid json file" >&2 + exit 5 + fi + + done +} + +validate_files() { + local FILES=("$@") + + for FILE in "${FILES[@]}"; do + FILE="$(realpath "$FILE")" + + if ! [ -e "$FILE" ]; then + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "File '$FILE' does not exist" >&2 + exit 5 + fi + + done +} + +MODE="unknown" + +change_mode() { + local NEW_MODE="$1" + + if [[ "$MODE" == "unknown" ]]; then + MODE="$NEW_MODE" + elif [[ "$MODE" == "$NEW_MODE" ]]; then + : + else + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Can't change mode from $MODE to $NEW_MODE" >&2 + exit 4 + fi +} + +NEXT_TYPE="unknown" + +change_next_type() { + local NEW_TYPE="$1" + + if [[ "$NEXT_TYPE" == "unknown" ]]; then + NEXT_TYPE="$NEW_TYPE" + elif [[ "$NEXT_TYPE" == "$NEW_TYPE" ]]; then + : + else + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Can't change next type from $NEXT_TYPE to $NEW_TYPE" >&2 + exit 4 + fi +} + +reset_next_type() { + NEXT_TYPE="unknown" +} + +require_empty_array() { + local ARRAY=("$@") + + if [ "${#ARRAY[@]}" -ne 0 ]; then + echo "Array is not empty but ${#ARRAY[@]} long" >&2 + exit 9 + fi +} + +to_json_array() { + local ARRAY=("$@") + + if [ "${#ARRAY[@]}" -eq 0 ]; then + echo "[]" + else + printf '%s\n' "${ARRAY[@]}" | jq -R . | jq -sc . + fi +} + +resolve_file() { + local FILE="$1" + + if ! [ -e "$FILE" ]; then + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Can't resolve file '$FILE': not found" >&2 + exit 6 + fi + + realpath "$FILE" + +} + +normalize_file() { + local FILE="$1" + + realpath "$FILE" +} + +is_soname() { + local SO_NAME="$1" + [[ "$SO_NAME" =~ (^|/)lib[^/]+\.so(\.[0-9]+)*$ ]] +} diff --git a/platforms/uefi/c-embed-wrapper.sh b/platforms/uefi/c-embed-wrapper.sh new file mode 100755 index 000000000..bd5898f7f --- /dev/null +++ b/platforms/uefi/c-embed-wrapper.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +# Exit immediately if a command exits with a non-zero status. +set -e +## Treat undefined variables as an error +set -u +# fails if any part of a pipeline (|) fails +set -o pipefail + +SCRIPT_DIR="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" + +# shellcheck source=./platforms/helper.sh +source "$SCRIPT_DIR/../helper.sh" + +TOOL="C-EMBED" +# Capture all args +ARGS=("$@") + +# shellcheck source=./platforms/uefi/base.sh +source "$SCRIPT_DIR/base.sh" + +if [ "$#" -eq 3 ]; then + C_EMBED_EXE="$(realpath "$1")" + INPUT_FOLDER="$(realpath "$2")" + OUTPUT_FILE="$(realpath "$3")" +else + echo "Too many arguments given, expected 3" >&2 + exit 1 +fi + +"$C_EMBED_EXE" "$INPUT_FOLDER" + +PARENT_DIR="$(dirname "$OUTPUT_FILE")" + +if [[ ! -d "$PARENT_DIR" ]]; then + mkdir -p "$PARENT_DIR" +fi + +REAL_O_FILE="$PARENT_DIR/c-embed_compiled.o" + +mv "./c-embed.o" "$REAL_O_FILE" + +# create a "extern_object" json description for the automatic inf creation process to generate the inf for this file, as if it was compiled via the edk2 toolchain, but it wasn't +cat <"$OUTPUT_FILE" +{ + "cwd": "$(pwd)", + "args": $(to_json_array), + "language": "c", + "type": "extern_object", + "dependencies": { + "output": "$OUTPUT_FILE", + "extern": $(to_json_array "$REAL_O_FILE") + } +} +EOF diff --git a/platforms/uefi/compile-final.sh b/platforms/uefi/compile-final.sh new file mode 100755 index 000000000..f244b2f17 --- /dev/null +++ b/platforms/uefi/compile-final.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash + +# Exit immediately if a command exits with a non-zero status. +set -e +## Treat undefined variables as an error +set -u +# fails if any part of a pipeline (|) fails +set -o pipefail + +SCRIPT_DIR="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" + +# shellcheck source=./platforms/helper.sh +source "$SCRIPT_DIR/../helper.sh" + +if [ "$#" -eq 2 ]; then + BUILD_INF="$(realpath "$1")" + DEST_FILE="$(realpath "$2")" +else + echo "Too many arguments given, expected 2" >&2 + exit 1 +fi + +UEFI_INFO_FILE="$(realpath "$SCRIPT_DIR/../crossbuild/uefi_info.json")" +EDK2_BUILD_COMMAND="$(jq -M -r -c '.["build"]' "$UEFI_INFO_FILE")" +EDK2_TARGET_PROPERTIES_ARCH="$(jq -M -r -c '.["arch"]' "$UEFI_INFO_FILE")" +WORKSPACE="$(jq -M -r -c '.["workspace"]' "$UEFI_INFO_FILE")" +EDK2_TOOLS_DIR="$(jq -M -r -c '.["edk2_tools_dir"]' "$UEFI_INFO_FILE")" +EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM="$(jq -M -r -c '.["platform"]' "$UEFI_INFO_FILE")" +EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM_NAME="$(jq -M -r -c '.["platform_name"]' "$UEFI_INFO_FILE")" +EDK2_TARGET_PROPERTIES_BUILDTYPE="$(jq -M -r -c '.["buildtype"]' "$UEFI_INFO_FILE")" +EDK2_TARGET_PROPERTIES_TOOLCHAIN="$(jq -M -r -c '.["toolchain"]' "$UEFI_INFO_FILE")" +EDK2_TARGET_PROPERTIES_RUNTIME_TARGET="$(jq -M -r -c '.["runtime_target"]' "$UEFI_INFO_FILE")" + +BUILD_NAME=$(basename -- $"$BUILD_INF") + +BUILD_FILE_TARGET="GeneratedPackages/$BUILD_NAME" + +BUILD_FILE_TARGET_ABS="$EDK2_TOOLS_DIR/$BUILD_FILE_TARGET" + +if ! [ -e "$BUILD_FILE_TARGET_ABS" ]; then + echo "Build file is not in the expected place: $BUILD_FILE_TARGET" >&2 + exit 2 +elif ! readlink "$BUILD_FILE_TARGET_ABS"; then + echo "Build file is not a symlink: $BUILD_FILE_TARGET_ABS" >&2 + exit 2 +else + BUILD_TARGET_LINK_TARGET="$(readlink "$BUILD_FILE_TARGET_ABS")" + + if [ "$BUILD_TARGET_LINK_TARGET" != "$BUILD_INF" ]; then + echo "Build file isn't linked correctly: '$BUILD_TARGET_LINK_TARGET' != '$BUILD_INF'" >&2 + exit 2 + fi +fi + +"$EDK2_BUILD_COMMAND" -a "$EDK2_TARGET_PROPERTIES_ARCH" \ + -p "$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM" \ + -m "$BUILD_NAME" \ + -b "$EDK2_TARGET_PROPERTIES_BUILDTYPE" \ + -t "$EDK2_TARGET_PROPERTIES_TOOLCHAIN" \ + -D "OOPETRIS_RUNTIME_TARGET=$EDK2_TARGET_PROPERTIES_RUNTIME_TARGET" \ + -w # -v # verbose + +##TODO: un-hardcode this +##NOTE: this is just hardcoded +PACKAGE_NAME="OOPetrisApplication" + +if [ "$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM_NAME" == "Platforms/OOPetrisPlatform.dsc" ]; then + MODULE_NAME="OOPetrisModule" +else + echo "MODULE_NAME mapping not supported for platform: $EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM_NAME" >&2 + exit 2 +fi + +OUTPUT_FILE="$WORKSPACE/Build/$MODULE_NAME/${EDK2_TARGET_PROPERTIES_BUILDTYPE}_${EDK2_TARGET_PROPERTIES_TOOLCHAIN}/${EDK2_TARGET_PROPERTIES_ARCH}/$PACKAGE_NAME.efi" + +# link the output .efi to the correct location +if ! [ -e "$DEST_FILE" ]; then + link_files_checked "$OUTPUT_FILE" "$DEST_FILE" +fi diff --git a/platforms/uefi/create-fat-folder.sh b/platforms/uefi/create-fat-folder.sh new file mode 100755 index 000000000..ba58cdc00 --- /dev/null +++ b/platforms/uefi/create-fat-folder.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +# Exit immediately if a command exits with a non-zero status. +set -e +## Treat undefined variables as an error +set -u +# fails if any part of a pipeline (|) fails +set -o pipefail + +SCRIPT_DIR="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" + +# shellcheck source=./platforms/helper.sh +source "$SCRIPT_DIR/../helper.sh" + +if [ "$#" -eq 3 ]; then + FAT_FOLDER_LOC="$(realpath "$1")" + EFI_FILE="$(realpath "$2")" + PSEUDO_OUTPUT="$(realpath "$3")" +else + echo "Too many arguments given, expected 3" >&2 + exit 1 +fi + +rm -rf "$FAT_FOLDER_LOC" + +BOOT_FOLDER_LOC="$FAT_FOLDER_LOC/EFI/BOOT" + +mkdir -p "$BOOT_FOLDER_LOC" + +DEST_FILE="$BOOT_FOLDER_LOC/BOOTX64.EFI" + +# copy the output .efi to the correct location +if ! [ -e "$DEST_FILE" ]; then + cp -p -f "$EFI_FILE" "$DEST_FILE" +fi + +touch "$PSEUDO_OUTPUT" diff --git a/platforms/uefi/edk2-libc/0001-feat-make-LibC-support-C.patch b/platforms/uefi/edk2-libc/0001-feat-make-LibC-support-C.patch new file mode 100644 index 000000000..12837fbe8 --- /dev/null +++ b/platforms/uefi/edk2-libc/0001-feat-make-LibC-support-C.patch @@ -0,0 +1,188 @@ +From f7003762ba238197634d4769c49e2d7c98757552 Mon Sep 17 00:00:00 2001 +From: Totto16 +Date: Fri, 21 Aug 2026 18:28:16 +0200 +Subject: [PATCH 1/3] feat: make LibC support C++ - make the includes support + c++ - fix some other small libc related things + +--- + StdLib/Include/assert.h | 7 +++++++ + StdLib/Include/math.h | 8 ++++++++ + StdLib/Include/time.h | 3 ++- + StdLib/Include/wchar.h | 3 +++ + StdLib/LibC/Math/s_ceil.c | 4 ++++ + StdLib/LibC/Stdio/Stdio.inf | 1 + + StdLib/LibC/Stdio/ftello.c | 13 +++++++++++++ + StdLib/LibC/Stdio/vasprintf.c | 9 +++------ + StdLib/LibC/gdtoa/gdtoa.inf | 3 +++ + 9 files changed, 44 insertions(+), 7 deletions(-) + +diff --git a/StdLib/Include/assert.h b/StdLib/Include/assert.h +index 26c7037..5296e9a 100644 +--- a/StdLib/Include/assert.h ++++ b/StdLib/Include/assert.h +@@ -25,6 +25,9 @@ + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + **/ ++ ++#ifndef _ASSERT_H_ ++#define _ASSERT_H_ + #include + + #undef assert ///< Remove any existing definition for assert. +@@ -49,6 +52,7 @@ + current application and returns to the environment that + the application was launched from. + **/ ++__BEGIN_DECLS + extern void + __assert(const char *file, const char *func, int line, const char *failedexpr); + +@@ -78,5 +82,8 @@ __assert(const char *file, const char *func, int line, const char *failedexpr); + #define assert(Expression) ((Expression) ? (void)0 :\ + __assert(__FILE__, __func__, __LINE__, #Expression) ) + #endif ++__END_DECLS + /// @} + /* END of file assert.h */ ++ ++#endif /* _ASSERT_H_ */ +diff --git a/StdLib/Include/math.h b/StdLib/Include/math.h +index 3041120..9eb0be2 100644 +--- a/StdLib/Include/math.h ++++ b/StdLib/Include/math.h +@@ -288,6 +288,14 @@ double sqrt(double Arg); + **/ + double ceil(double Arg); + ++/** Compute the smallest integer value not less than Arg. ++ ++ @param[in] Arg The value to compute the ceiling of. ++ ++ @return The ceiling of Arg expressed as a floating-point number. ++**/ ++float ceilf(float Arg); ++ + /** Compute the absolute value of Arg. + + @param[in] Arg The value to compute the absolute value of. +diff --git a/StdLib/Include/time.h b/StdLib/Include/time.h +index ecef1e2..7d7f70e 100644 +--- a/StdLib/Include/time.h ++++ b/StdLib/Include/time.h +@@ -138,6 +138,7 @@ + broken-down time. The first nine (9) members are as mandated by the + C95 standard. Additional fields have been added for EFI support. + **/ ++__BEGIN_DECLS + struct tm { + int tm_year; // years since 1900 + int tm_mon; // months since January [0, 11] +@@ -430,5 +431,5 @@ char *strptime(const char *, const char * format, struct tm*); + /* ################# Implementation Functions ########################### */ + + clock_t __getCPS(void); +- ++__END_DECLS + #endif /* _TIME_H */ +diff --git a/StdLib/Include/wchar.h b/StdLib/Include/wchar.h +index 3acc2a4..59e9d61 100644 +--- a/StdLib/Include/wchar.h ++++ b/StdLib/Include/wchar.h +@@ -455,6 +455,7 @@ struct tm; + transmitted, or a negative value if an output or encoding error + occurred. + **/ ++__BEGIN_DECLS + int fwprintf(FILE * __restrict stream, const wchar_t * __restrict format, ...); + + /** The fwscanf function reads input from the stream pointed to by stream, +@@ -1549,4 +1550,6 @@ size_t mbsrtowcs(wchar_t * __restrict dst, const char ** __restrict src, size_t + **/ + size_t wcsrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t len, mbstate_t * __restrict ps); + ++__END_DECLS ++ + #endif /* _WCHAR_H */ +diff --git a/StdLib/LibC/Math/s_ceil.c b/StdLib/LibC/Math/s_ceil.c +index e9579fa..64611d4 100644 +--- a/StdLib/LibC/Math/s_ceil.c ++++ b/StdLib/LibC/Math/s_ceil.c +@@ -72,3 +72,7 @@ ceil(double x) + INSERT_WORDS(x,i0,i1); + return x; + } ++ ++float ceilf(float x){ ++ return (float)ceil((double)x); ++} +diff --git a/StdLib/LibC/Stdio/Stdio.inf b/StdLib/LibC/Stdio/Stdio.inf +index fe87242..df122fa 100644 +--- a/StdLib/LibC/Stdio/Stdio.inf ++++ b/StdLib/LibC/Stdio/Stdio.inf +@@ -90,6 +90,7 @@ + swprintf.c # + swscanf.c # + ungetwc.c # ++ vasprintf.c # + vfwscanf.c # + vswprintf.c # + vswscanf.c # +diff --git a/StdLib/LibC/Stdio/ftello.c b/StdLib/LibC/Stdio/ftello.c +index 0677d1a..a9c1031 100644 +--- a/StdLib/LibC/Stdio/ftello.c ++++ b/StdLib/LibC/Stdio/ftello.c +@@ -98,3 +98,16 @@ ftello(FILE *fp) + FUNLOCKFILE(fp); + return (pos); + } ++ ++ ++// instead of using weak symbol, define an alias ++ ++#ifdef ftello ++#undef ftello ++#endif ++ ++off_t ++ftello(FILE *fp) ++{ ++ return _ftello(fp); ++} +diff --git a/StdLib/LibC/Stdio/vasprintf.c b/StdLib/LibC/Stdio/vasprintf.c +index 3a36468..e8ba589 100644 +--- a/StdLib/LibC/Stdio/vasprintf.c ++++ b/StdLib/LibC/Stdio/vasprintf.c +@@ -39,12 +39,9 @@ __RCSID("$NetBSD: vasprintf.c,v 1.10 2005/02/09 21:35:47 kleink Exp $"); + #include "reentrant.h" + #include "local.h" + +-int +-vasprintf(str, fmt, ap) +- char **str; +- const char *fmt; +- _BSD_VA_LIST_ ap; +-{ ++#include ++ ++int vasprintf( char **str, const char *fmt, va_list ap){ + int ret; + FILE f; + struct __sfileext fext; +diff --git a/StdLib/LibC/gdtoa/gdtoa.inf b/StdLib/LibC/gdtoa/gdtoa.inf +index 9d975bb..44af305 100644 +--- a/StdLib/LibC/gdtoa/gdtoa.inf ++++ b/StdLib/LibC/gdtoa/gdtoa.inf +@@ -61,6 +61,9 @@ + sum.c + ulp.c + ++ _strtof.c ++ _strtold.c ++ + [Packages] + StdLib/StdLib.dec + StdLibPrivateInternalFiles/DoNotUse.dec +-- +2.53.0 + diff --git a/platforms/uefi/edk2-libc/0002-fix-fix-naming-of-LibCType-to-LibCtype.patch b/platforms/uefi/edk2-libc/0002-fix-fix-naming-of-LibCType-to-LibCtype.patch new file mode 100644 index 000000000..e49efa981 --- /dev/null +++ b/platforms/uefi/edk2-libc/0002-fix-fix-naming-of-LibCType-to-LibCtype.patch @@ -0,0 +1,78 @@ +From 064d91037d5661b0520c1620f1de61310bd3eae4 Mon Sep 17 00:00:00 2001 +From: Totto16 +Date: Fri, 21 Aug 2026 18:28:44 +0200 +Subject: [PATCH 2/3] fix: fix naming of LibCType to LibCtype + +--- + StdLib/LibC/Locale/Locale.inf | 2 +- + StdLib/LibC/StdLib/StdLib.inf | 2 +- + StdLib/LibC/Stdio/Stdio.inf | 2 +- + StdLib/LibC/String/String.inf | 2 +- + StdLib/StdLib.inc | 2 +- + 5 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/StdLib/LibC/Locale/Locale.inf b/StdLib/LibC/Locale/Locale.inf +index 1bbb611..1c81272 100644 +--- a/StdLib/LibC/Locale/Locale.inf ++++ b/StdLib/LibC/Locale/Locale.inf +@@ -61,4 +61,4 @@ + + [LibraryClasses] + LibC +- LibCType ++ LibCtype +diff --git a/StdLib/LibC/StdLib/StdLib.inf b/StdLib/LibC/StdLib/StdLib.inf +index e7bdf5a..968e6a7 100644 +--- a/StdLib/LibC/StdLib/StdLib.inf ++++ b/StdLib/LibC/StdLib/StdLib.inf +@@ -53,7 +53,7 @@ + MemoryAllocationLib + ShellLib + LibC +- LibCType ++ LibCtype + LibSignal + + ################################################################ +diff --git a/StdLib/LibC/Stdio/Stdio.inf b/StdLib/LibC/Stdio/Stdio.inf +index df122fa..c6e6071 100644 +--- a/StdLib/LibC/Stdio/Stdio.inf ++++ b/StdLib/LibC/Stdio/Stdio.inf +@@ -129,7 +129,7 @@ + + [LibraryClasses] + LibC +- LibCType ++ LibCtype + LibGdtoa + LibLocale + LibStdLib +diff --git a/StdLib/LibC/String/String.inf b/StdLib/LibC/String/String.inf +index c8b4d88..4bd06da 100644 +--- a/StdLib/LibC/String/String.inf ++++ b/StdLib/LibC/String/String.inf +@@ -48,7 +48,7 @@ + PrintLib # Used for strerror() + PcdLib + LibC +- LibCType ++ LibCtype + LibStdLib + + ################################################################ +diff --git a/StdLib/StdLib.inc b/StdLib/StdLib.inc +index 8083e2b..4d08302 100644 +--- a/StdLib/StdLib.inc ++++ b/StdLib/StdLib.inc +@@ -29,7 +29,7 @@ + # C Standard Libraries + # + LibC|StdLib/LibC/LibC.inf +- LibCType|StdLib/LibC/Ctype/Ctype.inf ++ LibCtype|StdLib/LibC/Ctype/Ctype.inf + LibLocale|StdLib/LibC/Locale/Locale.inf + LibMath|StdLib/LibC/Math/Math.inf + LibSignal|StdLib/LibC/Signal/Signal.inf +-- +2.53.0 + diff --git a/platforms/uefi/edk2-libc/0003-feat-add-c-and-c-constructors.patch b/platforms/uefi/edk2-libc/0003-feat-add-c-and-c-constructors.patch new file mode 100644 index 000000000..e5665d6d5 --- /dev/null +++ b/platforms/uefi/edk2-libc/0003-feat-add-c-and-c-constructors.patch @@ -0,0 +1,189 @@ +From 7ea2fb646693a14f43ae8e85d861b67dc7e4ae43 Mon Sep 17 00:00:00 2001 +From: Totto16 +Date: Tue, 25 Aug 2026 17:06:59 +0200 +Subject: [PATCH 3/3] feat: add c and c++ constructors - add libcxx and libc + interlaving constructors and destructors, that are invoked before + .init_array and .fini_array - use better option to run libc initializer, use + the same mechanism as the init_array and fini_array one, but with other + section names, so that it can be run before any init array (note we have + .preinit_array but no destructor counterpart) + +--- + StdLib/Include/libc/main.h | 18 ++++++++ + StdLib/LibC/LibC.inf | 1 + + StdLib/LibC/Main/Main.c | 94 +++++++++++++++++++++++++++++++++++--- + StdLib/StdLib.inc | 2 + + 4 files changed, 109 insertions(+), 6 deletions(-) + create mode 100644 StdLib/Include/libc/main.h + +diff --git a/StdLib/Include/libc/main.h b/StdLib/Include/libc/main.h +new file mode 100644 +index 0000000..65bd539 +--- /dev/null ++++ b/StdLib/Include/libc/main.h +@@ -0,0 +1,18 @@ ++ ++#pragma once ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define EDK2_LIBC_ENTRY_NAME edk2_libc_main ++ ++extern int EDK2_LIBC_ENTRY_NAME(int, char**); ++ ++#ifdef __cplusplus ++} ++ ++#define EDK2_LIBCXX_ENTRY_NAME edk2_libcxx_main ++ ++extern int EDK2_LIBCXX_ENTRY_NAME(int, char**); ++#endif +diff --git a/StdLib/LibC/LibC.inf b/StdLib/LibC/LibC.inf +index 40b2222..4130326 100644 +--- a/StdLib/LibC/LibC.inf ++++ b/StdLib/LibC/LibC.inf +@@ -118,3 +118,4 @@ + GCC:*_*_IA32_CC_FLAGS = -fno-lto + GCC:*_*_ARM_CC_FLAGS = -fno-lto + GCC:*_*_LOONGARCH64_CC_FLAGS = -fno-lto ++ GCC:*_*_*_CC_FLAGS = -Wprio-ctor-dtor +diff --git a/StdLib/LibC/Main/Main.c b/StdLib/LibC/Main/Main.c +index b203d15..69204cd 100644 +--- a/StdLib/LibC/Main/Main.c ++++ b/StdLib/LibC/Main/Main.c +@@ -31,17 +31,95 @@ + #include + #include + +-extern int main( int, char**); ++#include ++ + extern int __sse2_available; + + struct __MainData *gMD; + +-/* Worker function to keep GCC happy. */ +-void __main() +-{ +- ; ++// these symbols are provided by the linker from the extions .init_array and .fini_array ++typedef void (*init_func_t)(void); ++ ++extern init_func_t __init_array_start[] __attribute__((section(".init_array"), aligned(sizeof(init_func_t)))); ++extern init_func_t __init_array_end[] __attribute__((section(".init_array"), aligned(sizeof(init_func_t)))); ++ ++extern init_func_t __fini_array_start[] __attribute__((section(".fini_array"), aligned(sizeof(init_func_t)))); ++extern init_func_t __fini_array_end[] __attribute__((section(".fini_array"), aligned(sizeof(init_func_t)))); ++ ++extern init_func_t __libc_init_array_start[] __attribute__((section(".init_array"), aligned(sizeof(init_func_t)))); ++extern init_func_t __libc_init_array_end[] __attribute__((section(".init_array"), aligned(sizeof(init_func_t)))); ++ ++extern init_func_t __libc_fini_array_start[] __attribute__((section(".fini_array"), aligned(sizeof(init_func_t)))); ++extern init_func_t __libc_fini_array_end[] __attribute__((section(".fini_array"), aligned(sizeof(init_func_t)))); ++ ++ ++ ++// see: https://gcc.gnu.org/onlinedocs/gccint/Initialization.html ++// for more information on how gcc handles initialization ++ ++static void run_init_array(void) { ++ size_t size = __init_array_end - __init_array_start; ++ for (size_t i = 0; i < size; ++i) { ++ init_func_t func = __init_array_start[i]; ++ if (*func != NULL) { ++ (*func)(); ++ } ++ } ++} ++ ++static void run_fini_array(void) { ++ // iterate reversed ++ size_t size = __fini_array_end - __fini_array_start; ++ for (size_t i = size; i != 0; --i) { ++ init_func_t func = __fini_array_start[i - 1]; ++ if (*func != NULL) { ++ (*func)(); ++ } ++ } ++} ++ ++// see eg. here for some information: ++// https://maskray.me/blog/2021-11-07-init-ctors-init-array ++ ++static void edk2_libc_call_constructors(void) { ++ run_init_array(); ++} ++ ++static void edk2_libc_call_destructors(void) { ++ run_fini_array(); ++} ++ ++static void __c_uefi_init_libc(void) { ++ size_t size = __libc_init_array_end - __libc_init_array_start; ++ for (size_t i = 0; i < size; ++i) { ++ init_func_t func = __libc_init_array_start[i]; ++ if (*func != NULL) { ++ (*func)(); ++ } ++ } ++} ++ ++ ++init_func_t __libc_init_ref_edk2_libc_call_constructors __attribute__((retain, used, section(".__libc_init.prio_99.libc_constructors"), aligned(sizeof(init_func_t)))) = ++edk2_libc_call_constructors; ++ ++ ++static void __c_uefi_deinit_libc(void) { ++ // iterate reversed ++ size_t size = __libc_fini_array_end - __libc_fini_array_start; ++ for (size_t i = size; i != 0; --i) { ++ init_func_t func = __libc_fini_array_start[i - 1]; ++ if (*func != NULL) { ++ (*func)(); ++ } ++ } + } + ++ ++init_func_t __libc_init_ref_edk2_libc_call_destructors __attribute__((retain, used, section(".__libc_fini.prio_99.libc_destructors"), aligned(sizeof(init_func_t)))) = ++edk2_libc_call_destructors; ++ ++ + /** Clean up data as required by the exit() function. + + **/ +@@ -67,6 +145,9 @@ exitCleanup(INTN ExitVal) + CleanUp(); + } + } ++ ++ // this is needed, if we use a c++ standard library, we need to clean up that before we clean up the libc and after custom cleanup and atexit calls ++ __c_uefi_deinit_libc(); + } + + /* Create mbcs versions of the Argv strings. */ +@@ -179,7 +260,8 @@ ShellAppMain ( + else { + if( setjmp(gMD->MainExit) == 0) { + errno = 0; // Clean up any "scratch" values from startup. +- ExitVal = (INTN)main( (int)Argc, gMD->NArgV); ++ __c_uefi_init_libc(); ++ ExitVal = (INTN)EDK2_LIBC_ENTRY_NAME( (int)Argc, gMD->NArgV); + exitCleanup(ExitVal); + } + /* You reach here if: +diff --git a/StdLib/StdLib.inc b/StdLib/StdLib.inc +index 4d08302..d6f2b73 100644 +--- a/StdLib/StdLib.inc ++++ b/StdLib/StdLib.inc +@@ -138,3 +138,5 @@ + MSFT:*_VS2015x86xASL_*_CC_FLAGS = /Wv:11 + MSFT:*_VS2017_*_CC_FLAGS = /Wv:11 + MSFT:*_VS2019_*_CC_FLAGS = /Wv:11 ++ ++ GCC:*_*_*_CC_FLAGS = -Wprio-ctor-dtor +-- +2.53.0 + diff --git a/platforms/uefi/edk2/0001-feat-correct-cxx-support.patch b/platforms/uefi/edk2/0001-feat-correct-cxx-support.patch new file mode 100644 index 000000000..8533da675 --- /dev/null +++ b/platforms/uefi/edk2/0001-feat-correct-cxx-support.patch @@ -0,0 +1,50 @@ +From 588d56df90b1ff3ef3543f904ead16987507d67e Mon Sep 17 00:00:00 2001 +From: Totto16 +Date: Tue, 25 Aug 2026 17:33:06 +0200 +Subject: [PATCH 1/4] feat: correct cxx support - make C++ correctly supported + +--- + BaseTools/Conf/build_rule.template | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/BaseTools/Conf/build_rule.template b/BaseTools/Conf/build_rule.template +index a89866d700..e804a1c965 100755 +--- a/BaseTools/Conf/build_rule.template ++++ b/BaseTools/Conf/build_rule.template +@@ -121,13 +121,13 @@ + $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj + + +- "$(CC)" /Fo${dst} $(DEPS_FLAGS) $(CC_FLAGS) $(INC) ${src} ++ "$(CC)" /Fo${dst} $(DEPS_FLAGS) $(CCONLY_FLAGS) $(CC_FLAGS) $(INC) ${src} + + +- "$(CC)" $(DEPS_FLAGS) $(CC_FLAGS) -c -o ${dst} $(INC) ${src} ++ "$(CC)" $(DEPS_FLAGS) $(CCONLY_FLAGS) $(CC_FLAGS) -c -o ${dst} $(INC) ${src} + + +- "$(CC)" $(DEPS_FLAGS) $(CC_FLAGS) -o ${dst} $(INC) ${src} ++ "$(CC)" $(DEPS_FLAGS) $(CCONLY_FLAGS) $(CC_FLAGS) -o ${dst} $(INC) ${src} + + [Cxx-Code-File] + +@@ -144,13 +144,13 @@ + $(OUTPUT_DIR)(+)${s_dir}(+)${s_base}.obj + + +- "$(CC)" /Fo${dst} $(DEPS_FLAGS) $(CC_FLAGS) $(CXX_FLAGS) $(INC) ${src} ++ "$(CC)" /TODO:x=c++ /Fo${dst} $(DEPS_FLAGS) $(CXX_FLAGS) $(CC_FLAGS) $(INC) ${src} + + +- "$(CC)" $(DEPS_FLAGS) $(CC_FLAGS) $(CXX_FLAGS) -c -o ${dst} $(INC) ${src} ++ "$(CC)" -x c++ $(DEPS_FLAGS) $(CXX_FLAGS) $(CC_FLAGS) -c -o ${dst} $(INC) ${src} + + +- "$(CC)" $(DEPS_FLAGS) $(CC_FLAGS) $(CXX_FLAGS) -o ${dst} $(INC) ${src} ++ "$(CC)" -x c++ $(DEPS_FLAGS) $(CXX_FLAGS) $(CC_FLAGS)-o ${dst} $(INC) ${src} + + [C-Code-File.BASE.AARCH64,C-Code-File.SEC.AARCH64,C-Code-File.PEI_CORE.AARCH64,C-Code-File.PEIM.AARCH64] + +-- +2.55.0 + diff --git a/platforms/uefi/edk2/0002-feat-use-x86_64-v1-for-the-architecture.patch b/platforms/uefi/edk2/0002-feat-use-x86_64-v1-for-the-architecture.patch new file mode 100644 index 000000000..c72193c1f --- /dev/null +++ b/platforms/uefi/edk2/0002-feat-use-x86_64-v1-for-the-architecture.patch @@ -0,0 +1,189 @@ +From 18bc84f196e6689834f6c13c6d0aeb41bc5b6e9f Mon Sep 17 00:00:00 2001 +From: Totto16 +Date: Tue, 25 Aug 2026 17:34:06 +0200 +Subject: [PATCH 2/4] feat: use x86_64 v1 for the architecture + +--- + BaseTools/Conf/tools_def.template | 64 +++++++++++++++---------------- + 1 file changed, 32 insertions(+), 32 deletions(-) + +diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template +index 72ca0dfa21..f437d0b9da 100644 +--- a/BaseTools/Conf/tools_def.template ++++ b/BaseTools/Conf/tools_def.template +@@ -618,7 +618,7 @@ DEFINE GCC_DEPS_FLAGS = -MMD -MF $@.deps + DEFINE GCC_ALL_CC_FLAGS = DEF(GCC_ALL_CC_COMMON) -ffunction-sections -fdata-sections -DSTRING_ARRAY_NAME=$(BASE_NAME)Strings + + DEFINE GCCNOLTO_IA32_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) DEF(GCC_IA32_X64_CC_FLAGS) -m32 -march=i586 -malign-double -D EFI32 -fno-asynchronous-unwind-tables -Wno-address -fno-omit-frame-pointer -fno-pic -fno-pie +-DEFINE GCCNOLTO_X64_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) DEF(GCC_IA32_X64_CC_FLAGS) -m64 "-DEFIAPI=__attribute__((ms_abi))" -maccumulate-outgoing-args -mno-red-zone -Wno-address -mcmodel=small -fpie -fno-asynchronous-unwind-tables -Wno-address -fno-omit-frame-pointer ++DEFINE GCCNOLTO_X64_CC_FLAGS = DEF(GCC_ALL_CC_FLAGS) DEF(GCC_IA32_X64_CC_FLAGS) -m64 -march=x86-64 "-DEFIAPI=__attribute__((ms_abi))" -maccumulate-outgoing-args -mno-red-zone -Wno-address -mcmodel=small -fpie -fno-asynchronous-unwind-tables -Wno-address -fno-omit-frame-pointer + DEFINE GCCNOLTO_IA32_X64_DLINK_COMMON = -nostdlib -Wl,-n,-q,--gc-sections -z common-page-size=0x40 + DEFINE GCCNOLTO_IA32_X64_ASLDLINK_FLAGS = DEF(GCCNOLTO_IA32_X64_DLINK_COMMON) -Wl,--defsym=PECOFF_HEADER_SIZE=0 DEF(GCC_DLINK2_FLAGS_COMMON) -Wl,--entry,ReferenceAcpiTable -u ReferenceAcpiTable + DEFINE GCCNOLTO_IA32_X64_DLINK_FLAGS = DEF(GCCNOLTO_IA32_X64_DLINK_COMMON) -Wl,--entry,$(IMAGE_ENTRY_POINT) -u $(IMAGE_ENTRY_POINT) -Wl,-Map,$(DEST_DIR_DEBUG)/$(BASE_NAME).map,--whole-archive +@@ -738,9 +738,9 @@ RELEASE_GCCNOLTO_IA32_CC_FLAGS = DEF(GCCNOLTO_IA32_CC_FLAGS) + *_GCCNOLTO_X64_ASLPP_PATH = DEF(GCCNOLTO_X64_PREFIX)gcc + *_GCCNOLTO_X64_RC_PATH = DEF(GCCNOLTO_X64_PREFIX)objcopy + +-*_GCCNOLTO_X64_ASLCC_FLAGS = DEF(GCCNOLTO_ASLCC_FLAGS) -m64 ++*_GCCNOLTO_X64_ASLCC_FLAGS = DEF(GCCNOLTO_ASLCC_FLAGS) -m64 -march=x86-64 + *_GCCNOLTO_X64_ASLDLINK_FLAGS = DEF(GCCNOLTO_IA32_X64_ASLDLINK_FLAGS) -Wl,-m,elf_x86_64 +-*_GCCNOLTO_X64_ASM_FLAGS = DEF(GCCNOLTO_ASM_FLAGS) -m64 ++*_GCCNOLTO_X64_ASM_FLAGS = DEF(GCCNOLTO_ASM_FLAGS) -m64 -march=x86-64 + *_GCCNOLTO_X64_DLINK_FLAGS = DEF(GCCNOLTO_X64_DLINK_FLAGS) + *_GCCNOLTO_X64_DLINK2_FLAGS = DEF(GCCNOLTO_X64_DLINK2_FLAGS) + *_GCCNOLTO_X64_RC_FLAGS = DEF(GCC_X64_RC_FLAGS) +@@ -832,11 +832,11 @@ RELEASE_GCCNOLTO_AARCH64_DLINK_FLAGS = DEF(GCCNOLTO_AARCH64_DLINK_FLAGS) + *_GCC_IA32_OBJCOPY_FLAGS = + *_GCC_IA32_NASM_FLAGS = -f elf32 + +- DEBUG_GCC_IA32_CC_FLAGS = DEF(GCC_IA32_CC_FLAGS) -flto +- DEBUG_GCC_IA32_DLINK_FLAGS = DEF(GCC_IA32_X64_DLINK_FLAGS) -flto -Os -Wl,-m,elf_i386,--oformat=elf32-i386 -z common-page-size=0x40 ++ DEBUG_GCC_IA32_CC_FLAGS = DEF(GCC_IA32_CC_FLAGS) -flto=auto ++ DEBUG_GCC_IA32_DLINK_FLAGS = DEF(GCC_IA32_X64_DLINK_FLAGS) -flto=auto -Os -Wl,-m,elf_i386,--oformat=elf32-i386 -z common-page-size=0x40 + +-RELEASE_GCC_IA32_CC_FLAGS = DEF(GCC_IA32_CC_FLAGS) -flto +-RELEASE_GCC_IA32_DLINK_FLAGS = DEF(GCC_IA32_X64_DLINK_FLAGS) -flto -Os -Wl,-m,elf_i386,--oformat=elf32-i386 -z common-page-size=0x40 ++RELEASE_GCC_IA32_CC_FLAGS = DEF(GCC_IA32_CC_FLAGS) -flto=auto ++RELEASE_GCC_IA32_DLINK_FLAGS = DEF(GCC_IA32_X64_DLINK_FLAGS) -flto=auto -Os -Wl,-m,elf_i386,--oformat=elf32-i386 -z common-page-size=0x40 + + NOOPT_GCC_IA32_CC_FLAGS = DEF(GCC_IA32_CC_FLAGS) -O0 + NOOPT_GCC_IA32_DLINK_FLAGS = DEF(GCC_IA32_X64_DLINK_FLAGS) -Wl,-m,elf_i386,--oformat=elf32-i386 -O0 -z common-page-size=0x40 +@@ -856,19 +856,19 @@ RELEASE_GCC_IA32_DLINK_FLAGS = DEF(GCC_IA32_X64_DLINK_FLAGS) -flto -Os -Wl,-m + *_GCC_X64_ASLPP_PATH = DEF(GCC_X64_PREFIX)gcc + *_GCC_X64_RC_PATH = DEF(GCC_X64_PREFIX)objcopy + +-*_GCC_X64_ASLCC_FLAGS = DEF(GCC_ASLCC_FLAGS) -m64 ++*_GCC_X64_ASLCC_FLAGS = DEF(GCC_ASLCC_FLAGS) -m64 -march=x86-64 + *_GCC_X64_ASLDLINK_FLAGS = DEF(GCC_IA32_X64_ASLDLINK_FLAGS) -Wl,-m,elf_x86_64 +-*_GCC_X64_ASM_FLAGS = DEF(GCC_ASM_FLAGS) -m64 ++*_GCC_X64_ASM_FLAGS = DEF(GCC_ASM_FLAGS) -m64 -march=x86-64 + *_GCC_X64_DLINK2_FLAGS = DEF(GCC_X64_DLINK2_FLAGS) + *_GCC_X64_RC_FLAGS = DEF(GCC_X64_RC_FLAGS) + *_GCC_X64_OBJCOPY_FLAGS = + *_GCC_X64_NASM_FLAGS = -f elf64 + +- DEBUG_GCC_X64_CC_FLAGS = DEF(GCC_X64_CC_FLAGS) -flto -DUSING_LTO +- DEBUG_GCC_X64_DLINK_FLAGS = DEF(GCC_X64_DLINK_FLAGS) -flto -Os -z common-page-size=0x1000 ++ DEBUG_GCC_X64_CC_FLAGS = DEF(GCC_X64_CC_FLAGS) -flto=auto -DUSING_LTO ++ DEBUG_GCC_X64_DLINK_FLAGS = DEF(GCC_X64_DLINK_FLAGS) -flto=auto -Os -z common-page-size=0x1000 + +-RELEASE_GCC_X64_CC_FLAGS = DEF(GCC_X64_CC_FLAGS) -flto -DUSING_LTO +-RELEASE_GCC_X64_DLINK_FLAGS = DEF(GCC_X64_DLINK_FLAGS) -flto -Os -z common-page-size=0x1000 ++RELEASE_GCC_X64_CC_FLAGS = DEF(GCC_X64_CC_FLAGS) -flto=auto -DUSING_LTO ++RELEASE_GCC_X64_DLINK_FLAGS = DEF(GCC_X64_DLINK_FLAGS) -flto=auto -Os -z common-page-size=0x1000 + + NOOPT_GCC_X64_CC_FLAGS = DEF(GCC_X64_CC_FLAGS) -O0 + NOOPT_GCC_X64_DLINK_FLAGS = DEF(GCC_X64_DLINK_FLAGS) -O0 -z common-page-size=0x1000 +@@ -900,11 +900,11 @@ RELEASE_GCC_X64_DLINK_FLAGS = DEF(GCC_X64_DLINK_FLAGS) -flto -Os -z common-p + *_GCC_AARCH64_VFRPP_FLAGS = $(PLATFORM_FLAGS) DEF(GCC_VFRPP_FLAGS) + *_GCC_AARCH64_CC_XIPFLAGS = DEF(GCC_AARCH64_CC_XIPFLAGS) + +- DEBUG_GCC_AARCH64_CC_FLAGS = DEF(GCC_AARCH64_CC_FLAGS) -flto +- DEBUG_GCC_AARCH64_DLINK_FLAGS = DEF(GCC_AARCH64_DLINK_FLAGS) -flto -Os -L$(WORKSPACE)/BaseTools/Bin/GccLto -llto-aarch64 -Wl,-plugin-opt=-pass-through=-llto-aarch64 -Wno-lto-type-mismatch -z common-page-size=0x1000 ++ DEBUG_GCC_AARCH64_CC_FLAGS = DEF(GCC_AARCH64_CC_FLAGS) -flto=auto ++ DEBUG_GCC_AARCH64_DLINK_FLAGS = DEF(GCC_AARCH64_DLINK_FLAGS) -flto=auto -Os -L$(WORKSPACE)/BaseTools/Bin/GccLto -llto-aarch64 -Wl,-plugin-opt=-pass-through=-llto-aarch64 -Wno-lto-type-mismatch -z common-page-size=0x1000 + +-RELEASE_GCC_AARCH64_CC_FLAGS = DEF(GCC_AARCH64_CC_FLAGS) -flto +-RELEASE_GCC_AARCH64_DLINK_FLAGS = DEF(GCC_AARCH64_DLINK_FLAGS) -flto -Os -L$(WORKSPACE)/BaseTools/Bin/GccLto -llto-aarch64 -Wl,-plugin-opt=-pass-through=-llto-aarch64 -Wno-lto-type-mismatch -z common-page-size=0x1000 ++RELEASE_GCC_AARCH64_CC_FLAGS = DEF(GCC_AARCH64_CC_FLAGS) -flto=auto ++RELEASE_GCC_AARCH64_DLINK_FLAGS = DEF(GCC_AARCH64_DLINK_FLAGS) -flto=auto -Os -L$(WORKSPACE)/BaseTools/Bin/GccLto -llto-aarch64 -Wl,-plugin-opt=-pass-through=-llto-aarch64 -Wno-lto-type-mismatch -z common-page-size=0x1000 + + NOOPT_GCC_AARCH64_CC_FLAGS = DEF(GCC_AARCH64_CC_FLAGS) -O0 + NOOPT_GCC_AARCH64_DLINK_FLAGS = DEF(GCC_AARCH64_DLINK_FLAGS) -O0 -z common-page-size=0x1000 +@@ -1056,8 +1056,8 @@ NOOPT_CLANGPDB_IA32_DLINK2_FLAGS = + *_CLANGPDB_X64_ASLPP_PATH = DEF(CLANGPDB_X64_PREFIX)clang + *_CLANGPDB_X64_RC_PATH = DEF(CLANGPDB_IA32_PREFIX)llvm-rc + +-*_CLANGPDB_X64_ASLCC_FLAGS = DEF(GCC_ASLCC_COMMON) -m64 -fno-lto DEF(CLANGPDB_X64_TARGET) +-*_CLANGPDB_X64_ASM_FLAGS = DEF(GCC_ASM_COMMON) -m64 DEF(CLANGPDB_X64_TARGET) ++*_CLANGPDB_X64_ASLCC_FLAGS = DEF(GCC_ASLCC_COMMON) -m64 -march=x86-64 -fno-lto DEF(CLANGPDB_X64_TARGET) ++*_CLANGPDB_X64_ASM_FLAGS = DEF(GCC_ASM_COMMON) -m64 -march=x86-64 DEF(CLANGPDB_X64_TARGET) + *_CLANGPDB_X64_OBJCOPY_FLAGS = + + DEBUG_CLANGPDB_X64_NASM_FLAGS = -Ox -f win64 -g +@@ -1068,17 +1068,17 @@ NOOPT_CLANGPDB_X64_NASM_FLAGS = -O0 -f win64 -g + *_CLANGPDB_X64_ASLPP_FLAGS = DEF(GCC_ASLPP_FLAGS) DEF(CLANGPDB_X64_TARGET) + *_CLANGPDB_X64_VFRPP_FLAGS = DEF(GCC_VFRPP_FLAGS) DEF(CLANGPDB_X64_TARGET) + +-DEBUG_CLANGPDB_X64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -Oz -flto DEF(CLANGPDB_X64_TARGET) -gcodeview -funwind-tables ++DEBUG_CLANGPDB_X64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 -march=x86-64"-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -Oz -flto DEF(CLANGPDB_X64_TARGET) -gcodeview -funwind-tables + DEBUG_CLANGPDB_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /ALIGN:4096 /DRIVER /FILEALIGN:32 /Machine:X64 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DEBUG:GHASH /MLLVM:-exception-model=wineh /lldmap + DEBUG_CLANGPDB_X64_DLINK2_FLAGS = + DEBUG_CLANGPDB_X64_GENFW_FLAGS = --keepexceptiontable + +-RELEASE_CLANGPDB_X64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -Oz -flto DEF(CLANGPDB_X64_TARGET) -fno-unwind-tables ++RELEASE_CLANGPDB_X64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 -march=x86-64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -Oz -flto DEF(CLANGPDB_X64_TARGET) -fno-unwind-tables + RELEASE_CLANGPDB_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /OPT:REF /OPT:ICF=10 /ALIGN:4096 /DRIVER /FILEALIGN:32 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:X64 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /MERGE:.rdata=.data /MLLVM:-exception-model=wineh /lldmap + RELEASE_CLANGPDB_X64_DLINK2_FLAGS = + RELEASE_CLANGPDB_X64_GENFW_FLAGS = + +-NOOPT_CLANGPDB_X64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -O0 DEF(CLANGPDB_X64_TARGET) -gcodeview -funwind-tables ++NOOPT_CLANGPDB_X64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 -march=x86-64"-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -O0 DEF(CLANGPDB_X64_TARGET) -gcodeview -funwind-tables + NOOPT_CLANGPDB_X64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /OPT:REF /OPT:ICF=10 /ALIGN:32 /DRIVER /FILEALIGN:32 /Machine:X64 /DLL /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DEBUG:GHASH /MLLVM:-exception-model=wineh /lldmap + NOOPT_CLANGPDB_X64_DLINK2_FLAGS = + NOOPT_CLANGPDB_X64_GENFW_FLAGS = --keepexceptiontable +@@ -1099,8 +1099,8 @@ NOOPT_CLANGPDB_X64_GENFW_FLAGS = --keepexceptiontable + *_CLANGPDB_AARCH64_ASLPP_PATH = DEF(CLANGPDB_AARCH64_PREFIX)clang + *_CLANGPDB_AARCH64_RC_PATH = DEF(CLANGPDB_AARCH64_PREFIX)llvm-rc + +-*_CLANGPDB_AARCH64_ASLCC_FLAGS = DEF(GCC_ASLCC_COMMON) -m64 -fno-lto DEF(CLANGPDB_AARCH64_TARGET) +-*_CLANGPDB_AARCH64_ASM_FLAGS = DEF(GCC_ASM_COMMON) -m64 DEF(CLANGPDB_AARCH64_TARGET) ++*_CLANGPDB_AARCH64_ASLCC_FLAGS = DEF(GCC_ASLCC_COMMON) -m64 -march=x86-64 -fno-lto DEF(CLANGPDB_AARCH64_TARGET) ++*_CLANGPDB_AARCH64_ASM_FLAGS = DEF(GCC_ASM_COMMON) -m64 -march=x86-64 DEF(CLANGPDB_AARCH64_TARGET) + *_CLANGPDB_AARCH64_OBJCOPY_FLAGS = + *_CLANGPDB_AARCH64_NASM_FLAGS = -f win64 + *_CLANGPDB_AARCH64_PP_FLAGS = DEF(GCC_PP_FLAGS) DEF(CLANGPDB_AARCH64_TARGET) +@@ -1108,16 +1108,16 @@ NOOPT_CLANGPDB_X64_GENFW_FLAGS = --keepexceptiontable + *_CLANGPDB_AARCH64_VFRPP_FLAGS = DEF(GCC_VFRPP_FLAGS) DEF(CLANGPDB_AARCH64_TARGET) + *_CLANGPDB_AARCH64_CC_XIPFLAGS = -mstrict-align + +-DEBUG_CLANGPDB_AARCH64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 -mcmodel=small -Oz -flto DEF(CLANGPDB_AARCH64_TARGET) -gcodeview -funwind-tables -Wno-deprecated-non-prototype -Wno-constant-conversion -Werror ++DEBUG_CLANGPDB_AARCH64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 -march=x86-64-mcmodel=small -Oz -flto DEF(CLANGPDB_AARCH64_TARGET) -gcodeview -funwind-tables -Wno-deprecated-non-prototype -Wno-constant-conversion -Werror + DEBUG_CLANGPDB_AARCH64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /WX /OPT:REF /OPT:ICF=10 /ALIGN:4096 /Machine:ARM64 /DLL /DRIVER /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DEBUG:GHASH /MLLVM:-exception-model=wineh /lldmap + DEBUG_CLANGPDB_AARCH64_DLINK2_FLAGS = + DEBUG_CLANGPDB_AARCH64_GENFW_FLAGS = --keepexceptiontable + +-RELEASE_CLANGPDB_AARCH64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 -mcmodel=small -Oz -flto DEF(CLANGPDB_AARCH64_TARGET) -fno-unwind-tables -Wno-deprecated-non-prototype -Wno-constant-conversion -Werror ++RELEASE_CLANGPDB_AARCH64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 -march=x86-64-mcmodel=small -Oz -flto DEF(CLANGPDB_AARCH64_TARGET) -fno-unwind-tables -Wno-deprecated-non-prototype -Wno-constant-conversion -Werror + RELEASE_CLANGPDB_AARCH64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /IGNORE:4254 /WX /OPT:REF /OPT:ICF=10 /ALIGN:4096 /SECTION:.xdata,D /SECTION:.pdata,D /Machine:ARM64 /DLL /DRIVER /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /MERGE:.rdata=.data /MLLVM:-exception-model=wineh /lldmap + RELEASE_CLANGPDB_AARCH64_DLINK2_FLAGS = + +-NOOPT_CLANGPDB_AARCH64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 -mcmodel=small -O0 DEF(CLANGPDB_AARCH64_TARGET) -gcodeview -funwind-tables -Wno-deprecated-non-prototype -Wno-constant-conversion -Werror ++NOOPT_CLANGPDB_AARCH64_CC_FLAGS = DEF(CLANGPDB_ALL_CC_FLAGS) -m64 -march=x86-64-mcmodel=small -O0 DEF(CLANGPDB_AARCH64_TARGET) -gcodeview -funwind-tables -Wno-deprecated-non-prototype -Wno-constant-conversion -Werror + NOOPT_CLANGPDB_AARCH64_DLINK_FLAGS = /NOLOGO /NODEFAULTLIB /IGNORE:4001 /WX /OPT:REF /OPT:ICF=10 /ALIGN:4096 /Machine:ARM64 /DLL /DRIVER /ENTRY:$(IMAGE_ENTRY_POINT) /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /SAFESEH:NO /BASE:0 /DEBUG:GHASH /MLLVM:-exception-model=wineh /lldmap + NOOPT_CLANGPDB_AARCH64_DLINK2_FLAGS = + NOOPT_CLANGPDB_AARCH64_GENFW_FLAGS = --keepexceptiontable +@@ -1234,9 +1234,9 @@ NOOPT_CLANGDWARF_IA32_DLINK2_FLAGS = DEF(CLANGDWARF_IA32_DLINK2_FLAGS) -O0 - + *_CLANGDWARF_X64_ASLPP_PATH = DEF(CLANGDWARF_X64_PREFIX)clang + *_CLANGDWARF_X64_RC_PATH = DEF(CLANGDWARF_X64_PREFIX)llvm-objcopy + +-*_CLANGDWARF_X64_ASLCC_FLAGS = DEF(GCC_ASLCC_COMMON) -m64 -fno-lto DEF(CLANGDWARF_X64_TARGET) ++*_CLANGDWARF_X64_ASLCC_FLAGS = DEF(GCC_ASLCC_COMMON) -m64 -march=x86-64 -fno-lto DEF(CLANGDWARF_X64_TARGET) + *_CLANGDWARF_X64_ASLDLINK_FLAGS = DEF(CLANGDWARF_IA32_X64_ASLDLINK_FLAGS) -Wl,-m,elf_x86_64 -fuse-ld=lld +-*_CLANGDWARF_X64_ASM_FLAGS = DEF(GCC_ASM_FLAGS) -m64 DEF(CLANGDWARF_X64_TARGET) ++*_CLANGDWARF_X64_ASM_FLAGS = DEF(GCC_ASM_FLAGS) -m64 -march=x86-64 DEF(CLANGDWARF_X64_TARGET) + *_CLANGDWARF_X64_RC_FLAGS = DEF(GCC_X64_RC_FLAGS) + *_CLANGDWARF_X64_OBJCOPY_FLAGS = + +@@ -1248,15 +1248,15 @@ NOOPT_CLANGDWARF_X64_NASM_FLAGS = -O0 -f elf64 -g + *_CLANGDWARF_X64_ASLPP_FLAGS = DEF(GCC_ASLPP_FLAGS) DEF(CLANGDWARF_X64_TARGET) + *_CLANGDWARF_X64_VFRPP_FLAGS = DEF(GCC_VFRPP_FLAGS) DEF(CLANGDWARF_X64_TARGET) + +-DEBUG_CLANGDWARF_X64_CC_FLAGS = DEF(CLANGDWARF_ALL_CC_FLAGS) -m64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -fpie -fdirect-access-external-data -Oz -flto DEF(CLANGDWARF_X64_TARGET) -g -funwind-tables ++DEBUG_CLANGDWARF_X64_CC_FLAGS = DEF(CLANGDWARF_ALL_CC_FLAGS) -m64 -march=x86-64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -fpie -fdirect-access-external-data -Oz -flto DEF(CLANGDWARF_X64_TARGET) -g -funwind-tables + DEBUG_CLANGDWARF_X64_DLINK_FLAGS = DEF(CLANGDWARF_X64_TARGET) DEF(CLANGDWARF_IA32_X64_DLINK_FLAGS) -flto -Wl,-O3 -Wl,-melf_x86_64 -Wl,--oformat,elf64-x86-64 -Wl,-pie -mcmodel=small -Wl,--apply-dynamic-relocs -z common-page-size=0x1000 + DEBUG_CLANGDWARF_X64_DLINK2_FLAGS = DEF(CLANGDWARF_X64_DLINK2_FLAGS) -O3 -fuse-ld=lld + +-RELEASE_CLANGDWARF_X64_CC_FLAGS = DEF(CLANGDWARF_ALL_CC_FLAGS) -m64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -fpie -fdirect-access-external-data -Oz -flto DEF(CLANGDWARF_X64_TARGET) ++RELEASE_CLANGDWARF_X64_CC_FLAGS = DEF(CLANGDWARF_ALL_CC_FLAGS) -m64 -march=x86-64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -fpie -fdirect-access-external-data -Oz -flto DEF(CLANGDWARF_X64_TARGET) + RELEASE_CLANGDWARF_X64_DLINK_FLAGS = DEF(CLANGDWARF_X64_TARGET) DEF(CLANGDWARF_IA32_X64_DLINK_FLAGS) -flto -Wl,-O3 -Wl,-melf_x86_64 -Wl,--oformat,elf64-x86-64 -Wl,-pie -mcmodel=small -Wl,--apply-dynamic-relocs -z common-page-size=0x1000 + RELEASE_CLANGDWARF_X64_DLINK2_FLAGS = DEF(CLANGDWARF_X64_DLINK2_FLAGS) -O3 -fuse-ld=lld + +-NOOPT_CLANGDWARF_X64_CC_FLAGS = DEF(CLANGDWARF_ALL_CC_FLAGS) -m64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -fpie -fdirect-access-external-data -O0 DEF(CLANGDWARF_X64_TARGET) -g -funwind-tables ++NOOPT_CLANGDWARF_X64_CC_FLAGS = DEF(CLANGDWARF_ALL_CC_FLAGS) -m64 -march=x86-64 "-DEFIAPI=__attribute__((ms_abi))" -mno-red-zone -mcmodel=small -fpie -fdirect-access-external-data -O0 DEF(CLANGDWARF_X64_TARGET) -g -funwind-tables + NOOPT_CLANGDWARF_X64_DLINK_FLAGS = DEF(CLANGDWARF_X64_TARGET) DEF(CLANGDWARF_IA32_X64_DLINK_FLAGS) -Wl,-O0 -Wl,-melf_x86_64 -Wl,--oformat,elf64-x86-64 -Wl,-pie -mcmodel=small -Wl,--apply-dynamic-relocs -z common-page-size=0x1000 + NOOPT_CLANGDWARF_X64_DLINK2_FLAGS = DEF(CLANGDWARF_X64_DLINK2_FLAGS) -O0 -fuse-ld=lld + +-- +2.55.0 + diff --git a/platforms/uefi/edk2/0003-feat-add-support-for-C-and-C-constructors-and-destru.patch b/platforms/uefi/edk2/0003-feat-add-support-for-C-and-C-constructors-and-destru.patch new file mode 100644 index 000000000..1aa60884e --- /dev/null +++ b/platforms/uefi/edk2/0003-feat-add-support-for-C-and-C-constructors-and-destru.patch @@ -0,0 +1,208 @@ +From 4a7b560f9b4e960a2a3046bcbf84716eea63035d Mon Sep 17 00:00:00 2001 +From: Totto16 +Date: Tue, 25 Aug 2026 17:35:20 +0200 +Subject: [PATCH 3/4] feat: add support for C and C++ constructors and + destructors - this requires as linker script change and GenFW modifications - + this can 5than be used by edk2-libc and libcxx for uefi + +--- + BaseTools/Scripts/GccBase.lds | 61 +++++++++++++++++++++++++ + BaseTools/Source/C/GenFw/Elf32Convert.c | 35 ++++++++++++++ + BaseTools/Source/C/GenFw/Elf64Convert.c | 35 ++++++++++++++ + 3 files changed, 131 insertions(+) + +diff --git a/BaseTools/Scripts/GccBase.lds b/BaseTools/Scripts/GccBase.lds +index 3d2a97ddeb..32b54385fc 100644 +--- a/BaseTools/Scripts/GccBase.lds ++++ b/BaseTools/Scripts/GccBase.lds +@@ -85,6 +85,67 @@ SECTIONS { + */ + .build-id (INFO) : { *(.note.gnu.build-id) } + ++ /* ++ * Retain the GCC static / global constructor / initializer and destructors / finalizer ++ */ ++ .init_array : { ++ PROVIDE_HIDDEN(__init_array_start = .); ++ ++ KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*))) ++ KEEP(*(.init_array)) ++ ++ PROVIDE_HIDDEN(__init_array_end = .); ++ ++ PROVIDE_HIDDEN(__libc_init_array_start = .); ++ ++ KEEP(*(SORT_BY_NAME(.__libc_init.*))) ++ ++ PROVIDE_HIDDEN(__libc_init_array_end = .); ++ } ++ ++ .fini_array : { ++ PROVIDE_HIDDEN(__fini_array_start = .); ++ ++ KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*))) ++ KEEP(*(.fini_array)) ++ ++ PROVIDE_HIDDEN(__fini_array_end = .); ++ ++ PROVIDE_HIDDEN(__libc_fini_array_start = .); ++ ++ KEEP(*(SORT_BY_NAME(.__libc_fini.*))) ++ ++ PROVIDE_HIDDEN(__libc_fini_array_end = .); ++ } ++ ++ /* ++ * Error on unsupported (or not yet implemented) sections for construction / destruction ++ */ ++ .preinit_array : { ++ *(.preinit_array) ++ } ++ ASSERT(SIZEOF(.preinit_array) == 0, "error: .preinit_array is not supported (yet)") ++ ++ .init : { ++ *(.init) ++ } ++ ASSERT(SIZEOF(.init) == 0, "error: .init is deprecated (System V uses it, and GCC uses other mechanisms)") ++ ++ .fini : { ++ *(.fini) ++ } ++ ASSERT(SIZEOF(.fini) == 0, "error: .fini is deprecated (System V uses it, and GCC uses other mechanisms)") ++ ++ .ctors : { ++ *(.ctors) ++ } ++ ASSERT(SIZEOF(.ctors) == 0, "error: .ctors is not implemented yet (C++ uses that)") ++ ++ .dtors : { ++ *(.dtors) ++ } ++ ASSERT(SIZEOF(.dtors) == 0, "error: .dtors is not implemented yet (C++ uses that)") ++ + /DISCARD/ : { + *(.note.GNU-stack) + *(.gnu_debuglink) +diff --git a/BaseTools/Source/C/GenFw/Elf32Convert.c b/BaseTools/Source/C/GenFw/Elf32Convert.c +index 7b4fb4410a..45d5965228 100644 +--- a/BaseTools/Source/C/GenFw/Elf32Convert.c ++++ b/BaseTools/Source/C/GenFw/Elf32Convert.c +@@ -239,6 +239,26 @@ IsHiiRsrcShdr ( + return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0); + } + ++#define ELF_INIT_ARRAY_SECTION_NAME ".init_array" ++#define ELF_FINI_ARRAY_SECTION_NAME ".fini_array" ++ ++STATIC ++BOOLEAN ++IsInitFiniArrayShdr ( ++ Elf_Shdr *Shdr ++ ) ++{ ++ Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx); ++ const CHAR8 *Name = (const CHAR8 *)mEhdr + ++ Namedr->sh_offset + ++ Shdr->sh_name; ++ ++ return (BOOLEAN)( ++ strcmp(Name, ELF_INIT_ARRAY_SECTION_NAME) == 0 || ++ strcmp(Name, ELF_FINI_ARRAY_SECTION_NAME) == 0 ++ ); ++} ++ + STATIC + BOOLEAN + IsDataShdr ( +@@ -248,6 +268,9 @@ IsDataShdr ( + if (IsHiiRsrcShdr(Shdr)) { + return FALSE; + } ++ if (IsInitFiniArrayShdr (Shdr)) { ++ return TRUE; ++ } + return (BOOLEAN) (Shdr->sh_flags & (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE); + } + +@@ -662,6 +685,18 @@ WriteSections32 ( + memset(mCoffFile + mCoffSectionsOffset[Idx], 0, Shdr->sh_size); + break; + ++ case SHT_INIT_ARRAY: ++ case SHT_FINI_ARRAY: ++ //NOTE: do the same as the SHT_PROGBITS section (we SHOULd have already determined them as data sections, so there should be space) ++ /* Copy. */ ++ if (Shdr->sh_offset + Shdr->sh_size > mFileBufferSize) { ++ return FALSE; ++ } ++ memcpy(mCoffFile + mCoffSectionsOffset[Idx], ++ (UINT8*)mEhdr + Shdr->sh_offset, ++ (size_t) Shdr->sh_size); ++ break; ++ + default: + // + // Ignore for unknown section type. +diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c b/BaseTools/Source/C/GenFw/Elf64Convert.c +index 1208137bca..c1a01de706 100644 +--- a/BaseTools/Source/C/GenFw/Elf64Convert.c ++++ b/BaseTools/Source/C/GenFw/Elf64Convert.c +@@ -323,6 +323,26 @@ IsSymbolShdr ( + return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namehdr->sh_offset + Shdr->sh_name, ELF_SYMBOL_SECTION_NAME) == 0); + } + ++#define ELF_INIT_ARRAY_SECTION_NAME ".init_array" ++#define ELF_FINI_ARRAY_SECTION_NAME ".fini_array" ++ ++STATIC ++BOOLEAN ++IsInitFiniArrayShdr ( ++ Elf_Shdr *Shdr ++ ) ++{ ++ Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx); ++ const CHAR8 *Name = (const CHAR8 *)mEhdr + ++ Namedr->sh_offset + ++ Shdr->sh_name; ++ ++ return (BOOLEAN)( ++ strcmp(Name, ELF_INIT_ARRAY_SECTION_NAME) == 0 || ++ strcmp(Name, ELF_FINI_ARRAY_SECTION_NAME) == 0 ++ ); ++} ++ + STATIC + BOOLEAN + IsDataShdr ( +@@ -332,6 +352,9 @@ IsDataShdr ( + if (IsHiiRsrcShdr(Shdr)) { + return FALSE; + } ++ if (IsInitFiniArrayShdr (Shdr)) { ++ return TRUE; ++ } + return (BOOLEAN) (Shdr->sh_flags & (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE); + } + +@@ -1388,6 +1411,18 @@ WriteSections64 ( + memset(mCoffFile + mCoffSectionsOffset[Idx], 0, (size_t) Shdr->sh_size); + break; + ++ case SHT_INIT_ARRAY: ++ case SHT_FINI_ARRAY: ++ //NOTE: do the same as the SHT_PROGBITS section (we SHOULd have already determined them as data sections, so there should be space) ++ /* Copy. */ ++ if (Shdr->sh_offset + Shdr->sh_size > mFileBufferSize) { ++ return FALSE; ++ } ++ memcpy(mCoffFile + mCoffSectionsOffset[Idx], ++ (UINT8*)mEhdr + Shdr->sh_offset, ++ (size_t) Shdr->sh_size); ++ break; ++ + default: + // + // Ignore for unknown section type. +-- +2.55.0 + diff --git a/platforms/uefi/edk2/0004-feat-support-compiling-crypto-library-with-stdlib.patch b/platforms/uefi/edk2/0004-feat-support-compiling-crypto-library-with-stdlib.patch new file mode 100644 index 000000000..8471feb89 --- /dev/null +++ b/platforms/uefi/edk2/0004-feat-support-compiling-crypto-library-with-stdlib.patch @@ -0,0 +1,421 @@ +From c79476b209aa2b390894c1e367f9efea1e7ed2da Mon Sep 17 00:00:00 2001 +From: Totto16 +Date: Tue, 25 Aug 2026 17:36:28 +0200 +Subject: [PATCH 4/4] feat: support compiling crypto library with stdlib - + don't use compatibility layer for crypto library as that creates link errors, + when using edk2-libc too + +--- + .../Library/BaseCryptLib/BaseCryptLib.inf | 9 +++++++ + .../Library/BaseCryptLib/Kdf/CryptHkdf.c | 9 ++++--- + .../Library/BaseCryptLib/Pk/CryptEdDsa.c | 6 +++-- + .../Library/BaseCryptLib/Pk/CryptMlDsa.c | 6 +++-- + .../Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c | 12 ++++++---- + .../Library/BaseCryptLib/Pk/CryptRsaPssSign.c | 6 +++-- + .../Library/BaseCryptLib/Pk/CryptSlhDsa.c | 6 +++-- + .../BaseCryptLib/SysCall/BaseMemAllocation.c | 7 ++++++ + .../Library/BaseCryptLib/SysCall/CrtWrapper.c | 5 ++++ + .../BaseCryptLib/SysCall/TimerWrapper.c | 5 ++++ + CryptoPkg/Library/Include/CrtLibSupport.h | 24 +++++++++++++++++++ + CryptoPkg/Library/IntrinsicLib/CopyMem.c | 4 ++++ + .../Library/IntrinsicLib/IntrinsicLib.inf | 2 ++ + .../Library/IntrinsicLib/MemoryIntrinsics.c | 3 +++ + CryptoPkg/Library/OpensslLib/OpensslLib.inf | 11 +++++++++ + 15 files changed, 100 insertions(+), 15 deletions(-) + +diff --git a/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf b/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf +index bf8f1f86af..8f50a77911 100644 +--- a/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf ++++ b/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf +@@ -116,3 +116,12 @@ + GCC:*_CLANGPDB_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types + + XCODE:*_*_*_CC_FLAGS = -std=c99 ++ # define or undefine this based on the usage of StdLib ++ *_*_*_CC_FLAGS = -U__CRYPTO_COMPILE_STANDALONE ++ *_*_*_CC_FLAGS = -I$(EDK2_LIBC_ROOT) ++ *_*_*_CC_FLAGS = -I$(EDK2_ROOT)/CryptoPkg/Library/Include ++ *_*_*_CC_FLAGS = -I$(EDK2_LIBC_ROOT)/StdLib/Include ++ ++[BuildOptions.X64] ++ *_*_*_CC_FLAGS = -I$(EDK2_LIBC_ROOT)/StdLib/Include/X64 ++ *_*_*_CC_FLAGS = -I$(EDK2_ROOT)/MdePkg/Include/X64 +diff --git a/CryptoPkg/Library/BaseCryptLib/Kdf/CryptHkdf.c b/CryptoPkg/Library/BaseCryptLib/Kdf/CryptHkdf.c +index 34e81246ed..8b260495a1 100644 +--- a/CryptoPkg/Library/BaseCryptLib/Kdf/CryptHkdf.c ++++ b/CryptoPkg/Library/BaseCryptLib/Kdf/CryptHkdf.c +@@ -73,7 +73,8 @@ HkdfMdExtractAndExpand ( + } + + if (Result) { +- Result = EVP_PKEY_derive (pHkdfCtx, Out, &OutSize) > 0; ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ Result = EVP_PKEY_derive (pHkdfCtx, Out, (size_t*)&OutSize) > 0; + } + + EVP_PKEY_CTX_free (pHkdfCtx); +@@ -153,7 +154,8 @@ HkdfMdExtract ( + } + + if (Result) { +- Result = EVP_PKEY_derive (pHkdfCtx, PrkOut, &PrkOutSize) > 0; ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ Result = EVP_PKEY_derive (pHkdfCtx, PrkOut, (size_t*)&PrkOutSize) > 0; + } + + EVP_PKEY_CTX_free (pHkdfCtx); +@@ -220,7 +222,8 @@ HkdfMdExpand ( + } + + if (Result) { +- Result = EVP_PKEY_derive (pHkdfCtx, Out, &OutSize) > 0; ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ Result = EVP_PKEY_derive (pHkdfCtx, Out, (size_t*)&OutSize) > 0; + } + + EVP_PKEY_CTX_free (pHkdfCtx); +diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptEdDsa.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptEdDsa.c +index 0b75f9542a..1ee91ebf20 100644 +--- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptEdDsa.c ++++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptEdDsa.c +@@ -378,7 +378,8 @@ EdDsaGetPubKey ( + + *PublicKeySize = FinalPublicKeySize; + +- Result = EVP_PKEY_get_raw_public_key (Ctx->EvpPkey, PublicKey, PublicKeySize); ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ Result = EVP_PKEY_get_raw_public_key (Ctx->EvpPkey, PublicKey, (size_t*)PublicKeySize); + if (Result != 1) { + return FALSE; + } +@@ -498,7 +499,8 @@ EdDsaSign ( + return FALSE; + } + +- if (EVP_DigestSign (SignCtx, Signature, SigSize, Message, MessageSize) != 1) { ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ if (EVP_DigestSign (SignCtx, Signature, (size_t*)SigSize, Message, MessageSize) != 1) { + EVP_MD_CTX_free (SignCtx); + return FALSE; + } +diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptMlDsa.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptMlDsa.c +index d17459daf9..b869bb6b73 100644 +--- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptMlDsa.c ++++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptMlDsa.c +@@ -471,7 +471,8 @@ MlDsaGetPubKey ( + + *PublicKeySize = FinalPublicKeySize; + +- Result = EVP_PKEY_get_raw_public_key (Ctx->EvpPkey, PublicKey, PublicKeySize); ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ Result = EVP_PKEY_get_raw_public_key (Ctx->EvpPkey, PublicKey, (size_t*)PublicKeySize); + if (Result != 1) { + return FALSE; + } +@@ -580,7 +581,8 @@ MlDsaSign ( + return FALSE; + } + +- Result = EVP_DigestSign (SignCtx, Signature, SigSize, Message, MessageSize); ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ Result = EVP_DigestSign (SignCtx, Signature, (size_t*)SigSize, Message, MessageSize); + if (Result != 1) { + EVP_MD_CTX_free (SignCtx); + return FALSE; +diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c +index 7634ab1f6f..e0c12dc264 100644 +--- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c ++++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c +@@ -166,7 +166,8 @@ InternalPkcs1v2Encrypt ( + // + // Determine the required buffer length for malloc'ing. + // +- if (EVP_PKEY_encrypt (PkeyCtx, NULL, &OutDataSize, InData, InDataSize) <= 0) { ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ if (EVP_PKEY_encrypt (PkeyCtx, NULL, (size_t*)&OutDataSize, InData, InDataSize) <= 0) { + // + // Fail to determine output buffer size. + // +@@ -187,7 +188,8 @@ InternalPkcs1v2Encrypt ( + // + // Encrypt Data. + // +- if (EVP_PKEY_encrypt (PkeyCtx, OutData, &OutDataSize, InData, InDataSize) <= 0) { ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ if (EVP_PKEY_encrypt (PkeyCtx, OutData, (size_t*)&OutDataSize, InData, InDataSize) <= 0) { + // + // Fail to encrypt data, need to free the output buffer. + // +@@ -514,7 +516,8 @@ InternalPkcs1v2Decrypt ( + // + // Determine the required buffer length for malloc'ing. + // +- ReturnCode = EVP_PKEY_decrypt (PkeyCtx, NULL, &TempDataSize, EncryptedData, EncryptedDataSize); ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ ReturnCode = EVP_PKEY_decrypt (PkeyCtx, NULL, (size_t*)&TempDataSize, EncryptedData, EncryptedDataSize); + if (ReturnCode <= 0) { + // + // Fail to determine output buffer size. +@@ -537,7 +540,8 @@ InternalPkcs1v2Decrypt ( + // + // Decrypt Data. + // +- ReturnCode = EVP_PKEY_decrypt (PkeyCtx, TempData, &TempDataSize, EncryptedData, EncryptedDataSize); ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ ReturnCode = EVP_PKEY_decrypt (PkeyCtx, TempData, (size_t*)&TempDataSize, EncryptedData, EncryptedDataSize); + if (ReturnCode <= 0) { + // + // Fail to decrypt data, need to free the output buffer. +diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssSign.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssSign.c +index 4835f81168..cefa40b440 100644 +--- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssSign.c ++++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssSign.c +@@ -165,7 +165,8 @@ RsaPssSign ( + } + + if (Result) { +- Result = EVP_DigestSignFinal (EvpVerifyCtx, Signature, SigSize) > 0; ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ Result = EVP_DigestSignFinal (EvpVerifyCtx, Signature, (size_t*)SigSize) > 0; + } + + _Exit: +@@ -284,10 +285,11 @@ RsaPssSignDigest ( + } + + if (Result) { ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); + Result = EVP_PKEY_sign ( + EvpSignCtx, + Signature, +- SigSize, ++ (size_t*)SigSize, + Digest, + (UINT32)DigestSize + ) > 0; +diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptSlhDsa.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptSlhDsa.c +index dc974fde12..3235a43412 100644 +--- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptSlhDsa.c ++++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptSlhDsa.c +@@ -471,7 +471,8 @@ SlhDsaGetPubKey ( + + *PublicKeySize = FinalPublicKeySize; + +- Result = EVP_PKEY_get_raw_public_key (Ctx->EvpPkey, PublicKey, PublicKeySize); ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ Result = EVP_PKEY_get_raw_public_key (Ctx->EvpPkey, PublicKey, (size_t*)PublicKeySize); + if (Result != 1) { + return FALSE; + } +@@ -580,7 +581,8 @@ SlhDsaSign ( + return FALSE; + } + +- Result = EVP_DigestSign (SignCtx, Signature, SigSize, Message, MessageSize); ++ _Static_assert(sizeof(UINTN) == sizeof(size_t)); ++ Result = EVP_DigestSign (SignCtx, Signature, (size_t*)SigSize, Message, MessageSize); + if (Result != 1) { + EVP_MD_CTX_free (SignCtx); + return FALSE; +diff --git a/CryptoPkg/Library/BaseCryptLib/SysCall/BaseMemAllocation.c b/CryptoPkg/Library/BaseCryptLib/SysCall/BaseMemAllocation.c +index b7bed15c18..b1271166a5 100644 +--- a/CryptoPkg/Library/BaseCryptLib/SysCall/BaseMemAllocation.c ++++ b/CryptoPkg/Library/BaseCryptLib/SysCall/BaseMemAllocation.c +@@ -7,9 +7,14 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ + ++ ++ + #include + #include + ++#if defined(__CRYPTO_COMPILE_STANDALONE) ++ ++ + // + // Extra header to record the memory buffer size from malloc routine. + // +@@ -120,3 +125,5 @@ free ( + FreePool (PoolHdr); + } + } ++ ++#endif +diff --git a/CryptoPkg/Library/BaseCryptLib/SysCall/CrtWrapper.c b/CryptoPkg/Library/BaseCryptLib/SysCall/CrtWrapper.c +index 8a8fdfefc7..0b9541267f 100644 +--- a/CryptoPkg/Library/BaseCryptLib/SysCall/CrtWrapper.c ++++ b/CryptoPkg/Library/BaseCryptLib/SysCall/CrtWrapper.c +@@ -9,6 +9,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + + #include + ++#if defined(__CRYPTO_COMPILE_STANDALONE) ++ + int errno = 0; + + FILE *stderr = NULL; +@@ -22,6 +24,7 @@ int + IN VOID *Buffer2 + ); + ++ + // + // Duplicated from EDKII BaseSortLib for qsort() wrapper + // +@@ -651,3 +654,5 @@ printf ( + { + return 0; + } ++ ++#endif +diff --git a/CryptoPkg/Library/BaseCryptLib/SysCall/TimerWrapper.c b/CryptoPkg/Library/BaseCryptLib/SysCall/TimerWrapper.c +index 894aeb016f..eca712b348 100644 +--- a/CryptoPkg/Library/BaseCryptLib/SysCall/TimerWrapper.c ++++ b/CryptoPkg/Library/BaseCryptLib/SysCall/TimerWrapper.c +@@ -12,6 +12,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + #include + #include + ++#if defined(__CRYPTO_COMPILE_STANDALONE) ++ ++ + // + // -- Time Management Routines -- + // +@@ -249,3 +252,5 @@ gettimeofday ( + tv->tv_usec = 0; + return 0; + } ++ ++#endif +diff --git a/CryptoPkg/Library/Include/CrtLibSupport.h b/CryptoPkg/Library/Include/CrtLibSupport.h +index dc5a357d8f..6c4a32186f 100644 +--- a/CryptoPkg/Library/Include/CrtLibSupport.h ++++ b/CryptoPkg/Library/Include/CrtLibSupport.h +@@ -42,14 +42,34 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + // SIXTY_FOUR_BIT, because 'long' is 32-bit and only 'long long' is + // 64-bit. Since using 'long long' works fine on GCC too, just do that. + // ++#define SSL_HAVE_ARCH_DEFINE + #define SIXTY_FOUR_BIT + #elif defined (MDE_CPU_IA32) || defined (MDE_CPU_EBC) + #define THIRTY_TWO_BIT ++#define SSL_HAVE_ARCH_DEFINE + #else + #error Unknown target architecture + #endif + #endif + ++#if !defined(__CRYPTO_COMPILE_STANDALONE) ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#else ++ + // + // Map all va_xxxx elements to VA_xxx defined in MdePkg/Include/Base.h + // +@@ -58,6 +78,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + #define va_start VA_START + #define va_end VA_END + ++ ++ + // + // Definitions for global constants used by CRT library routines + // +@@ -492,3 +514,5 @@ memcpy ( + #else + #define UINTPTR_MAX 0xFFFFFFFFUL + #endif ++ ++#endif +diff --git a/CryptoPkg/Library/IntrinsicLib/CopyMem.c b/CryptoPkg/Library/IntrinsicLib/CopyMem.c +index 5e346728c5..666ecc61d1 100644 +--- a/CryptoPkg/Library/IntrinsicLib/CopyMem.c ++++ b/CryptoPkg/Library/IntrinsicLib/CopyMem.c +@@ -35,6 +35,8 @@ memcpy ( + ); + + #else ++ ++#if defined(__CRYPTO_COMPILE_STANDALONE) + /* Copies bytes between buffers */ + void * + memcpy ( +@@ -47,3 +49,5 @@ memcpy ( + } + + #endif ++ ++#endif +diff --git a/CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf b/CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf +index 6dd9f5d5b9..a80bfe2949 100644 +--- a/CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf ++++ b/CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf +@@ -84,3 +84,5 @@ + MSFT:DEBUG_*_X64_CC_FLAGS == /nologo /c /WX /GS- /X /W4 /Gs32768 /D UNICODE /O1b2s /Gy /FIAutoGen.h /EHs-c- /GR- /GF /Zi /Gm + MSFT:RELEASE_*_X64_CC_FLAGS == /nologo /c /WX /GS- /X /W4 /Gs32768 /D UNICODE /O1b2s /Gy /FIAutoGen.h /EHs-c- /GR- /GF + INTEL:*_*_*_CC_FLAGS = /Oi- ++ # define or undefine this based on the usage of StdLib ++ *_*_*_CC_FLAGS = -U__CRYPTO_COMPILE_STANDALONE +diff --git a/CryptoPkg/Library/IntrinsicLib/MemoryIntrinsics.c b/CryptoPkg/Library/IntrinsicLib/MemoryIntrinsics.c +index 9b091f1901..faedee2d9e 100644 +--- a/CryptoPkg/Library/IntrinsicLib/MemoryIntrinsics.c ++++ b/CryptoPkg/Library/IntrinsicLib/MemoryIntrinsics.c +@@ -19,6 +19,8 @@ typedef UINTN size_t; + #define GLOBAL_USED + #endif + ++#if defined(__CRYPTO_COMPILE_STANDALONE) ++ + /* OpenSSL will use floating point support, and C compiler produces the _fltused + symbol by default. Simply define this symbol here to satisfy the linker. */ + int GLOBAL_USED _fltused = 1; +@@ -63,3 +65,4 @@ memcmp ( + { + return (int)CompareMem (buf1, buf2, count); + } ++#endif +diff --git a/CryptoPkg/Library/OpensslLib/OpensslLib.inf b/CryptoPkg/Library/OpensslLib/OpensslLib.inf +index 1456be7320..1aaf224333 100644 +--- a/CryptoPkg/Library/OpensslLib/OpensslLib.inf ++++ b/CryptoPkg/Library/OpensslLib/OpensslLib.inf +@@ -795,6 +795,7 @@ + # -Werror=unused-but-set-variable: Warn whenever a local variable is assigned to, but otherwise unused (aside from its declaration). + # + GCC:RELEASE_*_*_CC_FLAGS = -DNDEBUG ++ *_*_*_CC_FLAGS = -D__STDC_NO_ATOMICS__ + GCC:*_*_IA32_CC_FLAGS = -U_WIN32 -UWIN32 -U_WIN64 -U_MSC_VER $(OPENSSL_FLAGS) $(OPENSSL_FLAGS_NOASM) -Wno-error=maybe-uninitialized -Wno-error=unused-but-set-variable + GCC:*_*_X64_CC_FLAGS = -U_WIN32 -UWIN32 -U_WIN64 -U_MSC_VER $(OPENSSL_FLAGS) $(OPENSSL_FLAGS_NOASM) -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -DNO_MSABI_VA_FUNCS + GCC:*_*_AARCH64_CC_FLAGS = $(OPENSSL_FLAGS) -Wno-error=maybe-uninitialized -Wno-format -Wno-error=unused-but-set-variable -Wno-error=format +@@ -835,3 +836,13 @@ + # use floating point types, so clear the flags here. + # + GCC:*_*_AARCH64_CC_XIPFLAGS == ++ ++ # define or undefine this based on the usage of StdLib ++ *_*_*_CC_FLAGS = -U__CRYPTO_COMPILE_STANDALONE ++ *_*_*_CC_FLAGS = -I$(EDK2_LIBC_ROOT) ++ *_*_*_CC_FLAGS = -I$(EDK2_ROOT)/CryptoPkg/Library/Include ++ *_*_*_CC_FLAGS = -I$(EDK2_LIBC_ROOT)/StdLib/Include ++ ++[BuildOptions.X64] ++ *_*_*_CC_FLAGS = -I$(EDK2_LIBC_ROOT)/StdLib/Include/X64 ++ *_*_*_CC_FLAGS = -I$(EDK2_ROOT)/MdePkg/Include/X64 +-- +2.55.0 + diff --git a/platforms/uefi/extract-definitions.sh b/platforms/uefi/extract-definitions.sh new file mode 100755 index 000000000..f19f12ae0 --- /dev/null +++ b/platforms/uefi/extract-definitions.sh @@ -0,0 +1,559 @@ +#!/usr/bin/env bash + +# Exit immediately if a command exits with a non-zero status. +set -e +## Treat undefined variables as an error +set -u +# fails if any part of a pipeline (|) fails +set -o pipefail + +SCRIPT_DIR="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" + +# shellcheck source=./platforms/helper.sh +source "$SCRIPT_DIR/../helper.sh" + +expand_array_inf() { + local FILES=("$@") + + for FILE in "${FILES[@]}"; do + + echo " $FILE" + + done + +} + +is_soname() { + local SO_NAME="$1" + [[ "$SO_NAME" =~ (^|/)lib[^/]+\.so(\.[0-9]+)*$ ]] +} + +output_stem() { + local INPUT="$1" + + if is_soname "$INPUT"; then + echo "${INPUT%%.so*}" + else + echo "${INPUT%.*}" + fi + +} + +get_mapped_version() { + local INPUT="$1" + + MESON_PROJECT_INFO_FILE="$(pwd)/meson-info/intro-projectinfo.json" + + if [ "$INPUT" == "oopetris" ]; then + jq -M -r -c ".[\"version\"]" "$MESON_PROJECT_INFO_FILE" + elif [ "$INPUT" == "null" ]; then + echo "Error: invalid version argument: $INPUT" >&2 + exit 2 + else + jq -M -r -c ".[\"subprojects\"][] | select(.[\"name\"] == \"$INPUT\") | .[\"version\"]" "$MESON_PROJECT_INFO_FILE" + fi + +} + +if [ "$#" -eq 2 ]; then + SOURCE_FILE="$1" + DEST_FILE="$(realpath "$2")" +else + echo "Too many arguments given, expected 2" >&2 + exit 1 +fi + +C_LIBRARIES=("LibC" "LibCtype" "LibLocale" "LibMath" "LibSignal" "LibStdio" "LibStdLib" "LibString" "LibTime" "LibUefi" "LibWchar" "LibGdtoa") +CPP_LIBRARIES=("LibCXX" "LibCXXABI") + +MAPPINGS_FILE="$(realpath "$SCRIPT_DIR/../../src/executables/platforms/uefi/mappings.json")" + +DEST_FILE_DIR=$(dirname -- "$DEST_FILE") +DEST_FILE_NAME=$(basename -- "$DEST_FILE") +DEST_FILE_EXT="${DEST_FILE_NAME##*.}" +DEST_FILE_STEM="${DEST_FILE_NAME%.*}" + +if [ "$DEST_FILE_EXT" != "inf" ]; then + echo "Error: invalid dest file extension: $DEST_FILE_EXT" >&2 + exit 2 +fi + +MAPPING_ENTRY="$(jq -M -r -c ".[\"file\"][\"${DEST_FILE_STEM}\"]" "$MAPPINGS_FILE")" + +if [ "$MAPPING_ENTRY" = "null" ]; then + echo "Error: invalid name '$DEST_FILE_STEM': not found in mappings 'file'" >&2 + exit 2 +fi + +SOURCE_FILE_TYPE="$(jq -M -r -c '.["type"]' "$SOURCE_FILE")" + +if [ "$SOURCE_FILE_TYPE" == "link" ] || [ "$SOURCE_FILE_TYPE" == "extern_object" ] || [ "$SOURCE_FILE_TYPE" == "archive" ]; then + : +else + echo "Error: invalid source file type: $SOURCE_FILE_TYPE" >&2 + exit 2 +fi + +mapfile -t FILE_DEPENDENCIES < <(jq -e '.["dependencies"]["files"][]' -M -r -c "$SOURCE_FILE") + +UEFI_INFO_FILE="$(realpath "$SCRIPT_DIR/../crossbuild/uefi_info.json")" +UEFI_INFO_GENERATED_PACKAGES_DIR="$(jq -M -r -c '.["generated_packages"]' "$UEFI_INFO_FILE")" +EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM="$(jq -M -r -c '.["platform"]' "$UEFI_INFO_FILE")" + +add_component_to_platform() { + local PACKAGE_NAME="$1" + + local FINAL_PKG_NAME="$PACKAGE_NAME" + + if grep -q "$FINAL_PKG_NAME" "$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM"; then + : # found already, do nothing + else + cat <>"$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM" +[Components] + $FINAL_PKG_NAME + +EOF + + fi + +} + +add_include_to_platform() { + local PACKAGE_NAME="$1" + + local FINAL_PKG_INC_NAME="$PACKAGE_NAME" + + if grep -q "$FINAL_PKG_INC_NAME" "$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM"; then + : # found already, do nothing + else + cat <>"$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM" +!include $FINAL_PKG_INC_NAME #from extract-defintions + +EOF + + fi + +} + +link_package() { + local PACKAGE_NAME="$1" + local SOURCE_FILE="$2" + + local FINAL_FILE="$UEFI_INFO_GENERATED_PACKAGES_DIR/$PACKAGE_NAME" + + if [ -e "$FINAL_FILE" ]; then + rm "$FINAL_FILE" + fi + + validate_parent_dir "$FINAL_FILE" + + link_files_checked "$SOURCE_FILE" "$FINAL_FILE" + + local SOURCE_FILE_EXT="${SOURCE_FILE##*.}" + + if [ "$SOURCE_FILE_EXT" == "inf" ]; then + add_component_to_platform "$PACKAGE_NAME" + elif [ "$SOURCE_FILE_EXT" == "dec" ]; then + : + elif [ "$SOURCE_FILE_EXT" == "inc" ]; then + add_include_to_platform "$PACKAGE_NAME" + else + echo "Invalid package extension in link_package '$SOURCE_FILE_EXT'" >&2 + exit 2 + fi + +} + +DEP_SOURCES=() +DEP_PACKAGES=() +DEP_CLASSES=() +DEP_BUILD_OPTIONS=() + +for FILE_DEPENDENCY in "${FILE_DEPENDENCIES[@]}"; do + + FILE_DEPENDENCY_TYPE="$(jq -M -r -c '.["type"]' "$FILE_DEPENDENCY")" + + if [ "$FILE_DEPENDENCY_TYPE" == "compile" ]; then + mapfile -t FILE_DEPENDENCY_SRC < <(jq -e '.["dependencies"]["src"][]' -M -r -c "$FILE_DEPENDENCY") + + for FILE_DEPENDENCY_SRC_ENTRY in "${FILE_DEPENDENCY_SRC[@]}"; do + DEP_SOURCES+=("$FILE_DEPENDENCY_SRC_ENTRY") + done + elif [ "$FILE_DEPENDENCY_TYPE" == "archive" ] || [ "$FILE_DEPENDENCY_TYPE" == "link" ]; then + + DEP_OUTPUT="$(jq -e -M -r -c '.["dependencies"]["output"]' "$FILE_DEPENDENCY")" + + if [ "$DEP_OUTPUT" = "null" ]; then + echo "Error: output '$DEP_OUTPUT'" >&2 + exit 2 + fi + + DEP_OUTPUT_NAME=$(basename -- "$DEP_OUTPUT") + DEP_OUTPUT_STEM="$(output_stem "$DEP_OUTPUT_NAME")" + + MAPPING_ENTRY_DEP="$(jq -M -r -c ".[\"name\"][\"${DEP_OUTPUT_STEM}\"]" "$MAPPINGS_FILE")" + + if [ "$MAPPING_ENTRY_DEP" = "null" ]; then + echo "Error: invalid name '$DEP_OUTPUT_STEM': not found in mappings 'name' (dep)" >&2 + exit 2 + fi + + MAPPING_ENTRY_DEP_NAME="$(echo "$MAPPING_ENTRY_DEP" | jq -M -r -c ".[\"name\"]")" + + if [ "$MAPPING_ENTRY_DEP_NAME" = "null" ]; then + echo "Error: invalid name '$MAPPING_ENTRY_DEP_NAME': not found in dependency mapping 'name'" >&2 + exit 2 + fi + + MAPPING_ENTRY_FOR_LIB="$(jq -M -r -c ".[\"file\"][\"${MAPPING_ENTRY_DEP_NAME}\"]" "$MAPPINGS_FILE")" + + if [ "$MAPPING_ENTRY_FOR_LIB" = "null" ]; then + echo "Error: invalid name '$MAPPING_ENTRY_DEP_NAME': not found in mappings 'file'" >&2 + exit 2 + fi + + MAPPING_ENTRY_DEP_LIB="$(echo "$MAPPING_ENTRY_FOR_LIB" | jq -M -r -c ".[\"lib\"]")" + + if [ "$MAPPING_ENTRY_DEP_LIB" = "null" ]; then + echo "Error: invalid lib name '$MAPPING_ENTRY_DEP_LIB': not found in dependency mapping 'lib'" >&2 + exit 2 + fi + + PACKAGE_NAME="GenPkg/$MAPPING_ENTRY_DEP_NAME.dec" + + DEP_OUTPUT_FILE="$DEST_FILE_DIR/$MAPPING_ENTRY_DEP_NAME.inf" + + if ! [ -e "$DEP_OUTPUT_FILE" ]; then + "$SCRIPT_DIR/extract-definitions.sh" "$FILE_DEPENDENCY" "$DEP_OUTPUT_FILE" + fi + + DEP_PACKAGES+=("$PACKAGE_NAME") + DEP_CLASSES+=("$MAPPING_ENTRY_DEP_LIB") + elif [ "$FILE_DEPENDENCY_TYPE" == "extern_object" ]; then + mapfile -t FILE_DEPENDENCY_EXTERN < <(jq -e '.["dependencies"]["extern"][]' -M -r -c "$FILE_DEPENDENCY") + + for FILE_DEPENDENCY_EXTERN_ENTRY in "${FILE_DEPENDENCY_EXTERN[@]}"; do + DEP_SOURCES+=("$FILE_DEPENDENCY_EXTERN_ENTRY") + done + else + echo "Error: invalid file dependency type: $FILE_DEPENDENCY_TYPE" >&2 + exit 2 + fi + +done + +DEP_INCLUDES=() + +MESON_TARGETS_INFO_FILE="$(pwd)/meson-info/intro-targets.json" + +SOURCE_FILE_OUTPUT="$(jq -M -r -c '.["dependencies"]["output"]' "$SOURCE_FILE")" + +if [ "$SOURCE_FILE_OUTPUT" = "null" ]; then + echo "Error: output '$SOURCE_FILE_OUTPUT'" >&2 + exit 2 +fi + +SOURCE_FILE_OUTPUT_NAME=$(basename -- "$SOURCE_FILE_OUTPUT") +SOURCE_FILE_OUTPUT_STEM="$(output_stem "$SOURCE_FILE_OUTPUT_NAME")" + +SOURCE_FILE_ENTRY="$(jq -M -r -c ".[\"name\"][\"${SOURCE_FILE_OUTPUT_STEM}\"]" "$MAPPINGS_FILE")" + +if [ "$SOURCE_FILE_ENTRY" = "null" ]; then + echo "Error: invalid name '$SOURCE_FILE_OUTPUT_STEM': not found in mappings 'name' (src)" >&2 + exit 2 +fi + +SOURCE_FILE_ENTRY_MESON_NAME="$(echo "$SOURCE_FILE_ENTRY" | jq -M -r -c ".[\"meson\"]")" + +if [ "$SOURCE_FILE_ENTRY_MESON_NAME" = "null" ]; then + echo "Error: invalid name '$SOURCE_FILE_ENTRY_MESON_NAME': not found in dependency mapping 'meson'" >&2 + exit 2 +fi + +MESON_TARGETS_INFO_LIB="$( + jq -M -r -c ".[] | select(.[\"name\"] == \"$SOURCE_FILE_ENTRY_MESON_NAME\")" "$MESON_TARGETS_INFO_FILE" +)" + +if [ "$MESON_TARGETS_INFO_LIB" = "null" ] || [ "$MESON_TARGETS_INFO_LIB" = "" ]; then + echo "Error: invalid name '$SOURCE_FILE_ENTRY_MESON_NAME': not found in meson targets file'" >&2 + exit 2 +fi + +if [ "$SOURCE_FILE_TYPE" == "link" ] || [ "$SOURCE_FILE_TYPE" == "archive" ]; then + + MESON_TARGETS_INFO_LIB_TYPE="$(echo "$MESON_TARGETS_INFO_LIB" | jq -M -r -c ".[\"type\"]")" + + mapfile -t MESON_TARGETS_INFO_LIB_COMPILER_TARGETS < <(echo "$MESON_TARGETS_INFO_LIB" | jq '.["target_sources"][] | select( has("compiler") )' -M -r -c) + + if [ "${#MESON_TARGETS_INFO_LIB_COMPILER_TARGETS[@]}" -ne 1 ]; then + #this is fine, as some libraries consist of only extern_objects + : + else + + MESON_TARGETS_INFO_LIB_COMPILER_TARGET="${MESON_TARGETS_INFO_LIB_COMPILER_TARGETS[0]}" + + MESON_TARGETS_INFO_LIB_LANGUAGE="$(echo "$MESON_TARGETS_INFO_LIB_COMPILER_TARGET" | jq -M -r -c ".[\"language\"]")" + + FLAGS_TARGET="CC" + + if [ "$MESON_TARGETS_INFO_LIB_LANGUAGE" == "cpp" ]; then + FLAGS_TARGET="CXX" + for CPP_LIBRARY in "${CPP_LIBRARIES[@]}"; do + DEP_CLASSES+=("$CPP_LIBRARY") + done + DEP_PACKAGES+=("LLVM/LLVMPkg.dec") + DEP_PACKAGES+=("SupportLib/SupportLib.dec") # needed by LLVM + elif [ "$MESON_TARGETS_INFO_LIB_LANGUAGE" == "c" ]; then + FLAGS_TARGET="CC" + else + echo "Error: invalid meson target language: $MESON_TARGETS_INFO_LIB_LANGUAGE" >&2 + exit 2 + fi + + mapfile -t MESON_TARGETS_INFO_LIB_PARAMATERS < <(echo "$MESON_TARGETS_INFO_LIB_COMPILER_TARGET" | jq '.["parameters"][]' -M -r -c) + + for MESON_TARGETS_INFO_LIB_PARAMATER in "${MESON_TARGETS_INFO_LIB_PARAMATERS[@]}"; do + + case "$MESON_TARGETS_INFO_LIB_PARAMATER" in + -I*) + DEP_INCLUDES+=("${MESON_TARGETS_INFO_LIB_PARAMATER:2}") + ;; + -W*) + # TODO: include warnings + ;; + -nostdinc | -nostdinc++ | -nodefaultlibs | -D* | --sysroot=* | -isystem*) + DEP_BUILD_OPTIONS+=("*_*_*_${FLAGS_TARGET}_FLAGS = \"${MESON_TARGETS_INFO_LIB_PARAMATER}\"") + ;; + -t:use-lib:pkg=*) + DEP_PACKAGE_NAME="${MESON_TARGETS_INFO_LIB_PARAMATER:15}" + DEP_PACKAGES+=("$DEP_PACKAGE_NAME/$DEP_PACKAGE_NAME.dec") + ;; + -t:use-pkg:pkg=*) + DEP_PACKAGE_NAME="${MESON_TARGETS_INFO_LIB_PARAMATER:15}" + DEP_PACKAGES+=("$DEP_PACKAGE_NAME") + ;; + -t:use-lib:name=* | -t:use-pkg:name=*) + #ignore + ;; + -t:use-lib:lib=*) + DEP_PACKAGE_LIB="${MESON_TARGETS_INFO_LIB_PARAMATER:15}" + DEP_CLASSES+=("$DEP_PACKAGE_LIB") + ;; + -t:use-pkg:lib=*) + DEP_PACKAGE_LIB="${MESON_TARGETS_INFO_LIB_PARAMATER:15}" + DEP_CLASSES+=("$DEP_PACKAGE_LIB") + ;; + -pthread) + # ignore pthread + ;; + -f* | -m*) + DEP_BUILD_OPTIONS+=("*_*_*_${FLAGS_TARGET}_FLAGS = \"${MESON_TARGETS_INFO_LIB_PARAMATER}\"") + ;; + -g | -std=* | -O*) + #ignore + ;; + *) + echo "Invalid argument detected for compiling '$SOURCE_FILE_ENTRY_MESON_NAME': '$MESON_TARGETS_INFO_LIB_PARAMATER'" >&2 + exit 6 + ;; + esac + done + + fi + + # TODO: what should i do here, archives alias static_libraries don't specify argument, but executables and shared libraries hae -Wl -l or similar arguments + if [ "$MESON_TARGETS_INFO_LIB_TYPE" == "static library" ]; then + #TODO: maybe do something based on the json information we have? + : + elif [ "$MESON_TARGETS_INFO_LIB_TYPE" == "executable" ] || [ "$MESON_TARGETS_INFO_LIB_TYPE" == "shared library" ]; then + #TODO: maybe do something based on the json information we have? + : + else + echo "Error: invalid meson target type for '$SOURCE_FILE_ENTRY_MESON_NAME': $MESON_TARGETS_INFO_LIB_TYPE" >&2 + exit 2 + fi + +elif [ "$SOURCE_FILE_TYPE" == "extern_object" ]; then + : + echo "TODO: not implemented yet" >&2 + exit 35 +else + echo "Error: invalid source file type: $SOURCE_FILE_TYPE" >&2 + exit 2 +fi + +MAPPING_TYPE="$(echo "$MAPPING_ENTRY" | jq -M -r -c ".[\"type\"]")" +MAPPING_NAME="$(echo "$MAPPING_ENTRY" | jq -M -r -c ".[\"name\"]")" +MAPPING_GUID="$(echo "$MAPPING_ENTRY" | jq -M -r -c ".[\"guid\"]")" +MAPPING_VERSION="$(get_mapped_version "$(echo "$MAPPING_ENTRY" | jq -M -r -c ".[\"version\"]")")" + +if [ -z "$MAPPING_VERSION" ]; then + echo "Error: invalid version extracted '$MAPPING_NAME': $MAPPING_VERSION" >&2 + exit 2 + +fi + +if [ "$MAPPING_TYPE" == "application" ]; then + + # add include directories to the build options (as the files build inside the application need that) + for DEP_INCLUDE in "${DEP_INCLUDES[@]}"; do + DEP_BUILD_OPTIONS+=("*_*_*_${FLAGS_TARGET}_FLAGS = \"-I${DEP_INCLUDE}\"") + done + + validate_parent_dir "$DEST_FILE" + + cat <"$DEST_FILE" +[Defines] + INF_VERSION = 1.25 + BASE_NAME = $MAPPING_NAME + FILE_GUID = $MAPPING_GUID + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = $MAPPING_VERSION + ENTRY_POINT = ShellCEntryLibDynamical + +[Sources] +$(expand_array_inf "${DEP_SOURCES[@]}") + +[Packages] +# basic deps + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + LLVM/LLVMPkg.dec + StdLib/StdLib.dec + SupportLib/SupportLib.dec +# dynamic deps +$(expand_array_inf "${DEP_PACKAGES[@]}") + +[LibraryClasses] +# MdePkg + UefiApplicationEntryPoint + UefiLib + DebugLib +# shell libs + ShellCEntryLibDynamical +# C Libs +$(expand_array_inf "${C_LIBRARIES[@]}") +# CPP Libs +$(expand_array_inf "${CPP_LIBRARIES[@]}") +# Dep Classes +$(expand_array_inf "${DEP_CLASSES[@]}") + +[Guids] + +[Ppis] + +[Protocols] + gEfiHiiPackageListProtocolGuid ## CONSUMES + gEfiHttpProtocolGuid ## CONSUMES + gEfiHttpServiceBindingProtocolGuid ## CONSUMES + gEfiManagedNetworkServiceBindingProtocolGuid ## CONSUMES + +[FeaturePcd] + +[Pcd] + +[BuildOptions] + *_*_*_CCONLY_FLAGS = -std=c11 + *_*_*_CXX_FLAGS = -std=c++23 + +$(expand_array_inf "${DEP_BUILD_OPTIONS[@]}") +EOF + + link_package "$DEST_FILE_NAME" "$DEST_FILE" + +elif [ "$MAPPING_TYPE" == "library" ]; then + + # add include directories to the build options (as the files build inside the library need that) + # NOTE: we also define these as [Include], which is not entirely correct, but it didn't lead to problems until now + # TODO: ^ these should be private include dirs not public ones + for DEP_INCLUDE in "${DEP_INCLUDES[@]}"; do + DEP_BUILD_OPTIONS+=("*_*_*_${FLAGS_TARGET}_FLAGS = \"-I${DEP_INCLUDE}\"") + done + + # add custom options, that override fix dependencies + MAPPING_OPTIONS="$(echo "$MAPPING_ENTRY" | jq -M -r -c ".[\"options\"]")" + + if [ "$MAPPING_OPTIONS" != "null" ]; then + mapfile -t MAPPING_OPTIONS_ENTRIES < <(echo "$MAPPING_OPTIONS" | jq -e '.[]' -M -r -c) + + for MAPPING_OPTIONS_ENTRY in "${MAPPING_OPTIONS_ENTRIES[@]}"; do + DEP_BUILD_OPTIONS+=("*_*_*_${FLAGS_TARGET}_FLAGS = \"${MAPPING_OPTIONS_ENTRY}\"") + done + fi + + MAPPING_LIB_NAME="$(echo "$MAPPING_ENTRY" | jq -M -r -c ".[\"lib\"]")" + + LIB_DEST_DIR="$DEST_FILE_DIR/GenPkg" + + validate_parent_dir "$LIB_DEST_DIR/dummy" + + LIB_DEST_FILE_INF="$LIB_DEST_DIR/$DEST_FILE_STEM.inf" + + cat <"$LIB_DEST_FILE_INF" +[Defines] + INF_VERSION = 1.25 + BASE_NAME = $MAPPING_NAME + FILE_GUID = $MAPPING_GUID + MODULE_TYPE = BASE + VERSION_STRING = $MAPPING_VERSION + LIBRARY_CLASS = $MAPPING_LIB_NAME|UEFI_APPLICATION + +[Sources] +$(expand_array_inf "${DEP_SOURCES[@]}") + +[Packages] +# basic deps + MdePkg/MdePkg.dec +# dynamic deps +$(expand_array_inf "${DEP_PACKAGES[@]}") +# stdlib + StdLib/StdLib.dec + +[LibraryClasses] +# MdePkg + UefiLib +# C Libs +$(expand_array_inf "${C_LIBRARIES[@]}") +# Dep Classes +$(expand_array_inf "${DEP_CLASSES[@]}") + +[BuildOptions] + *_*_*_CCONLY_FLAGS = -std=c11 + *_*_*_CXX_FLAGS = -std=c++23 + +$(expand_array_inf "${DEP_BUILD_OPTIONS[@]}") +EOF + + link_package "GenPkg/$DEST_FILE_STEM.inf" "$LIB_DEST_FILE_INF" + + LIB_DEST_FILE_DEC="$LIB_DEST_DIR/$DEST_FILE_STEM.dec" + + cat <"$LIB_DEST_FILE_DEC" +[Defines] + DEC_SPECIFICATION = 1.25 + PACKAGE_NAME = $MAPPING_NAME + PACKAGE_GUID = $MAPPING_GUID + PACKAGE_VERSION = $MAPPING_VERSION + +[Includes] +$(expand_array_inf "${DEP_INCLUDES[@]}") + +[LibraryClasses] +# None # TODO, also add dsc? with ,.inf mappings +EOF + + link_package "GenPkg/$DEST_FILE_STEM.dec" "$LIB_DEST_FILE_DEC" + + LIB_DEST_FILE_INC="$LIB_DEST_DIR/$DEST_FILE_STEM.inc" + + cat <"$LIB_DEST_FILE_INC" +[LibraryClasses.common] + $MAPPING_LIB_NAME|GenPkg/$DEST_FILE_STEM.inf +EOF + + link_package "GenPkg/$DEST_FILE_STEM.inc" "$LIB_DEST_FILE_INC" + +else + echo "Error: invalid mapping type: $MAPPING_TYPE" >&2 + exit 2 +fi diff --git a/platforms/uefi/g++-wrapper.sh b/platforms/uefi/g++-wrapper.sh new file mode 100755 index 000000000..ed2cc67eb --- /dev/null +++ b/platforms/uefi/g++-wrapper.sh @@ -0,0 +1,229 @@ +#!/usr/bin/env bash + +# Exit immediately if a command exits with a non-zero status. +set -e +## Treat undefined variables as an error +set -u +# fails if any part of a pipeline (|) fails +set -o pipefail + +SCRIPT_DIR="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" + +# shellcheck source=./platforms/helper.sh +source "$SCRIPT_DIR/../helper.sh" + +CXX="g++-15" +TOOL="G++" + +# shellcheck source=./platforms/uefi/base.sh +source "$SCRIPT_DIR/base.sh" + +# Capture all args +ARGS=("$@") + +OUTPUT_FILE="" +DEPENDENCIES_O=() +DEPENDENCIES_SRC=() +DEPENDENCIES_LINK=() + +for ARG in "${ARGS[@]}"; do + case "$ARG" in + -Wl,--version | -Wl,-v) + change_mode "pass" + ;; + -c) + if [[ "$MODE" == "pass_override" ]]; then + : + else + change_mode "compile" + fi + ;; + -E | -H) + change_mode "pass" + ;; + -Wl,*) + change_mode "link" + LINK_ARG="${ARG:4}" + case "$LINK_ARG" in + --as-needed | --no-undefined | --fatal-warnings | --whole-archive | --no-whole-archive | -O* | -soname,* | -rpath,*) + # ignore, valid arguments + ;; + --start-group) + change_next_type "link" + ;; + --end-group) + reset_next_type + ;; + -t:use-lib* | -t:use-pkg*) + # ignore here, the extraction uses that for inf and dec dependencies + ;; + *) + echo "Invalid link argument detected: '$LINK_ARG'" >&2 + exit 6 + ;; + esac + ;; + -o) + change_next_type "output" + ;; + -MQ | -MF | -isystem) + change_next_type "ignore" + ;; + --version | -dM) + change_mode "pass" + ;; + -x) + change_mode "pass" + change_next_type "ignore" + ;; + -xc++) + # C++ specific + change_mode "pass" + ;; + *) + if [[ "$NEXT_TYPE" == "output" ]]; then + OUTPUT_FILE="$(normalize_file "$ARG")" + reset_next_type + + case "$OUTPUT_FILE" in + *.obj) + # meson compatibility, .obj is used for cc.compiles and cc.sizeof calls + MODE="unknown" + change_mode "pass_override" + ;; + *) ;; + esac + + elif [[ "$NEXT_TYPE" == "ignore" ]]; then + reset_next_type + elif [[ "$NEXT_TYPE" == "link" ]]; then + case "$ARG" in + -pthread | -m*) + # ignore + ;; + -l*) + DEPENDENCIES_LINK+=("SYSTEM:${ARG:2}") + ;; + *.o) + echo "Invalid file detected: '$ARG'" >&2 + exit 5 + ;; + *.cpp) + # C++ specific + echo "Invalid file detected: '$ARG'" >&2 + exit 5 + ;; + *.a | *.so) + DEPENDENCIES_LINK+=("$(resolve_file "$ARG")") + ;; + *) + if is_soname "$ARG"; then + DEPENDENCIES_LINK+=("$(resolve_file "$ARG")") + else + echo "Invalid link group argument detected: '$ARG'" >&2 + exit 6 + fi + ;; + esac + elif [[ "$NEXT_TYPE" == "unknown" ]]; then + case "$ARG" in + *.o) + DEPENDENCIES_O+=("$(resolve_file "$ARG")") + ;; + *.cpp) + # C++ specific + DEPENDENCIES_SRC+=("$(resolve_file "$ARG")") + ;; + *.a | *.so) + DEPENDENCIES_LINK+=("$(resolve_file "$ARG")") + ;; + -cpp) + # ignore this for meson usage, even if gcc only uses this for fortran, but it doesn't complain about it + ;; + -v | - | -g | -P | -MD | -pthread | -shared | -nostdinc | -nostdinc++ | -nodefaultlibs | -isystem* | --sysroot=* | -std=* | -f* | -m* | -D* | -U* | -W* | -O* | -I* | -L* | -l*) + # ignore, valid arguments + ;; + -t:use-lib* | -t:use-pkg*) + # ignore here, the extraction uses that for inf and dec dependencies + ;; + *) + if is_soname "$ARG"; then + DEPENDENCIES_LINK+=("$(resolve_file "$ARG")") + else + + echo "Invalid argument detected: '$ARG'" >&2 + exit 6 + fi + ;; + esac + else + echo "Not recognized next type: $NEXT_TYPE" >&2 + exit 11 + fi + ;; + esac +done + +if [[ "$MODE" == "pass" ]] || [[ "$MODE" == "pass_override" ]]; then + exec "$CXX" "${ARGS[@]}" +elif [[ "$MODE" == "compile" ]]; then + if [ -z "$OUTPUT_FILE" ]; then + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Missing output file" >&2 + exit 2 + fi + + validate_parent_dir "$OUTPUT_FILE" + + validate_files "${DEPENDENCIES_SRC[@]}" + + require_empty_array "${DEPENDENCIES_O[@]}" + + require_empty_array "${DEPENDENCIES_LINK[@]}" + + cat <"$OUTPUT_FILE" +{ + "cwd": "$(pwd)", + "args": $(to_json_array "${ARGS[@]}"), + "language": "cpp", + "type": "compile", + "dependencies": { + "output": "$OUTPUT_FILE", + "src": $(to_json_array "${DEPENDENCIES_SRC[@]}") + } +} +EOF + +elif [[ "$MODE" == "link" ]]; then + if [ -z "$OUTPUT_FILE" ]; then + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Missing output file" >&2 + exit 2 + fi + + validate_parent_dir "$OUTPUT_FILE" + + validate_dependencies "${DEPENDENCIES_O[@]}" + + validate_dependencies "${DEPENDENCIES_LINK[@]}" + + require_empty_array "${DEPENDENCIES_SRC[@]}" + + cat <"$OUTPUT_FILE" +{ + "cwd": "$(pwd)", + "args": $(to_json_array "${ARGS[@]}"), + "language": "cpp", + "type": "link", + "dependencies": { + "output": "$OUTPUT_FILE", + "files": $(to_json_array "${DEPENDENCIES_O[@]}" "${DEPENDENCIES_LINK[@]}") + } +} +EOF + +else + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Not recognized intent: $MODE" >&2 + exit 2 +fi diff --git a/platforms/uefi/gcc-wrapper.sh b/platforms/uefi/gcc-wrapper.sh new file mode 100755 index 000000000..61954a275 --- /dev/null +++ b/platforms/uefi/gcc-wrapper.sh @@ -0,0 +1,229 @@ +#!/usr/bin/env bash + +# Exit immediately if a command exits with a non-zero status. +set -e +## Treat undefined variables as an error +set -u +# fails if any part of a pipeline (|) fails +set -o pipefail + +SCRIPT_DIR="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" + +# shellcheck source=./platforms/helper.sh +source "$SCRIPT_DIR/../helper.sh" + +CC="gcc-15" +TOOL="GCC" + +# shellcheck source=./platforms/uefi/base.sh +source "$SCRIPT_DIR/base.sh" + +# Capture all args +ARGS=("$@") + +OUTPUT_FILE="" +DEPENDENCIES_O=() +DEPENDENCIES_SRC=() +DEPENDENCIES_LINK=() + +for ARG in "${ARGS[@]}"; do + case "$ARG" in + -Wl,--version | -Wl,-v) + change_mode "pass" + ;; + -c) + if [[ "$MODE" == "pass_override" ]]; then + : + else + change_mode "compile" + fi + ;; + -E | -H) + change_mode "pass" + ;; + -Wl,*) + change_mode "link" + LINK_ARG="${ARG:4}" + case "$LINK_ARG" in + --as-needed | --no-undefined | --fatal-warnings | --whole-archive | --no-whole-archive | -O* | -soname,* | -rpath,*) + # ignore, valid arguments + ;; + --start-group) + change_next_type "link" + ;; + --end-group) + reset_next_type + ;; + -t:use-lib* | -t:use-pkg*) + # ignore here, the extraction uses that for inf and dec dependencies + ;; + *) + echo "Invalid link argument detected: '$LINK_ARG'" >&2 + exit 6 + ;; + esac + ;; + -o) + change_next_type "output" + ;; + -MQ | -MF | -isystem) + change_next_type "ignore" + ;; + --version | -dM) + change_mode "pass" + ;; + -x) + change_mode "pass" + change_next_type "ignore" + ;; + -xc) + # C specific + change_mode "pass" + ;; + *) + if [[ "$NEXT_TYPE" == "output" ]]; then + OUTPUT_FILE="$(normalize_file "$ARG")" + reset_next_type + + case "$OUTPUT_FILE" in + *.obj) + # meson compatibility, .obj is used for cc.compiles and cc.sizeof calls + MODE="unknown" + change_mode "pass_override" + ;; + *) ;; + esac + + elif [[ "$NEXT_TYPE" == "ignore" ]]; then + reset_next_type + elif [[ "$NEXT_TYPE" == "link" ]]; then + case "$ARG" in + -pthread | -m*) + # ignore + ;; + -l*) + DEPENDENCIES_LINK+=("SYSTEM:${ARG:2}") + ;; + *.o) + echo "Invalid file detected: '$ARG'" >&2 + exit 5 + ;; + *.c) + # C specific + echo "Invalid file detected: '$ARG'" >&2 + exit 5 + ;; + *.a | *.so) + DEPENDENCIES_LINK+=("$(resolve_file "$ARG")") + ;; + *) + if is_soname "$ARG"; then + DEPENDENCIES_LINK+=("$(resolve_file "$ARG")") + else + echo "Invalid link group argument detected: '$ARG'" >&2 + exit 6 + fi + ;; + esac + elif [[ "$NEXT_TYPE" == "unknown" ]]; then + case "$ARG" in + *.o) + DEPENDENCIES_O+=("$(resolve_file "$ARG")") + ;; + *.c) + # C specific + DEPENDENCIES_SRC+=("$(resolve_file "$ARG")") + ;; + *.a | *.so) + DEPENDENCIES_LINK+=("$(resolve_file "$ARG")") + ;; + -cpp) + # ignore this for meson usage, even if gcc only uses this for fortran, but it doesn't complain about it + ;; + -v | - | -g | -P | -MD | -pthread | -shared | -nostdinc | -nodefaultlibs | -isystem* | --sysroot=* | -std=* | -f* | -m* | -D* | -U* | -W* | -O* | -I* | -L* | -l*) + # ignore, valid arguments + ;; + -t:use-lib* | -t:use-pkg*) + # ignore here, the extraction uses that for inf and dec dependencies + ;; + *) + if is_soname "$ARG"; then + DEPENDENCIES_LINK+=("$(resolve_file "$ARG")") + else + + echo "Invalid argument detected: '$ARG'" >&2 + exit 6 + fi + ;; + esac + else + echo "Not recognized next type: $NEXT_TYPE" >&2 + exit 11 + fi + ;; + esac +done + +if [[ "$MODE" == "pass" ]] || [[ "$MODE" == "pass_override" ]]; then + exec "$CC" "${ARGS[@]}" +elif [[ "$MODE" == "compile" ]]; then + if [ -z "$OUTPUT_FILE" ]; then + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Missing output file" >&2 + exit 2 + fi + + validate_parent_dir "$OUTPUT_FILE" + + validate_files "${DEPENDENCIES_SRC[@]}" + + require_empty_array "${DEPENDENCIES_O[@]}" + + require_empty_array "${DEPENDENCIES_LINK[@]}" + + cat <"$OUTPUT_FILE" +{ + "cwd": "$(pwd)", + "args": $(to_json_array "${ARGS[@]}"), + "language": "c", + "type": "compile", + "dependencies": { + "output": "$OUTPUT_FILE", + "src": $(to_json_array "${DEPENDENCIES_SRC[@]}") + } +} +EOF + +elif [[ "$MODE" == "link" ]]; then + if [ -z "$OUTPUT_FILE" ]; then + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Missing output file" >&2 + exit 2 + fi + + validate_parent_dir "$OUTPUT_FILE" + + validate_dependencies "${DEPENDENCIES_O[@]}" + + validate_dependencies "${DEPENDENCIES_LINK[@]}" + + require_empty_array "${DEPENDENCIES_SRC[@]}" + + cat <"$OUTPUT_FILE" +{ + "cwd": "$(pwd)", + "args": $(to_json_array "${ARGS[@]}"), + "language": "c", + "type": "link", + "dependencies": { + "output": "$OUTPUT_FILE", + "files": $(to_json_array "${DEPENDENCIES_O[@]}" "${DEPENDENCIES_LINK[@]}") + } +} +EOF + +else + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Not recognized intent: $MODE" >&2 + exit 2 +fi diff --git a/platforms/uefi/pkg-config-wrapper.sh b/platforms/uefi/pkg-config-wrapper.sh new file mode 100755 index 000000000..1af461f28 --- /dev/null +++ b/platforms/uefi/pkg-config-wrapper.sh @@ -0,0 +1,224 @@ +#!/usr/bin/env bash + +# Exit immediately if a command exits with a non-zero status. +set -e +## Treat undefined variables as an error +set -u +# fails if any part of a pipeline (|) fails +set -o pipefail + +SCRIPT_DIR="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" + +# shellcheck source=./platforms/helper.sh +source "$SCRIPT_DIR/../helper.sh" + +LIBRARIES_FILE="$(realpath "$SCRIPT_DIR/../../src/executables/platforms/uefi/libraries.json")" + +PKG_CONFIG="pkg-config" +TOOL="PKG-CONFIG" + +# Capture all ARGs +ARGS=("$@") + +MODE="unknown" + +change_mode() { + local NEW_MODE="$1" + + if [[ "$MODE" == "unknown" ]]; then + MODE="$NEW_MODE" + elif [[ "$MODE" == "$NEW_MODE" ]]; then + : + else + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Can't change mode from $MODE to $NEW_MODE" >&2 + exit 4 + fi +} + +UEFI_INFO_FILE="$(realpath "$SCRIPT_DIR/../crossbuild/uefi_info.json")" +EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM="$(jq -M -r -c '.["platform"]' "$UEFI_INFO_FILE")" +EDK2_TOOLS_DIR="$(jq -M -r -c '.["edk2_tools_dir"]' "$UEFI_INFO_FILE")" + +link_uefi_libray() { + local LIB_NAME_INF="$1" + local PACKAGE_NAME_INC="$2" + + if grep -q "$LIB_NAME_INF" "$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM"; then + : # found already, do nothing + else + cat <>"$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM" +[Components] + $LIB_NAME_INF + +EOF + + fi + + if [ "$PACKAGE_NAME_INC" != "null" ]; then + + if grep -q "$PACKAGE_NAME_INC" "$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM"; then + : # found already, do nothing + else + cat <>"$EDK2_TARGET_PROPERTIES_ACTIVE_PLATFORM" +!include $PACKAGE_NAME_INC # from pkg-config + +EOF + + fi + fi + +} + +link_built_libray() { + local PACKAGE_NAME_PKG="$1" + + local FINAL_PKG_NAME="$PACKAGE_NAME_PKG/$PACKAGE_NAME_PKG.inf" + + local FINAL_PKG_INC_NAME="$PACKAGE_NAME_PKG/$PACKAGE_NAME_PKG.inc" + + link_uefi_libray "$FINAL_PKG_NAME" "$FINAL_PKG_INC_NAME" + +} + +WHAT="" +PACKAGE_NAME="" +NEXT_IS_PACKAGE_NAME="false" + +for ARG in "${ARGS[@]}"; do + case "$ARG" in + --version) + change_mode "pass" + ;; + --modversion) + change_mode "get" + WHAT="version" + NEXT_IS_PACKAGE_NAME="true" + ;; + --cflags) + change_mode "get" + WHAT="cflags" + NEXT_IS_PACKAGE_NAME="true" + ;; + --libs) + change_mode "get" + WHAT="libflags" + NEXT_IS_PACKAGE_NAME="true" + ;; + *) + if [[ "$NEXT_IS_PACKAGE_NAME" == true ]]; then + PACKAGE_NAME="$ARG" + NEXT_IS_PACKAGE_NAME=false + fi + ;; + esac +done + +if [[ "$MODE" == "pass" ]]; then + exec "$PKG_CONFIG" "${ARGS[@]}" +elif [[ "$MODE" == "get" ]]; then + if [ -z "$PACKAGE_NAME" ]; then + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Missing package name" >&2 + exit 2 + fi + + case "$PACKAGE_NAME" in + uefi:*) + # special handling + + LIB_ENTRY_NAME_UEFI="${PACKAGE_NAME:5}" + + LIBRARY_ENTRY_UEFI="$(jq -M -r -c ".[\"uefi\"][\"${LIB_ENTRY_NAME_UEFI}\"]" "$LIBRARIES_FILE")" + + if [ "$LIBRARY_ENTRY_UEFI" = "null" ]; then + exit 1 + fi + + PACKAGE_NAME_UEFI="$(echo "$LIBRARY_ENTRY_UEFI" | jq -M -r -c ".[\"pkg\"]")" + LIB_NAME_UEFI="$(echo "$LIBRARY_ENTRY_UEFI" | jq -M -r -c ".[\"lib\"]")" + INF_FILE_UEFI="$(echo "$LIBRARY_ENTRY_UEFI" | jq -M -r -c ".[\"inf\"]")" + INC_FILE_UEFI="$(echo "$LIBRARY_ENTRY_UEFI" | jq -M -r -c ".[\"inc\"]")" + TOOL_PREFIX_UEFI="$(echo "$LIBRARY_ENTRY_UEFI" | jq -M -r -c ".[\"tool_prefix\"]")" + + PACKAGE_NAME_DEC="$PACKAGE_NAME_UEFI.dec" + PACKAGE_DESC_FILE="$EDK2_TOOLS_DIR/$TOOL_PREFIX_UEFI/$PACKAGE_NAME_DEC" + + if ! [ -e "$PACKAGE_DESC_FILE" ]; then + exit 1 + fi + + if [[ "$WHAT" == "version" ]]; then + PACKAGE_VERSION=$(grep -E '^[[:space:]]*PACKAGE_VERSION[[:space:]]*=' "$PACKAGE_DESC_FILE" | cut -d= -f2 | xargs) + echo "$PACKAGE_VERSION" + exit 0 + elif [[ "$WHAT" == "cflags" ]]; then + echo "-t:use-pkg:name=$PACKAGE_NAME_UEFI" + echo "-t:use-pkg:pkg=$PACKAGE_NAME_DEC" + echo "-t:use-pkg:lib=$LIB_NAME_UEFI" + + link_uefi_libray "$INF_FILE_UEFI" "$INC_FILE_UEFI" + + exit 0 + elif [[ "$WHAT" == "libflags" ]]; then + + echo "-Wl,-t:use-pkg:name=$PACKAGE_NAME_UEFI" + echo "-Wl,-t:use-pkg:pkg=$PACKAGE_NAME_DEC" + echo "-Wl,-t:use-pkg:lib=$LIB_NAME_UEFI" + + link_uefi_libray "$INF_FILE_UEFI" "$INC_FILE_UEFI" + + exit 0 + else + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Not recognized intent: $MODE" >&2 + exit 3 + fi + ;; + *) + # fall through + ;; + esac + + LIBRARY_ENTRY="$(jq -M -r -c ".[\"custom\"][\"${PACKAGE_NAME}\"]" "$LIBRARIES_FILE")" + + if [ "$LIBRARY_ENTRY" = "null" ]; then + exit 1 + fi + + if [[ "$WHAT" == "version" ]]; then + echo "$LIBRARY_ENTRY" | jq -M -r -c ".[\"version\"]" + exit 0 + elif [[ "$WHAT" == "cflags" ]]; then + PACKAGE_NAME_PKG="$(echo "$LIBRARY_ENTRY" | jq -M -r -c ".[\"pkg\"]")" + PACKAGE_NAME_LIB="$(echo "$LIBRARY_ENTRY" | jq -M -r -c ".[\"lib\"]")" + + echo "-t:use-lib:name=$PACKAGE_NAME" + echo "-t:use-lib:pkg=$PACKAGE_NAME_PKG" + echo "-t:use-lib:lib=$PACKAGE_NAME_LIB" + + link_built_libray "$PACKAGE_NAME_PKG" + + exit 0 + elif [[ "$WHAT" == "libflags" ]]; then + PACKAGE_NAME_PKG="$(echo "$LIBRARY_ENTRY" | jq -M -r -c ".[\"pkg\"]")" + PACKAGE_NAME_LIB="$(echo "$LIBRARY_ENTRY" | jq -M -r -c ".[\"lib\"]")" + + echo "-Wl,-t:use-lib:name=$PACKAGE_NAME" + echo "-Wl,-t:use-lib:pkg=$PACKAGE_NAME_PKG" + echo "-Wl,-t:use-lib:lib=$PACKAGE_NAME_LIB" + + link_built_libray "$PACKAGE_NAME_PKG" + + exit 0 + else + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Not recognized intent: $MODE" >&2 + exit 3 + fi + +else + echo "<$TOOL> ${ARGS[*]}" >&2 + echo "Not recognized intent: $MODE" >&2 + exit 2 +fi diff --git a/platforms/versions.sh b/platforms/versions.sh old mode 100644 new mode 100755 index 9e84e3f59..c46f2952c --- a/platforms/versions.sh +++ b/platforms/versions.sh @@ -30,3 +30,11 @@ export NDK_VER_DESC="r29" export EMSCRIPTEN_RELEASE_TAG="6.0.5" export EMSDK_EXECUTE_NODE_VERSION="24.7.0" + +# edk2 section + +export EDK2_RELEASE_TAG="edk2-stable202608" + +export EDK2_LIBC_COMMIT_HASH="e6985d1dd786f89be3c908ec7b19e3e6da463578" + +export EDK2_LLVM_PORT_BRANCH="uefi_port" diff --git a/src/discord/core.hpp b/src/discord/core.hpp index 7eb8efae5..e95b87d69 100644 --- a/src/discord/core.hpp +++ b/src/discord/core.hpp @@ -28,7 +28,7 @@ namespace constants::discord { //TODO(Totto): this isn't correct for all platforms and needs to be tested #if defined(__ANDROID__) constexpr const char* platform_dependent_launch_arguments = "TODO"; -#elif defined(__CONSOLE__) +#elif defined(__CONSOLE__) || defined(__UEFI__) #error "Not supported" #elif defined(FLATPAK_BUILD) constexpr const char* platform_dependent_launch_arguments = @@ -45,10 +45,10 @@ namespace constants::discord { #if defined(__ANDROID__) constexpr const discordpp::ActivityGamePlatforms supported_platforms = discordpp::ActivityGamePlatforms::Android; -#elif defined(__CONSOLE__) +#elif defined(__CONSOLE__) || defined(__UEFI__) #error "Not supported" #elif defined(FLATPAK_BUILD) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) \ - || defined(__APPLE__) || defined(__linux__) + || defined(__APPLE__) || defined(__linux__) || defined(__UEFI__) constexpr const discordpp::ActivityGamePlatforms supported_platforms = discordpp::ActivityGamePlatforms::Desktop; #else #error "Unsupported platform" diff --git a/src/executables/game/application.cpp b/src/executables/game/application.cpp index 0a6ceb831..6ac8f6bf1 100644 --- a/src/executables/game/application.cpp +++ b/src/executables/game/application.cpp @@ -32,7 +32,7 @@ namespace { - [[nodiscard]] helper::MessageBox::Type get_notification_level(helper::error::Severity severity) { + [[nodiscard]] [[maybe_unused]] helper::MessageBox::Type get_notification_level(helper::error::Severity severity) { return severity == helper::error::Severity::Fatal ? helper::MessageBox::Type::Error : severity == helper::error::Severity::Major ? helper::MessageBox::Type::Warning : helper::MessageBox::Type::Information; @@ -71,14 +71,14 @@ helper::TimeInfo::TimeInfo( helper::LoadingInfo::LoadingInfo( std::chrono::nanoseconds sleep_time, Uint64 start_time, - std::future&& load_everything_thread, + oopetris::future&& load_everything_future, std::chrono::steady_clock::time_point start_execution_time, bool finished_loading, scenes::LoadingScreen&& loading_screen ) : m_sleep_time{ sleep_time }, m_start_time{ start_time }, - m_load_everything_thread{ std::move(load_everything_thread) }, + m_load_everything_future{ std::move(load_everything_future) }, m_start_execution_time{ start_execution_time }, m_finished_loading{ finished_loading }, m_loading_screen{ std::move(loading_screen) } { } @@ -92,11 +92,16 @@ helper::LoadingInfo::LoadingInfo( } -[[nodiscard]] const std::future& helper::LoadingInfo::load_everything_thread() const { - return m_load_everything_thread; +[[nodiscard]] const oopetris::future& helper::LoadingInfo::load_everything_future() const { + return m_load_everything_future; } -Application::Application(std::shared_ptr&& window, CommandLineArguments&& arguments) try +Application::Application(std::shared_ptr&& window, CommandLineArguments&& arguments) + +#if !defined(__OOPETRIS_NO_EXCEPTIONS) + try +#endif + : m_command_line_arguments{ std::move(arguments) }, m_window{ std::move(window) }, m_renderer{ *m_window, m_command_line_arguments.target_fps.has_value() ? Renderer::VSync::Disabled @@ -109,7 +114,9 @@ Application::Application(std::shared_ptr&& window, CommandLineArguments& #endif { initialize(); -} catch (const helper::GeneralError& general_error) { +} +#if !defined(__OOPETRIS_NO_EXCEPTIONS) +catch (const helper::GeneralError& general_error) { const auto severity = general_error.severity(); const auto notification_level = get_notification_level(severity); @@ -120,11 +127,12 @@ Application::Application(std::shared_ptr&& window, CommandLineArguments& throw general_error; } } +#endif Application::~Application() = default; #if defined(__EMSCRIPTEN__) -void c_loop_entry(void* arg) { +static void c_loop_entry(void* arg) { auto application = reinterpret_cast(arg); application->emscripten_do_process(); application->loop_entry_emscripten(); @@ -300,9 +308,10 @@ void Application::load_loop() { // end waiting // wait until is faster, since it just compares two time_points instead of getting now() and than adding the wait-for argument - m_loading_info->m_finished_loading = - m_loading_info->load_everything_thread().wait_until(std::chrono::system_clock::time_point::min()) - == std::future_status::ready; + auto loading_status = + m_loading_info->load_everything_future().wait_until(std::chrono::system_clock::time_point::min()); + ASSERT(loading_status == oopetris::future_status::ready || loading_status == oopetris::future_status::timeout); + m_loading_info->m_finished_loading = loading_status == oopetris::future_status::ready; } @@ -369,30 +378,32 @@ void Application::update() { for (usize i = 0; i < num_scenes; ++i) { const auto index = num_scenes - i - 1; +#if !defined(__OOPETRIS_NO_EXCEPTIONS) try { +#endif auto [scene_update, scene_change] = m_scene_stack.at(index)->update(); if (scene_change) { std::visit( helper::Overloaded{ - [this, index](const scenes::Scene::Pop&) { + [this, index](const scenes::Scene::Pop&) -> void { m_scene_stack.erase( m_scene_stack.begin() + static_cast(index) ); }, - [this](const scenes::Scene::Push& push) { + [this](const scenes::Scene::Push& push) -> void { spdlog::info("pushing back scene {}", magic_enum::enum_name(push.target_scene)); m_scene_stack.push_back( scenes::create_scene(*this, push.target_scene, push.layout) ); }, - [this](scenes::Scene::RawPush& raw_push) { + [this](scenes::Scene::RawPush& raw_push) -> void { spdlog::info("pushing back scene {}", raw_push.name); m_scene_stack.push_back(std::move(raw_push.scene)); }, - [this](const scenes::Scene::Switch& scene_switch) { + [this](const scenes::Scene::Switch& scene_switch) -> void { spdlog::info( "switching to scene {}", magic_enum::enum_name(scene_switch.m_target_scene) ); @@ -421,7 +432,7 @@ void Application::update() { // if an error occurred on: // - creation: the creation wasn't finished, so just not pushing / switching to the scene // -update: the update failed in the middle, and the scene, that caused the error, has to make sure, that ignoring it, (and not crashing) resets the state, so that this doesn't occur on every frame - +#if !defined(__OOPETRIS_NO_EXCEPTIONS) } catch (const std::runtime_error& error) { m_window->show_simple(helper::MessageBox::Type::Error, "Error on Scene Initialization", error.what()); } catch (const helper::GeneralError& general_error) { @@ -429,6 +440,7 @@ void Application::update() { m_window->show_simple(notification_level, "Error on Scene Initialization", general_error.message()); } +#endif } #if defined(_HAVE_DISCORD_SOCIAL_SDK) @@ -464,7 +476,7 @@ void Application::initialize() { const auto start_time = SDL_GetTicks64(); - std::future load_everything_thread = std::async(std::launch::async, [this] { + oopetris::future load_everything_future = OOPETRIS_ASYNC(OOPETRIS_ASYNC_LAUNCH_ARG, [this]() -> void { this->m_settings_manager = std::make_unique(this); this->m_settings_manager->add_callback([this](const auto& settings) { this->reload_api(settings); }); @@ -509,7 +521,7 @@ void Application::initialize() { auto start_execution_time_arg = std::chrono::steady_clock::now(); m_loading_info = std::make_unique( - sleep_time, start_time, std::move(load_everything_thread), start_execution_time_arg, false, + sleep_time, start_time, std::move(load_everything_future), start_execution_time_arg, false, std::move(loading_screen_arg) ); diff --git a/src/executables/game/application.hpp b/src/executables/game/application.hpp index feef60df9..fdbd2ca5c 100644 --- a/src/executables/game/application.hpp +++ b/src/executables/game/application.hpp @@ -17,10 +17,41 @@ #include "ui/components/label.hpp" #include -#include #include #include +#if !defined(__OOPETRIS_HAVE_NO_THREADS) +#include + +#define OOPETRIS_ASYNC std::async +#define OOPETRIS_ASYNC_LAUNCH_ARG std::launch::async + +namespace oopetris { + template + using future = std::future; + using future_status = std::future_status; +} // namespace oopetris + +#else +#if defined(__UEFI__) + + +#include "helper/uefi_futures.hpp" + +#define OOPETRIS_ASYNC uefi::helper::async +#define OOPETRIS_ASYNC_LAUNCH_ARG (std::monostate{}) + +namespace oopetris { + template + using future = uefi::helper::future; + using future_status = uefi::helper::future_status; +} // namespace oopetris +#else +#error "We need threads in this environment" +#endif + +#endif + #if defined(__EMSCRIPTEN__) #include "helper/web_utils.hpp" @@ -61,7 +92,7 @@ namespace helper { std::chrono::nanoseconds m_sleep_time; Uint64 m_start_time; - std::future m_load_everything_thread; + oopetris::future m_load_everything_future; public: std::chrono::steady_clock::time_point m_start_execution_time; @@ -71,7 +102,7 @@ namespace helper { LoadingInfo( std::chrono::nanoseconds sleep_time, Uint64 start_time, - std::future&& load_everything_thread, + oopetris::future&& m_load_everything_future, std::chrono::steady_clock::time_point start_execution_time, bool finished_loading, scenes::LoadingScreen&& loading_screen @@ -81,7 +112,7 @@ namespace helper { [[nodiscard]] Uint64 start_time() const; - [[nodiscard]] const std::future& load_everything_thread() const; + [[nodiscard]] const oopetris::future& load_everything_future() const; }; } // namespace helper diff --git a/src/executables/game/main.cpp b/src/executables/game/main.cpp index d07dc7cf7..c39e1be79 100644 --- a/src/executables/game/main.cpp +++ b/src/executables/game/main.cpp @@ -24,6 +24,11 @@ #include "helper/console_helpers.hpp" #endif +#if defined(__UEFI__) +#include "helper/uefi_utils.hpp" +#endif + + #if defined(__EMSCRIPTEN__) #include "helper/web_utils.hpp" #endif @@ -52,6 +57,10 @@ namespace { sinks.push_back(std::make_shared(constants::program_name.c_str())); #elif defined(__CONSOLE__) sinks.push_back(std::make_shared()); +#elif defined(__UEFI__) + sinks.push_back(uefi::get_debug_sink()); + // is outputted to serial, handled by edk2-libc + sinks.push_back(std::make_shared(spdlog::color_mode::never)); #elif defined(__EMSCRIPTEN__) sinks.push_back(web::get_console_sink()); #else @@ -59,7 +68,7 @@ namespace { #endif -#if !(defined(__EMSCRIPTEN__)) +#if !(defined(__EMSCRIPTEN__) || defined(__UEFI__)) const auto logs_path = utils::get_root_folder() / "logs"; @@ -71,9 +80,11 @@ namespace { if (not created_log_dir.has_value()) { - sinks.push_back(std::make_shared( - fmt::format("{}/oopetris.log", logs_path.string()), 1024 * 1024 * 10, 5, true - )); + sinks.push_back( + std::make_shared( + fmt::format("{}/oopetris.log", logs_path.string()), 1024 * 1024 * 10, 5, true + ) + ); } #endif @@ -92,8 +103,9 @@ namespace { std::shared_ptr window{ nullptr }; +#if !defined(__OOPETRIS_NO_EXCEPTIONS) try { - +#endif initialize_spdlog(); std::vector arguments_vector{}; @@ -118,18 +130,21 @@ namespace { [[maybe_unused]] constexpr auto window_name = constants::program_name.c_str(); - +#if !defined(__OOPETRIS_NO_EXCEPTIONS) try { +#endif #if defined(__ANDROID__) or defined(__CONSOLE__) or defined(__SERENITY__) or defined(__EMSCRIPTEN__) window = std::make_shared(window_name, WindowPosition::Centered); #else - [[maybe_unused]] static constexpr int width = 1280; - [[maybe_unused]] static constexpr int height = 720; - window = std::make_shared(window_name, WindowPosition::Centered, width, height); + [[maybe_unused]] static constexpr int width = 1280; + [[maybe_unused]] static constexpr int height = 720; + window = std::make_shared(window_name, WindowPosition::Centered, width, height); #endif +#if !defined(__OOPETRIS_NO_EXCEPTIONS) } catch (const helper::GeneralError& general_error) { spdlog::error("Couldn't initialize window: {}", general_error.message()); } +#endif if (window == nullptr) { helper::MessageBox::show_simple( @@ -142,7 +157,7 @@ namespace { app.run(); return EXIT_SUCCESS; - +#if !defined(__OOPETRIS_NO_EXCEPTIONS) } catch (const helper::GeneralError& general_error) { spdlog::error("{}", general_error.message()); @@ -165,12 +180,25 @@ namespace { std::cerr << error.what(); return EXIT_FAILURE; } +#endif } } // namespace +#if defined(__UEFI__) + +#include + +int EDK2_LIBCXX_ENTRY_NAME(int argc, char** argv) { + return main_no_sdl_replace(argc, argv); +} + +#else + int main(int argc, char** argv) { return main_no_sdl_replace(argc, argv); } + +#endif diff --git a/src/executables/game/parser.cpp b/src/executables/game/parser.cpp index e855ab282..48d099689 100644 --- a/src/executables/game/parser.cpp +++ b/src/executables/game/parser.cpp @@ -10,10 +10,15 @@ #include "helper/spdlog_wrapper.hpp" -#include +#if !defined(__UEFI__) +#include +#endif helper::expected helper::parse_args(const std::vector& arguments) { +#if defined(__UEFI__) + return CommandLineArguments{ std::nullopt, std::nullopt }; +#else argparse::ArgumentParser parser{ constants::program_name, constants::version, argparse::default_arguments::all }; parser.add_argument("-r", "--recording").help("the path of a recorded game used for replay"); parser.add_argument("-f", "--target-fps").help("the number of simulation steps per second").scan<'i', u32>(); @@ -22,7 +27,9 @@ helper::expected helper::parse_args(const std .scan<'i', CommandLineArguments::Level>() .default_value(CommandLineArguments::default_starting_level); parser.add_argument("-s", "--silent").help("disable audio output").default_value(false).implicit_value(true); + try { + parser.parse_args(arguments); CommandLineArguments result{ std::nullopt, std::nullopt }; @@ -63,7 +70,9 @@ helper::expected helper::parse_args(const std result.silent = parser.get("--silent"); return result; + } catch (const std::exception& error) { return helper::unexpected{ error.what() }; } +#endif } diff --git a/src/executables/meson.build b/src/executables/meson.build index 8b67264af..189d999c2 100644 --- a/src/executables/meson.build +++ b/src/executables/meson.build @@ -12,6 +12,7 @@ if build_application 'oopetris', main_files, dependencies: [liboopetris_graphics_dep, graphic_application_deps], + cpp_args: common_cpp_compiler_args, override_options: { 'warning_level': '3', 'werror': true, @@ -132,6 +133,14 @@ if build_application ) endif + elif host_machine.system() == 'uefi' + + _uefi_options = [ + app_name, + main_files, + [liboopetris_graphics_dep, graphic_application_deps], + ] + subdir('platforms/uefi') else error('Unhandled cross built system: ' + host_machine.system()) endif diff --git a/src/executables/platforms/3ds/meson.build b/src/executables/platforms/3ds/meson.build index 33b019e15..2a9e189b5 100644 --- a/src/executables/platforms/3ds/meson.build +++ b/src/executables/platforms/3ds/meson.build @@ -6,7 +6,7 @@ _3ds_deps = _3ds_options[2] # libraries -_3ds_dependencies = ['flac', 'freetype2', 'ogg', 'ogg', 'opus', 'opusfile', 'vorbisidec', 'zlib'] +_3ds_dependencies = ['flac', 'freetype2', 'ogg', 'opus', 'opusfile', 'vorbisidec', 'zlib'] _3ds_dependencies_native = ['bz2', 'ctru', 'mad', 'mikmod', 'modplug', 'png16', 'SDL2main'] diff --git a/src/executables/platforms/uefi/libraries.json b/src/executables/platforms/uefi/libraries.json new file mode 100644 index 000000000..20b185edc --- /dev/null +++ b/src/executables/platforms/uefi/libraries.json @@ -0,0 +1,37 @@ +{ + "custom": { + "sdl2": { + "pkg": "SDL2Pkg", + "lib": "LibSDL2", + "version": "2.32.10" + }, + "sdl2_mixer": { + "pkg": "SDL2MixerPkg", + "lib": "LibSDL2Mixer", + "version": "2.8.2" + } + }, + "uefi": { + "HttpIoLib": { + "pkg": "NetworkPkg/NetworkPkg", + "lib": "HttpIoLib", + "inf": "NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.inf", + "inc": "NetworkPkg/Network.dsc.inc", + "tool_prefix": "edk2" + }, + "HttpLib": { + "pkg": "NetworkPkg/NetworkPkg", + "lib": "HttpLib", + "inf": "NetworkPkg/Library/DxeHttpLib/DxeHttpLib.inf", + "inc": "NetworkPkg/Network.dsc.inc", + "tool_prefix": "edk2" + }, + "BaseCryptLib": { + "pkg": "CryptoPkg/CryptoPkg", + "lib": "BaseCryptLib", + "inf": "CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf", + "inc": null, + "tool_prefix": "edk2" + } + } +} diff --git a/src/executables/platforms/uefi/mappings.json b/src/executables/platforms/uefi/mappings.json new file mode 100644 index 000000000..e30969158 --- /dev/null +++ b/src/executables/platforms/uefi/mappings.json @@ -0,0 +1,124 @@ +{ + "file": { + "OOPetrisPkg": { + "type": "application", + "name": "OOPetrisApplication", + "guid": "da6e059f-d6bd-4136-8f1b-b19c9062f3cd", + "version": "oopetris" + }, + "OOPetrisCorePkg": { + "type": "library", + "name": "OOPetrisCoreLib", + "lib": "LibOOPetrisCore", + "guid": "022bf605-571b-4d01-aeb5-e587e0045d6a", + "version": "oopetris" + }, + "OOPetrisGraphicsPkg": { + "type": "library", + "name": "OOPetrisGraphicsLib", + "lib": "LibOOPetrisGraphics", + "guid": "0bfc59b5-090c-4cd0-a0b7-498dcbed1e6e", + "version": "oopetris" + }, + "OOPetrisRecordingsPkg": { + "type": "library", + "name": "OOPetrisRecordingsLib", + "lib": "LibOOPetrisRecordings", + "guid": "84b90385-bd32-41e3-ba8d-ba4a056d72f5", + "version": "oopetris" + }, + "SDL2TTFPkg": { + "type": "library", + "name": "SDL2TTFLib", + "lib": "LibSDL2TTF", + "guid": "2252bce8-bee1-4ab8-9896-2ab58576e9db", + "version": "sdl2_ttf" + }, + "FreetypePkg": { + "type": "library", + "name": "FreetypeLib", + "lib": "LibFreetype", + "guid": "d6ea8d4f-c8e7-4a8c-988d-e316100b0742", + "version": "freetype2" + }, + "ZLibPkg": { + "type": "library", + "name": "ZLib", + "lib": "LibZ", + "guid": "cc61c805-2419-4b68-b806-495d11be162c", + "version": "zlib" + }, + "UEFIROMPkg": { + "type": "library", + "name": "UEFIROMLib", + "lib": "LibUEFIROM", + "guid": "a917a2c0-7ff6-4da8-a2b2-f1f28077c8c0", + "version": "c-embed" + }, + "SpdlogPkg": { + "type": "library", + "name": "SpdlogLib", + "lib": "LibSpdlog", + "guid": "dee047db-15c9-4d79-ab08-79d6244d9b0e", + "version": "spdlog", + "options": [ + "-DSPDLOG_NO_EXCEPTIONS=1", + "-DSPDLOG_NO_TLS=1", + "-DFMT_USE_INT128=0" + ] + }, + "SDL2ImagePkg": { + "type": "library", + "name": "SDL2ImageLib", + "lib": "LibSDL2Image", + "guid": "80834111-5231-4b9d-b781-381bc4a7ac38", + "version": "sdl2_image", + "options": [ + "-Wno-misleading-indentation", + "-DSTBI_NO_SIMD", + "-Wno-unused-but-set-variable" + ] + } + }, + "name": { + "liboopetris_graphics": { + "name": "OOPetrisGraphicsPkg", + "meson": "oopetris_graphics" + }, + "liboopetris_recordings": { + "name": "OOPetrisRecordingsPkg", + "meson": "oopetris_recordings" + }, + "liboopetris_core": { + "name": "OOPetrisCorePkg", + "meson": "oopetris_core" + }, + "libsdl2_ttf": { + "name": "SDL2TTFPkg", + "meson": "sdl2_ttf" + }, + "libfreetype": { + "name": "FreetypePkg", + "meson": "freetype" + }, + "libz": { + "name": "ZLibPkg", + "meson": "z" + }, + "libspdlog": { + "name": "SpdlogPkg", + "meson": "spdlog" + }, + "oopetris": { + "meson": "oopetris" + }, + "libsdl2image": { + "name": "SDL2ImagePkg", + "meson": "sdl2image" + }, + "libuefi_rom": { + "name": "UEFIROMPkg", + "meson": "uefi_rom" + } + } +} diff --git a/src/executables/platforms/uefi/meson.build b/src/executables/platforms/uefi/meson.build new file mode 100644 index 000000000..568ea9e43 --- /dev/null +++ b/src/executables/platforms/uefi/meson.build @@ -0,0 +1,246 @@ +## get the options object and "unpack" it + +_uefi_exe_name = _uefi_options[0] +_uefi_src_files = _uefi_options[1] +_uefi_deps = _uefi_options[2] + + +APP_ROMFS = meson.get_external_property('APP_ROMFS', '') + +if APP_ROMFS != '' + # create uefi_rom.o and add it as dependency + + fs = import('fs') + + if not fs.is_absolute(APP_ROMFS) + APP_ROMFS = meson.project_source_root() / APP_ROMFS + endif + + if not fs.exists(APP_ROMFS) + error('APP_ROMFS should exist, but doesn\'t: \'' + APP_ROMFS + '\'') + endif + + if not APP_ROMFS.endswith('/') + APP_ROMFS = APP_ROMFS + '/' + endif + + __uefi_c_embed_exe = find_program( + 'c-embed', + required: true, + native: true, + ) + + _uefi_c_embed_wrapper_exe = find_program( + 'c-embed-wrapper.sh', + dirs: [meson.project_source_root() / 'platforms' / 'uefi'], + required: true, + ) + + _uefi_rom_o = custom_target( + 'uefi_rom.o', + command: [ + _uefi_c_embed_wrapper_exe, + __uefi_c_embed_exe, + APP_ROMFS, + '@OUTPUT@', + ], + output: ['uefi_rom.o'], + build_by_default: false, + ) + + _uefi_rom_lib = library( + 'uefi_rom', + sources: _uefi_rom_o, + link_language: 'c', + ) + + _uefi_rom_dep = declare_dependency( + link_with: _uefi_rom_lib + ) + + _uefi_deps += _uefi_rom_dep + + +endif + + +## compilation + +_uefi_final_description = executable( + _uefi_exe_name, + _uefi_src_files, + dependencies: _uefi_deps, + override_options: { + 'warning_level': '3', + 'werror': true, + }, +) + +_uefi_extract_defs_exe = find_program( + 'extract-definitions.sh', + dirs: [meson.project_source_root() / 'platforms' / 'uefi'], + required: true, +) + +_uefi_extract_defs = custom_target( + _uefi_exe_name + '.json', + command: [ + _uefi_extract_defs_exe, + _uefi_final_description, + '@OUTPUT@', + ], + depends: [_uefi_final_description], + output: ['OOPetrisPkg.inf'], + build_by_default: true, +) + + +_uefi_compile_final_exe = find_program( + 'compile-final.sh', + dirs: [meson.project_source_root() / 'platforms' / 'uefi'], + required: true, +) + + +oopetris_efi = custom_target( + _uefi_exe_name + '.efi', + command: [_uefi_compile_final_exe, _uefi_extract_defs, '@OUTPUT@'], + depends: [_uefi_extract_defs], + output: [_uefi_exe_name + '.efi'], + build_by_default: true, +) + +RUNTIME_TARGET = meson.get_external_property('RUNTIME_TARGET', '') + +if RUNTIME_TARGET == 'hardware' + # nothing to do +elif RUNTIME_TARGET == 'emulator' + # add some qemu related targets + _qemu_system_exe = find_program( + 'qemu-system-x86_64', + required: false, + ) + + + if _qemu_system_exe.found() + cat = find_program('cat') + + os_release_info = run_command( + cat, + '/etc/os-release', + check: true, + ).stdout().strip().split('\n') + + linux_distro = '' + + foreach line : os_release_info + line_detail = line.split('=') + + if line_detail[0] == 'ID' + linux_distro = line_detail[1] + endif + + endforeach + + if linux_distro == '' + warning('Couldn\'t detect the linux distro') + OVMF_CODE_fd_path = '/usr/share/OVMF/OVMF_CODE.fd' + OVMF_VARS_fd_path = '/usr/share/OVMF/OVMF_VARS.fd' + elif linux_distro == 'ubuntu' + OVMF_CODE_fd_path = '/usr/share/OVMF/OVMF_CODE_4M.fd' + OVMF_VARS_fd_path = '/usr/share/OVMF/OVMF_VARS_4M.fd' + else + OVMF_CODE_fd_path = '/usr/share/OVMF/OVMF_CODE.fd' + OVMF_VARS_fd_path = '/usr/share/OVMF/OVMF_VARS.fd' + endif + + fs = import('fs') + + + if fs.exists(OVMF_CODE_fd_path) and fs.exists(OVMF_VARS_fd_path) + + _uefi_create_fat_folder_exe = find_program( + 'create-fat-folder.sh', + dirs: [meson.project_source_root() / 'platforms' / 'uefi'], + required: true, + ) + + fat_folder_loc = fs.parent(oopetris_efi.full_path()) / 'FAT_FOLDER' + + serial_debug_file = fs.parent(oopetris_efi.full_path()) / 'serial_debug.log' + + fat_folder = custom_target( + 'fat_folder', + command: [_uefi_create_fat_folder_exe, fat_folder_loc, '@INPUT@', '@OUTPUT@'], + depends: [oopetris_efi], + input: [oopetris_efi], + output: ['FAT_FOLDER_CREATED.meta'], + build_by_default: false, + ) + + user_vars_fd = fs.copyfile( + OVMF_VARS_fd_path, + 'OVMF_VARS.fd', + ) + + emulate_command = [ + _qemu_system_exe, + # this machine supports the tcd timer frequency ACPI getter call + '-machine', + 'q35', + # see https://www.qemu.org/docs/master/system/qemu-cpu-models.html#id1 + # this cpu has x86-64 v1 (baseline) support + '-cpu', + 'qemu64-v1', + '-smp', + 'sockets=1,cores=4,threads=1', + '-drive', + 'if=pflash,format=raw,unit=0,file=' + OVMF_CODE_fd_path + ',readonly=on', + '-drive', + 'if=pflash,format=raw,unit=1,file=' + user_vars_fd.full_path(), + '-drive', + 'format=raw,file=fat:rw:' + fat_folder_loc, + '-net', + 'none', + ] + + if get_option('buildtype') != 'release' + emulate_command += [ + '-debugcon', + 'stdio', + '-global', + 'isa-debugcon.iobase=0x402', + '-serial', + 'file:' + serial_debug_file, + ] + + + use_gdb = ['true', 'True', '1', true].contains( + meson.get_external_property('USE_GDB', '') + ) + + if use_gdb + emulate_command += [ + '-s', + '-S', + ] + endif + + endif + + + + run_target( + 'emulate_efi', + command: emulate_command, + depends: [oopetris_efi, fat_folder], + ) + else + warning('OVMF files couldn\'t be found: target for running efi not created') + endif + else + warning('qemu couldn\'t be found: target for running efi not created') + endif +else + error('RUNTIME_TARGET has invalid value: \'' + RUNTIME_TARGET + '\'') +endif diff --git a/src/executables/utility/command_line_arguments.hpp b/src/executables/utility/command_line_arguments.hpp index 22be1a88d..5fbe23e6b 100644 --- a/src/executables/utility/command_line_arguments.hpp +++ b/src/executables/utility/command_line_arguments.hpp @@ -2,7 +2,10 @@ #include +#if !defined(__UEFI__) #include +#endif + #include #include #include @@ -25,14 +28,14 @@ struct CommandLineArguments final { template - CommandLineArguments(std::filesystem::path&& recording_path, T&& value) - : recording_path{ std::move(recording_path) }, - value{ std::forward(value) } { } + CommandLineArguments(std::filesystem::path&& recording_path_a, T&& value_a) + : recording_path{ std::move(recording_path_a) }, + value{ std::forward(value_a) } { } template - CommandLineArguments(std::filesystem::path&& recording_path, const T& value) - : recording_path{ std::move(recording_path) }, - value{ value } { } + CommandLineArguments(std::filesystem::path&& recording_path_a, const T& value_a) + : recording_path{ std::move(recording_path_a) }, + value{ value_a } { } [[nodiscard]] static helper::expected from_args(int argc, char** argv) noexcept { diff --git a/src/game/command_line_arguments.cpp b/src/game/command_line_arguments.cpp index 48f068aa1..fa8c28206 100644 --- a/src/game/command_line_arguments.cpp +++ b/src/game/command_line_arguments.cpp @@ -5,12 +5,12 @@ CommandLineArguments::CommandLineArguments( - std::optional recording_path, - std::optional target_fps, - Level starting_level, - bool silent + std::optional recording_path_a, + std::optional target_fps_a, + Level starting_level_a, + bool silent_a ) - : recording_path{ std::move(recording_path) }, - target_fps{ target_fps }, - starting_level{ starting_level }, - silent{ silent } { } + : recording_path{ std::move(recording_path_a) }, + target_fps{ target_fps_a }, + starting_level{ starting_level_a }, + silent{ silent_a } { } diff --git a/src/game/command_line_arguments.hpp b/src/game/command_line_arguments.hpp index 2abf44026..14ade19df 100644 --- a/src/game/command_line_arguments.hpp +++ b/src/game/command_line_arguments.hpp @@ -23,9 +23,9 @@ struct CommandLineArguments final { bool silent; OOPETRIS_GRAPHICS_EXPORTED CommandLineArguments( - std::optional recording_path, - std::optional target_fps, - Level starting_level = default_starting_level, - bool silent = default_silent + std::optional recording_path_a, + std::optional target_fps_a, + Level starting_level_a = default_starting_level, + bool silent_a = default_silent ); }; diff --git a/src/game/simulated_tetrion.cpp b/src/game/simulated_tetrion.cpp index 5806bc9c8..7054ece1f 100644 --- a/src/game/simulated_tetrion.cpp +++ b/src/game/simulated_tetrion.cpp @@ -306,12 +306,14 @@ void SimulatedTetrion::clear_fully_occupied_lines() { spdlog::info("new level: {}", m_level); if (level == constants::music_change_level) { if (m_service_provider != nullptr) { - m_service_provider->music_manager() - .load_and_play_music( - utils::get_assets_folder() / "music" - / utils::get_supported_music_extension("03. Game Theme (50 Left)") - ) - .and_then(utils::log_error); + auto _ignore = + m_service_provider->music_manager() + .load_and_play_music( + utils::get_assets_folder() / "music" + / utils::get_supported_music_extension("03. Game Theme (50 Left)") + ) + .and_then(utils::log_error); + UNUSED(_ignore); } } } diff --git a/src/graphics/rect.hpp b/src/graphics/rect.hpp index cf930672b..43ba75e16 100644 --- a/src/graphics/rect.hpp +++ b/src/graphics/rect.hpp @@ -14,9 +14,9 @@ namespace shapes { Point bottom_right; constexpr AbstractRect() = default; - constexpr AbstractRect(Point top_left, Point bottom_right) // NOLINT(bugprone-easily-swappable-parameters) - : top_left{ top_left }, - bottom_right{ bottom_right } { } + constexpr AbstractRect(Point top_left_a, Point bottom_right_a) // NOLINT(bugprone-easily-swappable-parameters) + : top_left{ top_left_a }, + bottom_right{ bottom_right_a } { } constexpr AbstractRect(T x_pos, T y_pos, T width, T height) : top_left{ x_pos, y_pos }, bottom_right{ x_pos + width - 1, y_pos + height - 1 } { } diff --git a/src/graphics/renderer.cpp b/src/graphics/renderer.cpp index 5eb09c8f9..3aa983dac 100644 --- a/src/graphics/renderer.cpp +++ b/src/graphics/renderer.cpp @@ -10,7 +10,7 @@ Renderer::Renderer(const Window& window, const VSync v_sync) window.get_sdl_window(), -1, (v_sync == VSync::Enabled ? SDL_RENDERER_PRESENTVSYNC : 0) | SDL_RENDERER_TARGETTEXTURE -#if defined(__3DS__) || defined(__SERENITY__) +#if defined(__3DS__) || defined(__SERENITY__) || defined(__UEFI__) | SDL_RENDERER_SOFTWARE #else | SDL_RENDERER_ACCELERATED @@ -18,12 +18,15 @@ Renderer::Renderer(const Window& window, const VSync v_sync) ) } { if (m_renderer == nullptr) { - throw helper::InitializationError{ fmt::format("Failed creating a SDL Renderer: {}", SDL_GetError()) }; + utils::throw_(helper::InitializationError{ fmt::format("Failed creating a SDL Renderer: {}", SDL_GetError()) }); } auto result = SDL_SetRenderDrawBlendMode(m_renderer, SDL_BLENDMODE_BLEND); if (result < 0) { - throw helper::InitializationError{ fmt::format("Failed in setting BlendMode on Renderer: {}", SDL_GetError()) }; + utils::throw_( + helper::InitializationError{ + fmt::format("Failed in setting BlendMode on Renderer: {}", SDL_GetError()) } + ); } } @@ -65,7 +68,7 @@ Texture Renderer::get_texture_for_render_target(const shapes::UPoint& size) cons const auto supported = SDL_RenderTargetSupported(m_renderer); if (supported == SDL_FALSE) { - throw helper::FatalError{ "SDL does not support a target renderer, but we need one!" }; + utils::throw_(helper::FatalError{ "SDL does not support a target renderer, but we need one!" }); } return Texture::get_for_render_target(m_renderer, size); @@ -79,7 +82,9 @@ void Renderer::set_render_target(const Texture& texture) const { void Renderer::reset_render_target() const { const auto result = SDL_SetRenderTarget(m_renderer, nullptr); if (result < 0) { - throw helper::FatalError{ fmt::format("Failed to set render texture target with error: {}", SDL_GetError()) }; + utils::throw_( + helper::FatalError{ fmt::format("Failed to set render texture target with error: {}", SDL_GetError()) } + ); } } diff --git a/src/graphics/sdl_context.cpp b/src/graphics/sdl_context.cpp index e0c426f1d..3a4d8b39c 100644 --- a/src/graphics/sdl_context.cpp +++ b/src/graphics/sdl_context.cpp @@ -1,4 +1,5 @@ #include +#include #include "graphics/sdl_context.hpp" @@ -8,6 +9,8 @@ #if defined(__CONSOLE__) #include "helper/console_helpers.hpp" +#elif defined(__UEFI__) +#include "helper/uefi_utils.hpp" #endif #if defined(_HAVE_FILE_DIALOGS) @@ -18,22 +21,25 @@ SdlContext::SdlContext() { if (SDL_Init(SDL_INIT_VIDEO) < 0) { - throw helper::InitializationError{ fmt::format("Failed in initializing sdl: {}", SDL_GetError()) }; + utils::throw_(helper::InitializationError{ fmt::format("Failed in initializing sdl: {}", SDL_GetError()) }); } if (TTF_Init() < 0) { - throw helper::InitializationError{ fmt::format("Failed in initializing sdl ttf: {}", TTF_GetError()) }; + utils::throw_(helper::InitializationError{ fmt::format("Failed in initializing sdl ttf: {}", TTF_GetError()) }); } #if defined(__CONSOLE__) console::platform_init(); +#elif defined(__UEFI__) + uefi::platform_init(); #endif #if defined(_HAVE_FILE_DIALOGS) if (NFD::Init() != NFD_OKAY) { - throw helper::InitializationError{ - fmt::format("Failed to initialize the file dialog library: {}", NFD::GetError()) - }; + utils::throw_( + helper::InitializationError{ + fmt::format("Failed to initialize the file dialog library: {}", NFD::GetError()) } + ); } #endif @@ -47,6 +53,8 @@ SdlContext::~SdlContext() { #if defined(__CONSOLE__) console::platform_exit(); +#elif defined(__UEFI__) + uefi::platform_exit(); #endif TTF_Quit(); diff --git a/src/graphics/texture.cpp b/src/graphics/texture.cpp index 40f15e885..3b9e64dea 100644 --- a/src/graphics/texture.cpp +++ b/src/graphics/texture.cpp @@ -10,8 +10,13 @@ Texture Texture::from_image(SDL_Renderer* renderer, const std::filesystem::path& SDL_Texture* image = IMG_LoadTexture(renderer, image_path.string().c_str()); if (image == nullptr) { - throw std::runtime_error( - fmt::format("Failed to load image from path '{}' with error: {}", image_path.string(), SDL_GetError()) + utils::throw_( + std::runtime_error( + fmt::format( + "Failed to load image from path '{}' with error: {}", image_path.string(), + SDL_GetError() + ) + ) ); } return Texture{ image }; @@ -40,13 +45,17 @@ Texture Texture::prerender_text( UNREACHABLE(); } if (surface == nullptr) { - throw std::runtime_error(fmt::format("Failed to pre-render text into surface with error: {}", SDL_GetError())); + utils::throw_( + std::runtime_error(fmt::format("Failed to pre-render text into surface with error: {}", SDL_GetError())) + ); } SDL_Texture* const texture = SDL_CreateTextureFromSurface(renderer, surface); SDL_FreeSurface(surface); if (texture == nullptr) { - throw std::runtime_error(fmt::format("Failed to pre-render text into texture with error: {}", SDL_GetError())); + utils::throw_( + std::runtime_error(fmt::format("Failed to pre-render text into texture with error: {}", SDL_GetError())) + ); } @@ -58,19 +67,19 @@ Texture Texture::get_for_render_target(SDL_Renderer* renderer, const shapes::UPo SDL_DisplayMode mode{}; const int result = SDL_GetCurrentDisplayMode(0, &mode); if (result != 0) { - throw std::runtime_error{ "failed in getting display mode: " + std::string{ SDL_GetError() } }; + utils::throw_(std::runtime_error{ "failed in getting display mode: " + std::string{ SDL_GetError() } }); } auto* const texture = SDL_CreateTexture( renderer, mode.format, SDL_TEXTUREACCESS_TARGET, static_cast(size.x), static_cast(size.y) ); if (texture == nullptr) { - throw std::runtime_error(fmt::format("Failed to create texture with error: {}", SDL_GetError())); + utils::throw_(std::runtime_error(fmt::format("Failed to create texture with error: {}", SDL_GetError()))); } const auto target_result = SDL_SetRenderTarget(renderer, texture); if (target_result < 0) { - throw std::runtime_error(fmt::format("Failed to set render target with error: {}", SDL_GetError())); + utils::throw_(std::runtime_error(fmt::format("Failed to set render target with error: {}", SDL_GetError()))); } @@ -113,6 +122,8 @@ Texture::~Texture() { void Texture::set_as_render_target(SDL_Renderer* renderer) const { const auto result = SDL_SetRenderTarget(renderer, m_raw_texture); if (result < 0) { - throw std::runtime_error(fmt::format("Failed to set render texture target with error: {}", SDL_GetError())); + utils::throw_( + std::runtime_error(fmt::format("Failed to set render texture target with error: {}", SDL_GetError())) + ); } } diff --git a/src/graphics/window.cpp b/src/graphics/window.cpp index 72d8368f0..20a98b451 100644 --- a/src/graphics/window.cpp +++ b/src/graphics/window.cpp @@ -3,6 +3,8 @@ #include #include +#include + Window::Window(const std::string& title, WindowPosition position, u32 width, u32 height) : Window{ title, static_cast(position), static_cast(position), width, height } { } @@ -24,11 +26,11 @@ Window::Window(const std::string& title, u32 x_pos, u32 y_pos) { SDL_DisplayMode mode{}; const int result = SDL_GetCurrentDisplayMode(0, &mode); if (result != 0) { - throw std::runtime_error{ "failed in getting display mode: " + std::string{ SDL_GetError() } }; + utils::throw_(std::runtime_error{ "failed in getting display mode: " + std::string{ SDL_GetError() } }); } m_window = SDL_CreateWindow(title.c_str(), static_cast(x_pos), static_cast(y_pos), mode.w, mode.h, 0); if (m_window == nullptr) { - throw std::runtime_error{ "failed in creating window: " + std::string{ SDL_GetError() } }; + utils::throw_(std::runtime_error{ "failed in creating window: " + std::string{ SDL_GetError() } }); } } diff --git a/src/helper/clock_source.cpp b/src/helper/clock_source.cpp index 6c329f1b2..986b197d7 100644 --- a/src/helper/clock_source.cpp +++ b/src/helper/clock_source.cpp @@ -29,7 +29,7 @@ bool LocalClock::can_be_paused() { void LocalClock::pause() { if (m_paused_at) { - throw std::runtime_error("cannot pause if already paused"); + utils::throw_(std::runtime_error("cannot pause if already paused")); } m_paused_at = elapsed_time(); spdlog::info("pausing clock"); @@ -37,7 +37,7 @@ void LocalClock::pause() { double LocalClock::resume() { if (not m_paused_at) { - throw std::runtime_error("must have been paused before to be able to resume"); + utils::throw_(std::runtime_error("must have been paused before to be able to resume")); } const auto duration = elapsed_time() - *m_paused_at; m_start_time += duration; diff --git a/src/helper/clock_source.hpp b/src/helper/clock_source.hpp index d00d98359..2085378a2 100644 --- a/src/helper/clock_source.hpp +++ b/src/helper/clock_source.hpp @@ -2,6 +2,7 @@ #include +#include #include "./export_symbols.hpp" @@ -15,7 +16,7 @@ struct ClockSource { [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED virtual bool can_be_paused() = 0; OOPETRIS_GRAPHICS_EXPORTED virtual void pause() { - throw std::runtime_error("not implemented"); + utils::throw_(std::runtime_error("not implemented")); } /** @@ -23,7 +24,7 @@ struct ClockSource { * @return The duration of the pause. */ OOPETRIS_GRAPHICS_EXPORTED virtual double resume() { - throw std::runtime_error("not implemented"); + utils::throw_(std::runtime_error("not implemented")); }; }; diff --git a/src/helper/console_helpers.cpp b/src/helper/console_helpers.cpp index c804a0acf..48e96ea99 100644 --- a/src/helper/console_helpers.cpp +++ b/src/helper/console_helpers.cpp @@ -1,7 +1,9 @@ #include -#if defined(__NINTENDO_CONSOLE__) +#if !defined(__NINTENDO_CONSOLE__) +#error "only supported on consoles" +#endif #include "console_helpers.hpp" @@ -84,6 +86,3 @@ bool console::inMainLoop() { #error "not implemented" #endif } - - -#endif diff --git a/src/helper/console_helpers.hpp b/src/helper/console_helpers.hpp index 96e53d645..511a33d96 100644 --- a/src/helper/console_helpers.hpp +++ b/src/helper/console_helpers.hpp @@ -2,7 +2,9 @@ #pragma once -#if defined(__CONSOLE__) +#if !defined(__CONSOLE__) +#error "Only supported on consoles" +#endif #include @@ -65,6 +67,3 @@ namespace console { } // namespace console - - -#endif diff --git a/src/helper/graphic_utils.cpp b/src/helper/graphic_utils.cpp index 9debe74c8..a0a0ba31f 100644 --- a/src/helper/graphic_utils.cpp +++ b/src/helper/graphic_utils.cpp @@ -42,6 +42,10 @@ std::vector utils::supported_features() { return std::filesystem::path{ std::string{ pref_path } }; #elif defined(__EMSCRIPTEN__) return std::filesystem::path{ "/" }; +#elif defined(__UEFI__) + //TODO: can i have writable file systems in uefi? + //NOTE: UEFI has no writable filesystems, so just use "." and than open calls fail + return std::filesystem::path{ "." }; #elif defined(__CONSOLE__) // this is in the sdcard of the switch / 3ds , since internal storage is read-only for applications! return std::filesystem::path{ "." }; @@ -103,8 +107,11 @@ std::vector utils::supported_features() { #if defined(__ANDROID__) return std::filesystem::path{ "" }; #elif defined(__EMSCRIPTEN__) - // emscripten mounts a memfs in the / location, we package assest into this dir, see: https://emscripten.org/docs/porting/files/packaging_files.html#packaging-using-emcc + // emscripten mounts a memfs in the / location, we package assets into this dir, see: https://emscripten.org/docs/porting/files/packaging_files.html#packaging-using-emcc return std::filesystem::path{ "/assets" }; +#elif defined(__UEFI__) + // this is a embedded read only file system, created by c-embed and mounted by edk2-libc and our layer above that (fuse like) + return std::filesystem::path{ "romfs:/assets" }; #elif defined(__CONSOLE__) // this is in the internal storage of the nintendo switch, it is mounted by libnx (runtime switch support library) and filled at compile time with assets (its called ROMFS there) return std::filesystem::path{ "romfs:/assets" }; @@ -163,7 +170,9 @@ std::optional utils::create_directory(const std::filesystem::path& return std::nullopt; } +#if !defined(__OOPETRIS_NO_EXCEPTIONS) try { +#endif if (recursive) { auto result = std::filesystem::create_directories(folder); if (not result) { @@ -178,9 +187,11 @@ std::optional utils::create_directory(const std::filesystem::path& return "an unknown error occurred"; } return std::nullopt; +#if !defined(__OOPETRIS_NO_EXCEPTIONS) } catch (const std::exception& error) { return error.what(); } +#endif } void utils::exit(int status_code) { diff --git a/src/helper/meson.build b/src/helper/meson.build index 49f745a00..5a0bdc4fc 100644 --- a/src/helper/meson.build +++ b/src/helper/meson.build @@ -1,8 +1,6 @@ graphics_src_files += files( 'clock_source.cpp', 'clock_source.hpp', - 'console_helpers.cpp', - 'console_helpers.hpp', 'constants.hpp', 'export_symbols.hpp', 'git_helper.hpp', @@ -14,10 +12,33 @@ graphics_src_files += files( 'platform.cpp', 'platform.hpp', 'spdlog_wrapper.hpp', - 'web_utils.cpp', - 'web_utils.hpp', ) +if meson.is_cross_build() and host_machine.system() == 'uefi' + graphics_src_files += files( + 'uefi_futures.cpp', + 'uefi_futures.hpp', + 'uefi_utils.cpp', + 'uefi_utils.hpp', + ) +elif meson.is_cross_build() and host_machine.system() == 'emscripten' + graphics_src_files += files( + 'web_utils.cpp', + 'web_utils.hpp', + ) +elif meson.is_cross_build() and ( + host_machine.system() == '3ds' + or host_machine.system() == 'switch' +) + graphics_src_files += files( + 'console_helpers.cpp', + 'console_helpers.hpp', + ) + +endif + + + if have_file_dialogs graphics_src_files += files('nfd.cpp', 'nfd_include.hpp') endif diff --git a/src/helper/message_box.cpp b/src/helper/message_box.cpp index d1277ef0b..d06b971cc 100644 --- a/src/helper/message_box.cpp +++ b/src/helper/message_box.cpp @@ -1,6 +1,8 @@ #include "message_box.hpp" +#include + #include #include @@ -17,6 +19,6 @@ void helper::MessageBox::show_simple( const int result = SDL_ShowSimpleMessageBox(flags, title.c_str(), content.c_str(), window); if (result < 0) { - throw std::runtime_error{ fmt::format("Failed to show Simple MessageBox: {}", SDL_GetError()) }; + utils::throw_(std::runtime_error{ fmt::format("Failed to show Simple MessageBox: {}", SDL_GetError()) }); } } diff --git a/src/helper/nfd_include.hpp b/src/helper/nfd_include.hpp index 417b9ec3c..c4d5a6330 100644 --- a/src/helper/nfd_include.hpp +++ b/src/helper/nfd_include.hpp @@ -10,8 +10,21 @@ #ifdef _WIN32 #define NFD_DIFFERENT_NATIVE_FUNCTIONS #endif + + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wundef" + +#endif + #include +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + + #include #include #include diff --git a/src/helper/platform.cpp b/src/helper/platform.cpp index 3b70f7dd3..38e8b0b9e 100644 --- a/src/helper/platform.cpp +++ b/src/helper/platform.cpp @@ -49,6 +49,8 @@ namespace { return "Nintendo Switch"; #elif defined(__3DS__) return "Nintendo 3DS"; +#elif defined(__UEFI__) + return "UEFI"; #elif defined(FLATPAK_BUILD) return "Linux (Flatpak)"; #elif defined(__linux__) @@ -76,7 +78,9 @@ namespace { } return true; - +#elif defined(__UEFI__) + UNUSED(url); + return false; #elif defined(__CONSOLE__) auto result = console::open_url(url); spdlog::info("Returned string from url open was: {}", result); diff --git a/src/helper/uefi_futures.cpp b/src/helper/uefi_futures.cpp new file mode 100644 index 000000000..0c74535d4 --- /dev/null +++ b/src/helper/uefi_futures.cpp @@ -0,0 +1,301 @@ +#include "./uefi_futures.hpp" + + +extern "C" { +#include +#include +#include +} + +details::MainCPUState* details::__cpu_state = nullptr; + + +static UINTN my_cpu_id_impl(EFI_MP_SERVICES_PROTOCOL* Mp) { + + ASSERT(Mp); + + UINTN BspNumber; + + EFI_STATUS Status = Mp->WhoAmI(Mp, &BspNumber); + + if (EFI_ERROR(Status)) { + EFI_DEBUG((DEBUG_ERROR, "ERROR: couldn't execute WhoAmI: %r\n", Status)); + abort(); + } + + return BspNumber; +} + + +UINTN details::my_cpu_id() { + ASSERT(__cpu_state != nullptr); + return my_cpu_id_impl(__cpu_state->Mp); +} + + +void details::init_cpu_state() { + if (__cpu_state != nullptr) { + return; + } + + __cpu_state = new details::MainCPUState(nullptr, 0, 0, {}); + + + if (!gBS) { + EFI_DEBUG((DEBUG_ERROR, "ERROR: gBS is NULL\n")); + abort(); + } + + + EFI_STATUS Status = gBS->LocateProtocol(&gEfiMpServiceProtocolGuid, NULL, (VOID**) &(__cpu_state->Mp)); + + if (EFI_ERROR(Status)) { + EFI_DEBUG((DEBUG_ERROR, "ERROR: couldn't get the EfiMpServiceProtocolGuid: %r\n", Status)); + abort(); + } + + UINTN NumberOfEnabledProcessors; + + Status = __cpu_state->Mp->GetNumberOfProcessors( + __cpu_state->Mp, &(__cpu_state->NumberOfProcessors), &NumberOfEnabledProcessors + ); + + if (EFI_ERROR(Status)) { + EFI_DEBUG((DEBUG_ERROR, "ERROR: couldn't get the Number Of Processors: %r\n", Status)); + abort(); + } + + __cpu_state->BspId = my_cpu_id_impl(__cpu_state->Mp); + + __cpu_state->cpus = std::vector{}; + __cpu_state->cpus.reserve(__cpu_state->NumberOfProcessors - 1); + + for (size_t i = 0; i < __cpu_state->NumberOfProcessors; ++i) { + + EFI_PROCESSOR_INFORMATION info; + + Status = __cpu_state->Mp->GetProcessorInfo(__cpu_state->Mp, (UINTN) i, &info); + + if (EFI_ERROR(Status)) { + EFI_DEBUG((DEBUG_ERROR, "ERROR: couldn't Get Processor Info: %r\n", Status)); + abort(); + } + + if ((info.StatusFlag & PROCESSOR_AS_BSP_BIT) != 0) { + continue; + } + + __cpu_state->cpus.emplace_back(info.ProcessorId, (UINTN) i, info.StatusFlag, false); + } +} + + +static __attribute__((destructor)) void deinit_cpu_state(void) { + if (details::__cpu_state == nullptr) { + return; + } + + delete details::__cpu_state; +} + + +details::SecondaryCPUState* find_cpu_for_new_thread_impl(details::MainCPUState* const state) { + + ASSERT(state); + + for (size_t i = 0; i < state->cpus.size(); i++) { + details::SecondaryCPUState* cpu = &(state->cpus.data()[i]); + + if (cpu->IsBusy) { + continue; + } + + if ((cpu->StatusFlags & PROCESSOR_ENABLED_BIT) == 0) { + continue; + } + + if ((cpu->StatusFlags & PROCESSOR_HEALTH_STATUS_BIT) == 0) { + continue; + } + + return cpu; + } + + return nullptr; +} + + +details::SecondaryCPUState* details::find_cpu_for_new_thread(void) { + + ASSERT(__cpu_state != nullptr); + return find_cpu_for_new_thread_impl(__cpu_state); +} + +static void EFIAPI __impl_uefi_new_thread_function(IN OUT VOID* private_data) { + details::ThreadInfo* ptr = static_cast(private_data); + + ptr->info.fn(); +} + + +struct details::DetachedThreadStateImpl { + // inout state + EFI_EVENT DoneEvent; + BOOLEAN finished; + //output state + bool terminated; + + // mutex to protect state, that can be used by the AP (when writing the result) and the BSP (when using poll) + details::helper::ThreadMutex data_mutex; + + DetachedThreadStateImpl() : DoneEvent{}, finished{ FALSE }, terminated{ false }, data_mutex{} { + // + } + + void terminate(void) { + const std::lock_guard scope_lock(this->data_mutex); + + this->terminated = true; + } + + details::thread_state poll(void) { + const std::lock_guard scope_lock(this->data_mutex); + + // likely for long running async + if (!this->terminated) [[likely]] { + return details::thread_state::running; + } + + // unlikely, as we don't set a timeout + if (!this->finished) [[unlikely]] { + return details::thread_state::aborted; + } + + return details::thread_state::finished; + } + + ~DetachedThreadStateImpl() noexcept { + gBS->CloseEvent(DoneEvent); + } +}; + +details::DetachedThreadStatePublic::DetachedThreadStatePublic(DetachedThreadState* state_impl) + : m_state_impl{ state_impl } { + // +} + +details::DetachedThreadStatePublic::~DetachedThreadStatePublic() { + if (m_state_impl != nullptr) { + delete m_state_impl; + m_state_impl = nullptr; + } +} + +details::thread_state details::DetachedThreadStatePublic::poll() { + ASSERT(m_state_impl != nullptr); + return m_state_impl->poll(); +} + + +static VOID EFIAPI __impl_uefi_thread_done_function(IN EFI_EVENT Event, IN VOID* Context) { + details::DetachedThreadStateImpl* state = static_cast(Context); + + state->terminate(); +} + + +std::shared_ptr start_detached_thread_impl( + EFI_MP_SERVICES_PROTOCOL* Mp, + const details::SecondaryCPUState* const cpu_to_execute_on, + const std::shared_ptr& info +) { + + ASSERT(Mp != nullptr); + ASSERT(cpu_to_execute_on != nullptr); + + details::DetachedThreadStateImpl* state = new details::DetachedThreadStateImpl(); + + EFI_STATUS Status = gBS->CreateEvent( + EVT_NOTIFY_SIGNAL, TPL_CALLBACK, __impl_uefi_thread_done_function, state, &(state->DoneEvent) + ); + + if (EFI_ERROR(Status)) { + EFI_DEBUG((DEBUG_ERROR, "ERROR: couldn't execute CreateEvent: %r\n", Status)); + abort(); + } + + + Status = Mp->StartupThisAP( + Mp, __impl_uefi_new_thread_function, cpu_to_execute_on->Id, state->DoneEvent, 0, info.get(), + &(state->finished) + ); + + + if (EFI_ERROR(Status)) { + EFI_DEBUG((DEBUG_ERROR, "ERROR: couldn't execute StartupThisAP: %r\n", Status)); + abort(); + } + + std::shared_ptr public_state = + std::make_shared(state); + + return public_state; +} + + +std::shared_ptr details::start_detached_thread( + const details::SecondaryCPUState* const cpu_to_execute_on, + const std::shared_ptr& info +) { + + ASSERT(__cpu_state != nullptr); + return start_detached_thread_impl(__cpu_state->Mp, cpu_to_execute_on, info); +} + + +details::helper::ThreadMutex::ThreadMutex() noexcept : locked{ 0 } { + // +} + +details::helper::ThreadMutex::ThreadMutex(ThreadMutex&& other) noexcept : locked{ 0 } { + ASSERT(!other.locked); + + other.locked = 0; +} + +details::helper::ThreadMutex& details::helper::ThreadMutex::operator=(ThreadMutex&& other) noexcept { + ASSERT(!other.locked); + + this->locked = other.locked; + other.locked = 0; + + return *this; +} + +details::helper::ThreadMutex::~ThreadMutex() noexcept { + ASSERT(!this->locked); +} + + +void details::helper::ThreadMutex::lock() { + while (InterlockedCompareExchange32( + &(this->locked), + 0, // Compare: unlocked + 1 // Exchange: locked + ) + != 0) { + // + // Someone else owns it. + // + CpuPause(); + } +} + +void details::helper::ThreadMutex::unlock() { + + InterlockedCompareExchange32( + &(this->locked), + 1, // Compare: locked + 0 // Exchange: unlocked + ); +} diff --git a/src/helper/uefi_futures.hpp b/src/helper/uefi_futures.hpp new file mode 100644 index 000000000..858d4575d --- /dev/null +++ b/src/helper/uefi_futures.hpp @@ -0,0 +1,283 @@ + + +#pragma once + + +#if !defined(__UEFI__) +#error "this header is for uefi only" +#endif + + +#include + +extern "C" { +#include + +#include + +#include +} + +#include +#include +#include +#include +#include +#include + + +//COPY from oopetris, to make this header more independent +namespace helper::uefi::future { + + template + struct Overloaded : Ts... { + using Ts::operator()...; + }; + template + Overloaded(Ts...) -> Overloaded; +} // namespace helper::uefi::future + + +namespace details { + + struct SecondaryCPUState { + UINT64 UniqueProcessorId; + UINTN Id; + UINT32 StatusFlags; + bool IsBusy; + }; + + struct MainCPUState { + EFI_MP_SERVICES_PROTOCOL* Mp; + UINTN NumberOfProcessors; + UINTN BspId; + std::vector cpus; + }; + + extern MainCPUState* __cpu_state; + + void init_cpu_state(); + + [[nodiscard]] UINTN my_cpu_id(); + + + [[nodiscard]] SecondaryCPUState* find_cpu_for_new_thread(); + + struct RunningFunctionInfo { + //TODO: use generic fn pointer; + std::function fn; + //TODO: support arguments + // void args; + }; + + struct SignalState { + __sighandler_t* old_sig_handler; + jmp_buf jump_state; + }; + + struct ThreadInfo { + RunningFunctionInfo info; + SignalState state; + }; + + enum class thread_state { aborted, running, finished }; + + typedef struct DetachedThreadStateImpl DetachedThreadState; + + + struct DetachedThreadStatePublic { + private: + DetachedThreadState* m_state_impl; + + public: + DetachedThreadStatePublic(DetachedThreadState* state_impl); + + ~DetachedThreadStatePublic(); + + [[nodiscard]] thread_state poll(); + }; + + std::shared_ptr + start_detached_thread(const SecondaryCPUState* const cpu_to_execute_on, const std::shared_ptr& info); + + namespace helper { + + //TODO: we could use a c++ wrapper of the SPIN_LOCK from "SynchronizationLib.h" instead + struct ThreadMutex { + private: + volatile UINT32 locked; + + public: + ThreadMutex() noexcept; + + ThreadMutex(const ThreadMutex& other) = delete; + ThreadMutex& operator=(const ThreadMutex& other) = delete; + + ThreadMutex(ThreadMutex&& other) noexcept; + ThreadMutex& operator=(ThreadMutex&& other) noexcept; + + ~ThreadMutex() noexcept; + + void lock(); + void unlock(); + }; + + } // namespace helper + + +} // namespace details + + +namespace uefi::helper { + + enum class future_status { ready, timeout, error }; + + template + //TODO: only allow void! + class future { + private: + struct ErrorState { + std::string error; + }; + + struct FinishedState { + std::conditional_t, std::monostate, T> value; + }; + + struct RunningState { + details::SecondaryCPUState* cpu; + std::shared_ptr info; + std::shared_ptr thread; + }; + + mutable std::variant m_state; + // + + void __internal_poll(void) const { + std::optional> new_value = std::visit( + ::helper::uefi::future::Overloaded{ + [this](const RunningState& state) + -> std::optional> { + auto thread_st = state.thread->poll(); + + switch (thread_st) { + case details::thread_state::running: + return std::nullopt; + + case details::thread_state::finished: { + //TODO: how to get the value + return FinishedState{}; + } + case details::thread_state::aborted: + default: { + //TODO: get the error from somewhere + return ErrorState{ "TODO" }; + } + } + }, + [this](const ErrorState& state) + -> std::optional> { + return std::nullopt; + }, + [this](const FinishedState& state) + -> std::optional> { + return std::nullopt; + }, + + }, + this->m_state + ); + + if (new_value.has_value()) { + this->m_state = std::move(new_value.value()); + } + } + + public: + future(details::SecondaryCPUState* const cpu, + std::shared_ptr&& info, + std::shared_ptr&& thread) + : m_state{ + RunningState{ cpu, std::move(info), std::move(thread) } + } { + // + } + + template + [[nodiscard]] future_status wait_until(const std::chrono::time_point<_Clock, _Duration>& __abs_time) const { + + //TODO: implement other wait too, but we only use this atm + if (__abs_time != std::chrono::system_clock::time_point::min()) { + spdlog::error("Invalid abs_time for wait_until: {}", __abs_time); + abort(); + } + + this->__internal_poll(); + + + return std::visit( + ::helper::uefi::future::Overloaded{ + [this](const RunningState& state) -> future_status { return future_status::timeout; }, + [this](const ErrorState& state) -> future_status { return future_status::error; }, + [this](const FinishedState& state) -> future_status { return future_status::ready; }, + + }, + this->m_state + ); + } + }; + + using async_launch_type = std::monostate; + + + //NOTE: that all calls in this thread are NOT THREAD SAFE, but it should be fine(tm), as we don't use many services at a time anyway + template + [[nodiscard]] future, std::decay_t...>> + async(async_launch_type launch_type, F&& f, Args&&... args) { + + // NOTE: atm only implemented for this, so we don't have to pass arguments ore set the result value + static_assert(sizeof...(Args) == 0, "the function inside async() doesn't support arguments yet"); + + static_assert( + std::is_void_v, std::decay_t...>>, + "the function inside async() doesn't support a non void return type" + ); + + details::init_cpu_state(); + + ASSERT(details::__cpu_state != nullptr); + auto my_id = details::my_cpu_id(); + if (details::__cpu_state->BspId != my_id) { + spdlog::error("Invalid start of async in non main CPU: {} != {}", details::__cpu_state->BspId, my_id); + abort(); + } + + // need no lock, as only the bsp can do that, and it is single threaded + details::SecondaryCPUState* const cpu_to_execute_on = details::find_cpu_for_new_thread(); + + if (cpu_to_execute_on == nullptr) { + spdlog::error("Can't find CPU to start thread on", details::__cpu_state->BspId, my_id); + abort(); + } + + details::RunningFunctionInfo fn_info = { f }; + + //TODO: this is global, so just reset it once, so when old_sig_handler == __impl_sigabrt_handler, don't add it, have one global old handler + __sighandler_t* old_sig_handler = signal(SIGABRT, __impl_sigabrt_handler); + + //TODO: inline this in start_detached_thread + + SignalState state = { + old_sig_handler = old_sig_handler, + jmp_buf jump_state, + }; + + std::shared_ptr info = std::make_shared(fn_info, state); + + + auto thread = details::start_detached_thread(cpu_to_execute_on, info); + + return future, std::decay_t...>>{ cpu_to_execute_on, std::move(info), + std::move(thread) }; + } +}; // namespace uefi::helper diff --git a/src/helper/uefi_utils.cpp b/src/helper/uefi_utils.cpp new file mode 100644 index 000000000..77c46991c --- /dev/null +++ b/src/helper/uefi_utils.cpp @@ -0,0 +1,489 @@ + + +#if !defined(__UEFI__) +#error "Only supported on UEFI" +#endif + +#include + +#include "./uefi_utils.hpp" + +#include +#include + + +std::shared_ptr uefi::get_debug_sink() { + return std::make_shared([](const spdlog::details::log_msg& msg) { + const std::string message = std::string{ msg.payload.begin(), msg.payload.end() }; + + + switch (msg.level) { + case spdlog::level::off: + return; + case spdlog::level::trace: + case spdlog::level::debug: + EFI_DEBUG((DEBUG_VERBOSE, "%a\n", message.c_str())); + break; + case spdlog::level::info: + EFI_DEBUG((DEBUG_INFO, "%a\n", message.c_str())); + break; + case spdlog::level::warn: + EFI_DEBUG((DEBUG_WARN, "%a\n", message.c_str())); + break; + case spdlog::level::err: + case spdlog::level::critical: + EFI_DEBUG((DEBUG_ERROR, "%a\n", message.c_str())); + break; + default: + return; + } + }); +} + + +[[nodiscard]] std::string uefi::map_efi_status_to_string(EFI_STATUS status) { + + switch (status) { + case EFI_SUCCESS: + return "SUCCESS"; + case EFI_LOAD_ERROR: + return "LOAD_ERROR"; + case EFI_INVALID_PARAMETER: + return "INVALID_PARAMETER"; + case EFI_UNSUPPORTED: + return "UNSUPPORTED"; + case EFI_BAD_BUFFER_SIZE: + return "BAD_BUFFER_SIZE"; + case EFI_BUFFER_TOO_SMALL: + return "BUFFER_TOO_SMALL"; + case EFI_NOT_READY: + return "NOT_READY"; + case EFI_DEVICE_ERROR: + return "DEVICE_ERROR"; + case EFI_WRITE_PROTECTED: + return "WRITE_PROTECTED"; + case EFI_OUT_OF_RESOURCES: + return "OUT_OF_RESOURCES"; + case EFI_VOLUME_CORRUPTED: + return "VOLUME_CORRUPTED"; + case EFI_VOLUME_FULL: + return "VOLUME_FULL"; + case EFI_NO_MEDIA: + return "NO_MEDIA"; + case EFI_MEDIA_CHANGED: + return "MEDIA_CHANGED"; + case EFI_NOT_FOUND: + return "NOT_FOUND"; + case EFI_ACCESS_DENIED: + return "ACCESS_DENIED"; + case EFI_NO_RESPONSE: + return "NO_RESPONSE"; + case EFI_NO_MAPPING: + return "NO_MAPPING"; + case EFI_TIMEOUT: + return "TIMEOUT"; + case EFI_NOT_STARTED: + return "NOT_STARTED"; + case EFI_ALREADY_STARTED: + return "ALREADY_STARTED"; + case EFI_ABORTED: + return "ABORTED"; + case EFI_ICMP_ERROR: + return "ICMP_ERROR"; + case EFI_TFTP_ERROR: + return "TFTP_ERROR"; + case EFI_PROTOCOL_ERROR: + return "PROTOCOL_ERROR"; + case EFI_INCOMPATIBLE_VERSION: + return "INCOMPATIBLE_VERSION"; + case EFI_SECURITY_VIOLATION: + return "SECURITY_VIOLATION"; + case EFI_CRC_ERROR: + return "CRC_ERROR"; + case EFI_END_OF_MEDIA: + return "END_OF_MEDIA"; + case EFI_END_OF_FILE: + return "END_OF_FILE"; + case EFI_INVALID_LANGUAGE: + return "INVALID_LANGUAGE"; + case EFI_COMPROMISED_DATA: + return "COMPROMISED_DATA"; + case EFI_IP_ADDRESS_CONFLICT: + return "IP_ADDRESS_CONFLICT"; + case EFI_HTTP_ERROR: + return "HTTP_ERROR"; + case EFI_WARN_UNKNOWN_GLYPH: + return "WARN_UNKNOWN_GLYPH"; + case EFI_WARN_DELETE_FAILURE: + return "WARN_DELETE_FAILURE"; + case EFI_WARN_WRITE_FAILURE: + return "WARN_WRITE_FAILURE"; + case EFI_WARN_BUFFER_TOO_SMALL: + return "WARN_BUFFER_TOO_SMALL"; + case EFI_WARN_STALE_DATA: + return "WARN_STALE_DATA"; + case EFI_WARN_FILE_SYSTEM: + return "WARN_FILE_SYSTEM"; + case EFI_WARN_RESET_REQUIRED: + return "WARN_RESET_REQUIRED"; + default: + return ""; + } +} + +extern "C" { + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" + +#define rewind erewind +#include +#undef rewind + +#pragma GCC diagnostic pop + +#include +#include +#include + +// use stdlib internals, to register a new rom device under romfs: +#include + +#include +} + +#define ROM_COOKIE 0x464d4f52 ///< 'RomF' + + +/** EFI specific operations for close(). + + @param[in] Fp Pointer to a file descriptor structure. + + @retval 0 Successful completion. + @retval -1 Operation failed. Further information is specified by errno. +**/ +static int EFIAPI _f_romfs_Close(IN struct __filedes* Fp) { + eclose((EFILE*) (&Fp->devdata)); + return 0; +} + +/** EFI specific operations for deleting a file or directory. + + @param[in] filp Pointer to a file descriptor structure. + + @retval 0 Successful completion. + @retval -1 Operation failed. Further information is specified by errno. +**/ +static int EFIAPI _f_romfs_Delete(struct __filedes* filp) { + errno = ENOTSUP; + return -1; +} + +/** EFI specific operations for setting the position within a file. + + @param[in] filp Pointer to a file descriptor structure. + @param[in] offset Relative position to move to. + @param[in] whence Specifies the location offset is relative to: Beginning, Current, End. + + @return Returns the new file position or EOF if the seek failed. +**/ +static off_t EFIAPI _f_romfs_Seek(struct __filedes* filp, off_t offset, int whence) { + EFILE* file = (EFILE*) (&filp->devdata); + + //NOTE: eseek works differently than the expected seek, so map the behavior + + int result = eseek(file, offset, whence); + if (result != 0) { + errno = eerrno; + return EOF; + } + + //NOTE: etell cannot fail + return etell(file); +} + +/** The directory path is created with the access permissions specified by + perms. + + The directory is closed after it is created. + + @param[in] path The directory to be created. + @param[in] perms Access permissions for the new directory. + + @retval 0 The directory was created successfully. + @retval -1 An error occurred and an error code is stored in errno. +**/ +static int EFIAPI _f_romfs_Mkdir(const char* path, __mode_t perms) { + errno = ENOTSUP; + return -1; +} + +/** EFI specific operations for reading from a file. + + @param[in] filp Pointer to a file descriptor structure. + @param[in] offset Offset into the file to begin reading at, or NULL. + @param[in] BufferSize Number of bytes in Buffer. Max number of bytes to read. + @param[in] Buffer Pointer to a buffer to receive the read data. + + @return Returns the number of bytes successfully read, + or -1 if the operation failed. Further information is specified by errno. +**/ +static ssize_t EFIAPI +_f_romfs_Read(IN OUT struct __filedes* filp, IN OUT off_t* offset, IN size_t BufferSize, OUT VOID* Buffer) { + + EFILE* stream = (EFILE*) (&filp->devdata); + + if (offset != NULL) { + //TODO: support + errno = ENOTSUP; + return -1; + } + // NOTE: eread cannot fail, it doesn't return negative values + + return (ssize_t) eread(Buffer, BufferSize, 1, stream); +} + +/** EFI specific operations for writing to a file. + + @param[in] filp Pointer to a file descriptor structure. + @param[in] offset Offset into the file to begin writing at, or NULL. + @param[in] BufferSize Number of bytes in Buffer. Max number of bytes to write. + @param[in] Buffer Pointer to a buffer containing the data to be written. + + @return Returns the number of bytes successfully written, + or -1 if the operation failed. Further information is specified by errno. +**/ +static ssize_t EFIAPI +_f_romfs_Write(IN struct __filedes* filp, IN off_t* offset, IN size_t BufferSize, IN const void* Buffer) { + errno = ENOTSUP; + return -1; +} + + +static int EFIAPI _f_romfs_Fcntl(struct __filedes* filp, UINT32 Cmd, void* p3, void* p4) { + errno = ENOTSUP; + return -1; +} + +/** EFI specific operations for getting information about an open file. + + @param[in] filp Pointer to a file descriptor structure. + @param[out] statbuf Buffer in which to store the file status. + @param[in] Something This parameter is not used by this device. + + @retval 0 Successful completion. + @retval -1 Operation failed. Further information is specified by errno. +**/ +static int EFIAPI _f_romfs_Stat(struct __filedes* filp, struct stat* statbuf, void* Something) { + EFILE* file = (EFILE*) (&filp->devdata); + + + // Got the info, now populate statbuf with it + statbuf->st_size = file->size; + statbuf->st_physsize = 0; + statbuf->st_curpos = 0; + + statbuf->st_birthtime = 0; + statbuf->st_atime = 0; + statbuf->st_mtime = 0; + + statbuf->st_mode = filp->f_iflags; + statbuf->st_blksize = S_BLKSIZE; + + return 0; +} + +/** EFI specific operations for low-level control of a file or device. + + @param[in] filp Pointer to a file descriptor structure. + @param[in] cmd The command this ioctl is to perform. + @param[in,out] argp Zero or more arguments as needed by the command. + + @retval 0 Successful completion. + @retval -1 Operation failed. Further information is specified by errno. +**/ +static int EFIAPI _f_romfs_Ioctl(struct __filedes* filp, ULONGN cmd, va_list argp) { + errno = ENOTSUP; + return -1; +} + +/** EFI specific operations for opening a file. + + @param[in] DevNode Pointer to the Device control structure for this stream. + @param[in] filp Pointer to the new file control structure for this stream. + @param[in] DevInstance Not used by this device. + @param[in] Path File-system path to the file or directory. + @param[in] MPath Not used by this device. + + @retval 0 This console stream has been successfully opened. + @retval -1 The DevNode or filp pointer is NULL. + @retval -1 DevNode does not point to a valid console stream device. +**/ +int EFIAPI _f_romfs_Open( + DeviceNode* DevNode, + struct __filedes* filp, + int DevInstance, /* Not used by romfs */ + wchar_t* Path, + wchar_t* MPath +) { + if (filp->Oflags != O_RDONLY) { + errno = EINVAL; + return -1; + } + + char* strPath = (char*) AllocateZeroPool(PATH_MAX); + if (strPath == NULL) { + errno = ENOMEM; + return -1; + } + + size_t convert_result = wcstombs(strPath, Path, PATH_MAX); + + if (convert_result == ((size_t) -1) || convert_result > PATH_MAX) { + errno = EINVAL; + return -1; + } + + // Call the EFI's Open function + EFILE* file = eopen(strPath, "r"); + if (file == NULL) { + filp->f_iflags = 0; // Release our reservation on this FD + // Set errno based upon Status + errno = eerrno; + + FreePool(strPath); + return -1; + } + + FreePool(strPath); + + // Successfully got a regular File (note c-embed doesnÄt support to open directories) + filp->f_iflags |= S_IFREG; + + // Update the info in the fd + filp->devdata = (void*) file; + + GenericInstance* Gip = (GenericInstance*) DevNode->InstanceList; + filp->f_offset = 0; + filp->f_ops = &Gip->Abstraction; + + return 0; +} + +/** Returns a bit mask describing which operations could be completed immediately. + + For now, assume the file system, via the shell, is always ready. + + (POLLIN | POLLRDNORM) The file system is ready to be read. + (POLLOUT) The file system is ready for output. + + @param[in] filp Pointer to a file descriptor structure. + @param[in] events Bit mask describing which operations to check. + + @return The returned value is a bit mask describing which operations + could be completed immediately, without blocking. +**/ +static short EFIAPI _f_romfs_Poll(struct __filedes* filp, short events) { + errno = ENOTSUP; + return -1; +} + +static int EFIAPI _f_romfs_Flush(struct __filedes* filp) { + errno = ENOTSUP; + return -1; +} + + +/** EFI specific operations for renaming a file. + + @param[in] from Name of the file to be renamed. + @param[in] to New name for the file. + + @retval 0 Successful completion. + @retval -1 Operation failed. Further information is specified by errno. +**/ +static int EFIAPI _f_romfs_Rename(const char* from, const char* to) { + errno = ENOTSUP; + return -1; +} + +/** EFI specific operations for deleting directories. + + @param[in] filp Pointer to a file descriptor structure. + + @retval 0 Successful completion. + @retval -1 Operation failed. Further information is specified by errno. +**/ +static int EFIAPI _f_romfs_Rmdir(struct __filedes* filp) { + errno = ENOTSUP; + return -1; +} + + +#define ROMFS_NAME ((const CHAR16*) L"romfs:") + +GenericInstance* _g_stream_instance = NULL; + +RETURN_STATUS +EFIAPI +__ctor_rom_fs(void) { + GenericInstance* Stream = (GenericInstance*) AllocateZeroPool(sizeof(GenericInstance)); + if (Stream == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + + Stream->Cookie = ROM_COOKIE; + Stream->InstanceNum = 1; // not used by this + Stream->Dev = NULL; + + Stream->Abstraction.fo_close = &_f_romfs_Close; + Stream->Abstraction.fo_read = &_f_romfs_Read; + Stream->Abstraction.fo_write = &_f_romfs_Write; + Stream->Abstraction.fo_fcntl = &_f_romfs_Fcntl; + Stream->Abstraction.fo_poll = &_f_romfs_Poll; + Stream->Abstraction.fo_flush = &_f_romfs_Flush; + Stream->Abstraction.fo_stat = &_f_romfs_Stat; + Stream->Abstraction.fo_ioctl = &_f_romfs_Ioctl; + Stream->Abstraction.fo_delete = &_f_romfs_Delete; + Stream->Abstraction.fo_rmdir = &_f_romfs_Rmdir; + Stream->Abstraction.fo_mkdir = &_f_romfs_Mkdir; + Stream->Abstraction.fo_rename = &_f_romfs_Rename; + Stream->Abstraction.fo_lseek = &_f_romfs_Seek; + + DeviceNode* Node = __DevRegister(ROMFS_NAME, NULL, &_f_romfs_Open, Stream, 1, sizeof(GenericInstance), O_RDONLY); + RETURN_STATUS Status = EFIerrno; + Stream->Parent = Node; + + _g_stream_instance = Stream; + + return Status; +} + + +RETURN_STATUS +EFIAPI +__dtor__rom_fs(void) { + if (_g_stream_instance != NULL) { + FreePool(_g_stream_instance); + } + return RETURN_SUCCESS; +} + + +void uefi::platform_init() { + // auto status = __ctor_rom_fs(); + // if (EFI_ERROR(status)) { + // utils::throw_( + // std::runtime_error{ fmt::format("can't initialize ROM fs: {}", map_efi_status_to_string(status)) } + // ); + // } +} + +void uefi::platform_exit() { + // auto status = __dtor__rom_fs(); + // if (EFI_ERROR(status)) { + // utils::throw_( + // std::runtime_error{ fmt::format("can't deinitialize ROM fs: {}", map_efi_status_to_string(status)) } + // ); + // } +} diff --git a/src/helper/uefi_utils.hpp b/src/helper/uefi_utils.hpp new file mode 100644 index 000000000..ec910ea56 --- /dev/null +++ b/src/helper/uefi_utils.hpp @@ -0,0 +1,32 @@ + + +#pragma once + + +#if !defined(__UEFI__) +#error "this header is for uefi only" +#endif + + +#include "manager/service_provider.hpp" + +#include "helper/spdlog_wrapper.hpp" +#include +#include +#include + + +#include + + +namespace uefi { + + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::shared_ptr get_debug_sink(); + + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::string map_efi_status_to_string(EFI_STATUS status); + + OOPETRIS_GRAPHICS_EXPORTED void platform_init(); + + OOPETRIS_GRAPHICS_EXPORTED void platform_exit(); + +}; // namespace uefi diff --git a/src/helper/web_utils.cpp b/src/helper/web_utils.cpp index d463a68e4..3984693b4 100644 --- a/src/helper/web_utils.cpp +++ b/src/helper/web_utils.cpp @@ -1,10 +1,8 @@ -#if defined(__EMSCRIPTEN__) - #include -#include "web_utils.hpp" +#include "./web_utils.hpp" #include #include @@ -190,5 +188,3 @@ void web::WebContext::do_processing() { [[nodiscard]] const web::LocalStorage& web::WebContext::local_storage() const { return m_local_storage; } - -#endif diff --git a/src/input/controller_input.cpp b/src/input/controller_input.cpp index 9f14cf02f..7fb6da313 100644 --- a/src/input/controller_input.cpp +++ b/src/input/controller_input.cpp @@ -77,7 +77,8 @@ input::ControllerInput::get_by_device_index(int device_index) { } -[[nodiscard]] std::optional input::ControllerInput::get_navigation_event(const SDL_Event& event +[[nodiscard]] std::optional input::ControllerInput::get_navigation_event( + const SDL_Event& event ) const { if (event.type == SDL_CONTROLLERBUTTONDOWN) { @@ -123,7 +124,7 @@ input::ControllerInput::get_by_device_index(int device_index) { case NavigationEvent::RIGHT: return "Right"; case NavigationEvent::TAB: - throw std::runtime_error("Tab is not supported"); + utils::throw_(std::runtime_error("Tab is not supported")); default: UNREACHABLE(); } @@ -238,7 +239,8 @@ input::ControllerGameInput::ControllerGameInput( } -[[nodiscard]] std::optional input::ControllerGameInput::sdl_event_to_input_event(const SDL_Event& event +[[nodiscard]] std::optional input::ControllerGameInput::sdl_event_to_input_event( + const SDL_Event& event ) const { if (event.type == SDL_CONTROLLERBUTTONDOWN) { @@ -314,9 +316,12 @@ sdl::ControllerKey json_helper::get_controller_key(const nlohmann::json& obj, co const auto& value = sdl::ControllerKey::from_string(string::to_lower_case(input)); if (not value.has_value()) { - throw nlohmann::json::type_error::create( - 302, fmt::format("Expected a valid Key for key '{}', but got '{}': {}", name, input, value.error()), - &context + utils::throw_( + nlohmann::json::type_error::create( + 302, + fmt::format("Expected a valid Key for key '{}', but got '{}': {}", name, input, value.error()), + &context + ) ); } return value.value(); diff --git a/src/input/controller_input.hpp b/src/input/controller_input.hpp index 7e9b385a2..0ab0dc34b 100644 --- a/src/input/controller_input.hpp +++ b/src/input/controller_input.hpp @@ -142,7 +142,7 @@ namespace nlohmann { const auto is_valid = settings.validate(); if (not is_valid.has_value()) { - throw std::runtime_error(is_valid.error()); + utils::throw_(std::runtime_error(is_valid.error())); } return settings; diff --git a/src/input/input.cpp b/src/input/input.cpp index 10f9cb4bb..b1b5f9f13 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -96,7 +96,8 @@ input::InputManager::InputManager(const std::shared_ptr& window) { } -[[nodiscard]] std::optional input::InputManager::get_navigation_event(const SDL_Event& event +[[nodiscard]] std::optional input::InputManager::get_navigation_event( + const SDL_Event& event ) const { for (const auto& input : m_inputs) { @@ -108,7 +109,8 @@ input::InputManager::InputManager(const std::shared_ptr& window) { return std::nullopt; } -[[nodiscard]] std::optional input::InputManager::get_pointer_event(const SDL_Event& event +[[nodiscard]] std::optional input::InputManager::get_pointer_event( + const SDL_Event& event ) const { for (const auto& input : m_inputs) { if (const auto pointer_input = utils::is_child_class(input); pointer_input.has_value()) { @@ -122,8 +124,8 @@ input::InputManager::InputManager(const std::shared_ptr& window) { } -[[nodiscard]] SDL_Event input::InputManager::offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) - const { +[[nodiscard]] SDL_Event +input::InputManager::offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) const { for (const auto& input : m_inputs) { if (const auto pointer_input = utils::is_child_class(input); pointer_input.has_value()) { if (const auto pointer_event = pointer_input.value()->get_pointer_event(event); pointer_event.has_value()) { @@ -132,7 +134,7 @@ input::InputManager::InputManager(const std::shared_ptr& window) { } } - throw std::runtime_error("Tried to offset event, that is no pointer event"); + utils::throw_(std::runtime_error("Tried to offset event, that is no pointer event")); } diff --git a/src/input/input_creator.cpp b/src/input/input_creator.cpp index 2e7906bc2..6cbc6e0dc 100644 --- a/src/input/input_creator.cpp +++ b/src/input/input_creator.cpp @@ -34,7 +34,7 @@ namespace { SDL_DisplayMode mode{}; const int mode_result = SDL_GetCurrentDisplayMode(0, &mode); if (mode_result != 0) { - throw helper::FatalError{ fmt::format("failed in getting display mode: {}", SDL_GetError()) }; + utils::throw_(helper::FatalError{ fmt::format("failed in getting display mode: {}", SDL_GetError()) }); } if (mode.refresh_rate != 0) { target_fps = static_cast(mode.refresh_rate); @@ -61,8 +61,10 @@ input::get_game_parameters_for_replay( auto maybe_recording_reader = recorder::RecordingReader::from_path(recording_path); if (not maybe_recording_reader.has_value()) { - throw std::runtime_error( - fmt::format("an error occurred while reading recording: {}", maybe_recording_reader.error()) + utils::throw_( + std::runtime_error( + fmt::format("an error occurred while reading recording: {}", maybe_recording_reader.error()) + ) ); } @@ -131,7 +133,9 @@ input::get_game_parameters_for_replay( const auto date_time_str = date.to_string(); if (not date_time_str.has_value()) { - throw std::runtime_error{ fmt::format("Erro in date to string conversion: {}", date_time_str.error()) }; + utils::throw_( + std::runtime_error{ fmt::format("Erro in date to string conversion: {}", date_time_str.error()) } + ); } const auto filename = fmt::format("{}.{}", date_time_str.value(), constants::recording::extension); @@ -141,7 +145,7 @@ input::get_game_parameters_for_replay( auto recording_writer_create_result = recorder::RecordingWriter::get_writer(file_path, std::move(tetrion_headers), std::move(information)); if (not recording_writer_create_result.has_value()) { - throw std::runtime_error(recording_writer_create_result.error()); + utils::throw_(std::runtime_error(recording_writer_create_result.error())); } const auto recording_writer = diff --git a/src/input/input_creator.hpp b/src/input/input_creator.hpp index 1c3f44ded..bd95f0b23 100644 --- a/src/input/input_creator.hpp +++ b/src/input/input_creator.hpp @@ -19,17 +19,17 @@ namespace tetrion { std::optional> recording_writer; StartingParameters( - u32 target_fps, - Random::Seed seed, - u32 starting_level, // NOLINT(bugprone-easily-swappable-parameters) - u8 tetrion_index, - std::optional> recording_writer = std::nullopt + u32 target_fps_a, // NOLINT(bugprone-easily-swappable-parameters) + Random::Seed seed_a, + u32 starting_level_a, + u8 tetrion_index_a, + std::optional> recording_writer_a = std::nullopt ) - : target_fps{ target_fps }, - seed{ seed }, - starting_level{ starting_level }, - tetrion_index{ tetrion_index }, - recording_writer{ std::move(recording_writer) } { } + : target_fps{ target_fps_a }, + seed{ seed_a }, + starting_level{ starting_level_a }, + tetrion_index{ tetrion_index_a }, + recording_writer{ std::move(recording_writer_a) } { } }; } // namespace tetrion diff --git a/src/input/joystick_input.cpp b/src/input/joystick_input.cpp index 539135357..aa46cf4dd 100644 --- a/src/input/joystick_input.cpp +++ b/src/input/joystick_input.cpp @@ -75,7 +75,7 @@ input::JoystickInput& input::JoystickInput::operator=(JoystickInput&& input) noe const auto guid = sdl::GUID{ SDL_JoystickGetGUID(m_joystick) }; if (guid == sdl::GUID{}) { - throw std::runtime_error{ fmt::format("Failed to get joystick GUID: {}", SDL_GetError()) }; + utils::throw_(std::runtime_error{ fmt::format("Failed to get joystick GUID: {}", SDL_GetError()) }); } return guid; @@ -268,10 +268,12 @@ void input::JoyStickInputManager::remove_device( } //this happens way to often, since Sdl outputs both SDL_JOYDEVICEREMOVED and SDL_CONTROLLERDEVICEREMOVED at the same time, in case of a controller, so the second time, this is reached :( - spdlog::debug(fmt::format( - "Failed to remove removed {} from internal input vector", - type == input::JoystickLikeType::Joystick ? "joystick" : "controller" - )); + spdlog::debug( + fmt::format( + "Failed to remove removed {} from internal input vector", + type == input::JoystickLikeType::Joystick ? "joystick" : "controller" + ) + ); } [[nodiscard]] bool input::JoyStickInputManager::process_special_inputs( @@ -673,7 +675,8 @@ input::JoystickLikeGameInput::~JoystickLikeGameInput() { } input::JoystickLikeGameInput::JoystickLikeGameInput(JoystickLikeGameInput&& input) noexcept = default; -[[nodiscard]] input::JoystickLikeGameInput& input::JoystickLikeGameInput::operator=(JoystickLikeGameInput&& input +[[nodiscard]] input::JoystickLikeGameInput& input::JoystickLikeGameInput::operator=( + JoystickLikeGameInput&& input ) noexcept = default; void input::JoystickLikeGameInput::handle_event(const SDL_Event& event) { @@ -742,7 +745,9 @@ input::JoystickGameInput::get_game_input_by_settings( if (const auto joystick_input = utils::is_child_class(input); joystick_input.has_value()) { +#if !defined(__OOPETRIS_NO_EXCEPTIONS) try { +#endif auto result = get_game_joystick_by_guid( settings.identification.guid, settings, event_dispatcher, joystick_input.value() ); @@ -750,10 +755,11 @@ input::JoystickGameInput::get_game_input_by_settings( if (result.has_value()) { return result.value(); } - +#if !defined(__OOPETRIS_NO_EXCEPTIONS) } catch (const std::exception& exception) { spdlog::warn("Couldn't construct JoystickGameInput: {}", exception.what()); } +#endif } } @@ -775,8 +781,8 @@ input::ConsoleJoystickInput::ConsoleJoystickInput( : JoystickInput{ joystick, instance_id, name }, m_key_mappings{ key_mappings } { } -[[nodiscard]] const input::MappingType& input::ConsoleJoystickInput::key_mappings( -) const { +[[nodiscard]] const input::MappingType& +input::ConsoleJoystickInput::key_mappings() const { return m_key_mappings; } @@ -925,7 +931,8 @@ std::optional input::ConsoleJoystickGameInput::sdl_event_to_input_ev return std::nullopt; } -[[nodiscard]] std::optional input::ConsoleJoystickGameInput::get_menu_event(const SDL_Event& event +[[nodiscard]] std::optional input::ConsoleJoystickGameInput::get_menu_event( + const SDL_Event& event ) const { if (event.type == SDL_JOYBUTTONDOWN) { diff --git a/src/input/joystick_input.hpp b/src/input/joystick_input.hpp index 87356ceef..459eacbae 100644 --- a/src/input/joystick_input.hpp +++ b/src/input/joystick_input.hpp @@ -254,7 +254,8 @@ namespace input { [[nodiscard]] JoystickLikeGameInput& operator=(const JoystickLikeGameInput& input) = delete; OOPETRIS_GRAPHICS_EXPORTED JoystickLikeGameInput(JoystickLikeGameInput&& input) noexcept; - [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED JoystickLikeGameInput& operator=(JoystickLikeGameInput&& input + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED JoystickLikeGameInput& operator=( + JoystickLikeGameInput&& input ) noexcept; OOPETRIS_GRAPHICS_EXPORTED void handle_event(const SDL_Event& event) override; @@ -360,8 +361,11 @@ namespace nlohmann { const auto& value = sdl::GUID::from_string(input); if (not value.has_value()) { - throw nlohmann::json::type_error::create( - 302, fmt::format("Expected a valid GUID but got '{}': {}", input, value.error()), &context + utils::throw_( + nlohmann::json::type_error::create( + 302, fmt::format("Expected a valid GUID but got '{}': {}", input, value.error()), + &context + ) ); } @@ -375,10 +379,12 @@ namespace nlohmann { } static void to_json(json& obj, const input::JoystickIdentification& identification) { - obj = nlohmann::json::object({ - { "guid", identification.guid.to_string() }, - { "name", identification.name } - }); + obj = nlohmann::json::object( + { + { "guid", identification.guid.to_string() }, + { "name", identification.name } + } + ); } }; @@ -422,7 +428,7 @@ namespace nlohmann { const auto is_valid = settings.validate(); if (not is_valid.has_value()) { - throw std::runtime_error(is_valid.error()); + utils::throw_(std::runtime_error(is_valid.error())); } return settings; @@ -433,18 +439,22 @@ namespace nlohmann { auto identification = nlohmann::json::object(); adl_serializer::to_json(identification, settings.identification); - obj = nlohmann::json::object({ - { "identification", identification }, - { "rotate_left", settings.rotate_left }, - { "rotate_right", settings.rotate_right }, - { "move_left", settings.move_left }, - { "move_right", settings.move_right }, - { "move_down", settings.move_down }, - { "drop", settings.drop }, - { "hold", settings.hold }, - { "menu", nlohmann::json::object({ { "pause", settings.pause }, - { "open_settings", settings.open_settings } }) } - }); + obj = nlohmann::json::object( + { + { "identification",identification }, + { "rotate_left", settings.rotate_left }, + { "rotate_right", settings.rotate_right }, + { "move_left", settings.move_left }, + { "move_right", settings.move_right }, + { "move_down", settings.move_down }, + { "drop", settings.drop }, + { "hold", settings.hold }, + { "menu", + nlohmann::json::object( + { { "pause", settings.pause }, { "open_settings", settings.open_settings } } + ) } + } + ); } }; } // namespace nlohmann diff --git a/src/input/keyboard_input.cpp b/src/input/keyboard_input.cpp index da37ce6e1..7a4412cef 100644 --- a/src/input/keyboard_input.cpp +++ b/src/input/keyboard_input.cpp @@ -8,7 +8,8 @@ input::KeyboardInput::KeyboardInput() : input::Input{ "keyboard", InputType::Keyboard } { } -[[nodiscard]] std::optional input::KeyboardInput::get_navigation_event(const SDL_Event& event +[[nodiscard]] std::optional input::KeyboardInput::get_navigation_event( + const SDL_Event& event ) const { @@ -159,8 +160,8 @@ input::KeyboardGameInput::~KeyboardGameInput() { input::KeyboardGameInput::KeyboardGameInput(KeyboardGameInput&& input) noexcept = default; -[[nodiscard]] input::KeyboardGameInput& input::KeyboardGameInput::operator=(KeyboardGameInput&& input -) noexcept = default; +[[nodiscard]] input::KeyboardGameInput& input::KeyboardGameInput::operator=(KeyboardGameInput&& input) noexcept = + default; [[nodiscard]] helper::expected input::KeyboardSettings::validate() const { @@ -181,9 +182,12 @@ sdl::Key json_helper::get_key(const nlohmann::json& obj, const std::string& name const auto& value = sdl::Key::from_string(input); if (not value.has_value()) { - throw nlohmann::json::type_error::create( - 302, fmt::format("Expected a valid Key for key '{}', but got '{}': {}", name, input, value.error()), - &context + utils::throw_( + nlohmann::json::type_error::create( + 302, + fmt::format("Expected a valid Key for key '{}', but got '{}': {}", name, input, value.error()), + &context + ) ); } return value.value(); diff --git a/src/input/keyboard_input.hpp b/src/input/keyboard_input.hpp index 2b541058c..564139a68 100644 --- a/src/input/keyboard_input.hpp +++ b/src/input/keyboard_input.hpp @@ -24,7 +24,8 @@ namespace input { const SDL_Event& event ) const override; - [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::string describe_navigation_event(NavigationEvent event + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::string describe_navigation_event( + NavigationEvent event ) const override; }; @@ -82,7 +83,8 @@ namespace input { OOPETRIS_GRAPHICS_EXPORTED void update(SimulationStep simulation_step_index) override; - [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::optional get_menu_event(const SDL_Event& event + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::optional get_menu_event( + const SDL_Event& event ) const override; [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::string describe_menu_event(MenuEvent event) const override; @@ -140,24 +142,28 @@ namespace nlohmann { const auto is_valid = settings.validate(); if (not is_valid.has_value()) { - throw std::runtime_error(is_valid.error()); + utils::throw_(std::runtime_error(is_valid.error())); } return settings; } static void to_json(json& obj, const input::KeyboardSettings& settings) { - obj = nlohmann::json::object({ - { "rotate_left", settings.rotate_left.to_string() }, - { "rotate_right", settings.rotate_right.to_string() }, - { "move_left", settings.move_left.to_string() }, - { "move_right", settings.move_right.to_string() }, - { "move_down", settings.move_down.to_string() }, - { "drop", settings.drop.to_string() }, - { "hold", settings.hold.to_string() }, - { "menu", nlohmann::json::object({ { "pause", settings.pause.to_string() }, - { "open_settings", settings.open_settings.to_string() } }) } - }); + obj = nlohmann::json::object( + { + { "rotate_left", settings.rotate_left.to_string() }, + { "rotate_right", settings.rotate_right.to_string() }, + { "move_left", settings.move_left.to_string() }, + { "move_right", settings.move_right.to_string() }, + { "move_down", settings.move_down.to_string() }, + { "drop", settings.drop.to_string() }, + { "hold", settings.hold.to_string() }, + { "menu", nlohmann::json::object( + { { "pause", settings.pause.to_string() }, + { "open_settings", settings.open_settings.to_string() } } + ) } + } + ); } }; } // namespace nlohmann diff --git a/src/input/mouse_input.cpp b/src/input/mouse_input.cpp index f286b75db..b19430a5e 100644 --- a/src/input/mouse_input.cpp +++ b/src/input/mouse_input.cpp @@ -8,8 +8,8 @@ input::MouseInput::MouseInput() : PointerInput("mouse") { } -[[nodiscard]] SDL_Event input::MouseInput::offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) - const { +[[nodiscard]] SDL_Event +input::MouseInput::offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) const { auto new_event = event; @@ -28,23 +28,24 @@ input::MouseInput::MouseInput() : PointerInput("mouse") { } new_event.button.y = event.button.y + point.y; break; default: - throw std::runtime_error("Tried to offset event, that is no pointer event: in Mouse Input"); + utils::throw_(std::runtime_error("Tried to offset event, that is no pointer event: in Mouse Input")); } return new_event; } -[[nodiscard]] std::optional input::MouseInput::get_navigation_event(const SDL_Event& /*event*/) - const { +[[nodiscard]] std::optional +input::MouseInput::get_navigation_event(const SDL_Event& /*event*/) const { return std::nullopt; } [[nodiscard]] std::string input::MouseInput::describe_navigation_event(NavigationEvent /*event*/) const { - throw std::runtime_error("not supported"); + utils::throw_(std::runtime_error("not supported")); } -[[nodiscard]] std::optional input::MouseInput::get_pointer_event(const SDL_Event& event +[[nodiscard]] std::optional input::MouseInput::get_pointer_event( + const SDL_Event& event ) const { auto pointer_event = input::PointerEvent::PointerUp; diff --git a/src/input/replay_input.cpp b/src/input/replay_input.cpp index 1b3cb8b82..c95d59858 100644 --- a/src/input/replay_input.cpp +++ b/src/input/replay_input.cpp @@ -73,7 +73,7 @@ void input::ReplayGameInput::late_update(const SimulationStep simulation_step_in spdlog::info("snapshots are equal"); } else { spdlog::error("{}", compare_result.error()); - throw std::runtime_error{ "snapshots are not equal" }; + utils::throw_(std::runtime_error{ "snapshots are not equal" }); } ++m_next_snapshot_index; @@ -86,7 +86,7 @@ void input::ReplayGameInput::late_update(const SimulationStep simulation_step_in } [[nodiscard]] std::string input::ReplayGameInput::describe_menu_event(MenuEvent /*event*/) const { - throw std::runtime_error("not supported"); + utils::throw_(std::runtime_error("not supported")); } [[nodiscard]] bool input::ReplayGameInput::is_end_of_recording() const { diff --git a/src/input/touch_input.cpp b/src/input/touch_input.cpp index b8812042e..244b604e1 100644 --- a/src/input/touch_input.cpp +++ b/src/input/touch_input.cpp @@ -52,9 +52,8 @@ std::optional input::TouchGameInput::sdl_event_to_input_event(const const auto timestamp = event.tfinger.timestamp; m_finger_state.insert_or_assign( - finger_id, - std::optional{ - PressedState{ timestamp, x_pos, y_pos } + finger_id, std::optional{ + PressedState{ timestamp, x_pos, y_pos } } ); } @@ -176,7 +175,7 @@ input::TouchGameInput::TouchGameInput(TouchGameInput&& input) noexcept = default case input::MenuEvent::Pause: return "Back"; case input::MenuEvent::OpenSettings: - throw std::runtime_error("Open Settings is not supported"); + utils::throw_(std::runtime_error("Open Settings is not supported")); default: UNREACHABLE(); } @@ -213,7 +212,8 @@ input::TouchInput::get_by_device_index(const std::shared_ptr& window, in } -[[nodiscard]] std::optional input::TouchInput::get_navigation_event(const SDL_Event& event +[[nodiscard]] std::optional input::TouchInput::get_navigation_event( + const SDL_Event& event ) const { //technically no touch event, but it's a navigation event, and by APi design it can also handle those if (event.type == SDL_KEYDOWN and event.key.keysym.sym == SDLK_AC_BACK) { @@ -239,7 +239,8 @@ input::TouchInput::get_by_device_index(const std::shared_ptr& window, in } } -[[nodiscard]] std::optional input::TouchInput::get_pointer_event(const SDL_Event& event +[[nodiscard]] std::optional input::TouchInput::get_pointer_event( + const SDL_Event& event ) const { auto pointer_event = input::PointerEvent::PointerUp; @@ -276,14 +277,14 @@ input::TouchInput::get_by_device_index(const std::shared_ptr& window, in } -[[nodiscard]] SDL_Event input::TouchInput::offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) - const { +[[nodiscard]] SDL_Event +input::TouchInput::offset_pointer_event(const SDL_Event& event, const shapes::IPoint& point) const { auto new_event = event; if (event.type != SDL_FINGERMOTION and event.type != SDL_FINGERDOWN and event.type != SDL_FINGERUP) { - throw std::runtime_error("Tried to offset event, that is no pointer event: in Touch Input"); + utils::throw_(std::runtime_error("Tried to offset event, that is no pointer event: in Touch Input")); } using FloatType = decltype(event.tfinger.x); @@ -293,8 +294,8 @@ input::TouchInput::get_by_device_index(const std::shared_ptr& window, in const auto window_size = m_window->size(); - new_event.tfinger.x = x_percent + static_cast(point.x) / static_cast(window_size.x); - new_event.tfinger.y = y_percent + static_cast(point.y) / static_cast(window_size.y); + new_event.tfinger.x = x_percent + (static_cast(point.x) / static_cast(window_size.x)); + new_event.tfinger.y = y_percent + (static_cast(point.y) / static_cast(window_size.y)); return new_event; } diff --git a/src/input/touch_input.hpp b/src/input/touch_input.hpp index 26d1de72f..b8654b56e 100644 --- a/src/input/touch_input.hpp +++ b/src/input/touch_input.hpp @@ -27,7 +27,8 @@ namespace input { const SDL_Event& event ) const override; - [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::string describe_navigation_event(NavigationEvent event + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::string describe_navigation_event( + NavigationEvent event ) const override; [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::optional get_pointer_event( @@ -62,8 +63,12 @@ namespace input { Uint32 timestamp; float x; float y; - explicit PressedState(Uint32 timestamp, float x_pos, float y_pos) //NOLINT(bugprone-easily-swappable-parameters) - : timestamp{ timestamp }, + explicit PressedState( + Uint32 timestamp_a, //NOLINT(bugprone-easily-swappable-parameters) + float x_pos, + float y_pos + ) + : timestamp{ timestamp_a }, x{ x_pos }, y{ y_pos } { } }; @@ -97,7 +102,8 @@ namespace input { OOPETRIS_GRAPHICS_EXPORTED void handle_event(const SDL_Event& event) override; OOPETRIS_GRAPHICS_EXPORTED void update(SimulationStep simulation_step_index) override; - [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::optional get_menu_event(const SDL_Event& event + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::optional get_menu_event( + const SDL_Event& event ) const override; [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::string describe_menu_event(MenuEvent event) const override; @@ -150,13 +156,15 @@ namespace json_helper { if (not error.has_value()) { - throw nlohmann::json::type_error::create( - 302, - fmt::format( - "Expected a valid number of type '{}' for key '{}' but an error occurred: {}", - typeid(T).name(), name, error.error() - ), - &context + utils::throw_( + nlohmann::json::type_error::create( + 302, + fmt::format( + "Expected a valid number of type '{}' for key '{}' but an error occurred: {}", + typeid(T).name(), name, error.error() + ), + &context + ) ); } @@ -177,14 +185,13 @@ namespace nlohmann { ::json::check_for_no_additional_keys( - obj, - { - "type", - "move_x_threshold", - "move_y_threshold", - "rotation_duration_threshold", - "drop_duration_threshold", - } + obj, { + "type", + "move_x_threshold", + "move_y_threshold", + "rotation_duration_threshold", + "drop_duration_threshold", + } ); const auto move_x_threshold = json_helper::get_number(obj, "move_x_threshold"); @@ -201,7 +208,7 @@ namespace nlohmann { const auto is_valid = settings.validate(); if (not is_valid.has_value()) { - throw std::runtime_error(is_valid.error()); + utils::throw_(std::runtime_error(is_valid.error())); } return settings; @@ -209,12 +216,14 @@ namespace nlohmann { static void to_json(json& obj, const input::TouchSettings& settings) { - obj = nlohmann::json::object({ - { "move_x_threshold", settings.move_x_threshold }, - { "move_y_threshold", settings.move_y_threshold }, - { "rotation_duration_threshold", settings.rotation_duration_threshold }, - { "drop_duration_threshold", settings.drop_duration_threshold } - }); + obj = nlohmann::json::object( + { + { "move_x_threshold", settings.move_x_threshold }, + { "move_y_threshold", settings.move_y_threshold }, + { "rotation_duration_threshold", settings.rotation_duration_threshold }, + { "drop_duration_threshold", settings.drop_duration_threshold } + } + ); } }; } // namespace nlohmann diff --git a/src/libs/core/hash-library/sha256.cpp b/src/libs/core/hash-library/sha256.cpp index d085a97e2..2c588ed37 100644 --- a/src/libs/core/hash-library/sha256.cpp +++ b/src/libs/core/hash-library/sha256.cpp @@ -29,6 +29,8 @@ #endif #elif defined(__APPLE__) #include +#elif defined(__UEFI__) +#include #else #include #endif diff --git a/src/libs/core/helper/color.hpp b/src/libs/core/helper/color.hpp index b47601a64..f845c7150 100644 --- a/src/libs/core/helper/color.hpp +++ b/src/libs/core/helper/color.hpp @@ -46,14 +46,14 @@ struct HSVColor { } else { if (h < 0.0 || h > 360.0) { - throw std::runtime_error{ fmt::format("h has to be in range 0.0 - 360.0 but was: {}", h) }; + utils::throw_(std::runtime_error{ fmt::format("h has to be in range 0.0 - 360.0 but was: {}", h) }); } if (s < 0.0 || s > 1.0) { - throw std::runtime_error{ fmt::format("s has to be in range 0.0 - 1.0 but was: {}", s) }; + utils::throw_(std::runtime_error{ fmt::format("s has to be in range 0.0 - 1.0 but was: {}", s) }); } if (v < 0.0 || v > 1.0) { - throw std::runtime_error{ fmt::format("v has to be in range 0.0 - 1.0 but was: {}", v) }; + utils::throw_(std::runtime_error{ fmt::format("v has to be in range 0.0 - 1.0 but was: {}", v) }); } } } @@ -223,9 +223,9 @@ struct Color { const FloatType offset = value - chroma; - const auto finish_value = [offset](FloatType value) -> u8 { + const auto finish_value = [offset](FloatType f_value) -> u8 { const auto result = - std::clamp(value + offset, static_cast(0.0), static_cast(1.0)) + std::clamp(f_value + offset, static_cast(0.0), static_cast(1.0)) * static_cast(0xFF); return static_cast(round_constexpr(result)); diff --git a/src/libs/core/helper/const_utils.hpp b/src/libs/core/helper/const_utils.hpp index 233348b64..7e741e6f2 100644 --- a/src/libs/core/helper/const_utils.hpp +++ b/src/libs/core/helper/const_utils.hpp @@ -20,6 +20,15 @@ (if constexpr (!(CHECK)) { static_assert(false, MSG); }()) s*/ +#else +#if defined(__OOPETRIS_NO_EXCEPTIONS) + +#define CONSTEVAL_ONLY_STATIC_ASSERT(CHECK, MSG) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ + ((CHECK) ? void(0) : [] { \ + /* If you see this really bad c++ error message, follow the origin of MSG, to see the real error message, c++ error messages suck xD */ \ + /* MSG*/ \ + abort(); \ + }()) #else #define CONSTEVAL_ONLY_STATIC_ASSERT(CHECK, MSG) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ ((CHECK) ? void(0) : [] { \ @@ -27,6 +36,7 @@ s*/ throw(MSG); \ }()) #endif +#endif #define CONSTEVAL_STATIC_ASSERT(CHECK, MSG) /*NOLINT(cppcoreguidelines-macro-usage)*/ \ do { /*NOLINT(cppcoreguidelines-avoid-do-while)*/ \ diff --git a/src/libs/core/helper/date.cpp b/src/libs/core/helper/date.cpp index 1af602ac7..b6e7233d5 100644 --- a/src/libs/core/helper/date.cpp +++ b/src/libs/core/helper/date.cpp @@ -1,5 +1,6 @@ #include "./date.hpp" +#include "./utils.hpp" #include #include @@ -13,7 +14,7 @@ date::ISO8601Date::ISO8601Date(std::tm time_struct) { const std::time_t time = std::mktime(&time_struct); if (time < 0) { - throw std::runtime_error("Couldn't convert std::tm to std::time_t"); + utils::throw_(std::runtime_error("Couldn't convert std::tm to std::time_t")); } m_value = static_cast(time); @@ -72,6 +73,12 @@ helper::expected date::ISO8601Date::from_string( if (gmtime_s(&time_struct, &value) != 0) { return helper::unexpected{ "error calling gmtime_s" }; } +#elif defined(__UEFI__) + std::tm* tm_p = ::localtime(&value); + if (tm_p == nullptr) { + return helper::unexpected{ fmt::format("error calling gmtime: {}", std::strerror(errno)) }; + } + time_struct = *tm_p; #else if (gmtime_r(&value, &time_struct) == nullptr) { return helper::unexpected{ fmt::format("error calling gmtime_r: {}", std::strerror(errno)) }; @@ -87,7 +94,18 @@ date::ISO8601Date::format_tm_struct(std::tm time_struct, const char* format_stri static constexpr auto buffer_size = usize{ 100 }; std::array buffer{}; +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif + const auto result = std::strftime(buffer.data(), buffer.size(), format_string, &time_struct); + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + + if (result == 0) { return helper::unexpected{ "error calling std::strftime" }; } diff --git a/src/libs/core/helper/meson.build b/src/libs/core/helper/meson.build index c440546a5..027e23ca3 100644 --- a/src/libs/core/helper/meson.build +++ b/src/libs/core/helper/meson.build @@ -29,6 +29,7 @@ _header_files = files( 'string_manipulation.hpp', 'timer.hpp', 'types.hpp', + 'uefi_debug.h', 'utils.hpp', 'versions.hpp', ) diff --git a/src/libs/core/helper/parse_json.cpp b/src/libs/core/helper/parse_json.cpp index 34b5f6bab..a2af52bfc 100644 --- a/src/libs/core/helper/parse_json.cpp +++ b/src/libs/core/helper/parse_json.cpp @@ -3,6 +3,9 @@ #include "./parse_json.hpp" +#include "./utils.hpp" + + std::string json::get_json_type(const nlohmann::json::value_t& type) { switch (type) { @@ -41,8 +44,10 @@ bool json::is_meta_key(const std::string& key) { void json::check_for_no_additional_keys(const nlohmann::json& obj, const std::vector& keys) { if (not obj.is_object()) { - throw nlohmann::json::type_error::create( - 302, fmt::format("expected an object, but got type '{}'", get_json_type(obj.type())), &obj + utils::throw_( + nlohmann::json::type_error::create( + 302, fmt::format("expected an object, but got type '{}'", get_json_type(obj.type())), &obj + ) ); } @@ -54,8 +59,10 @@ void json::check_for_no_additional_keys(const nlohmann::json& obj, const std::ve continue; } if (std::ranges::find(keys, key) == keys.cend()) { - throw nlohmann::json::type_error::create( - 302, fmt::format("object may only contain expected keys, but contained '{}'", key), &obj + utils::throw_( + nlohmann::json::type_error::create( + 302, fmt::format("object may only contain expected keys, but contained '{}'", key), &obj + ) ); } } diff --git a/src/libs/core/helper/parse_json.hpp b/src/libs/core/helper/parse_json.hpp index 09022614e..675439d32 100644 --- a/src/libs/core/helper/parse_json.hpp +++ b/src/libs/core/helper/parse_json.hpp @@ -58,7 +58,16 @@ namespace json { template [[nodiscard]] helper::expected try_parse_json(const std::string& content) noexcept { +#if defined(__OOPETRIS_NO_EXCEPTIONS) + auto result_j = nlohmann::json::parse(content, nullptr, false); + if (result_j.is_discarded()) { + return helper::unexpected{ "A JSON error occurred, but no further details available" }; + } + T result = result_j; + + return result; +#else try { T result = nlohmann::json::parse(content); return result; @@ -72,6 +81,7 @@ namespace json { } catch (std::exception& exception) { return helper::unexpected{ fmt::format("unknown exception: {}", exception.what()) }; } +#endif } template @@ -117,6 +127,11 @@ namespace json { template [[nodiscard]] helper::expected try_convert_to_json(const T& input) noexcept { +#if defined(__OOPETRIS_NO_EXCEPTIONS) + nlohmann::json value = input; + //TODO: this may throw exceptions, but they just abort, which is not in the spirit of this function so either use another nlohmann json mechanism or another json library that supports return values for custom subparser + return value; +#else try { nlohmann::json value = input; return value; @@ -127,33 +142,24 @@ namespace json { } catch (std::exception& exception) { return helper::unexpected{ fmt::format("unknown exception: {}", exception.what()) }; } +#endif } template [[nodiscard]] helper::expected try_json_to_string(const T& type, const bool pretty = false) noexcept { - try { + auto value = try_convert_to_json(type); - auto value = try_convert_to_json(type); - - if (not value.has_value()) { - return helper::unexpected{ value.error() }; - } - - if (pretty) { - return value.value().dump(1, '\t'); - } - - return value.value().dump(-1, ' '); + if (not value.has_value()) { + return helper::unexpected{ value.error() }; + } - } catch (nlohmann::json::type_error& type_error) { - return helper::unexpected{ fmt::format("type error: {}", type_error.what()) }; - } catch (nlohmann::json::exception& exception) { - return helper::unexpected{ fmt::format("unknown json exception: {}", exception.what()) }; - } catch (std::exception& exception) { - return helper::unexpected{ fmt::format("unknown exception: {}", exception.what()) }; + if (pretty) { + return value.value().dump(1, '\t'); } + + return value.value().dump(-1, ' '); } @@ -170,6 +176,7 @@ namespace json { std::ofstream file_stream{ file }; + if (not file_stream.is_open()) { return fmt::format("File '{}' couldn't be opened!", file.string()); } diff --git a/src/libs/core/helper/sleep.cpp b/src/libs/core/helper/sleep.cpp index 1d9f76936..480364b2d 100644 --- a/src/libs/core/helper/sleep.cpp +++ b/src/libs/core/helper/sleep.cpp @@ -20,6 +20,13 @@ using namespace std::chrono_literals; #endif +#if defined(__UEFI__) + + +#include + +#endif + bool helper::sleep_nanoseconds(std::chrono::nanoseconds nano_seconds) { #if defined(_MSC_VER) diff --git a/src/libs/core/helper/uefi_debug.h b/src/libs/core/helper/uefi_debug.h new file mode 100644 index 000000000..075a99d87 --- /dev/null +++ b/src/libs/core/helper/uefi_debug.h @@ -0,0 +1,19 @@ + +#pragma once + +#if defined(NDEBUG) +#define MDEPKG_NDEBUG 1 +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#include + +#if defined(__cplusplus) +} +#endif + + +#define EFI_DEBUG DEBUG diff --git a/src/libs/core/helper/utils.hpp b/src/libs/core/helper/utils.hpp index a2289f5c9..d3919a1b1 100644 --- a/src/libs/core/helper/utils.hpp +++ b/src/libs/core/helper/utils.hpp @@ -15,6 +15,10 @@ #include #include +#if defined(__UEFI__) +#include "./uefi_debug.h" +#endif + namespace helper { template @@ -124,12 +128,40 @@ namespace utils { #define STATIC_ASSERT_WITH_MESSAGE(check, msg) static_assert(check); // NOLINT(cppcoreguidelines-macro-usage) #endif + template + [[noreturn]] inline void throw_(E&& exc) { //NOLINT(readability-identifier-naming) +#if defined(__OOPETRIS_NO_EXCEPTIONS) +#if defined(__UEFI__) + EFI_DEBUG((DEBUG_ERROR, "Exception: %a\n", exc.what())); +#else + std::cerr << "Exception: " << exc.what() << "\n"; +#endif + abort(); +#else + throw std::forward(exc); +#endif + } + } // namespace utils #define UNUSED(x) (void(x)) // NOLINT(cppcoreguidelines-macro-usage) + +#if defined(__UEFI__) +#ifdef UNREACHABLE +#undef UNREACHABLE +#endif +#endif + #if !defined(NDEBUG) +#if defined(__UEFI__) +#define UNREACHABLE() /* NOLINT(cppcoreguidelines-macro-usage)*/ \ + do { /* NOLINT(cppcoreguidelines-avoid-do-while)*/ \ + EFI_DEBUG((DEBUG_ERROR, "UNREACHABLE %a:%d - %a\n", __FILE__, __LINE__, __FUNCTION__)); \ + utils::unreachable(); \ + } while (false) +#else #define UNREACHABLE() /* NOLINT(cppcoreguidelines-macro-usage)*/ \ do { /* NOLINT(cppcoreguidelines-avoid-do-while)*/ \ std::cerr << "UNREACHABLE " << (__FILE__) /* NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)*/ \ @@ -138,12 +170,20 @@ namespace utils { << "\n"; \ utils::unreachable(); \ } while (false) +#endif #else #define UNREACHABLE() utils::unreachable() // NOLINT(cppcoreguidelines-macro-usage) #endif // NOLINT(cppcoreguidelines-macro-usage) +#if defined(__UEFI__) +#ifdef ASSERT +#undef ASSERT +#endif +#endif + + #if defined(NDEBUG) #define ASSERT(x) (UNUSED(x)) // NOLINT(cppcoreguidelines-macro-usage) #else diff --git a/src/libs/recordings/utility/additional_information.cpp b/src/libs/recordings/utility/additional_information.cpp index e4104f319..698fdaba9 100644 --- a/src/libs/recordings/utility/additional_information.cpp +++ b/src/libs/recordings/utility/additional_information.cpp @@ -6,7 +6,8 @@ #include #include -[[nodiscard]] std::string recorder::InformationValue::to_string(u32 recursion_depth // NOLINT(misc-no-recursion) +[[nodiscard]] std::string recorder::InformationValue::to_string( + u32 recursion_depth // NOLINT(misc-no-recursion) ) const { return std::visit( helper::Overloaded{ @@ -20,12 +21,16 @@ [](const i32& value) { return std::to_string(value); }, [](const u64& value) { return std::to_string(value); }, [](const i64& value) { return std::to_string(value); }, - [recursion_depth](const std::vector& value // NOLINT(misc-no-recursion) + [recursion_depth]( + const std::vector& value // NOLINT(misc-no-recursion) ) { if (recursion_depth >= max_recursion_depth) { - throw std::runtime_error{ fmt::format( - "Reached maximum recursion depth of {} while printing vectors!", max_recursion_depth - ) }; + utils::throw_( + std::runtime_error{ fmt::format( + "Reached maximum recursion depth of {} while printing vectors!", + max_recursion_depth + ) } + ); } std::vector strings{}; @@ -461,7 +466,7 @@ helper::expected recorder::Additio void recorder::AdditionalInformation::add_value(const std::string& key, const InformationValue& value, bool overwrite) { if (m_values.contains(key) and not overwrite) { - throw std::runtime_error("Can't overwrite already existing key"); + utils::throw_(std::runtime_error("Can't overwrite already existing key")); } m_values.insert_or_assign(key, value); @@ -519,8 +524,8 @@ std::optional recorder::AdditionalInformation::get(c return bytes; } -[[nodiscard]] helper::expected recorder::AdditionalInformation::get_checksum( -) const { +[[nodiscard]] helper::expected +recorder::AdditionalInformation::get_checksum() const { Sha256Stream sha256_creator{}; static_assert(sizeof(u32) == 4); diff --git a/src/libs/recordings/utility/additional_information.hpp b/src/libs/recordings/utility/additional_information.hpp index 57fbd06d2..b7912ecf2 100644 --- a/src/libs/recordings/utility/additional_information.hpp +++ b/src/libs/recordings/utility/additional_information.hpp @@ -46,7 +46,7 @@ namespace recorder { template [[nodiscard]] T& as() { if (!is()) { - throw std::runtime_error(fmt::format("Bad cast: can't cast to type '{}' !", typeid(T).name())); + utils::throw_(std::runtime_error(fmt::format("Bad cast: can't cast to type '{}' !", typeid(T).name()))); } return std::get(m_value); @@ -55,7 +55,7 @@ namespace recorder { template [[nodiscard]] const T& as() const { if (!is()) { - throw std::runtime_error(fmt::format("Bad cast: can't cast to type '{}' !", typeid(T).name())); + utils::throw_(std::runtime_error(fmt::format("Bad cast: can't cast to type '{}' !", typeid(T).name()))); } return std::get(m_value); @@ -97,14 +97,14 @@ namespace recorder { return false; } - const auto& other = this->as>(); + const auto& nested_other = this->as>(); - if (other.size() != value.size()) { + if (nested_other.size() != value.size()) { return false; } - for (decltype(other.size()) i = 0; i < other.size(); ++i) { - if (other.at(i) != value.at(i)) { + for (decltype(nested_other.size()) i = 0; i < nested_other.size(); ++i) { + if (nested_other.at(i) != value.at(i)) { return false; } } @@ -180,8 +180,8 @@ namespace recorder { [[nodiscard]] OOPETRIS_RECORDINGS_EXPORTED helper::expected, std::string> to_bytes() const; - [[nodiscard]] OOPETRIS_RECORDINGS_EXPORTED helper::expected get_checksum( - ) const; + [[nodiscard]] OOPETRIS_RECORDINGS_EXPORTED helper::expected + get_checksum() const; // iterator trait using iterator = UnderlyingContainer::iterator; //NOLINT(readability-identifier-naming) diff --git a/src/libs/recordings/utility/helper.hpp b/src/libs/recordings/utility/helper.hpp index d5f362b51..077dafe31 100644 --- a/src/libs/recordings/utility/helper.hpp +++ b/src/libs/recordings/utility/helper.hpp @@ -14,6 +14,7 @@ #include #include + namespace helper { namespace reader { @@ -31,7 +32,7 @@ namespace helper { template [[nodiscard]] ReadResult> read_integral_from_file(std::ifstream& file) { - if (not file) { + if (file.fail()) { return helper::unexpected{ { ReadErrorType::InvalidStream, "failed to read data from file (before reading)" } }; @@ -43,7 +44,7 @@ namespace helper { sizeof(little_endian_data) ); - if (not file) { + if (file.fail()) { return helper::unexpected{ { ReadErrorType::Incomplete, "failed to read data from file (after reading)" } }; @@ -54,7 +55,7 @@ namespace helper { template [[nodiscard]] ReadResult> read_array_from_file(std::ifstream& file) { - if (not file) { + if (file.fail()) { return helper::unexpected{ { ReadErrorType::InvalidStream, "failed to read data from file (before reading)" } }; @@ -69,7 +70,7 @@ namespace helper { result.at(i) = read_data.value(); } - if (not file) { + if (file.fail()) { return helper::unexpected{ { ReadErrorType::Incomplete, "failed to read data from file (after reading)" } }; @@ -80,7 +81,7 @@ namespace helper { template [[nodiscard]] std::optional read_from_istream(std::istream& istream) { - if (not istream) { + if (istream.fail()) { return std::nullopt; } auto value = Integral{}; @@ -89,7 +90,7 @@ namespace helper { sizeof(Integral) ); - if (not istream) { + if (istream.fail()) { return std::nullopt; } @@ -98,7 +99,7 @@ namespace helper { template [[nodiscard]] std::optional> read_array_from_istream(std::istream& istream) { - if (not istream) { + if (istream.fail()) { return std::nullopt; } @@ -111,7 +112,7 @@ namespace helper { result.at(i) = read_data.value(); } - if (not istream) { + if (istream.fail()) { return std::nullopt; } @@ -125,7 +126,7 @@ namespace helper { template helper::expected write_integral_to_file(std::ofstream& file, const Integral data) { - if (not file) { + if (file.fail()) { return helper::unexpected{ fmt::format("failed to write data \"{}\"", data) }; } @@ -141,7 +142,8 @@ namespace helper { } template - helper::expected write_vector_to_file(std::ofstream& file, const std::vector& values) { + helper::expected + write_vector_to_file(std::ofstream& file, const std::vector& values) { helper::expected result{}; for (const auto& value : values) { result = write_integral_to_file(file, value); diff --git a/src/libs/recordings/utility/recording.cpp b/src/libs/recordings/utility/recording.cpp index 7c621ac0f..6a5801145 100644 --- a/src/libs/recordings/utility/recording.cpp +++ b/src/libs/recordings/utility/recording.cpp @@ -4,9 +4,12 @@ #include -recorder::TetrionHeader::TetrionHeader(Random::Seed seed, u32 starting_level) - : seed{ seed }, - starting_level{ starting_level } { } +recorder::TetrionHeader::TetrionHeader( + Random::Seed seed_a, //NOLINT(bugprone-easily-swappable-parameters) + u32 starting_level_a +) + : seed{ seed_a }, + starting_level{ starting_level_a } { } [[nodiscard]] const std::vector& recorder::Recording::tetrion_headers() const { @@ -39,7 +42,7 @@ recorder::TetrionHeader::TetrionHeader(Random::Seed seed, u32 starting_level) const auto information_checksum = information.get_checksum(); if (not information_checksum.has_value()) { - throw std::runtime_error(information_checksum.error()); + utils::throw_(std::runtime_error(information_checksum.error())); } sha256_creator << information_checksum.value(); diff --git a/src/libs/recordings/utility/recording.hpp b/src/libs/recordings/utility/recording.hpp index 2faff8f76..14b32b2ee 100644 --- a/src/libs/recordings/utility/recording.hpp +++ b/src/libs/recordings/utility/recording.hpp @@ -37,7 +37,7 @@ namespace recorder { Random::Seed seed; u32 starting_level; - OOPETRIS_RECORDINGS_EXPORTED TetrionHeader(Random::Seed seed, u32 starting_level); + OOPETRIS_RECORDINGS_EXPORTED TetrionHeader(Random::Seed seed_a, u32 starting_level_a); }; struct Recording { diff --git a/src/libs/recordings/utility/recording_json_wrapper.hpp b/src/libs/recordings/utility/recording_json_wrapper.hpp index 628ff6cbc..ca0dd5a08 100644 --- a/src/libs/recordings/utility/recording_json_wrapper.hpp +++ b/src/libs/recordings/utility/recording_json_wrapper.hpp @@ -11,12 +11,14 @@ #include "./recording_reader.hpp" #include "./tetrion_snapshot.hpp" +//TODO: for ALL json wrappers, make a api, that returns std::optional so that it can work without exceptions +// support nlohmann json per using a tenmoplate type, that make an adl_serializer for all these types! namespace nlohmann { template<> struct adl_serializer { static recorder::InformationValue from_json(const json& /* obj */) { //TODO(Totto): Implement - throw std::runtime_error{ "NOT IMPLEMENTED" }; + utils::throw_(std::runtime_error{ "NOT IMPLEMENTED" }); } static void to_json(json& obj, const recorder::InformationValue& information) { // NOLINT(misc-no-recursion) @@ -40,7 +42,7 @@ namespace nlohmann { struct adl_serializer { static recorder::AdditionalInformation from_json(const json& /* obj */) { //TODO(Totto): Implement - throw std::runtime_error{ "NOT IMPLEMENTED" }; + utils::throw_(std::runtime_error{ "NOT IMPLEMENTED" }); } static void to_json(json& obj, const recorder::AdditionalInformation& information) { @@ -60,14 +62,16 @@ namespace nlohmann { struct adl_serializer { static recorder::TetrionHeader from_json(const json& /* obj */) { //TODO(Totto): Implement - throw std::runtime_error{ "NOT IMPLEMENTED" }; + utils::throw_(std::runtime_error{ "NOT IMPLEMENTED" }); } static void to_json(json& obj, const recorder::TetrionHeader& tetrion_header) { - obj = nlohmann::json::object({ - { "seed", tetrion_header.seed }, - { "starting_level", tetrion_header.starting_level } - }); + obj = nlohmann::json::object( + { + { "seed", tetrion_header.seed }, + { "starting_level", tetrion_header.starting_level } + } + ); } }; @@ -75,7 +79,7 @@ namespace nlohmann { struct adl_serializer { static InputEvent from_json(const json& /* obj */) { //TODO(Totto): Implement - throw std::runtime_error{ "NOT IMPLEMENTED" }; + utils::throw_(std::runtime_error{ "NOT IMPLEMENTED" }); } static void to_json(json& obj, const InputEvent& event) { @@ -88,16 +92,18 @@ namespace nlohmann { struct adl_serializer { static recorder::Record from_json(const json& /* obj */) { //TODO(Totto): Implement - throw std::runtime_error{ "NOT IMPLEMENTED" }; + utils::throw_(std::runtime_error{ "NOT IMPLEMENTED" }); } static void to_json(json& obj, const recorder::Record& record) { - obj = nlohmann::json::object({ - { "tetrion_index", record.tetrion_index }, - { "simulation_step_index", record.simulation_step_index }, - { "event", record.event } - }); + obj = nlohmann::json::object( + { + { "tetrion_index", record.tetrion_index }, + { "simulation_step_index", record.simulation_step_index }, + { "event", record.event } + } + ); } }; @@ -106,14 +112,16 @@ namespace nlohmann { struct adl_serializer> { static shapes::AbstractPoint from_json(const json& /* obj */) { //TODO(Totto): Implement - throw std::runtime_error{ "NOT IMPLEMENTED" }; + utils::throw_(std::runtime_error{ "NOT IMPLEMENTED" }); } static void to_json(json& obj, const shapes::AbstractPoint& point) { - obj = nlohmann::json::object({ - { "x", point.x }, - { "y", point.y } - }); + obj = nlohmann::json::object( + { + { "x", point.x }, + { "y", point.y } + } + ); } }; @@ -122,7 +130,7 @@ namespace nlohmann { struct adl_serializer { static helper::TetrominoType from_json(const json& /* obj */) { //TODO(Totto): Implement - throw std::runtime_error{ "NOT IMPLEMENTED" }; + utils::throw_(std::runtime_error{ "NOT IMPLEMENTED" }); } static void to_json(json& obj, const helper::TetrominoType& type) { @@ -135,14 +143,16 @@ namespace nlohmann { struct adl_serializer { static Mino from_json(const json& /* obj */) { //TODO(Totto): Implement - throw std::runtime_error{ "NOT IMPLEMENTED" }; + utils::throw_(std::runtime_error{ "NOT IMPLEMENTED" }); } static void to_json(json& obj, const Mino& mino) { - obj = nlohmann::json::object({ - { "position", mino.position() }, - { "type", mino.type() } - }); + obj = nlohmann::json::object( + { + { "position", mino.position() }, + { "type", mino.type() } + } + ); } }; @@ -151,7 +161,7 @@ namespace nlohmann { struct adl_serializer { static TetrionSnapshot from_json(const json& /* obj */) { //TODO(Totto): Implement - throw std::runtime_error{ "NOT IMPLEMENTED" }; + utils::throw_(std::runtime_error{ "NOT IMPLEMENTED" }); } static void to_json(json& obj, const TetrionSnapshot& snapshot) { @@ -160,14 +170,16 @@ namespace nlohmann { nlohmann::adl_serializer>::to_json(mino_stack_json, snapshot.mino_stack().minos()); - obj = nlohmann::json::object({ - { "tetrion_index", snapshot.tetrion_index() }, - { "level", snapshot.level() }, - { "score", snapshot.score() }, - { "lines_cleared", snapshot.lines_cleared() }, - { "simulation_step_index", snapshot.simulation_step_index() }, - { "mino_stack", mino_stack_json } - }); + obj = nlohmann::json::object( + { + { "tetrion_index", snapshot.tetrion_index() }, + { "level", snapshot.level() }, + { "score", snapshot.score() }, + { "lines_cleared", snapshot.lines_cleared() }, + { "simulation_step_index", snapshot.simulation_step_index() }, + { "mino_stack", mino_stack_json } + } + ); } }; @@ -176,7 +188,7 @@ namespace nlohmann { struct adl_serializer { static recorder::RecordingReader from_json(const json& /* obj */) { //TODO(Totto): Implement - throw std::runtime_error{ "NOT IMPLEMENTED" }; + utils::throw_(std::runtime_error{ "NOT IMPLEMENTED" }); } static void to_json(json& obj, const recorder::RecordingReader& recording_reader) { @@ -199,13 +211,15 @@ namespace nlohmann { snapshots_json, recording_reader.snapshots() ); - obj = nlohmann::json::object({ - { "version", recorder::Recording::current_supported_version_number }, - { "information", information_json }, - { "tetrion_headers", tetrion_headers_json }, - { "records", records_json }, - { "snapshots", snapshots_json }, - }); + obj = nlohmann::json::object( + { + { "version", recorder::Recording::current_supported_version_number }, + { "information", information_json }, + { "tetrion_headers", tetrion_headers_json }, + { "records", records_json }, + { "snapshots", snapshots_json }, + } + ); } }; } // namespace nlohmann diff --git a/src/libs/recordings/utility/recording_reader.cpp b/src/libs/recordings/utility/recording_reader.cpp index a908ccbe9..077a0adaa 100644 --- a/src/libs/recordings/utility/recording_reader.cpp +++ b/src/libs/recordings/utility/recording_reader.cpp @@ -30,7 +30,7 @@ helper::expected< recorder::RecordingReader::get_header_from_path(const std::filesystem::path& path) { std::ifstream file{ path, std::ios::in | std::ios::binary }; - if (not file) { + if (file.fail()) { return helper::unexpected{ fmt::format("unable to load recording from file \"{}\"", path.string()) }; @@ -210,7 +210,7 @@ helper::expected recorder::RecordingRead [[nodiscard]] helper::reader::ReadResult recorder::RecordingReader::read_tetrion_header_from_file(std::ifstream& file) { - if (not file) { + if (file.fail()) { return helper::unexpected{ { helper::reader::ReadErrorType::InvalidStream, "failed to read data from file" } }; @@ -237,7 +237,7 @@ recorder::RecordingReader::read_tetrion_header_from_file(std::ifstream& file) { [[nodiscard]] helper::reader::ReadResult recorder::RecordingReader::read_record_from_file( std::ifstream& file ) { - if (not file) { + if (file.fail()) { return helper::unexpected{ { helper::reader::ReadErrorType::InvalidStream, "invalid input file stream while trying to read record" } }; diff --git a/src/libs/recordings/utility/tetrion_core_information.hpp b/src/libs/recordings/utility/tetrion_core_information.hpp index 8f7df5a60..44b7662e7 100644 --- a/src/libs/recordings/utility/tetrion_core_information.hpp +++ b/src/libs/recordings/utility/tetrion_core_information.hpp @@ -11,15 +11,15 @@ struct TetrionCoreInformation { MinoStack mino_stack; TetrionCoreInformation( - u8 tetrion_index, // NOLINT(bugprone-easily-swappable-parameters) - u32 level, - u64 score, - u32 lines_cleared, - MinoStack mino_stack + u8 tetrion_index_a, // NOLINT(bugprone-easily-swappable-parameters) + u32 level_a, + u64 score_a, + u32 lines_cleared_a, + MinoStack mino_stack_a ) - : tetrion_index{ tetrion_index }, - level{ level }, - score{ score }, - lines_cleared{ lines_cleared }, - mino_stack{ std::move(mino_stack) } { }; + : tetrion_index{ tetrion_index_a }, + level{ level_a }, + score{ score_a }, + lines_cleared{ lines_cleared_a }, + mino_stack{ std::move(mino_stack_a) } { }; }; diff --git a/src/lobby/api.cpp b/src/lobby/api.cpp index c96924346..3d824015e 100644 --- a/src/lobby/api.cpp +++ b/src/lobby/api.cpp @@ -3,7 +3,10 @@ #include "api.hpp" #include "helper/spdlog_wrapper.hpp" + +#if !defined(__OOPETRIS_HAVE_NO_THREADS) #include +#endif #if !defined(_OOPETRIS_ONLINE_SYSTEM) #error "_OOPETRIS_ONLINE_SYSTEM has to be defined" @@ -15,6 +18,8 @@ #include "./web_client.hpp" #elif _OOPETRIS_ONLINE_SYSTEM == 2 #include "./curl_client.hpp" +#elif _OOPETRIS_ONLINE_SYSTEM == 3 +#include "./uefi_client.hpp" #else #error "_OOPETRIS_ONLINE_SYSTEM has an invalid value" #endif @@ -61,14 +66,23 @@ helper::expected lobby::API::check_reachability() { } lobby::API::API(ServiceProvider* service_provider, const std::string& api_url) - : m_client{ std::make_unique(api_url) }, + : m_client{ + +#if defined(__UEFI__) + oopetris::http::implementation::ActualClient::construct(api_url) +#else + std::make_unique(api_url) + +#endif + + }, m_secret_storage{ std::make_unique(service_provider, secret::KeyringType::User) } { auto value = m_secret_storage->load(token::constants::api_token_key); if (value.has_value()) { if (not this->setup_authentication(value.value().as_string())) { - throw std::runtime_error("Couldn't setup authentication"); + utils::throw_(std::runtime_error("Couldn't setup authentication")); } } else { spdlog::info("API: Key not found, so probably not logged in already: {}", value.error()); @@ -92,7 +106,9 @@ lobby::API::~API() = default; helper::expected lobby::API::get_api(ServiceProvider* service_provider, const std::string& url) { +#if !defined(__OOPETRIS_NO_EXCEPTIONS) try { +#endif API api{ service_provider, url }; @@ -105,9 +121,11 @@ lobby::API::get_api(ServiceProvider* service_provider, const std::string& url) { //TODO(Totto): once version is standard, check here if the version is supported return api; +#if !defined(__OOPETRIS_NO_EXCEPTIONS) } catch (const std::exception& error) { return helper::unexpected{ error.what() }; } +#endif } void lobby::API::check_url( @@ -117,11 +135,19 @@ void lobby::API::check_url( ) { //TODO(Totto): is this done correctly + +#if !defined(__OOPETRIS_HAVE_NO_THREADS) + std::ignore = std::async(std::launch::async, [url, callback = std::move(callback), service_provider] { auto result = lobby::API::get_api(service_provider, url); callback(result.has_value()); }); +#else + auto result = lobby::API::get_api(service_provider, url); + + callback(result.has_value()); +#endif } @@ -238,7 +264,8 @@ helper::expected lobby::API::start_lobby(int lobby_id) { return is_request_ok(res, 204); } -helper::expected lobby::API::create_lobby(const CreateLobbyRequest& arguments +helper::expected lobby::API::create_lobby( + const CreateLobbyRequest& arguments ) { if (not is_authenticated()) { return helper::unexpected{ diff --git a/src/lobby/client.cpp b/src/lobby/client.cpp index 69455c74f..e28456219 100644 --- a/src/lobby/client.cpp +++ b/src/lobby/client.cpp @@ -23,6 +23,13 @@ std::string oopetris::http::status_message([[maybe_unused]] int status) { #include "./curl_client.hpp" +std::string oopetris::http::status_message([[maybe_unused]] int status) { + return "Not Available"; +} +#elif _OOPETRIS_ONLINE_SYSTEM == 3 + +#include "./uefi_client.hpp" + std::string oopetris::http::status_message([[maybe_unused]] int status) { return "Not Available"; } diff --git a/src/lobby/credentials/secret.cpp b/src/lobby/credentials/secret.cpp index 8ea5373c3..b11de0888 100644 --- a/src/lobby/credentials/secret.cpp +++ b/src/lobby/credentials/secret.cpp @@ -1,7 +1,7 @@ #include "./secret.hpp" -#if defined(__linux__) || defined(__ANDROID__) +#if defined(_HAVE_KEYUTILS) #include #include @@ -45,7 +45,8 @@ secret::SecretStorage::SecretStorage(ServiceProvider* service_provider, KeyringT // -1 stands for current uid, 0 stands for: do not create a link to another keyring auto result = keyctl_get_persistent(-1, 0); if (result < 0) { - throw std::runtime_error(fmt::format("Error while getting the persistent keyring: {}", strerror(errno)) + throw std::runtime_error( + fmt::format("Error while getting the persistent keyring: {}", strerror(errno)) ); } @@ -373,7 +374,7 @@ secret::SecretStorage::store(const std::string& key, const Buffer& value, bool u return std::nullopt; } -#elif defined(__CONSOLE__) || defined(__APPLE__) +#elif defined(_SECRET_USE_JSON_FILE) #include "helper/graphic_utils.hpp" #include diff --git a/src/lobby/credentials/secret.hpp b/src/lobby/credentials/secret.hpp index 5d3330977..154b04f33 100644 --- a/src/lobby/credentials/secret.hpp +++ b/src/lobby/credentials/secret.hpp @@ -11,9 +11,24 @@ #include "helper/export_symbols.hpp" #include "manager/service_provider.hpp" -#if defined(__linux__) +#if (defined(__linux__) && !defined(__UEFI__)) || defined(__ANDROID__) +#define _HAVE_KEYUTILS +#endif + +#if defined(_HAVE_KEYUTILS) + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#endif #include + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + + #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) #include @@ -23,6 +38,10 @@ namespace oopetris::secret::details { #endif +#if defined(__CONSOLE__) || defined(__APPLE__) || defined(__UEFI__) +#define _SECRET_USE_JSON_FILE +#endif + namespace secret { enum class KeyringType : u8 { User, Session, Persistent }; @@ -32,9 +51,9 @@ namespace secret { [[maybe_unused]] ServiceProvider* m_service_provider; KeyringType m_type; -#if defined(__linux__) || defined(__ANDROID__) +#if defined(_HAVE_KEYUTILS) key_serial_t m_ring_id; -#elif defined(__CONSOLE__) || defined(__APPLE__) +#elif defined(_SECRET_USE_JSON_FILE) std::string m_file_path; #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) oopetris::secret::details::NCRYPT_PROV_HANDLE m_phProvider; @@ -52,7 +71,8 @@ namespace secret { OOPETRIS_GRAPHICS_EXPORTED SecretStorage(SecretStorage&& other) noexcept; SecretStorage& operator=(SecretStorage&& other) noexcept = delete; - [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED helper::expected load(const std::string& key + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED helper::expected load( + const std::string& key ) const; [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::optional diff --git a/src/lobby/curl_client.cpp b/src/lobby/curl_client.cpp index 22cf92318..5532adab7 100644 --- a/src/lobby/curl_client.cpp +++ b/src/lobby/curl_client.cpp @@ -107,6 +107,7 @@ void oopetris::http::implementation::ActualClient::set_url(const std::string& ur auto [content, content_type] = payload.value(); + //TODO: set content_type m_session->SetBody(cpr::Body{ content }); return TRANSFORM_RESULT(m_session->Post()); @@ -123,7 +124,7 @@ void oopetris::http::implementation::ActualClient::set_url(const std::string& ur } auto [content, content_type] = payload.value(); - + //TODO: set content_type m_session->SetBody(cpr::Body{ content }); return TRANSFORM_RESULT(m_session->Put()); @@ -144,7 +145,7 @@ void oopetris::http::implementation::ActualClient::ResetBearerAuth() { #if CPR_LIBCURL_VERSION_NUM >= 0x073D00 - m_session->SetBearer(cpr::Bearer{""}); + m_session->SetBearer(cpr::Bearer{ "" }); #else m_session->SetHeader(); #endif diff --git a/src/lobby/curl_client.hpp b/src/lobby/curl_client.hpp index 60505fa06..189f6b220 100644 --- a/src/lobby/curl_client.hpp +++ b/src/lobby/curl_client.hpp @@ -4,16 +4,17 @@ #include "./client.hpp" -#if defined(__3DS__) +#if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" +#pragma GCC diagnostic ignored "-Wundef" #endif #include -#if defined(__3DS__) +#if defined(__GNUC__) #pragma GCC diagnostic pop #endif diff --git a/src/lobby/httplib_client.hpp b/src/lobby/httplib_client.hpp index 73a785541..5bb1332c2 100644 --- a/src/lobby/httplib_client.hpp +++ b/src/lobby/httplib_client.hpp @@ -6,6 +6,8 @@ #pragma GCC diagnostic ignored "-Wold-style-cast" #pragma GCC diagnostic ignored "-Warray-bounds" #pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wundef" +#pragma GCC diagnostic ignored "-Wredundant-decls" #elif defined(_MSC_VER) #pragma warning(disable : 4100) #endif diff --git a/src/lobby/meson.build b/src/lobby/meson.build index 5ebbad64b..2b816bb5c 100644 --- a/src/lobby/meson.build +++ b/src/lobby/meson.build @@ -4,6 +4,8 @@ elif online_multiplayer_system == 'httplib' graphics_src_files += files('httplib_client.cpp', 'httplib_client.hpp') elif online_multiplayer_system == 'web' graphics_src_files += files('web_client.cpp', 'web_client.hpp') +elif online_multiplayer_system == 'uefi' + graphics_src_files += files('uefi_client.cpp', 'uefi_client.hpp') else error('Unhandled online_multiplayer_system: \'' + online_multiplayer_system + '\'') endif diff --git a/src/lobby/uefi_client.cpp b/src/lobby/uefi_client.cpp new file mode 100644 index 000000000..e27a7d08e --- /dev/null +++ b/src/lobby/uefi_client.cpp @@ -0,0 +1,451 @@ + +#include "./uefi_client.hpp" +#include "helper/uefi_utils.hpp" + +#include +#include + + +extern "C" { +#include +#include +#include +} + +#include + +#define TRANSFORM_RESULT(result) \ + std::make_unique((result).first, (result).second) //NOLINT(cppcoreguidelines-macro-usage + +namespace { + + using HttpHeaders = oopetris::http::implementation::details::HttpHeaders; + + [[nodiscard]] int map_status_code_enum(EFI_HTTP_STATUS_CODE code) { + switch (code) { + case HTTP_STATUS_UNSUPPORTED_STATUS: + return -1; + case HTTP_STATUS_100_CONTINUE: + return 100; + case HTTP_STATUS_101_SWITCHING_PROTOCOLS: + return 101; + case HTTP_STATUS_200_OK: + return 200; + case HTTP_STATUS_201_CREATED: + return 201; + case HTTP_STATUS_202_ACCEPTED: + return 202; + case HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION: + return 203; + case HTTP_STATUS_204_NO_CONTENT: + return 204; + case HTTP_STATUS_205_RESET_CONTENT: + return 205; + case HTTP_STATUS_206_PARTIAL_CONTENT: + return 206; + case HTTP_STATUS_300_MULTIPLE_CHOICES: + return 300; + case HTTP_STATUS_301_MOVED_PERMANENTLY: + return 301; + case HTTP_STATUS_302_FOUND: + return 302; + case HTTP_STATUS_303_SEE_OTHER: + return 303; + case HTTP_STATUS_304_NOT_MODIFIED: + return 304; + case HTTP_STATUS_305_USE_PROXY: + return 305; + case HTTP_STATUS_307_TEMPORARY_REDIRECT: + return 307; + case HTTP_STATUS_400_BAD_REQUEST: + return 400; + case HTTP_STATUS_401_UNAUTHORIZED: + return 401; + case HTTP_STATUS_402_PAYMENT_REQUIRED: + return 402; + case HTTP_STATUS_403_FORBIDDEN: + return 403; + case HTTP_STATUS_404_NOT_FOUND: + return 404; + case HTTP_STATUS_405_METHOD_NOT_ALLOWED: + return 405; + case HTTP_STATUS_406_NOT_ACCEPTABLE: + return 406; + case HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED: + return 407; + case HTTP_STATUS_408_REQUEST_TIME_OUT: + return 408; + case HTTP_STATUS_409_CONFLICT: + return 409; + case HTTP_STATUS_410_GONE: + return 410; + case HTTP_STATUS_411_LENGTH_REQUIRED: + return 411; + case HTTP_STATUS_412_PRECONDITION_FAILED: + return 412; + case HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE: + return 413; + case HTTP_STATUS_414_REQUEST_URI_TOO_LARGE: + return 414; + case HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE: + return 415; + case HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED: + return 416; + case HTTP_STATUS_417_EXPECTATION_FAILED: + return 417; + case HTTP_STATUS_500_INTERNAL_SERVER_ERROR: + return 500; + case HTTP_STATUS_501_NOT_IMPLEMENTED: + return 501; + case HTTP_STATUS_502_BAD_GATEWAY: + return 502; + case HTTP_STATUS_503_SERVICE_UNAVAILABLE: + return 503; + case HTTP_STATUS_504_GATEWAY_TIME_OUT: + return 504; + case HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED: + return 505; + case HTTP_STATUS_308_PERMANENT_REDIRECT: + return 308; + case HTTP_STATUS_429_TOO_MANY_REQUESTS: + return 429; + default: + return -1; + } + } + + +} // namespace + +oopetris::http::implementation::ActualResult::ActualResult( + HTTP_IO_RESPONSE_DATA&& response, + std::unique_ptr&& io +) + : m_response{ std::move(response) }, + m_io{ std::move(io) } { } + + +oopetris::http::implementation::ActualResult::~ActualResult() { + if (m_io == nullptr) { + HttpIoDestroyIo(m_io.get()); + m_io = nullptr; + } +}; + + +oopetris::http::implementation::ActualResult::ActualResult(ActualResult&& other) noexcept + : m_response{ std::move(other.m_response) }, + m_io{ std::move(other.m_io) } { + other.m_io = nullptr; +} + +[[nodiscard]] std::optional oopetris::http::implementation::ActualResult::get_header( + const std::string& key +) const { + for (size_t i = 0; i < m_response.HeaderCount; ++i) { + const EFI_HTTP_HEADER& header = m_response.Headers[i]; + if (header.FieldName == key) { + return std::string{ header.FieldValue }; + } + } + + return std::nullopt; +} + +[[nodiscard]] std::string oopetris::http::implementation::ActualResult::body() const { + + if (m_response.Body == nullptr) { + return ""; + } + + + std::string result{ m_response.Body, m_response.Body + m_response.BodyLength }; + + return result; +} + +[[nodiscard]] int oopetris::http::implementation::ActualResult::status() const { + return map_status_code_enum(m_response.Response.StatusCode); +} + +[[nodiscard]] std::optional oopetris::http::implementation::ActualResult::get_error() const { + + + if (m_response.Status != EFI_SUCCESS) { + return fmt::format("Invalid EFI status: {}", uefi::map_efi_status_to_string(m_response.Status)); + } + + return std::nullopt; +} + +namespace { + using HttpData = std::pair; + using RequestResponse = std::pair>; + + std::string normalize_url(const std::string& value) { + if (value.ends_with("/")) { + return value.substr(0, value.size() - 1); + } + + return value; + } + + std::string concat_url(const std::string& normalized_base, const std::string& value) { + if (value.starts_with("/")) { + return normalized_base + value; + } + + return normalized_base + "/" + value; + } + + CHAR16* ToChar16(const std::string& Str) { + CHAR16* Result = (CHAR16*) AllocateZeroPool((Str.size() + 1) * sizeof(CHAR16)); + + if (Result == nullptr) { + return nullptr; + } + + for (size_t i = 0; i < Str.size(); ++i) { + Result[i] = (CHAR16) (UINT8) Str[i]; + } + + return Result; + } + + RequestResponse make_request_impl( + EFI_HTTP_METHOD method, + const std::string& url, + const HttpHeaders& header, + const std::optional& data, + EFI_HANDLE image_handle, + EFI_HANDLE controller_handle + ) { + + + std::unique_ptr HttpIo = std::make_unique(); + HTTP_IO_CONFIG_DATA ConfigData; + EFI_HTTP_REQUEST_DATA Request; + + HTTP_IO_RESPONSE_DATA Response; + + ZeroMem(HttpIo.get(), sizeof(HttpIo)); + ZeroMem(&ConfigData, sizeof(ConfigData)); + ZeroMem(&Request, sizeof(Request)); + ZeroMem(&Response, sizeof(Response)); + + + ConfigData.Config4.HttpVersion = HttpVersion11; + ConfigData.Config4.RequestTimeOut = 5000; + ConfigData.Config4.ResponseTimeOut = 5000; + ConfigData.Config4.UseDefaultAddress = TRUE; + ConfigData.Config4.LocalPort = 0; + + EFI_STATUS Status = + HttpIoCreateIo(image_handle, controller_handle, IP_VERSION_4, &ConfigData, NULL, NULL, HttpIo.get()); + if (EFI_ERROR(Status)) { + Response.Status = Status; + return RequestResponse{ Response, std::move(HttpIo) }; + } + + Request.Method = method; + Request.Url = ToChar16(url.c_str()); + + if (Request.Url == nullptr) { + Response.Status = EFI_OUT_OF_RESOURCES; + return RequestResponse{ Response, std::move(HttpIo) }; + } + + std::vector raw_headers{}; + for (const auto& [key, value] : header) { + raw_headers.push_back(EFI_HTTP_HEADER{ strdup(key.c_str()), strdup(value.c_str()) }); + } + + + UINTN BodyLength = 0; + VOID* Body = NULL; + + if (data.has_value()) { + const auto& [mime_type, raw_data] = data.value(); + + Body = const_cast(raw_data.data()); + BodyLength = raw_data.size(); + raw_headers.push_back(EFI_HTTP_HEADER{ strdup("Content-Type"), strdup(mime_type.c_str()) }); + } + + UINTN HeaderCount = raw_headers.size(); + EFI_HTTP_HEADER* Headers = raw_headers.data(); + + Status = HttpIoSendRequest(HttpIo.get(), &Request, HeaderCount, Headers, BodyLength, Body); + if (EFI_ERROR(Status)) { + Response.Status = Status; + return RequestResponse{ Response, std::move(HttpIo) }; + } + + //TODO: I am not sure who allocates the body here? do in eed to set bodylength and allocate body and make this call again with FALSE and new space? + + Status = HttpIoRecvResponse(HttpIo.get(), TRUE, &Response); + if (EFI_ERROR(Status)) { + Response.Status = Status; + return RequestResponse{ Response, std::move(HttpIo) }; + } + + for (const auto& raw_header : raw_headers) { + free(raw_header.FieldName); + free(raw_header.FieldValue); + } + + FreePool(Request.Url); + + + return RequestResponse{ Response, std::move(HttpIo) }; + } + + RequestResponse make_request( + EFI_HTTP_METHOD method, + const std::string& url, + const HttpHeaders& header, + EFI_HANDLE image_handle, + EFI_HANDLE controller_handle + ) { + return make_request_impl(method, url, header, std::nullopt, image_handle, controller_handle); + } + + RequestResponse make_request_with_data( + EFI_HTTP_METHOD method, + const std::string& url, + const HttpHeaders& header, + const HttpData& data, + EFI_HANDLE image_handle, + EFI_HANDLE controller_handle + ) { + return make_request_impl(method, url, header, data, image_handle, controller_handle); + } +} // namespace + + +oopetris::http::implementation::ActualClient::ActualClient(ActualClient&& other) noexcept + : m_base_url{ std::move(other.m_base_url) }, + m_headers{ std::move(other.m_headers) }, + m_image_handle{ std::move(other.m_image_handle) }, + m_controller_handle{ std::move(other.m_controller_handle) } { } + +oopetris::http::implementation::ActualClient::~ActualClient() = default; + +oopetris::http::implementation::ActualClient::ActualClient( + const std::string& api_url, + EFI_HANDLE image_handle, + EFI_HANDLE controller_handle +) + : m_base_url{ normalize_url(api_url) }, + m_headers{}, + m_image_handle{ image_handle }, + m_controller_handle{ controller_handle } { + + //NOTE: no Accept header or compression is set here, as uefi http request doesn't support gzip (at least I think it doesn#t support it) +} + +static EFI_STATUS FindNetworkController(OUT EFI_HANDLE* Controller) { + EFI_HANDLE* Handles = NULL; + UINTN HandleCount = 0; + + if (!gBS) { + return EFI_NOT_READY; + } + + EFI_STATUS Status = gBS->LocateHandleBuffer( + ByProtocol, &gEfiManagedNetworkServiceBindingProtocolGuid, NULL, &HandleCount, &Handles + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + if (HandleCount == 0) { + FreePool(Handles); + return EFI_NOT_FOUND; + } + + // + // For now, just use the first network controller. + // + *Controller = Handles[0]; + + FreePool(Handles); + + return EFI_SUCCESS; +} + +OOPETRIS_GRAPHICS_EXPORTED std::unique_ptr +oopetris::http::implementation::ActualClient::construct(const std::string& api_url) { + EFI_HANDLE controller_handle = nullptr; + EFI_STATUS status = FindNetworkController(&controller_handle); + + if (EFI_ERROR(status)) { + utils::throw_( + std::runtime_error{ + fmt::format("couldn't get network controller: {}", uefi::map_efi_status_to_string(status)) } + ); + } + + return std::make_unique(api_url, gImageHandle, controller_handle); +} + +[[nodiscard]] std::unique_ptr oopetris::http::implementation::ActualClient::Get( + const std::string& url +) { + + const auto final_url = concat_url(m_base_url, url); + + return TRANSFORM_RESULT(make_request(HttpMethodGet, final_url, m_headers, m_image_handle, m_controller_handle)); +} + +[[nodiscard]] std::unique_ptr oopetris::http::implementation::ActualClient::Delete( + const std::string& url +) { + const auto final_url = concat_url(m_base_url, url); + + return TRANSFORM_RESULT(make_request(HttpMethodDelete, final_url, m_headers, m_image_handle, m_controller_handle)); +} + +[[nodiscard]] std::unique_ptr oopetris::http::implementation::ActualClient::Post( + const std::string& url, + const std::optional>& payload +) { + const auto final_url = concat_url(m_base_url, url); + + if (not payload.has_value()) { + return TRANSFORM_RESULT( + make_request(HttpMethodPost, final_url, m_headers, m_image_handle, m_controller_handle) + ); + } + + return TRANSFORM_RESULT(make_request_with_data( + HttpMethodPost, final_url, m_headers, payload.value(), m_image_handle, m_controller_handle + )); +} + +[[nodiscard]] std::unique_ptr oopetris::http::implementation::ActualClient::Put( + const std::string& url, + const std::optional>& payload +) { + const auto final_url = concat_url(m_base_url, url); + + if (not payload.has_value()) { + return TRANSFORM_RESULT(make_request(HttpMethodPut, final_url, m_headers, m_image_handle, m_controller_handle)); + } + + + return TRANSFORM_RESULT(make_request_with_data( + HttpMethodPut, final_url, m_headers, payload.value(), m_image_handle, m_controller_handle + )); +} + +void oopetris::http::implementation::ActualClient::SetBearerAuth(const std::string& token) { + + m_headers.at("Authorization") = fmt::format("Bearer {}", token); +} + +void oopetris::http::implementation::ActualClient::ResetBearerAuth() { + + m_headers.erase("Authorization"); +} diff --git a/src/lobby/uefi_client.hpp b/src/lobby/uefi_client.hpp new file mode 100644 index 000000000..e9f924000 --- /dev/null +++ b/src/lobby/uefi_client.hpp @@ -0,0 +1,124 @@ + +#pragma once + + +#if defined(__GNUC__) +#pragma GCC diagnostic push +//TODO +//#pragma GCC diagnostic ignored "-fpermissive" + +#endif + +extern "C" { +#include + + +//this is needed to mix stdlib and openssl / crypto / tls libraries + +#undef NTOHL +#undef HTONL +#undef NTOHS +#undef HTONS + +#include +} + +//this is needed to mix stdlib and openssl / crypto / tls libraries + +#undef NTOHL +#undef HTONL +#undef NTOHS +#undef HTONS + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + + +#include "./client.hpp" + +#include +#include + +namespace oopetris::http::implementation { + namespace details { + using HttpHeaders = std::unordered_map; + } // namespace details + + + struct ActualResult : ::oopetris::http::Result { + private: + HTTP_IO_RESPONSE_DATA m_response; + std::unique_ptr m_io; + + + public: + OOPETRIS_GRAPHICS_EXPORTED explicit ActualResult( + HTTP_IO_RESPONSE_DATA&& response, + std::unique_ptr&& io + ); + + OOPETRIS_GRAPHICS_EXPORTED ~ActualResult() override; + + OOPETRIS_GRAPHICS_EXPORTED ActualResult(ActualResult&& other) noexcept; + OOPETRIS_GRAPHICS_EXPORTED ActualResult& operator=(ActualResult&& other) noexcept = delete; + + OOPETRIS_GRAPHICS_EXPORTED ActualResult(const ActualResult& other) = delete; + OOPETRIS_GRAPHICS_EXPORTED ActualResult& operator=(const ActualResult& other) = delete; + + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::optional get_header( + const std::string& key + ) const override; + + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::string body() const override; + + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED int status() const override; + + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::optional get_error() const override; + }; + + + struct ActualClient : ::oopetris::http::Client { + + private: + std::string m_base_url; + details::HttpHeaders m_headers; + EFI_HANDLE m_image_handle; + EFI_HANDLE m_controller_handle; + + public: + OOPETRIS_GRAPHICS_EXPORTED ActualClient(ActualClient&& other) noexcept; + OOPETRIS_GRAPHICS_EXPORTED ActualClient& operator=(ActualClient&& other) noexcept = delete; + + OOPETRIS_GRAPHICS_EXPORTED ActualClient(const ActualClient& other) = delete; + OOPETRIS_GRAPHICS_EXPORTED ActualClient& operator=(const ActualClient& other) = delete; + + OOPETRIS_GRAPHICS_EXPORTED ~ActualClient() override; + + OOPETRIS_GRAPHICS_EXPORTED explicit ActualClient( + const std::string& api_url, + EFI_HANDLE image_handle, + EFI_HANDLE controller_handle + ); + + OOPETRIS_GRAPHICS_EXPORTED static std::unique_ptr construct( + const std::string& api_url + ); + + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::unique_ptr Get(const std::string& url) override; + + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::unique_ptr Delete(const std::string& url) override; + + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::unique_ptr + Post(const std::string& url, const std::optional>& payload) override; + + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::unique_ptr + Put(const std::string& url, const std::optional>& payload) override; + + OOPETRIS_GRAPHICS_EXPORTED void SetBearerAuth(const std::string& token) override; + + OOPETRIS_GRAPHICS_EXPORTED void ResetBearerAuth() override; + }; + + +} // namespace oopetris::http::implementation diff --git a/src/lobby/web_client.cpp b/src/lobby/web_client.cpp index bac2dac31..38e1bdfbc 100644 --- a/src/lobby/web_client.cpp +++ b/src/lobby/web_client.cpp @@ -89,7 +89,8 @@ oopetris::http::implementation::ActualResult::ActualResult(ActualResult&& other) : m_request{ std::move(other.m_request) }, m_response_headers{ std::move(other.m_response_headers) } { } -[[nodiscard]] std::optional oopetris::http::implementation::ActualResult::get_header(const std::string& key +[[nodiscard]] std::optional oopetris::http::implementation::ActualResult::get_header( + const std::string& key ) const { if (m_response_headers.contains(key)) { return std::nullopt; @@ -239,8 +240,6 @@ oopetris::http::implementation::ActualClient::ActualClient(const std::string& ap return TRANSFORM_RESULT(make_request("POST", final_url, m_headers)); } - auto [content, content_type] = payload.value(); - return TRANSFORM_RESULT(make_request_with_data("POST", final_url, m_headers, payload.value())); } @@ -254,8 +253,6 @@ oopetris::http::implementation::ActualClient::ActualClient(const std::string& ap return TRANSFORM_RESULT(make_request("PUT", final_url, m_headers)); } - auto [content, content_type] = payload.value(); - return TRANSFORM_RESULT(make_request_with_data("PUT", final_url, m_headers, payload.value())); } diff --git a/src/manager/font.cpp b/src/manager/font.cpp index 6f04ff077..949bf0df9 100644 --- a/src/manager/font.cpp +++ b/src/manager/font.cpp @@ -13,7 +13,7 @@ Font::Font(const std::filesystem::path& path, int size) if (not std::filesystem::exists(path)) { error = "path '" + path.string() + "' doesn't exist!"; } - throw FontLoadingError{ "error loading font: '" + error + "'" }; + utils::throw_(FontLoadingError{ "error loading font: '" + error + "'" }); } } diff --git a/src/manager/font.hpp b/src/manager/font.hpp index af721268a..71b13b065 100644 --- a/src/manager/font.hpp +++ b/src/manager/font.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include diff --git a/src/manager/music_manager.cpp b/src/manager/music_manager.cpp index 5c9eee526..e8be670f8 100644 --- a/src/manager/music_manager.cpp +++ b/src/manager/music_manager.cpp @@ -28,15 +28,23 @@ MusicManager::MusicManager(ServiceProvider* service_provider, u8 channel_size) return; } +#if defined(__UEFI__) + SDL_SetHint(SDL_HINT_AUDIODRIVER, "dummy"); +#endif + const auto result = SDL_InitSubSystem(SDL_INIT_AUDIO); if (result != 0) { - throw helper::InitializationError{ fmt::format("Failed to initialize the audio system: {}", SDL_GetError()) }; + utils::throw_( + helper::InitializationError{ fmt::format("Failed to initialize the audio system: {}", SDL_GetError()) } + ); } //TODO(Totto): dynamically handle codecs const auto initialized_codecs = Mix_Init(MIX_INIT_FLAC | MIX_INIT_MP3); if (initialized_codecs == 0) { - throw helper::InitializationError{ fmt::format("Failed to initialize any audio codec: {}", SDL_GetError()) }; + utils::throw_( + helper::InitializationError{ fmt::format("Failed to initialize any audio codec: {}", SDL_GetError()) } + ); } // retrieve allocated channels @@ -49,16 +57,20 @@ MusicManager::MusicManager(ServiceProvider* service_provider, u8 channel_size) // see: https://wiki.libsdl.org/SDL2_mixer/Mix_AllocateChannels auto newly_allocated_channels = Mix_AllocateChannels(channel_size); if (newly_allocated_channels != channel_size) { - throw helper::InitializationError{ fmt::format( - "Failed to initialize the requested channels, requested {} but only got {}: {}", channel_size, - newly_allocated_channels, SDL_GetError() - ) }; + utils::throw_( + helper::InitializationError{ fmt::format( + "Failed to initialize the requested channels, requested {} but only got {}: {}", + channel_size, newly_allocated_channels, SDL_GetError() + ) } + ); } } #if defined(__EMSCRIPTEN__) //TODO: do we need this, first do this: // https://github.com/libsdl-org/SDL/issues/6385 +#elif defined(__UEFI__) +// do nothing #else const auto audio_channels = 2; @@ -69,7 +81,7 @@ MusicManager::MusicManager(ServiceProvider* service_provider, u8 channel_size) if (audio_result != 0) { - throw helper::InitializationError{ fmt::format("Failed to open an audio device: {}", SDL_GetError()) }; + utils::throw_(helper::InitializationError{ fmt::format("Failed to open an audio device: {}", SDL_GetError()) }); } #endif @@ -238,7 +250,7 @@ void MusicManager::hook_music_finished() { } if (m_queued_music == nullptr) { - throw std::runtime_error{ "implementation error: m_queued_music is null but it shouldn't be" }; + utils::throw_(std::runtime_error{ "implementation error: m_queued_music is null but it shouldn't be" }); } if (m_music != nullptr) { @@ -247,8 +259,10 @@ void MusicManager::hook_music_finished() { const int result = Mix_FadeInMusic(m_queued_music, -1, static_cast(m_delay)); if (result != 0) { - throw std::runtime_error( - "an error occurred while trying to play the music (fading in): " + std::string{ Mix_GetError() } + utils::throw_( + std::runtime_error( + "an error occurred while trying to play the music (fading in): " + std::string{ Mix_GetError() } + ) ); } m_music = m_queued_music; @@ -313,8 +327,10 @@ void MusicManager::set_volume( if (m_music != nullptr) { const int result = Mix_PlayMusic(m_music, -1); if (result != 0) { - throw std::runtime_error( - "an error occurred while trying to play the music: " + std::string{ Mix_GetError() } + utils::throw_( + std::runtime_error( + "an error occurred while trying to play the music: " + std::string{ Mix_GetError() } + ) ); } } diff --git a/src/manager/sdl_controller_key.cpp b/src/manager/sdl_controller_key.cpp index 7655879aa..d72b0d9ed 100644 --- a/src/manager/sdl_controller_key.cpp +++ b/src/manager/sdl_controller_key.cpp @@ -1,6 +1,7 @@ #include "sdl_controller_key.hpp" +#include sdl::ControllerKey::ControllerKey(SDL_GameControllerButton button) : m_button{ button } { } @@ -25,10 +26,14 @@ helper::expected sdl::ControllerKey::from_strin const auto* name = SDL_GameControllerGetStringForButton(m_button); if (name == nullptr or std::strlen(name) == 0) { - throw std::runtime_error(fmt::format( - "No name for the SDL key {}: {}", static_cast>(m_button), - SDL_GetError() - )); + utils::throw_( + std::runtime_error( + fmt::format( + "No name for the SDL key {}: {}", + static_cast>(m_button), SDL_GetError() + ) + ) + ); } return std::string{ name }; } diff --git a/src/manager/sdl_key.cpp b/src/manager/sdl_key.cpp index a5e6e20da..b542cea75 100644 --- a/src/manager/sdl_key.cpp +++ b/src/manager/sdl_key.cpp @@ -151,10 +151,14 @@ namespace { [[nodiscard]] std::string sdl_key_name(SDL_KeyCode keycode) { const auto* name = SDL_GetKeyName(keycode); if (name == nullptr or std::strlen(name) == 0) { - throw std::runtime_error(fmt::format( - "No name for the SDL key {}: {}", static_cast>(keycode), - SDL_GetError() - )); + utils::throw_( + std::runtime_error( + fmt::format( + "No name for the SDL key {}: {}", + static_cast>(keycode), SDL_GetError() + ) + ) + ); } return std::string{ name }; } diff --git a/src/manager/sdl_key.hpp b/src/manager/sdl_key.hpp index 899245e61..c4b07a5d9 100644 --- a/src/manager/sdl_key.hpp +++ b/src/manager/sdl_key.hpp @@ -98,13 +98,14 @@ namespace sdl { * @param ignore_special_modifiers * @return bool */ - [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED bool is_equal(const Key& other, bool ignore_special_modifiers = true) - const; + [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED bool + is_equal(const Key& other, bool ignore_special_modifiers = true) const; [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED std::string to_string() const; private: - [[nodiscard]] static helper::expected sdl_keycode_from_string(const std::string& value + [[nodiscard]] static helper::expected sdl_keycode_from_string( + const std::string& value ); [[nodiscard]] static UnderlyingModifierType sdl_modifier_from_modifiers(const std::vector& modifiers); diff --git a/src/manager/settings.hpp b/src/manager/settings.hpp index 425baf8a3..b8a36ca48 100644 --- a/src/manager/settings.hpp +++ b/src/manager/settings.hpp @@ -36,7 +36,7 @@ namespace nlohmann { return Controls{ nlohmann::adl_serializer::from_json(obj) }; } - throw std::runtime_error{ fmt::format("unsupported control type '{}'", to_string(type)) }; + utils::throw_(std::runtime_error{ fmt::format("unsupported control type '{}'", to_string(type)) }); } static void to_json(json& obj, Controls controls) { // NOLINT(misc-no-recursion) diff --git a/src/scenes/main_menu/main_menu.cpp b/src/scenes/main_menu/main_menu.cpp index 931c90c66..03c0ae109 100644 --- a/src/scenes/main_menu/main_menu.cpp +++ b/src/scenes/main_menu/main_menu.cpp @@ -10,10 +10,16 @@ namespace scenes { - MainMenu::MainMenu(ServiceProvider* service_provider, const ui::Layout& layout) - : Scene{service_provider, layout}, - m_main_grid{ 0,6,ui::Direction::Vertical, ui::RelativeMargin{layout,ui::Direction::Vertical, 0.05}, std::pair{ 0.05, 0.05 - } ,ui::RelativeLayout{ layout, 0.0, 0.1, 1.0, 0.8 }} { + MainMenu::MainMenu(ServiceProvider* service_provider, const ui::Layout& layout) + : Scene{ + service_provider, layout + }, + m_main_grid{ 0, + 6, + ui::Direction::Vertical, + ui::RelativeMargin{ layout, ui::Direction::Vertical, 0.05 }, + std::pair{ 0.05, 0.05 }, + ui::RelativeLayout{ layout, 0.0, 0.1, 1.0, 0.8 } } { auto focus_helper = ui::FocusHelper{ 1 }; @@ -99,11 +105,13 @@ namespace scenes { #endif - service_provider->music_manager() - .load_and_play_music( - utils::get_assets_folder() / "music" / utils::get_supported_music_extension("01. Main Menu") - ) - .and_then(utils::log_error); + auto _ignore = service_provider->music_manager() + .load_and_play_music( + utils::get_assets_folder() / "music" + / utils::get_supported_music_extension("01. Main Menu") + ) + .and_then(utils::log_error); + UNUSED(_ignore); } [[nodiscard]] Scene::UpdateResult MainMenu::update() { diff --git a/src/scenes/online_lobby/online_lobby.cpp b/src/scenes/online_lobby/online_lobby.cpp index 072f33402..12ee92b07 100644 --- a/src/scenes/online_lobby/online_lobby.cpp +++ b/src/scenes/online_lobby/online_lobby.cpp @@ -17,16 +17,16 @@ namespace scenes { OnlineLobby::OnlineLobby(ServiceProvider* service_provider, const ui::Layout& layout) - : Scene{ service_provider, layout }, - m_main_layout{ - utils::SizeIdentity<3>(), - 0, - ui::Direction::Vertical, - { 0.1, 0.9 }, - ui::AbsolutMargin{ 10 }, - std::pair{ 0.05, 0.03 }, - layout - } { + : Scene{ + service_provider, layout + }, + m_main_layout{ utils::SizeIdentity<3>(), + 0, + ui::Direction::Vertical, + { 0.1, 0.9 }, + ui::AbsolutMargin{ 10 }, + std::pair{ 0.05, 0.03 }, + layout } { auto focus_helper = ui::FocusHelper{ 1 }; m_main_layout.add( @@ -134,11 +134,13 @@ namespace scenes { } - throw std::runtime_error("Requested action on unknown widget, this is a fatal error"); + utils::throw_(std::runtime_error("Requested action on unknown widget, this is a fatal error")); } - throw helper::FatalError( - fmt::format("Unsupported Handle Type: {}", magic_enum::enum_name(additional->first)) + utils::throw_( + helper::FatalError( + fmt::format("Unsupported Handle Type: {}", magic_enum::enum_name(additional->first)) + ) ); } diff --git a/src/scenes/recording_selector/recording_selector.cpp b/src/scenes/recording_selector/recording_selector.cpp index 9f82116bf..cc5cbbaaf 100644 --- a/src/scenes/recording_selector/recording_selector.cpp +++ b/src/scenes/recording_selector/recording_selector.cpp @@ -28,16 +28,16 @@ namespace scenes { using namespace details::recording::selector; //NOLINT(google-build-using-namespace) RecordingSelector::RecordingSelector(ServiceProvider* service_provider, const ui::Layout& layout) - : Scene{ service_provider, layout }, - m_main_layout{ - utils::SizeIdentity<3>(), - 0, - ui::Direction::Vertical, - { 0.1, 0.9 }, - ui::AbsolutMargin{ 10 }, - std::pair{ 0.05, 0.03 }, - layout - } { + : Scene{ + service_provider, layout + }, + m_main_layout{ utils::SizeIdentity<3>(), + 0, + ui::Direction::Vertical, + { 0.1, 0.9 }, + ui::AbsolutMargin{ 10 }, + std::pair{ 0.05, 0.03 }, + layout } { auto focus_helper = ui::FocusHelper{ 1 }; @@ -118,7 +118,9 @@ namespace scenes { } #endif - throw std::runtime_error("Requested action on unknown widget, this is a fatal error"); + utils::throw_( + std::runtime_error("Requested action on unknown widget, this is a fatal error") + ); } }, m_next_command.value().m_value ); diff --git a/src/scenes/replay_game/replay_game.cpp b/src/scenes/replay_game/replay_game.cpp index 15b02e28e..d0fdf4e7d 100644 --- a/src/scenes/replay_game/replay_game.cpp +++ b/src/scenes/replay_game/replay_game.cpp @@ -25,7 +25,7 @@ namespace scenes { layouts.reserve(parameters.size()); if (parameters.empty()) { - throw std::runtime_error("An empty recording file isn't supported"); + utils::throw_(std::runtime_error("An empty recording file isn't supported")); } else if (parameters.size() == 1) { // NOLINT(readability-else-after-return,llvm-else-after-return) layouts.push_back(ui::RelativeLayout{ layout, 0.02, 0.01, 0.96, 0.98 }); } else if (parameters.size() == 2) { @@ -34,7 +34,7 @@ namespace scenes { } else { //TODO(Totto): support bigger layouts than just 2 - throw std::runtime_error("At the moment only replays from up to two players are supported"); + utils::throw_(std::runtime_error("At the moment only replays from up to two players are supported")); } u32 simulation_frequency = constants::simulation_frequency; @@ -47,9 +47,12 @@ namespace scenes { for (decltype(parameters.size()) i = 0; i < parameters.size(); ++i) { auto [input, starting_parameters] = std::move(parameters.at(i)); - m_games.emplace_back(std::make_unique( - service_provider, std::move(input), starting_parameters, simulation_frequency, layouts.at(i), false - )); + m_games.emplace_back( + std::make_unique( + service_provider, std::move(input), starting_parameters, simulation_frequency, + layouts.at(i), false + ) + ); } @@ -67,11 +70,13 @@ namespace scenes { #endif - m_service_provider->music_manager() - .load_and_play_music( - utils::get_assets_folder() / "music" / utils::get_supported_music_extension("02. Game Theme") - ) - .and_then(utils::log_error); + auto _ignore = m_service_provider->music_manager() + .load_and_play_music( + utils::get_assets_folder() / "music" + / utils::get_supported_music_extension("02. Game Theme") + ) + .and_then(utils::log_error); + UNUSED(_ignore); } diff --git a/src/scenes/scene.cpp b/src/scenes/scene.cpp index 0e2cc5512..18128c421 100644 --- a/src/scenes/scene.cpp +++ b/src/scenes/scene.cpp @@ -46,7 +46,7 @@ namespace scenes { case SceneId::AchievementsPage: return std::make_unique(&service_provider, layout); */ default: - throw std::runtime_error("Not implemented ID"); + utils::throw_(std::runtime_error("Not implemented ID")); } } diff --git a/src/scenes/scene.hpp b/src/scenes/scene.hpp index 407782c46..55a2f68be 100644 --- a/src/scenes/scene.hpp +++ b/src/scenes/scene.hpp @@ -31,27 +31,27 @@ namespace scenes { std::string name; std::unique_ptr scene; - RawSwitch(std::string name, std::unique_ptr&& scene) - : name{ std::move(name) }, - scene{ std::move(scene) } { } + RawSwitch(std::string name_a, std::unique_ptr&& scene_a) + : name{ std::move(name_a) }, + scene{ std::move(scene_a) } { } }; struct Push { SceneId target_scene; ui::Layout layout; - Push(const SceneId target_scene, const ui::Layout& layout) - : target_scene{ target_scene }, - layout{ layout } { } + Push(const SceneId target_scene_a, const ui::Layout& layout_a) + : target_scene{ target_scene_a }, + layout{ layout_a } { } }; struct RawPush { std::string name; std::unique_ptr scene; - RawPush(std::string name, std::unique_ptr&& scene) - : name{ std::move(name) }, - scene{ std::move(scene) } { } + RawPush(std::string name_a, std::unique_ptr&& scene_a) + : name{ std::move(name_a) }, + scene{ std::move(scene_a) } { } }; struct Pop { }; diff --git a/src/scenes/settings_menu/color_setting_row.cpp b/src/scenes/settings_menu/color_setting_row.cpp index cfe8d9812..98bb71329 100644 --- a/src/scenes/settings_menu/color_setting_row.cpp +++ b/src/scenes/settings_menu/color_setting_row.cpp @@ -91,8 +91,14 @@ detail::ColorPickerScene::ColorPickerScene( ) : Scene{ service_provider, layout - }, - m_color_picker{ service_provider, starting_color, std::move(callback), std::pair{ 0.95, 0.95 }, ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Bottom }, layout, false } { } +}, + m_color_picker{ service_provider, + starting_color, + std::move(callback), + std::pair{ 0.95, 0.95 }, + ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Bottom }, + layout, + false } { } [[nodiscard]] scenes::Scene::UpdateResult detail::ColorPickerScene::update() { if (m_should_exit) { @@ -142,7 +148,9 @@ custom_ui::ColorSettingRow::ColorSettingRow( const ui::Layout& layout, bool is_top_level ) - : ui::Widget{ layout, ui::WidgetType::Component, is_top_level }, + : ui::Widget{ + layout, ui::WidgetType::Component, is_top_level +}, ui::Focusable{ focus_id }, ui::Hoverable{ layout.get_rect() }, m_service_provider{ service_provider }, @@ -187,7 +195,9 @@ helper::BoolWrapper> custom_ui::Colo }; } - throw helper::FatalError(fmt::format("Unsupported Handle Type: {}", magic_enum::enum_name(additional->first))); + utils::throw_( + helper::FatalError(fmt::format("Unsupported Handle Type: {}", magic_enum::enum_name(additional->first))) + ); } return result; diff --git a/src/scenes/settings_menu/settings_menu.cpp b/src/scenes/settings_menu/settings_menu.cpp index 01d62b275..2506a6f9f 100644 --- a/src/scenes/settings_menu/settings_menu.cpp +++ b/src/scenes/settings_menu/settings_menu.cpp @@ -29,17 +29,25 @@ namespace scenes { ) : SettingsMenu{ service_provider, layout, std::optional>{ game_input } } { } - SettingsMenu::SettingsMenu(ServiceProvider* service_provider, const ui::Layout& layout, const std::optional>& game_input) : Scene{service_provider, layout} - , m_main_layout{ utils::SizeIdentity<3>(), - 0, - ui::Direction::Vertical, - { 0.1, 0.9 }, - ui::AbsolutMargin{ 10 }, - std::pair{ 0.05, 0.03 }, - layout + SettingsMenu::SettingsMenu( + ServiceProvider* service_provider, + const ui::Layout& layout, + const std::optional>& game_input + ) + : Scene{ + service_provider, layout }, - m_colors{COLOR_LITERAL("#FF33FF"), COLOR_LITERAL("hsv(281.71, 0.70085, 0.45882)"), COLOR_LITERAL("rgb(246, 255, 61)"),COLOR_LITERAL("hsv(103.12, 0.39024, 0.32157)")},m_game_input{game_input},m_settings{m_service_provider->settings_manager().settings()} -{ + m_main_layout{ utils::SizeIdentity<3>(), + 0, + ui::Direction::Vertical, + { 0.1, 0.9 }, + ui::AbsolutMargin{ 10 }, + std::pair{ 0.05, 0.03 }, + layout }, + m_colors{ COLOR_LITERAL("#FF33FF"), COLOR_LITERAL("hsv(281.71, 0.70085, 0.45882)"), + COLOR_LITERAL("rgb(246, 255, 61)"), COLOR_LITERAL("hsv(103.12, 0.39024, 0.32157)") }, + m_game_input{ game_input }, + m_settings{ m_service_provider->settings_manager().settings() } { auto focus_helper = ui::FocusHelper{ 1 }; m_main_layout.add( @@ -83,10 +91,9 @@ namespace scenes { ); service_provider->music_manager().add_volume_listener( - listener_name, - [this, scroll_layout_index, slider_index](std::optional) { - auto* scroll_layout = this->m_main_layout.get(scroll_layout_index); - scroll_layout->get(slider_index)->on_change(); + listener_name, [this, scroll_layout_index, slider_index](std::optional) { + auto* volume_scroll_layout = this->m_main_layout.get(scroll_layout_index); + volume_scroll_layout->get(slider_index)->on_change(); if (auto volume = this->m_service_provider->music_manager().get_volume(); volume.has_value()) { this->m_settings.volume = static_cast(volume.value()); @@ -224,7 +231,9 @@ namespace scenes { } - throw std::runtime_error("Requested action on unknown widget, this is a fatal error"); + utils::throw_( + std::runtime_error("Requested action on unknown widget, this is a fatal error") + ); } }, m_next_command.value().m_value ); diff --git a/src/scenes/single_player_game/game_over.cpp b/src/scenes/single_player_game/game_over.cpp index 9b04d8363..46831991c 100644 --- a/src/scenes/single_player_game/game_over.cpp +++ b/src/scenes/single_player_game/game_over.cpp @@ -11,28 +11,34 @@ namespace scenes { - SinglePlayerGameOver::SinglePlayerGameOver(ServiceProvider* service_provider, const ui::Layout& layout, const std::shared_ptr& game_input) - : Scene{ service_provider, layout }, - m_text{ - service_provider, - fmt::format( - "Game Over, Press {} to continue", - game_input->underlying_input()->describe_navigation_event(input::NavigationEvent::BACK) - ), - service_provider->font_manager().get(FontId::Default), - Color::white(), - utils::get_orientation() == utils::Orientation::Landscape - ? std::pair{ 0.7, 0.07 } - : std::pair{ 0.95, 0.07 }, - ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }, - layout, - true - } ,m_game_input{game_input}{ - service_provider->music_manager() - .load_and_play_music( - utils::get_assets_folder() / "music" / utils::get_supported_music_extension("05. Results") - ) - .and_then(utils::log_error); + SinglePlayerGameOver::SinglePlayerGameOver( + ServiceProvider* service_provider, + const ui::Layout& layout, + const std::shared_ptr& game_input + ) + : Scene{ + service_provider, layout + }, + m_text{ service_provider, + fmt::format( + "Game Over, Press {} to continue", + game_input->underlying_input()->describe_navigation_event(input::NavigationEvent::BACK) + ), + service_provider->font_manager().get(FontId::Default), + Color::white(), + utils::get_orientation() == utils::Orientation::Landscape ? std::pair{ 0.7, 0.07 } + : std::pair{ 0.95, 0.07 }, + ui::Alignment{ ui::AlignmentHorizontal::Middle, ui::AlignmentVertical::Center }, + layout, + true }, + m_game_input{ game_input } { + auto _ignore = service_provider->music_manager() + .load_and_play_music( + utils::get_assets_folder() / "music" + / utils::get_supported_music_extension("05. Results") + ) + .and_then(utils::log_error); + UNUSED(_ignore); } [[nodiscard]] Scene::UpdateResult SinglePlayerGameOver::update() { diff --git a/src/scenes/single_player_game/single_player_game.cpp b/src/scenes/single_player_game/single_player_game.cpp index 73d5bc302..71c5d14cc 100644 --- a/src/scenes/single_player_game/single_player_game.cpp +++ b/src/scenes/single_player_game/single_player_game.cpp @@ -35,10 +35,15 @@ namespace scenes { input::get_single_player_game_parameters(service_provider, std::move(additional_information), date); if (not result.has_value()) { - throw helper::MajorError(fmt::format( - "No suitable input was configured, go into the settings to select a suitable input: {}", - result.error() - )); + utils::throw_( + helper::MajorError( + fmt::format( + "No suitable input was configured, go into the settings to select a suitable " + "input: {}", + result.error() + ) + ) + ); } auto [input, starting_parameters] = result.value(); @@ -61,11 +66,13 @@ namespace scenes { #endif - m_service_provider->music_manager() - .load_and_play_music( - utils::get_assets_folder() / "music" / utils::get_supported_music_extension("02. Game Theme") - ) - .and_then(utils::log_error); + auto _ignore = m_service_provider->music_manager() + .load_and_play_music( + utils::get_assets_folder() / "music" + / utils::get_supported_music_extension("02. Game Theme") + ) + .and_then(utils::log_error); + UNUSED(_ignore); } diff --git a/src/ui/components/textinput.cpp b/src/ui/components/textinput.cpp index 2223980b6..1c6cdfa21 100644 --- a/src/ui/components/textinput.cpp +++ b/src/ui/components/textinput.cpp @@ -231,9 +231,10 @@ ui::TextInput::handle_event( //NOLINT(readability-function-cognitive-complexity) if (ctrl_pressed) { const int result = SDL_SetClipboardText(m_text.c_str()); if (result != 0) { - throw helper::MinorError{ - fmt::format("failed in setting the clipboard text: {}", SDL_GetError()) - }; + utils::throw_( + helper::MinorError{ + fmt::format("failed in setting the clipboard text: {}", SDL_GetError()) } + ); } return true; } @@ -302,7 +303,8 @@ void ui::TextInput::recalculate_textures(bool text_changed) { if (text_changed) { - m_text_texture = renderer.get_texture_for_render_target(shapes::UPoint(1, 1) // this is a dummy point! + m_text_texture = renderer.get_texture_for_render_target( + shapes::UPoint(1, 1) // this is a dummy point! ); m_scaled_text_size = 0; } @@ -348,7 +350,7 @@ void ui::TextInput::recalculate_textures(bool text_changed) { const int result = TTF_SizeUTF8(m_font.get(), sub_string.c_str(), &width, &height); if (result < 0) { - throw helper::FatalError{ fmt::format("Error during SDL_TTF_SizeUTF8: {}", SDL_GetError()) }; + utils::throw_(helper::FatalError{ fmt::format("Error during SDL_TTF_SizeUTF8: {}", SDL_GetError()) }); } const double ratio_sub_string = static_cast(height) / static_cast(fill_rect().height()); @@ -414,7 +416,7 @@ bool ui::TextInput::add_string(const std::string& add) { // cursor_position is the range [0, length] (inclusively !) if (m_cursor_position > current_string_length) { - throw std::runtime_error("cursor_postion is invalid!"); + utils::throw_(std::runtime_error("cursor_postion is invalid!")); } std::string result{}; @@ -460,7 +462,7 @@ bool ui::TextInput::remove_at_cursor(RemoveMode remove_mode) { // cursor_position is the range [0, length] (inclusively !) if (m_cursor_position > current_string_length) { - throw std::runtime_error("cursor_postion is invalid!"); + utils::throw_( std::runtime_error("cursor_postion is invalid!")); } diff --git a/src/ui/layouts/focus_layout.cpp b/src/ui/layouts/focus_layout.cpp index aa87dd5e0..d5bc963a3 100644 --- a/src/ui/layouts/focus_layout.cpp +++ b/src/ui/layouts/focus_layout.cpp @@ -140,7 +140,7 @@ ui::FocusLayout::handle_event_result(const std::optional case ui::EventHandleType::RequestFocus: { const auto focusable = as_focusable(widget); if (not focusable.has_value()) { - throw std::runtime_error("Only Focusables can request focus!"); + utils::throw_(std::runtime_error("Only Focusables can request focus!")); } if (not m_focus_id.has_value()) { @@ -174,7 +174,7 @@ ui::FocusLayout::handle_event_result(const std::optional const auto focusable = as_focusable(widget); if (not focusable.has_value()) { - throw std::runtime_error("Only Focusables can request un-focus!"); + utils::throw_(std::runtime_error("Only Focusables can request un-focus!")); } @@ -235,7 +235,7 @@ ui::FocusLayout::handle_event_result(const std::optional // this works, since result is sorted already const auto duplicates = std::ranges::adjacent_find(result); if (duplicates != result.cend()) { - throw std::runtime_error("Focusables have duplicates: " + std::to_string(*duplicates)); + utils::throw_(std::runtime_error("Focusables have duplicates: " + std::to_string(*duplicates))); } #endif std::ranges::sort(result); diff --git a/src/ui/layouts/focus_layout.hpp b/src/ui/layouts/focus_layout.hpp index 2240e4a47..92b0d8c1e 100644 --- a/src/ui/layouts/focus_layout.hpp +++ b/src/ui/layouts/focus_layout.hpp @@ -76,15 +76,17 @@ namespace ui { template [[nodiscard]] T* get(const u32 index) { if (index >= m_widgets.size()) { - throw std::runtime_error{ fmt::format( - "Invalid get of FocusLayout item: index out of bound: {} is not in range [{} - {})", index, 0, - m_widgets.size() - ) }; + utils::throw_( + std::runtime_error{ fmt::format( + "Invalid get of FocusLayout item: index out of bound: {} is not in range [{} - {})", + index, 0, m_widgets.size() + ) } + ); } auto item = utils::is_child_class(m_widgets.at(index)); if (not item.has_value()) { - throw std::runtime_error("Invalid get of FocusLayout item!"); + utils::throw_(std::runtime_error("Invalid get of FocusLayout item!")); } return item.value(); @@ -93,12 +95,12 @@ namespace ui { template [[nodiscard]] const T* get(const u32 index) const { if (index >= m_widgets.size()) { - throw std::runtime_error("Invalid get of FocusLayout item: index out of bound!"); + utils::throw_(std::runtime_error("Invalid get of FocusLayout item: index out of bound!")); } const auto item = utils::is_child_class(m_widgets.at(index).get()); if (item == nullptr) { - throw std::runtime_error("Invalid get of FocusLayout item!"); + utils::throw_(std::runtime_error("Invalid get of FocusLayout item!")); } return item.value(); diff --git a/src/ui/layouts/grid_layout.cpp b/src/ui/layouts/grid_layout.cpp index e55339169..72e2f690f 100644 --- a/src/ui/layouts/grid_layout.cpp +++ b/src/ui/layouts/grid_layout.cpp @@ -3,21 +3,23 @@ ui::GridLayout::GridLayout( - u32 focus_id, // NOLINT(bugprone-easily-swappable-parameters) - u32 size, - Direction direction, - Margin gap, - std::pair margin, - const Layout& layout, - bool is_top_level - ) - : FocusLayout{ layout, focus_id, FocusOptions{ .wrap_around=is_top_level, .allow_tab=is_top_level }, is_top_level }, - m_size{ size }, - m_direction{ direction }, - m_gap{ gap }, - m_margin{ static_cast(margin.first * layout.get_rect().width()), - static_cast(margin.second * layout.get_rect().height()) } { - } + u32 focus_id, // NOLINT(bugprone-easily-swappable-parameters) + u32 size, + Direction direction, + Margin gap, + std::pair margin, + const Layout& layout, + bool is_top_level +) + : FocusLayout{ + layout, focus_id, FocusOptions{ .wrap_around = is_top_level, .allow_tab = is_top_level }, + is_top_level +}, + m_size{ size }, + m_direction{ direction }, + m_gap{ gap }, + m_margin{ static_cast(margin.first * layout.get_rect().width()), + static_cast(margin.second * layout.get_rect().height()) } { } [[nodiscard]] u32 ui::GridLayout::total_size() const { return m_size; @@ -32,7 +34,7 @@ void ui::GridLayout::render(const ServiceProvider& service_provider) const { [[nodiscard]] ui::Layout ui::GridLayout::get_layout_for_index(u32 index) { if (index >= this->m_size) { - throw std::runtime_error("GridLayout is already full"); + utils::throw_(std::runtime_error("GridLayout is already full")); } const auto start_point = layout().get_rect().top_left; diff --git a/src/ui/layouts/scroll_layout.cpp b/src/ui/layouts/scroll_layout.cpp index 8e46ce698..a32a3e537 100644 --- a/src/ui/layouts/scroll_layout.cpp +++ b/src/ui/layouts/scroll_layout.cpp @@ -3,7 +3,7 @@ #include "input/input.hpp" #include "scroll_layout.hpp" -ui::ItemSize::ItemSize(const u32 height, ItemSizeType type) : height{ height }, type{ type } { } +ui::ItemSize::ItemSize(const u32 height_a, ItemSizeType type_a) : height{ height_a }, type{ type_a } { } [[nodiscard]] u32 ui::ItemSize::get_height() const { @@ -14,34 +14,36 @@ ui::ItemSize::ItemSize(const u32 height, ItemSizeType type) : height{ height }, return type; } -ui::AbsolutItemSize::AbsolutItemSize(const u32 height) : ItemSize{ height, ItemSizeType::Absolut } { } +ui::AbsolutItemSize::AbsolutItemSize(const u32 height_a) : ItemSize{ height_a, ItemSizeType::Absolut } { } -ui::RelativeItemSize::RelativeItemSize(const shapes::URect& rect, const double height) - : ItemSize{ static_cast(height * rect.height()), ItemSizeType::Relative } { +ui::RelativeItemSize::RelativeItemSize(const shapes::URect& rect, const double height_d) + : ItemSize{ static_cast(height_d * rect.height()), ItemSizeType::Relative } { // no checks for upper cases, since it theoretically can also be larger than the whole screen! - assert(height >= 0.0 && "height has to be in correct percentage range!"); + assert(height_d >= 0.0 && "height has to be in correct percentage range!"); } -ui::RelativeItemSize::RelativeItemSize(const Window* window, const double height) - : RelativeItemSize{ window->screen_rect(), height } { } -ui::RelativeItemSize::RelativeItemSize(const Window& window, const double height) - : RelativeItemSize{ window.screen_rect(), height } { } -ui::RelativeItemSize::RelativeItemSize(const Layout& layout, const double height) - : RelativeItemSize{ layout.get_rect(), height } { } +ui::RelativeItemSize::RelativeItemSize(const Window* window, const double height_d) + : RelativeItemSize{ window->screen_rect(), height_d } { } +ui::RelativeItemSize::RelativeItemSize(const Window& window, const double height_d) + : RelativeItemSize{ window.screen_rect(), height_d } { } +ui::RelativeItemSize::RelativeItemSize(const Layout& layout, const double height_d) + : RelativeItemSize{ layout.get_rect(), height_d } { } ui::ScrollLayout::ScrollLayout( - ServiceProvider* service_provider, - u32 focus_id, - Margin gap, - std::pair margin, - const Layout& layout, - bool is_top_level - ) - : FocusLayout{ - layout, focus_id, FocusOptions{ .wrap_around=is_top_level, .allow_tab=is_top_level }, is_top_level}, // if on top, we support tab and wrap around, otherwise not - m_gap{ gap }, - m_texture{ std::nullopt }, - m_service_provider{ service_provider }, - m_step_size{ static_cast(layout.get_rect().height() * 0.05) } { + ServiceProvider* service_provider, + u32 focus_id, + Margin gap, + std::pair margin, + const Layout& layout, + bool is_top_level +) + : FocusLayout{ + layout, focus_id, FocusOptions{ .wrap_around = is_top_level, .allow_tab = is_top_level }, + is_top_level +}, // if on top, we support tab and wrap around, otherwise not + m_gap{ gap }, + m_texture{ std::nullopt }, + m_service_provider{ service_provider }, + m_step_size{ static_cast(layout.get_rect().height() * 0.05) } { const auto layout_rect = layout.get_rect(); const auto absolut_margin = std::pair{ static_cast(margin.first * layout_rect.width()), @@ -292,7 +294,7 @@ void ui::ScrollLayout::clear_widgets() { [[nodiscard]] ui::Layout ui::ScrollLayout::get_layout_for_index(u32 /*index*/) { // see TODO comment over handle_event in header file - throw std::runtime_error("NOT SUPPORTED"); + utils::throw_(std::runtime_error("NOT SUPPORTED")); } [[nodiscard]] ui::Layout ui::ScrollLayout::get_layout_for_new(ItemSize size) { diff --git a/src/ui/layouts/scroll_layout.hpp b/src/ui/layouts/scroll_layout.hpp index c4f29eace..eac77ad2c 100644 --- a/src/ui/layouts/scroll_layout.hpp +++ b/src/ui/layouts/scroll_layout.hpp @@ -20,7 +20,7 @@ namespace ui { ItemSizeType type; protected: - ItemSize(u32 height, ItemSizeType type); + ItemSize(u32 height_a, ItemSizeType type_a); public: [[nodiscard]] OOPETRIS_GRAPHICS_EXPORTED u32 get_height() const; @@ -29,15 +29,15 @@ namespace ui { }; struct AbsolutItemSize : public ItemSize { - OOPETRIS_GRAPHICS_EXPORTED explicit AbsolutItemSize(u32 height); + OOPETRIS_GRAPHICS_EXPORTED explicit AbsolutItemSize(u32 height_a); }; struct RelativeItemSize : public ItemSize { - OOPETRIS_GRAPHICS_EXPORTED RelativeItemSize(const shapes::URect& rect, double height); - OOPETRIS_GRAPHICS_EXPORTED RelativeItemSize(const Window* window, double height); - OOPETRIS_GRAPHICS_EXPORTED RelativeItemSize(const Window& window, double height); - OOPETRIS_GRAPHICS_EXPORTED RelativeItemSize(const Layout& layout, double height); + OOPETRIS_GRAPHICS_EXPORTED RelativeItemSize(const shapes::URect& rect, double height_d); + OOPETRIS_GRAPHICS_EXPORTED RelativeItemSize(const Window* window, double height_d); + OOPETRIS_GRAPHICS_EXPORTED RelativeItemSize(const Window& window, double height_d); + OOPETRIS_GRAPHICS_EXPORTED RelativeItemSize(const Layout& layout, double height_d); }; diff --git a/src/ui/layouts/tile_layout.cpp b/src/ui/layouts/tile_layout.cpp index 2a4baaa57..858a8cfeb 100644 --- a/src/ui/layouts/tile_layout.cpp +++ b/src/ui/layouts/tile_layout.cpp @@ -11,7 +11,7 @@ void ui::TileLayout::render(const ServiceProvider& service_provider) const { [[nodiscard]] ui::Layout ui::TileLayout::get_layout_for_index(u32 index) { if (index >= this->m_size) { - throw std::runtime_error("TileLayout is already full"); + utils::throw_(std::runtime_error("TileLayout is already full")); } const auto start_point = layout().get_rect().top_left; diff --git a/subprojects/c-embed.wrap b/subprojects/c-embed.wrap new file mode 100644 index 000000000..204f9b25a --- /dev/null +++ b/subprojects/c-embed.wrap @@ -0,0 +1,11 @@ +[wrap-git] +url = https://github.com/weigert/c-embed.git +revision = main +depth = 1 +patch_directory = c-embed +diff_files = c-embed-system-checked.diff + + +[provide] +dependency_names = c-embed +program_names = c-embed diff --git a/subprojects/cpp-httplib.wrap b/subprojects/cpp-httplib.wrap index 1bfbded97..8a2a56cd1 100644 --- a/subprojects/cpp-httplib.wrap +++ b/subprojects/cpp-httplib.wrap @@ -1,11 +1,10 @@ [wrap-file] -directory = cpp-httplib-0.25.0 -source_url = https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.25.0.tar.gz -source_filename = cpp-httplib-0.25.0.tar.gz -source_hash = ac7c59fa72325d4cb9f73af266312d82632ac35a5c4c8a1be620c1f946ec9cea -source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/cpp-httplib_0.25.0-1/cpp-httplib-0.25.0.tar.gz -wrapdb_version = 0.25.0-1 -diff_files = cpp-httplib-0.25.0_mingw.diff +directory = cpp-httplib-0.51.0 +source_url = https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.51.0.tar.gz +source_filename = cpp-httplib-0.51.0.tar.gz +source_hash = d740ced75352f44e9d66d08806dc231b5621bb3592b5a5d5b2bd890a9a9d86cc +source_fallback_url = https://wrapdb.mesonbuild.com/v2/cpp-httplib_0.51.0-1/get_source/cpp-httplib-0.51.0.tar.gz +wrapdb_version = 0.51.0-1 [provide] -cpp-httplib = cpp_httplib_dep +dependency_names = cpp-httplib diff --git a/subprojects/discord-social-sdk.wrap b/subprojects/discord-social-sdk.wrap index 0122eb3c7..b14fd15c6 100644 --- a/subprojects/discord-social-sdk.wrap +++ b/subprojects/discord-social-sdk.wrap @@ -1,10 +1,10 @@ [wrap-file] directory = discord_social_sdk -source_url = https://oopetris.totto.lt/static/assets/discord/DiscordSocialSdk-1.4.9649.zip -source_filename = DiscordSocialSdk-1.4.9649.zip -source_hash = 55af4030abf3286ee0a8e562c30cd839a605063eb5e987aea110bfc81bc39312 +source_url = https://oopetris.totto.lt/static/assets/discord/DiscordSocialSdk-1.10.18247.zip +source_filename = DiscordSocialSdk-1.10.18247.zip +source_hash = 505bfba1a8ae3277ff2f8a04f586d39f8f22ab31467a702a540901ab1253e857 patch_directory = discord_social_sdk -diff_files = discord_social_sdk-1.4.9649_mingw.diff +diff_files = discord_social_sdk-1.10.18247_mingw.diff [provide] discord-social-sdk = discord_social_sdk_dep diff --git a/subprojects/packagefiles/SDL2_image_2.6.3_define_fix.diff b/subprojects/packagefiles/SDL2_image_2.6.3_define_fix.diff new file mode 100644 index 000000000..09e5758b1 --- /dev/null +++ b/subprojects/packagefiles/SDL2_image_2.6.3_define_fix.diff @@ -0,0 +1,19 @@ +diff --git a/IMG_gif.c b/IMG_gif.c +index 5611dec..43498b2 100644 +--- a/IMG_gif.c ++++ b/IMG_gif.c +@@ -63,8 +63,14 @@ + + #define MAXCOLORMAPSIZE 256 + ++#ifndef TRUE + #define TRUE 1 ++#endif ++ ++#ifndef FALSE + #define FALSE 0 ++#endif ++ + + #define CM_RED 0 + #define CM_GREEN 1 diff --git a/subprojects/packagefiles/c-embed-system-checked.diff b/subprojects/packagefiles/c-embed-system-checked.diff new file mode 100644 index 000000000..52e3e0cbd --- /dev/null +++ b/subprojects/packagefiles/c-embed-system-checked.diff @@ -0,0 +1,24 @@ +diff --git a/c-embed.c b/c-embed.c +index bdcec8d..e233d4a 100644 +--- a/c-embed.c ++++ b/c-embed.c +@@ -106,6 +106,19 @@ void iterdir(char* d){ + + } + ++void system_checked(const char *command){ ++ ++ int result = system(command); ++ ++ if(result != 0){ ++ fprintf(stderr, "system() failed with %d: %s\n", result, command); ++ exit(1); ++ } ++ ++} ++ ++#define system system_checked ++ + int main(int argc, char* argv[]){ + + char fmt[CEMBED_MAXPATH]; diff --git a/subprojects/packagefiles/c-embed/meson.build b/subprojects/packagefiles/c-embed/meson.build new file mode 100644 index 000000000..0633c2539 --- /dev/null +++ b/subprojects/packagefiles/c-embed/meson.build @@ -0,0 +1,39 @@ +project( + 'c-embed', + 'c', + meson_version: '>=1.12.0', + version: '0.0.1', + license: 'MIT', + default_options: { + 'optimization': '3', + 'warning_level': '2', + 'werror': true, + 'c_std': ['c11'], + 'b_ndebug': 'if-release', + }, +) + +inc_dirs = include_directories('.') + + + +c_embed_exe = executable( + 'c-embed', + files('c-embed.c'), + include_directories: inc_dirs, + native: true, +) + +meson.override_find_program( + 'c-embed', + c_embed_exe, + native: true, +) + + +c_embed_dep = declare_dependency( + include_directories: inc_dirs, + version: meson.project_version(), +) + +meson.override_dependency('c-embed', c_embed_dep) diff --git a/subprojects/packagefiles/cpp-httplib-0.25.0_mingw.diff b/subprojects/packagefiles/cpp-httplib-0.26.0_mingw.diff similarity index 100% rename from subprojects/packagefiles/cpp-httplib-0.25.0_mingw.diff rename to subprojects/packagefiles/cpp-httplib-0.26.0_mingw.diff diff --git a/subprojects/packagefiles/discord_social_sdk-1.4.9649_mingw.diff b/subprojects/packagefiles/discord_social_sdk-1.10.18247_mingw.diff similarity index 100% rename from subprojects/packagefiles/discord_social_sdk-1.4.9649_mingw.diff rename to subprojects/packagefiles/discord_social_sdk-1.10.18247_mingw.diff diff --git a/subprojects/packagefiles/discord_social_sdk/meson.build b/subprojects/packagefiles/discord_social_sdk/meson.build index d16b6b897..a37e38c6b 100644 --- a/subprojects/packagefiles/discord_social_sdk/meson.build +++ b/subprojects/packagefiles/discord_social_sdk/meson.build @@ -2,7 +2,7 @@ project( 'discord-social-sdk', 'cpp', 'c', - version: '1.4.9649', + version: '1.10.18247', meson_version: '>=1.4.0', default_options: { 'cpp_std': ['c++17'], @@ -66,6 +66,8 @@ if not meson.is_cross_build() elif host_machine.system() == 'windows' if host_machine.cpu_family() == 'x86_64' lib_base_dir = get_option('default_library') == 'static' ? 'bin' : 'lib' + elif host_machine.cpu_family() == 'aarch64' + lib_base_dir = (get_option('default_library') == 'static' ? 'bin' : 'lib') / 'arm64' else error('unsupported architecture for windows: ' + host_machine.cpu_family()) endif @@ -85,6 +87,21 @@ if not meson.is_cross_build() required: true, ) + + if host_machine.system() == 'linux' + install_lib_dir = get_option('prefix') / get_option('libdir') + + discord_partner_sdk_file = files( + meson.project_source_root() / lib_dir / 'libdiscord_partner_sdk.so' + ) + + install_data( + discord_partner_sdk_file, + install_dir: install_lib_dir, + install_tag: 'runtime', + ) + endif + ## NOTE: this is a static library, as it doesn't export the symbols correctly, so on windows the dll would fail to link discord_social_sdk_lib = static_library( 'discord_social_sdk', diff --git a/subprojects/packagefiles/expected-1.1.0_installable.diff b/subprojects/packagefiles/expected-1.3.1_installable.diff similarity index 100% rename from subprojects/packagefiles/expected-1.1.0_installable.diff rename to subprojects/packagefiles/expected-1.3.1_installable.diff diff --git a/subprojects/packagefiles/keyutils/meson.build b/subprojects/packagefiles/keyutils/meson.build index e2e0e04d3..79e95be2b 100644 --- a/subprojects/packagefiles/keyutils/meson.build +++ b/subprojects/packagefiles/keyutils/meson.build @@ -9,7 +9,7 @@ project( 'warning_level': '2', 'werror': true, 'strip': true, - 'cpp_std': ['c++23', 'c++latest', 'vc++latest', 'c++20'], + 'c_std': ['c11'], 'b_ndebug': 'if-release', }, ) diff --git a/subprojects/packagefiles/sdl2_mixer-2.6.2_example_option.diff b/subprojects/packagefiles/sdl2_mixer-2.6.2_example_option.diff new file mode 100644 index 000000000..49100f085 --- /dev/null +++ b/subprojects/packagefiles/sdl2_mixer-2.6.2_example_option.diff @@ -0,0 +1,46 @@ +diff --git a/meson.build b/meson.build +index b354993..563c3cc 100644 +--- a/meson.build ++++ b/meson.build +@@ -73,14 +73,17 @@ sdl2_mixer_dep = declare_dependency( + link_with: sdl2_mixer_lib, + ) + +-if sdl2_dep.type_name() == 'internal' +- sdl2main_dep = dependency('sdl2main') +-else +- sdl2main_dep = cc.find_library('SDL2main') +-endif ++if get_option('example') ++ if sdl2_dep.type_name() == 'internal' ++ sdl2main_dep = dependency('sdl2main') ++ else ++ sdl2main_dep = cc.find_library('SDL2main') ++ endif + +-executable( +- 'playmus', +- 'playmus.c', +- dependencies: [sdl2_dep, sdl2main_dep, sdl2_mixer_dep], +-) ++ executable( ++ 'playmus', ++ 'playmus.c', ++ dependencies: [sdl2_dep, sdl2main_dep, sdl2_mixer_dep], ++ ) ++ ++endif +diff --git a/meson_options.txt b/meson_options.txt +index 34a5d2a..58ee5ab 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -15,3 +15,9 @@ option( + description: 'Opus support', + ) + ++option( ++ 'example', ++ type: 'boolean', ++ description: 'compile the example', ++ value: false ++) diff --git a/subprojects/packagefiles/sdl2_ttf-2.20.1_sdl_uefi_sse_fix.diff b/subprojects/packagefiles/sdl2_ttf-2.20.1_sdl_uefi_sse_fix.diff new file mode 100644 index 000000000..8733c57fe --- /dev/null +++ b/subprojects/packagefiles/sdl2_ttf-2.20.1_sdl_uefi_sse_fix.diff @@ -0,0 +1,13 @@ +diff --git a/SDL_ttf.c b/SDL_ttf.c +index 404e00b..35cfa4b 100644 +--- a/SDL_ttf.c ++++ b/SDL_ttf.c +@@ -114,7 +114,7 @@ int TTF_SetScript(int script) /* hb_script_t */ + } + + /* Round glyph to 16 bytes width and use SSE2 instructions */ +-#if defined(__SSE2__) ++#if defined(__SSE2__) && !defined(SDL_DISABLE_SSE2_INTRINSICS) + # define HAVE_SSE2_INTRINSICS 1 + #endif + diff --git a/subprojects/packagefiles/spdlog_1.17.0_std_format_detection_fix.diff b/subprojects/packagefiles/spdlog_1.17.0_std_format_detection_fix.diff new file mode 100644 index 000000000..f86d0901b --- /dev/null +++ b/subprojects/packagefiles/spdlog_1.17.0_std_format_detection_fix.diff @@ -0,0 +1,22 @@ +diff --git a/meson.build b/meson.build +index c842472..92099e0 100644 +--- a/meson.build ++++ b/meson.build +@@ -3,7 +3,7 @@ project( + 'cpp', + version: '1.17.0', + license: 'MIT', +- meson_version: '>=0.56.0', ++ meson_version: '>=0.59.0', + ) + + inc = include_directories('include') +@@ -14,7 +14,7 @@ spdlog_dependencies = [thread_dep] + spdlog_compile_args = [] + override_cpp = meson.version().version_compare('>=1.3.0') ? 'cpp_std=gnu++17,c++17' : 'cpp_std=gnu++17' + +-if meson.get_compiler('cpp').has_header_symbol( ++if get_option('std_format').allowed() and meson.get_compiler('cpp').has_header_symbol( + 'format', + '__cpp_lib_format', + required: get_option('std_format'), diff --git a/subprojects/packagefiles/spdlog_1.17.0_uefi_support.diff b/subprojects/packagefiles/spdlog_1.17.0_uefi_support.diff new file mode 100644 index 000000000..100438bfa --- /dev/null +++ b/subprojects/packagefiles/spdlog_1.17.0_uefi_support.diff @@ -0,0 +1,111 @@ +diff --git a/include/spdlog/cfg/helpers-inl.h b/include/spdlog/cfg/helpers-inl.h +index 6ed8695..6d4a55b 100644 +--- a/include/spdlog/cfg/helpers-inl.h ++++ b/include/spdlog/cfg/helpers-inl.h +@@ -54,6 +54,7 @@ inline std::pair extract_kv_(char sep, const std::stri + return std::make_pair(trim_(k), trim_(v)); + } + ++#if !defined(__UEFI__) + // return vector of key/value pairs from a sequence of "K1=V1,K2=V2,.." + // "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...} + inline std::unordered_map extract_key_vals_(const std::string &str) { +@@ -69,6 +70,29 @@ inline std::unordered_map extract_key_vals_(const std: + } + return rv; + } ++#else ++inline std::unordered_map extract_key_vals_(const std::string &str) { ++ std::unordered_map rv{}; ++ ++ size_t start = 0; ++ while (start < str.size()) { ++ size_t end = str.find(',', start); ++ if (end == std::string::npos) { ++ end = str.size(); ++ } ++ ++ if (end > start) { ++ auto token = str.substr(start, end - start); ++ auto kv = extract_kv_('=', token); ++ rv[kv.first] = kv.second; ++ } ++ ++ start = end + 1; ++ } ++ ++ return rv; ++} ++#endif + + SPDLOG_INLINE void load_levels(const std::string &input) { + if (input.empty() || input.size() >= 32768) { +diff --git a/include/spdlog/details/os-inl.h b/include/spdlog/details/os-inl.h +index b4bfe83..6a5f408 100644 +--- a/include/spdlog/details/os-inl.h ++++ b/include/spdlog/details/os-inl.h +@@ -42,7 +42,7 @@ + #include + #include + +-#ifdef __linux__ ++#if defined(__linux__) && !defined(__UEFI__) + #include //Use gettid() syscall under linux to get thread id + + #elif defined(_AIX) +@@ -88,6 +88,9 @@ SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT { + #ifdef _WIN32 + std::tm tm; + ::localtime_s(&tm, &time_tt); ++#elif defined(__UEFI__) ++ std::tm* tm_p = ::localtime(&time_tt); ++ std::tm tm = *tm_p; + #else + std::tm tm; + ::localtime_r(&time_tt, &tm); +@@ -104,6 +107,9 @@ SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT { + #ifdef _WIN32 + std::tm tm; + ::gmtime_s(&tm, &time_tt); ++#elif defined(__UEFI__) ++ std::tm* tm_p = ::gmtime(&time_tt); ++ std::tm tm = *tm_p; + #else + std::tm tm; + ::gmtime_r(&time_tt, &tm); +@@ -216,7 +222,7 @@ SPDLOG_INLINE size_t filesize(FILE *f) { + + #else // unix + // OpenBSD and AIX doesn't compile with :: before the fileno(..) +-#if defined(__OpenBSD__) || defined(_AIX) ++#if defined(__OpenBSD__) || defined(_AIX) || defined(__UEFI__) + int fd = fileno(f); + #else + int fd = ::fileno(f); +@@ -260,7 +266,7 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) { + auto offset_seconds = utc_time_t - local_time_t; + return static_cast(offset_seconds / 60); + } +-#elif defined(__3DS__) || defined(__SWITCH__) ++#elif defined(__3DS__) || defined(__SWITCH__) || defined(__UEFI__) + SPDLOG_INLINE int utc_minutes_offset(const std::tm &/* tm */) { + throw_spdlog_ex("Not implemented yet on this platform", errno); + } +@@ -278,6 +284,8 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) { + SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT { + #ifdef _WIN32 + return static_cast(::GetCurrentThreadId()); ++#elif defined(__UEFI__) ++ return std::hash{}(std::this_thread::get_id()); + #elif defined(__linux__) + #if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) + #define SYS_gettid __NR_gettid +@@ -552,6 +560,8 @@ std::string SPDLOG_INLINE getenv(const char *field) { + SPDLOG_INLINE bool fsync(FILE *fp) { + #ifdef _WIN32 + return FlushFileBuffers(reinterpret_cast(_get_osfhandle(_fileno(fp)))) != 0; ++#elif defined(__UEFI__) ++ return fflush(fp) == 0; + #else + return ::fsync(fileno(fp)) == 0; + #endif diff --git a/subprojects/packagefiles/utfcpp-4.0.8_no_exceptions.diff b/subprojects/packagefiles/utfcpp-4.0.8_no_exceptions.diff new file mode 100644 index 000000000..0dffd828d --- /dev/null +++ b/subprojects/packagefiles/utfcpp-4.0.8_no_exceptions.diff @@ -0,0 +1,935 @@ +diff --git a/source/utf8/checked.h b/source/utf8/checked.h +index 96ceb4d..1d2cd97 100644 +--- a/source/utf8/checked.h ++++ b/source/utf8/checked.h +@@ -74,7 +74,7 @@ namespace utf8 + octet_iterator append(utfchar32_t cp, octet_iterator result) + { + if (!utf8::internal::is_code_point_valid(cp)) +- throw invalid_code_point(cp); ++ UTFCPP_THROW(invalid_code_point(cp)); + + return internal::append(cp, result); + } +@@ -88,7 +88,7 @@ namespace utf8 + word_iterator append16(utfchar32_t cp, word_iterator result) + { + if (!utf8::internal::is_code_point_valid(cp)) +- throw invalid_code_point(cp); ++ UTFCPP_THROW(invalid_code_point(cp)); + + return internal::append16(cp, result); + } +@@ -156,13 +156,13 @@ namespace utf8 + case internal::UTF8_OK : + break; + case internal::NOT_ENOUGH_ROOM : +- throw not_enough_room(); ++ UTFCPP_THROW(not_enough_room()); + case internal::INVALID_LEAD : + case internal::INCOMPLETE_SEQUENCE : + case internal::OVERLONG_SEQUENCE : +- throw invalid_utf8(static_cast(*it)); ++ UTFCPP_THROW(invalid_utf8(static_cast(*it))); + case internal::INVALID_CODE_POINT : +- throw invalid_code_point(cp); ++ UTFCPP_THROW(invalid_code_point(cp)); + } + return cp; + } +@@ -173,7 +173,7 @@ namespace utf8 + utfchar32_t cp = 0; + internal::utf_error err_code = utf8::internal::validate_next16(it, end, cp); + if (err_code == internal::NOT_ENOUGH_ROOM) +- throw not_enough_room(); ++ UTFCPP_THROW(not_enough_room()); + return cp; + } + +@@ -188,13 +188,13 @@ namespace utf8 + { + // can't do much if it == start + if (it == start) +- throw not_enough_room(); ++ UTFCPP_THROW(not_enough_room()); + + octet_iterator end = it; + // Go back until we hit either a lead octet or start + while (utf8::internal::is_trail(*(--it))) + if (it == start) +- throw invalid_utf8(*it); // error - no lead byte in the sequence ++ UTFCPP_THROW(invalid_utf8(*it)); // error - no lead byte in the sequence + return utf8::peek_next(it, end); + } + +@@ -235,15 +235,15 @@ namespace utf8 + if (utf8::internal::is_trail_surrogate(trail_surrogate)) + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + else +- throw invalid_utf16(static_cast(trail_surrogate)); ++ UTFCPP_THROW(invalid_utf16(static_cast(trail_surrogate))); + } + else +- throw invalid_utf16(static_cast(cp)); ++ UTFCPP_THROW(invalid_utf16(static_cast(cp))); + + } + // Lone trail surrogate + else if (utf8::internal::is_trail_surrogate(cp)) +- throw invalid_utf16(static_cast(cp)); ++ UTFCPP_THROW(invalid_utf16(static_cast(cp))); + + result = utf8::append(cp, result); + } +@@ -302,7 +302,7 @@ namespace utf8 + it(octet_it), range_start(rangestart), range_end(rangeend) + { + if (it < range_start || it > range_end) +- throw std::out_of_range("Invalid utf-8 iterator position"); ++ UTFCPP_THROW(std::out_of_range("Invalid utf-8 iterator position")); + } + // the default "big three" are OK + octet_iterator base () const { return it; } +@@ -314,7 +314,7 @@ namespace utf8 + bool operator == (const iterator& rhs) const + { + if (range_start != rhs.range_start || range_end != rhs.range_end) +- throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); ++ UTFCPP_THROW(std::logic_error("Comparing utf-8 iterators defined with different ranges")); + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const +diff --git a/source/utf8/core.h b/source/utf8/core.h +index 064f838..0dd1d99 100644 +--- a/source/utf8/core.h ++++ b/source/utf8/core.h +@@ -28,8 +28,8 @@ DEALINGS IN THE SOFTWARE. + #ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + #define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +-#include + #include ++#include + #include + + // Determine the C++ standard version. +@@ -37,412 +37,407 @@ DEALINGS IN THE SOFTWARE. + // Otherwise, trust the unreliable predefined macro __cplusplus + + #if !defined UTF_CPP_CPLUSPLUS +- #define UTF_CPP_CPLUSPLUS __cplusplus ++#define UTF_CPP_CPLUSPLUS __cplusplus + #endif + + #if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later +- #define UTF_CPP_OVERRIDE override +- #define UTF_CPP_NOEXCEPT noexcept +- #define UTF_CPP_STATIC_ASSERT(condition) static_assert(condition, "UTFCPP static assert"); ++#define UTF_CPP_OVERRIDE override ++#define UTF_CPP_NOEXCEPT noexcept ++#define UTF_CPP_STATIC_ASSERT(condition) static_assert(condition, "UTFCPP static assert"); + #else // C++ 98/03 +- #define UTF_CPP_OVERRIDE +- #define UTF_CPP_NOEXCEPT throw() +- // Simulate static_assert: +- template struct StaticAssert {static void utf8_static_assert() {char static_assert_impl[Condition ? 1 : 0]; } }; +- template <> struct StaticAssert {static void utf8_static_assert() {}}; +- #define UTF_CPP_STATIC_ASSERT(condition) StaticAssert::utf8_static_assert(); ++#define UTF_CPP_OVERRIDE ++#define UTF_CPP_NOEXCEPT throw() ++// Simulate static_assert: ++template ++struct StaticAssert { ++ static void utf8_static_assert() { ++ char static_assert_impl[Condition ? 1 : 0]; ++ } ++}; ++template<> ++struct StaticAssert { ++ static void utf8_static_assert() { } ++}; ++#define UTF_CPP_STATIC_ASSERT(condition) StaticAssert::utf8_static_assert(); + #endif // C++ 11 or later + + +-namespace utf8 +-{ ++namespace utf8 { + // The typedefs for 8-bit, 16-bit and 32-bit code units + #if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later +- #if UTF_CPP_CPLUSPLUS >= 202002L // C++ 20 or later +- typedef char8_t utfchar8_t; +- #else // C++ 11/14/17 +- typedef unsigned char utfchar8_t; +- #endif +- typedef char16_t utfchar16_t; +- typedef char32_t utfchar32_t; +-#else // C++ 98/03 +- typedef unsigned char utfchar8_t; +- typedef unsigned short utfchar16_t; +- typedef unsigned int utfchar32_t; ++#if UTF_CPP_CPLUSPLUS >= 202002L // C++ 20 or later ++ typedef char8_t utfchar8_t; ++#else // C++ 11/14/17 ++ typedef unsigned char utfchar8_t; ++#endif ++ typedef char16_t utfchar16_t; ++ typedef char32_t utfchar32_t; ++#else // C++ 98/03 ++ typedef unsigned char utfchar8_t; ++ typedef unsigned short utfchar16_t; ++ typedef unsigned int utfchar32_t; + #endif // C++ 11 or later + +-// Helper code - not intended to be directly called by the library users. May be changed at any time +-namespace internal +-{ +- // Unicode constants +- // Leading (high) surrogates: 0xd800 - 0xdbff +- // Trailing (low) surrogates: 0xdc00 - 0xdfff +- const utfchar16_t LEAD_SURROGATE_MIN = 0xd800u; +- const utfchar16_t LEAD_SURROGATE_MAX = 0xdbffu; +- const utfchar16_t TRAIL_SURROGATE_MIN = 0xdc00u; +- const utfchar16_t TRAIL_SURROGATE_MAX = 0xdfffu; +- const utfchar16_t LEAD_OFFSET = 0xd7c0u; // LEAD_SURROGATE_MIN - (0x10000 >> 10) +- const utfchar32_t SURROGATE_OFFSET = 0xfca02400u; // 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN +- +- // Maximum valid value for a Unicode code point +- const utfchar32_t CODE_POINT_MAX = 0x0010ffffu; +- +- template +- inline utfchar8_t mask8(octet_type oc) +- { +- return static_cast(0xff & oc); +- } +- +- template +- inline utfchar16_t mask16(u16_type oc) +- { +- return static_cast(0xffff & oc); +- } +- +- template +- inline bool is_trail(octet_type oc) +- { +- return ((utf8::internal::mask8(oc) >> 6) == 0x2); +- } +- +- inline bool is_lead_surrogate(utfchar32_t cp) +- { +- return (cp >= static_cast(LEAD_SURROGATE_MIN) && cp <= static_cast(LEAD_SURROGATE_MAX)); +- } ++ // Helper code - not intended to be directly called by the library users. May be changed at any time ++ namespace internal { ++ // Unicode constants ++ // Leading (high) surrogates: 0xd800 - 0xdbff ++ // Trailing (low) surrogates: 0xdc00 - 0xdfff ++ const utfchar16_t LEAD_SURROGATE_MIN = 0xd800u; ++ const utfchar16_t LEAD_SURROGATE_MAX = 0xdbffu; ++ const utfchar16_t TRAIL_SURROGATE_MIN = 0xdc00u; ++ const utfchar16_t TRAIL_SURROGATE_MAX = 0xdfffu; ++ const utfchar16_t LEAD_OFFSET = 0xd7c0u; // LEAD_SURROGATE_MIN - (0x10000 >> 10) ++ const utfchar32_t SURROGATE_OFFSET = 0xfca02400u; // 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN ++ ++ // Maximum valid value for a Unicode code point ++ const utfchar32_t CODE_POINT_MAX = 0x0010ffffu; ++ ++ template ++ inline utfchar8_t mask8(octet_type oc) { ++ return static_cast(0xff & oc); ++ } + +- inline bool is_trail_surrogate(utfchar32_t cp) +- { +- return (cp >= static_cast(TRAIL_SURROGATE_MIN) && cp <= static_cast(TRAIL_SURROGATE_MAX)); +- } ++ template ++ inline utfchar16_t mask16(u16_type oc) { ++ return static_cast(0xffff & oc); ++ } + +- inline bool is_surrogate(utfchar32_t cp) +- { +- return (cp >= static_cast(LEAD_SURROGATE_MIN) && cp <= static_cast(TRAIL_SURROGATE_MAX)); +- } ++ template ++ inline bool is_trail(octet_type oc) { ++ return ((utf8::internal::mask8(oc) >> 6) == 0x2); ++ } + +- inline bool is_code_point_valid(utfchar32_t cp) +- { +- return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); +- } ++ inline bool is_lead_surrogate(utfchar32_t cp) { ++ return (cp >= static_cast(LEAD_SURROGATE_MIN) ++ && cp <= static_cast(LEAD_SURROGATE_MAX)); ++ } + +- inline bool is_in_bmp(utfchar32_t cp) +- { +- return cp < utfchar32_t(0x10000); +- } ++ inline bool is_trail_surrogate(utfchar32_t cp) { ++ return (cp >= static_cast(TRAIL_SURROGATE_MIN) ++ && cp <= static_cast(TRAIL_SURROGATE_MAX)); ++ } + +- template +- int sequence_length(octet_iterator lead_it) +- { +- const utfchar8_t lead = utf8::internal::mask8(*lead_it); +- if (lead < 0x80) +- return 1; +- else if ((lead >> 5) == 0x6) +- return 2; +- else if ((lead >> 4) == 0xe) +- return 3; +- else if ((lead >> 3) == 0x1e) +- return 4; +- else +- return 0; +- } ++ inline bool is_surrogate(utfchar32_t cp) { ++ return (cp >= static_cast(LEAD_SURROGATE_MIN) ++ && cp <= static_cast(TRAIL_SURROGATE_MAX)); ++ } + +- inline bool is_overlong_sequence(utfchar32_t cp, int length) +- { +- if (cp < 0x80) { +- if (length != 1) +- return true; ++ inline bool is_code_point_valid(utfchar32_t cp) { ++ return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); + } +- else if (cp < 0x800) { +- if (length != 2) +- return true; ++ ++ inline bool is_in_bmp(utfchar32_t cp) { ++ return cp < utfchar32_t(0x10000); + } +- else if (cp < 0x10000) { +- if (length != 3) +- return true; ++ ++ template ++ int sequence_length(octet_iterator lead_it) { ++ const utfchar8_t lead = utf8::internal::mask8(*lead_it); ++ if (lead < 0x80) ++ return 1; ++ else if ((lead >> 5) == 0x6) ++ return 2; ++ else if ((lead >> 4) == 0xe) ++ return 3; ++ else if ((lead >> 3) == 0x1e) ++ return 4; ++ else ++ return 0; + } +- return false; +- } + +- enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; ++ inline bool is_overlong_sequence(utfchar32_t cp, int length) { ++ if (cp < 0x80) { ++ if (length != 1) ++ return true; ++ } else if (cp < 0x800) { ++ if (length != 2) ++ return true; ++ } else if (cp < 0x10000) { ++ if (length != 3) ++ return true; ++ } ++ return false; ++ } + +- /// Helper for get_sequence_x +- template +- utf_error increase_safely(octet_iterator& it, const octet_iterator end) +- { +- if (++it == end) +- return NOT_ENOUGH_ROOM; ++ enum utf_error { ++ UTF8_OK, ++ NOT_ENOUGH_ROOM, ++ INVALID_LEAD, ++ INCOMPLETE_SEQUENCE, ++ OVERLONG_SEQUENCE, ++ INVALID_CODE_POINT ++ }; + +- if (!utf8::internal::is_trail(*it)) +- return INCOMPLETE_SEQUENCE; ++ /// Helper for get_sequence_x ++ template ++ utf_error increase_safely(octet_iterator& it, const octet_iterator end) { ++ if (++it == end) ++ return NOT_ENOUGH_ROOM; + +- return UTF8_OK; +- } ++ if (!utf8::internal::is_trail(*it)) ++ return INCOMPLETE_SEQUENCE; + +- #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;} ++ return UTF8_OK; ++ } + +- /// get_sequence_x functions decode utf-8 sequences of the length x +- template +- utf_error get_sequence_1(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) +- { +- if (it == end) +- return NOT_ENOUGH_ROOM; ++#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) \ ++ { \ ++ utf_error ret = increase_safely(IT, END); \ ++ if (ret != UTF8_OK) \ ++ return ret; \ ++ } + +- code_point = static_cast(utf8::internal::mask8(*it)); ++ /// get_sequence_x functions decode utf-8 sequences of the length x ++ template ++ utf_error get_sequence_1(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) { ++ if (it == end) ++ return NOT_ENOUGH_ROOM; + +- return UTF8_OK; +- } ++ code_point = static_cast(utf8::internal::mask8(*it)); + +- template +- utf_error get_sequence_2(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) +- { +- if (it == end) +- return NOT_ENOUGH_ROOM; ++ return UTF8_OK; ++ } + +- code_point = static_cast(utf8::internal::mask8(*it)); ++ template ++ utf_error get_sequence_2(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) { ++ if (it == end) ++ return NOT_ENOUGH_ROOM; + +- UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) ++ code_point = static_cast(utf8::internal::mask8(*it)); + +- code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f); ++ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + +- return UTF8_OK; +- } ++ code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f); + +- template +- utf_error get_sequence_3(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) +- { +- if (it == end) +- return NOT_ENOUGH_ROOM; ++ return UTF8_OK; ++ } + +- code_point = static_cast(utf8::internal::mask8(*it)); ++ template ++ utf_error get_sequence_3(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) { ++ if (it == end) ++ return NOT_ENOUGH_ROOM; + +- UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) ++ code_point = static_cast(utf8::internal::mask8(*it)); + +- code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); ++ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + +- UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) ++ code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); + +- code_point = static_cast(code_point + ((*it) & 0x3f)); ++ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + +- return UTF8_OK; +- } ++ code_point = static_cast(code_point + ((*it) & 0x3f)); + +- template +- utf_error get_sequence_4(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) +- { +- if (it == end) +- return NOT_ENOUGH_ROOM; ++ return UTF8_OK; ++ } + +- code_point = static_cast(utf8::internal::mask8(*it)); ++ template ++ utf_error get_sequence_4(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) { ++ if (it == end) ++ return NOT_ENOUGH_ROOM; + +- UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) ++ code_point = static_cast(utf8::internal::mask8(*it)); + +- code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); ++ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + +- UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) ++ code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); + +- code_point = static_cast(code_point + ((utf8::internal::mask8(*it) << 6) & 0xfff)); ++ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + +- UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) ++ code_point = static_cast(code_point + ((utf8::internal::mask8(*it) << 6) & 0xfff)); + +- code_point = static_cast(code_point + ((*it) & 0x3f)); ++ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + +- return UTF8_OK; +- } ++ code_point = static_cast(code_point + ((*it) & 0x3f)); + +- #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR +- +- template +- utf_error validate_next(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) +- { +- if (it == end) +- return NOT_ENOUGH_ROOM; +- +- // Save the original value of it so we can go back in case of failure +- // Of course, it does not make much sense with i.e. stream iterators +- octet_iterator original_it = it; +- +- utfchar32_t cp = 0; +- // Determine the sequence length based on the lead octet +- const int length = utf8::internal::sequence_length(it); +- +- // Get trail octets and calculate the code point +- utf_error err = UTF8_OK; +- switch (length) { +- case 0: +- return INVALID_LEAD; +- case 1: +- err = utf8::internal::get_sequence_1(it, end, cp); +- break; +- case 2: +- err = utf8::internal::get_sequence_2(it, end, cp); +- break; +- case 3: +- err = utf8::internal::get_sequence_3(it, end, cp); +- break; +- case 4: +- err = utf8::internal::get_sequence_4(it, end, cp); +- break; ++ return UTF8_OK; + } + +- if (err == UTF8_OK) { +- // Decoding succeeded. Now, security checks... +- if (utf8::internal::is_code_point_valid(cp)) { +- if (!utf8::internal::is_overlong_sequence(cp, length)){ +- // Passed! Return here. +- code_point = cp; +- ++it; +- return UTF8_OK; +- } +- else +- err = OVERLONG_SEQUENCE; ++#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR ++ ++ template ++ utf_error validate_next(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) { ++ if (it == end) ++ return NOT_ENOUGH_ROOM; ++ ++ // Save the original value of it so we can go back in case of failure ++ // Of course, it does not make much sense with i.e. stream iterators ++ octet_iterator original_it = it; ++ ++ utfchar32_t cp = 0; ++ // Determine the sequence length based on the lead octet ++ const int length = utf8::internal::sequence_length(it); ++ ++ // Get trail octets and calculate the code point ++ utf_error err = UTF8_OK; ++ switch (length) { ++ case 0: ++ return INVALID_LEAD; ++ case 1: ++ err = utf8::internal::get_sequence_1(it, end, cp); ++ break; ++ case 2: ++ err = utf8::internal::get_sequence_2(it, end, cp); ++ break; ++ case 3: ++ err = utf8::internal::get_sequence_3(it, end, cp); ++ break; ++ case 4: ++ err = utf8::internal::get_sequence_4(it, end, cp); ++ break; + } +- else +- err = INVALID_CODE_POINT; +- } + +- // Failure branch - restore the original value of the iterator +- it = original_it; +- return err; +- } ++ if (err == UTF8_OK) { ++ // Decoding succeeded. Now, security checks... ++ if (utf8::internal::is_code_point_valid(cp)) { ++ if (!utf8::internal::is_overlong_sequence(cp, length)) { ++ // Passed! Return here. ++ code_point = cp; ++ ++it; ++ return UTF8_OK; ++ } else ++ err = OVERLONG_SEQUENCE; ++ } else ++ err = INVALID_CODE_POINT; ++ } + +- template +- inline utf_error validate_next(octet_iterator& it, octet_iterator end) { +- utfchar32_t ignored; +- return utf8::internal::validate_next(it, end, ignored); +- } ++ // Failure branch - restore the original value of the iterator ++ it = original_it; ++ return err; ++ } + +- template +- utf_error validate_next16(word_iterator& it, word_iterator end, utfchar32_t& code_point) +- { +- // Make sure the iterator dereferences a large enough type +- typedef typename std::iterator_traits::value_type word_type; +- UTF_CPP_STATIC_ASSERT(sizeof(word_type) >= sizeof(utfchar16_t)); +- // Check the edge case: +- if (it == end) +- return NOT_ENOUGH_ROOM; +- // Save the original value of it so we can go back in case of failure +- // Of course, it does not make much sense with i.e. stream iterators +- word_iterator original_it = it; +- +- utf_error err = UTF8_OK; +- +- const utfchar16_t first_word = *it++; +- if (!is_surrogate(first_word)) { +- code_point = first_word; +- return UTF8_OK; ++ template ++ inline utf_error validate_next(octet_iterator& it, octet_iterator end) { ++ utfchar32_t ignored; ++ return utf8::internal::validate_next(it, end, ignored); + } +- else { ++ ++ template ++ utf_error validate_next16(word_iterator& it, word_iterator end, utfchar32_t& code_point) { ++ // Make sure the iterator dereferences a large enough type ++ typedef typename std::iterator_traits::value_type word_type; ++ UTF_CPP_STATIC_ASSERT(sizeof(word_type) >= sizeof(utfchar16_t)); ++ // Check the edge case: + if (it == end) +- err = NOT_ENOUGH_ROOM; +- else if (is_lead_surrogate(first_word)) { +- const utfchar16_t second_word = *it++; +- if (is_trail_surrogate(static_cast(second_word))) { +- code_point = static_cast(first_word << 10) + static_cast(second_word) + SURROGATE_OFFSET; +- return UTF8_OK; +- } else +- err = INCOMPLETE_SEQUENCE; ++ return NOT_ENOUGH_ROOM; ++ // Save the original value of it so we can go back in case of failure ++ // Of course, it does not make much sense with i.e. stream iterators ++ word_iterator original_it = it; ++ ++ utf_error err = UTF8_OK; + ++ const utfchar16_t first_word = *it++; ++ if (!is_surrogate(first_word)) { ++ code_point = first_word; ++ return UTF8_OK; + } else { +- err = INVALID_LEAD; ++ if (it == end) ++ err = NOT_ENOUGH_ROOM; ++ else if (is_lead_surrogate(first_word)) { ++ const utfchar16_t second_word = *it++; ++ if (is_trail_surrogate(static_cast(second_word))) { ++ code_point = static_cast(first_word << 10) + static_cast(second_word) ++ + SURROGATE_OFFSET; ++ return UTF8_OK; ++ } else ++ err = INCOMPLETE_SEQUENCE; ++ ++ } else { ++ err = INVALID_LEAD; ++ } + } ++ // error branch ++ it = original_it; ++ return err; + } +- // error branch +- it = original_it; +- return err; +- } + +- // Internal implementation of both checked and unchecked append() function +- // This function will be invoked by the overloads below, as they will know +- // the octet_type. +- template +- octet_iterator append(utfchar32_t cp, octet_iterator result) { +- if (cp < 0x80) // one octet +- *(result++) = static_cast(cp); +- else if (cp < 0x800) { // two octets +- *(result++) = static_cast((cp >> 6) | 0xc0); +- *(result++) = static_cast((cp & 0x3f) | 0x80); +- } +- else if (cp < 0x10000) { // three octets +- *(result++) = static_cast((cp >> 12) | 0xe0); +- *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); +- *(result++) = static_cast((cp & 0x3f) | 0x80); +- } +- else { // four octets +- *(result++) = static_cast((cp >> 18) | 0xf0); +- *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); +- *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); +- *(result++) = static_cast((cp & 0x3f) | 0x80); ++ // Internal implementation of both checked and unchecked append() function ++ // This function will be invoked by the overloads below, as they will know ++ // the octet_type. ++ template ++ octet_iterator append(utfchar32_t cp, octet_iterator result) { ++ if (cp < 0x80) // one octet ++ *(result++) = static_cast(cp); ++ else if (cp < 0x800) { // two octets ++ *(result++) = static_cast((cp >> 6) | 0xc0); ++ *(result++) = static_cast((cp & 0x3f) | 0x80); ++ } else if (cp < 0x10000) { // three octets ++ *(result++) = static_cast((cp >> 12) | 0xe0); ++ *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); ++ *(result++) = static_cast((cp & 0x3f) | 0x80); ++ } else { // four octets ++ *(result++) = static_cast((cp >> 18) | 0xf0); ++ *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); ++ *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); ++ *(result++) = static_cast((cp & 0x3f) | 0x80); ++ } ++ return result; + } +- return result; +- } + +- // One of the following overloads will be invoked from the API calls ++ // One of the following overloads will be invoked from the API calls + +- // A simple (but dangerous) case: the caller appends byte(s) to a char array +- inline char* append(utfchar32_t cp, char* result) { +- return append(cp, result); +- } ++ // A simple (but dangerous) case: the caller appends byte(s) to a char array ++ inline char* append(utfchar32_t cp, char* result) { ++ return append(cp, result); ++ } + +- // Hopefully, most common case: the caller uses back_inserter +- // i.e. append(cp, std::back_inserter(str)); +- template +- std::back_insert_iterator append +- (utfchar32_t cp, std::back_insert_iterator result) { +- return append, +- typename container_type::value_type>(cp, result); +- } ++ // Hopefully, most common case: the caller uses back_inserter ++ // i.e. append(cp, std::back_inserter(str)); ++ template ++ std::back_insert_iterator ++ append(utfchar32_t cp, std::back_insert_iterator result) { ++ return append, typename container_type::value_type>(cp, result); ++ } + +- // The caller uses some other kind of output operator - not covered above +- // Note that in this case we are not able to determine octet_type +- // so we assume it's utfchar8_t; that can cause a conversion warning if we are wrong. +- template +- octet_iterator append(utfchar32_t cp, octet_iterator result) { +- return append(cp, result); +- } ++ // The caller uses some other kind of output operator - not covered above ++ // Note that in this case we are not able to determine octet_type ++ // so we assume it's utfchar8_t; that can cause a conversion warning if we are wrong. ++ template ++ octet_iterator append(utfchar32_t cp, octet_iterator result) { ++ return append(cp, result); ++ } + +- // Internal implementation of both checked and unchecked append16() function +- // This function will be invoked by the overloads below, as they will know +- // the word_type. +- template +- word_iterator append16(utfchar32_t cp, word_iterator result) { +- UTF_CPP_STATIC_ASSERT(sizeof(word_type) >= sizeof(utfchar16_t)); +- if (is_in_bmp(cp)) +- *(result++) = static_cast(cp); +- else { +- // Code points from the supplementary planes are encoded via surrogate pairs +- *(result++) = static_cast(LEAD_OFFSET + (cp >> 10)); +- *(result++) = static_cast(TRAIL_SURROGATE_MIN + (cp & 0x3FF)); ++ // Internal implementation of both checked and unchecked append16() function ++ // This function will be invoked by the overloads below, as they will know ++ // the word_type. ++ template ++ word_iterator append16(utfchar32_t cp, word_iterator result) { ++ UTF_CPP_STATIC_ASSERT(sizeof(word_type) >= sizeof(utfchar16_t)); ++ if (is_in_bmp(cp)) ++ *(result++) = static_cast(cp); ++ else { ++ // Code points from the supplementary planes are encoded via surrogate pairs ++ *(result++) = static_cast(LEAD_OFFSET + (cp >> 10)); ++ *(result++) = static_cast(TRAIL_SURROGATE_MIN + (cp & 0x3FF)); ++ } ++ return result; + } +- return result; +- } + +- // Hopefully, most common case: the caller uses back_inserter +- // i.e. append16(cp, std::back_inserter(str)); +- template +- std::back_insert_iterator append16 +- (utfchar32_t cp, std::back_insert_iterator result) { +- return append16, +- typename container_type::value_type>(cp, result); +- } ++ // Hopefully, most common case: the caller uses back_inserter ++ // i.e. append16(cp, std::back_inserter(str)); ++ template ++ std::back_insert_iterator ++ append16(utfchar32_t cp, std::back_insert_iterator result) { ++ return append16, typename container_type::value_type>(cp, result); ++ } + +- // The caller uses some other kind of output operator - not covered above +- // Note that in this case we are not able to determine word_type +- // so we assume it's utfchar16_t; that can cause a conversion warning if we are wrong. +- template +- word_iterator append16(utfchar32_t cp, word_iterator result) { +- return append16(cp, result); +- } ++ // The caller uses some other kind of output operator - not covered above ++ // Note that in this case we are not able to determine word_type ++ // so we assume it's utfchar16_t; that can cause a conversion warning if we are wrong. ++ template ++ word_iterator append16(utfchar32_t cp, word_iterator result) { ++ return append16(cp, result); ++ } + +-} // namespace internal ++ } // namespace internal + + /// The library API - functions intended to be called by the users + + // Byte order mark +- const utfchar8_t bom[] = {0xef, 0xbb, 0xbf}; ++ const utfchar8_t bom[] = { 0xef, 0xbb, 0xbf }; + +- template +- octet_iterator find_invalid(octet_iterator start, octet_iterator end) +- { ++ template ++ octet_iterator find_invalid(octet_iterator start, octet_iterator end) { + octet_iterator result = start; + while (result != end) { + utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end); +@@ -452,51 +447,60 @@ namespace internal + return result; + } + +- inline const char* find_invalid(const char* str) +- { ++ inline const char* find_invalid(const char* str) { + const char* end = str + std::strlen(str); + return find_invalid(str, end); + } + +- inline std::size_t find_invalid(const std::string& s) +- { ++ inline std::size_t find_invalid(const std::string& s) { + std::string::const_iterator invalid = find_invalid(s.begin(), s.end()); + return (invalid == s.end()) ? std::string::npos : static_cast(invalid - s.begin()); + } + +- template +- inline bool is_valid(octet_iterator start, octet_iterator end) +- { ++ template ++ inline bool is_valid(octet_iterator start, octet_iterator end) { + return (utf8::find_invalid(start, end) == end); + } + +- inline bool is_valid(const char* str) +- { ++ inline bool is_valid(const char* str) { + return (*(utf8::find_invalid(str)) == '\0'); + } + +- inline bool is_valid(const std::string& s) +- { ++ inline bool is_valid(const std::string& s) { + return is_valid(s.begin(), s.end()); + } + + +- +- template +- inline bool starts_with_bom (octet_iterator it, octet_iterator end) +- { +- return ( +- ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) && +- ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) && +- ((it != end) && (utf8::internal::mask8(*it)) == bom[2]) +- ); ++ template ++ inline bool starts_with_bom(octet_iterator it, octet_iterator end) { ++ return (((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) ++ && ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) ++ && ((it != end) && (utf8::internal::mask8(*it)) == bom[2])); + } + +- inline bool starts_with_bom(const std::string& s) +- { ++ inline bool starts_with_bom(const std::string& s) { + return starts_with_bom(s.begin(), s.end()); + } + } // namespace utf8 + +-#endif // header guard + ++#if defined(UTFCPP_NO_EXCEPTIONS) ++#if defined(__UEFI__) ++#define UTFCPP_THROW(exc) \ ++ do { \ ++ DEBUG((DEBUG_ERROR, "THROW %a:%d - %a: %a\n", __FILE__, __LINE__, __FUNCTION__, exc.what())); \ ++ abort(); \ ++ } while (false) ++#else ++#define UTFCPP_THROW(exc) \ ++ do { \ ++ std::cerr << "THROW " << (__FILE__) << ":" << (__LINE__) << " - " << (__FUNCTION__) << ": " << (exc.what()) \ ++ << "\n"; \ ++ abort(); \ ++ } while (false) ++#endif ++#else ++#define UTFCPP_THROW(exc) throw exc ++#endif ++ ++#endif // header guard diff --git a/subprojects/packagefiles/zlib-1.3.2_uefi_fix.diff b/subprojects/packagefiles/zlib-1.3.2_uefi_fix.diff new file mode 100644 index 000000000..852e5dbf4 --- /dev/null +++ b/subprojects/packagefiles/zlib-1.3.2_uefi_fix.diff @@ -0,0 +1,15 @@ +diff --git a/deflate.c b/deflate.c +index d7d2c7c..4eaa3f6 100644 +--- a/deflate.c ++++ b/deflate.c +@@ -1647,6 +1647,10 @@ local void check_match(deflate_state *s, IPos start, IPos match, int length) { + /* Maximum stored block length in deflate format (not including header). */ + #define MAX_STORED 65535 + ++#if defined(__UEFI__) ++#undef MIN ++#endif ++ + /* Minimum of a and b. */ + #define MIN(a, b) ((a) > (b) ? (b) : (a)) + diff --git a/subprojects/sdl2_image.wrap b/subprojects/sdl2_image.wrap index 2206ad110..205c5d174 100644 --- a/subprojects/sdl2_image.wrap +++ b/subprojects/sdl2_image.wrap @@ -8,6 +8,6 @@ patch_url = https://wrapdb.mesonbuild.com/v2/sdl2_image_2.6.3-3/get_patch patch_hash = 4c7132ec24d277c54491c3faad75c4a5d0c5ce15cb9fadbd72b232d7abf35d7e source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/sdl2_image_2.6.3-3/SDL2_image-2.6.3.tar.gz wrapdb_version = 2.6.3-3 - +diff_files = SDL2_image_2.6.3_define_fix.diff [provide] sdl2_image = sdl2_image_dep diff --git a/subprojects/sdl2_mixer.wrap b/subprojects/sdl2_mixer.wrap index 080986ec2..86264017c 100644 --- a/subprojects/sdl2_mixer.wrap +++ b/subprojects/sdl2_mixer.wrap @@ -8,7 +8,7 @@ patch_url = https://wrapdb.mesonbuild.com/v2/sdl2_mixer_2.6.2-4/get_patch patch_hash = 127025fa0666dd3ea66fb7c334182c393a748fb78810c6a44cdc1a85d619d934 source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/sdl2_mixer_2.6.2-4/SDL2_mixer-2.6.2.tar.gz wrapdb_version = 2.6.2-4 -diff_files = sdl2_mixer-2.6.2_correct_flac_wrap.diff +diff_files = sdl2_mixer-2.6.2_correct_flac_wrap.diff, sdl2_mixer-2.6.2_example_option.diff [provide] sdl2_mixer = sdl2_mixer_dep diff --git a/subprojects/sdl2_ttf.wrap b/subprojects/sdl2_ttf.wrap index 4fd78ddbd..235f525ff 100644 --- a/subprojects/sdl2_ttf.wrap +++ b/subprojects/sdl2_ttf.wrap @@ -8,6 +8,7 @@ patch_url = https://wrapdb.mesonbuild.com/v2/sdl2_ttf_2.20.1-4/get_patch patch_hash = 44311aba31c9d5a3366101e5afd439a1d95e64d2079e9d5487e4d0790b6858f1 source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/sdl2_ttf_2.20.1-4/SDL2_ttf-2.20.1.tar.gz wrapdb_version = 2.20.1-4 +diff_files = sdl2_ttf-2.20.1_sdl_uefi_sse_fix.diff [provide] sdl2_ttf = sdl2_ttf_dep diff --git a/subprojects/spdlog.wrap b/subprojects/spdlog.wrap index 815f8f18a..82083f0f8 100644 --- a/subprojects/spdlog.wrap +++ b/subprojects/spdlog.wrap @@ -9,7 +9,7 @@ patch_url = https://wrapdb.mesonbuild.com/v2/spdlog_1.17.0-1/get_patch patch_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/spdlog_1.17.0-1/spdlog_1.17.0-1_patch.zip patch_hash = 295bcca990facdca84256b60aaa86ba2e2320895cad30bee997d7a463a30b40c wrapdb_version = 1.17.0-1 -diff_files = spdlog_1.17.0_fmt_12.0.0_compatibility.diff, spdlog_1.17.0_no_tls_option.diff, spdlog_1.17.0_nintendo_time_fix.diff +diff_files = spdlog_1.17.0_fmt_12.0.0_compatibility.diff, spdlog_1.17.0_no_tls_option.diff, spdlog_1.17.0_nintendo_time_fix.diff, spdlog_1.17.0_std_format_detection_fix.diff, spdlog_1.17.0_uefi_support.diff [provide] diff --git a/subprojects/tl-expected.wrap b/subprojects/tl-expected.wrap index 0f6610fec..0122fcda8 100644 --- a/subprojects/tl-expected.wrap +++ b/subprojects/tl-expected.wrap @@ -8,8 +8,7 @@ patch_filename = tl-expected_1.3.1-1_patch.zip patch_url = https://wrapdb.mesonbuild.com/v2/tl-expected_1.3.1-1/get_patch patch_hash = 91cfeae04ba6ea05792e68a37781236a7045b9e2e4e0c8b7093fd8c3e43b0bad wrapdb_version = 1.3.1-1 - -diff_files = expected-1.1.0_installable.diff +diff_files = expected-1.3.1_installable.diff [provide] dependency_names = tl-expected diff --git a/subprojects/utfcpp.wrap b/subprojects/utfcpp.wrap index 3ecb8f765..9207c8941 100644 --- a/subprojects/utfcpp.wrap +++ b/subprojects/utfcpp.wrap @@ -8,6 +8,7 @@ patch_filename = utfcpp_4.0.8-1_patch.zip patch_url = https://wrapdb.mesonbuild.com/v2/utfcpp_4.0.8-1/get_patch patch_hash = 83888527bbd2ee13f49f3d791ecdc698b95c614da3e23c44b87c185bd5c19989 wrapdb_version = 4.0.8-1 +diff_files = utfcpp-4.0.8_no_exceptions.diff [provide] dependency_names = utf8cpp diff --git a/subprojects/zlib.wrap b/subprojects/zlib.wrap index 0626401ac..e1d21b9d8 100644 --- a/subprojects/zlib.wrap +++ b/subprojects/zlib.wrap @@ -9,6 +9,7 @@ patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.3.2-1/get_patch patch_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/zlib_1.3.2-1/zlib_1.3.2-1_patch.zip patch_hash = 5ae7a2e92f823df118cfb8c1b23d94e3117864392b3446581d669049b2fba6dd wrapdb_version = 1.3.2-1 +diff_files = zlib-1.3.2_uefi_fix.diff [provide] dependency_names = zlib diff --git a/tests/core/color.cpp b/tests/core/color.cpp index ae4b42a12..b6d8c1d4e 100644 --- a/tests/core/color.cpp +++ b/tests/core/color.cpp @@ -35,18 +35,18 @@ operator==(const HSVColor& value1, const HSVColor& value2) { //NOLINT(misc-use-i // make colors printable -void PrintTo(const Color& color, std::ostream* os) { //NOLINT(misc-use-internal-linkage) +static void PrintTo(const Color& color, std::ostream* os) { //NOLINT(misc-use-internal-linkage) *os << color.to_string(); } -void PrintTo(const HSVColor& color, std::ostream* os) { //NOLINT(misc-use-internal-linkage) +static void PrintTo(const HSVColor& color, std::ostream* os) { //NOLINT(misc-use-internal-linkage) *os << color.to_string(); } namespace color { - void PrintTo(const SerializeMode& value, std::ostream* os) { //NOLINT(misc-use-internal-linkage) + static void PrintTo(const SerializeMode& value, std::ostream* os) { //NOLINT(misc-use-internal-linkage) *os << magic_enum::enum_name(value); } diff --git a/tests/graphics/sdl_key.cpp b/tests/graphics/sdl_key.cpp index 26c610ba2..e14e6e152 100644 --- a/tests/graphics/sdl_key.cpp +++ b/tests/graphics/sdl_key.cpp @@ -13,12 +13,12 @@ namespace sdl { // make keys printable - void PrintTo(const Key& key, std::ostream* os) { //NOLINT(misc-use-internal-linkage) + static void PrintTo(const Key& key, std::ostream* os) { //NOLINT(misc-use-internal-linkage) *os << key.to_string(); } - std::ostream& operator<<(std::ostream& os, const Key& value) { //NOLINT(misc-use-internal-linkage) + static std::ostream& operator<<(std::ostream& os, const Key& value) { //NOLINT(misc-use-internal-linkage) os << value.to_string(); return os; } diff --git a/tools/dependencies/meson.build b/tools/dependencies/meson.build index e05e6e115..2be0d3b28 100644 --- a/tools/dependencies/meson.build +++ b/tools/dependencies/meson.build @@ -133,6 +133,14 @@ if meson.is_cross_build() 'deps': [graphics_lib.get('deps'), native_deps], } + elif host_machine.system() == 'uefi' + temp = core_lib.get('compile_args') + temp += '-D__OOPETRIS_HAVE_NO_THREADS' + + core_lib += { + 'compile_args': temp, + } + temp = 0 else error('Unhandled cross built system: ' + host_machine.system()) endif @@ -143,9 +151,21 @@ fmt_use_header_only = false if ( meson.is_cross_build() and (host_machine.system() == 'switch' - or host_machine.system() == '3ds') + or host_machine.system() == '3ds' + or host_machine.system() == 'uefi') ) fmt_use_header_only = true + + temp = core_lib.get('compile_args') + temp += '-D__OOPETRIS_NO_EXCEPTIONS=1' + temp += '-DJSON_NOEXCEPTION=1' + temp += '-DSPDLOG_NO_EXCEPTIONS=1' + temp += '-DUTFCPP_NO_EXCEPTIONS=1' + temp += '-DFMT_USE_INT128=0' + core_lib += { + 'compile_args': temp, + } + temp = 0 endif if fmt_use_header_only @@ -301,16 +321,24 @@ if build_application endif ## the switch sdl2 packages are not findable with '--fatal-meson-warnings' and cmake, so prefind it and than override the dependency - if (meson.is_cross_build() and host_machine.system() == 'switch') - sdl2_ttf_switch_dep = dependency( - 'sdl2_ttf', - 'SDL2_ttf', - method: 'pkg-config', - allow_fallback: not only_allow_native_libs, - required: true, - ) + if meson.is_cross_build() + if host_machine.system() == 'switch' + sdl2_ttf_switch_dep = dependency( + 'sdl2_ttf', + 'SDL2_ttf', + method: 'pkg-config', + allow_fallback: not only_allow_native_libs, + required: true, + ) - meson.override_dependency('sdl2_ttf', sdl2_ttf_switch_dep) + meson.override_dependency('sdl2_ttf', sdl2_ttf_switch_dep) + elif host_machine.system() == 'uefi' + c_embed_dep = dependency('c-embed') + + graphics_lib += { + 'deps': [graphics_lib.get('deps'), c_embed_dep], + } + endif endif @@ -329,6 +357,9 @@ if build_application 'SDL2_image', allow_fallback: not only_allow_native_libs, required: true, + default_options: { + 'test': false, + }, ) graphics_lib += { 'deps': [graphics_lib.get('deps'), sdl2_image_dep], @@ -378,16 +409,44 @@ if build_application spdlog_no_tls = false + if (meson.is_cross_build() and host_machine.system() == '3ds') spdlog_no_tls = true endif + spdlog_std_format = 'auto' + + if not cpp.has_header_symbol( + 'format', + '__cpp_lib_format', + args: core_lib.get('compile_args'), + ) or not cpp.compiles( + ''' + #include + int main(void) { + /* If it's not defined as a macro, try to use as a symbol */ + #ifndef __cpp_lib_format + __cpp_lib_format; + #else + #if __cpp_lib_format < 202207L + #error "fmt not supported" + #endif + #endif + return 0; + } + ''', + args: core_lib.get('compile_args'), + ) + spdlog_std_format = 'disabled' + endif + spdlog_dep = dependency( 'spdlog', required: true, default_options: { 'tests': 'disabled', 'no_tls': spdlog_no_tls, + 'std_format': spdlog_std_format, }, ) graphics_lib += { @@ -399,8 +458,12 @@ if build_application required: false, allow_fallback: true, default_options: { - 'openssl': 'enabled', + 'tls': 'enabled', + 'tls_backend': 'openssl', 'zlib': 'enabled', + 'brotli': 'auto', + 'zstd': 'auto', + 'test': false, }, ) @@ -419,6 +482,24 @@ if build_application graphics_lib += { 'compile_args': [graphics_lib.get('compile_args'), '-D_OOPETRIS_ONLINE_SYSTEM=1'], } + elif meson.is_cross_build() and host_machine.system() == 'uefi' + online_multiplayer_system = 'uefi' + + uefi_http_lib_dep = dependency('uefi:HttpLib') + uefi_http_io_lib_dep = dependency('uefi:HttpIoLib') + uefi_crypto_lib_dep = dependency('uefi:BaseCryptLib') + + graphics_lib += { + 'deps': [ + graphics_lib.get('deps'), + uefi_http_lib_dep, + uefi_http_io_lib_dep, + uefi_crypto_lib_dep, + ], + 'compile_args': [graphics_lib.get('compile_args'), '-D_OOPETRIS_ONLINE_SYSTEM=3'], + } + + else online_multiplayer_system = 'curl' diff --git a/tools/options/meson.build b/tools/options/meson.build index 2071d2f80..e34af035f 100644 --- a/tools/options/meson.build +++ b/tools/options/meson.build @@ -1,15 +1,86 @@ oopetris_author = 'Coder2k' oopetris_name = 'OOPetris' +cpp = meson.get_compiler('cpp') + +internal_cpp_compiler_args = cpp.get_supported_arguments( + '-Wassign-enum', + '-Wenum-conversion', + '-Wenum-switch', + '-fstrict-enums', + '-Wenum-identifier', + '-Wenum-compare', + '-Wenum-enum-conversion', + '-Wenum-float-conversion', + '-Wenum-too-large', + '-Wenum-compare-switch', + '-Wenum-compare-conditional', + '-fno-strict-aliasing', + '-Wpointer-arith', + '-Wmissing-declarations', + '-Wformat=2', + '-Wstrict-prototypes', + '-Wmissing-prototypes', + '-Wnested-externs', + '-Wold-style-definition', + '-Wundef', + '-Wunused', + '-Wcast-align', + '-Wmissing-format-attribute', + '-Wmissing-include-dirs', + '-Wlogical-op', + '-Wignored-qualifiers', + '-Werror=redundant-decls', + '-Werror=implicit', + '-Werror=nonnull', + '-Werror=init-self', + '-Werror=main', + '-Werror=missing-braces', + '-Werror=sequence-point', + '-Werror=return-type', + '-Werror=trigraphs', + '-Werror=array-bounds', + '-Werror=write-strings', + '-Werror=address', + '-Werror=int-to-pointer-cast', + '-Werror=pointer-to-int-cast', + '-Werror=empty-body', + '-Werror=write-strings', + '-Werror=strict-aliasing', + '-Wno-sign-compare', + '-Wno-cast-function-type', + '-Wno-unused-parameter', + '-Wno-missing-field-initializers', + '-Wno-type-limits', + '-Wshadow', + '-Wfloat-conversion', +) + +common_cpp_compiler_args = [] + +foreach internal_cpp_compiler_arg : internal_cpp_compiler_args + + # cpp.get_supported_arguments reports true, but it is not really smart and the actual compiler doesn't accept this :( + ##TODO: maybe file a meson bug? + if internal_cpp_compiler_arg not in ['-Werror=implicit', '-Werror=pointer-to-int-cast'] + common_cpp_compiler_args += internal_cpp_compiler_arg + endif + +endforeach + +if cpp.get_id() == 'gcc' + common_cpp_compiler_args += cpp.get_supported_arguments('-Wno-missing-braces') +endif + core_lib = { 'inc_dirs': [], - 'compile_args': ['-DOOPETRIS_VERSION=' + meson.project_version()], + 'compile_args': ['-DOOPETRIS_VERSION=' + meson.project_version()] + common_cpp_compiler_args, 'deps': [], } recordings_lib = { 'inc_dirs': [], - 'compile_args': [], + 'compile_args': [] + common_cpp_compiler_args, 'deps': [], } @@ -19,7 +90,7 @@ graphics_lib = { '-DOOPETRIS_VERSION=' + meson.project_version(), '-DOOPETRIS_NAME=' + oopetris_name, '-DOOPETRIS_AUTHOR=' + oopetris_author, - ], + ] + common_cpp_compiler_args, 'deps': [], } @@ -266,6 +337,8 @@ elif cpp.get_id() == 'clang' endif + message('Building C++ with libc++') + else # TODO: once clang with libstdc++ (gcc c++ stdlib) supports std::expected, remove this special behaviour allow_tl_expected_fallback = true diff --git a/wrapper/java b/wrapper/java index 209d69fee..a747e4c33 160000 --- a/wrapper/java +++ b/wrapper/java @@ -1 +1 @@ -Subproject commit 209d69fee297430461f39d633c7c1160df823816 +Subproject commit a747e4c33e6a67b346ece586299b377a751a0103