Merge pull request #424 from encounter/update-dtk

Update dtk-template & add clangd support
This commit is contained in:
Liam Coleman 2024-10-23 08:16:21 -05:00 committed by GitHub
commit 023b70219d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 755 additions and 402 deletions

View file

@ -6,7 +6,7 @@ on:
jobs:
build:
container: ghcr.io/rainchus/marioparty4-build:main
container: ghcr.io/mariopartyrd/mp-gc-build:main
runs-on: ubuntu-latest
strategy:
@ -15,11 +15,10 @@ jobs:
version: [GMPE01_00]
steps:
# Checkout the repository (shallow clone)
# Checkout the repository
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
# Set Git config

40
.gitignore vendored
View file

@ -1,13 +1,35 @@
# IDE folders
.idea/
.vs/
# Caches
__pycache__
.idea
.vscode
.ninja_*
*.exe
build
build.ninja
objdiff.json
.mypy_cache
.cache/
# Original files
orig/*/*
!orig/*/.gitkeep
*.dol
*.rel
*.elf
*.o
*.map
*.MAP
# Build files
build/
.ninja_*
build.ninja
# decompctx output
ctx.*
*.ctx
# Generated configs
objdiff.json
compile_commands.json
# Miscellaneous
/*.txt
ctx.c
tools/output/*
*.exe

View file

@ -1,23 +0,0 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/include/**",
"${workspaceFolder}/build/GMPE01_00/include/**"
],
"cStandard": "c99",
"cppStandard": "c++98",
"intelliSenseMode": "linux-clang-x86",
"compilerPath": "",
"configurationProvider": "ms-vscode.makefile-tools",
"browse": {
"path": [
"${workspaceFolder}/include"
],
"limitSymbolsToIncludedHeaders": true
}
}
],
"version": 4
}

View file

@ -1,26 +0,0 @@
{
"[c]": {
"files.encoding": "utf8",
"editor.defaultFormatter": "xaver.clang-format"
},
"[cpp]": {
"files.encoding": "utf8",
"editor.defaultFormatter": "xaver.clang-format"
},
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
},
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"files.associations": {
"*.inc": "cpp"
},
"search.useIgnoreFiles": false,
"search.exclude": {
"build/*/config.json": true,
"build/**/*.MAP": true,
"build.ninja": true,
".ninja_*": true,
"objdiff.json": true
}
}

12
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,12 @@
{
"recommendations": [
"llvm-vs-code-extensions.vscode-clangd",
"ms-python.black-formatter",
"ms-python.flake8",
],
"unwantedRecommendations": [
"ms-vscode.cmake-tools",
"ms-vscode.cpptools-extension-pack",
"ms-vscode.cpptools",
]
}

33
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,33 @@
{
"[c]": {
"files.encoding": "utf8",
"editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd"
},
"[cpp]": {
"files.encoding": "utf8",
"editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd"
},
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
},
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"files.associations": {
"*.inc": "c",
".clangd": "yaml"
},
"search.useIgnoreFiles": false,
"search.exclude": {
"build/*/config.json": true,
"build/**/*.MAP": true,
"build.ninja": true,
".ninja_*": true,
"objdiff.json": true,
"progress.json": true,
"report.json": true,
"compile_commands.json": true,
},
// Disable C/C++ IntelliSense, use clangd instead
"C_Cpp.intelliSenseEngine": "disabled",
"cmake.ignoreCMakeListsMissing": true,
}

16
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,16 @@
{
// Use Ctrl+Shift+B to run build tasks.
// Or "Run Build Task" in the Command Palette.
"version": "2.0.0",
"tasks": [
{
"label": "ninja",
"type": "shell",
"command": "ninja",
"group": {
"kind": "build",
"isDefault": true
}
},
]
}

View file

