Merge branch 'main' into actor

This commit is contained in:
Aetias
2024-06-21 11:59:50 +02:00
34 changed files with 118 additions and 156 deletions
+4 -2
View File
@@ -12,13 +12,12 @@ Contents:
1. Use one of these platforms:
- Windows (MSYS)
- Linux via WSL
- Recommended for Windows users
- Linux
2. Install the following:
- Python 3.11+ and pip
- GCC 9+
- Make
- **On Linux/WSL**: Wine
- **On Linux/WSL**: Wine/Wibo
3. Install the Python dependencies:
```shell
python -m pip install -r tools/requirements.txt
@@ -28,6 +27,9 @@ python -m pip install -r tools/requirements.txt
python tools/setup.py
```
> [!NOTE]
> For Linux users: If you plan to use Wibo instead of Wine, run make with `make WINE=<path/to/wibo> ...`.
## Build the ROM
This repository does not include any of the game's assets, and you will need an original decrypted base ROM.
+14 -8
View File
@@ -11,7 +11,7 @@ endif
ifeq ($(OS),Windows_NT)
WINE :=
else
WINE := wine
WINE ?= wine
PYTHON ?= python3.11
endif
@@ -27,11 +27,13 @@ ASSETS_TXT := assets.txt
ASM_FILES := $(shell find asm -name *.s)
CXX_FILES := $(shell find src -name *.cpp) $(shell find libs -name *.cpp)
C_FILES := $(shell find src -name *.c) $(shell find libs -name *.c)
ASM_OBJS = $(ASM_FILES:%.s=$(TARGET_DIR)/%.s.o)
ASM_INCS = $(ASM_FILES:%.s=%.inc)
CXX_OBJS = $(CXX_FILES:%.cpp=$(TARGET_DIR)/%.cpp.o)
C_OBJS = $(C_FILES:%.c=$(TARGET_DIR)/%.c.o)
C_FILES := $(shell find src -name *.c) $(shell find libs -name *.c)
ASM_OBJS = $(ASM_FILES:%.s=$(TARGET_DIR)/%.s.o)
ASM_INCS = $(ASM_FILES:%.s=%.inc)
CXX_OBJS = $(CXX_FILES:%.cpp=$(TARGET_DIR)/%.cpp.o)
C_OBJS = $(C_FILES:%.c=$(TARGET_DIR)/%.c.o)
CXX_CTXS = $(CXX_FILES:%.cpp=$(TARGET_DIR)/%.cpp.ctx)
C_CTXS = $(C_FILES:%.c=$(TARGET_DIR)/%.c.ctx)
OV_BINS := $(wildcard $(TARGET_DIR)/overlays/*.bin)
OV_LZS = $(OV_BINS:%.bin=%.lz)
@@ -124,16 +126,20 @@ $(ASM_OBJS): $(TARGET_DIR)/%.o: %
mkdir -p $(dir $@)
LM_LICENSE_FILE=$(MW_LICENSE) $(WINE) $(MW_ASM) $(ASM_FLAGS) $< -o $@
$(CXX_OBJS): $(TARGET_DIR)/%.o: %
$(CXX_OBJS): $(TARGET_DIR)/%.o: % $(TARGET_DIR)/%.ctx
mkdir -p $(dir $@)
LM_LICENSE_FILE=$(MW_LICENSE) $(WINE) $(MW_CC) $(CC_FLAGS) $(CXX_FLAGS) $< -o $@
$(TOOLS_DIR)/elf/elfkill -s $< -e $@
$(C_OBJS): $(TARGET_DIR)/%.o: %
$(C_OBJS): $(TARGET_DIR)/%.o: % $(TARGET_DIR)/%.ctx
mkdir -p $(dir $@)
LM_LICENSE_FILE=$(MW_LICENSE) $(WINE) $(MW_CC) $(CC_FLAGS) $(C_FLAGS) $< -o $@
$(TOOLS_DIR)/elf/elfkill -s $< -e $@
$(CXX_CTXS) $(C_CTXS): $(TARGET_DIR)/%.ctx: %
mkdir -p $(dir $@)
$(PYTHON) $(TOOLS_DIR)/m2ctx.py -f $@ $<
.PHONY: link
link: lcf $(ASM_OBJS) $(CXX_OBJS) $(C_OBJS)
cd $(TARGET_DIR) && LM_LICENSE_FILE=$(MW_LICENSE) $(WINE) $(MW_LD) $(LD_FLAGS) $(LCF_FILE) @$(OBJS_FILE)
+1 -1
View File
@@ -56,7 +56,7 @@ When the code is linked, all code of the same section will be written adjacent t
## Compiling code
This game was written in C++, so most of the code we decompile will be in this programming language. In C++, we typically don't
have to express which section we want the code to be written to. Instead, the compiler determines the section automatically.
Here are a few examples of how to
Here are a few examples of how to generate code for different section types.
- `.text`
- Functions and member functions (aka methods)
+46 -34
View File
@@ -20,43 +20,55 @@ again. Remember to make a pull request of any notable progress you made on the s
[non-matching functions](/CONTRIBUTING.md#non-matching-functions).
## Decompiling a source file
It can be tricky to fully decompile an assembly file into a C/C++ source file, so here's some advice to make it easier:
- C/C++ code is built before assembly code
- This means you can take one function from the top of your assembly file, decompile it, and append it to the bottom of
your C/C++ file.
- Build the ROM often
- We recommend building every time you decompile a function.
- This is because functions can sometimes match in decomp.me, but not when building.
- If your ROM doesn't match, it's easier to know which function is wrong if it's the only function added since the last
successful build.
We use the object diffing tool [`objdiff`](https://github.com/encounter/objdiff) to track differences between C++ and assembly
code.
1. [Download the latest release.](https://github.com/encounter/objdiff/releases/latest)
1. Run `python tools/objdiff.py <EUR|USA>` to generate `objdiff.json` in the project root.
1. In `objdiff`, set the project directory to the root of this project. This will load `objdiff.json`.
1. Select your source file in the left sidebar:
![List of objects in objdiff](images/objdiff_objects.png)
5. See the list of functions and data to decompile:
![List of symbols in objdiff](images/objdiff_symbols.png)
> [!NOTE]
> If a source file is missing in `objdiff`, or `objdiff` fails to build a file, first rerun `objdiff.py` to update
> `objdiff.json`. If the problem persists, feel free to ask for help.
## Decompiling a function
Say you've found a function you want to decompile. Here are the steps we recommend for decompiling it:
1. Visit [decomp.me](https://decomp.me/) and start decomping.
1. Under the platforms, select "Nintendo DS".
1. Select compiler preset "Phantom Hourglass".
1. Copy and paste the target assembly for your function, including the `func_start` and `func_end` macros, and the pool
constants. For example:
```arm
.global func_ov09_0211bf48
thumb_func_start func_ov09_0211bf48
func_ov09_0211bf48: ; 0x0211bf48
ldr r0, _0211bf50 ; =data_ov09_0211f59c
ldrb r0, [r0]
bx lr
nop
thumb_func_end func_ov09_0211bf48
_0211bf50: .word data_ov09_0211f59c
Once you've opened a source file in `objdiff`, you can choose to decompile the functions in any order. We recommend starting
with a small function if you're unfamiliar with decompilation. Here's an example:
![Function in objdiff](images/objdiff_function.png)
As a starting point, we look at the decompiler output in Ghidra. You can request access to our shared Ghidra project [in this section](#the-ghidra-project).
![Decompiler in Ghidra](images/ghidra_decomp.png)
Looking at this output, we might try writing something like this:
```cpp
ARM bool Actor::SetVelocity(Vec3p *vel) {
if (mUnk_11b) {
mVel = *vel;
mUnk_11b = false;
return true;
}
return false;
}
```
5. Run `m2ctx.py include/MyHeader.hpp -c` to generate a context and put it in your clipboard.
- If no suitable header file exists, make a new one and put any structs and types you need in there.
1. Paste the context into decomp.me, and create the scratch.
1. Decompile the function and try to get a 100% match.
- There's no ARM decompiler in decomp.me yet, but Ghidra does the job quite well. See [the Ghidra section](#the-ghidra-project)
for more info.
- If you're unable to get a 100% match, share your decomp.me scratch with other contributors and they may assist you.
- In the worst case, you can also contribute [non-matching functions](/CONTRIBUTING.md#non-matching-functions) to this
project.
Now we can go back to `objdiff` and look at the result:
![Matching function in objdiff](images/objdiff_match.png)
Success! Note that this was a simple example and that you'll sometimes get stuck on a function. In that case, try the
following:
- Decompile a different function and come back later.
- Export to [decomp.me](https://decomp.me/):
1. Press the `decomp.me` button in `objdiff`.
1. Once you're sent to `decomp.me`, go to "Options" and change the preset to "Phantom Hourglass".
1. Paste your code into the "Source code" tab.
1. Share the link with us!
- In the worst case, add the function as a [non-matching function](/CONTRIBUTING.md#non-matching-functions).
## Decompiling `.init` functions
> [!NOTE]
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

+1 -1
View File
@@ -21,7 +21,7 @@ dcd 0x1234
#### `ldconst`: Loads a literal 32-bit value
```asm
ldconst 0x1234
ldconst r0, 0x1234
bx lr
```
This code is equivalent to the above example using `dcd`.
+1
View File
@@ -140,6 +140,7 @@ struct ActorType {
/* 10 */ ActorType *next;
/* 14 */
inline ActorType() {}
ActorType(ActorTypeId id, ActorCreateFunc create, unk32 (*unk_08)());
~ActorType();
unk32 func_0203e7c8();
+1
View File
@@ -42,4 +42,5 @@ public:
void func_ov00_020aee58(s16 param1, u16 param2);
void func_ov00_020aee84();
bool func_ov00_020aeeac();
};
+1 -4
View File
@@ -1,14 +1,12 @@
#include "Actor/ActorManager.hpp"
#ifdef STUBS
void ActorManager::DeleteActor(u32 index, bool param2) {}
void ActorManager::func_ov00_020c3484(ActorRef *ref, Actor *actor, unk32 param3) {}
void ActorManager::Actor_vfunc_10(u32 param1) {}
Actor* ActorManager::FindActorById(u32 id) {}
Actor* ActorManager::GetActor(ActorRef *ref) {}
bool FilterActor::Filter(Actor *actor) {}
s32 ActorManager::FilterActors(ActorFilterBase *filter, ActorList *filteredActors) {}
s32 ActorManager::FilterActors(FilterActorBase *filter, ActorList *filteredActors) {}
void ActorManager::FindActorByType(ActorRef *ref, ActorManager *manager, ActorTypeId type) {}
void ActorManager::FindNearestActorOfType(ActorRef *ref, ActorManager *manager, ActorTypeId type, Vec3p *pos) {}
bool ActorManager::func_ov00_020c398c(u32 index) {}
@@ -20,4 +18,3 @@ void ActorManager::func_ov00_020c3ce8(unk32 param1, unk32 param2) {}
void ActorManager::Actor_vfunc_28() {}
bool ActorManager::ActorTypeIsOneOf(u32 type, ActorTypeId *types) {}
#endif
-4
View File
@@ -1,8 +1,4 @@
#include "Item/Item.hpp"
#ifdef STUBS
bool Item::func_ov00_020ad020(ItemId item) {}
bool Item::func_ov00_020ad068(ItemId item) {}
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "Map/Course.hpp"
#ifdef STUBS
void Course::GetDungeonProgress(CourseProgress *param_2) {}
void Course::func_ov00_0207ca28(s32 param_2, unk32 param_3, unk32 param_4) {}
char* Course::SetCourseName(char *src) {}
@@ -51,5 +49,3 @@ void Course::SetMapDataFlag4(unk32 param_2, unk32 param_3) {}
bool Course::GetMapDataFlag4(unk32 param_2) {}
MapData* Course::FindMapData(u32 map) {}
MapData* Course::FindCurrentMapData() {}
#endif
-4
View File
@@ -1,8 +1,6 @@
#include "Map/MapBase.hpp"
#include "Map/MapManager.hpp"
#ifdef STUBS
MapBase::~MapBase() {}
MapBase_Unk_180::~MapBase_Unk_180() {}
void MapBase::SetBounds(unk32 map, unk32 course) {}
@@ -112,5 +110,3 @@ unk32 TriggerBase::vfunc_10() {}
void MapBase::func_ov00_02080de4() {}
unk8 MapBase::func_ov00_02080de8(unk32 param_2) {}
void MapBase::func_ov00_02080edc() {}
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "Map/MapManager.hpp"
#ifdef STUBS
void MapManager::func_ov00_020820ec(unk32 *param_2) {}
void MapManager::func_ov00_020820fc(s32 param_2, unk32 param_3, unk32 param_4) {}
unk8 MapManager::func_ov00_0208210c(unk32 param_2, unk32 param_3) {}
@@ -200,5 +198,3 @@ unk8 MapManager::func_ov00_02085c60(unk32 param_2, unk32 param_3, unk32 param_4,
unk8 MapManager::func_ov00_02086044(unk32 param_2, unk32 param_3, unk32 param_4) {}
bool MapManager::func_ov00_02086284(s32 *param_2, Vec3p *param_3, Vec3p *param_4, s32 param_5, u16 param_6, Vec3p *param_7, Vec3p *param_8) {}
bool MapManager::func_ov00_02086a84(s32 *param_2, Vec3p *param_3, Vec3p *param_4, s32 param_5, s32 param_6, unk32 param_7, Vec3p *param_8, Vec3p *param_9) {}
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "Player/LinkStateBase.hpp"
#ifdef STUBS
void LinkStateBase::vfunc_00() {}
void LinkStateBase::OnStateEnter() {}
void LinkStateBase::OnStateLeave(s32 param1) {}
@@ -85,5 +83,3 @@ unk32 LinkStateBase::Get_PlayerControlData_Unk120() {}
s32 LinkStateBase::Get_PlayerLinkBase_Unk38() {}
DebugHierarchy* LinkStateBase::GetDebugHierarchy0() {}
DebugHierarchy* LinkStateBase::GetDebugHierarchy1() {}
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "Player/LinkStateDamage.hpp"
#ifdef STUBS
void LinkStateDamage::vfunc_00() {}
void LinkStateDamage::CreateDebugHierarchy() {}
void LinkStateDamage::OnStateEnter() {}
@@ -16,5 +14,3 @@ bool LinkStateDamage::vfunc_24(s32 param1) {}
bool LinkStateDamage::vfunc_20(s32 param1) {}
void LinkStateDamage::func_ov00_020acfe8(bool param1) {}
LinkStateId LinkStateDamage::GetId() {}
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "Player/LinkStateFollow.hpp"
#ifdef STUBS
void LinkStateFollow::vfunc_00() {}
LinkStateId LinkStateFollow::GetId() {}
void LinkStateFollow::MoveTowardTarget() {}
@@ -12,5 +10,3 @@ LinkStateCutscene* LinkStateFollow::GetLinkStateCutscene() {}
bool LinkStateFollow::vfunc_34(Vec3p *param1) {}
bool LinkStateFollow::func_ov00_020a9180(Vec3p *param1) {}
bool LinkStateFollow::func_ov00_020a9210(Vec3p *param1, Actor *param2) {}
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "Player/LinkStateInteract.hpp"
#ifdef STUBS
void LinkStateInteract::vfunc_00() {}
LinkStateId LinkStateInteract::GetId() {}
void LinkStateInteract::CreateDebugHierarchy() {}
@@ -30,5 +28,3 @@ void LinkStateInteract::func_ov00_020abbdc(ActorRef *ref) {}
void LinkStateInteract::func_ov00_020abc18(ActorRef *ref) {}
bool LinkStateInteract::func_ov00_020abc40() {}
bool LinkStateInteract::func_ov00_020abc78(ActorRef *ref) {}
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "Player/LinkStateItem.hpp"
#ifdef STUBS
void LinkStateItem::vfunc_00() {}
LinkStateId LinkStateItem::GetId() {}
s32 LinkStateItem::IsHammerEquipped() {}
@@ -10,5 +8,3 @@ EquipBombchu* LinkStateItem::GetEquipBombchu() {}
LinkStateMove* LinkStateItem::GetLinkStateMove() {}
bool LinkStateItem::func_ov00_020abf70() {}
bool LinkStateItem::vfunc_28() {}
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "Player/LinkStateMove.hpp"
#ifdef STUBS
void LinkStateMove::vfunc_00() {}
LinkStateId LinkStateMove::GetId() {}
void LinkStateMove::CreateDebugHierarchy() {}
@@ -10,5 +8,3 @@ void LinkStateMove::OnStateLeave(s32 param1) {}
bool LinkStateMove::vfunc_24(s32 param1) {}
bool LinkStateMove::func_ov00_020a8f2c() {}
bool LinkStateMove::func_ov00_020a8f4c() {}
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "Player/LinkStateRoll.hpp"
#ifdef STUBS
void LinkStateRoll::vfunc_00() {}
LinkStateId LinkStateRoll::GetId() {}
void LinkStateRoll::CreateDebugHierarchy() {}
@@ -12,5 +10,3 @@ bool LinkStateRoll::vfunc_24(s32 param1) {}
void LinkStateRoll::func_ov00_020aee58(s16 param1, u16 param2) {}
void LinkStateRoll::func_ov00_020aee84() {}
bool LinkStateRoll::func_ov00_020aeeac() {}
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "Player/PlayerLinkBase.hpp"
#ifdef STUBS
bool PlayerBase::vfunc_04() {}
ItemFlag PlayerBase::GetEquipId() {}
bool PlayerBase::CanMove() {}
@@ -20,5 +18,3 @@ void PlayerBase::AddHealth(s16 amount) {}
bool PlayerBase::Teleport(Vec3p *pos, s16 angle, unk32 param3, bool param4, bool param5) {}
bool PlayerBase::TeleportToEntrance(unk32 entranceId, bool param2) {}
bool PlayerBase::TeleportToLastEntrance(bool param1) {}
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "Player/PlayerControl.hpp"
#ifdef STUBS
bool PlayerControl::func_ov00_020aeeac() {}
void PlayerControl::func_ov00_020aeef8() {}
void PlayerControl::func_ov00_020aef30() {}
@@ -52,5 +50,3 @@ bool PlayerControl::IsNotTouching() {}
bool PlayerControl::IsTouchingFast() {}
bool PlayerControl::IsTappedNow() {}
bool PlayerControl::func_ov00_020b13c4() {}
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "Player/TouchControl.hpp"
#ifdef STUBS
TouchControl::TouchControl() {}
void TouchControl::IncreaseSpeed(s16 increase) {}
void TouchControl::UpdateFlags(u16 speed) {}
@@ -11,5 +9,3 @@ bool TouchControl::func_ov00_0207aeac() {}
void TouchControl::UpdateConditionally(TouchState *state, u16 speed) {}
void TouchControl::func_ov00_0207af38(u16 speed, bool param2) {}
TouchControl::~TouchControl() {}
#endif
-4
View File
@@ -1,7 +1,5 @@
#include "Player/TouchGesture.hpp"
#ifdef STUBS
TouchGesture::TouchGesture() {}
void TouchGesture::ResetTouchHistory() {}
void TouchGesture::Update(void *param1) {}
@@ -9,5 +7,3 @@ TouchGesture::~TouchGesture() {}
void TouchGestureBase::ResetTouchHistory() {}
TouchGestureBase::~TouchGestureBase() {}
#endif STUBS
-4
View File
@@ -1,7 +1,5 @@
#include "Save/AdventureFlags.hpp"
#ifdef STUBS
bool AdventureFlags::Exists() {}
void AdventureFlags::CopyTo(unk32 *flags) {}
void AdventureFlags::func_ov00_02097674() {}
@@ -50,5 +48,3 @@ bool AdventureFlags::func_ov00_0209809c() {}
bool AdventureFlags::func_ov00_020980ac() {}
void AdventureFlags::func_ov00_020980bc(s32 param1) {}
void AdventureFlags::func_ov00_020980d0() {}
#endif
-5
View File
@@ -1,8 +1,5 @@
#include "Actor/ActorRupee.hpp"
#ifdef STUBS
Resource ActorRupee::gResource;
ActorType ActorRupee::gType;
ActorRupee* ActorRupee::Create() {}
@@ -21,5 +18,3 @@ void ActorRupee::func_ov14_0213b5f4(RupeeId id, unk32 param2, Vec3p *param3, boo
void ActorRupee::func_ov14_0213b6a4(RupeeId id, void *param2) {}
bool ActorRupee::func_ov14_0213b70c(RupeeId id) {}
ActorRupee::~ActorRupee() {}
#endif
-19
View File
@@ -33,63 +33,45 @@ DTCM_OBJECTS = [
ov00 = Overlay(name='ov00', after='ARM9', objects=[
'asm/ov00/ov00_020773c0.s',
'src/00_Core/Player/TouchControl.cpp',
'asm/ov00/Player/TouchControl.s',
'asm/ov00/ov00_0207afa0.s',
'asm/ov00/Map/Course.s',
'src/00_Core/Map/Course.cpp',
'asm/ov00/Map/MapBase.s',
'src/00_Core/Map/MapBase.cpp',
'asm/ov00/ov00_0207da38.s',
'asm/ov00/Map/MapManager.s',
'src/00_Core/Map/MapManager.cpp',
'asm/ov00/ov00_02086cd0.s',
'src/00_Core/Save/AdventureFlags.cpp',
'asm/ov00/Save/AdventureFlags.s',
'asm/ov00/ov00_020980f4.s',
'src/00_Core/Player/PlayerBase.cpp',
'asm/ov00/Player/PlayerBase.s',
'src/00_Core/Player/LinkStateBase.cpp',
'asm/ov00/Player/LinkStateBase.s',
'src/00_Core/Player/LinkStateMove.cpp',
'asm/ov00/Player/LinkStateMove.s',
'src/00_Core/Player/LinkStateFollow.cpp',
'asm/ov00/Player/LinkStateFollow.s',
'src/00_Core/Player/TouchGesture.cpp',
'asm/ov00/Player/TouchGesture.s',
'asm/ov00/ov00_020a8e04.s',
'src/00_Core/Player/LinkStateInteract.cpp',
'asm/ov00/Player/LinkStateInteract.s',
'src/00_Core/Player/LinkStateItem.cpp',
'asm/ov00/Player/LinkStateItem.s',
'src/00_Core/Player/LinkStateDamage.cpp',
'asm/ov00/Player/LinkStateDamage.s',
'src/00_Core/Item/Item.cpp',
'asm/ov00/Item/Item.s',
'src/00_Core/Item/ItemManager.cpp',
'src/00_Core/Player/LinkStateRoll.cpp',
'asm/ov00/Player/LinkStateRoll.s',
'src/00_Core/Player/PlayerControl.cpp',
'asm/ov00/Player/PlayerControl.s',
'asm/ov00/ov00_020b1498.s',
# 'src/00_Core/Actor/Actor.cpp',
'asm/ov00/Actor/Actor.s',
'asm/ov00/ov00_020c3348.s',
'src/00_Core/Actor/ActorManager.cpp',
'asm/ov00/Actor/ActorManager.s',
'asm/ov00/ov00_020c3e54.s',
@@ -136,7 +118,6 @@ ov13 = Overlay(name='ov13', after=[ov04, ov05, ov06, ov07], objects=[
ov14 = Overlay(name='ov14', after=[ov08, ov09, ov10, ov13], objects=[
'asm/ov14/ov14_0211f640.s',
'src/14_Land/Actor/ActorRupee.cpp',
'asm/ov14/Actor/ActorRupee.s',
'asm/ov14/ov14_0213b778.s',
+35 -12
View File
@@ -6,6 +6,8 @@ import subprocess
import os
from pathlib import Path
import argparse
import re
import tempfile
parser = argparse.ArgumentParser(description="Generates a context for decomp.me")
parser.add_argument('file', help="Input file to preprocess")
@@ -28,19 +30,40 @@ root_dir = script_dir / ".."
def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
try:
ctx: str = subprocess.check_output([
'gcc',
'-E', '-P', '-fworking-directory', '-undef', '-dD',
*CXX_FLAGS,
args.file
], cwd=root_dir, encoding=args.encoding)
except subprocess.CalledProcessError as e:
eprint(f"Failed to preprocess '{args.file}'")
if args.verbose: eprint(e)
else: eprint("Use -v for more verbose error output")
exit(1)
# Finds all lines starting with #include followed by <...> or "..."
INCLUDE_REGEX = r'^\s*#\s*include\s*([<"][\S ]+[>"])\s*$'
# Finds all line comments and multiline comments
COMMENT_REGEX = r'\/\/.*$|\/\*(?:.|\r|\n)+?\*\/'
# Finds all lines from #ifndef NONMATCHING to #else
NONMATCH_REGEX = r'^\s*#\s*ifndef\s*NONMATCHING\s*(?:.|\r|\n)*\n\s*#\s*else\s*$'
with open(args.file, 'r') as f:
contents = f.read()
contents = re.sub(COMMENT_REGEX, '', contents, 0, re.MULTILINE)
contents = re.sub(NONMATCH_REGEX, '', contents, 0, re.MULTILINE)
includes = re.findall(INCLUDE_REGEX, contents, re.MULTILINE)
_, suffix = os.path.splitext(args.file)
with tempfile.NamedTemporaryFile(delete=True, suffix=suffix) as tmp_file:
# Write includes
for include in includes:
tmp_file.write(f'#include {include}\n'.encode())
tmp_file.flush()
# Run preprocessor
try:
ctx: str = subprocess.check_output([
'gcc',
'-E', '-P', '-fworking-directory', '-undef', '-dD',
*CXX_FLAGS,
tmp_file.name
], cwd=root_dir, encoding=args.encoding)
except subprocess.CalledProcessError as e:
eprint(f"Failed to preprocess '{args.file}'")
if args.verbose: eprint(e)
else: eprint("Use -v for more verbose error output")
exit(1)
lines = ctx.splitlines(True)
for i in reversed(range(len(lines))):
-1
View File
@@ -38,7 +38,6 @@ cc.extend([
'-i', include_dir,
'-i', libc_include_dir,
'-i', libcpp_include_dir,
'-DSTUBS',
args.file
])
+14 -5
View File
@@ -35,16 +35,16 @@ def find_asm_path(src_path: Path) -> Path | None:
return asm_path
def get_build_path(path: Path) -> Path:
def get_build_path(path: Path, extension='.o') -> Path:
region = args.region.lower()
return Path('build') / region / path.parent / (path.name + '.o')
return Path('build') / region / path.parent / (path.name + extension)
config = dict()
config["custom_make"] = "make"
config["custom_args"] = [
f"REGION={args.region}",
"-B" # Always build target
"-B",
f"REGION={args.region}"
]
config["build_target"] = True
config["watch_patterns"] = [
@@ -62,6 +62,7 @@ for (root, dirs, files) in os.walk(src_dir):
src_path = Path(f'{root}/{file}')
src_path = src_path.relative_to(src_dir)
asm_path = find_asm_path(src_path)
src_path = 'src' / src_path
if asm_path: asm_path = 'asm' / asm_path
@@ -70,9 +71,17 @@ for (root, dirs, files) in os.walk(src_dir):
obj = dict()
obj["name"] = name
if asm_path.exists(): obj["target_path"] = str(get_build_path(asm_path))
obj["base_path"] = str(get_build_path('src' / src_path))
obj["base_path"] = str(get_build_path(src_path))
obj["reverse_fn_order"] = False
scratch = dict()
scratch["platform"] = "nds_arm9"
scratch["compiler"] = "mwcc_30_131"
scratch["ctx_path"] = str(get_build_path(src_path, '.ctx'))
scratch["build_ctx"] = True
obj["scratch"] = scratch
config["objects"].append(obj)
with open(config_path, 'w') as f: