sm64ex-alo/Makefile
AloXado320 215aab6f48 Some build fixes from sm64ex and SDL2 rumble fix
Make: Set CPP_ASSEMBLY on web target and additional mips cross target

Potentially fix switch build on macOS

Fix buffer overflow on skyconv using gcc 13 and glibc 2.39

Additional rumble code for later SDL2 versions
2024-12-19 00:48:52 -05:00

1874 lines
61 KiB
Makefile
Executable file

# Makefile to rebuild SM64 split image
include util.mk
# Default target
default: all
# Preprocessor definitions
DEFINES :=
#==============================================================================#
# Build Options #
#==============================================================================#
# These options can either be set by building with 'make SETTING=value'.
# 'make clean' may be required first.
# Makefile Refactor from Refresh 13 is somewhat adapted but
# has to be carefully to make sure sm64ex and other ports still work.
# There's also some HackerSM64 N64 specific Makefile changes.
# Manual target defines
# Build for original N64
TARGET_N64 ?= 0
# Build and optimize for Raspberry Pi(s)
TARGET_RPI ?= 0
# Build for Emscripten/WebGL
TARGET_WEB ?= 0
# Build for the Wii U
TARGET_WII_U ?= 0
# Build for the 3DS
TARGET_N3DS ?= 0
# Build for Nintendo Switch
TARGET_SWITCH ?= 0
# Compiler to use for N64 (and other targets if required)
# gcc - uses the GNU C Compiler
# clang - uses clang C/C++ frontend for LLVM
COMPILER_TYPE ?= gcc
$(eval $(call validate-option,COMPILER_TYPE,gcc clang))
COMPILER_OPT ?= default
$(eval $(call validate-option,COMPILER_OPT,debug debugmax default fast))
# Automatic target defines
# Build for Windows
WINDOWS_BUILD ?= 0
# Build for Android
TARGET_ANDROID ?= 0
# Makeflag to enable OSX fixes
OSX_BUILD ?= 0
# Specify the target you are building for, TARGET_BITS=0 means native
TARGET_ARCH ?= native
TARGET_BITS ?= 0
# PC Port defines
PC_PORT_DEFINES ?= 0
# PC Port defines from a ported console device
TARGET_PORT_CONSOLE ?= 0
# Various workarounds for weird and/or old toolchains
CPP_ASSEMBLY ?= 0
NO_BZERO_BCOPY ?= 0
NO_LDIV ?= 0
NO_PIE ?= 1
# Use vendor-gnostic GLVND implementation, instead of the old/legacy GLX X11-only implementation.
USE_GLVND ?= 0
# Backend selection
# Renders: GL, GL_LEGACY, D3D11, D3D12, GX2 (forced if the target is Wii U), C3D (forced if the target is 3DS)
RENDER_API ?= GL
# Window managers: SDL1, SDL2, DXGI (forced if D3D11 or D3D12 in RENDER_API), GX2 (forced if the target is Wii U), 3DS (forced if the target is 3DS)
WINDOW_API ?= SDL2
# Audio backends: SDL1, SDL2 (forced if the target is Wii U), 3DS (forced if the target is 3DS)
AUDIO_API ?= SDL2
# Controller backends (can have multiple, space separated): SDL1, SDL2
# WII_U (forced if the target is Wii U), 3DS (forced if the target is 3DS), SWITCH (forced if the target is SWITCH)
CONTROLLER_API ?= SDL2
#==============================================================================#
# Automatic settings for target devices #
#==============================================================================#
# Attempt to detect OS
ifeq ($(OS),Windows_NT)
HOST_OS ?= Windows
else
HOST_OS ?= $(shell uname -s 2>/dev/null || echo Unknown)
# some weird MINGW/Cygwin env that doesn't define $OS
ifneq (,$(findstring MINGW,HOST_OS))
HOST_OS := Windows
endif
endif
OLD_APKSIGNER ?= 0
# Attempt to detect termux android build
ifneq ($(shell which termux-setup-storage 2>/dev/null),)
TARGET_ANDROID := 1
COMPILER_TYPE := clang
ifeq ($(shell dpkg -s apksigner | grep Version | sed "s/Version: //"),0.7-2)
OLD_APKSIGNER := 1
endif
endif
ifeq ($(TARGET_N64),0)
GRUCODE := f3dex2e
PC_PORT_DEFINES := 1
else
GRUCODE ?= f3dzex
NO_LDIV := 1
endif
ifeq ($(TARGET_WII_U),1)
RENDER_API := GX2
WINDOW_API := GX2
AUDIO_API := SDL2
CONTROLLER_API := WII_U
TARGET_PORT_CONSOLE := 1
endif
ifeq ($(TARGET_N3DS),1)
RENDER_API := C3D
WINDOW_API := 3DS
AUDIO_API := 3DS
CONTROLLER_API := 3DS
TARGET_PORT_CONSOLE := 1
endif
ifeq ($(TARGET_SWITCH),1)
RENDER_API := GL
WINDOW_API := SDL2
AUDIO_API := SDL2
CONTROLLER_API := SWITCH
TARGET_PORT_CONSOLE := 1
endif
TOUCH_CONTROLS ?= 0
ifeq ($(TARGET_ANDROID),1)
RENDER_API := GL
WINDOW_API := SDL2
AUDIO_API := SDL2
CONTROLLER_API := SDL2
TOUCH_CONTROLS := 1
endif
# Enforce C preprocessor on these targets
ifeq ($(COMPILER_TYPE),clang)
CPP_ASSEMBLY := 1
endif
ifeq ($(TARGET_PORT_CONSOLE),1)
CPP_ASSEMBLY := 1
endif
ifeq ($(TARGET_WEB),1)
CPP_ASSEMBLY := 1
endif
# Custom Defines
include defines.mk
# MXE overrides
ifeq ($(HOST_OS),Windows)
ifeq ($(TARGET_WEB),0)
ifeq ($(TARGET_PORT_CONSOLE),0)
WINDOWS_BUILD := 1
endif
endif
ifeq ($(CROSS),i686-w64-mingw32.static-)
TARGET_ARCH = i386pe
TARGET_BITS = 32
NO_BZERO_BCOPY := 1
else ifeq ($(CROSS),x86_64-w64-mingw32.static-)
TARGET_ARCH = i386pep
TARGET_BITS = 64
NO_BZERO_BCOPY := 1
endif
endif
ifneq (,$(filter $(RENDER_API),D3D11 D3D12))
ifneq ($(WINDOWS_BUILD),1)
$(error DirectX is only supported on Windows)
endif
ifneq ($(WINDOW_API),DXGI)
$(warning DirectX renderers require DXGI, forcing WINDOW_API value)
WINDOW_API := DXGI
endif
else
ifeq ($(WINDOW_API),DXGI)
$(error DXGI can only be used with DirectX renderers)
endif
endif
# macOS overrides
ifeq ($(HOST_OS),Darwin)
OSX_BUILD := 1
CPP_ASSEMBLY := 1
# Using Homebrew?
ifeq ($(shell which brew >/dev/null 2>&1 && echo y),y)
OSX_GCC_VER = $(shell find `brew --prefix`/bin/gcc* | grep -oE '[[:digit:]]+' | sort -n | uniq | tail -1)
CC := gcc-$(OSX_GCC_VER)
CXX := g++-$(OSX_GCC_VER)
CPP := cpp-$(OSX_GCC_VER)
PLATFORM_CFLAGS := -I $(shell brew --prefix)/include
PLATFORM_LDFLAGS := -L $(shell brew --prefix)/lib
else
# Using MacPorts?
ifeq ($(shell test -d /opt/local/lib && echo y),y)
OSX_GCC_VER = $(shell find /opt/local/bin/gcc* | grep -oE '[[:digit:]]+' | sort -n | uniq | tail -1)
CC := gcc-mp-$(OSX_GCC_VER)
CXX := g++-mp-$(OSX_GCC_VER)
CPP := cpp-mp-$(OSX_GCC_VER)
PLATFORM_CFLAGS := -I /opt/local/include
PLATFORM_LDFLAGS := -L /opt/local/lib
else
$(error No suitable macOS toolchain found, have you installed Homebrew?)
endif
endif
endif
ifneq ($(TARGET_BITS),0)
BITS := -m$(TARGET_BITS)
endif
# Set up WUT for Wii U
ifeq ($(TARGET_WII_U),1)
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
ifeq ($(strip $(DEVKITPPC)),)
$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=<path to>/devkitPro/devkitPPC")
endif
include $(DEVKITPPC)/base_tools
PORTLIBS := $(PORTLIBS_PATH)/wiiu $(PORTLIBS_PATH)/ppc
export PATH := $(PORTLIBS_PATH)/wiiu/bin:$(PORTLIBS_PATH)/ppc/bin:$(PATH)
WUT_ROOT ?= $(DEVKITPRO)/wut
RPXSPECS := -specs=$(WUT_ROOT)/share/wut.specs
MACHDEP = -DESPRESSO -mcpu=750 -meabi -mhard-float
LIBDIRS := $(PORTLIBS) $(WUT_ROOT)
INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include)
LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
endif
# Base settings for EXTERNAL_DATA
ifeq ($(TARGET_PORT_CONSOLE),1)
BASEDIR ?= sm64ex_res
else
BASEDIR ?= res
endif
BASEPACK ?= base.zip
#==============================================================================#
# Main defines #
#==============================================================================#
# VERSION - selects the version of the game to build
# jp - builds the 1996 Japanese version
# us - builds the 1996 North American version
# eu - builds the 1997 PAL version
# sh - builds the 1997 Japanese Shindou version, with rumble pak support
# cn - builds the 2003 Chinese iQue version
VERSION ?= us
$(eval $(call validate-option,VERSION,jp us eu sh cn))
NEW_AUDIO_REV ?= false
ifeq ($(VERSION),jp)
VER_DEFINES += VERSION_JP=1
else ifeq ($(VERSION),us)
VER_DEFINES += VERSION_US=1
else ifeq ($(VERSION),eu)
VER_DEFINES += VERSION_EU=1
else ifeq ($(VERSION),sh)
VER_DEFINES += VERSION_SH=1
NEW_AUDIO_REV := true
else ifeq ($(VERSION),cn)
VER_DEFINES += VERSION_CN=1
NEW_AUDIO_REV := true
endif
DEFINES += $(VER_DEFINES)
TARGET := sm64.$(VERSION).$(GRUCODE)
# GRUCODE - selects which RSP microcode to use.
# f3d_old - First version the Fast3D (Originally in JP - US)
# f3d_new - Second version the Fast3D (Originally in EU - SH)
# f3dex - First version of Fast3D Extended
# f3dex2 - Second (rewritten) version of Fast3D Extended
# l3dex2 - F3DEX2 version that only renders in wireframe
# f3dex2e - Exclusive PC Version of the F3DEX2 microcode
# f3dzex - newer, experimental microcode used in Animal Crossing
# super3d - extremely experimental version of Fast3D lacking many features for speed
$(eval $(call validate-option,GRUCODE,f3d_old f3dex f3dex2 f3dex2e f3dex2pl f3d_new f3dzex super3d l3dex2))
ifeq ($(GRUCODE),f3d_old)
GRU_DEFINES += F3D_OLD=1
else ifeq ($(GRUCODE),f3d_new) # Fast3D 2.0H
GRU_DEFINES += F3D_NEW=1
else ifeq ($(GRUCODE),f3dex) # Fast3DEX
GRU_DEFINES += F3DEX_GBI=1 F3DEX_GBI_SHARED=1
else ifeq ($(GRUCODE),f3dex2) # Fast3DEX2
GRU_DEFINES += F3DEX_GBI_2=1 F3DEX_GBI_SHARED=1
else ifeq ($(GRUCODE),l3dex2) # Line3DEX2
GRU_DEFINES += L3DEX2_GBI=1 L3DEX2_ALONE=1 F3DEX_GBI_2=1 F3DEX_GBI_SHARED=1
else ifeq ($(GRUCODE),f3dex2pl) # Fast3DEX2_PosLight
GRU_DEFINES += F3DEX2PL_GBI=1 F3DEX_GBI_2=1 F3DEX_GBI_SHARED=1
else ifeq ($(GRUCODE),f3dzex) # Fast3DZEX (2.08J / Animal Forest - Dōbutsu no Mori)
GRU_DEFINES += F3DZEX_GBI_2=1 F3DEX_GBI_2=1 F3DEX_GBI_SHARED=1
else ifeq ($(GRUCODE),super3d) # Super3D
$(warning Super3D is experimental. Try at your own risk.)
GRU_DEFINES += SUPER3D_GBI=1 F3D_NEW=1
else ifeq ($(GRUCODE),f3dex2e) # Fast3DEX2 Extended (PC Only)
ifeq ($(TARGET_N64),1)
$(error f3dex2e is only supported on PC Port)
else
GRU_DEFINES += F3DEX_GBI_2E=1
endif
endif
DEFINES += $(GRU_DEFINES)
# Specify target defines
ifeq ($(TARGET_RPI),1) # Define RPi to change SDL2 title & GLES2 hints
DEFINES += TARGET_RPI=1 USE_GLES=1
else ifeq ($(TARGET_ANDROID),1)
DEFINES += TARGET_ANDROID=1 USE_GLES=1
else ifeq ($(OSX_BUILD),1) # Modify GFX & SDL2 for OSX GL
DEFINES += OSX_BUILD=1
else ifeq ($(TARGET_WEB),1)
DEFINES += TARGET_WEB=1 USE_GLES=1
else ifeq ($(TARGET_WII_U),1)
DEFINES += TARGET_WII_U=1
else ifeq ($(TARGET_N3DS),1)
DEFINES += TARGET_N3DS=1
else ifeq ($(TARGET_SWITCH),1)
DEFINES += TARGET_SWITCH=1 USE_GLES=1
endif
# OpenGL defines
ifeq ($(USE_GLES),1) # GLES can be used outside Raspberry Pi, Android or Switch
DEFINES += USE_GLES=1
endif
# Libultra defines
LIBULTRA ?= L
# Libultra number revision (only used on 2.0D)
LIBULTRA_REVISION ?= 0
# LIBULTRA - sets the libultra OS version to use
$(eval $(call validate-option,LIBULTRA,D F H I J K L BB))
# Libultra number revision (only used on 2.0D)
LIBULTRA_REVISION ?= 0
ULTRA_VER_D := 1
ULTRA_VER_E := 2
ULTRA_VER_F := 3
ULTRA_VER_G := 4
ULTRA_VER_H := 5
ULTRA_VER_I := 6
ULTRA_VER_J := 7
ULTRA_VER_K := 8
ULTRA_VER_L := 9
ifeq ($(LIBULTRA),BB)
ULTRA_VER_DEF := LIBULTRA_VERSION=$(ULTRA_VER_L) BBPLAYER
ULTRA_VER_STR := LIBULTRA_STR_VER=\"L\"
else
ULTRA_VER_DEF := LIBULTRA_VERSION=$(ULTRA_VER_$(LIBULTRA)) LIBULTRA_REVISION=$(LIBULTRA_REVISION)
ULTRA_VER_STR := LIBULTRA_STR_VER=\"$(LIBULTRA)\"
endif
DEFINES += $(ULTRA_VER_DEF) $(ULTRA_VER_STR)
# Important defines
# Mandatory defines to ensture correct compilation
DEFINES += NON_MATCHING=1 AVOID_UB=1
# Check for no bzero/bcopy workaround option
ifeq ($(NO_BZERO_BCOPY),1)
DEFINES += NO_BZERO_BCOPY=1
endif
# Use internal ldiv()/lldiv()
ifeq ($(NO_LDIV),1)
DEFINES += NO_LDIV=1
endif
# Set no-pie if compiler supports it
ifeq ($(NO_PIE),1)
NO_PIE_DEF := -no-pie
endif
ifeq ($(TARGET_N64),1)
DEFINES += TARGET_N64=1 _FINALROM=1
endif
#==============================================================================#
# Universal Dependencies #
#==============================================================================#
PYTHON := python3
TOOLS_DIR = tools
# (This is a bit hacky, but a lot of rules implicitly depend
# on tools and assets, and we use directory globs further down
# in the makefile that we want should cover assets.)
ifeq ($(filter clean distclean print-%,$(MAKECMDGOALS)),)
# Make sure assets exist
NOEXTRACT ?= 0
ifeq ($(NOEXTRACT),0)
DUMMY != $(PYTHON) extract_assets.py $(VERSION) >&2 || echo FAIL
ifeq ($(DUMMY),FAIL)
$(error Failed to extract assets from US ROM)
endif
ifneq (,$(wildcard baserom.jp.z64))
DUMMY != $(PYTHON) extract_assets.py jp >&2 || echo FAIL
ifeq ($(DUMMY),FAIL)
$(error Failed to extract assets from JP ROM)
endif
endif
ifneq (,$(wildcard baserom.eu.z64))
DUMMY != $(PYTHON) extract_assets.py eu >&2 || echo FAIL
ifeq ($(DUMMY),FAIL)
$(error Failed to extract assets from EU ROM)
endif
endif
ifneq (,$(wildcard baserom.sh.z64))
DUMMY != $(PYTHON) extract_assets.py sh >&2 || echo FAIL
ifeq ($(DUMMY),FAIL)
$(error Failed to extract assets from SH ROM)
endif
endif
endif
# Make tools if out of date
$(info Building tools...)
ifeq ($(TARGET_PORT_CONSOLE),0)
DUMMY != CC=$(CC) CXX=$(CXX) $(MAKE) -s -C $(TOOLS_DIR) >&2 || echo FAIL
else
DUMMY != $(MAKE) -s -C $(TOOLS_DIR) >&2 || echo FAIL
endif
ifeq ($(DUMMY),FAIL)
$(error Failed to build tools)
endif
$(info Building game...)
endif
#==============================================================================#
# Optimization flags #
#==============================================================================#
ifeq ($(TARGET_N64),1)
ifeq ($(COMPILER_TYPE),gcc)
MIPSISET := -mips3
OPT_FLAGS := -Ofast
else ifeq ($(COMPILER_TYPE),clang)
# clang doesn't support ABI 'o32' for 'mips3'
MIPSISET := -mips2
OPT_FLAGS := -Ofast
endif
else
ifeq ($(COMPILER_OPT),default)
OPT_FLAGS := -O2
else ifeq ($(COMPILER_OPT),debug)
OPT_FLAGS := -g
else ifeq ($(COMPILER_OPT),debugmax)
OPT_FLAGS := -O2 -g3
else ifeq ($(COMPILER_OPT),fast)
OPT_FLAGS := -Ofast
endif
# Set BITS (32/64) to compile for
OPT_FLAGS += $(BITS)
endif
ifeq ($(TARGET_WEB),1)
OPT_FLAGS := -O2 -g4 --source-map-base http://localhost:8080/
endif
ifeq ($(TARGET_RPI),1)
OPT_FLAGS := -O3 -march=native -mtune=native
endif
#==============================================================================#
# Target Executable and Sources #
#==============================================================================#
# BUILD_DIR is location where all build artifacts are placed
BUILD_DIR_BASE := build
TARGET_NAME :=
ifeq ($(TARGET_N64),1)
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)
EXE := $(BUILD_DIR)/$(TARGET)
ROM := $(BUILD_DIR)/$(TARGET).z64
TARGET_NAME := Nintendo 64
else ifeq ($(TARGET_WEB),1)
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_web
EXE := $(BUILD_DIR)/$(TARGET).html
TARGET_NAME := Website
else ifeq ($(TARGET_WII_U),1)
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_wiiu
EXE := $(BUILD_DIR)/$(TARGET).rpx
TARGET_NAME := Nintendo Wii U
else ifeq ($(TARGET_N3DS),1)
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_3ds
EXE := $(BUILD_DIR)/$(TARGET).3dsx
CIA := $(BUILD_DIR)/$(TARGET).cia
TARGET_NAME := Nintendo 3DS
else ifeq ($(TARGET_SWITCH),1)
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_nx
EXE := $(BUILD_DIR)/$(TARGET).nro
TARGET_NAME := Nintendo Switch
else ifeq ($(TARGET_ANDROID),1)
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_android
EXE := $(BUILD_DIR)/libmain.so
APK := $(BUILD_DIR)/$(TARGET).unsigned.apk
APK_SIGNED := $(BUILD_DIR)/$(TARGET).apk
TARGET_NAME := Android
else ifeq ($(WINDOWS_BUILD),1) # us_win (to be renamed)
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_pc
EXE := $(BUILD_DIR)/$(TARGET).exe
TARGET_NAME := Windows
else # Linux/Unix builds/binary namer
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_pc
ifeq ($(TARGET_RPI),1) # us_rpi (to be renamed)
EXE := $(BUILD_DIR)/$(TARGET).arm
else # us_tux (to be renamed)
EXE := $(BUILD_DIR)/$(TARGET)
endif
ifeq ($(OSX_BUILD),1)
TARGET_NAME := macOS
else ifeq ($(HOST_OS),Haiku)
TARGET_NAME := Haiku OS
else ifeq ($(TARGET_RPI),1)
TARGET_NAME := Raspberry Pi
else
TARGET_NAME := Linux-Unix system
endif
endif
ELF := $(BUILD_DIR)/$(TARGET).elf
LD_SCRIPT := sm64.ld
CHARMAP := charmap.txt
CHARMAP_DEBUG := charmap.debug.txt
MIO0_DIR := $(BUILD_DIR)/bin
SOUND_BIN_DIR := $(BUILD_DIR)/sound
TEXTURE_DIR := textures
ACTOR_DIR := actors
LEVEL_DIRS := $(patsubst levels/%,%,$(dir $(wildcard levels/*/header.h)))
# Directories containing source files
SRC_DIRS := src src/engine src/game src/audio src/menu src/buffers src/extras actors levels bin bin/$(VERSION) data assets sound
BOOT_DIR := src/boot
ifeq ($(TARGET_N64),1)
SRC_DIRS += asm lib src/extras/n64
else
# Specify target folders
PLATFORM_DIR := platform
SRC_DIRS += src/pc src/pc/audio src/pc/controller src/pc/crash src/pc/fs src/pc/fs/packtypes src/pc/gfx
ifeq ($(WINDOWS_BUILD),1)
PLATFORM_DIR := $(PLATFORM_DIR)/win
else ifeq ($(TARGET_N3DS),1)
PLATFORM_DIR := $(PLATFORM_DIR)/3ds
else ifeq ($(TARGET_SWITCH),1)
PLATFORM_DIR := $(PLATFORM_DIR)/switch
else ifeq ($(TARGET_ANDROID),1)
PLATFORM_DIR := $(PLATFORM_DIR)/android
endif
SRC_DIRS += $(PLATFORM_DIR)
endif
ifeq ($(TARGET_PORT_CONSOLE),0)
ifeq ($(DISCORDRPC),1)
SRC_DIRS += src/pc/discord
endif
endif
BIN_DIRS := bin bin/$(VERSION)
ifeq ($(LIBULTRA),BB)
ULTRA_SRC_DIRS := $(shell find lib/ultra -type d)
else
ULTRA_SRC_DIRS := $(shell find lib/ultra -type d -not -path "lib/ultra/bb/*")
endif
ULTRA_BIN_DIRS := lib/bin
LIBGCC_SRC_DIRS := lib/gcc
ifeq ($(GODDARD_MFACE),1)
GODDARD_SRC_DIRS := src/goddard src/goddard/dynlists
endif
# Whether to hide commands or not
VERBOSE ?= 0
ifeq ($(VERBOSE),0)
V := @
endif
# Whether to colorize build messages
COLOR ?= 1
# File dependencies and variables for specific files
include Makefile.split
# Source code files
LEVEL_C_FILES := $(wildcard levels/*/leveldata.c) $(wildcard levels/*/script.c) $(wildcard levels/*/geo.c)
ifeq ($(RM2C),1)
LEVEL_C_FILES += $(wildcard levels/*/custom.leveldata.c) $(wildcard levels/*/custom.script.c) $(wildcard levels/*/custom.geo.c)
endif
C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c)) $(LEVEL_C_FILES)
CXX_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.cpp))
S_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.s))
ifeq ($(TARGET_N64),1)
C_FILES += $(foreach dir,$(BOOT_DIR),$(wildcard $(dir)/*.c))
S_FILES += $(foreach dir,$(BOOT_DIR),$(wildcard $(dir)/*.s))
ULTRA_C_FILES := $(foreach dir,$(ULTRA_SRC_DIRS),$(wildcard $(dir)/*.c))
ULTRA_S_FILES := $(foreach dir,$(ULTRA_SRC_DIRS),$(wildcard $(dir)/*.s))
LIBGCC_C_FILES := $(foreach dir,$(LIBGCC_SRC_DIRS),$(wildcard $(dir)/*.c))
endif
ifeq ($(GODDARD_MFACE),1)
GODDARD_C_FILES := $(foreach dir,$(GODDARD_SRC_DIRS),$(wildcard $(dir)/*.c))
endif
ifeq ($(WINDOWS_BUILD),1)
RC_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.rc))
endif
GENERATED_C_FILES := $(BUILD_DIR)/assets/mario_anim_data.c $(BUILD_DIR)/assets/demo_data.c
ifneq ($(TARGET_N64),1)
GENERATED_C_FILES += $(addprefix $(BUILD_DIR)/bin/,$(addsuffix _skybox.c,$(notdir $(basename $(wildcard textures/skyboxes/*.png)))))
ULTRA_C_FILES := \
audio/bnkf.c \
gu/lookatref.c \
gu/mtxutil.c \
gu/normalize.c \
gu/ortho.c \
gu/perspective.c \
gu/rotate.c \
gu/scale.c \
gu/translate.c \
libc/ldiv.c
ULTRA_C_FILES := $(addprefix lib/ultra/,$(ULTRA_C_FILES))
C_FILES += $(addprefix src/boot/,memory.c)
endif
# "If we're not N64, use the above"
SOUND_BANK_FILES := $(wildcard sound/sound_banks/*.json)
ifeq ($(VERSION),cn)
SOUND_SEQUENCE_DIRS := sound/sequences sound/sequences/sh
else
SOUND_SEQUENCE_DIRS := sound/sequences sound/sequences/$(VERSION)
endif
# all .m64 files in SOUND_SEQUENCE_DIRS, plus all .m64 files that are generated from .s files in SOUND_SEQUENCE_DIRS
SOUND_SEQUENCE_FILES := \
$(foreach dir,$(SOUND_SEQUENCE_DIRS),\
$(wildcard $(dir)/*.m64) \
$(foreach file,$(wildcard $(dir)/*.s),$(BUILD_DIR)/$(file:.s=.m64)) \
)
SOUND_SAMPLE_DIRS := $(wildcard sound/samples/*)
SOUND_SAMPLE_AIFFS := $(foreach dir,$(SOUND_SAMPLE_DIRS),$(wildcard $(dir)/*.aiff))
SOUND_SAMPLE_TABLES := $(foreach file,$(SOUND_SAMPLE_AIFFS),$(BUILD_DIR)/$(file:.aiff=.table))
SOUND_SAMPLE_AIFCS := $(foreach file,$(SOUND_SAMPLE_AIFFS),$(BUILD_DIR)/$(file:.aiff=.aifc))
# Object files
O_FILES := $(foreach file,$(C_FILES),$(BUILD_DIR)/$(file:.c=.o)) \
$(foreach file,$(CXX_FILES),$(BUILD_DIR)/$(file:.cpp=.o)) \
$(foreach file,$(S_FILES),$(BUILD_DIR)/$(file:.s=.o)) \
$(foreach file,$(GENERATED_C_FILES),$(file:.c=.o))
ifeq ($(WINDOWS_BUILD),1)
O_FILES += $(foreach file,$(RC_FILES),$(BUILD_DIR)/$(file:.rc=.o))
endif
ULTRA_O_FILES := $(foreach file,$(ULTRA_S_FILES),$(BUILD_DIR)/$(file:.s=.o)) \
$(foreach file,$(ULTRA_C_FILES),$(BUILD_DIR)/$(file:.c=.o))
ifeq ($(GODDARD_MFACE),1)
GODDARD_O_FILES := $(foreach file,$(GODDARD_C_FILES),$(BUILD_DIR)/$(file:.c=.o))
endif
ifeq ($(TARGET_N64),1)
LIBGCC_O_FILES := $(foreach file,$(LIBGCC_C_FILES),$(BUILD_DIR)/$(file:.c=.o))
endif
RPC_LIBS :=
ifeq ($(TARGET_PORT_CONSOLE),0)
ifeq ($(DISCORDRPC),1)
ifeq ($(WINDOWS_BUILD),1)
RPC_LIBS := lib/discord/libdiscord-rpc.dll
else ifeq ($(OSX_BUILD),1)
# needs testing
RPC_LIBS := lib/discord/libdiscord-rpc.dylib
else
RPC_LIBS := lib/discord/libdiscord-rpc.so
endif
endif
endif
# Automatic dependency files
DEP_FILES := $(O_FILES:.o=.d) $(ULTRA_O_FILES:.o=.d) $(GODDARD_O_FILES:.o=.d) $(BUILD_DIR)/$(LD_SCRIPT).d
ifeq ($(TARGET_N64),1)
DEP_FILES += $(LIBGCC_O_FILES:.o=.d)
endif
#==============================================================================#
# Compiler Options #
#==============================================================================#
INCLUDE_DIRS := include $(BUILD_DIR) $(BUILD_DIR)/include src .
ifeq ($(TARGET_N64),1)
INCLUDE_DIRS += include/gcc
endif
ifeq ($(TARGET_ANDROID),1)
INCLUDE_DIRS += $(PLATFORM_DIR)/SDL/include
endif
ifeq ($(TARGET_SWITCH),1)
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
export PATH := $(DEVKITPRO)/devkitA64/bin:$(PATH)
include $(DEVKITPRO)/devkitA64/base_tools
NXPATH := $(DEVKITPRO)/portlibs/switch/bin
PORTLIBS ?= $(DEVKITPRO)/portlibs/switch
LIBNX ?= $(DEVKITPRO)/libnx
CROSS ?= aarch64-none-elf-
SDLCROSS := $(NXPATH)/
CC := $(CROSS)gcc
CXX := $(CROSS)g++
STRIP := $(CROSS)strip
NXARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
INCLUDE_DIRS += $(LIBNX)/include $(PORTLIBS)/include
NX_APP_TITLE := Super Mario 64
NX_APP_AUTHOR := Nintendo - Port by Vatuu, fgsfdsfgs and KiritoDev
NX_APP_VERSION := ver_$(VERSION)
NX_APP_ICON := $(PLATFORM_DIR)/logo.jpg
NACP_FILE := $(BUILD_DIR)/$(PLATFORM_DIR)/sm64.nacp
endif
C_DEFINES := $(foreach d,$(DEFINES),-D$(d))
DEF_INC_CFLAGS := $(foreach i,$(INCLUDE_DIRS),-I $(i)) $(C_DEFINES)
# Set C Preprocessor flags
ifeq ($(COMPILER_TYPE),gcc)
CPPFLAGS := -P -Wno-trigraphs
else ifeq ($(COMPILER_TYPE),clang)
CPPFLAGS := -E -P -x c -Wno-trigraphs
endif
CPPFLAGS += $(DEF_INC_CFLAGS) $(CUSTOM_C_DEFINES)
ASMDEFINES := $(VER_DEFINES) $(GRU_DEFINES) $(ULTRA_VER_DEF)
# 3DS Minimap flags
ifeq ($(TARGET_N3DS),1)
MINIMAP := $(PLATFORM_DIR)/minimap
MINIMAP_C := $(wildcard $(MINIMAP)/*.c)
MINIMAP_O := $(foreach file,$(MINIMAP_C),$(BUILD_DIR)/$(file:.c=.o))
MINIMAP_TEXTURES := $(MINIMAP)/textures
MINIMAP_PNG := $(wildcard $(MINIMAP_TEXTURES)/*.png)
MINIMAP_T3S := $(foreach file,$(MINIMAP_PNG),$(BUILD_DIR)/$(file:.png=.t3s))
MINIMAP_T3X := $(foreach file,$(MINIMAP_T3S),$(file:.t3s=.t3x))
MINIMAP_T3X_O := $(foreach file,$(MINIMAP_T3X),$(file:.t3x=.t3x.o))
MINIMAP_T3X_HEADERS := $(foreach file,$(MINIMAP_PNG),$(BUILD_DIR)/$(file:.png=_t3x.h))
endif
ifeq ($(TARGET_N64),1)
# detect prefix for MIPS toolchain
ifneq ($(call find-command,mips64-elf-ld),)
CROSS := mips64-elf-
else ifneq ($(call find-command,mips-n64-ld),)
CROSS := mips-n64-
else ifneq ($(call find-command,mips64-ld),)
CROSS := mips64-
else ifneq ($(call find-command,mips-linux-gnu-ld),)
CROSS := mips-linux-gnu-
else ifneq ($(call find-command,mips64-linux-gnu-ld),)
CROSS := mips64-linux-gnu-
else ifneq ($(call find-command,mips64-none-elf-ld),)
CROSS := mips64-none-elf-
else ifneq ($(call find-command,mips-ld),)
CROSS := mips-
else
$(error Unable to detect a suitable MIPS toolchain installed)
endif
# change the compiler to gcc, to use the default, install the gcc-mips-linux-gnu package
ifeq ($(COMPILER_TYPE),gcc)
CC := $(CROSS)gcc
CPP := cpp
else ifeq ($(COMPILER_TYPE),clang)
CC := clang
CPP := clang
endif
# use GNU binutils for assembler, linker, archiver, and object tools
AS := $(CROSS)as
LD := $(CROSS)ld
AR := $(CROSS)ar
OBJDUMP := $(CROSS)objdump
OBJCOPY := $(CROSS)objcopy
# Check code syntax with host compiler
CFLAGS := -G 0 -nostdinc $(MIPSISET) $(DEF_INC_CFLAGS)
ifeq ($(COMPILER_TYPE),gcc)
CFLAGS += -mno-shared -march=vr4300 -mfix4300 -mabi=32 -mhard-float -mdivide-breaks -fno-stack-protector -fno-common -fno-zero-initialized-in-bss -fno-PIC -mno-abicalls -fno-strict-aliasing -fno-inline-functions -ffreestanding -fwrapv -Wall -Wextra
CFLAGS += -Wno-missing-braces
else ifeq ($(COMPILER_TYPE),clang)
CFLAGS += -mfpxx -target mips -mabi=32 -mhard-float -fomit-frame-pointer -fno-stack-protector -fno-common -I include -I src/ -I $(BUILD_DIR)/include -fno-PIC -mno-abicalls -fno-strict-aliasing -fno-inline-functions -ffreestanding -fwrapv -Wall -Wextra
CFLAGS += -Wno-missing-braces
else
CFLAGS += -non_shared -Wab,-r4300_mul -Xcpluscomm -Xfullwarn -signed -32
endif
ifeq ($(CPP_ASSEMBLY),1)
ASFLAGS := -march=vr4300 -mabi=32 $(foreach i,$(INCLUDE_DIRS),-I$(i)) $(foreach d,$(ASMDEFINES),--defsym $(d))
else
ASMFLAGS := -G 0 $(DEF_INC_CFLAGS) -w -nostdinc -c -march=vr4300 -mfix4300 -mno-abicalls -DMIPSEB -D_LANGUAGE_ASSEMBLY -D_MIPS_SIM=1 -D_MIPS_SZLONG=32
endif
RSPASMFLAGS := $(foreach d,$(ASMDEFINES),-definelabel $(subst =, ,$(d)))
OBJCOPYFLAGS := --pad-to=0x800000 --gap-fill=0xFF
SYMBOL_LINKING_FLAGS := --no-check-sections $(addprefix -R ,$(SEG_FILES))
LDFLAGS := -T $(BUILD_DIR)/$(LD_SCRIPT) -Map $(BUILD_DIR)/sm64.$(VERSION).map $(SYMBOL_LINKING_FLAGS)
CFLAGS += $(CUSTOM_C_DEFINES)
ASMFLAGS += $(CUSTOM_C_DEFINES)
else # TARGET_N64
ifeq ($(TARGET_WII_U),1)
LD := $(CXX)
CPP := powerpc-eabi-cpp
OBJDUMP := powerpc-eabi-objdump
SDLCONFIG :=
else ifeq ($(TARGET_N3DS),1)
CPP := $(DEVKITARM)/bin/arm-none-eabi-cpp
OBJDUMP := $(DEVKITARM)/bin/arm-none-eabi-objdump
OBJCOPY := $(DEVKITARM)/bin/arm-none-eabi-objcopy
AS := $(DEVKITARM)/bin/arm-none-eabi-as
CC := $(DEVKITARM)/bin/arm-none-eabi-gcc
CXX := $(DEVKITARM)/bin/arm-none-eabi-g++
LD := $(CXX)
SDLCONFIG :=
SMDH_TITLE ?= Super Mario 64
SMDH_DESCRIPTION ?= Super Mario 64 3DS Port
SMDH_AUTHOR ?= Nintendo - port by Fnouwt (Gericom) and mkst
SMDH_ICON := $(PLATFORM_DIR)/icon.smdh
else
# for some reason sdl-config in dka64 is not prefixed, while pkg-config is
SDLCROSS ?= $(CROSS)
AS ?= $(CROSS)as
ifeq ($(OSX_BUILD),1) # As in, not using macOS
AS := /usr/bin/as
endif
ifneq ($(TARGET_WEB),1) # As in, not-web PC port
CC ?= $(CROSS)gcc
CXX ?= $(CROSS)g++
else
CC := emcc
CXX := emcc
endif
AS_MINGW := i686-w64-mingw32-as
LD := $(CXX)
ifeq ($(DISCORDRPC),1)
LD := $(CXX)
else ifeq ($(WINDOWS_BUILD),1)
ifeq ($(CROSS),i686-w64-mingw32.static-) # fixes compilation in MXE on Linux and WSL
LD := $(CC)
else ifeq ($(CROSS),x86_64-w64-mingw32.static-)
LD := $(CC)
else
LD := $(CXX)
endif
endif
ifeq ($(WINDOWS_BUILD),1) # fixes compilation in MXE on Linux and WSL
CPP := cpp
OBJCOPY := objcopy
OBJDUMP := $(CROSS)objdump
else ifeq ($(OSX_BUILD),1)
OBJCOPY := i686-w64-mingw32-objcopy
OBJDUMP := i686-w64-mingw32-objdump
else ifeq ($(TARGET_ANDROID),1) # Termux has clang
ifeq ($(COMPILER_TYPE),clang)
CPP := clang
else
CPP := cpp
endif
OBJCOPY := $(CROSS)objcopy
OBJDUMP := $(CROSS)objdump
else # Linux & other builds
ifeq ($(COMPILER_TYPE),clang)
CPP := clang
else
CPP := $(CROSS)cpp
endif
OBJCOPY := $(CROSS)objcopy
OBJDUMP := $(CROSS)objdump
endif
SDLCONFIG := $(SDLCROSS)sdl2-config
WINDRES := $(CROSS)windres
endif
# configure backend flags
BACKEND_CFLAGS := -DRAPI_$(RENDER_API)=1 -DWAPI_$(WINDOW_API)=1 -DAAPI_$(AUDIO_API)=1
# can have multiple controller APIs
BACKEND_CFLAGS += $(foreach capi,$(CONTROLLER_API),-DCAPI_$(capi)=1)
BACKEND_LDFLAGS :=
SDL1_USED := 0
SDL2_USED := 0
# for now, it's either SDL+GL, DXGI+DirectX, GX2 or C3D so choose based on WAPI
ifeq ($(WINDOW_API),DXGI)
DXBITS := `cat $(ENDIAN_BITWIDTH) | tr ' ' '\n' | tail -1`
ifeq ($(RENDER_API),D3D12)
BACKEND_CFLAGS += -Iinclude/dxsdk
endif
BACKEND_LDFLAGS += -ld3dcompiler -ldxgi -ldxguid
BACKEND_LDFLAGS += -lsetupapi -ldinput8 -luser32 -lgdi32 -limm32 -lole32 -loleaut32 -lshell32 -lwinmm -lversion -luuid -static
else ifeq ($(findstring SDL,$(WINDOW_API)),SDL)
ifeq ($(WINDOWS_BUILD),1)
BACKEND_LDFLAGS += -lglew32 -lglu32 -lopengl32
else ifeq ($(TARGET_ANDROID),1)
BACKEND_LDFLAGS += -lGLESv2
else ifeq ($(TARGET_RPI),1)
BACKEND_LDFLAGS += -lGLESv2
else ifeq ($(TARGET_SWITCH),1)
BACKEND_LDFLAGS += -lGLESv2
else ifeq ($(USE_GLES),1)
BACKEND_LDFLAGS += -lGLESv2
else ifeq ($(OSX_BUILD),1)
BACKEND_LDFLAGS += -framework OpenGL $(shell pkg-config --libs glew)
else ifeq ($(USE_GLVND),1)
BACKEND_LDFLAGS += -lOpenGL
else
BACKEND_LDFLAGS += -lGL
endif
else ifeq ($(WINDOW_API),GX2)
BACKEND_LDFLAGS += -lSDL2 -lwut
else ifeq ($(WINDOW_API),C3D)
BACKEND_LDFLAGS +=
endif
ifneq (,$(findstring SDL2,$(AUDIO_API)$(WINDOW_API)$(CONTROLLER_API)))
SDL2_USED := 1
endif
ifneq (,$(findstring SDL1,$(AUDIO_API)$(WINDOW_API)$(CONTROLLER_API)))
SDL1_USED := 1
endif
ifeq ($(SDL1_USED)$(SDL2_USED),11)
$(error Cannot link both SDL1 and SDL2 at the same time)
endif
# SDL can be used by different systems, so we consolidate all of that shit into this
ifeq ($(SDL2_USED),1)
SDLCONFIG := $(SDLCROSS)sdl2-config
BACKEND_CFLAGS += -DHAVE_SDL2=1
else ifeq ($(SDL1_USED),1)
SDLCONFIG := $(SDLCROSS)sdl-config
BACKEND_CFLAGS += -DHAVE_SDL1=1
endif
ifeq ($(TARGET_WII_U),0)
ifneq ($(SDL1_USED)$(SDL2_USED),00)
ifeq ($(TARGET_ANDROID),1)
BACKEND_LDFLAGS += -lhidapi -lSDL2
else ifeq ($(OSX_BUILD),1)
# on OSX at least the homebrew version of sdl-config gives include path as `.../include/SDL2` instead of `.../include`
OSX_PREFIX := $(shell $(SDLCONFIG) --prefix)
BACKEND_CFLAGS += -I$(OSX_PREFIX)/include $(shell $(SDLCONFIG) --cflags)
BACKEND_LDFLAGS += $(shell $(SDLCONFIG) --libs)
else
BACKEND_CFLAGS += $(shell $(SDLCONFIG) --cflags)
ifeq ($(WINDOWS_BUILD),1)
BACKEND_LDFLAGS += $(shell $(SDLCONFIG) --static-libs) -lsetupapi -luser32 -limm32 -lole32 -loleaut32 -lshell32 -lwinmm -lversion
else
BACKEND_LDFLAGS += $(shell $(SDLCONFIG) --libs)
endif
endif
endif
endif
ifeq ($(WINDOWS_BUILD),1)
CFLAGS := $(BACKEND_CFLAGS) $(DEF_INC_CFLAGS) -fno-strict-aliasing -fwrapv
ifeq ($(TARGET_BITS), 32)
BACKEND_LDFLAGS += -ldbghelp
endif
else ifeq ($(TARGET_WEB),1)
CFLAGS := $(BACKEND_CFLAGS) $(DEF_INC_CFLAGS) -fno-strict-aliasing -fwrapv -s USE_SDL=2
# Linux / Other builds below
else
CFLAGS := $(PLATFORM_CFLAGS) $(BACKEND_CFLAGS) $(DEF_INC_CFLAGS) -fno-strict-aliasing -fwrapv
ifeq ($(TARGET_PORT_CONSOLE),0)
BACKEND_LDFLAGS += -rdynamic
endif
endif
ifeq ($(TARGET_WII_U),1)
CFLAGS += -ffunction-sections $(MACHDEP) -ffast-math -D__WIIU__ -D__WUT__ $(INCLUDE)
endif
ifeq ($(TARGET_N3DS),1)
CTRULIB := $(DEVKITPRO)/libctru
LIBDIRS := $(CTRULIB)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
CFLAGS += -mtp=soft -DosGetTime=n64_osGetTime -D__3DS__ -march=armv6k -mtune=mpcore -mfloat-abi=hard -mword-relocations -fomit-frame-pointer -ffast-math $(foreach dir,$(LIBDIRS),-I$(dir)/include)
ifeq ($(DISABLE_N3DS_AUDIO),1)
CFLAGS += -DDISABLE_N3DS_AUDIO
endif
ifeq ($(DISABLE_N3DS_FRAMESKIP),1)
CFLAGS += -DDISABLE_N3DS_FRAMESKIP
endif
endif
ifeq ($(TARGET_SWITCH),1)
CFLAGS := $(NXARCH) $(BACKEND_CFLAGS) $(DEF_INC_CFLAGS) -fno-strict-aliasing -ftls-model=local-exec -fPIC -fwrapv -D__SWITCH__=1
endif
ifeq ($(CPP_ASSEMBLY),1)
ASFLAGS := $(foreach i,$(INCLUDE_DIRS),-I$(i))
ASFLAGS_DEFSYM := $(foreach d,$(ASMDEFINES),--defsym $(d))
ifeq ($(OSX_BUILD),0)
ASFLAGS += $(ASFLAGS_DEFSYM)
endif
else
ASMFLAGS := $(DEF_INC_CFLAGS) -D_LANGUAGE_ASSEMBLY
endif
CFLAGS += $(CUSTOM_C_DEFINES)
ASMFLAGS += $(CUSTOM_C_DEFINES)
# Load external textures
ifeq ($(EXTERNAL_DATA),1)
CFLAGS += -DFS_BASEDIR="\"$(BASEDIR)\""
# tell skyconv to write names instead of actual texture data and save the split tiles so we can use them later
SKYTILE_DIR := $(BUILD_DIR)/textures/skybox_tiles
SKYCONV_ARGS := --store-names --write-tiles "$(SKYTILE_DIR)"
endif
ifeq ($(TARGET_WEB),1)
LDFLAGS := -lm -lGL -lSDL2 $(NO_PIE_DEF) -s TOTAL_MEMORY=64MB -g4 --source-map-base http://localhost:8080/ -s "EXTRA_EXPORTED_RUNTIME_METHODS=['callMain']"
else ifeq ($(TARGET_WII_U),1)
LDFLAGS := -lm $(NO_PIE_DEF) $(BACKEND_LDFLAGS) $(MACHDEP) $(RPXSPECS) $(LIBPATHS)
else ifeq ($(TARGET_N3DS),1)
LDFLAGS := $(LIBPATHS) -lcitro3d -lctru -lm -specs=3dsx.specs -g -marm -mthumb-interwork -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft # -Wl,-Map,$(notdir $*.map)
else ifeq ($(TARGET_SWITCH),1)
LDFLAGS := -specs=$(LIBNX)/switch.specs $(NXARCH) $(BACKEND_LDFLAGS) -lstdc++ -lm
else ifeq ($(WINDOWS_BUILD),1)
LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -Llib -lpthread $(BACKEND_LDFLAGS) -static
ifeq ($(CROSS),)
LDFLAGS += $(NO_PIE_DEF)
endif
ifneq ($(DEBUG),0)
LDFLAGS += -mconsole
endif
else ifeq ($(TARGET_RPI),1)
LDFLAGS := -lm $(BACKEND_LDFLAGS) $(NO_PIE_DEF)
else ifeq ($(TARGET_ANDROID),1)
ifneq ($(shell uname -m | grep "i.86"),)
ARCH_APK := x86
else ifeq ($(shell uname -m),x86_64)
ARCH_APK := x86_64
else ifeq ($(shell getconf LONG_BIT),64)
ARCH_APK := arm64-v8a
else
ARCH_APK := armeabi-v7a
endif
CFLAGS += -fPIC
LDFLAGS := -L ./$(PLATFORM_DIR)/android/lib/$(ARCH_APK)/ -lm $(BACKEND_LDFLAGS) -shared
else ifeq ($(OSX_BUILD),1)
LDFLAGS := -lm $(PLATFORM_LDFLAGS) $(BACKEND_LDFLAGS) -lpthread
else ifeq ($(HOST_OS),Haiku)
LDFLAGS := $(BACKEND_LDFLAGS) $(NO_PIE_DEF)
else
LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -lm $(BACKEND_LDFLAGS) -lpthread -ldl $(NO_PIE_DEF)
ifeq ($(DISCORDRPC),1)
LDFLAGS += -Wl,-rpath .
endif
endif # End of LDFLAGS
endif
#==============================================================================#
# Miscellaneous Tools #
#==============================================================================#
WINEXT :=
ifeq ($(HOST_OS),Windows)
WINEXT := .exe
endif
# Executable tools
MIO0TOOL := $(TOOLS_DIR)/sm64tools/mio0$(WINEXT)
N64CKSUM := $(TOOLS_DIR)/sm64tools/n64cksum$(WINEXT)
N64GRAPHICS := $(TOOLS_DIR)/sm64tools/n64graphics$(WINEXT)
N64GRAPHICS_CI := $(TOOLS_DIR)/sm64tools/n64graphics_ci$(WINEXT)
TEXTCONV := $(TOOLS_DIR)/textconv$(WINEXT)
TABLEDESIGN := $(TOOLS_DIR)/tabledesign$(WINEXT)
VADPCM_ENC := $(TOOLS_DIR)/vadpcm_enc$(WINEXT)
EXTRACT_DATA_FOR_MIO := $(TOOLS_DIR)/extract_data_for_mio$(WINEXT)
SKYCONV := $(TOOLS_DIR)/skyconv$(WINEXT)
ifneq (,$(call find-command,armips))
RSPASM = armips
else
RSPASM := $(TOOLS_DIR)/armips$(WINEXT)
endif
# Python tools
ZEROTERM := $(PYTHON) $(TOOLS_DIR)/zeroterm.py
GET_GODDARD_SIZE := $(PYTHON) $(TOOLS_DIR)/getGoddardSize.py
BINPNG := $(TOOLS_DIR)/BinPNG.py
ENDIAN_BITWIDTH := $(BUILD_DIR)/endian-and-bitwidth
EMULATOR = mupen64plus
EMU_FLAGS =
LOADER = loader64
LOADER_FLAGS = -vwf
SHA1SUM = sha1sum
PRINT = printf
ifeq ($(COLOR),1)
NO_COL := \033[0m
RED := \033[0;31m
GREEN := \033[0;32m
BLUE := \033[0;34m
YELLOW := \033[0;33m
BLINK := \033[32;5m
endif
EXTRACT_DATA_FOR_MIO := $(OBJCOPY) -O binary --only-section=.data
# Common build print status function
define print
@$(PRINT) "$(GREEN)$(1) $(YELLOW)$(2)$(GREEN) -> $(BLUE)$(3)$(NO_COL)\n"
endef
#==============================================================================#
# Main Targets #
#==============================================================================#
ifeq ($(TARGET_N64),1)
ALL_FILE := $(ROM)
else ifeq ($(TARGET_ANDROID),1)
ALL_FILE := $(APK_SIGNED)
else
ALL_FILE := $(EXE)
endif
all: $(ALL_FILE)
@$(SHA1SUM) $(ALL_FILE)
@$(PRINT) "${BLINK}Build succeeded.\n$(NO_COL)"
@$(PRINT) "==== Build Details ====$(NO_COL)\n"
@$(PRINT) "${GREEN}File: $(BLUE)$(ALL_FILE)$(NO_COL)\n"
@$(PRINT) "${GREEN}Version: $(BLUE)$(VERSION)$(NO_COL)\n"
ifeq ($(TARGET_N64),1)
@$(PRINT) "${GREEN}Microcode: $(BLUE)$(GRUCODE)$(NO_COL)\n"
endif
@$(PRINT) "${GREEN}Target: $(BLUE)$(TARGET_NAME)$(NO_COL)\n"
ifeq ($(TARGET_ANDROID),1)
EXE_DEPEND := $(APK_SIGNED)
else
EXE_DEPEND := $(EXE)
endif
ifeq ($(TARGET_N3DS),1)
cia: $(CIA)
endif
# thank you apple very cool
ifeq ($(HOST_OS),Darwin)
CP := gcp
else
CP := cp
endif
ifeq ($(EXTERNAL_DATA),1)
BASEPACK_PATH := $(BUILD_DIR)/$(BASEDIR)/$(BASEPACK)
BASEPACK_LST := $(BUILD_DIR)/basepack.lst
# depend on resources as well
all: $(BASEPACK_PATH)
# phony target for building resources
res: $(BASEPACK_PATH)
# prepares the basepack.lst
$(BASEPACK_LST): $(EXE_DEPEND)
@$(PRINT) "$(GREEN)Generating external data list: $(BLUE)$@ $(NO_COL)\n"
@mkdir -p $(BUILD_DIR)/$(BASEDIR)
@echo "$(BUILD_DIR)/sound/bank_sets sound/bank_sets" > $(BASEPACK_LST)
@echo "$(BUILD_DIR)/sound/sequences.bin sound/sequences.bin" >> $(BASEPACK_LST)
@echo "$(BUILD_DIR)/sound/sound_data.ctl sound/sound_data.ctl" >> $(BASEPACK_LST)
@echo "$(BUILD_DIR)/sound/sound_data.tbl sound/sound_data.tbl" >> $(BASEPACK_LST)
ifeq ($(VERSION),sh)
@echo "$(BUILD_DIR)/sound/sequences_header sound/sequences_header" >> $(BASEPACK_LST)
@echo "$(BUILD_DIR)/sound/ctl_header sound/ctl_header" >> $(BASEPACK_LST)
@echo "$(BUILD_DIR)/sound/tbl_header sound/tbl_header" >> $(BASEPACK_LST)
endif
@$(foreach f, $(wildcard $(SKYTILE_DIR)/*), echo $(f) gfx/$(f:$(BUILD_DIR)/%=%) >> $(BASEPACK_LST);)
@find actors -name \*.png -exec echo "{} gfx/{}" >> $(BASEPACK_LST) \;
@find levels -name \*.png -exec echo "{} gfx/{}" >> $(BASEPACK_LST) \;
@find textures -name \*.png -exec echo "{} gfx/{}" >> $(BASEPACK_LST) \;
ifeq ($(PORT_MOP_OBJS),1)
@find src/extras/mop/actors -name \*.png -exec echo "{} gfx/{}" >> $(BASEPACK_LST) \;
endif
# prepares the resource ZIP with base data
$(BASEPACK_PATH): $(BASEPACK_LST)
$(call print,Zipping from list:,$<,$@)
$(V)$(PYTHON) $(TOOLS_DIR)/mkzip.py $(BASEPACK_LST) $(BASEPACK_PATH)
endif
clean:
$(RM) -r $(BUILD_DIR_BASE)
distclean: clean
$(PYTHON) ./extract_assets.py --clean
$(MAKE) -C $(TOOLS_DIR) clean
test: $(ROM)
$(EMULATOR) $(EMU_FLAGS) $<
load: $(ROM)
$(LOADER) $(LOADER_FLAGS) $<
$(BUILD_DIR)/$(RPC_LIBS):
@$(CP) -f $(RPC_LIBS) $(BUILD_DIR)
# Extra object file dependencies
ifeq ($(TARGET_N64),1)
$(BUILD_DIR)/asm/ipl3_font.o: $(IPL3_RAW_FILES)
$(BUILD_DIR)/src/boot/crash_screen.o: $(CRASH_TEXTURE_C_FILES)
$(CRASH_TEXTURE_C_FILES): TEXTURE_ENCODING := u32
RSP_DIR := $(BUILD_DIR)/rsp
$(BUILD_DIR)/lib/rsp.o: $(RSP_DIR)/rspboot.bin $(RSP_DIR)/fast3d.bin $(RSP_DIR)/audio.bin
else
$(BUILD_DIR)/src/pc/crash/crash_handler.o: $(CRASH_TEXTURE_PC_C_FILES)
endif
SOUND_FILES := $(SOUND_BIN_DIR)/sound_data.ctl $(SOUND_BIN_DIR)/sound_data.tbl $(SOUND_BIN_DIR)/sequences.bin $(SOUND_BIN_DIR)/bank_sets
SOUND_FILES_SH :=
ifeq ($(NEW_AUDIO_REV),true)
ifeq ($(EXTERNAL_DATA),1)
SOUND_FILES_SH := $(SOUND_BIN_DIR)/sequences_header $(SOUND_BIN_DIR)/ctl_header $(SOUND_BIN_DIR)/tbl_header
SOUND_FILES += $(SOUND_FILES_SH)
else
SOUND_FILES_SH := $(SOUND_BIN_DIR)/bank_sets.inc.c $(SOUND_BIN_DIR)/sequences_header.inc.c $(SOUND_BIN_DIR)/ctl_header.inc.c $(SOUND_BIN_DIR)/tbl_header.inc.c
$(BUILD_DIR)/src/audio/load_sh.o: $(SOUND_FILES_SH)
endif
endif
$(SOUND_BIN_DIR)/sound_data.o: $(SOUND_FILES)
$(BUILD_DIR)/levels/scripts.o: $(BUILD_DIR)/include/level_headers.h
ifeq ($(VERSION),eu)
TEXT_DIRS := text/de text/us text/fr
# EU encoded text inserted into individual segment 0x19 files,
# and course data also duplicated in leveldata.c
$(BUILD_DIR)/bin/eu/translation_en.o: $(BUILD_DIR)/text/us/define_text.inc.c
$(BUILD_DIR)/bin/eu/translation_de.o: $(BUILD_DIR)/text/de/define_text.inc.c
$(BUILD_DIR)/bin/eu/translation_fr.o: $(BUILD_DIR)/text/fr/define_text.inc.c
$(BUILD_DIR)/levels/menu/leveldata.o: $(BUILD_DIR)/text/us/define_courses.inc.c
$(BUILD_DIR)/levels/menu/leveldata.o: $(BUILD_DIR)/text/de/define_courses.inc.c
$(BUILD_DIR)/levels/menu/leveldata.o: $(BUILD_DIR)/text/fr/define_courses.inc.c
else
ifeq ($(VERSION),sh)
TEXT_DIRS := text/jp
$(BUILD_DIR)/bin/segment2.o: $(BUILD_DIR)/text/jp/define_text.inc.c
else
TEXT_DIRS := text/$(VERSION)
# non-EU encoded text inserted into segment 0x02
$(BUILD_DIR)/bin/segment2.o: $(BUILD_DIR)/text/$(VERSION)/define_text.inc.c
endif
endif
$(BUILD_DIR)/bin/segment2.o: $(BUILD_DIR)/text/debug_text.raw.inc.c
# N64 specific optimization files
ifeq ($(TARGET_N64),1)
$(BUILD_DIR)/actors/%.o: OPT_FLAGS := -Ofast -mlong-calls
$(BUILD_DIR)/levels/%.o: OPT_FLAGS := -Ofast -mlong-calls
$(BUILD_DIR)/src/audio/heap.o: OPT_FLAGS := -Os -fno-jump-tables
$(BUILD_DIR)/src/audio/synthesis.o: OPT_FLAGS := -Os -fno-jump-tables
$(BUILD_DIR)/lib/ultra/%.o: OPT_FLAGS := -O2
$(BUILD_DIR)/lib/gcc/%.o: OPT_FLAGS := -O2
ifeq ($(COMPILER_TYPE),gcc)
$(BUILD_DIR)/src/engine/surface_collision.o: OPT_FLAGS += --param case-values-threshold=20 --param max-completely-peeled-insns=100 --param max-unrolled-insns=100 -finline-limit=0 -fno-inline -freorder-blocks-algorithm=simple -falign-functions=32
# Setting any sort of -finline-limit has shown to worsen performance with math_util.c,
# lower values were the worst, the higher you go - the closer performance gets to not setting it at all
$(BUILD_DIR)/src/engine/math_util.o: OPT_FLAGS +=-fno-unroll-loops -fno-peel-loops --param case-values-threshold=20 -falign-functions=32
$(BUILD_DIR)/src/game/rendering_graph_node.o: OPT_FLAGS += --param case-values-threshold=20 --param max-completely-peeled-insns=100 --param max-unrolled-insns=100 -finline-limit=0 -freorder-blocks-algorithm=simple -falign-functions=32
endif
endif
ALL_DIRS := $(BUILD_DIR) $(addprefix $(BUILD_DIR)/,$(SRC_DIRS) $(BOOT_DIR) $(GODDARD_SRC_DIRS) $(ULTRA_SRC_DIRS) $(ULTRA_BIN_DIRS) $(BIN_DIRS) $(TEXTURE_DIRS) $(TEXT_DIRS) $(SOUND_SAMPLE_DIRS) $(addprefix levels/,$(LEVEL_DIRS)) include) $(MIO0_DIR) $(addprefix $(MIO0_DIR)/,$(VERSION)) $(SOUND_BIN_DIR) $(SOUND_BIN_DIR)/sequences/$(VERSION)
ifeq ($(TARGET_N64),1)
ALL_DIRS += $(RSP_DIR) $(BUILD_DIR)/$(LIBGCC_SRC_DIRS)
endif
ifeq ($(EXTERNAL_DATA),1)
ALL_DIRS += $(SKYTILE_DIR)
endif
ifeq ($(TARGET_N3DS),1)
# create build dir for .t3x etc
ALL_DIRS += $(BUILD_DIR)/$(MINIMAP_TEXTURES) $(BUILD_DIR)/$(PLATFORM_DIR)
endif
# Make sure build directory exists before compiling anything
DUMMY != mkdir -p $(ALL_DIRS)
$(BUILD_DIR)/include/text_strings.h: $(BUILD_DIR)/include/text_menu_strings.h
ifeq ($(EXT_OPTIONS_MENU),1)
$(BUILD_DIR)/include/text_strings.h: $(BUILD_DIR)/include/text_options_strings.h
endif
ifeq ($(CHEATS_ACTIONS),1)
$(BUILD_DIR)/include/text_strings.h: $(BUILD_DIR)/include/text_cheats_strings.h
endif
ifeq ($(EXT_DEBUG_MENU),1)
$(BUILD_DIR)/include/text_strings.h: $(BUILD_DIR)/include/text_debug_strings.h
endif
ifeq ($(VERSION),eu)
LANG_O_FILES := $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
else
LANG_O_FILES :=
endif
$(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h $(LANG_O_FILES)
$(BUILD_DIR)/src/menu/star_select.o: $(BUILD_DIR)/include/text_strings.h $(LANG_O_FILES)
$(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h $(LANG_O_FILES)
ifeq ($(TARGET_N64),1)
$(BUILD_DIR)/src/boot/ext_mem_screen.o: $(BUILD_DIR)/include/text_strings.h
endif
ifeq ($(EXT_OPTIONS_MENU),1)
ifeq ($(BETTERCAMERA),1)
$(BUILD_DIR)/src/extras/bettercamera.o: $(BUILD_DIR)/include/text_strings.h $(LANG_O_FILES)
endif
ifeq ($(CHEATS_ACTIONS),1)
$(BUILD_DIR)/src/extras/cheats.o: $(BUILD_DIR)/include/text_strings.h $(LANG_O_FILES)
endif
ifeq ($(EXT_DEBUG_MENU),1)
$(BUILD_DIR)/src/extras/debug_menu.o: $(BUILD_DIR)/include/text_strings.h $(LANG_O_FILES)
endif
$(BUILD_DIR)/src/extras/options_menu.o: $(BUILD_DIR)/include/text_strings.h $(LANG_O_FILES)
endif
ifeq ($(TARGET_PORT_CONSOLE),0)
ifeq ($(DISCORDRPC),1)
$(BUILD_DIR)/src/pc/discord/discordrpc.o: $(BUILD_DIR)/include/text_strings.h $(LANG_O_FILES)
endif
endif
#==============================================================================#
# Texture Generation #
#==============================================================================#
TEXTURE_ENCODING := u8
# Convert PNGs to RGBA32, RGBA16, IA16, IA8, IA4, IA1, I8, I4 binary files
ifeq ($(EXTERNAL_DATA),1)
$(BUILD_DIR)/%: %.png
$(call print,Converting:,$<,$@)
$(V)$(ZEROTERM) "$(patsubst %.png,%,$^)" > $@
$(BUILD_DIR)/%.inc.c: $(BUILD_DIR)/% %.png
$(call print,Converting:,$<,$@)
$(V)hexdump -v -e '1/1 "0x%X,"' $< > $@
else
$(BUILD_DIR)/%: %.png
$(call print,Converting:,$<,$@)
$(V)$(N64GRAPHICS) -s raw -i $@ -g $< -f $(lastword $(subst ., ,$@))
$(BUILD_DIR)/%.inc.c: %.png
$(call print,Converting:,$<,$@)
$(V)$(N64GRAPHICS) -s $(TEXTURE_ENCODING) -i $@ -g $< -f $(lastword ,$(subst ., ,$(basename $<)))
# Color Index CI8
$(BUILD_DIR)/%.ci8.inc.c: %.ci8.png
$(call print,Converting CI:,$<,$@)
$(PYTHON) $(BINPNG) $< $@ 8
# Color Index CI4
$(BUILD_DIR)/%.ci4.inc.c: %.ci4.png
$(call print,Converting CI:,$<,$@)
$(PYTHON) $(BINPNG) $< $@ 4
endif
#==============================================================================#
# Compressed Segment Generation #
#==============================================================================#
ifeq ($(TARGET_N64),1)
# Link segment file to resolve external labels
# TODO: ideally this would be `-Trodata-segment=0x07000000` but that doesn't set the address
$(BUILD_DIR)/%.elf: $(BUILD_DIR)/%.o
$(call print,Linking ELF file:,$<,$@)
$(V)$(LD) -e 0 -Ttext=$(SEGMENT_ADDRESS) -Map $@.map -o $@ $<
# Override for leveldata.elf, which otherwise matches the above pattern.
# Has to be a static pattern rule for make-4.4 and above to trigger the second expansion.
.SECONDEXPANSION:
$(LEVEL_ELF_FILES): $(BUILD_DIR)/levels/%/leveldata.elf: $(BUILD_DIR)/levels/%/leveldata.o $(BUILD_DIR)/bin/$$(TEXTURE_BIN).elf
$(call print,Linking level ELF file:,$<,$@)
$(V)$(LD) -e 0 -Ttext=$(SEGMENT_ADDRESS) -Map $@.map --just-symbols=$(BUILD_DIR)/bin/$(TEXTURE_BIN).elf -o $@ $<
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf
$(call print,Extracting compressible data from:,$<,$@)
$(V)$(EXTRACT_DATA_FOR_MIO) $< $@
$(BUILD_DIR)/levels/%/leveldata.bin: $(BUILD_DIR)/levels/%/leveldata.elf
$(call print,Extracting compressible data from:,$<,$@)
$(V)$(EXTRACT_DATA_FOR_MIO) $< $@
# Compress binary file
$(BUILD_DIR)/%.mio0: $(BUILD_DIR)/%.bin
$(call print,Compressing:,$<,$@)
$(V)$(MIO0TOOL) $< $@
# convert binary mio0 to object file
$(BUILD_DIR)/%.mio0.o: $(BUILD_DIR)/%.mio0
$(call print,Converting MIO0 to ELF:,$<,$@)
$(V)$(LD) -r -b binary $< -o $@
endif
#==============================================================================#
# Sound File Generation #
#==============================================================================#
$(BUILD_DIR)/%.table: %.aiff
$(call print,Generating ADPCM table:,$<,$@)
$(V)$(TABLEDESIGN) -s 1 $< >$@
$(BUILD_DIR)/%.aifc: $(BUILD_DIR)/%.table %.aiff
$(call print,Encoding ADPCM:,$(word 2,$^),$@)
$(V)$(VADPCM_ENC) -c $^ $@
# Endianness and bit width
$(ENDIAN_BITWIDTH): $(TOOLS_DIR)/determine-endian-bitwidth.c
@$(PRINT) "$(GREEN)Generating endian-bitwidth $(NO_COL)\n"
$(V)$(CC) -c $(CFLAGS) -o $@.dummy2 $< 2>$@.dummy1; true
$(V)grep -o 'msgbegin --endian .* --bitwidth .* msgend' $@.dummy1 > $@.dummy2
$(V)head -n1 <$@.dummy2 | cut -d' ' -f2-5 > $@
$(V)$(RM) $@.dummy1
$(V)$(RM) $@.dummy2
$(SOUND_BIN_DIR)/sound_data.ctl: sound/sound_banks/ $(SOUND_BANK_FILES) $(SOUND_SAMPLE_AIFCS) $(ENDIAN_BITWIDTH)
@$(PRINT) "$(GREEN)Generating: $(BLUE)$@ $(NO_COL)\n"
$(V)$(PYTHON) $(TOOLS_DIR)/assemble_sound.py $(BUILD_DIR)/sound/samples/ sound/sound_banks/ $(SOUND_BIN_DIR)/sound_data.ctl $(SOUND_BIN_DIR)/ctl_header $(SOUND_BIN_DIR)/sound_data.tbl $(SOUND_BIN_DIR)/tbl_header $(C_DEFINES) $$(cat $(ENDIAN_BITWIDTH))
$(SOUND_BIN_DIR)/sound_data.tbl: $(SOUND_BIN_DIR)/sound_data.ctl
@true
$(SOUND_BIN_DIR)/ctl_header: $(SOUND_BIN_DIR)/sound_data.ctl
@true
$(SOUND_BIN_DIR)/tbl_header: $(SOUND_BIN_DIR)/sound_data.ctl
@true
$(SOUND_BIN_DIR)/sequences.bin: $(SOUND_BANK_FILES) sound/sequences.json $(SOUND_SEQUENCE_DIRS) $(SOUND_SEQUENCE_FILES) $(ENDIAN_BITWIDTH)
@$(PRINT) "$(GREEN)Generating: $(BLUE)$@ $(NO_COL)\n"
$(V)$(PYTHON) $(TOOLS_DIR)/assemble_sound.py --sequences $@ $(SOUND_BIN_DIR)/sequences_header $(SOUND_BIN_DIR)/bank_sets sound/sound_banks/ sound/sequences.json $(SOUND_SEQUENCE_FILES) $(C_DEFINES) $$(cat $(ENDIAN_BITWIDTH))
$(SOUND_BIN_DIR)/bank_sets: $(SOUND_BIN_DIR)/sequences.bin
@true
$(SOUND_BIN_DIR)/sequences_header: $(SOUND_BIN_DIR)/sequences.bin
@true
$(SOUND_BIN_DIR)/%.m64: $(SOUND_BIN_DIR)/%.o
$(call print,Converting to M64:,$<,$@)
$(V)$(OBJCOPY) -j .rodata $< -O binary $@
# Assemble 00_sound_player.s using mingw64 on macOS
ifeq ($(OSX_BUILD),1)
ifeq ($(TARGET_PORT_CONSOLE),0)
ifneq ($(call find-command,i686-w64-mingw32-as),)
$(SOUND_BIN_DIR)/sequences/%.o: sound/sequences/%.s
$(call print,Assembling:,$<,$@)
$(V)$(CPP) $(CPPFLAGS) -D_LANGUAGE_ASSEMBLY $< | $(AS_MINGW) $(ASFLAGS) $(ASFLAGS_DEFSYM) -MD $(BUILD_DIR)/$*.d -o $@
else
$(warning Compiling sequence file without mingw32 assembly)
endif
endif
endif
#==============================================================================#
# Generated Source Code Files #
#==============================================================================#
# Convert binary file to a comma-separated list of byte values for inclusion in C code
$(BUILD_DIR)/%.inc.c: $(BUILD_DIR)/%
$(call print,Converting to C:,$<,$@)
$(V)hexdump -v -e '1/1 "0x%X,"' $< > $@
$(V)echo >> $@
# Generate animation data
$(BUILD_DIR)/assets/mario_anim_data.c: $(wildcard assets/anims/*.inc.c)
@$(PRINT) "$(GREEN)Generating animation data $(NO_COL)\n"
$(V)$(PYTHON) tools/mario_anims_converter.py > $@
# Generate demo input data
$(BUILD_DIR)/assets/demo_data.c: assets/demo_data.json $(wildcard assets/demos/*.bin)
@$(PRINT) "$(GREEN)Generating demo data $(NO_COL)\n"
$(V)$(PYTHON) tools/demo_data_converter.py assets/demo_data.json $(DEF_INC_CFLAGS) > $@
# Encode in-game text strings
$(BUILD_DIR)/$(CHARMAP): $(CHARMAP)
$(call print,Preprocessing charmap:,$<,$@)
$(V)$(CPP) $(CPPFLAGS) -DBUILD_DIR=$(BUILD_DIR) -MMD -MP -MT $@ -MF $@.d -o $@ $<
$(BUILD_DIR)/$(CHARMAP_DEBUG): $(CHARMAP)
$(call print,Preprocessing charmap:,$<,$@)
$(V)$(CPP) $(CPPFLAGS) -DCHARMAP_DEBUG -DBUILD_DIR=$(BUILD_DIR) -MMD -MP -MT $@ -MF $@.d -o $@ $<
$(BUILD_DIR)/include/text_strings.h: include/text_strings.h.in $(BUILD_DIR)/$(CHARMAP)
$(call print,Encoding:,$<,$@)
$(V)$(TEXTCONV) $(BUILD_DIR)/$(CHARMAP) $< $@
$(BUILD_DIR)/include/text_menu_strings.h: include/text_menu_strings.h.in
$(call print,Encoding:,$<,$@)
$(V)$(TEXTCONV) charmap_menu.txt $< $@
$(BUILD_DIR)/text/%/define_courses.inc.c: text/define_courses.inc.c text/%/courses.h
@$(PRINT) "$(GREEN)Preprocessing: $(BLUE)$@ $(NO_COL)\n"
$(V)$(CPP) $(CPPFLAGS) $< -o - -I text/$*/ | $(TEXTCONV) $(BUILD_DIR)/$(CHARMAP) - $@
$(BUILD_DIR)/text/%/define_text.inc.c: text/define_text.inc.c text/%/courses.h text/%/dialogs.h
@$(PRINT) "$(GREEN)Preprocessing: $(BLUE)$@ $(NO_COL)\n"
$(V)$(CPP) $(CPPFLAGS) $< -o - -I text/$*/ | $(TEXTCONV) $(BUILD_DIR)/$(CHARMAP) - $@
$(BUILD_DIR)/text/debug_text.raw.inc.c: text/debug_text.inc.c $(BUILD_DIR)/$(CHARMAP_DEBUG)
@$(PRINT) "$(GREEN)Preprocessing: $(BLUE)$@ $(NO_COL)\n"
$(V)$(CPP) $(CPPFLAGS) $< -o - -I text/$*/ | $(TEXTCONV) $(BUILD_DIR)/$(CHARMAP_DEBUG) - $@
ifeq ($(EXT_OPTIONS_MENU),1)
$(BUILD_DIR)/include/text_options_strings.h: include/text_options_strings.h.in
$(call print,Encoding:,$<,$@)
$(V)$(TEXTCONV) $(BUILD_DIR)/$(CHARMAP) $< $@
ifeq ($(CHEATS_ACTIONS),1)
$(BUILD_DIR)/include/text_cheats_strings.h: include/text_cheats_strings.h.in
$(call print,Encoding:,$<,$@)
$(V)$(TEXTCONV) $(BUILD_DIR)/$(CHARMAP) $< $@
endif
ifeq ($(EXT_DEBUG_MENU),1)
$(BUILD_DIR)/include/text_debug_strings.h: include/text_debug_strings.h.in
$(call print,Encoding:,$<,$@)
$(V)$(TEXTCONV) $(BUILD_DIR)/$(CHARMAP) $< $@
endif
endif
# Level headers
$(BUILD_DIR)/include/level_headers.h: levels/level_headers.h.in
$(call print,Preprocessing level headers:,$<,$@)
$(V)$(CPP) $(CPPFLAGS) -I . $< | sed -E 's|(.+)|#include "\1"|' > $@
#==============================================================================#
# Compilation Recipes #
#==============================================================================#
# Compile C code
$(BUILD_DIR)/%.o: %.c
$(call print,Compiling:,$<,$@)
$(V)$(CC) -c $(CFLAGS) -D_LANGUAGE_C=1 $(OPT_FLAGS) -MMD -MF $(BUILD_DIR)/$*.d -o $@ $<
$(BUILD_DIR)/%.o: $(BUILD_DIR)/%.c
$(call print,Compiling:,$<,$@)
$(V)$(CC) -c $(CFLAGS) -D_LANGUAGE_C=1 $(OPT_FLAGS) -MMD -MF $(BUILD_DIR)/$*.d -o $@ $<
# Compile C++ code
$(BUILD_DIR)/%.o: %.cpp
$(call print,Compiling:,$<,$@)
$(V)$(CXX) -c $(CFLAGS) -D_LANGUAGE_C_PLUS_PLUS=1 $(OPT_FLAGS) -MMD -MF $(BUILD_DIR)/$*.d -o $@ $<
# Assemble assembly code
$(BUILD_DIR)/%.o: %.s
$(call print,Assembling:,$<,$@)
ifeq ($(CPP_ASSEMBLY),1)
$(V)$(CPP) $(CPPFLAGS) -D_LANGUAGE_ASSEMBLY $< | $(AS) $(ASFLAGS) -o $@
else
$(V)$(CC) -c $(ASMFLAGS) -x assembler-with-cpp -MMD -MF $(BUILD_DIR)/$*.d -o $@ $<
endif
ifeq ($(TARGET_N64),1)
# Assemble RSP assembly code
$(BUILD_DIR)/rsp/%.bin $(BUILD_DIR)/rsp/%_data.bin: rsp/%.s
$(call print,Assembling:,$<,$@)
$(V)$(RSPASM) -sym $@.sym $(RSPASMFLAGS) -strequ CODE_FILE $(BUILD_DIR)/rsp/$*.bin -strequ DATA_FILE $(BUILD_DIR)/rsp/$*_data.bin $<
endif
ifeq ($(WINDOWS_BUILD),1)
# Compile Windows icon
$(BUILD_DIR)/%.o: %.rc
$(call print,Compiling Windows resource:,$<,$@)
$(V)$(WINDRES) -o $@ -i $<
endif
#==============================================================================#
# Executable Generation #
#==============================================================================#
ifeq ($(TARGET_N64),1)
# Link libgcc
$(BUILD_DIR)/libgcc.a: $(LIBGCC_O_FILES)
@$(PRINT) "$(GREEN)Linking libgcc: $(BLUE)$@ $(NO_COL)\n"
$(V)$(AR) rcs -o $@ $(LIBGCC_O_FILES)
LIB_GCC_FILE := $(BUILD_DIR)/libgcc.a
LIB_GCC_FLAG := -lgcc
ifeq ($(GODDARD_MFACE),1)
GODDARD_TXT_INC := $(BUILD_DIR)/goddard.txt
endif
# Run linker script through the C preprocessor
$(BUILD_DIR)/$(LD_SCRIPT): $(LD_SCRIPT) $(GODDARD_TXT_INC)
$(call print,Preprocessing linker script:,$<,$@)
$(V)$(CPP) $(CPPFLAGS) -DBUILD_DIR=$(BUILD_DIR) -MMD -MP -MT $@ -MF $@.d -o $@ $<
# Link libultra
$(BUILD_DIR)/libultra.a: $(ULTRA_O_FILES)
@$(PRINT) "$(GREEN)Linking libultra: $(BLUE)$@ $(NO_COL)\n"
$(V)$(AR) rcs -o $@ $(ULTRA_O_FILES)
ifeq ($(GODDARD_MFACE),1)
# Link libgoddard
$(BUILD_DIR)/libgoddard.a: $(GODDARD_O_FILES)
@$(PRINT) "$(GREEN)Linking libgoddard: $(BLUE)$@ $(NO_COL)\n"
$(V)$(AR) rcs -o $@ $(GODDARD_O_FILES)
LIB_GD_FILE := $(BUILD_DIR)/libgoddard.a
LIB_GD_FLAG := -lgoddard
# SS2: Goddard rules to get size
$(BUILD_DIR)/sm64_prelim.ld: $(LD_SCRIPT) $(O_FILES) $(MIO0_OBJ_FILES) $(SEG_FILES) $(BUILD_DIR)/libultra.a $(LIB_GD_FILE) $(LIB_GCC_FILE)
$(call print,Preprocessing preliminary linker script:,$<,$@)
$(V)$(CPP) $(CPPFLAGS) -DPRELIMINARY=1 -DBUILD_DIR=$(BUILD_DIR) -MMD -MP -MT $@ -MF $@.d -o $@ $<
$(BUILD_DIR)/sm64_prelim.elf: $(BUILD_DIR)/sm64_prelim.ld
@$(PRINT) "$(GREEN)Linking Preliminary ELF file: $(BLUE)$@ $(NO_COL)\n"
# Slightly edited version of LDFLAGS
$(V)$(LD) -L $(BUILD_DIR) -T $< -Map $(BUILD_DIR)/sm64_prelim.map $(SYMBOL_LINKING_FLAGS) -o $@ $(O_FILES) -lultra $(LIB_GD_FLAG) $(LIB_GCC_FLAG)
$(BUILD_DIR)/goddard.txt: $(BUILD_DIR)/sm64_prelim.elf
$(call print,Getting Goddard size...)
$(V)$(GET_GODDARD_SIZE) $(BUILD_DIR)/sm64_prelim.map $(VERSION)
LIB_GD_PRE_ELF := $(BUILD_DIR)/sm64_prelim.elf
endif # GODDARD_MFACE
# Link SM64 ELF file
$(ELF): $(LIB_GD_PRE_ELF) $(O_FILES) $(MIO0_OBJ_FILES) $(SEG_FILES) $(BUILD_DIR)/$(LD_SCRIPT) $(BUILD_DIR)/libultra.a $(LIB_GD_FILE) $(LIB_GCC_FILE)
@$(PRINT) "$(GREEN)Linking ELF file: $(BLUE)$@ $(NO_COL)\n"
$(V)$(LD) -L $(BUILD_DIR) $(LDFLAGS) $(GODDARD_TXT_INC) -o $@ $(O_FILES) -lultra $(LIB_GD_FLAG) $(LIB_GCC_FLAG)
# Build ROM
$(ROM): $(ELF)
$(V)$(OBJCOPY) $(OBJCOPYFLAGS) $< $(@:.z64=.bin) -O binary
$(V)$(N64CKSUM) $(@:.z64=.bin) $@
$(BUILD_DIR)/$(TARGET).objdump: $(ELF)
$(OBJDUMP) -D $< > $@
else ifeq ($(TARGET_WII_U),1)
$(ELF): $(O_FILES) $(MIO0_FILES:.mio0=.o) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(BUILD_DIR)/$(RPC_LIBS)
@$(PRINT) "$(GREEN)Linking ELF file: $(BLUE)$@ $(NO_COL)\n"
$(V)$(LD) -L $(BUILD_DIR) -o $@ $(O_FILES) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(LDFLAGS)
$(EXE): $(ELF)
$(V)cp $< $*.strip.elf
$(V)$(STRIP) -g $*.strip.elf $(ERROR_FILTER)
$(V)elf2rpl $*.strip.elf $@ $(ERROR_FILTER)
$(V)rm $*.strip.elf
else ifeq ($(TARGET_N3DS),1)
# Builds the vertex shader
$(BUILD_DIR)/src/pc/gfx/shader.shbin.o : src/pc/gfx/shader.v.pica
$(eval CURBIN := $<.shbin)
$(call print,Compiling 3DS Shader:,$<,$@)
$(V)$(DEVKITPRO)/tools/bin/picasso -o $(BUILD_DIR)/src/pc/gfx/shader.shbin $<
$(V)$(DEVKITPRO)/tools/bin/bin2s $(BUILD_DIR)/src/pc/gfx/shader.shbin | $(AS) -o $@
$(ELF): $(O_FILES) $(MIO0_FILES:.mio0=.o) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(BUILD_DIR)/src/pc/gfx/shader.shbin.o $(SMDH_ICON)
@$(PRINT) "$(GREEN)Linking ELF file: $(BLUE)$@ $(NO_COL)\n"
$(V)$(LD) -L $(BUILD_DIR) -o $@ $(O_FILES) $(BUILD_DIR)/src/pc/gfx/shader.shbin.o $(MINIMAP_T3X_O) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(LDFLAGS)
$(EXE): $(ELF)
$(V)3dsxtool $< $@ --smdh=$(BUILD_DIR)/$(SMDH_ICON)
$(CIA): $(ELF)
@echo "Generating $@, please wait..."
$(V)makerom -f cia -o "$@" -rsf $(PLATFORM_DIR)/template.rsf -target t -elf "$<" -icon $(PLATFORM_DIR)/icon.icn -banner $(PLATFORM_DIR)/banner.bnr
%.smdh: %.png
$(V)smdhtool --create "$(SMDH_TITLE)" "$(SMDH_DESCRIPTION)" "$(SMDH_AUTHOR)" $< $(BUILD_DIR)/$@
# Builds converted 3DS textures
# from /opt/devkitpro/devkitARM/base_tools
define bin2o
bin2s -a 4 -H $(BUILD_DIR)/$(MINIMAP_TEXTURES)/`(echo $(<F) | tr . _)`.h $(BUILD_DIR)/$< | $(AS) -o $(BUILD_DIR)/$(MINIMAP_TEXTURES)/$(<F).o
endef
# TODO: simplify dependency chain
$(BUILD_DIR)/src/pc/gfx/gfx_citro3d.o: $(BUILD_DIR)/src/pc/gfx/gfx_3ds.o
$(BUILD_DIR)/src/pc/gfx/gfx_3ds.o: $(BUILD_DIR)/src/pc/gfx/gfx_3ds_menu.o
$(BUILD_DIR)/src/pc/gfx/gfx_3ds_menu.o: $(MINIMAP_T3X_HEADERS)
# Phase 3
%.t3x.o $(BUILD_DIR)/%_t3x.h: %.t3x
$(call print,Assembling 3DS texture:,$<,$@)
$(V)$(bin2o)
# Phase 2
%.t3x: %.t3s
$(call print,Converting 3DS texture:,$<,$@)
$(V)tex3ds -i $(BUILD_DIR)/$< -o $(BUILD_DIR)/$@
# Phase 1
%.t3s: %.png
$(call print,Preprocessing 3DS texture header:,$<,$@)
@printf -- "-f rgba -z auto\n../../../../../../$(<)\n" > $(BUILD_DIR)/$@
else ifeq ($(TARGET_SWITCH),1)
$(ELF): $(O_FILES) $(MIO0_FILES:.mio0=.o) $(ULTRA_O_FILES) $(GODDARD_O_FILES)
@$(PRINT) "$(GREEN)Linking ELF file: $(BLUE)$@ $(NO_COL)\n"
$(V)$(LD) -L $(BUILD_DIR) -o $@ $(O_FILES) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(LDFLAGS)
$(EXE): $(ELF)
$(V)cp $< $*.strip.elf
$(V)$(STRIP) -g $*.strip.elf $(ERROR_FILTER)
$(V)nacptool --create "$(NX_APP_TITLE)" "$(NX_APP_AUTHOR)" "$(NX_APP_VERSION)" $(NACP_FILE) $(NACPFLAGS)
$(V)elf2nro $*.strip.elf $@ --nacp=$(NACP_FILE) --icon=$(NX_APP_ICON) $(ERROR_FILTER)
$(V)rm $*.strip.elf
else
ifeq ($(TARGET_ANDROID),1)
APK_FILES := $(shell find $(PLATFORM_DIR)/android/ -type f)
$(APK): $(EXE) $(APK_FILES)
@$(PRINT) "$(GREEN)Packing game and libraries to an APK: $(BLUE)$@ $(NO_COL)\n"
$(V)cp -r $(PLATFORM_DIR)/android $(BUILD_DIR)/$(PLATFORM_DIR)/ && \
cp $(PREFIX)/lib/libc++_shared.so $(BUILD_DIR)/$(PLATFORM_DIR)/android/lib/$(ARCH_APK)/ && \
cp $(EXE) $(BUILD_DIR)/$(PLATFORM_DIR)/android/lib/$(ARCH_APK)/ && \
cd $(BUILD_DIR)/$(PLATFORM_DIR)/android && \
zip -q -r ../../../../../$@ ./* && \
cd ../../../../.. && \
rm -rf $(BUILD_DIR)/$(PLATFORM_DIR)/android
ifeq ($(OLD_APKSIGNER),1)
$(APK_SIGNED): $(APK)
$(call print,Signing APK:,$<,$@)
$(V)apksigner $(BUILD_DIR)/keystore $< $@
else
$(APK_SIGNED): $(APK)
$(call print,Signing APK:,$<,$@)
$(V)cp $< $@
$(V)apksigner sign --cert $(PLATFORM_DIR)/certificate.pem --key $(PLATFORM_DIR)/key.pk8 $@
endif
endif
# For the crash handler on Windows and Linux
ifeq ($(TARGET_PORT_CONSOLE),0)
all: PC_EXE_MAP
PC_EXE_MAP: $(EXE)
$(V)objdump -t $(EXE) > $(BUILD_DIR)/sm64pc.map
endif
$(EXE): $(O_FILES) $(MIO0_FILES:.mio0=.o) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(BUILD_DIR)/$(RPC_LIBS)
$(V)$(LD) -L $(BUILD_DIR) -o $@ $(O_FILES) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(LDFLAGS)
endif
# Remove built-in rules, to improve performance
MAKEFLAGS += -r
# with no prerequisites, .SECONDARY causes no intermediate target to be removed
.SECONDARY:
# Disable built-in rules
.SUFFIXES:
# Phony targets
.PHONY: all clean distclean default diff test load libultra res
# General Dependencies
-include $(DEP_FILES)
# Debug variable print target
print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true