mirror of
https://github.com/ARMSX2/ARMSX1.git
synced 2026-08-24 16:53:35 -07:00
1097 lines
50 KiB
Makefile
1097 lines
50 KiB
Makefile
.ONESHELL:
|
|
.SHELLFLAGS := -ec
|
|
|
|
# ★ Pinned, not inherited. GNU make's default goal is whichever target it happens to read FIRST,
|
|
# so any rule added above `all:` silently becomes what a bare `make` builds. Adding the pgo-stamp
|
|
# helper below did exactly that — plain `make` started printing a hash instead of building the
|
|
# emulator, and nothing complained, because ./build.sh names its goals explicitly and every test
|
|
# gate does too. Pinning it here makes where a rule is written irrelevant.
|
|
.DEFAULT_GOAL := all
|
|
|
|
WASM_TARGET := $(filter wasm,$(MAKECMDGOALS))
|
|
|
|
ifeq ($(WASM_TARGET),wasm)
|
|
CC := emcc
|
|
CXX := em++
|
|
SDL_STATIC := 0
|
|
SDL_CFLAGS := -sUSE_SDL=2
|
|
SDL_LIBS_DYNAMIC :=
|
|
SDL_LIBS_STATIC :=
|
|
WASM_LDFLAGS := -sUSE_SDL=2 -sALLOW_MEMORY_GROWTH=1 -sASSERTIONS=1 -sFORCE_FILESYSTEM=1 -sFULL_ES3=1 -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 -sNO_EXIT_RUNTIME=0 -sEXPORTED_RUNTIME_METHODS='["FS","ccall","cwrap"]' -sEXPORTED_FUNCTIONS='["_main","_psxe_run","_external_main","_external_main_ex","_psxe_wasm_on_file","_psxe_wasm_on_error","_psxe_enqueue_launch_argument"]' --preload-file icons@/icons
|
|
endif
|
|
|
|
SDL_CONFIG ?= sdl2-config
|
|
|
|
CC ?= gcc
|
|
CXX ?= g++
|
|
AR := /usr/bin/ar
|
|
RANLIB := /usr/bin/ranlib
|
|
|
|
SDL_CFLAGS ?= $(shell $(SDL_CONFIG) --cflags 2>/dev/null)
|
|
SDL_LIBS_DYNAMIC ?= $(shell $(SDL_CONFIG) --libs 2>/dev/null)
|
|
SDL_LIBS_STATIC ?= $(shell $(SDL_CONFIG) --static-libs 2>/dev/null || $(SDL_CONFIG) --libs --static 2>/dev/null)
|
|
SDL_STATIC ?= 1
|
|
WASM_LDFLAGS ?=
|
|
USE_CHD ?= 1
|
|
HW_DEBUG ?= 0
|
|
|
|
# Presentation backends (frontend/render*.cpp). The SDL_Renderer backend is always built.
|
|
# ARMSX_ENABLE_GL GLES 3.0 / GL 3.3-core present path. Needs nothing but SDL at build
|
|
# time (entry points come from SDL_GL_GetProcAddress); on Android it
|
|
# additionally binds EGL to the host ANativeWindow, which needs -lEGL.
|
|
# ARMSX_ENABLE_VULKAN Vulkan present path. EXPERIMENTAL and compile-verified only. Needs
|
|
# <vulkan/vulkan.h> at build time; libvulkan is dlopen()ed at runtime
|
|
# through a replaceable loader, so there is no -lvulkan.
|
|
# ARMSX_ENABLE_SHADERS RetroArch (.slangp) shader chains via librashader
|
|
# (frontend/render_shaders.cpp). Adds NO link-time dependency:
|
|
# third_party/librashader/prebuilt/arm64-v8a/liblibrashader_capi.so is
|
|
# dlopen()ed, so `llvm-readelf -d bin/libarmsx.so` gains nothing and a
|
|
# missing librashader degrades to plain presentation. Forced off below
|
|
# when ARMSX_ENABLE_VULKAN is off — librashader has no GLES runtime, so
|
|
# there would be no present path to hook.
|
|
ARMSX_ENABLE_GL ?= 1
|
|
ARMSX_ENABLE_VULKAN ?= 0
|
|
ARMSX_ENABLE_SHADERS ?= 1
|
|
|
|
PLATFORM := $(shell uname -s)
|
|
ifeq ($(WASM_TARGET),wasm)
|
|
PLATFORM := Emscripten
|
|
endif
|
|
IOS_TARGET ?= 0
|
|
IOS_SDK ?= iphoneos
|
|
IOS_DEPLOYMENT_TARGET ?= 14.0
|
|
MACOS_DEPLOYMENT_TARGET ?= 10.15
|
|
WINDOWS_TARGET ?= 0
|
|
UWP_TARGET ?= 0
|
|
PSVITA_TARGET ?= 0
|
|
VITASDK ?=
|
|
IOS_SDL_FRAMEWORK ?= $(CURDIR)/ios/Frameworks/SDL2.xcframework/ios-arm64/SDL2.framework
|
|
IOS_SDL_FRAMEWORK_PARENT := $(dir $(IOS_SDL_FRAMEWORK))
|
|
SDKROOT ?=
|
|
CONTROLLER_GENERIC ?= 0
|
|
FSUI_DIR := third_party/fsui-lib
|
|
FSUI_BUILD_DIR ?= build/fsui/native
|
|
WASM_HTML_POSTPROCESS := web/postprocess_web_html.cmake
|
|
FSUI_LINK_SYSTEM_GL ?= 1
|
|
|
|
ifeq ($(PSVITA_TARGET),1)
|
|
ifeq ($(strip $(VITASDK)),)
|
|
$(error VITASDK must be set when PSVITA_TARGET=1)
|
|
endif
|
|
SDL_CONFIG := $(VITASDK)/bin/arm-vita-eabi-pkg-config
|
|
CC := $(VITASDK)/bin/arm-vita-eabi-gcc
|
|
CXX := $(VITASDK)/bin/arm-vita-eabi-g++
|
|
AR := $(VITASDK)/bin/arm-vita-eabi-ar
|
|
RANLIB := $(VITASDK)/bin/arm-vita-eabi-ranlib
|
|
PLATFORM := Vita
|
|
SDL_STATIC := 1
|
|
endif
|
|
|
|
ifeq ($(IOS_TARGET),1)
|
|
SDKROOT ?= $(shell xcrun --sdk $(IOS_SDK) --show-sdk-path)
|
|
CC ?= $(shell xcrun --sdk $(IOS_SDK) --find clang)
|
|
CXX ?= $(shell xcrun --sdk $(IOS_SDK) --find clang++)
|
|
|
|
# Force dynamic SDL when targeting iOS
|
|
SDL_STATIC := 0
|
|
SDL_CFLAGS := -isysroot $(SDKROOT) -arch arm64 -miphoneos-version-min=$(IOS_DEPLOYMENT_TARGET) \
|
|
-F$(IOS_SDL_FRAMEWORK_PARENT) -I$(IOS_SDL_FRAMEWORK)/Headers -DIOS_TARGET -D_THREAD_SAFE
|
|
SDL_LIBS_DYNAMIC := -isysroot $(SDKROOT) -arch arm64 -miphoneos-version-min=$(IOS_DEPLOYMENT_TARGET) \
|
|
-F$(IOS_SDL_FRAMEWORK_PARENT) -framework SDL2
|
|
SDL_LIBS_STATIC :=
|
|
endif
|
|
|
|
BASE_CFLAGS = -g -DLOG_USE_COLOR -I"." -I"psx" $(SDL_CFLAGS)
|
|
BASE_CFLAGS += -O3 -ffast-math -Wno-overflow -Wall -pedantic -Wno-address-of-packed-member -flto
|
|
|
|
FSUI_INCLUDE_FLAGS = \
|
|
-I$(FSUI_DIR)/include \
|
|
-I$(FSUI_DIR)/third_party/imgui \
|
|
-I$(FSUI_DIR)/third_party/imgui/backends \
|
|
-I$(FSUI_DIR)/third_party/stb
|
|
|
|
ifneq ($(WASM_TARGET),wasm)
|
|
FSUI_INCLUDE_FLAGS += -I$(FSUI_BUILD_DIR)/gladsources/fsui_glad/include
|
|
endif
|
|
|
|
FSUI_COMPILE_DEFS = -DIMGUI_FRONTEND -DFSUI_HAS_SDL2_PLATFORM -DFSUI_HAS_SDL2SURFACE_RENDERER -DFSUI_HAS_SDL2RENDERER_RENDERER -DSDL_MAIN_HANDLED
|
|
|
|
LIBCHDR_DIR := third_party/libchdr
|
|
LIBCHDR_BUILD_DIR :=
|
|
LIBCHDR_INCLUDE_FLAGS :=
|
|
LIBCHDR_INPUTS :=
|
|
LIBCHDR_ARCHIVE :=
|
|
LIBCHDR_LIBS :=
|
|
LIBCHDR_CONFIGURE :=
|
|
LIBCHDR_CMAKE_ARGS :=
|
|
CHD_COMPILE_DEFS :=
|
|
CHD_BUILD_DEPS :=
|
|
CHD_LINK_LIBS :=
|
|
ifeq ($(USE_CHD),1)
|
|
ifeq ($(WASM_TARGET),wasm)
|
|
LIBCHDR_BUILD_DIR := build/libchdr/wasm
|
|
else ifeq ($(PSVITA_TARGET),1)
|
|
LIBCHDR_BUILD_DIR := build/libchdr/psvita
|
|
else ifeq ($(IOS_TARGET),1)
|
|
LIBCHDR_BUILD_DIR := build/libchdr/ios
|
|
else
|
|
LIBCHDR_BUILD_DIR := build/libchdr/native
|
|
endif
|
|
|
|
LIBCHDR_INCLUDE_FLAGS := -I$(LIBCHDR_DIR)/include -I$(LIBCHDR_DIR)/deps/miniz-3.1.1
|
|
LIBCHDR_INPUTS := $(shell find $(LIBCHDR_DIR) -type f 2>/dev/null)
|
|
LIBCHDR_ARCHIVE := $(LIBCHDR_BUILD_DIR)/libchdr-static.a
|
|
LIBCHDR_LIBS := \
|
|
$(LIBCHDR_ARCHIVE) \
|
|
$(LIBCHDR_BUILD_DIR)/deps/lzma-25.01/libchdr-lzma.a \
|
|
$(LIBCHDR_BUILD_DIR)/deps/miniz-3.1.1/libminiz.a \
|
|
$(LIBCHDR_BUILD_DIR)/deps/zstd-1.5.7/libzstd.a
|
|
LIBCHDR_CONFIGURE := cmake
|
|
ifeq ($(WASM_TARGET),wasm)
|
|
LIBCHDR_CONFIGURE := emcmake cmake
|
|
endif
|
|
|
|
LIBCHDR_CMAKE_ARGS := -S $(LIBCHDR_DIR) -B $(LIBCHDR_BUILD_DIR) -DBUILD_SHARED_LIBS=OFF -DCHDR_WANT_RAW_DATA_SECTOR=ON -DCHDR_WANT_SUBCODE=ON -DMINIZ_ARCHIVE_APIS=ON -DMINIZ_STDIO=ON -DCMAKE_BUILD_TYPE=Release
|
|
# Extra cmake args injectable per-platform (e.g. Android passes -DCMAKE_SYSTEM_NAME=Linux so the
|
|
# host-macOS CMake stops adding an unsupported -arch flag to the NDK clang cross-build).
|
|
LIBCHDR_CMAKE_ARGS += $(LIBCHDR_EXTRA_CMAKE_ARGS)
|
|
ifneq ($(strip $(CC)),)
|
|
LIBCHDR_CMAKE_ARGS += -DCMAKE_C_COMPILER=$(CC)
|
|
endif
|
|
ifneq ($(strip $(CXX)),)
|
|
LIBCHDR_CMAKE_ARGS += -DCMAKE_CXX_COMPILER=$(CXX)
|
|
endif
|
|
ifneq ($(strip $(AR)),)
|
|
LIBCHDR_CMAKE_ARGS += -DCMAKE_AR=$(AR)
|
|
endif
|
|
ifneq ($(strip $(RANLIB)),)
|
|
LIBCHDR_CMAKE_ARGS += -DCMAKE_RANLIB=$(RANLIB)
|
|
endif
|
|
ifeq ($(PLATFORM),Darwin)
|
|
ifneq ($(IOS_TARGET),1)
|
|
LIBCHDR_CMAKE_ARGS += -DCMAKE_OSX_DEPLOYMENT_TARGET=$(MACOS_DEPLOYMENT_TARGET)
|
|
endif
|
|
endif
|
|
ifeq ($(IOS_TARGET),1)
|
|
LIBCHDR_CMAKE_ARGS += -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_OSX_DEPLOYMENT_TARGET=$(IOS_DEPLOYMENT_TARGET) -DCMAKE_OSX_SYSROOT=$(SDKROOT)
|
|
endif
|
|
|
|
CHD_COMPILE_DEFS := -DUSE_CHD
|
|
CHD_BUILD_DEPS := $(LIBCHDR_ARCHIVE)
|
|
CHD_LINK_LIBS := $(LIBCHDR_LIBS)
|
|
endif
|
|
|
|
# RetroAchievements (rcheevos, vendored). RC_NO_THREADS: frontend/achievements.cpp serialises
|
|
# every rc_client call behind its own lock, so the library's optional threading is dead weight.
|
|
# The hashers we do NOT need are compiled out; RC_HASH_NO_DISC is deliberately absent, because
|
|
# the PS1 disc hash (src/rhash/hash_disc.c) is exactly what game identification runs on.
|
|
RCHEEVOS_DIR := third_party/rcheevos
|
|
RCHEEVOS_INCLUDE_FLAGS := -I$(RCHEEVOS_DIR)/include
|
|
RCHEEVOS_COMPILE_DEFS := -DRC_NO_THREADS=1 -DRC_HASH_NO_ENCRYPTED -DRC_HASH_NO_ROM -DRC_HASH_NO_ZIP
|
|
|
|
BASE_CXXFLAGS = -std=c++20 $(BASE_CFLAGS) $(FSUI_INCLUDE_FLAGS) $(FSUI_COMPILE_DEFS)
|
|
BASE_CFLAGS += $(LIBCHDR_INCLUDE_FLAGS) $(CHD_COMPILE_DEFS)
|
|
BASE_CXXFLAGS += $(LIBCHDR_INCLUDE_FLAGS) $(CHD_COMPILE_DEFS)
|
|
BASE_CFLAGS += $(RCHEEVOS_INCLUDE_FLAGS) $(RCHEEVOS_COMPILE_DEFS)
|
|
BASE_CXXFLAGS += $(RCHEEVOS_INCLUDE_FLAGS) $(RCHEEVOS_COMPILE_DEFS)
|
|
|
|
# adrenotools (BSD 2-Clause, third_party/libadrenotools). Set by build.sh's android target, which
|
|
# builds the static lib and stages the hook .so files. Empty everywhere else: the loader compiles
|
|
# to its dlopen fallback when ARMSX_HAVE_ADRENOTOOLS is undefined.
|
|
ADRENOTOOLS_FLAGS ?=
|
|
BASE_CFLAGS += $(ADRENOTOOLS_FLAGS)
|
|
BASE_CXXFLAGS += $(ADRENOTOOLS_FLAGS)
|
|
|
|
ifeq ($(CONTROLLER_GENERIC),1)
|
|
BASE_CFLAGS += -DCONTROLLER_GENERIC
|
|
BASE_CXXFLAGS += -DCONTROLLER_GENERIC
|
|
endif
|
|
|
|
BASE_CFLAGS += -DUSE_HARDWARE
|
|
BASE_CXXFLAGS += -DUSE_HARDWARE
|
|
|
|
# The Vita has no GL/Vulkan surface we can reach through SDL, and the wasm target is served
|
|
# by SDL's own GL emulation; keep both on the SDL backend.
|
|
ifeq ($(PSVITA_TARGET),1)
|
|
ARMSX_ENABLE_GL := 0
|
|
ARMSX_ENABLE_VULKAN := 0
|
|
endif
|
|
ifeq ($(WASM_TARGET),wasm)
|
|
ARMSX_ENABLE_GL := 0
|
|
ARMSX_ENABLE_VULKAN := 0
|
|
endif
|
|
|
|
ifeq ($(ARMSX_ENABLE_GL),1)
|
|
BASE_CFLAGS += -DARMSX_ENABLE_GL
|
|
BASE_CXXFLAGS += -DARMSX_ENABLE_GL
|
|
endif
|
|
|
|
ifeq ($(ARMSX_ENABLE_VULKAN),1)
|
|
BASE_CFLAGS += -DARMSX_ENABLE_VULKAN
|
|
BASE_CXXFLAGS += -DARMSX_ENABLE_VULKAN
|
|
else
|
|
# librashader has no GLES runtime and its C API is typed in Vulkan handles, so without
|
|
# the Vulkan present path there is nothing to hook and no <vulkan/vulkan.h> to include.
|
|
# frontend/render_shaders.cpp then compiles to the inert stubs, which still LINK and
|
|
# still return safe values ("[]" and false) — android_jni.cpp calls them unconditionally.
|
|
ARMSX_ENABLE_SHADERS := 0
|
|
endif
|
|
|
|
ifeq ($(ARMSX_ENABLE_SHADERS),1)
|
|
BASE_CFLAGS += -DARMSX_ENABLE_SHADERS
|
|
BASE_CXXFLAGS += -DARMSX_ENABLE_SHADERS
|
|
endif
|
|
|
|
ifeq ($(HW_DEBUG),1)
|
|
BASE_CFLAGS += -DHW_DEBUG
|
|
BASE_CXXFLAGS += -DHW_DEBUG
|
|
endif
|
|
|
|
ifeq ($(UWP_TARGET),1)
|
|
BASE_CFLAGS += -DUWP_TARGET
|
|
BASE_CXXFLAGS += -DUWP_TARGET
|
|
endif
|
|
|
|
ifeq ($(PSVITA_TARGET),1)
|
|
BASE_CFLAGS += -DPSVITA_TARGET -D__DLL_BUILD -I$(VITASDK)/arm-vita-eabi/include -I$(VITASDK)/arm-vita-eabi/include/SDL2 -marm
|
|
BASE_CXXFLAGS += -DPSVITA_TARGET -D__DLL_BUILD -I$(VITASDK)/arm-vita-eabi/include -I$(VITASDK)/arm-vita-eabi/include/SDL2 -marm
|
|
endif
|
|
|
|
ifeq ($(WASM_TARGET),wasm)
|
|
BASE_CFLAGS := $(filter-out -flto,$(BASE_CFLAGS))
|
|
BASE_CXXFLAGS := $(filter-out -flto,$(BASE_CXXFLAGS))
|
|
endif
|
|
|
|
ifeq ($(PSVITA_TARGET),1)
|
|
BASE_CFLAGS := $(filter-out -flto,$(BASE_CFLAGS))
|
|
BASE_CXXFLAGS := $(filter-out -flto,$(BASE_CXXFLAGS))
|
|
endif
|
|
|
|
ifeq ($(IOS_TARGET),1)
|
|
BASE_CFLAGS += -fembed-bitcode
|
|
BASE_CXXFLAGS += -fembed-bitcode
|
|
endif
|
|
|
|
ifeq ($(WASM_TARGET),wasm)
|
|
OS_INFO := Emscripten
|
|
else ifeq ($(PSVITA_TARGET),1)
|
|
OS_INFO := PS Vita
|
|
else ifneq ($(IOS_TARGET),1)
|
|
OS_INFO := $(shell uname -rmo)
|
|
else
|
|
OS_INFO := iOS
|
|
endif
|
|
|
|
ifeq ($(PLATFORM),Darwin)
|
|
ifneq ($(IOS_TARGET),1)
|
|
BASE_CFLAGS += -mmacosx-version-min=$(MACOS_DEPLOYMENT_TARGET) -Wno-newline-eof
|
|
BASE_CXXFLAGS += -mmacosx-version-min=$(MACOS_DEPLOYMENT_TARGET)
|
|
endif
|
|
endif
|
|
|
|
SHARED_EXT := .so
|
|
SHARED_LDFLAGS := -shared
|
|
SHARED_CFLAGS := $(BASE_CFLAGS) -D__DLL_BUILD -fPIC
|
|
SHARED_CXXFLAGS := $(BASE_CXXFLAGS) -D__DLL_BUILD -fPIC
|
|
|
|
ifeq ($(PLATFORM),Darwin)
|
|
SHARED_EXT := .dylib
|
|
SHARED_LDFLAGS := -dynamiclib
|
|
else ifeq ($(WINDOWS_TARGET),1)
|
|
SHARED_EXT := .dll
|
|
endif
|
|
|
|
ifeq ($(IOS_TARGET),1)
|
|
SHARED_LDFLAGS += -Wl,-install_name,@rpath/libarmsx$(SHARED_EXT)
|
|
SHARED_CFLAGS += -DIOS_TARGET
|
|
SHARED_CXXFLAGS += -DIOS_TARGET
|
|
endif
|
|
|
|
VERSION_TAG := $(shell git describe --always --tags --abbrev=0)
|
|
COMMIT_HASH := $(shell git rev-parse --short HEAD)
|
|
|
|
BIN_DIR := bin
|
|
ifeq ($(WASM_TARGET),wasm)
|
|
BIN_DIR := bin/wasm
|
|
else ifeq ($(PSVITA_TARGET),1)
|
|
BIN_DIR := bin/psvita
|
|
endif
|
|
OBJ_DIR := $(BIN_DIR)/obj
|
|
|
|
BIN := $(BIN_DIR)/armsx
|
|
ifeq ($(WASM_TARGET),wasm)
|
|
BIN := $(BIN_DIR)/armsx.html
|
|
else ifeq ($(WINDOWS_TARGET),1)
|
|
BIN := $(BIN_DIR)/armsx.exe
|
|
endif
|
|
SHARED_BIN := $(BIN_DIR)/libarmsx$(SHARED_EXT)
|
|
VITA_NATIVE_LIB := $(BIN_DIR)/libarmsx_vita.a
|
|
RUNTIME_ICON_SRC := icons/FsuiAppIcon.png
|
|
RUNTIME_ICON_DEST := $(BIN_DIR)/icons/FsuiAppIcon.png
|
|
WINDRES ?= windres
|
|
|
|
C_SOURCES := $(wildcard psx/*.c) \
|
|
$(wildcard psx/dev/*.c) \
|
|
$(wildcard psx/dev/cdrom/*.c) \
|
|
$(wildcard psx/input/*.c) \
|
|
$(wildcard psx/disc/*.c) \
|
|
frontend/argparse.c \
|
|
frontend/config.c \
|
|
frontend/diagnostics.c \
|
|
frontend/toml.c
|
|
C_SOURCES := $(filter-out psx/dev/cdrom/chd.c,$(C_SOURCES))
|
|
C_SOURCES += frontend/gpu_hw.c
|
|
# Internal-resolution rasterizer backend ([video] renderer = "hardware"). Its whole body
|
|
# is behind #ifdef USE_HARDWARE, and it installs itself through psx/dev/gpu_backend.h, so
|
|
# the software path is untouched when the setting is off.
|
|
C_SOURCES += frontend/gpu_hw_rt.c
|
|
# GLES 3.0 rasterizer backend behind the same psx/dev/gpu_backend.h vtable. Its whole body
|
|
# is behind USE_HARDWARE + ARMSX_ENABLE_GL + __ANDROID__ and it compiles to three stubs
|
|
# everywhere else, so it is listed unconditionally like frontend/render_gl.cpp.
|
|
C_SOURCES += frontend/gpu_hw_gl.c
|
|
# frontend/gpu_profile.c identifies the mobile GPU and driver and answers "does this driver do
|
|
# X correctly". Unconditional and dependency-free (no SDL, no GL, no Vulkan headers) so the GL
|
|
# backend, the Vulkan backend and the hardware rasteriser can all consult one answer.
|
|
C_SOURCES += frontend/gpu_profile.c
|
|
# frontend/host_usage.c samples DEVICE cpu/ram/gpu for the OSD (see host_usage.h).
|
|
C_SOURCES += frontend/host_usage.c
|
|
# frontend/perf_hint.c is the ADPF CPU clock hint + emulation-thread affinity (see perf_hint.h).
|
|
# Listed unconditionally like gpu_profile.c: the whole body is behind __ANDROID__ and every entry
|
|
# point compiles to an empty function elsewhere, so no platform needs a conditional here.
|
|
C_SOURCES += frontend/perf_hint.c
|
|
# frontend/pgo.c is the profile-guided-optimisation seam (see the PGO block below, and the long
|
|
# comment at the top of the file). Listed unconditionally like gpu_profile.c: every entry point
|
|
# exists in all three PGO modes, and that is deliberate — a caller whose control flow changed
|
|
# between the instrumented build and the optimised build would lose its own profile to a CFG
|
|
# hash mismatch.
|
|
C_SOURCES += frontend/pgo.c
|
|
ifeq ($(USE_CHD),1)
|
|
C_SOURCES += psx/dev/cdrom/chd.c
|
|
endif
|
|
ifeq ($(PSVITA_TARGET),1)
|
|
C_SOURCES += frontend/vita_sdl_stubs.c
|
|
endif
|
|
|
|
# rcheevos. Listed file by file rather than wildcarded: rc_libretro.c, rc_client_external.c and
|
|
# rc_client_raintegration.c are upstream integrations ARMSX does not use, and hash_rom.c /
|
|
# hash_zip.c / hash_encrypted.c are compiled out by RCHEEVOS_COMPILE_DEFS above.
|
|
RCHEEVOS_SOURCES := \
|
|
$(RCHEEVOS_DIR)/src/rc_client.c \
|
|
$(RCHEEVOS_DIR)/src/rc_compat.c \
|
|
$(RCHEEVOS_DIR)/src/rc_util.c \
|
|
$(RCHEEVOS_DIR)/src/rc_version.c \
|
|
$(RCHEEVOS_DIR)/src/rapi/rc_api_common.c \
|
|
$(RCHEEVOS_DIR)/src/rapi/rc_api_editor.c \
|
|
$(RCHEEVOS_DIR)/src/rapi/rc_api_info.c \
|
|
$(RCHEEVOS_DIR)/src/rapi/rc_api_runtime.c \
|
|
$(RCHEEVOS_DIR)/src/rapi/rc_api_user.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/alloc.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/condition.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/condset.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/consoleinfo.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/format.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/lboard.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/memref.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/operand.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/rc_validate.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/richpresence.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/runtime.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/runtime_progress.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/trigger.c \
|
|
$(RCHEEVOS_DIR)/src/rcheevos/value.c \
|
|
$(RCHEEVOS_DIR)/src/rhash/cdreader.c \
|
|
$(RCHEEVOS_DIR)/src/rhash/hash.c \
|
|
$(RCHEEVOS_DIR)/src/rhash/hash_disc.c \
|
|
$(RCHEEVOS_DIR)/src/rhash/md5.c
|
|
C_SOURCES += $(RCHEEVOS_SOURCES)
|
|
|
|
C_SOURCES_SHARED := $(C_SOURCES)
|
|
|
|
# rcheevos back out of -ffast-math. Its float memref conversion (src/rcheevos/memref.c) produces
|
|
# and compares INFINITY/NaN, and -ffinite-math-only tells the compiler those cannot occur — which
|
|
# is exactly the assumption that would quietly mis-evaluate a float-typed achievement condition.
|
|
# Nothing here is hot enough to care.
|
|
RCHEEVOS_OBJS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(RCHEEVOS_SOURCES))
|
|
$(RCHEEVOS_OBJS): BASE_CFLAGS += -fno-fast-math
|
|
|
|
# frontend/android_jni.cpp is the in-process Android host (Compose-owned Surface + the
|
|
# kr.co.iefriends.pcsx2.NativeApp JNI surface). Its whole body is behind #if defined(__ANDROID__),
|
|
# so it compiles to an empty object everywhere else and is listed unconditionally.
|
|
# frontend/render*.cpp is the presentation backend layer (see frontend/render.h). render_gl
|
|
# and render_vk compile to empty objects unless ARMSX_ENABLE_GL / ARMSX_ENABLE_VULKAN are on,
|
|
# so they are listed unconditionally.
|
|
# frontend/achievements.cpp is the RetroAchievements (rcheevos) layer. Platform-neutral C++ —
|
|
# the Android host installs the HTTP transport into it, everything else links it inert.
|
|
# frontend/render_shaders.cpp is the librashader (.slangp) seam. Like render_gl/render_vk it
|
|
# is listed unconditionally and compiles to inert stubs without ARMSX_ENABLE_SHADERS. It adds
|
|
# no link-time dependency in EITHER configuration: librashader is dlopen()ed.
|
|
CPP_SOURCES := frontend/archive.cpp frontend/main.cpp frontend/android_jni.cpp \
|
|
frontend/achievements.cpp \
|
|
frontend/render.cpp frontend/render_sdl.cpp frontend/render_gl.cpp frontend/render_vk.cpp \
|
|
frontend/render_shaders.cpp
|
|
|
|
FSUI_LIBS := \
|
|
$(FSUI_BUILD_DIR)/libfsui-donor.a \
|
|
$(FSUI_BUILD_DIR)/libfsui-backend-sdl.a \
|
|
$(FSUI_BUILD_DIR)/libfsui-platform-sdl2.a \
|
|
$(FSUI_BUILD_DIR)/libfsui-renderer-sdl2.a \
|
|
$(FSUI_BUILD_DIR)/libfsui-renderer-sdl2surface.a \
|
|
$(FSUI_BUILD_DIR)/libfsui-core.a \
|
|
$(FSUI_BUILD_DIR)/libfsui_imgui.a \
|
|
$(FSUI_BUILD_DIR)/libfsui_resources.a
|
|
ifeq ($(WASM_TARGET),wasm)
|
|
FSUI_LIBS += \
|
|
$(FSUI_BUILD_DIR)/libfsui-renderer-opengl.a
|
|
else
|
|
FSUI_LIBS += \
|
|
$(FSUI_BUILD_DIR)/libfsui-renderer-opengl.a \
|
|
$(FSUI_BUILD_DIR)/libfsui_glad.a
|
|
endif
|
|
|
|
PLATFORM_EXTRA_LDFLAGS :=
|
|
PLATFORM_EXTRA_LIBS :=
|
|
|
|
ifeq ($(PLATFORM),Darwin)
|
|
FSUI_LIBS += $(FSUI_BUILD_DIR)/libfsui-renderer-metal.a
|
|
ifeq ($(IOS_TARGET),1)
|
|
PLATFORM_EXTRA_LIBS += -framework Foundation -framework Metal -framework OpenGLES -framework QuartzCore -framework UIKit
|
|
else
|
|
PLATFORM_EXTRA_LDFLAGS += -mmacosx-version-min=$(MACOS_DEPLOYMENT_TARGET)
|
|
PLATFORM_EXTRA_LIBS += -framework Cocoa -framework Foundation -framework IOKit -framework Metal -framework OpenGL -framework QuartzCore
|
|
endif
|
|
else ifeq ($(WINDOWS_TARGET),1)
|
|
PLATFORM_EXTRA_LIBS += -lsetupapi -limm32 -lversion -lwinmm -lgdi32 -lole32 -loleaut32 -lshell32 -luuid -lopengl32
|
|
ifneq ($(UWP_TARGET),1)
|
|
PLATFORM_EXTRA_LIBS += -ldbghelp
|
|
endif
|
|
else ifneq ($(WASM_TARGET),wasm)
|
|
PLATFORM_EXTRA_LIBS += -ldl
|
|
ifeq ($(FSUI_LINK_SYSTEM_GL),1)
|
|
PLATFORM_EXTRA_LIBS += -lGL
|
|
endif
|
|
endif
|
|
|
|
C_OBJS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(C_SOURCES))
|
|
C_OBJS_SHARED := $(patsubst %.c,$(OBJ_DIR)/%.o,$(C_SOURCES_SHARED))
|
|
CPP_OBJS := $(patsubst %.cpp,$(OBJ_DIR)/%.o,$(CPP_SOURCES))
|
|
RC_SOURCES :=
|
|
ifeq ($(WINDOWS_TARGET),1)
|
|
RC_SOURCES += resources/windows/armsx.rc
|
|
endif
|
|
RC_OBJS := $(patsubst %.rc,$(OBJ_DIR)/%.o,$(RC_SOURCES))
|
|
ALL_OBJS := $(C_OBJS) $(CPP_OBJS) $(RC_OBJS)
|
|
ALL_OBJS_SHARED := $(C_OBJS_SHARED) $(CPP_OBJS)
|
|
|
|
# ================================================================================================
|
|
# Profile-guided optimisation (PGO)
|
|
# ================================================================================================
|
|
#
|
|
# make PGO=generate shared instrumented: counters compiled in, written on the device.
|
|
# make PGO=use shared optimised against build/pgo/armsx.profdata.
|
|
# make shared (PGO=off, the default) neither.
|
|
#
|
|
# ./build.sh android forwards PGO / PGO_PROFILE / PGO_ALLOW_STALE / PGO_STRICT straight through,
|
|
# and tools/pgo.sh drives the whole loop. Runtime behaviour — where the .profraw lands, and why
|
|
# it has to be written explicitly rather than at exit — is documented in frontend/pgo.c.
|
|
#
|
|
# IR instrumentation (-fprofile-generate), not frontend instrumentation
|
|
# (-fprofile-instr-generate): fewer counters, and it is the one that composes with the -flto in
|
|
# BASE_CFLAGS. The instrumentation and the profile annotation both run PRE-LINK, on the bitcode,
|
|
# so the compile line is what carries -fprofile-use; only -fprofile-generate additionally needs
|
|
# to reach the LINK line, to pull in compiler-rt's profile runtime.
|
|
#
|
|
# ── SCOPE ───────────────────────────────────────────────────────────────────────────────────────
|
|
# psx/ + frontend/ only. Everything else is either built by its own cmake (SDL, libchdr,
|
|
# librashader, adrenotools — untouched by these flags) or is rcheevos, which is listed in
|
|
# C_SOURCES but runs a handful of times a second at most: instrumenting it would add counters and
|
|
# profile bulk to code no amount of PGO will make matter. $(OBJ_DIR)/frontend/pgo.o is excluded
|
|
# too, and that one is REQUIRED, not a judgement call — it is the only file whose control flow
|
|
# legitimately differs between the instrumented and the optimised build, so feeding it its own
|
|
# profile would guarantee the hash mismatch this whole block exists to detect.
|
|
#
|
|
# ── STALENESS ───────────────────────────────────────────────────────────────────────────────────
|
|
# A profile that predates the code does not degrade to "no PGO", it degrades to "PGO pointed at
|
|
# the wrong branches", and it is measurably slower than not using one. The sibling PS2 project
|
|
# lost a large chunk of recompiler throughput to exactly this and it took real effort to find,
|
|
# because nothing said the profile was old. Three independent checks, on purpose:
|
|
#
|
|
# 1. HERE, before a single object compiles. The merged profile carries a provenance file
|
|
# naming the commit AND a hash over psx/+frontend/ sources; if either disagrees with the
|
|
# tree being built, this is a hard error. PGO_ALLOW_STALE=1 downgrades it to a warning.
|
|
# The source hash is the stronger of the two: a commit hash cannot see uncommitted edits.
|
|
# 2. clang, per function. ★ The diagnostic is "function control flow change detected (hash
|
|
# mismatch)" under -Wbackend-plugin. NOT -Wprofile-instr-out-of-date, which only covers
|
|
# frontend instrumentation and would silently never fire for this build — assuming
|
|
# otherwise is exactly how a stale profile gets waved through a build that "had no
|
|
# warnings". PGO_STRICT=1 (the default) promotes it to an error.
|
|
# 3. Runtime, in logcat, from frontend/pgo.c's constructor — for a build already on a device.
|
|
|
|
PGO ?= off
|
|
PGO_DIR ?= build/pgo
|
|
PGO_PROFILE ?= $(PGO_DIR)/armsx.profdata
|
|
PGO_PROVENANCE ?= $(PGO_PROFILE).provenance
|
|
PGO_ALLOW_STALE ?= 0
|
|
PGO_STRICT ?= 1
|
|
|
|
PGO_CFLAGS :=
|
|
PGO_LDFLAGS :=
|
|
PGO_STAMP_DEFS :=
|
|
|
|
# Everything PGO is applied to, as a file list. $(wildcard) silently drops patterns that match
|
|
# nothing, which is what makes it safe to list a directory that may not exist — unlike a shell
|
|
# glob, which either errors or (worse, under zsh) expands to nothing and hands the hash below an
|
|
# EMPTY input, producing git's empty-blob hash. That value looks like a perfectly good stamp and
|
|
# compares equal to any other empty run, so the staleness guard would silently stop guarding.
|
|
# `make pgo-stamp` below is the only supported way to ask for this; do not reimplement it.
|
|
PGO_STAMP_INPUTS := $(sort $(wildcard \
|
|
psx/*.c psx/*.h psx/dev/*.c psx/dev/*.h psx/dev/cdrom/*.c psx/dev/cdrom/*.h \
|
|
psx/input/*.c psx/input/*.h \
|
|
frontend/*.c frontend/*.h frontend/*.cpp frontend/*.hpp))
|
|
|
|
# tools/pgo.sh asks the Makefile for the stamp rather than computing its own. Two implementations
|
|
# of the same hash drifting apart is precisely how a staleness guard turns into a rubber stamp,
|
|
# and the first draft of that script did exactly that: its shell glob missed a directory the
|
|
# Makefile pattern also missed, hashed nothing, and got a stable-looking answer that matched
|
|
# nothing forever.
|
|
.PHONY: pgo-stamp
|
|
pgo-stamp:
|
|
@cat $(PGO_STAMP_INPUTS) | git hash-object --stdin | cut -c1-16
|
|
|
|
ifneq ($(PGO),off)
|
|
|
|
# Hash over those sources. Deliberately the SOURCES and not the commit: the commit is what a human
|
|
# reads, this is what actually answers "is the profile describing this code" — it sees uncommitted
|
|
# edits, which a commit hash cannot. Via git hash-object because git is already a hard dependency
|
|
# here (VERSION_TAG) and shasum/sha256sum are spelled differently on macOS and Linux. Computed only
|
|
# when PGO is on: it is a few MB of I/O and every `make clean` would otherwise pay for it.
|
|
PGO_SOURCE_STAMP := $(shell cat $(PGO_STAMP_INPUTS) 2>/dev/null | git hash-object --stdin 2>/dev/null | cut -c1-16)
|
|
PGO_BUILD_COMMIT := $(shell git rev-parse HEAD 2>/dev/null)
|
|
|
|
# git's hash of empty input. If the file list came out empty this is what lands in the stamp, and
|
|
# it would compare equal to every other broken run — a guard that always says "fresh".
|
|
ifeq ($(PGO_SOURCE_STAMP),e69de29bb2d1d643)
|
|
$(error PGO=$(PGO): the source stamp hashed NOTHING (empty input). PGO_STAMP_INPUTS matched no \
|
|
files, so staleness could never be detected. Refusing to build)
|
|
endif
|
|
|
|
ifeq ($(strip $(PGO_SOURCE_STAMP)),)
|
|
$(error PGO=$(PGO): could not compute a source stamp (is git on PATH?). Refusing to build a \
|
|
profile that cannot be checked for staleness later)
|
|
endif
|
|
|
|
PGO_STAMP_DEFS := -DARMSX_PGO_BUILD_COMMIT='"$(PGO_BUILD_COMMIT)"' \
|
|
-DARMSX_PGO_SOURCE_STAMP='"$(PGO_SOURCE_STAMP)"'
|
|
|
|
endif
|
|
|
|
ifeq ($(PGO),generate)
|
|
|
|
PGO_CFLAGS := -fprofile-generate
|
|
PGO_LDFLAGS := -fprofile-generate
|
|
PGO_STAMP_DEFS += -DARMSX_PGO_GENERATE=1
|
|
$(info [pgo] INSTRUMENTED build — commit $(PGO_BUILD_COMMIT), source stamp $(PGO_SOURCE_STAMP))
|
|
$(info [pgo] this binary is for profiling only; it is several times slower than a release build)
|
|
|
|
else ifeq ($(PGO),use)
|
|
|
|
ifeq ($(wildcard $(PGO_PROFILE)),)
|
|
$(error PGO=use: no merged profile at $(PGO_PROFILE). Build PGO=generate, play the device \
|
|
workloads, then run: tools/pgo.sh merge)
|
|
endif
|
|
|
|
ifeq ($(wildcard $(PGO_PROVENANCE)),)
|
|
ifneq ($(PGO_ALLOW_STALE),1)
|
|
$(error PGO=use: $(PGO_PROFILE) exists but has no provenance file at $(PGO_PROVENANCE), so \
|
|
there is no way to tell what code it was recorded against. Re-merge with tools/pgo.sh merge, \
|
|
or set PGO_ALLOW_STALE=1 to build anyway)
|
|
endif
|
|
PGO_PROFILE_COMMIT := unknown
|
|
PGO_PROFILE_STAMP := unknown
|
|
else
|
|
PGO_PROFILE_COMMIT := $(shell sed -n 's/^commit=//p' $(PGO_PROVENANCE) 2>/dev/null | head -1)
|
|
PGO_PROFILE_STAMP := $(shell sed -n 's/^stamp=//p' $(PGO_PROVENANCE) 2>/dev/null | head -1)
|
|
endif
|
|
|
|
ifeq ($(strip $(PGO_PROFILE_STAMP)),$(strip $(PGO_SOURCE_STAMP)))
|
|
PGO_PROFILE_FRESH := 1
|
|
else
|
|
PGO_PROFILE_FRESH := 0
|
|
endif
|
|
|
|
ifeq ($(PGO_PROFILE_FRESH),0)
|
|
ifeq ($(PGO_ALLOW_STALE),1)
|
|
$(warning [pgo] ★ STALE PROFILE, building anyway because PGO_ALLOW_STALE=1.)
|
|
$(warning [pgo] profile recorded from commit $(PGO_PROFILE_COMMIT) stamp $(PGO_PROFILE_STAMP))
|
|
$(warning [pgo] tree being built is commit $(PGO_BUILD_COMMIT) stamp $(PGO_SOURCE_STAMP))
|
|
$(warning [pgo] a mismatched profile makes code SLOWER than no profile at all.)
|
|
else
|
|
$(error PGO=use: STALE PROFILE. $(PGO_PROFILE) was recorded from commit $(PGO_PROFILE_COMMIT) \
|
|
(source stamp $(PGO_PROFILE_STAMP)); this tree is commit $(PGO_BUILD_COMMIT) (source stamp \
|
|
$(PGO_SOURCE_STAMP)). Using it would mis-optimise rather than simply do nothing. Re-run the \
|
|
loop (tools/pgo.sh generate ...) or, if you have measured that it still helps, rebuild with \
|
|
PGO_ALLOW_STALE=1)
|
|
endif
|
|
endif
|
|
|
|
# -Wbackend-plugin is on by default; named explicitly so that turning it OFF has to be a
|
|
# deliberate act rather than a side effect of someone widening a -Wno- list.
|
|
PGO_CFLAGS := -fprofile-use=$(abspath $(PGO_PROFILE)) -Wbackend-plugin
|
|
ifeq ($(PGO_STRICT),1)
|
|
PGO_CFLAGS += -Werror=backend-plugin
|
|
endif
|
|
PGO_STAMP_DEFS += -DARMSX_PGO_USE=1 \
|
|
-DARMSX_PGO_PROFILE_COMMIT='"$(PGO_PROFILE_COMMIT)"' \
|
|
-DARMSX_PGO_PROFILE_STAMP='"$(PGO_PROFILE_STAMP)"' \
|
|
-DARMSX_PGO_PROFILE_FRESH=$(PGO_PROFILE_FRESH)
|
|
$(info [pgo] OPTIMISED build using $(PGO_PROFILE) (commit $(PGO_PROFILE_COMMIT), stamp $(PGO_PROFILE_STAMP)))
|
|
ifeq ($(PGO_STRICT),1)
|
|
$(info [pgo] PGO_STRICT=1: a per-function profile hash mismatch is an ERROR, not a warning)
|
|
endif
|
|
|
|
else ifneq ($(PGO),off)
|
|
$(error PGO must be one of: off, generate, use (got '$(PGO)'))
|
|
endif
|
|
|
|
# The emulator's own translation units, minus the two exclusions argued for above. $(sort) also
|
|
# de-duplicates, since ALL_OBJS and ALL_OBJS_SHARED overlap almost entirely.
|
|
PGO_OBJS := $(sort $(filter-out $(RCHEEVOS_OBJS) $(RC_OBJS) $(OBJ_DIR)/frontend/pgo.o, \
|
|
$(ALL_OBJS) $(ALL_OBJS_SHARED)))
|
|
|
|
$(PGO_OBJS): BASE_CFLAGS += $(PGO_CFLAGS)
|
|
$(PGO_OBJS): BASE_CXXFLAGS += $(PGO_CFLAGS)
|
|
|
|
# pgo.o gets the provenance -D's and NOT the instrumentation flags. It is the file that reports
|
|
# what this build is; it must not be described by the profile it helps collect.
|
|
$(OBJ_DIR)/frontend/pgo.o: BASE_CFLAGS += $(PGO_STAMP_DEFS)
|
|
|
|
# Force dynamic SDL when building the shared library
|
|
ifneq (,$(filter shared,$(MAKECMDGOALS)))
|
|
override SDL_STATIC := 0
|
|
BASE_CFLAGS += -D__DLL_BUILD -fPIC
|
|
BASE_CXXFLAGS += -D__DLL_BUILD -fPIC
|
|
endif
|
|
|
|
ifeq ($(SDL_STATIC),1)
|
|
ifeq ($(SDL_LIBS_STATIC),)
|
|
$(warning Static SDL2 libraries not found; falling back to dynamic SDL2)
|
|
SDL_STATIC := 0
|
|
endif
|
|
endif
|
|
|
|
SDL_LIBS := $(if $(filter 1,$(SDL_STATIC)),$(SDL_LIBS_STATIC),$(SDL_LIBS_DYNAMIC))
|
|
SDL_LIBS_SHARED := $(SDL_LIBS_DYNAMIC)
|
|
|
|
.PHONY: all clean shared wasm psvita-lib test test-cpu test-cpu-spec test-gte test-cheats test-gpu test-texrep test-gpu-profile test-raster-select test-present-dst test-audio-queue test-mdec-bounds test-spu-width test-mcard-diverge test-cdrom-getlocp test-chd test-zip test-sdl-runtime test-sdl-lifecycle test-disc-serial disc-probe
|
|
|
|
all: $(BIN)
|
|
|
|
shared: $(SHARED_BIN)
|
|
|
|
wasm: $(BIN)
|
|
|
|
psvita-lib: $(VITA_NATIVE_LIB)
|
|
|
|
TEST_CORE_SOURCES := $(wildcard psx/*.c) \
|
|
$(wildcard psx/dev/*.c) \
|
|
$(wildcard psx/dev/cdrom/*.c) \
|
|
$(wildcard psx/input/*.c)
|
|
TEST_CORE_SOURCES := $(filter-out psx/dev/cdrom/chd.c,$(TEST_CORE_SOURCES))
|
|
|
|
# chd.c is filtered out above because disc.c reaches it only under #ifdef USE_CHD, so a gate that
|
|
# does not want libchdr simply does not compile it. psx/dev/cdrom/pbp.c has NO such guard —
|
|
# disc.c's CD_EXT_PBP case is unconditional — so every gate that links the core also compiles
|
|
# pbp.c, which #include's miniz.h and calls into it. Without these three the whole suite fails to
|
|
# build with "'miniz.h' file not found", which is what it did from the moment PBP support landed.
|
|
# All three come from the libchdr build (miniz is one of its deps) and are empty when USE_CHD=0.
|
|
TEST_CORE_CFLAGS := $(LIBCHDR_INCLUDE_FLAGS)
|
|
TEST_CORE_LIBS := $(CHD_LINK_LIBS)
|
|
TEST_CORE_DEPS := $(CHD_BUILD_DEPS)
|
|
TEST_CPU_BIN := build/tests/cpu_differential
|
|
TEST_CHEATS_BIN := build/tests/cheat_engine
|
|
TEST_GPU_BIN := build/tests/gpu_renderer_parity
|
|
TEST_CHD_BIN := build/tests/chd_logic
|
|
TEST_ZIP_BIN := build/tests/zip_integration
|
|
TEST_SDL_BIN := build/tests/sdl_renderer_smoke
|
|
TEST_SDL_LIFECYCLE_BIN := build/tests/sdl_subsystem_lease
|
|
TEST_DISC_SERIAL_BIN := build/tests/disc_serial
|
|
TEST_MDEC_BOUNDS_BIN := build/tests/mdec_bounds
|
|
DISC_PROBE_BIN := build/tests/disc_probe
|
|
|
|
$(TEST_CPU_BIN): tests/cpu_differential.c $(TEST_CORE_SOURCES) | $(TEST_CORE_DEPS)
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx $(TEST_CORE_CFLAGS) $^ $(TEST_CORE_LIBS) -lm -o $@
|
|
|
|
test-cpu: $(TEST_CPU_BIN)
|
|
./$(TEST_CPU_BIN)
|
|
|
|
# GTE against psx-spx, independently recomputed (tests/gte_matrix.c).
|
|
#
|
|
# Separate from cpu_differential on purpose, for the same reason gpu_texrep_parity is
|
|
# separate from test-gpu: every case above is DIFFERENTIAL (interpreter vs cached
|
|
# interpreter -- both this project's code, written from one understanding), which is
|
|
# structurally blind to a shared wrong rule. The GTE had NO gate of either kind. This one
|
|
# recomputes the UNR divide (table rebuilt from the documented formula, swept over the
|
|
# full 2^32 numerator x divisor space), RTPS/RTPT (per-step 44-bit sign-expansion, IR/SXY
|
|
# saturation and FLAG bits, both FIFOs, the sf=0 IR3 quirk, the DQA/DQB depth queue),
|
|
# NCLIP, AVSZ3/AVSZ4, MVMVA (including the documented CV=FC bug path) and the COP2
|
|
# register-file access semantics from the psx-spx pseudocode INSIDE the test, then drives
|
|
# the real emulator and compares full COP2 state. The three dispatch paths (interpreter
|
|
# switch, decode-cache handler, fetched psx_cpu_cycle in both modes) are cross-checked so
|
|
# a slip in any one of the duplicated GTE latch decoders is visible.
|
|
#
|
|
# psx/cpu.c is #include'd BY the test (unity-style) so the gate can reach the static
|
|
# internals (gte_divide, gte_write_register, psx_cpu_decode) directly -- the exhaustive
|
|
# divide sweep alone is ~4.3e9 calls, only affordable in-TU. It is therefore filtered OUT
|
|
# of the linked core sources; listing it as a prerequisite keeps the mutation-test loop
|
|
# honest (edit cpu.c -> relink -> gate must go red).
|
|
TEST_GTE_BIN := build/tests/gte_matrix
|
|
TEST_GTE_CORE_SOURCES := $(filter-out psx/cpu.c,$(TEST_CORE_SOURCES))
|
|
|
|
$(TEST_GTE_BIN): tests/gte_matrix.c psx/cpu.c psx/cpu.h $(TEST_GTE_CORE_SOURCES) | $(TEST_CORE_DEPS)
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx $(TEST_CORE_CFLAGS) tests/gte_matrix.c $(TEST_GTE_CORE_SOURCES) $(TEST_CORE_LIBS) -lm -lpthread -o $@
|
|
|
|
test-gte: $(TEST_GTE_BIN)
|
|
./$(TEST_GTE_BIN)
|
|
|
|
# R3000A against psx-spx / the R3000A manual, independently recomputed (tests/cpu_spec.c).
|
|
#
|
|
# Separate from cpu_differential for the same reason test-gte is: every case there is
|
|
# DIFFERENTIAL (interpreter vs cached interpreter -- both this project's code, one
|
|
# understanding), which is structurally blind to a rule that is wrong in both halves. This
|
|
# one re-implements the rules INSIDE the test -- load sign/zero extension, address-error
|
|
# behaviour, the LWL/LWR/SWL/SWR switch forms and the unaligned idioms they exist for, the
|
|
# load delay slot for every consumer class, the shift matrix, the ALU/overflow matrix,
|
|
# MULT/DIV including the degenerate results, branch/jump targets and link values, the
|
|
# exception model (EPC, CAUSE.BD, the SR mode stack, both vectors, RFE) and the COP0 write
|
|
# masks -- and runs every vector through BOTH execution modes.
|
|
#
|
|
# Links the whole core, like test-cpu, because the loads and stores go through the real bus.
|
|
TEST_CPU_SPEC_BIN := build/tests/cpu_spec
|
|
|
|
$(TEST_CPU_SPEC_BIN): tests/cpu_spec.c $(TEST_CORE_SOURCES) | $(TEST_CORE_DEPS)
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx $(TEST_CORE_CFLAGS) $^ $(TEST_CORE_LIBS) -lm -o $@
|
|
|
|
test-cpu-spec: $(TEST_CPU_SPEC_BIN)
|
|
./$(TEST_CPU_SPEC_BIN)
|
|
|
|
# Cheat engine (psx/cheats.c): the .cht parser, name-based arming, every implemented
|
|
# GameShark code type, and the RetroAchievements hardcore interlock. Links the whole core
|
|
# because it applies codes to a REAL psx_t, through the same RAM writer the emulator uses.
|
|
$(TEST_CHEATS_BIN): tests/cheat_engine.c $(TEST_CORE_SOURCES) | $(TEST_CORE_DEPS)
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx $(TEST_CORE_CFLAGS) $^ $(TEST_CORE_LIBS) -lm -o $@
|
|
|
|
test-cheats: $(TEST_CHEATS_BIN)
|
|
./$(TEST_CHEATS_BIN)
|
|
|
|
# psx/pgxp.c rides along because gpu.c's GP0 intake and poly parse call into it
|
|
# (inert while disabled, which the parity gate relies on).
|
|
TEST_GPU_SOURCES := tests/gpu_renderer_parity.c psx/dev/gpu.c psx/perf.c psx/pgxp.c \
|
|
psx/texrep.c psx/texrep_png.c \
|
|
frontend/gpu_hw.c frontend/gpu_hw_rt.c
|
|
|
|
# psx/dev/gpu.h is a PREREQUISITE, not a source: the accuracy helpers and the mask contract
|
|
# (PSX_GPU_MASK_WRITE / PSX_GPU_MASK_SKIP) live there and the test asserts them directly, so a
|
|
# header-only change has to relink or the gate keeps passing against a stale binary — which it
|
|
# did, silently, when the contract test was first written.
|
|
# -DARMSX_TEST_OFFSET_CENSUS is deliberately set HERE AND NOWHERE ELSE. It compiles in the
|
|
# drawing-offset census that `offset-stream-integrity` asserts on (psx/dev/gpu.h). That census
|
|
# runs once per primitive inside gpu_render_triangle() / _rect() / _flat_line(), so leaving it
|
|
# in a shipped binary would put ~1800 calls a frame in the hottest function in the emulator and
|
|
# hand a PGO run a profile shaped by test-only code. Adding this flag to any other rule, or to
|
|
# the library build, silently undoes that.
|
|
$(TEST_GPU_BIN): $(TEST_GPU_SOURCES) psx/dev/gpu.h
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -DUSE_HARDWARE -DPSXE_DIAG_STDIO_DISABLE -DARMSX_TEST_OFFSET_CENSUS -I. -Ipsx -Ifrontend $(SDL_CFLAGS) $(TEST_GPU_SOURCES) -lm -o $@
|
|
|
|
test-gpu: $(TEST_GPU_BIN)
|
|
./$(TEST_GPU_BIN)
|
|
|
|
# Texture dumping / replacement (psx/texrep.c), checked BEHAVIOURALLY.
|
|
#
|
|
# Separate from test-gpu on purpose. GPU_PARITY compares the two CPU rasterizers against each
|
|
# other, which is structurally blind to a mistake both make -- 0.5.12, 0.5.13 and 0.5.15 were
|
|
# each one formula written identically wrong in all three, and that gate passed through every
|
|
# one of them. Every case here pins output against the FEATURE'S contract instead: a dumped
|
|
# texture fed back as a replacement has to reproduce the original frame bit for bit.
|
|
#
|
|
# psx/dev/gpu.h and psx/texrep.h are PREREQUISITES, not sources: gpu_fetch_texel_f(),
|
|
# psx_gpu_filter_active() and the PSX_TEXREP_GLSL text the matrix case transcribes all live in
|
|
# headers, so a header-only change has to relink or the gate keeps passing against a stale
|
|
# binary -- the same trap $(TEST_GPU_BIN) documents above.
|
|
TEST_TEXREP_BIN := build/tests/gpu_texrep_parity
|
|
TEST_TEXREP_SOURCES := tests/gpu_texrep_parity.c psx/dev/gpu.c psx/perf.c psx/pgxp.c \
|
|
psx/texrep.c psx/texrep_png.c \
|
|
frontend/gpu_hw.c frontend/gpu_hw_rt.c
|
|
|
|
$(TEST_TEXREP_BIN): $(TEST_TEXREP_SOURCES) psx/dev/gpu.h psx/texrep.h
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -DUSE_HARDWARE -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx -Ifrontend $(SDL_CFLAGS) $(TEST_TEXREP_SOURCES) -lm -o $@
|
|
|
|
test-texrep: $(TEST_TEXREP_BIN)
|
|
./$(TEST_TEXREP_BIN)
|
|
|
|
# Host-side test for frontend/gpu_profile.c. Runs on the build machine precisely BECAUSE the
|
|
# interesting cases are hardware nobody here owns: Mali, MediaTek, ANGLE, Turnip, Xclipse. The
|
|
# rules those devices need are otherwise unverifiable until a user reports a regression.
|
|
TEST_GPU_PROFILE_BIN = bin/tests/gpu_profile_rules
|
|
|
|
$(TEST_GPU_PROFILE_BIN): tests/gpu_profile_rules.c frontend/gpu_profile.c frontend/gpu_profile.h
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -Wall -I. tests/gpu_profile_rules.c frontend/gpu_profile.c -o $@
|
|
|
|
test-gpu-profile: $(TEST_GPU_PROFILE_BIN)
|
|
./$(TEST_GPU_PROFILE_BIN)
|
|
|
|
# Which rasterizer a configuration SELECTS, as opposed to what it draws. Every case in
|
|
# test-gpu compares rasterizer output, so none of them can see the GLES backend starting to
|
|
# attach on a device where it used to decline — which is exactly what took the PS1 BIOS's
|
|
# text away while all four gates stayed green. Compiles gpu_hw_gl.c on the host, where it
|
|
# takes its non-Android stub branch and pulls in no GL at all; the rule under test is a pure
|
|
# predicate placed outside that guard for this purpose.
|
|
TEST_RASTER_SELECT_BIN := build/tests/gpu_rasterizer_select
|
|
|
|
$(TEST_RASTER_SELECT_BIN): tests/gpu_rasterizer_select.c frontend/gpu_hw_gl.c frontend/gpu_hw_gl.h
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -Wall -DUSE_HARDWARE -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx -Ifrontend \
|
|
tests/gpu_rasterizer_select.c frontend/gpu_hw_gl.c -lm -o $@
|
|
|
|
test-raster-select: $(TEST_RASTER_SELECT_BIN)
|
|
./$(TEST_RASTER_SELECT_BIN)
|
|
|
|
# The blit bridge renders into a capped host framebuffer and copies it into the ANativeWindow
|
|
# with an UNSCALED row copy, so the buffer geometry it requests and the destination rect it
|
|
# fills must be the same number — SurfaceFlinger supplies the upscale. A GL backend binding the
|
|
# window resets that geometry to the window's natural size, and when the fallback ladder later
|
|
# lands on the bridge the mismatch draws the picture at a 2/3 top-left inset. compute_dst was
|
|
# never wrong, so a gate over compute_dst alone passed straight through the bug; this one pins
|
|
# all three of framebuffer size, destination rect, and the equality BETWEEN them.
|
|
# Pure rule: render.cpp only, with the backend factories stubbed in the test, so it needs no
|
|
# window, GL context or device.
|
|
TEST_PRESENT_DST_BIN := build/tests/present_dst_rect
|
|
|
|
$(TEST_PRESENT_DST_BIN): tests/present_dst_rect.c frontend/render.cpp frontend/render.h \
|
|
frontend/render_internal.h
|
|
mkdir -p $(dir $@)
|
|
$(CXX) -std=c++17 -O2 -g -Wall -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx -Ifrontend $(SDL_CFLAGS) \
|
|
-x c++ tests/present_dst_rect.c frontend/render.cpp -lm -o $@
|
|
|
|
test-present-dst: $(TEST_PRESENT_DST_BIN)
|
|
./$(TEST_PRESENT_DST_BIN)
|
|
|
|
# A callback that consumes a short tail and then writes silence tears an audio frame and can stay
|
|
# phase-locked at the device floor. Pin the callback side of the pause/re-prime hand-off here.
|
|
TEST_AUDIO_QUEUE_BIN := build/tests/audio_queue_policy
|
|
|
|
$(TEST_AUDIO_QUEUE_BIN): tests/audio_queue_policy.cpp frontend/audio_queue_policy.h
|
|
mkdir -p $(dir $@)
|
|
$(CXX) -std=c++17 -O2 -g -Wall -I. $< -o $@
|
|
|
|
test-audio-queue: $(TEST_AUDIO_QUEUE_BIN)
|
|
./$(TEST_AUDIO_QUEUE_BIN)
|
|
|
|
# MDEC streams are game-controlled RLE. Exercise the public command path with exact, truncated,
|
|
# padding-only and coefficient-overflow inputs so the decoder cannot regress to indexing before
|
|
# validating a run.
|
|
$(TEST_MDEC_BOUNDS_BIN): tests/mdec_bounds.c $(TEST_CORE_SOURCES) | $(TEST_CORE_DEPS)
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx $(TEST_CORE_CFLAGS) \
|
|
$^ $(TEST_CORE_LIBS) -lm -o $@
|
|
|
|
test-mdec-bounds: $(TEST_MDEC_BOUNDS_BIN)
|
|
./$(TEST_MDEC_BOUNDS_BIN)
|
|
|
|
# SPU register access WIDTH (psx/dev/spu.c): 8/16/32-bit against a 16-bit-wide register file.
|
|
#
|
|
# The file implemented 16- and 32-bit access only. An 8-bit read logged at FATAL and returned
|
|
# 0, an 8-bit write was dropped, and Xenogears reads voice ADSR registers a byte at a time —
|
|
# so it polled envelope state, got zero, and produced 1.1 MB of log doing it. No existing gate
|
|
# could see that: nothing crashes, and the 16-bit path everything else exercises stays correct.
|
|
#
|
|
# Links the whole core for the same reason test-cpu does — the byte-write path deliberately
|
|
# goes back through psx_spu_write16(), so key-on, key-off and the sound-RAM transfer address
|
|
# have to be reachable, not stubbed.
|
|
#
|
|
# psx/dev/spu.h is a PREREQUISITE, not a source: the register mirror's bound is derived from
|
|
# the psx_spu_t layout, so a header-only change has to relink or the gate keeps passing against
|
|
# a stale binary — the trap $(TEST_GPU_BIN) documents above.
|
|
TEST_SPU_WIDTH_BIN := build/tests/spu_register_widths
|
|
|
|
$(TEST_SPU_WIDTH_BIN): tests/spu_register_widths.c $(TEST_CORE_SOURCES) psx/dev/spu.h | $(TEST_CORE_DEPS)
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx $(TEST_CORE_CFLAGS) \
|
|
tests/spu_register_widths.c $(TEST_CORE_SOURCES) $(TEST_CORE_LIBS) -lm -o $@
|
|
|
|
test-spu-width: $(TEST_SPU_WIDTH_BIN)
|
|
./$(TEST_SPU_WIDTH_BIN)
|
|
|
|
# Save-state <-> memory-card divergence (PSX_SS_MCARD in psx/state.c).
|
|
#
|
|
# Links the whole core because the interesting behaviour is the interaction between three
|
|
# real things: the card's serial write protocol, the state container's optional-section
|
|
# rule, and the identity phase that refuses a load before touching the machine. A gate over
|
|
# the verdict function alone would pass while the section was never written, never read, or
|
|
# marked mandatory — the last of which would brick every save state already on a device.
|
|
#
|
|
# psx/state.h and psx/dev/mcd.h are PREREQUISITES, not sources: the section id, the error
|
|
# codes and the load flag live in headers, so a header-only change has to relink or the gate
|
|
# keeps passing against a stale binary — the trap $(TEST_GPU_BIN) documents above.
|
|
TEST_MCARD_BIN := build/tests/state_mcard_divergence
|
|
|
|
$(TEST_MCARD_BIN): tests/state_mcard_divergence.c $(TEST_CORE_SOURCES) psx/state.h psx/dev/mcd.h | $(TEST_CORE_DEPS)
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx $(TEST_CORE_CFLAGS) \
|
|
tests/state_mcard_divergence.c $(TEST_CORE_SOURCES) $(TEST_CORE_LIBS) -lm -o $@
|
|
|
|
test-mcard-diverge: $(TEST_MCARD_BIN)
|
|
./$(TEST_MCARD_BIN)
|
|
|
|
# What the drive REPORTS about itself: CdlGetlocP (psx/dev/cdrom/impl.c) and the response
|
|
# FIFO it comes back through (psx/dev/cdrom/cdrom.c).
|
|
#
|
|
# CdlGetlocP is the one command a game can sit in a loop on, so a wrong answer does not look
|
|
# like a CD bug: the emulator runs at full speed, the last frame keeps being drawn, and the
|
|
# only symptom is that input appears dead, because the game's main loop never gets past its
|
|
# poll. Nothing else in the suite can see that — the drive answers, it answers promptly, and
|
|
# every byte it answers with is well-formed. What was wrong was that the answer never
|
|
# changed, so the two properties this gate exists for are that the position MOVES and that it
|
|
# moves to somewhere useful.
|
|
#
|
|
# Links the whole core, like test-cpu, because the interesting behaviour is the interaction
|
|
# between the command state machine, the response FIFO and psx_cdrom_update()'s clock — the
|
|
# position advances on emulated time, so a gate over the response builder alone would pass
|
|
# against a drive that never moves. The disc is a 2352-byte-sector image the test writes and
|
|
# deletes itself; no real game image is involved.
|
|
#
|
|
# psx/dev/cdrom/cdrom.h is a PREREQUISITE, not a source: the hold window, the seek undershoot
|
|
# and the reported-position fields live in the header, so a header-only change has to relink
|
|
# or the gate keeps passing against a stale binary — the trap $(TEST_GPU_BIN) documents above.
|
|
TEST_GETLOCP_BIN := build/tests/cdrom_getlocp
|
|
|
|
$(TEST_GETLOCP_BIN): tests/cdrom_getlocp.c $(TEST_CORE_SOURCES) psx/dev/cdrom/cdrom.h | $(TEST_CORE_DEPS)
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx $(TEST_CORE_CFLAGS) \
|
|
tests/cdrom_getlocp.c $(TEST_CORE_SOURCES) $(TEST_CORE_LIBS) -lm -o $@
|
|
|
|
test-cdrom-getlocp: $(TEST_GETLOCP_BIN)
|
|
./$(TEST_GETLOCP_BIN) $(dir $(TEST_GETLOCP_BIN))
|
|
|
|
$(TEST_CHD_BIN): tests/chd_logic.c $(CHD_BUILD_DEPS)
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -DUSE_CHD -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx $(LIBCHDR_INCLUDE_FLAGS) $< $(CHD_LINK_LIBS) -lm -o $@
|
|
|
|
test-chd: $(TEST_CHD_BIN)
|
|
./$(TEST_CHD_BIN)
|
|
|
|
$(TEST_ZIP_BIN): tests/zip_integration.cpp frontend/archive.cpp $(CHD_BUILD_DEPS)
|
|
mkdir -p $(dir $@)
|
|
$(CXX) -std=c++20 -O0 -DUSE_CHD -I. $(LIBCHDR_INCLUDE_FLAGS) \
|
|
tests/zip_integration.cpp frontend/archive.cpp $(CHD_LINK_LIBS) -o $@
|
|
|
|
test-zip: $(TEST_ZIP_BIN)
|
|
python3 tests/validate_zip.py ./$(TEST_ZIP_BIN)
|
|
|
|
$(TEST_SDL_BIN): tests/sdl_renderer_smoke.c
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g $(SDL_CFLAGS) $< $(SDL_LIBS) -o $@
|
|
|
|
test-sdl-runtime: $(TEST_SDL_BIN)
|
|
./$(TEST_SDL_BIN)
|
|
|
|
$(TEST_SDL_LIFECYCLE_BIN): tests/sdl_subsystem_lease.cpp frontend/sdl_subsystem_lease.h
|
|
mkdir -p $(dir $@)
|
|
$(CXX) -std=c++17 -O2 -g $(SDL_CFLAGS) $< $(SDL_LIBS) -o $@
|
|
|
|
test-sdl-lifecycle: $(TEST_SDL_LIFECYCLE_BIN)
|
|
./$(TEST_SDL_LIFECYCLE_BIN)
|
|
|
|
# Disc serial identification (psx/discid.c), which is what gives a .chd its cover art, its
|
|
# per-game settings key and its achievements identity. Built with USE_CHD and the real disc
|
|
# readers so `--image <path>` can identify an actual .chd end to end; the gate itself needs no
|
|
# game image and no libchdr decode — see the header of tests/disc_serial.c.
|
|
#
|
|
# psx/discid.h is a PREREQUISITE, not a source: the buffer size and the API contract live there,
|
|
# so a header-only change has to relink or the gate keeps passing against a stale binary.
|
|
$(TEST_DISC_SERIAL_BIN): tests/disc_serial.c psx/discid.c psx/discid.h psx/perf.c \
|
|
psx/dev/cdrom/disc.c psx/dev/cdrom/cue.c psx/dev/cdrom/list.c psx/dev/cdrom/chd.c \
|
|
psx/dev/cdrom/pbp.c $(CHD_BUILD_DEPS)
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -DUSE_CHD -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx $(LIBCHDR_INCLUDE_FLAGS) \
|
|
tests/disc_serial.c psx/discid.c psx/perf.c psx/dev/cdrom/disc.c psx/dev/cdrom/cue.c \
|
|
psx/dev/cdrom/list.c psx/dev/cdrom/chd.c psx/dev/cdrom/pbp.c \
|
|
$(CHD_LINK_LIBS) -lm -o $@
|
|
|
|
test-disc-serial: $(TEST_DISC_SERIAL_BIN)
|
|
./$(TEST_DISC_SERIAL_BIN) $(dir $(TEST_DISC_SERIAL_BIN))
|
|
|
|
$(DISC_PROBE_BIN): tests/disc_probe.c psx/dev/cdrom/disc.c psx/dev/cdrom/cue.c psx/dev/cdrom/list.c psx/dev/cdrom/chd.c psx/dev/cdrom/pbp.c $(CHD_BUILD_DEPS)
|
|
mkdir -p $(dir $@)
|
|
$(CC) -std=c11 -O2 -g -DUSE_CHD -DPSXE_DIAG_STDIO_DISABLE -I. -Ipsx $(LIBCHDR_INCLUDE_FLAGS) \
|
|
tests/disc_probe.c psx/dev/cdrom/disc.c psx/dev/cdrom/cue.c psx/dev/cdrom/list.c psx/dev/cdrom/chd.c psx/dev/cdrom/pbp.c \
|
|
$(CHD_LINK_LIBS) -lm -o $@
|
|
|
|
disc-probe: $(DISC_PROBE_BIN)
|
|
|
|
test:
|
|
python3 tests/run_validation.py
|
|
|
|
$(BIN_DIR):
|
|
mkdir -p $(BIN_DIR)
|
|
|
|
$(OBJ_DIR):
|
|
mkdir -p $(OBJ_DIR)
|
|
|
|
$(OBJ_DIR)/%.o: %.c | $(OBJ_DIR)
|
|
mkdir -p $(dir $@)
|
|
$(CC) -c $< -o $@ $(BASE_CFLAGS) \
|
|
-DOS_INFO="$(OS_INFO)" \
|
|
-DREP_VERSION="$(VERSION_TAG)" \
|
|
-DREP_COMMIT_HASH="$(COMMIT_HASH)"
|
|
|
|
$(OBJ_DIR)/%.o: %.cpp | $(OBJ_DIR)
|
|
mkdir -p $(dir $@)
|
|
$(CXX) -c $< -o $@ $(BASE_CXXFLAGS) \
|
|
-DOS_INFO="$(OS_INFO)" \
|
|
-DREP_VERSION="$(VERSION_TAG)" \
|
|
-DREP_COMMIT_HASH="$(COMMIT_HASH)"
|
|
|
|
$(OBJ_DIR)/%.o: %.rc | $(OBJ_DIR)
|
|
mkdir -p $(dir $@)
|
|
$(WINDRES) -I. $< $@
|
|
|
|
ifeq ($(USE_CHD),1)
|
|
$(LIBCHDR_ARCHIVE): $(LIBCHDR_INPUTS)
|
|
mkdir -p $(LIBCHDR_BUILD_DIR)
|
|
$(LIBCHDR_CONFIGURE) $(LIBCHDR_CMAKE_ARGS)
|
|
cmake --build $(LIBCHDR_BUILD_DIR) --target chdr-static -j$(BUILD_JOBS)
|
|
endif
|
|
|
|
$(RUNTIME_ICON_DEST): $(RUNTIME_ICON_SRC) | $(BIN_DIR)
|
|
mkdir -p $(dir $@)
|
|
cp $< $@
|
|
|
|
$(BIN): $(ALL_OBJS) $(RUNTIME_ICON_DEST) $(CHD_BUILD_DEPS) | $(BIN_DIR)
|
|
$(CXX) $(ALL_OBJS) $(CHD_LINK_LIBS) $(FSUI_LIBS) -o $(BIN) $(SDL_LIBS) $(PLATFORM_EXTRA_LDFLAGS) $(PLATFORM_EXTRA_LIBS) $(PGO_LDFLAGS) $(WASM_LDFLAGS)
|
|
ifeq ($(WASM_TARGET),wasm)
|
|
@if [ ! -f "$(BIN)" ]; then \
|
|
echo "WASM build did not produce $(BIN)"; \
|
|
exit 1; \
|
|
fi
|
|
cmake -DINPUT_FILE="$(BIN)" -P "$(WASM_HTML_POSTPROCESS)"
|
|
endif
|
|
|
|
$(VITA_NATIVE_LIB): $(ALL_OBJS) $(RUNTIME_ICON_DEST) | $(BIN_DIR)
|
|
$(AR) rcs $@ $(ALL_OBJS)
|
|
$(RANLIB) $@
|
|
|
|
# $(PGO_LDFLAGS) is -fprofile-generate on an instrumented build and empty otherwise. It is what
|
|
# links compiler-rt's profile runtime in; without it the link fails on an undefined
|
|
# __llvm_profile_runtime rather than producing a .so that quietly writes nothing.
|
|
$(SHARED_BIN): $(ALL_OBJS_SHARED) $(CHD_BUILD_DEPS) | $(BIN_DIR)
|
|
$(CXX) $(SHARED_LDFLAGS) $(ALL_OBJS_SHARED) $(CHD_LINK_LIBS) $(FSUI_LIBS) -o $(SHARED_BIN) $(SDL_LIBS_SHARED) $(PLATFORM_EXTRA_LDFLAGS) $(PLATFORM_EXTRA_LIBS) $(PGO_LDFLAGS)
|
|
|
|
clean:
|
|
rm -rf "$(BIN_DIR)"
|