Merge pull request #599 from Henny022p/makefile

New Makefile
This commit is contained in:
notyourav 2023-04-25 11:20:17 -07:00 committed by GitHub
commit a9910e74cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 288 additions and 326 deletions

163
GBA.mk Normal file
View File

@ -0,0 +1,163 @@
.PHONY: default
default:
@echo do not use this directly
include Toolchain.mk
GAME_VERSION ?= USA
BUILD_DIR = build/$(GAME_VERSION)
TITLE := GBAZELDA MC
MAKER_CODE := 01
REVISION := 0
ifeq ($(GAME_VERSION), EU)
GAME_CODE := BZMP
BUILD_NAME := tmc_eu
GAME_LANGUAGE := ENGLISH
TRANSLATIONS := translations/English.bin translations/French.bin translations/German.bin translations/Spanish.bin translations/Italian.bin
else ifeq ($(GAME_VERSION), JP)
GAME_CODE := BZMJ
BUILD_NAME := tmc_jp
GAME_LANGUAGE := JAPANESE
TRANSLATIONS :=
else ifeq ($(GAME_VERSION), USA)
GAME_CODE := BZME
BUILD_NAME := tmc
GAME_LANGUAGE := ENGLISH
TRANSLATIONS := translations/USA.bin
else ifeq ($(GAME_VERSION), DEMO_USA)
GAME_CODE := BZHE
BUILD_NAME := tmc_demo_usa
GAME_LANGUAGE := ENGLISH
TRANSLATIONS := translations/USA.bin
else ifeq ($(GAME_VERSION), DEMO_JP)
GAME_CODE := BZMJ
BUILD_NAME := tmc_demo_jp
GAME_LANGUAGE := JAPANESE
TRANSLATIONS :=
else
$(error unknown version $(GAME_VERSION))
endif
ROM = $(BUILD_NAME).gba
ELF = $(BUILD_NAME).elf
# Clear the default suffixes
.SUFFIXES:
# Don't delete intermediate files
.SECONDARY:
# Delete files that weren't built properly
.DELETE_ON_ERROR:
# Secondary expansion is required for dependency variables in object rules.
.SECONDEXPANSION:
# ==================
# entrypoint targets
# ==================
CUSTOM ?=
COMPARE ?= $(if $(CUSTOM),0,1)
.PHONY: build extract_assets build_assets
build: $(if $(CUSTOM), build_assets, $(BUILD_DIR)/extracted_assets_$(GAME_VERSION))
@$(MAKE) -f GBA.mk $(ROM)
ifeq ($(COMPARE), 1)
@$(SHA1) $(BUILD_NAME).sha1
endif
extract_assets: $(BUILD_DIR)/converted_assets_$(GAME_VERSION)
# TODO this is slow, especially on builds with minor/no changes
build_assets: $(BUILD_DIR)/converted_assets_$(GAME_VERSION)
$(ASSET_PROCESSOR) build $(GAME_VERSION) $(BUILD_DIR)/assets
.PHONY: clean
clean:
rm -rf build
rm -f t*.gba
rm -f t*.elf
# ===============
# build ASM files
# ===============
ASINCLUDE := -I $(BUILD_DIR)/assets -I $(BUILD_DIR)/enum_include
ASFLAGS := -mcpu=arm7tdmi --defsym $(GAME_VERSION)=1 --defsym REVISION=$(REVISION) --defsym $(GAME_LANGUAGE)=1 $(ASINCLUDE)
# TODO try solve this without the glob
ENUM_ASM_SRCS := $(wildcard include/*.h)
ENUM_ASM_HEADERS := $(patsubst include/%.h,$(BUILD_DIR)/enum_include/%.inc,$(ENUM_ASM_SRCS))
# if this is too broad dependency scanning will clash with C file
$(BUILD_DIR)/asm/%.o: deps = $(shell $(SCANINC) -I . $(ASINCLUDE) $*.s)
$(BUILD_DIR)/data/%.o: deps = $(shell $(SCANINC) -I . $(ASINCLUDE) $*.s)
$(BUILD_DIR)/%.o: %.s $$(deps) $(ENUM_ASM_HEADERS)
@mkdir -p $(dir $@)
$(PREPROC) $(BUILD_NAME) $< -- $(ASINCLUDE) | $(AS) $(ASFLAGS) -o $@
$(BUILD_DIR)/enum_include/%.inc: include/%.h
@mkdir -p $(dir $@)
$(ENUM_PROCESSOR) $< $(CC) "-D__attribute__(x)=" "-D$(GAME_VERSION)" "-E" "-nostdinc" "-Itools/agbcc" "-Itools/agbcc/include" "-iquote include" > $@
# =============
# build C files
# =============
# agbcc includes are separate because we don't want dependency scanning on them
CINCLUDE := -I include -I $(BUILD_DIR)
CPPFLAGS := -I tools/agbcc -I tools/agbcc/include $(CINCLUDE) -nostdinc -undef -D$(GAME_VERSION) -DREVISION=$(REVISION) -D$(GAME_LANGUAGE)
CFLAGS := -O2 -Wimplicit -Wparentheses -Werror -Wno-multichar -g3
interwork := $(BUILD_DIR)/src/interrupts.o \
$(BUILD_DIR)/src/collision.o \
$(BUILD_DIR)/src/playerItem.o \
$(BUILD_DIR)/src/object.o \
$(BUILD_DIR)/src/manager.o \
$(BUILD_DIR)/src/npc.o \
$(BUILD_DIR)/src/gba/m4a.o
$(interwork): CFLAGS += -mthumb-interwork
$(BUILD_DIR)/src/eeprom.o: CFLAGS += -O1 -mthumb-interwork
# if this is too broad dependency scanning will clash with ASM file
$(BUILD_DIR)/src/%.o: deps = $(shell $(SCANINC) $(CINCLUDE) $*.c)
$(BUILD_DIR)/%.o : %.c $$(deps)
@mkdir -p $(dir $@)
$(CPP) $(CPPFLAGS) $< -o $(BUILD_DIR)/$*.i
$(CC1) $(CFLAGS) -o $(BUILD_DIR)/$*.s $(BUILD_DIR)/$*.i
@echo "\t.text\n\t.align\t2, 0 @ Don't pad with nop\n" >> $(BUILD_DIR)/$*.s
$(AS) $(ASFLAGS) -o $@ $(BUILD_DIR)/$*.s
# ==============
# build binaries
# ==============
LDFLAGS = -Map ../../$(BUILD_DIR)/$(BUILD_NAME).map
LIB := -L ../../tools/agbcc/lib -lc
$(ROM): $(ELF)
$(OBJCOPY) -O binary --gap-fill 0xFF --pad-to 0x9000000 $< $@
$(ELF): objs = $(shell grep -o -E "(\w|/)+\.o" linker.ld)
$(ELF): $(BUILD_DIR)/linker.ld $$(addprefix $(BUILD_DIR)/, $$(objs))
cd $(BUILD_DIR) && $(LD) $(LDFLAGS) -n -T linker.ld -o ../../$@ $(LIB)
$(FIX) $@ -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(REVISION) --silent
$(BUILD_DIR)/linker.ld: linker.ld
@mkdir -p $(BUILD_DIR)
$(CPP) $(CPPFLAGS) -x c linker.ld | grep -v '^#' >$(BUILD_DIR)/linker.ld
# ======
# assets
# ======
$(BUILD_DIR)/extracted_assets_%: assets/assets.json assets/gfx.json assets/map.json assets/samples.json assets/sounds.json $(TRANSLATIONS)
@mkdir -p $(dir $@)
$(ASSET_PROCESSOR) extract $(GAME_VERSION) $(BUILD_DIR)/assets
touch $@
$(BUILD_DIR)/converted_assets_%: $(BUILD_DIR)/extracted_assets_%
@mkdir -p $(dir $@)
$(ASSET_PROCESSOR) convert $(GAME_VERSION) $(BUILD_DIR)/assets
touch $@
translations/%.bin: translations/%.json
tools/bin/tmc_strings -p --source $< --dest $@

View File

@ -1,14 +1,22 @@
# Install # Install
First, you must put a The Legend of Zelda: The Minish Cap (U) ROM (with SHA1: `b4bd50e4131b027c334547b4524e2dbbd4227130`) in the root directory of the repository and name it `baserom.gba`. This repository does not include any of the games assets.
To build the game using the decomp you need an original baserom for each version you want to build.
Put them with the appropriate filename into the repository root directory.
The supported versions are:
## Building other variants | Version | Filename | SHA1 |
To build other variants, you need to place the corresponding baserom before building, e.g. `baserom_jp.gba` for JP. |-----------------------|------------------------|--------------------------------------------|
| USA (project default) | `baserom.gba` | `b4bd50e4131b027c334547b4524e2dbbd4227130` |
| EU | `baserom_eu.gba` | `cff199b36ff173fb6faf152653d1bccf87c26fb7` |
| JP | `baserom_jp.gba` | `6c5404a1effb17f481f352181d0f1c61a2765c5d` |
| USA (Demo) | `baserom_demo_usa.gba` | `63fcad218f9047b6a9edbb68c98bd0dec322d7a1` |
| JP (Demo) | `baserom_demo_jp.gba` | `9cdb56fa79bba13158b81925c1f3641251326412` |
## Prerequisites ## Prerequisites
| Linux | macOS | Windows 10 (build 18917+) | Windows 10 (1709+) | Windows 8, 8.1, and 10 (1507, 1511, 1607, 1703) | Linux | macOS | Windows 10 (build 18917+) | Windows 10 (1709+) | Windows 8, 8.1, and 10 (1507, 1511, 1607, 1703) |
| ----- | ----- | ------------------------- | ------------------ | --------------------------------------------------------- |-------|-------------------------------------------|---------------------------------------|------------------------------------|-------------------------------------------------|
| none | [Xcode Command Line Tools package][xcode] | [Windows Subsystem for Linux 2][wsl2] | [Windows Subsystem for Linux][wsl] | [Cygwin][cygwin] | none | [Xcode Command Line Tools package][xcode] | [Windows Subsystem for Linux 2][wsl2] | [Windows Subsystem for Linux][wsl] | [Cygwin][cygwin] |
[xcode]: https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-DOWNLOADING_COMMAND_LINE_TOOLS_IS_NOT_AVAILABLE_IN_XCODE_FOR_MACOS_10_9__HOW_CAN_I_INSTALL_THEM_ON_MY_MACHINE_ [xcode]: https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-DOWNLOADING_COMMAND_LINE_TOOLS_IS_NOT_AVAILABLE_IN_XCODE_FOR_MACOS_10_9__HOW_CAN_I_INSTALL_THEM_ON_MY_MACHINE_
[wsl2]: https://docs.microsoft.com/windows/wsl/wsl2-install [wsl2]: https://docs.microsoft.com/windows/wsl/wsl2-install
@ -17,53 +25,59 @@ To build other variants, you need to place the corresponding baserom before buil
The [prerelease version of the Linux subsystem](https://docs.microsoft.com/windows/wsl/install-legacy) available in the 1607 and 1703 releases of Windows 10 is obsolete so consider uninstalling it. The [prerelease version of the Linux subsystem](https://docs.microsoft.com/windows/wsl/install-legacy) available in the 1607 and 1703 releases of Windows 10 is obsolete so consider uninstalling it.
Make sure that the `build-essential`, `git`, `python3`, `python3-pip`, `cmake` and `libpng-dev` packages are installed. The `build-essential` package includes the `make`, `gcc-core`, and `g++` packages so they do not have to be obtained separately. Make sure that the `build-essential`, `git`, `python3`, `python3-pip`, `cmake` and `libpng-dev` packages are installed. The `build-essential` package includes the `make`, `gcc-core`, and `g++` packages, so they do not have to be obtained separately.
In the case of Cygwin, [include](https://cygwin.com/cygwin-ug-net/setup-net.html#setup-packages) the `make`, `git`, `gcc-core`, `gcc-g++`, and `libpng-devel` packages. In the case of Cygwin, [include](https://cygwin.com/cygwin-ug-net/setup-net.html#setup-packages) the `make`, `git`, `gcc-core`, `gcc-g++`, and `libpng-devel` packages.
Install the **devkitARM** toolchain of [devkitPro](https://devkitpro.org/wiki/Getting_Started) and add its environment variables. For Windows versions without the Linux subsystem, the devkitPro [graphical installer](https://github.com/devkitPro/installer/releases) includes a preconfigured MSYS2 environment, thus the steps below are not required. To build the games code, the `arm-none-eabi-gcc` compiler is required.
Both a standalone installation and [devkitPro](https://devkitpro.org/wiki/Getting_Started) are supported.
For devkitPro, install the `gba-dev` package.
sudo (dkp-)pacman -S gba-dev If `arm-none-eabi-gcc` is not available through `PATH` use `TOOLCHAIN_PATH=<path>` to indicate its location.
export DEVKITPRO=/opt/devkitpro This is not required for devkitPro, the `DEVKITARM` environment variable is used for auto-detection.
echo "export DEVKITPRO=$DEVKITPRO" >> ~/.bashrc
export DEVKITARM=$DEVKITPRO/devkitARM
echo "export DEVKITARM=$DEVKITARM" >> ~/.bashrc
Install the pycparser python package: Install `python3` and the `pycparser` python package:
pip3 install pycparser `pip3 install pycparser`
## Installation ## Installation
To set up the repository: To set up the repository:
```shell
git clone https://github.com/zeldaret/tmc
git clone https://github.com/pret/agbcc
git clone https://github.com/zeldaret/tmc cd ./agbcc
git clone https://github.com/pret/agbcc sh build.sh
sh install.sh ../tmc
cd ./agbcc cd ../tmc
sh build.sh make tools
sh install.sh ../tmc ```
To build `tmc.gba`:
```shell
make -j$(nproc)
```
>**Note:** If the build command is not recognized on Linux, including the Linux environment used within Windows, run `nproc` and replace `$(nproc)` with the returned value (e.g.: `make -j4`). Because `nproc` is not available on macOS, the alternative is `sysctl -n hw.ncpu`.
cd ../tmc You can configure the game version built by using the `GAME_VERSION` variable (ie. `make GAME_VERSION=EU`).
make setup Convenience targets for all 5 versions exist (`make usa eu jp demo_usa demo_jp`).
`make all` builds all 5 versions.
To build **tmc.gba**: If you modify the game you need to do a custom build.
Use `CUSTOM=1` for that (any nonempty value will enable it, so `CUSTOM=0` will NOT disable it).
There is a convenience target `make custom` that does a custom USA build.
make -j$(nproc) The `COMPARE` variable controls the SHA1 verification check.
It is enabled (`1`) for normal builds and disabled (`0`) for custom builds by default.
If only `.c` or `.s` files were changed, turn off the dependency scanning temporarily. Changes to any other files will be ignored and the build will either fail or not reflect those changes.
make -j$(nproc) NODEP=1
**Note:** If the build command is not recognized on Linux, including the Linux environment used within Windows, run `nproc` and replace `$(nproc)` with the returned value (e.g.: `make -j4`). Because `nproc` is not available on macOS, the alternative is `sysctl -n hw.ncpu`.
### Note for Mac users ### Note for Mac users
The BSD make that comes with Mac XCode can be buggy, so obtain GNU make and sed using [Homebrew](https://brew.sh): The BSD make that comes with Mac XCode can be buggy, so obtain GNU make and sed using [Homebrew](https://brew.sh):
```shell
brew install make gnu-sed brew install make gnu-sed
```
When compiling agbcc, substitute the `build.sh` line for When compiling agbcc, substitute the `build.sh` line for
```shell
gsed 's/^make/gmake/g' build.sh | sh gsed 's/^make/gmake/g' build.sh | sh
```
Finally, use `gmake` instead of `make` to compile the ROM(s). Finally, use `gmake` instead of `make` to compile the ROM(s).

4
Jenkinsfile vendored
View File

@ -12,12 +12,12 @@ pipeline {
sh 'cp /usr/local/etc/roms/tmc.demo.jp.gba baserom_demo_jp.gba' sh 'cp /usr/local/etc/roms/tmc.demo.jp.gba baserom_demo_jp.gba'
sh 'cp /usr/local/etc/roms/tmc.jp.gba baserom_jp.gba' sh 'cp /usr/local/etc/roms/tmc.jp.gba baserom_jp.gba'
sh 'cp /usr/local/etc/roms/tmc.eu.gba baserom_eu.gba' sh 'cp /usr/local/etc/roms/tmc.eu.gba baserom_eu.gba'
sh 'make -j setup' sh 'make tools'
} }
} }
stage('Build') { stage('Build') {
steps { steps {
sh 'make usa demo_usa jp demo_jp eu -j' sh 'make all -j'
} }
} }
stage('Report Progress') { stage('Report Progress') {

305
Makefile
View File

@ -1,294 +1,41 @@
include $(DEVKITARM)/base_tools .PHONY: default all
default: build
COMPARE ?= 0 all: eu jp usa demo_jp demo_usa
CPP := $(CC) -E
LD := $(DEVKITARM)/bin/arm-none-eabi-ld
GAME_VERSION ?= USA
REVISION := 0
GAME_LANGUAGE := ENGLISH
TITLE := GBAZELDA MC
MAKER_CODE := 01
ifeq ($(GAME_VERSION), USA)
GAME_CODE := BZME
BUILD_NAME := tmc
else
ifeq ($(GAME_VERSION), DEMO_USA)
GAME_CODE := BZHE
BUILD_NAME := tmc_demo_usa
else
ifeq ($(GAME_VERSION), JP)
GAME_CODE := BZMJ
BUILD_NAME := tmc_jp
GAME_LANGUAGE := JAPANESE
else
ifeq ($(GAME_VERSION), DEMO_JP)
GAME_CODE := BZMJ
BUILD_NAME := tmc_demo_jp
GAME_LANGUAGE := JAPANESE
else
ifeq ($(GAME_VERSION), EU)
GAME_CODE := BZMP
BUILD_NAME := tmc_eu
else
$(error unknown version $(GAME_VERSION))
endif
endif
endif
endif
endif
SHELL := /bin/bash -o pipefail
ROM := $(BUILD_NAME).gba
OBJ_DIR := build/$(BUILD_NAME)
ELF = $(ROM:.gba=.elf)
MAP = $(ROM:.gba=.map)
C_SUBDIR = src
DATA_C_SUBDIR = src/data
ASM_SUBDIR = asm
DATA_ASM_SUBDIR = data
SONG_SUBDIR = sound/songs
MID_SUBDIR = sound/songs/midi
ASSET_SUBDIR = assets
ENUM_INCLUDE_SUBDIR = enum_include
C_BUILDDIR = $(OBJ_DIR)/$(C_SUBDIR)
ASM_BUILDDIR = $(OBJ_DIR)/$(ASM_SUBDIR)
ASM_ENUM_INCLUDE_DIR = $(ASM_BUILDDIR)/$(ENUM_INCLUDE_SUBDIR)
DATA_ASM_BUILDDIR = $(OBJ_DIR)/$(DATA_ASM_SUBDIR)
SONG_BUILDDIR = $(OBJ_DIR)/$(SONG_SUBDIR)
MID_BUILDDIR = $(OBJ_DIR)/$(MID_SUBDIR)
ASSET_BUILDDIR = $(OBJ_DIR)/$(ASSET_SUBDIR)
PREPROC_INC_PATHS = $(ASSET_BUILDDIR) $(ASM_ENUM_INCLUDE_DIR)
ASFLAGS := -mcpu=arm7tdmi --defsym $(GAME_VERSION)=1 --defsym REVISION=$(REVISION) --defsym $(GAME_LANGUAGE)=1 -I $(ASSET_SUBDIR) -I $(ASSET_BUILDDIR) -I $(ASM_ENUM_INCLUDE_DIR)
CC1 := tools/agbcc/bin/agbcc
override CFLAGS += -O2 -Wimplicit -Wparentheses -Werror -Wno-multichar -g3
# -fhex-asm
# ifeq ($(DINFO),1)
# override CFLAGS += -g
# endif
CPPFLAGS := -I tools/agbcc -I tools/agbcc/include -iquote include -nostdinc -undef -D$(GAME_VERSION) -DREVISION=$(REVISION) -D$(GAME_LANGUAGE) -I $(OBJ_DIR)
LDFLAGS = -Map ../../$(MAP)
LIB := -L ../../tools/agbcc/lib -lc
SHA1 := $(shell { command -v sha1sum || command -v shasum; } 2>/dev/null) -c
GFX := tools/bin/gbagfx
AIF := tools/bin/aif2pcm
MID := tools/bin/mid2agb
SCANINC := tools/bin/scaninc
# TODO: use charmap?
PREPROC := tools/bin/preproc
FIX := tools/bin/gbafix
ASSET_PROCESSOR := tools/bin/asset_processor
ENUM_PROCESSOR := tools/extract_include_enum.py
ASSET_CONFIGS = assets/assets.json assets/gfx.json assets/map.json assets/samples.json assets/sounds.json
TRANSLATIONS = translations/USA.bin translations/English.bin translations/French.bin translations/German.bin translations/Spanish.bin translations/Italian.bin
# Clear the default suffixes
.SUFFIXES:
# Don't delete intermediate files
.SECONDARY:
# Delete files that weren't built properly
.DELETE_ON_ERROR:
# Secondary expansion is required for dependency variables in object rules.
.SECONDEXPANSION:
$(shell mkdir -p $(C_BUILDDIR) $(ASM_BUILDDIR) $(DATA_ASM_BUILDDIR) $(SONG_BUILDDIR) $(MID_BUILDDIR))
infoshell = $(foreach line, $(shell $1 | sed "s/ /__SPACE__/g"), $(info $(subst __SPACE__, ,$(line))))
# Build tools when building the rom
# Disable dependency scanning for clean/tidy/tools
ifeq (,$(filter-out all compare target,$(MAKECMDGOALS)))
$(call infoshell, $(MAKE) tools)
else
NODEP := 1
endif
interwork := $(C_BUILDDIR)/interrupts.o \
$(C_BUILDDIR)/collision.o \
$(C_BUILDDIR)/playerItem.o \
$(C_BUILDDIR)/object.o \
$(C_BUILDDIR)/manager.o \
$(C_BUILDDIR)/npc.o
$(interwork): CFLAGS += -mthumb-interwork
$(C_BUILDDIR)/gba/m4a.o: CFLAGS = -O2 -mthumb-interwork -Wimplicit -Wparentheses -Werror -Wno-multichar
$(C_BUILDDIR)/eeprom.o: CFLAGS = -O1 -mthumb-interwork -Wimplicit -Wparentheses -Werror -Wno-multichar
C_SRCS := $(wildcard $(C_SUBDIR)/*.c $(C_SUBDIR)/*/*.c)
C_OBJS := $(patsubst $(C_SUBDIR)/%.c,$(C_BUILDDIR)/%.o,$(C_SRCS))
ASM_SRCS := $(wildcard $(ASM_SUBDIR)/*.s $(ASM_SUBDIR)/*/*.s)
ASM_OBJS := $(patsubst $(ASM_SUBDIR)/%.s,$(ASM_BUILDDIR)/%.o,$(ASM_SRCS)) $(patsubst $(ASM_SUBDIR)/*/%.s,$(ASM_BUILDDIR)/**/%.o,$(ASM_SRCS))
DATA_ASM_SRCS := $(wildcard $(DATA_ASM_SUBDIR)/*.s $(DATA_ASM_SUBDIR)/**/*.s $(DATA_ASM_SUBDIR)/**/**/*.s)
DATA_ASM_OBJS := $(patsubst $(DATA_ASM_SUBDIR)/%.s,$(DATA_ASM_BUILDDIR)/%.o,$(DATA_ASM_SRCS))
SONG_SRCS := $(wildcard $(SONG_SUBDIR)/*.s)
SONG_OBJS := $(patsubst $(SONG_SUBDIR)/%.s,$(SONG_BUILDDIR)/%.o,$(SONG_SRCS))
MID_SRCS := $(wildcard $(MID_SUBDIR)/*.mid)
MID_OBJS := $(patsubst $(MID_SUBDIR)/%.mid,$(MID_BUILDDIR)/%.o,$(MID_SRCS))
ENUM_ASM_SRCS := $(wildcard include/*.h)
ENUM_ASM_HEADERS := $(patsubst include/%.h,$(ASM_ENUM_INCLUDE_DIR)/%.inc,$(ENUM_ASM_SRCS))
OBJS := $(C_OBJS) $(ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS)
OBJS_REL := $(patsubst $(OBJ_DIR)/%,%,$(OBJS))
SUBDIRS := $(sort $(dir $(OBJS) $(ENUM_ASM_HEADERS)))
$(shell mkdir -p $(SUBDIRS))
.PHONY: all setup clean-tools mostlyclean clean tidy tools extractassets buildassets custom
MAKEFLAGS += --no-print-directory MAKEFLAGS += --no-print-directory
AUTO_GEN_TARGETS := .PHONY: build eu jp usa demo_jp demo_usa custom
build: GAME_VERSION ?=USA
build: tools
@$(MAKE) -f GBA.mk build GAME_VERSION=$(GAME_VERSION)
# TODO do we really need this extra step just so that the assets are always extracted at first? eu: GAME_VERSION=EU
all: build/extracted_assets_$(GAME_VERSION) jp: GAME_VERSION=JP
@$(MAKE) target GAME_VERSION=$(GAME_VERSION) usa: GAME_VERSION=USA
demo_jp: GAME_VERSION=DEMO_JP
demo_usa: GAME_VERSION=DEMO_USA
eu jp usa demo_jp demo_usa: tools
@$(MAKE) GAME_VERSION=$(GAME_VERSION)
target: $(ROM) custom: tools
@$(SHA1) $(BUILD_NAME).sha1 @$(MAKE) GAME_VERSION=USA CUSTOM=1
custom: buildassets .PHONY: extract_assets
@$(MAKE) target GAME_VERSION=$(GAME_VERSION) extract_assets: tools
@$(MAKE) -f GBA.mk extract_assets
# kept for backwards compat .PHONY: tools
compare: $(ROM) tools: tools/bin
@$(SHA1) $(BUILD_NAME).sha1
setup: tools tools/bin:
# all tools are build at once
# FIXME figure out why make builds multiple times when specifying all tools here
tools: $(GFX)
$(GFX) $(AIF) $(MID) $(SCANINC) $(PREPROC) $(FIX) $(ASSET_PROCESSOR) tools/bin/agb2mid tools/bin/tmc_strings tools/bin/bin2c &:
mkdir -p tools/cmake-build mkdir -p tools/cmake-build
unset CC CXX AS LD LDFLAGS && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=tools -S tools -B tools/cmake-build cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=tools -S tools -B tools/cmake-build
cmake --build tools/cmake-build -j --target install cmake --build tools/cmake-build -j --target install
# Automatically extract binary data .PHONY: clean clean-tools
build/extracted_assets_%: $(ASSET_CONFIGS) $(TRANSLATIONS) clean:
$(ASSET_PROCESSOR) extract $(GAME_VERSION) $(ASSET_BUILDDIR) @$(MAKE) -f GBA.mk clean
touch $@
# Extract assets to human readable form
extractassets:
$(ASSET_PROCESSOR) convert $(GAME_VERSION) $(ASSET_BUILDDIR)
# Build the assets from the human readable form
buildassets:
$(ASSET_PROCESSOR) build $(GAME_VERSION) $(ASSET_BUILDDIR)
mostlyclean: tidy
rm -f sound/direct_sound_samples/*.bin
rm -f $(SONG_OBJS) $(MID_SUBDIR)/*.s
find . \( -iname '*.1bpp' -o -iname '*.4bpp' -o -iname '*.8bpp' -o -iname '*.gbapal' -o -iname '*.lz' -o -iname '*.latfont' -o -iname '*.hwjpnfont' -o -iname '*.fwjpnfont' \) -exec rm {} +
rm -f $(AUTO_GEN_TARGETS)
clean-tools: clean-tools:
rm -rf tools/bin rm -rf tools/bin
rm -rf tools/cmake-build rm -rf tools/cmake-build
clean: mostlyclean clean-tools
tidy:
rm -f tmc.gba tmc.elf tmc.map
rm -f tmc_demo_usa.gba tmc_demo_usa.elf tmc_demo_usa.map
rm -f tmc_jp.gba tmc_jp.elf tmc_jp.map
rm -f tmc_demo_jp.gba tmc_demo_jp.elf tmc_demo_jp.map
rm -f tmc_eu.gba tmc_eu.elf tmc_eu.map
rm -r build/*
%.s: ;
%.png: ;
%.pal: ;
%.aif: ;
%.1bpp: %.png ; $(GFX) $< $@
%.4bpp: %.png ; $(GFX) $< $@
%.8bpp: %.png ; $(GFX) $< $@
%.gbapal: %.pal ; $(GFX) $< $@
%.gbapal: %.png ; $(GFX) $< $@
%.lz: % ; $(GFX) $< $@
%.rl: % ; $(GFX) $< $@
cd $(@D) && ../../$(MID) $(<F)
translations/USA.bin: translations/USA.json ; tools/bin/tmc_strings -p --source $< --dest $@ --size 0x499E0
translations/English.bin: translations/English.json ; tools/bin/tmc_strings -p --source $< --dest $@ --size 0x488C0
translations/French.bin: translations/French.json ; tools/bin/tmc_strings -p --source $< --dest $@ --size 0x47A90
translations/German.bin: translations/German.json ; tools/bin/tmc_strings -p --source $< --dest $@ --size 0x42FC0
translations/Spanish.bin: translations/Spanish.json ; tools/bin/tmc_strings -p --source $< --dest $@ --size 0x41930
translations/Italian.bin: translations/Italian.json ; tools/bin/tmc_strings -p --source $< --dest $@ --size 0x438E0
ifeq ($(NODEP),1)
$(C_BUILDDIR)/%.o: c_dep :=
else
$(C_BUILDDIR)/%.o: c_dep = $(shell $(SCANINC) -I include $(C_SUBDIR)/$*.c)
endif
$(C_BUILDDIR)/%.o : $(C_SUBDIR)/%.c $$(c_dep)
@$(CPP) $(CPPFLAGS) $< -o $(C_BUILDDIR)/$*.i
$(PREPROC) $(BUILD_NAME) $(C_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(C_BUILDDIR)/$*.s
@echo -e "\t.text\n\t.align\t2, 0 @ Don't pad with nop\n" >> $(C_BUILDDIR)/$*.s
$(AS) $(ASFLAGS) -o $@ $(C_BUILDDIR)/$*.s
ifeq ($(NODEP),1)
$(ASM_BUILDDIR)/%.o: asm_dep :=
else
$(ASM_BUILDDIR)/%.o: asm_dep = $(shell $(SCANINC) -I . $(ASM_SUBDIR)/$*.s)
endif
$(ASM_BUILDDIR)/%.o: $(ASM_SUBDIR)/%.s $$(asm_dep)
$(PREPROC) $(BUILD_NAME) $< -- $(PREPROC_INC_PATHS) | $(AS) $(ASFLAGS) -o $@
$(ASM_ENUM_INCLUDE_DIR)/%.inc: include/%.h
$(ENUM_PROCESSOR) $< $(CC) "-D__attribute__(x)=" "-D$(GAME_VERSION)" "-E" "-nostdinc" "-Itools/agbcc" "-Itools/agbcc/include" "-iquote include" > $@
ifeq ($(NODEP),1)
$(DATA_ASM_BUILDDIR)/%.o: data_dep :=
else
$(DATA_ASM_BUILDDIR)/%.o: data_dep = $(shell $(SCANINC) -I . -I $(ASSET_SUBDIR) -I $(ASSET_BUILDDIR) -I $(ASM_ENUM_INCLUDE_DIR) $(DATA_ASM_SUBDIR)/$*.s)
endif
$(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s $$(data_dep) $(ENUM_ASM_HEADERS)
$(PREPROC) $(BUILD_NAME) $< charmap.txt -- $(PREPROC_INC_PATHS) | $(CPP) -I include -nostdinc -undef -Wno-unicode - | $(AS) $(ASFLAGS) -o $@
$(SONG_BUILDDIR)/%.o: $(SONG_SUBDIR)/%.s
$(AS) $(ASFLAGS) -I sound -o $@ $<
$(OBJ_DIR)/linker.ld: linker.ld
$(CPP) $(CPPFLAGS) -x c linker.ld | grep -v '^#' >$(OBJ_DIR)/linker.ld
$(ELF): $(OBJS) $(OBJ_DIR)/linker.ld
cd $(OBJ_DIR) && $(LD) $(LDFLAGS) -n -T linker.ld -o ../../$@ $(LIB)
$(FIX) $@ -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(REVISION) --silent
$(ROM): $(ELF)
$(OBJCOPY) -O binary --gap-fill 0xFF --pad-to 0x9000000 $< $@
usa: ; @$(MAKE) GAME_VERSION=USA
demo_usa: ; @$(MAKE) GAME_VERSION=DEMO_USA
jp: ; @$(MAKE) GAME_VERSION=JP
demo_jp: ; @$(MAKE) GAME_VERSION=DEMO_JP
eu: ; @$(MAKE) GAME_VERSION=EU

38
Toolchain.mk Normal file
View File

@ -0,0 +1,38 @@
# ========
# compiler
# ========
ifndef TOOLCHAIN_PATH
ifneq (,$(shell which arm-none-eabi-gcc))
TOOLCHAIN_PATH :=
else ifdef DEVKITARM
TOOLCHAIN_PATH := $(DEVKITARM)/bin/
else
$(error arm-none-eabi-gcc not found, please install (devkitPro supported))
endif
endif
# ensure trailing slash
ifneq ($(TOOLCHAIN_PATH),)
override TOOLCHAIN_PATH:=$(TOOLCHAIN_PATH)/
endif
CC := $(TOOLCHAIN_PATH)arm-none-eabi-gcc
CPP := $(CC) -E
CXX := $(TOOLCHAIN_PATH)arm-none-eabi-g++
AS := $(TOOLCHAIN_PATH)arm-none-eabi-as
LD := $(TOOLCHAIN_PATH)arm-none-eabi-ld
OBJCOPY := $(TOOLCHAIN_PATH)arm-none-eabi-objcopy
# ============
# custom tools
# ============
CC1 := tools/agbcc/bin/agbcc
SHA1 := $(shell { command -v sha1sum || command -v shasum; } 2>/dev/null) -c
SCANINC := tools/bin/scaninc
PREPROC := tools/bin/preproc
ASSET_PROCESSOR := tools/bin/asset_processor
ENUM_PROCESSOR := tools/extract_include_enum.py
FIX := tools/bin/gbafix

View File

@ -867,7 +867,7 @@ SECTIONS {
src/gba/m4a.o(.text); src/gba/m4a.o(.text);
asm/lib/libagbsyscall.o(.text); asm/lib/libagbsyscall.o(.text);
src/eeprom.o(.text); src/eeprom.o(.text);
*libc.a:memcpy.o(.text); libc.a(.text);
/* handwritten assembly in arm mode */ /* handwritten assembly in arm mode */
asm/src/intr.o(.text); asm/src/intr.o(.text);

View File

@ -29,7 +29,7 @@ AsmFile::AsmFile(std::string path) {
FILE* fp = std::fopen(path.c_str(), "rb"); FILE* fp = std::fopen(path.c_str(), "rb");
if (fp == NULL) if (fp == NULL)
fatal_error("Failed to open \"%s\" for reading.\n", path.c_str()); fatal_error("Failed to open \"{}\" for reading.\n", path.c_str());
std::fseek(fp, 0, SEEK_END); std::fseek(fp, 0, SEEK_END);
@ -40,7 +40,7 @@ AsmFile::AsmFile(std::string path) {
std::rewind(fp); std::rewind(fp);
if (std::fread(m_buffer, m_size, 1, fp) != 1) if (std::fread(m_buffer, m_size, 1, fp) != 1)
fatal_error("Failed to read \"%s\".\n", path.c_str()); fatal_error("Failed to read \"{}\".\n", path.c_str());
std::fclose(fp); std::fclose(fp);
@ -159,7 +159,7 @@ void AsmFile::SkipString() {
fatal_error(INPUT_ERROR_MESSAGE("unexpected EOF in string\n")); fatal_error(INPUT_ERROR_MESSAGE("unexpected EOF in string\n"));
if (c == '\\') { if (c == '\\') {
c = GetChar(); c = GetChar();
} }
} }
} }

