Files
ph/CONTRIBUTING.md
T
2023-12-27 13:26:42 +01:00

141 lines
5.5 KiB
Markdown

# Contribution guide
- [Project structure](#project-structure)
- [Decompiling a function](#decompiling-a-function)
- [Code style](#code-style)
- [Creating new `.c`/`.cpp` files](#creating-new-ccpp-files)
- [Non-matching functions](#non-matching-functions)
## Project structure
- `asm/`: Non-decompiled assembly code
- `ovXX/`: Code for overlay `XX`
- `*.s`: Source file in assembly
- `include/*.inc`: External symbols imported by respective source file
- `build/`: Build output
- `arm9_linker_script.lcf`: Linker command file for ARM9 program, specifies the order to put code and data into the ROM
- `arm9_objects.txt`: List of object files to pass to the linker
- `eur/`: Compiled/linked files
- `asm/`: Built assembly code
- `src/`: Built C/C++ code
- `overlays/`: Contains `.bin` and `.lz` files for each overlay
- `*.bin`: Linked code/data to compress or put in the ROM
- `*.lz`: Compressed code to put in the ROM
- `main.bin.xMAP`: Map file listing RAM addresses for all symbols
- `docs/`: Documentation about the game
- `include/`: Include files
- `ph_eur/`: Game assets, extracted from your own supplied ROM
- `assets/`: Unmodified assets
- `banner/`: Banner logo and text that shows on the DS home menu
- `arm7.bin`: Extracted ARM7 program
- `arm9_ovdata.bin`: Data about ARM9 overlays
- `src/`: Source C/C++ files
- `tools/`: Tools for this project
- `compress/`: Compresses code before it is put in the ROM
- `mwccarm/`: Compiler toolchain
- `rom/`: Extracts and builds ROMs
- `lcf.py`: Generates `arm9_linker_script.lcf`
- `patch_mwcc.py`: Patches bugs in the toolchain
- `requirements.txt`: Python libraries
- `setup.py`: Sets up the project
- `assets.txt`: The order of asset directories to put in the ROM
- `*.sha1`: SHA-1 digests of different versions of the game
## Decompiling a function
WIP
## Creating new `.c`/`.cpp` files
New source files must be added to the LCF (Linker Command File). This is done via `lcf.py`, which generates the LCF when
building.
In `lcf.py`, you will see a list of overlays near the top. Each overlay then has a list of source files ending in `.s`, `.c` or
`.cpp`. Those source files, when compiled, are appended to the ROM in the order that they appear in the list.
So, to create a new source file, you put the path to the source file in the correct overlay so that it appears in the correct
order in relation to other source files.
## Code style
The code style is not strict, but please try to mimic the existing style as much as possible.
If it's impossible to match a function while following the code style, then it's OK to not follow it. But do let us know when
this happens so we may amend the code style.
Below is an example of the code style in this project. If something is unclear, look at existing code. If the existing code is
insufficient, then you may decide the code style in that situation.
```cpp
// Space before pointer asterisk * and reference ampersand &
s32 MyClass::MyMethod(MyStruct *myStruct, s32 &anInteger) {
// Opening brace { on the same line
// Space after `if`, `while`, `for` and `switch`
if (myStruct->isCool) {
// Access member fields using `this`
// Class member fields are prefixed with "m"
this->mInteger = anInteger;
}
// No space before asterisk * in pointer casts
// Space after cast operator
this->mPointer = (u32*) &anInteger;
// Prefer pre-increment ++i
// Use s32, s16, s8, etc. instead of int, short, char
for (s32 i = 0; i < 10; ++i) {
// Use `char` instead of s8 to indicate actual characters
char ch = 'A' + i * 2;
this->mString[i] = ch;
}
// Put long conditions on new line
if (
// Add clarifying parentheses for bool operators
(this->mInteger > 10 && this->mPointer != NULL) ||
(this->mInteger < 5)
) {
// Add clarifying parentheses for bitwise operators
this->mBool = ((this->mInteger >> 5) & 1) != 0;
}
do {
// Call member functions using `this`
this->DoStuff();
// In do-while loops, `while` on same line as closing brace }
} while (this->CanDoStuff());
switch (this->mInteger) {
// Indent `case`
// If possible, put braces after `case`
case 8: {
return *this->mPointer;
// If possible, put `break` after closing brace }
} break;
}
// No parentheses around return value
return this->mInteger;
}
```
## Non-matching functions
This project supports non-matching functions, and you can build them by using `make NONMATCHING=1`.
Non-matching functions must be written as follows:
```cpp
#include "global.hpp"
NONMATCH void MyFunction() {
#ifndef NONMATCHING
#include "../asm/path/to/asm.inc"
#else
// non-matching code here
#endif
}
```
When building normally, the `NONMATCH` macro will mark `MyFunction` as an assembly function, and the `NONMATCHING` macro will
not be defined so that the `asm.inc` file will be included.
Conversely, when building in non-matching mode, `MyFunction` will be a regular C/C++ function, and the non-matching code will
be inserted instead of `asm.inc`.
When contributing non-matching functions to this project, please build in both modes and fix any build errors you may get.
Delete the `.o` file between building in each mode so that the `Makefile` runs the compiler both times.
> [!NOTE] The inline assembler does not function the same as the standalone assembler. [See differences here.](inline_assembler.md#differences-from-standalone-assembler)