@ -1,12 +1,13 @@
Mario Party 4
[![Build Status]][actions] ![Progress] ![DOL Progress] ![RELs Progress] [![Discord Badge]][discord]
[![Build Status]][actions] [![Progress]][progress site] [![DOL Progress]][progress site] [![RELs Progress]][progress site] [![Discord Badge]][discord]
=============
[Build Status]: https://github.com/Rainchus/marioparty4/actions/workflows/build.yml/badge.svg
[actions]: https://github.com/Rainchus/marioparty4/actions/workflows/build.yml
[Progress]: https://img.shields.io/endpoint?label=Code&url=https%3A%2F%2Fprogress.decomp.club%2Fdata%2Fmarioparty4%2FGMPE01_00%2Fall%2F%3Fmode%3Dshield%26measure%3Dcode
[DOL Progress]: https://img.shields.io/endpoint?label=DOL&url=https%3A%2F%2Fprogress.decomp.club%2Fdata%2Fmarioparty4%2FGMPE01_00%2Fdol%2F%3Fmode%3Dshield%26measure%3Dcode
[RELs Progress]: https://img.shields.io/endpoint?label=RELs&url=https%3A%2F%2Fprogress.decomp.club%2Fdata%2Fmarioparty4%2FGMPE01_00%2Fmodules%2F%3Fmode%3Dshield%26measure%3Dcode
[Build Status]: https://github.com/mariopartyrd/marioparty4/actions/workflows/build.yml/badge.svg
[actions]: https://github.com/mariopartyrd/marioparty4/actions/workflows/build.yml
[Progress]: https://decomp.dev/mariopartyrd/marioparty4.svg?mode=shield&measure=code&label=Code&category=all
[DOL Progress]: https://decomp.dev/mariopartyrd/marioparty4.svg?mode=shield&measure=code&label=DOL&category=dol
[RELs Progress]: https://decomp.dev/mariopartyrd/marioparty4.svg?mode=shield&measure=code&label=RELs&category=modules
[progress site]: https://decomp.dev/mariopartyrd/marioparty4
[Discord Badge]: https://img.shields.io/discord/994839212618690590?color=%237289DA&logo=discord&logoColor=%23FFFFFF
[discord]: https://discord.gg/T4faGveujK
@ -59,28 +60,29 @@ Building
- Clone the repository:
```
git clone https://github.com/Rainchus/marioparty4.git
git clone https://github.com/mariopartyrd/marioparty4.git
```
- Using [Dolphin Emulator](https://dolphin-emu.org/), extract your game to `orig/GMPE01_00`.
![](assets/dolphin-extract.png)
- To save space, the only necessary files are the following. Any others can be deleted.
- `sys/main.dol`
- `files/dll/*.rel`
- Initialize and update submodules:
```sh
git submodule update --init --recursive
```
- Copy your game's disc image to `orig/GMPE01_00`.
- Supported formats: ISO (GCM), RVZ, WIA, WBFS, CISO, NFS, GCZ, TGC
- After the initial build, the disc image can be deleted to save space.
- Configure:
```
python configure.py
```
To use a version other than `GMPE01_00` (USA), specify it with `--version`.
- Build:
```
ninja
```
Visual Studio Code
==================
If desired, use the recommended Visual Studio Code settings by renaming the `.vscode.example` directory to `.vscode`.
Diffing
=======
@ -89,5 +91,3 @@ Once the initial build succeeds, an `objdiff.json` should exist in the project r
Download the latest release from [encounter/objdiff](https://github.com/encounter/objdiff). Under project settings, set `Project directory`. The configuration should be loaded automatically.
Select an object from the left sidebar to begin diffing. Changes to the project will rebuild automatically: changes to source files, headers, `configure.py`, `splits.txt` or `symbols.txt`.
![](assets/objdiff.png)

View file

@ -1,4 +1,5 @@
object: orig/GMPE01_00/sys/main.dol
object_base: orig/GMPE01_00
object: sys/main.dol
hash: ff8d894776d37167e454ae3f0c9e644407c1e6b1
symbols: config/GMPE01_00/symbols.txt
splits: config/GMPE01_00/splits.txt
@ -7,12 +8,12 @@ mw_comment_version: 10 # GC 2.6 linker
force_active: [__register_global_object, lbl_801D40D0, _kerent]
modules:
- object: orig/GMPE01_00/files/dll/_minigameDll.rel
- object: files/dll/_minigameDll.rel
hash: 3fbbebc0440f0d91432ecd6a27ef68d5309b87b6
symbols: config/GMPE01_00/rels/_minigameDll/symbols.txt
splits: config/GMPE01_00/rels/_minigameDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/bootDll.rel
- object: files/dll/bootDll.rel
hash: bdfca4f9bce60519badca0d2d0a5b71f6d99706f
symbols: config/GMPE01_00/rels/bootDll/symbols.txt
splits: config/GMPE01_00/rels/bootDll/splits.txt
@ -21,487 +22,487 @@ modules:
- symbol: logoNintendoData
binary: logoNintendoData.bin
header: logoNintendoData.inc
- object: orig/GMPE01_00/files/dll/instDll.rel
- object: files/dll/instDll.rel
hash: f09399fee83c63abfe2adb25341152adad959a93
symbols: config/GMPE01_00/rels/instDll/symbols.txt
splits: config/GMPE01_00/rels/instDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m302Dll.rel
- object: files/dll/m302Dll.rel
hash: f1ad7b5a5198a14d34141b28c654bc1704c9dcd9
symbols: config/GMPE01_00/rels/m302Dll/symbols.txt
splits: config/GMPE01_00/rels/m302Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m303Dll.rel
- object: files/dll/m303Dll.rel
hash: f1ad7b5a5198a14d34141b28c654bc1704c9dcd9
symbols: config/GMPE01_00/rels/m303Dll/symbols.txt
splits: config/GMPE01_00/rels/m303Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m330Dll.rel
- object: files/dll/m330Dll.rel
hash: f1ad7b5a5198a14d34141b28c654bc1704c9dcd9
symbols: config/GMPE01_00/rels/m330Dll/symbols.txt
splits: config/GMPE01_00/rels/m330Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m333Dll.rel
- object: files/dll/m333Dll.rel
hash: f1ad7b5a5198a14d34141b28c654bc1704c9dcd9
symbols: config/GMPE01_00/rels/m333Dll/symbols.txt
splits: config/GMPE01_00/rels/m333Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m402Dll.rel
- object: files/dll/m402Dll.rel
hash: 136d192a1464e593cd0b767691dfa012c58730ed
symbols: config/GMPE01_00/rels/m402Dll/symbols.txt
splits: config/GMPE01_00/rels/m402Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m403Dll.rel
- object: files/dll/m403Dll.rel
hash: b834eb5f8a2749f3be52aa9023cc81403075eba9
symbols: config/GMPE01_00/rels/m403Dll/symbols.txt
splits: config/GMPE01_00/rels/m403Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m404Dll.rel
- object: files/dll/m404Dll.rel
hash: c46b7814cefa8e5dee8dfd1883e369877ac78c0c
symbols: config/GMPE01_00/rels/m404Dll/symbols.txt
splits: config/GMPE01_00/rels/m404Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m405Dll.rel
- object: files/dll/m405Dll.rel
hash: 7857e0822079d0c7bbfec756a7cf4206b754d100
symbols: config/GMPE01_00/rels/m405Dll/symbols.txt
splits: config/GMPE01_00/rels/m405Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m406Dll.rel
- object: files/dll/m406Dll.rel
hash: bea398ac8abe018dce80914e6b3d6d7578eb86bb
symbols: config/GMPE01_00/rels/m406Dll/symbols.txt
splits: config/GMPE01_00/rels/m406Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m407dll.rel
- object: files/dll/m407dll.rel
hash: 6f63338c417ab62740a40f0968c03c570b440b8a
symbols: config/GMPE01_00/rels/m407dll/symbols.txt
splits: config/GMPE01_00/rels/m407dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m408Dll.rel
- object: files/dll/m408Dll.rel
hash: 7a8ff34b4bcaff39037c9e2f717505cbc63d4230
symbols: config/GMPE01_00/rels/m408Dll/symbols.txt
splits: config/GMPE01_00/rels/m408Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m409Dll.rel
- object: files/dll/m409Dll.rel
hash: 984f031fc50121369d5b04d1ec2c54322efdf281
symbols: config/GMPE01_00/rels/m409Dll/symbols.txt
splits: config/GMPE01_00/rels/m409Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m410Dll.rel
- object: files/dll/m410Dll.rel
hash: 94e308e409038f7919177d190110ce589cc8a8e8
symbols: config/GMPE01_00/rels/m410Dll/symbols.txt
splits: config/GMPE01_00/rels/m410Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m411Dll.rel
- object: files/dll/m411Dll.rel
hash: 26ac81a3db9f3850bb43b23cdb7168dcddccaeea
symbols: config/GMPE01_00/rels/m411Dll/symbols.txt
splits: config/GMPE01_00/rels/m411Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m412Dll.rel
- object: files/dll/m412Dll.rel
hash: 3ebb173a52aaea75acb414f73264e72a2943c6f8
symbols: config/GMPE01_00/rels/m412Dll/symbols.txt
splits: config/GMPE01_00/rels/m412Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m413Dll.rel
- object: files/dll/m413Dll.rel
hash: e59d4b66b1f57637c335b4745a696e3dbcb4bbe3
symbols: config/GMPE01_00/rels/m413Dll/symbols.txt
splits: config/GMPE01_00/rels/m413Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m414Dll.rel
- object: files/dll/m414Dll.rel
hash: f7fe1aa24c7b6b8ca2bb28922696c0392dc7d029
symbols: config/GMPE01_00/rels/m414Dll/symbols.txt
splits: config/GMPE01_00/rels/m414Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m415Dll.rel
- object: files/dll/m415Dll.rel
hash: 3c697b54ebdd01971b99af8c812b4850fa181f4f
symbols: config/GMPE01_00/rels/m415Dll/symbols.txt
splits: config/GMPE01_00/rels/m415Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m416Dll.rel
- object: files/dll/m416Dll.rel
hash: d26526935455b26beb2b9eaed1bfae3f3f458c25
symbols: config/GMPE01_00/rels/m416Dll/symbols.txt
splits: config/GMPE01_00/rels/m416Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m417Dll.rel
- object: files/dll/m417Dll.rel
hash: b5c3805ec3cb023299ed09b782b92441085d0054
symbols: config/GMPE01_00/rels/m417Dll/symbols.txt
splits: config/GMPE01_00/rels/m417Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m418Dll.rel
- object: files/dll/m418Dll.rel
hash: 0d02610005c46ad4f47ff51f5e154f9b0d16a4f4
symbols: config/GMPE01_00/rels/m418Dll/symbols.txt
splits: config/GMPE01_00/rels/m418Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m419Dll.rel
- object: files/dll/m419Dll.rel
hash: bbceb138b8cc43e578179a7892801633892cb03c
symbols: config/GMPE01_00/rels/m419Dll/symbols.txt
splits: config/GMPE01_00/rels/m419Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m420dll.rel
- object: files/dll/m420dll.rel
hash: 2ef4ee163bc2aa15f87c8c89afb4f28939f088c8
symbols: config/GMPE01_00/rels/m420dll/symbols.txt
splits: config/GMPE01_00/rels/m420dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m421Dll.rel
- object: files/dll/m421Dll.rel
hash: 216a99780a3915d7096385bbcddfc979ab3a4025
symbols: config/GMPE01_00/rels/m421Dll/symbols.txt
splits: config/GMPE01_00/rels/m421Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m422Dll.rel
- object: files/dll/m422Dll.rel
hash: 9ad72ba6c3ac277e521dca2fc1372a5d31c18930
symbols: config/GMPE01_00/rels/m422Dll/symbols.txt
splits: config/GMPE01_00/rels/m422Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m423Dll.rel
- object: files/dll/m423Dll.rel
hash: 377c6a56b3faf8f991ec4fccaf1972cb41910438
symbols: config/GMPE01_00/rels/m423Dll/symbols.txt
splits: config/GMPE01_00/rels/m423Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m424Dll.rel
- object: files/dll/m424Dll.rel
hash: 5814f59970268406bd86a86d0fee5a09359ab506
symbols: config/GMPE01_00/rels/m424Dll/symbols.txt
splits: config/GMPE01_00/rels/m424Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m425Dll.rel
- object: files/dll/m425Dll.rel
hash: ecaeae453393d228f2769aab9c022820bcdb58f1
symbols: config/GMPE01_00/rels/m425Dll/symbols.txt
splits: config/GMPE01_00/rels/m425Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m426Dll.rel
- object: files/dll/m426Dll.rel
hash: c240697a57cc08d34e27e89d8d3455454799e8b1
symbols: config/GMPE01_00/rels/m426Dll/symbols.txt
splits: config/GMPE01_00/rels/m426Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m427Dll.rel
- object: files/dll/m427Dll.rel
hash: c78a0857e9c44fb33bd4fdc3e392a15b4dec0431
symbols: config/GMPE01_00/rels/m427Dll/symbols.txt
splits: config/GMPE01_00/rels/m427Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m428Dll.rel
- object: files/dll/m428Dll.rel
hash: a1d5672d8ef0aac089dda00287fd68bf2bb67807
symbols: config/GMPE01_00/rels/m428Dll/symbols.txt
splits: config/GMPE01_00/rels/m428Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m429Dll.rel
- object: files/dll/m429Dll.rel
hash: d25f198ce04aa5ca7b54ada9de52f722bd751447
symbols: config/GMPE01_00/rels/m429Dll/symbols.txt
splits: config/GMPE01_00/rels/m429Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m430Dll.rel
- object: files/dll/m430Dll.rel
hash: 8bef3e2f51db3afa82dcaf64e209067a58c04bf9
symbols: config/GMPE01_00/rels/m430Dll/symbols.txt
splits: config/GMPE01_00/rels/m430Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m431Dll.rel
- object: files/dll/m431Dll.rel
hash: 7148ec21ca6e0aa8d213a1dce0aeb9d93a9b496c
symbols: config/GMPE01_00/rels/m431Dll/symbols.txt
splits: config/GMPE01_00/rels/m431Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m432Dll.rel
- object: files/dll/m432Dll.rel
hash: 096f5a85bb837af68bd491e962eda7726d8d26a0
symbols: config/GMPE01_00/rels/m432Dll/symbols.txt
splits: config/GMPE01_00/rels/m432Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m433Dll.rel
- object: files/dll/m433Dll.rel
hash: c36f56264ab9cf74b882c2544cdb9b89f6a098cd
symbols: config/GMPE01_00/rels/m433Dll/symbols.txt
splits: config/GMPE01_00/rels/m433Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m434Dll.rel
- object: files/dll/m434Dll.rel
hash: 55912c8441002b61701fc8c769f707c69e2740c1
symbols: config/GMPE01_00/rels/m434Dll/symbols.txt
splits: config/GMPE01_00/rels/m434Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m435Dll.rel
- object: files/dll/m435Dll.rel
hash: 56f1fc330e8b97fa426fac3d901b1feed946566e
symbols: config/GMPE01_00/rels/m435Dll/symbols.txt
splits: config/GMPE01_00/rels/m435Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m436Dll.rel
- object: files/dll/m436Dll.rel
hash: e53f3d381bfb99351483e70b9d79c2e8676f73d5
symbols: config/GMPE01_00/rels/m436Dll/symbols.txt
splits: config/GMPE01_00/rels/m436Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m437Dll.rel
- object: files/dll/m437Dll.rel
hash: 404698b53acad1231e00d84d0196ddce8d9d9dd9
symbols: config/GMPE01_00/rels/m437Dll/symbols.txt
splits: config/GMPE01_00/rels/m437Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m438Dll.rel
- object: files/dll/m438Dll.rel
hash: 9bddf4b81b9a792260000abe2631da493a8b8564
symbols: config/GMPE01_00/rels/m438Dll/symbols.txt
splits: config/GMPE01_00/rels/m438Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m439Dll.rel
- object: files/dll/m439Dll.rel
hash: a2a18c9d26dedfa8e2ae003c3a2e1bdcc1cbd4cc
symbols: config/GMPE01_00/rels/m439Dll/symbols.txt
splits: config/GMPE01_00/rels/m439Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m440Dll.rel
- object: files/dll/m440Dll.rel
hash: 227ca13bcd72059bdd506e9611d9b52f661af6c5
symbols: config/GMPE01_00/rels/m440Dll/symbols.txt
splits: config/GMPE01_00/rels/m440Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m441Dll.rel
- object: files/dll/m441Dll.rel
hash: d6cbf72115374e06ffea3f15001977c288a9c3fb
symbols: config/GMPE01_00/rels/m441Dll/symbols.txt
splits: config/GMPE01_00/rels/m441Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m442Dll.rel
- object: files/dll/m442Dll.rel
hash: 347fcb836b5266dfe3d1088e1aa796c043b0fe60
symbols: config/GMPE01_00/rels/m442Dll/symbols.txt
splits: config/GMPE01_00/rels/m442Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m443Dll.rel
- object: files/dll/m443Dll.rel
hash: 77444c6739a4d9390f30ba56c5fcd82ee4efc0c2
symbols: config/GMPE01_00/rels/m443Dll/symbols.txt
splits: config/GMPE01_00/rels/m443Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m444dll.rel
- object: files/dll/m444dll.rel
hash: 76154b165cd86472ce3155028ea049ba0a0f3dcb
symbols: config/GMPE01_00/rels/m444dll/symbols.txt
splits: config/GMPE01_00/rels/m444dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m445Dll.rel
- object: files/dll/m445Dll.rel
hash: d4d9f2aad53aa7f4e1c313438a0e3767f8e58eb9
symbols: config/GMPE01_00/rels/m445Dll/symbols.txt
splits: config/GMPE01_00/rels/m445Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m446dll.rel
- object: files/dll/m446dll.rel
hash: 4b16e5eff613eaf4cc98411809cd1f1578e33fd1
symbols: config/GMPE01_00/rels/m446dll/symbols.txt
splits: config/GMPE01_00/rels/m446dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m447dll.rel
- object: files/dll/m447dll.rel
hash: 775ca8f8b3be867ad67f91bc3b6ebcc8c3068d2b
symbols: config/GMPE01_00/rels/m447dll/symbols.txt
splits: config/GMPE01_00/rels/m447dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m448Dll.rel
- object: files/dll/m448Dll.rel
hash: e6f7586dadbe3f5b5045c0bdf2fe618d42ef3a44
symbols: config/GMPE01_00/rels/m448Dll/symbols.txt
splits: config/GMPE01_00/rels/m448Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m449Dll.rel
- object: files/dll/m449Dll.rel
hash: e797c2ff132ab35e768be62cb62219592464ca9d
symbols: config/GMPE01_00/rels/m449Dll/symbols.txt
splits: config/GMPE01_00/rels/m449Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m450Dll.rel
- object: files/dll/m450Dll.rel
hash: f2ea7da07cf8be4f449c97b829d3231911e158a0
symbols: config/GMPE01_00/rels/m450Dll/symbols.txt
splits: config/GMPE01_00/rels/m450Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m451Dll.rel
- object: files/dll/m451Dll.rel
hash: 3f82fd24071582b6494a9f99750c0bc3c10d502e
symbols: config/GMPE01_00/rels/m451Dll/symbols.txt
splits: config/GMPE01_00/rels/m451Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m453Dll.rel
- object: files/dll/m453Dll.rel
hash: 49ef28c2862000fae4d8efd8fec0ff9b41f24461
symbols: config/GMPE01_00/rels/m453Dll/symbols.txt
splits: config/GMPE01_00/rels/m453Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m455Dll.rel
- object: files/dll/m455Dll.rel
hash: e0b21cfbe592955c84662ff50d8a33e147403906
symbols: config/GMPE01_00/rels/m455Dll/symbols.txt
splits: config/GMPE01_00/rels/m455Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m456Dll.rel
- object: files/dll/m456Dll.rel
hash: 97d5701b151c6ad8cf8cea6e776973daa95eea34
symbols: config/GMPE01_00/rels/m456Dll/symbols.txt
splits: config/GMPE01_00/rels/m456Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m457Dll.rel
- object: files/dll/m457Dll.rel
hash: d4a411f9ef850f52506afd1ad1de88d2d8de361b
symbols: config/GMPE01_00/rels/m457Dll/symbols.txt
splits: config/GMPE01_00/rels/m457Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m458Dll.rel
- object: files/dll/m458Dll.rel
hash: 7ac361c5a04f83d46f516a13a43e43b59b929435
symbols: config/GMPE01_00/rels/m458Dll/symbols.txt
splits: config/GMPE01_00/rels/m458Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m459dll.rel
- object: files/dll/m459dll.rel
hash: 1aafc4f38ddfee64ea8f7dda7cbd7113e86997ba
symbols: config/GMPE01_00/rels/m459dll/symbols.txt
splits: config/GMPE01_00/rels/m459dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m460Dll.rel
- object: files/dll/m460Dll.rel
hash: 5d28f1a87edee5216b9bb28d9cbff2b22d617747
symbols: config/GMPE01_00/rels/m460Dll/symbols.txt
splits: config/GMPE01_00/rels/m460Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m461Dll.rel
- object: files/dll/m461Dll.rel
hash: ab058151bd25600f05f8b6fedbec1c7448175123
symbols: config/GMPE01_00/rels/m461Dll/symbols.txt
splits: config/GMPE01_00/rels/m461Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m462Dll.rel
- object: files/dll/m462Dll.rel
hash: 78d6ab00677791ece684a0c149d1ae72efc52d1c
symbols: config/GMPE01_00/rels/m462Dll/symbols.txt
splits: config/GMPE01_00/rels/m462Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/m463Dll.rel
- object: files/dll/m463Dll.rel
hash: 32010595b4fd0b75293fc46b9026c5613d0ea4c2
symbols: config/GMPE01_00/rels/m463Dll/symbols.txt
splits: config/GMPE01_00/rels/m463Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/mentDll.rel
- object: files/dll/mentDll.rel
hash: 9e63dd96943ffd2747be5aad924b95892d46051a
symbols: config/GMPE01_00/rels/mentDll/symbols.txt
splits: config/GMPE01_00/rels/mentDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/messDll.rel
- object: files/dll/messDll.rel
hash: 7e119de456b3557dcf514c70bd7ab81dc5f9cf54
symbols: config/GMPE01_00/rels/messDll/symbols.txt
splits: config/GMPE01_00/rels/messDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/mgmodedll.rel
- object: files/dll/mgmodedll.rel
hash: 376c78e2d1b7d7a429959c532e9cb92c98f73b7e
symbols: config/GMPE01_00/rels/mgmodedll/symbols.txt
splits: config/GMPE01_00/rels/mgmodedll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/modeltestDll.rel
- object: files/dll/modeltestDll.rel
hash: 8de28c0f254a2c574c4da9b6a3a17e5ad7ffe1f9
symbols: config/GMPE01_00/rels/modeltestDll/symbols.txt
splits: config/GMPE01_00/rels/modeltestDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/modeseldll.rel
- object: files/dll/modeseldll.rel
hash: bdf8cd57fa23f07c429393817037ade04e2c6024
symbols: config/GMPE01_00/rels/modeseldll/symbols.txt
splits: config/GMPE01_00/rels/modeseldll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/mpexDll.rel
- object: files/dll/mpexDll.rel
hash: 4524e63b63510b42bca907f72e67affddec856f9
symbols: config/GMPE01_00/rels/mpexDll/symbols.txt
splits: config/GMPE01_00/rels/mpexDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/msetupDll.rel
- object: files/dll/msetupDll.rel
hash: 86ff8288bb92472376d02cade1d3c9603b613c57
symbols: config/GMPE01_00/rels/msetupDll/symbols.txt
splits: config/GMPE01_00/rels/msetupDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/mstory2Dll.rel
- object: files/dll/mstory2Dll.rel
hash: 7579ff7aa9638488d876dbb61d3e4b868974a040
symbols: config/GMPE01_00/rels/mstory2Dll/symbols.txt
splits: config/GMPE01_00/rels/mstory2Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/mstory3Dll.rel
- object: files/dll/mstory3Dll.rel
hash: 951f1951eac515fce1d3314059f27fdc7b39f035
symbols: config/GMPE01_00/rels/mstory3Dll/symbols.txt
splits: config/GMPE01_00/rels/mstory3Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/mstory4Dll.rel
- object: files/dll/mstory4Dll.rel
hash: 7f9cc4a18a137f861b2c326b099c02ba4e5bd94b
symbols: config/GMPE01_00/rels/mstory4Dll/symbols.txt
splits: config/GMPE01_00/rels/mstory4Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/mstoryDll.rel
- object: files/dll/mstoryDll.rel
hash: 979a83f2d6f5200e2de4333ec8f943701a250131
symbols: config/GMPE01_00/rels/mstoryDll/symbols.txt
splits: config/GMPE01_00/rels/mstoryDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/nisDll.rel
- object: files/dll/nisDll.rel
hash: d74a5147245a1877b140ee2af7f75b2b6c90892d
symbols: config/GMPE01_00/rels/nisDll/symbols.txt
splits: config/GMPE01_00/rels/nisDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/option.rel
- object: files/dll/option.rel
hash: 5c6973fe7e0271885a5a87d87d4e7164ef711abb
symbols: config/GMPE01_00/rels/option/symbols.txt
splits: config/GMPE01_00/rels/option/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/present.rel
- object: files/dll/present.rel
hash: ddb8d8a825578a588276b9d4f65eceee26f91253
symbols: config/GMPE01_00/rels/present/symbols.txt
splits: config/GMPE01_00/rels/present/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/resultDll.rel
- object: files/dll/resultDll.rel
hash: 41a820438884ae8566f34f895198a186aae60305
symbols: config/GMPE01_00/rels/resultDll/symbols.txt
splits: config/GMPE01_00/rels/resultDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/safDll.rel
- object: files/dll/safDll.rel
hash: f34c104078b41971412cb09b37c4dc9526be02e3
symbols: config/GMPE01_00/rels/safDll/symbols.txt
splits: config/GMPE01_00/rels/safDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/selmenuDll.rel
- object: files/dll/selmenuDll.rel
hash: 81a00a71b8d1ab22bfd3df10d815c87ba618ec84
symbols: config/GMPE01_00/rels/selmenuDll/symbols.txt
splits: config/GMPE01_00/rels/selmenuDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/staffDll.rel
- object: files/dll/staffDll.rel
hash: a6210fbcdf3d7f0063f3052e2ae525abacac08e7
symbols: config/GMPE01_00/rels/staffDll/symbols.txt
splits: config/GMPE01_00/rels/staffDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/subchrselDll.rel
- object: files/dll/subchrselDll.rel
hash: 7488bc249dc7c656f60105e4d24c4011983c2ba2
symbols: config/GMPE01_00/rels/subchrselDll/symbols.txt
splits: config/GMPE01_00/rels/subchrselDll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/w01Dll.rel
- object: files/dll/w01Dll.rel
hash: d3de36269886995d959e1fd58d8ad806843c8819
symbols: config/GMPE01_00/rels/w01Dll/symbols.txt
splits: config/GMPE01_00/rels/w01Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/w02Dll.rel
- object: files/dll/w02Dll.rel
hash: 750c4d6cd6a49d290f5cc63432d4f65642fbd7e4
symbols: config/GMPE01_00/rels/w02Dll/symbols.txt
splits: config/GMPE01_00/rels/w02Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/w03Dll.rel
- object: files/dll/w03Dll.rel
hash: f9e8d9c4581d44488adaffa3d46d9bc835d4f9bd
symbols: config/GMPE01_00/rels/w03Dll/symbols.txt
splits: config/GMPE01_00/rels/w03Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/w04Dll.rel
- object: files/dll/w04Dll.rel
hash: 821126eeb7054150744b925cc4cb06c751ddcefd
symbols: config/GMPE01_00/rels/w04Dll/symbols.txt
splits: config/GMPE01_00/rels/w04Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/w05Dll.rel
- object: files/dll/w05Dll.rel
hash: d29f7ccadcba23c8446d05101c4efa5caba26dfd
symbols: config/GMPE01_00/rels/w05Dll/symbols.txt
splits: config/GMPE01_00/rels/w05Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/w06Dll.rel
- object: files/dll/w06Dll.rel
hash: d11a7a6d44189ba8d1e3a7168ea640ea9f2152fe
symbols: config/GMPE01_00/rels/w06Dll/symbols.txt
splits: config/GMPE01_00/rels/w06Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/w10Dll.rel
- object: files/dll/w10Dll.rel
hash: 54bb23228b04c5aaa6aa7c8ca1f846baec5a1f2c
symbols: config/GMPE01_00/rels/w10Dll/symbols.txt
splits: config/GMPE01_00/rels/w10Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/w20Dll.rel
- object: files/dll/w20Dll.rel
hash: 98cc41456afa9e1ccbb8e03718b8d3cb64e4e86f
symbols: config/GMPE01_00/rels/w20Dll/symbols.txt
splits: config/GMPE01_00/rels/w20Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/w21Dll.rel
- object: files/dll/w21Dll.rel
hash: b888f2c6703e680699ff8c59ad9200b9d78d30a1
symbols: config/GMPE01_00/rels/w21Dll/symbols.txt
splits: config/GMPE01_00/rels/w21Dll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/ztardll.rel
- object: files/dll/ztardll.rel
hash: 87d9fee70ed4f011e0b30e05156d087204cf686f
symbols: config/GMPE01_00/rels/ztardll/symbols.txt
splits: config/GMPE01_00/rels/ztardll/splits.txt
links: []
- object: orig/GMPE01_00/files/dll/E3setupDLL.rel
- object: files/dll/E3setupDLL.rel
hash: 234e07cee1491c7060e30805681bf5f39150122d
symbols: config/GMPE01_00/rels/E3setupDLL/symbols.txt
splits: config/GMPE01_00/rels/E3setupDLL/splits.txt
links: [_minigameDll]
- object: orig/GMPE01_00/files/dll/m300Dll.rel
- object: files/dll/m300Dll.rel
hash: eba8a17e8b263bc9cd601b1aea7e698a8785416a
symbols: config/GMPE01_00/rels/m300Dll/symbols.txt
splits: config/GMPE01_00/rels/m300Dll/splits.txt
links: [_minigameDll]
- object: orig/GMPE01_00/files/dll/m401Dll.rel
- object: files/dll/m401Dll.rel
hash: f3ec526c25986a3fcf7dfbc8c463626839a3a801
symbols: config/GMPE01_00/rels/m401Dll/symbols.txt
splits: config/GMPE01_00/rels/m401Dll/splits.txt

View file

@ -16,7 +16,15 @@ import argparse
import sys
from pathlib import Path
from typing import Any, Dict, List
from tools.project import *
from tools.project import (
Object,
ProgressCategory,
ProjectConfig,
calculate_progress,
generate_build,
is_windows,
)
# Game versions
DEFAULT_VERSION = 0
@ -105,6 +113,12 @@ parser.add_argument(
action="store_true",
help="builds equivalent (but non-matching) or modded objects",
)
parser.add_argument(
"--no-progress",
dest="progress",
action="store_false",
help="disable progress calculation",
)
args = parser.parse_args()
config = ProjectConfig()
@ -117,10 +131,10 @@ config.dtk_path = args.dtk
config.objdiff_path = args.objdiff
config.binutils_path = args.binutils
config.compilers_path = args.compilers
config.debug = args.debug
config.generate_map = args.map
config.non_matching = args.non_matching
config.sjiswrap_path = args.sjiswrap
config.progress = args.progress
if not is_windows():
config.wrapper = args.wrapper
# Don't build asm unless we're --non-matching
@ -130,8 +144,8 @@ if not config.non_matching:
# Tool versions
config.binutils_tag = "2.42-1"
config.compilers_tag = "20240706"
config.dtk_tag = "v0.9.6"
config.objdiff_tag = "v2.0.0-beta.6"
config.dtk_tag = "v1.1.4"
config.objdiff_tag = "v2.3.3"
config.sjiswrap_tag = "v1.1.1"
config.wibo_tag = "0.6.11"
@ -149,6 +163,10 @@ config.ldflags = [
"-fp hardware",
"-nodefaults",
]
if args.debug:
config.ldflags.append("-g")
if args.map:
config.ldflags.append("-mapunused")
# Base flags, common to most GC/Wii games.
# Generally leave untouched, with overrides added below.
@ -178,7 +196,7 @@ cflags_base = [
]
# Debug flags
if config.debug:
if args.debug:
cflags_base.extend(["-sym on", "-DDEBUG=1"])
else:
cflags_base.append("-DNDEBUG=1")
@ -324,6 +342,12 @@ Matching = True # Object matches and should be linked
NonMatching = False # Object does not match and should not be linked
Equivalent = config.non_matching # Object should be linked when configured with --non-matching
# Object is only matching for specific versions
def MatchingFor(*versions):
return config.version in versions
config.warn_missing_config = True
config.warn_missing_source = False
config.libs = [

View file

@ -1,6 +1,7 @@
#ifndef _CTYPE_H
#define _CTYPE_H
#include "dolphin/types.h"
extern unsigned char __ctype_map[256];
extern unsigned char __lower_map[256];
@ -22,19 +23,25 @@ extern unsigned char __upper_map[256];
#define __whitespace (__motion_char | __space_char)
#define __control (__motion_char | __control_char)
#ifdef __MWERKS__
#define DECL_WEAK __declspec(weak)
#else
#define DECL_WEAK __attribute__((weak))
#endif
#ifdef __cplusplus
extern "C"
{
#endif
__declspec(weak) int isalpha(int __c);
__declspec(weak) int isdigit(int __c);
__declspec(weak) int isspace(int __c);
__declspec(weak) int isupper(int __c);
__declspec(weak) int isxdigit(int __c);
DECL_WEAK int isalpha(int __c);
DECL_WEAK int isdigit(int __c);
DECL_WEAK int isspace(int __c);
DECL_WEAK int isupper(int __c);
DECL_WEAK int isxdigit(int __c);
__declspec(weak) int tolower(int __c);
__declspec(weak) int toupper(int __c);
DECL_WEAK int tolower(int __c);
DECL_WEAK int toupper(int __c);
// added underscore to avoid naming conflicts
inline int _isalpha(int c) { return (int)(__ctype_map[(u8)c] & __letter); }
@ -48,4 +55,4 @@ extern "C"
#ifdef __cplusplus
}
#endif
#endif
#endif

View file

@ -19,7 +19,7 @@ extern "C" {
#ifdef __MWERKS__
#define AT_ADDRESS(xyz) : (xyz)
#else
#define AT_ADDRESS
#define AT_ADDRESS(xyz)
#endif
typedef s64 OSTime;
typedef u32 OSTick;

View file

@ -7,7 +7,7 @@
void GWInit(void);
void GWGameStatReset(void);
s32 GWMessSpeedGet(void);
// s32 GWMessSpeedGet(void);
s32 GWMessDelayGet(void);
void GWMGRecordSet(s32 index, u32 value);
u32 GWMGRecordGet(s32 index);

View file

@ -7,6 +7,7 @@
#define _MATH_INLINE static inline
#endif
#ifdef __MWERKS__
extern inline float sqrtf(float x)
{
volatile float y;
@ -21,6 +22,9 @@ extern inline float sqrtf(float x)
}
return x;
}
#else
float sqrtf(float x);
#endif
double atan(double x);
double copysign(double x, double y);
@ -38,15 +42,15 @@ double fmod(double x, double y);
double log(double x);
double pow(double x, double y);
float tanf(float x);
float sinf(float x);
float cosf(float x);
float atan2f(float y, float x);
float acosf(float x);
#ifdef __MWERKS__
extern inline double fabs(double x)
{
return __fabs(x);
}
#else
double fabs(double x);
#endif
_MATH_INLINE float fabsf(float x) { return (float)fabs((double)x); }
_MATH_INLINE float sinf(float x) { return (float)sin((double)x); }

View file

@ -1,6 +1,10 @@
#ifndef _STDLIB_H
#define _STDLIB_H
#ifdef __MWERKS__
#define abs(x) __abs(x)
#else
int abs(int x);
#endif
#endif

View file

@ -23,7 +23,7 @@ include_dirs = [
# Add additional include directories here
]
include_pattern = re.compile(r'^#\s*include\s*[<"](.+?)[>"]$')
include_pattern = re.compile(r'^#\s*include\s*[<"](.+?)[>"]')
guard_pattern = re.compile(r"^#\s*ifndef\s+(.*)$")
defines = set()

View file

@ -55,6 +55,7 @@ def dtk_url(tag: str) -> str:
repo = "https://github.com/encounter/decomp-toolkit"
return f"{repo}/releases/download/{tag}/dtk-{system}-{arch}{suffix}"
def objdiff_cli_url(tag: str) -> str:
uname = platform.uname()
suffix = ""

View file

@ -17,7 +17,7 @@ import os
import platform
import sys
from pathlib import Path
from typing import Any, Dict, List, Optional, Set, Tuple, Union, cast
from typing import IO, Any, Dict, Iterable, List, Optional, Set, Tuple, Union, cast
from . import ninja_syntax
from .ninja_syntax import serialize_path
@ -41,8 +41,9 @@ class Object:
"asflags": None,
"asm_dir": None,
"cflags": None,
"extra_asflags": None,
"extra_cflags": None,
"extra_asflags": [],
"extra_cflags": [],
"extra_clang_flags": [],
"host": None,
"lib": None,
"mw_version": None,
@ -81,6 +82,20 @@ class Object:
set_default("shift_jis", config.shift_jis)
set_default("src_dir", config.src_dir)
# Validate progress categories
def check_category(category: str):
if not any(category == c.id for c in config.progress_categories):
sys.exit(
f"Progress category '{category}' missing from config.progress_categories"
)
progress_category = obj.options["progress_category"]
if isinstance(progress_category, list):
for category in progress_category:
check_category(category)
elif progress_category is not None:
check_category(progress_category)
# Resolve paths
build_dir = config.out_path()
obj.src_path = Path(obj.options["src_dir"]) / obj.options["source"]
@ -131,7 +146,6 @@ class ProjectConfig:
self.build_rels: bool = True # Build REL files
self.check_sha_path: Optional[Path] = None # Path to version.sha1
self.config_path: Optional[Path] = None # Path to config.yml
self.debug: bool = False # Build with debug info
self.generate_map: bool = False # Generate map file(s)
self.asflags: Optional[List[str]] = None # Assembler flags
self.ldflags: Optional[List[str]] = None # Linker flags
@ -156,14 +170,22 @@ class ProjectConfig:
self.custom_build_steps: Optional[Dict[str, List[Dict[str, Any]]]] = (
None # Custom build steps, types are ["pre-compile", "post-compile", "post-link", "post-build"]
)
self.generate_compile_commands: bool = (
True # Generate compile_commands.json for clangd
)
self.extra_clang_flags: List[str] = [] # Extra flags for clangd
# Progress output, progress.json and report.json config
self.progress = True # Enable report.json generation and CLI progress output
self.progress_all: bool = True # Include combined "all" category
self.progress_modules: bool = True # Include combined "modules" category
self.progress_each_module: bool = (
False # Include individual modules, disable for large numbers of modules
)
self.progress_categories: List[ProgressCategory] = [] # Additional categories
self.print_progress_categories: Union[bool, List[str]] = (
True # Print additional progress categories in the CLI progress output
)
# Progress fancy printing
self.progress_use_fancy: bool = False
@ -200,9 +222,40 @@ class ProjectConfig:
out[obj.name] = obj.resolve(self, lib)
return out
# Gets the output path for build-related files.
def out_path(self) -> Path:
return self.build_dir / str(self.version)
# Gets the path to the compilers directory.
# Exits the program if neither `compilers_path` nor `compilers_tag` is provided.
def compilers(self) -> Path:
if self.compilers_path:
return self.compilers_path
elif self.compilers_tag:
return self.build_dir / "compilers"
else:
sys.exit("ProjectConfig.compilers_tag missing")
# Gets the wrapper to use for compiler commands, if set.
def compiler_wrapper(self) -> Optional[Path]:
wrapper = self.wrapper
if self.use_wibo():
wrapper = self.build_dir / "tools" / "wibo"
if not is_windows() and wrapper is None:
wrapper = Path("wine")
return wrapper
# Determines whether or not to use wibo as the compiler wrapper.
def use_wibo(self) -> bool:
return (
self.wibo_tag is not None
and sys.platform == "linux"
and platform.machine() in ("i386", "x86_64")
and self.wrapper is None
)
def is_windows() -> bool:
return os.name == "nt"
@ -214,11 +267,26 @@ CHAIN = "cmd /c " if is_windows() else ""
EXE = ".exe" if is_windows() else ""
def make_flags_str(cflags: Union[str, List[str]]) -> str:
if isinstance(cflags, list):
return " ".join(cflags)
else:
return cflags
def file_is_asm(path: Path) -> bool:
return path.suffix.lower() == ".s"
def file_is_c(path: Path) -> bool:
return path.suffix.lower() == ".c"
def file_is_cpp(path: Path) -> bool:
return path.suffix.lower() in (".cc", ".cp", ".cpp", ".cxx")
def file_is_c_cpp(path: Path) -> bool:
return file_is_c(path) or file_is_cpp(path)
def make_flags_str(flags: Optional[List[str]]) -> str:
if flags is None:
return ""
return " ".join(flags)
# Load decomp-toolkit generated config.json
@ -235,14 +303,14 @@ def load_build_config(
build_config: Dict[str, Any] = json.load(f)
config_version = build_config.get("version")
if config_version is None:
# Invalid config.json
print("Invalid config.json, regenerating...")
f.close()
os.remove(build_config_path)
return None
dtk_version = str(config.dtk_tag)[1:] # Strip v
if versiontuple(config_version) < versiontuple(dtk_version):
# Outdated config.json
print("Outdated config.json, regenerating...")
f.close()
os.remove(build_config_path)
return None
@ -251,13 +319,14 @@ def load_build_config(
return build_config
# Generate build.ninja and objdiff.json
# Generate build.ninja, objdiff.json and compile_commands.json
def generate_build(config: ProjectConfig) -> None:
config.validate()
objects = config.objects()
build_config = load_build_config(config, config.out_path() / "config.json")
generate_build_ninja(config, objects, build_config)
generate_objdiff_config(config, objects, build_config)
generate_compile_commands(config, objects, build_config)
# Generate build.ninja
@ -283,12 +352,7 @@ def generate_build_ninja(
# Variables
###
n.comment("Variables")
ldflags = " ".join(config.ldflags or [])
if config.generate_map:
ldflags += " -mapunused"
if config.debug:
ldflags += " -g"
n.variable("ldflags", ldflags)
n.variable("ldflags", make_flags_str(config.ldflags))
if config.linker_version is None:
sys.exit("ProjectConfig.linker_version missing")
n.variable("mw_version", Path(config.linker_version))
@ -409,16 +473,10 @@ def generate_build_ninja(
else:
sys.exit("ProjectConfig.sjiswrap_tag missing")
wrapper = config.compiler_wrapper()
# Only add an implicit dependency on wibo if we download it
wrapper = config.wrapper
wrapper_implicit: Optional[Path] = None
if (
config.wibo_tag is not None
and sys.platform == "linux"
and platform.machine() in ("i386", "x86_64")
and config.wrapper is None
):
wrapper = build_tools_path / "wibo"
if wrapper is not None and config.use_wibo():
wrapper_implicit = wrapper
n.build(
outputs=wrapper,
@ -429,15 +487,11 @@ def generate_build_ninja(
"tag": config.wibo_tag,
},
)
if not is_windows() and wrapper is None:
wrapper = Path("wine")
wrapper_cmd = f"{wrapper} " if wrapper else ""
compilers = config.compilers()
compilers_implicit: Optional[Path] = None
if config.compilers_path:
compilers = config.compilers_path
elif config.compilers_tag:
compilers = config.build_dir / "compilers"
if config.compilers_path is None and config.compilers_tag is not None:
compilers_implicit = compilers
n.build(
outputs=compilers,
@ -448,8 +502,6 @@ def generate_build_ninja(
"tag": config.compilers_tag,
},
)
else:
sys.exit("ProjectConfig.compilers_tag missing")
binutils_implicit = None
if config.binutils_path:
@ -663,7 +715,6 @@ def generate_build_ninja(
n.comment(f"Link {self.name}")
if self.module_id == 0:
elf_path = build_path / f"{self.name}.elf"
dol_path = build_path / f"{self.name}.dol"
elf_ldflags = f"$ldflags -lcf {serialize_path(self.ldscript)}"
if config.generate_map:
elf_map = map_path(elf_path)
@ -728,17 +779,33 @@ def generate_build_ninja(
source_added: Set[Path] = set()
def c_build(obj: Object, src_path: Path) -> Optional[Path]:
cflags_str = make_flags_str(obj.options["cflags"])
if obj.options["extra_cflags"] is not None:
extra_cflags_str = make_flags_str(obj.options["extra_cflags"])
cflags_str += " " + extra_cflags_str
used_compiler_versions.add(obj.options["mw_version"])
# Avoid creating duplicate build rules
if obj.src_obj_path is None or obj.src_obj_path in source_added:
return obj.src_obj_path
source_added.add(obj.src_obj_path)
cflags = obj.options["cflags"]
extra_cflags = obj.options["extra_cflags"]
# Add appropriate language flag if it doesn't exist already
# Added directly to the source so it flows to other generation tasks
if not any(flag.startswith("-lang") for flag in cflags) and not any(
flag.startswith("-lang") for flag in extra_cflags
):
# Ensure extra_cflags is a unique instance,
# and insert into there to avoid modifying shared sets of flags
extra_cflags = obj.options["extra_cflags"] = list(extra_cflags)
if file_is_cpp(src_path):
extra_cflags.insert(0, "-lang=c++")
else:
extra_cflags.insert(0, "-lang=c")
cflags_str = make_flags_str(cflags)
if len(extra_cflags) > 0:
extra_cflags_str = make_flags_str(extra_cflags)
cflags_str += " " + extra_cflags_str
used_compiler_versions.add(obj.options["mw_version"])
# Add MWCC build rule
lib_name = obj.options["lib"]
n.comment(f"{obj.name}: {lib_name} (linked {obj.completed})")
@ -770,7 +837,7 @@ def generate_build_ninja(
if obj.options["host"] and obj.host_obj_path is not None:
n.build(
outputs=obj.host_obj_path,
rule="host_cc" if src_path.suffix == ".c" else "host_cpp",
rule="host_cc" if file_is_c(src_path) else "host_cpp",
inputs=src_path,
variables={
"basedir": os.path.dirname(obj.host_obj_path),
@ -792,7 +859,7 @@ def generate_build_ninja(
if obj.options["asflags"] is None:
sys.exit("ProjectConfig.asflags missing")
asflags_str = make_flags_str(obj.options["asflags"])
if obj.options["extra_asflags"] is not None:
if len(obj.options["extra_asflags"]) > 0:
extra_asflags_str = make_flags_str(obj.options["extra_asflags"])
asflags_str += " " + extra_asflags_str
@ -830,10 +897,10 @@ def generate_build_ninja(
link_built_obj = obj.completed
built_obj_path: Optional[Path] = None
if obj.src_path is not None and obj.src_path.exists():
if obj.src_path.suffix in (".c", ".cp", ".cpp"):
if file_is_c_cpp(obj.src_path):
# Add MWCC & host build rules
built_obj_path = c_build(obj, obj.src_path)
elif obj.src_path.suffix == ".s":
elif file_is_asm(obj.src_path):
# Add assembler build rule
built_obj_path = asm_build(obj, obj.src_path, obj.src_obj_path)
else:
@ -1040,7 +1107,12 @@ def generate_build_ninja(
n.build(
outputs=progress_path,
rule="progress",
implicit=[ok_path, configure_script, python_lib, config.config_path],
implicit=[
ok_path,
configure_script,
python_lib,
report_path,
],
)
###
@ -1153,8 +1225,10 @@ def generate_build_ninja(
if build_config:
if config.non_matching:
n.default(link_outputs)
else:
elif config.progress:
n.default(progress_path)
else:
n.default(ok_path)
else:
n.default(build_config_path)
@ -1173,6 +1247,13 @@ def generate_objdiff_config(
if build_config is None:
return
# Load existing objdiff.json
existing_units = {}
if Path("objdiff.json").is_file():
with open("objdiff.json", "r", encoding="utf-8") as r:
existing_config = json.load(r)
existing_units = {unit["name"]: unit for unit in existing_config["units"]}
objdiff_config: Dict[str, Any] = {
"min_version": "2.0.0-beta.5",
"custom_make": "ninja",
@ -1194,7 +1275,6 @@ def generate_objdiff_config(
}
# decomp.me compiler name mapping
# Commented out versions have not been added to decomp.me yet
COMPILER_MAP = {
"GC/1.0": "mwcc_233_144",
"GC/1.1": "mwcc_233_159",
@ -1231,15 +1311,27 @@ def generate_objdiff_config(
) -> None:
obj_path, obj_name = build_obj["object"], build_obj["name"]
base_object = Path(obj_name).with_suffix("")
name = str(Path(module_name) / base_object).replace(os.sep, "/")
unit_config: Dict[str, Any] = {
"name": Path(module_name) / base_object,
"name": name,
"target_path": obj_path,
"base_path": None,
"scratch": None,
"metadata": {
"auto_generated": build_obj["autogenerated"],
"complete": None,
"reverse_fn_order": None,
"source_path": None,
"progress_categories": progress_categories,
"auto_generated": build_obj["autogenerated"],
},
"symbol_mappings": None,
}
# Preserve existing symbol mappings
existing_unit = existing_units.get(name)
if existing_unit is not None:
unit_config["symbol_mappings"] = existing_unit.get("symbol_mappings")
obj = objects.get(obj_name)
if obj is None:
objdiff_config["units"].append(unit_config)
@ -1248,40 +1340,31 @@ def generate_objdiff_config(
src_exists = obj.src_path is not None and obj.src_path.exists()
if src_exists:
unit_config["base_path"] = obj.src_obj_path
unit_config["metadata"]["source_path"] = obj.src_path
cflags = obj.options["cflags"]
reverse_fn_order = False
if type(cflags) is list:
for flag in cflags:
if not flag.startswith("-inline "):
continue
for value in flag.split(" ")[1].split(","):
if value == "deferred":
reverse_fn_order = True
elif value == "nodeferred":
reverse_fn_order = False
for flag in cflags:
if not flag.startswith("-inline "):
continue
for value in flag.split(" ")[1].split(","):
if value == "deferred":
reverse_fn_order = True
elif value == "nodeferred":
reverse_fn_order = False
# Filter out include directories
def keep_flag(flag):
return not flag.startswith("-i ") and not flag.startswith("-I ")
# Filter out include directories
def keep_flag(flag):
return not flag.startswith("-i ") and not flag.startswith("-I ")
cflags = list(filter(keep_flag, cflags))
# Add appropriate lang flag
if obj.src_path is not None and not any(
flag.startswith("-lang") for flag in cflags
):
if obj.src_path.suffix in (".cp", ".cpp"):
cflags.insert(0, "-lang=c++")
else:
cflags.insert(0, "-lang=c")
cflags = list(filter(keep_flag, cflags))
compiler_version = COMPILER_MAP.get(obj.options["mw_version"])
if compiler_version is None:
print(f"Missing scratch compiler mapping for {obj.options['mw_version']}")
else:
cflags_str = make_flags_str(cflags)
if obj.options["extra_cflags"] is not None:
if len(obj.options["extra_cflags"]) > 0:
extra_cflags_str = make_flags_str(obj.options["extra_cflags"])
cflags_str += " " + extra_cflags_str
unit_config["scratch"] = {
@ -1305,7 +1388,6 @@ def generate_objdiff_config(
{
"complete": obj.completed,
"reverse_fn_order": reverse_fn_order,
"source_path": obj.src_path,
"progress_categories": progress_categories,
}
)
@ -1349,160 +1431,357 @@ def generate_objdiff_config(
for category in config.progress_categories:
add_category(category.id, category.name)
def cleandict(d):
if isinstance(d, dict):
return {k: cleandict(v) for k, v in d.items() if v is not None}
elif isinstance(d, list):
return [cleandict(v) for v in d]
else:
return d
# Write objdiff.json
with open("objdiff.json", "w", encoding="utf-8") as w:
def unix_path(input: Any) -> str:
return str(input).replace(os.sep, "/") if input else ""
json.dump(objdiff_config, w, indent=4, default=unix_path)
json.dump(cleandict(objdiff_config), w, indent=2, default=unix_path)
def generate_compile_commands(
config: ProjectConfig,
objects: Dict[str, Object],
build_config: Optional[Dict[str, Any]],
) -> None:
if build_config is None or not config.generate_compile_commands:
return
# The following code attempts to convert mwcc flags to clang flags
# for use with clangd.
# Flags to ignore explicitly
CFLAG_IGNORE: Set[str] = {
# Search order modifier
# Has a different meaning to Clang, and would otherwise
# be picked up by the include passthrough prefix
"-I-",
"-i-",
}
CFLAG_IGNORE_PREFIX: Tuple[str, ...] = (
# Recursive includes are not supported by modern compilers
"-ir ",
)
# Flags to replace
CFLAG_REPLACE: Dict[str, str] = {}
CFLAG_REPLACE_PREFIX: Tuple[Tuple[str, str], ...] = (
# Includes
("-i ", "-I"),
("-I ", "-I"),
("-I+", "-I"),
# Defines
("-d ", "-D"),
("-D ", "-D"),
("-D+", "-D"),
)
# Flags with a finite set of options
CFLAG_REPLACE_OPTIONS: Tuple[Tuple[str, Dict[str, Tuple[str, ...]]], ...] = (
# Exceptions
(
"-Cpp_exceptions",
{
"off": ("-fno-cxx-exceptions",),
"on": ("-fcxx-exceptions",),
},
),
# RTTI
(
"-RTTI",
{
"off": ("-fno-rtti",),
"on": ("-frtti",),
},
),
# Language configuration
(
"-lang",
{
"c": ("--language=c", "--std=c99"),
"c99": ("--language=c", "--std=c99"),
"c++": ("--language=c++", "--std=c++98"),
"cplus": ("--language=c++", "--std=c++98"),
},
),
# Enum size
(
"-enum",
{
"min": ("-fshort-enums",),
"int": ("-fno-short-enums",),
},
),
# Common BSS
(
"-common",
{
"off": ("-fno-common",),
"on": ("-fcommon",),
},
),
)
# Flags to pass through
CFLAG_PASSTHROUGH: Set[str] = set()
CFLAG_PASSTHROUGH_PREFIX: Tuple[str, ...] = (
"-I", # includes
"-D", # defines
)
clangd_config = []
def add_unit(build_obj: Dict[str, Any]) -> None:
obj = objects.get(build_obj["name"])
if obj is None:
return
# Skip unresolved objects
if (
obj.src_path is None
or obj.src_obj_path is None
or not file_is_c_cpp(obj.src_path)
):
return
# Gather cflags for source file
cflags: list[str] = []
def append_cflags(flags: Iterable[str]) -> None:
# Match a flag against either a set of concrete flags, or a set of prefixes.
def flag_match(
flag: str, concrete: Set[str], prefixes: Tuple[str, ...]
) -> bool:
if flag in concrete:
return True
for prefix in prefixes:
if flag.startswith(prefix):
return True
return False
# Determine whether a flag should be ignored.
def should_ignore(flag: str) -> bool:
return flag_match(flag, CFLAG_IGNORE, CFLAG_IGNORE_PREFIX)
# Determine whether a flag should be passed through.
def should_passthrough(flag: str) -> bool:
return flag_match(flag, CFLAG_PASSTHROUGH, CFLAG_PASSTHROUGH_PREFIX)
# Attempts replacement for the given flag.
def try_replace(flag: str) -> bool:
replacement = CFLAG_REPLACE.get(flag)
if replacement is not None:
cflags.append(replacement)
return True
for prefix, replacement in CFLAG_REPLACE_PREFIX:
if flag.startswith(prefix):
cflags.append(flag.replace(prefix, replacement, 1))
return True
for prefix, options in CFLAG_REPLACE_OPTIONS:
if not flag.startswith(prefix):
continue
# "-lang c99" and "-lang=c99" are both generally valid option forms
option = flag.removeprefix(prefix).removeprefix("=").lstrip()
replacements = options.get(option)
if replacements is not None:
cflags.extend(replacements)
return True
return False
for flag in flags:
# Ignore flags first
if should_ignore(flag):
continue
# Then find replacements
if try_replace(flag):
continue
# Pass flags through last
if should_passthrough(flag):
cflags.append(flag)
continue
append_cflags(obj.options["cflags"])
append_cflags(obj.options["extra_cflags"])
cflags.extend(config.extra_clang_flags)
cflags.extend(obj.options["extra_clang_flags"])
unit_config = {
"directory": Path.cwd(),
"file": obj.src_path,
"output": obj.src_obj_path,
"arguments": [
"clang",
"-nostdinc",
"-fno-builtin",
"--target=powerpc-eabi",
*cflags,
"-c",
obj.src_path,
"-o",
obj.src_obj_path,
],
}
clangd_config.append(unit_config)
# Add DOL units
for unit in build_config["units"]:
add_unit(unit)
# Add REL units
for module in build_config["modules"]:
for unit in module["units"]:
add_unit(unit)
# Write compile_commands.json
with open("compile_commands.json", "w", encoding="utf-8") as w:
def default_format(o):
if isinstance(o, Path):
return o.resolve().as_posix()
return str(o)
json.dump(clangd_config, w, indent=2, default=default_format)
# Calculate, print and write progress to progress.json
def calculate_progress(config: ProjectConfig) -> None:
config.validate()
objects = config.objects()
out_path = config.out_path()
build_config = load_build_config(config, out_path / "config.json")
if build_config is None:
return
report_path = out_path / "report.json"
if not report_path.is_file():
sys.exit(f"Report file {report_path} does not exist")
class ProgressUnit:
def __init__(self, name: str) -> None:
self.name: str = name
self.code_total: int = 0
self.code_fancy_frac: int = config.progress_code_fancy_frac
self.code_fancy_item: str = config.progress_code_fancy_item
self.code_progress: int = 0
self.data_total: int = 0
self.data_fancy_frac: int = config.progress_data_fancy_frac
self.data_fancy_item: str = config.progress_data_fancy_item
self.data_progress: int = 0
self.objects_progress: int = 0
self.objects_total: int = 0
self.objects: Set[Object] = set()
report_data: Dict[str, Any] = {}
with open(report_path, "r", encoding="utf-8") as f:
report_data = json.load(f)
def add(self, build_obj: Dict[str, Any]) -> None:
self.code_total += build_obj["code_size"]
self.data_total += build_obj["data_size"]
# Convert string numbers (u64) to int
def convert_numbers(data: Dict[str, Any]) -> None:
for key, value in data.items():
if isinstance(value, str) and value.isdigit():
data[key] = int(value)
# Avoid counting the same object in different modules twice
include_object = build_obj["name"] not in self.objects
if include_object:
self.objects.add(build_obj["name"])
self.objects_total += 1
convert_numbers(report_data["measures"])
for category in report_data.get("categories", []):
convert_numbers(category["measures"])
if build_obj["autogenerated"]:
# Skip autogenerated objects
return
# Output to GitHub Actions job summary, if available
summary_path = os.getenv("GITHUB_STEP_SUMMARY")
summary_file: Optional[IO[str]] = None
if summary_path:
summary_file = open(summary_path, "a", encoding="utf-8")
summary_file.write("```\n")
obj = objects.get(build_obj["name"])
if obj is None or not obj.completed:
return
self.code_progress += build_obj["code_size"]
self.data_progress += build_obj["data_size"]
if include_object:
self.objects_progress += 1
def code_frac(self) -> float:
if self.code_total == 0:
return 1.0
return self.code_progress / self.code_total
def data_frac(self) -> float:
if self.data_total == 0:
return 1.0
return self.data_progress / self.data_total
progress_units: Dict[str, ProgressUnit] = {}
if config.progress_all:
progress_units["all"] = ProgressUnit("All")
progress_units["dol"] = ProgressUnit("DOL")
if len(build_config["modules"]) > 0:
if config.progress_modules:
progress_units["modules"] = ProgressUnit("Modules")
if len(config.progress_categories) > 0:
for category in config.progress_categories:
progress_units[category.id] = ProgressUnit(category.name)
if config.progress_each_module:
for module in build_config["modules"]:
progress_units[module["name"]] = ProgressUnit(module["name"])
def add_unit(id: str, unit: Dict[str, Any]) -> None:
progress = progress_units.get(id)
if progress is not None:
progress.add(unit)
# Add DOL units
for unit in build_config["units"]:
add_unit("all", unit)
add_unit("dol", unit)
obj = objects.get(unit["name"])
if obj is not None:
category_opt = obj.options["progress_category"]
if isinstance(category_opt, list):
for id in category_opt:
add_unit(id, unit)
elif category_opt is not None:
add_unit(category_opt, unit)
# Add REL units
for module in build_config["modules"]:
for unit in module["units"]:
add_unit("all", unit)
add_unit("modules", unit)
add_unit(module["name"], unit)
obj = objects.get(unit["name"])
if obj is not None:
category_opt = obj.options["progress_category"]
if isinstance(category_opt, list):
for id in category_opt:
add_unit(id, unit)
elif category_opt is not None:
add_unit(category_opt, unit)
def progress_print(s: str) -> None:
print(s)
if summary_file:
summary_file.write(s + "\n")
# Print human-readable progress
print("Progress:")
progress_print("Progress:")
def print_category(unit: Optional[ProgressUnit]) -> None:
if unit is None:
return
def print_category(name: str, measures: Dict[str, Any]) -> None:
total_code = measures.get("total_code", 0)
matched_code = measures.get("matched_code", 0)
matched_code_percent = measures.get("matched_code_percent", 0)
total_data = measures.get("total_data", 0)
matched_data = measures.get("matched_data", 0)
matched_data_percent = measures.get("matched_data_percent", 0)
total_functions = measures.get("total_functions", 0)
matched_functions = measures.get("matched_functions", 0)
complete_code_percent = measures.get("complete_code_percent", 0)
total_units = measures.get("total_units", 0)
complete_units = measures.get("complete_units", 0)
code_frac = unit.code_frac()
data_frac = unit.data_frac()
print(
f" {unit.name}: {code_frac:.2%} code, {data_frac:.2%} data ({unit.objects_progress} / {unit.objects_total} files)"
progress_print(
f" {name}: {matched_code_percent:.2f}% matched, {complete_code_percent:.2f}% linked ({complete_units} / {total_units} files)"
)
progress_print(
f" Code: {matched_code} / {total_code} bytes ({matched_functions} / {total_functions} functions)"
)
progress_print(
f" Data: {matched_data} / {total_data} bytes ({matched_data_percent:.2f}%)"
)
print(f" Code: {unit.code_progress} / {unit.code_total} bytes")
print(f" Data: {unit.data_progress} / {unit.data_total} bytes")
if config.progress_use_fancy:
print(
"\nYou have {} out of {} {} and {} out of {} {}.".format(
math.floor(code_frac * unit.code_fancy_frac),
unit.code_fancy_frac,
unit.code_fancy_item,
math.floor(data_frac * unit.data_fancy_frac),
unit.data_fancy_frac,
unit.data_fancy_item,
)
)
for progress in progress_units.values():
print_category(progress)
print_category("All", report_data["measures"])
for category in report_data.get("categories", []):
if config.print_progress_categories is True or (
isinstance(config.print_progress_categories, list)
and category["id"] in config.print_progress_categories
):
print_category(category["name"], category["measures"])
if config.progress_use_fancy:
measures = report_data["measures"]
total_code = measures.get("total_code", 0)
total_data = measures.get("total_data", 0)
if total_code == 0 or total_data == 0:
return
code_frac = measures.get("complete_code", 0) / total_code
data_frac = measures.get("complete_data", 0) / total_data
progress_print(
"\nYou have {} out of {} {} and {} out of {} {}.".format(
math.floor(code_frac * config.progress_code_fancy_frac),
config.progress_code_fancy_frac,
config.progress_code_fancy_item,
math.floor(data_frac * config.progress_data_fancy_frac),
config.progress_data_fancy_frac,
config.progress_data_fancy_item,
)
)
# Finalize GitHub Actions job summary
if summary_file:
summary_file.write("```\n")
summary_file.close()
# Generate and write progress.json
progress_json: Dict[str, Any] = {}
def add_category(category: str, unit: ProgressUnit) -> None:
progress_json[category] = {
"code": unit.code_progress,
"code/total": unit.code_total,
"data": unit.data_progress,
"data/total": unit.data_total,
def add_category(id: str, measures: Dict[str, Any]) -> None:
progress_json[id] = {
"code": measures.get("complete_code", 0),
"code/total": measures.get("total_code", 0),
"data": measures.get("complete_data", 0),
"data/total": measures.get("total_data", 0),
"matched_code": measures.get("matched_code", 0),
"matched_code/total": measures.get("total_code", 0),
"matched_data": measures.get("matched_data", 0),
"matched_data/total": measures.get("total_data", 0),
"matched_functions": measures.get("matched_functions", 0),
"matched_functions/total": measures.get("total_functions", 0),
"fuzzy_match": int(measures.get("fuzzy_match_percent", 0) * 100),
"fuzzy_match/total": 10000,
"units": measures.get("complete_units", 0),
"units/total": measures.get("total_units", 0),
}
for id, progress in progress_units.items():
add_category(id, progress)
if config.progress_all:
add_category("all", report_data["measures"])
else:
# Support for old behavior where "dol" was the main category
add_category("dol", report_data["measures"])
for category in report_data.get("categories", []):
add_category(category["id"], category["measures"])
with open(out_path / "progress.json", "w", encoding="utf-8") as w:
json.dump(progress_json, w, indent=4)
json.dump(progress_json, w, indent=2)