View File

@ -26,7 +26,7 @@ CFile::CFile(std::string path) {
FILE* fp = std::fopen(path.c_str(), "rb"); FILE* fp = std::fopen(path.c_str(), "rb");
if (fp == NULL) if (fp == NULL)
fatal_error("Failed to open \"%s\" for reading.\n", path.c_str()); fatal_error("Failed to open \"{}\" for reading.\n", path.c_str());
std::fseek(fp, 0, SEEK_END); std::fseek(fp, 0, SEEK_END);
@ -38,7 +38,7 @@ CFile::CFile(std::string path) {
std::rewind(fp); std::rewind(fp);
if (std::fread(m_buffer, m_size, 1, fp) != 1) if (std::fread(m_buffer, m_size, 1, fp) != 1)
fatal_error("Failed to read \"%s\".\n", path.c_str()); fatal_error("Failed to read \"{}\".\n", path.c_str());
std::fclose(fp); std::fclose(fp);

View File

@ -25,7 +25,7 @@ SourceFileType GetFileType(std::string& path) {
std::size_t pos = path.find_last_of('.'); std::size_t pos = path.find_last_of('.');
if (pos == std::string::npos) if (pos == std::string::npos)
fatal_error("no file extension in path \"%s\"\n", path.c_str()); fatal_error("no file extension in path \"{}\"\n", path.c_str());
std::string extension = path.substr(pos + 1); std::string extension = path.substr(pos + 1);
@ -38,7 +38,7 @@ SourceFileType GetFileType(std::string& path) {
else if (extension == "inc") else if (extension == "inc")
return SourceFileType::Inc; return SourceFileType::Inc;
else else
fatal_error("Unrecognized extension \"%s\"\n", extension.c_str()); fatal_error("Unrecognized extension \"{}\"\n", extension.c_str());
// Unreachable // Unreachable
return SourceFileType::Cpp; return SourceFileType::Cpp;