mirror of
https://github.com/zeldaret/tww.git
synced 2024-11-22 21:09:40 +00:00
Update dtk-template, switch from intellisense to clangd
This commit is contained in:
parent
c6bd52facd
commit
26ca0cd4b5
48
.github/workflows/build.yml
vendored
48
.github/workflows/build.yml
vendored
@ -12,36 +12,57 @@ permissions:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/zeldaret/tww-build:main
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version: [GZLE01, GZLP01, GZLJ01]
|
||||
|
||||
steps:
|
||||
# Checkout the repository
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
# Set Git config
|
||||
- name: Git config
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
|
||||
# Copy the original files to the workspace
|
||||
- name: Prepare
|
||||
run: cp -R /orig/${{matrix.version}} orig
|
||||
run: cp -R /orig .
|
||||
|
||||
# Build the project
|
||||
- name: Build
|
||||
run: |
|
||||
python configure.py --version ${{matrix.version}} --compilers /compilers --warn error --no-progress
|
||||
ninja
|
||||
python configure.py --version ${{matrix.version}} --compilers /compilers --warn off
|
||||
ninja all_source build/${{ matrix.version }}/progress.json build/${{ matrix.version }}/report.json
|
||||
python configure.py --map --version ${{ matrix.version }} \
|
||||
--binutils /binutils --compilers /compilers
|
||||
ninja all_source build/${{ matrix.version }}/progress.json \
|
||||
build/${{ matrix.version }}/report.json
|
||||
|
||||
# Upload progress if we're on the main branch
|
||||
- name: Upload progress
|
||||
if: github.ref == 'refs/heads/main'
|
||||
continue-on-error: true
|
||||
env:
|
||||
PROGRESS_API_KEY: ${{secrets.PROGRESS_API_KEY}}
|
||||
PROGRESS_SLUG: tww
|
||||
PROGRESS_API_KEY: ${{ secrets.PROGRESS_API_KEY }}
|
||||
run: |
|
||||
python tools/upload_progress.py -b https://progress.decomp.club/ -p tww -v ${{matrix.version}} \
|
||||
build/${{matrix.version}}/progress.json
|
||||
python tools/upload_progress.py -b https://progress.decomp.club/ \
|
||||
-p $PROGRESS_SLUG -v ${{ matrix.version }} \
|
||||
build/${{ matrix.version }}/progress.json
|
||||
|
||||
# Upload map files
|
||||
- name: Upload map
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.version }}_maps
|
||||
path: build/${{ matrix.version }}/**/*.MAP
|
||||
|
||||
# Upload progress report
|
||||
- name: Upload report
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
@ -52,29 +73,36 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: github.ref == 'refs/heads/main'
|
||||
|
||||
steps:
|
||||
- name: Checkout website code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: LagoLunatic/tww-decomp-website
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: GZLE01_report
|
||||
path: ./artifacts
|
||||
|
||||
- name: Rename artifact
|
||||
run: |
|
||||
mv ./artifacts/report.json ./artifacts/progress.json
|
||||
|
||||
- uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: "8.x.x"
|
||||
|
||||
- name: Build Website
|
||||
run: |
|
||||
python build.py
|
||||
|
||||
- name: Upload website artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: './dist'
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
|
38
.gitignore
vendored
38
.gitignore
vendored
@ -1,13 +1,35 @@
|
||||
# IDE folders
|
||||
.idea/
|
||||
.vs/
|
||||
|
||||
# Caches
|
||||
__pycache__
|
||||
.idea
|
||||
.vscode
|
||||
.ninja_*
|
||||
.mypy_cache
|
||||
*.exe
|
||||
build
|
||||
build.ninja
|
||||
objdiff.json
|
||||
.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
|
||||
*.exe
|
||||
|
12
.vscode/extensions.json
vendored
Normal file
12
.vscode/extensions.json
vendored
Normal 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",
|
||||
]
|
||||
}
|
23
.vscode/settings.json
vendored
Normal file
23
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"[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"
|
||||
},
|
||||
// "editor.tabSize": 2,
|
||||
"files.autoSave": "onFocusChange",
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimFinalNewlines": true,
|
||||
"files.associations": {
|
||||
"*.inc": "c",
|
||||
".clangd": "yaml"
|
||||
},
|
||||
// Disable C/C++ IntelliSense, use clangd instead
|
||||
"C_Cpp.intelliSenseEngine": "disabled",
|
||||
}
|
16
.vscode/tasks.json
vendored
Normal file
16
.vscode/tasks.json
vendored
Normal 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
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
14
README.md
14
README.md
@ -64,20 +64,20 @@ Building
|
||||
```
|
||||
git clone https://github.com/zeldaret/tww.git
|
||||
```
|
||||
- Using [Dolphin Emulator](https://dolphin-emu.org/), extract your game to `orig/GZLE01` (or `GZLJ01` for JPN, `GZLP01` for PAL).
|
||||
![](assets/dolphin-extract.png)
|
||||
- To save space, the only necessary files are the following. Any others can be deleted.
|
||||
- `sys/main.dol`
|
||||
- `files/rels/*.rel`
|
||||
- `files/RELS.arc`
|
||||
|
||||
- Copy your game's disc image to `orig/GZLE01`.
|
||||
- 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 `GZLE01` (USA), specify `--version GZLJ01` (JPN) or `--version GZLP01` (PAL).
|
||||
|
||||
- Build:
|
||||
```
|
||||
ninja && ninja all_source
|
||||
ninja
|
||||
```
|
||||
|
||||
Diffing
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
18
configure.py
18
configure.py
@ -150,8 +150,8 @@ if args.no_asm:
|
||||
# Tool versions
|
||||
config.binutils_tag = "2.42-1"
|
||||
config.compilers_tag = "20240706"
|
||||
config.dtk_tag = "v1.0.0"
|
||||
config.objdiff_tag = "v2.2.1"
|
||||
config.dtk_tag = "v1.1.3"
|
||||
config.objdiff_tag = "v2.3.2"
|
||||
config.sjiswrap_tag = "v1.1.1"
|
||||
config.wibo_tag = "0.6.11"
|
||||
|
||||
@ -307,6 +307,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 = [
|
||||
@ -794,10 +800,10 @@ config.libs = [
|
||||
Object(NonMatching, "JSystem/JAudio/JASChannelMgr.cpp"),
|
||||
Object(Matching, "JSystem/JAudio/JASOscillator.cpp"),
|
||||
Object(Matching, "JSystem/JAudio/JASDriverTables.cpp"),
|
||||
Object(Matching, "JSystem/JAudio/dspproc.c", extra_cflags="-lang c++ -O4 -func_align 32"),
|
||||
Object(Matching, "JSystem/JAudio/dsptask.c", extra_cflags="-lang c++ -O4 -func_align 32"),
|
||||
Object(Matching, "JSystem/JAudio/osdsp.c", extra_cflags="-lang c++ -O4 -func_align 32 -str nopool"),
|
||||
Object(Matching, "JSystem/JAudio/osdsp_task.c", extra_cflags="-lang c++ -O4 -func_align 32"),
|
||||
Object(Matching, "JSystem/JAudio/dspproc.c", extra_cflags=["-lang c++", "-O4", "-func_align 32"]),
|
||||
Object(Matching, "JSystem/JAudio/dsptask.c", extra_cflags=["-lang c++", "-O4", "-func_align 32"]),
|
||||
Object(Matching, "JSystem/JAudio/osdsp.c", extra_cflags=["-lang c++", "-O4", "-func_align 32", "-str nopool"]),
|
||||
Object(Matching, "JSystem/JAudio/osdsp_task.c", extra_cflags=["-lang c++", "-O4", "-func_align 32"]),
|
||||
Object(NonMatching, "JSystem/JAudio/JAIAnimation.cpp"),
|
||||
Object(NonMatching, "JSystem/JAudio/JAIBasic.cpp"),
|
||||
Object(Matching, "JSystem/JAudio/JAIBankWave.cpp"),
|
||||
|
@ -1,68 +0,0 @@
|
||||
Visual Studio Code
|
||||
==================
|
||||
|
||||
Settings
|
||||
--------
|
||||
|
||||
Recommended `.vscode/settings.json`:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"[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,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
C/C++ configuration
|
||||
-------------------
|
||||
|
||||
Recommended `.vscode/c_cpp_properties.json`:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/include/**",
|
||||
"${workspaceFolder}/src/**"
|
||||
],
|
||||
"cStandard": "c99",
|
||||
"cppStandard": "c++98",
|
||||
"intelliSenseMode": "linux-clang-x86",
|
||||
"compilerPath": "",
|
||||
"configurationProvider": "ms-vscode.makefile-tools",
|
||||
"browse": {
|
||||
"path": [
|
||||
"${workspaceFolder}/include",
|
||||
"${workspaceFolder}/src"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
```
|
@ -230,15 +230,15 @@ struct TEnumerator2 {
|
||||
};
|
||||
|
||||
template <typename T, int I>
|
||||
struct TContainerEnumerator : public TEnumerator2<TLinkList<T, I>::iterator, T> {
|
||||
struct TContainerEnumerator : public TEnumerator2<typename TLinkList<T, I>::iterator, T> {
|
||||
inline TContainerEnumerator(TLinkList<T, I>* param_0)
|
||||
: TEnumerator2<TLinkList<T, I>::iterator, T>(param_0->begin(), param_0->end()) {}
|
||||
: TEnumerator2<typename TLinkList<T, I>::iterator, T>(param_0->begin(), param_0->end()) {}
|
||||
};
|
||||
|
||||
template <typename T, int I>
|
||||
struct TContainerEnumerator_const : public TEnumerator2<TLinkList<T, I>::const_iterator, const T> {
|
||||
struct TContainerEnumerator_const : public TEnumerator2<typename TLinkList<T, I>::const_iterator, const T> {
|
||||
inline TContainerEnumerator_const(const TLinkList<T, I>* param_0)
|
||||
: TEnumerator2<TLinkList<T, I>::const_iterator, const T>(param_0->begin(), param_0->end()) {}
|
||||
: TEnumerator2<typename TLinkList<T, I>::const_iterator, const T>(param_0->begin(), param_0->end()) {}
|
||||
};
|
||||
|
||||
}; // namespace JGadget
|
||||
|
@ -88,6 +88,15 @@ public:
|
||||
inline virtual void draw(T);
|
||||
}; // Size: 0x04
|
||||
|
||||
template<>
|
||||
void JPACallBackBase<JPABaseEmitter*>::init(JPABaseEmitter*) {}
|
||||
template<>
|
||||
void JPACallBackBase<JPABaseEmitter*>::execute(JPABaseEmitter*) {}
|
||||
template<>
|
||||
void JPACallBackBase<JPABaseEmitter*>::executeAfter(JPABaseEmitter*) {}
|
||||
template<>
|
||||
void JPACallBackBase<JPABaseEmitter*>::draw(JPABaseEmitter*) {}
|
||||
|
||||
template<typename T, typename U>
|
||||
class JPACallBackBase2 {
|
||||
public:
|
||||
@ -99,6 +108,13 @@ public:
|
||||
inline virtual void draw(T, U);
|
||||
};
|
||||
|
||||
template<>
|
||||
void JPACallBackBase2<JPABaseEmitter*, JPABaseParticle*>::init(JPABaseEmitter*, JPABaseParticle*) {}
|
||||
template<>
|
||||
void JPACallBackBase2<JPABaseEmitter*, JPABaseParticle*>::execute(JPABaseEmitter*, JPABaseParticle*) {}
|
||||
template<>
|
||||
void JPACallBackBase2<JPABaseEmitter*, JPABaseParticle*>::draw(JPABaseEmitter*, JPABaseParticle*) {}
|
||||
|
||||
struct JPAEmitterInfo {
|
||||
public:
|
||||
JPAEmitterInfo() : mRandom(0) {}
|
||||
@ -393,13 +409,4 @@ public:
|
||||
/* 0x216 */ u16 field_0x216;
|
||||
};
|
||||
|
||||
void JPACallBackBase<JPABaseEmitter*>::init(JPABaseEmitter*) {}
|
||||
void JPACallBackBase<JPABaseEmitter*>::execute(JPABaseEmitter*) {}
|
||||
void JPACallBackBase<JPABaseEmitter*>::executeAfter(JPABaseEmitter*) {}
|
||||
void JPACallBackBase<JPABaseEmitter*>::draw(JPABaseEmitter*) {}
|
||||
|
||||
void JPACallBackBase2<JPABaseEmitter*, JPABaseParticle*>::init(JPABaseEmitter*, JPABaseParticle*) {}
|
||||
void JPACallBackBase2<JPABaseEmitter*, JPABaseParticle*>::execute(JPABaseEmitter*, JPABaseParticle*) {}
|
||||
void JPACallBackBase2<JPABaseEmitter*, JPABaseParticle*>::draw(JPABaseEmitter*, JPABaseParticle*) {}
|
||||
|
||||
#endif /* JPAEMITTER_H */
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define offsetof(type, member) ((size_t) & (((type*)0)->member))
|
||||
#endif
|
||||
|
||||
#ifndef __INTELLISENSE__
|
||||
#ifdef __MWERKS__
|
||||
#define GLUE(a, b) a##b
|
||||
#define GLUE2(a, b) GLUE(a, b)
|
||||
#define STATIC_ASSERT(cond) typedef char GLUE2(static_assertion_failed, __LINE__)[(cond) ? 1 : -1]
|
||||
|
@ -23,4 +23,4 @@ typedef long ptrdiff_t;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -56,17 +56,7 @@ def dtk_url(tag: str) -> str:
|
||||
return f"{repo}/releases/download/{tag}/dtk-{system}-{arch}{suffix}"
|
||||
|
||||
|
||||
def sjiswrap_url(tag: str) -> str:
|
||||
repo = "https://github.com/encounter/sjiswrap"
|
||||
return f"{repo}/releases/download/{tag}/sjiswrap-windows-x86.exe"
|
||||
|
||||
|
||||
def wibo_url(tag: str) -> str:
|
||||
repo = "https://github.com/decompals/wibo"
|
||||
return f"{repo}/releases/download/{tag}/wibo"
|
||||
|
||||
|
||||
def objdiffcli_url(tag: str) -> str:
|
||||
def objdiff_cli_url(tag: str) -> str:
|
||||
uname = platform.uname()
|
||||
suffix = ""
|
||||
system = uname.system.lower()
|
||||
@ -82,13 +72,23 @@ def objdiffcli_url(tag: str) -> str:
|
||||
return f"{repo}/releases/download/{tag}/objdiff-cli-{system}-{arch}{suffix}"
|
||||
|
||||
|
||||
def sjiswrap_url(tag: str) -> str:
|
||||
repo = "https://github.com/encounter/sjiswrap"
|
||||
return f"{repo}/releases/download/{tag}/sjiswrap-windows-x86.exe"
|
||||
|
||||
|
||||
def wibo_url(tag: str) -> str:
|
||||
repo = "https://github.com/decompals/wibo"
|
||||
return f"{repo}/releases/download/{tag}/wibo"
|
||||
|
||||
|
||||
TOOLS: Dict[str, Callable[[str], str]] = {
|
||||
"binutils": binutils_url,
|
||||
"compilers": compilers_url,
|
||||
"dtk": dtk_url,
|
||||
"objdiff-cli": objdiff_cli_url,
|
||||
"sjiswrap": sjiswrap_url,
|
||||
"wibo": wibo_url,
|
||||
"objdiff-cli": objdiffcli_url,
|
||||
}
|
||||
|
||||
|
||||
|
399
tools/project.py
399
tools/project.py
@ -17,7 +17,7 @@ import os
|
||||
import platform
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import IO, 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"]
|
||||
@ -155,15 +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 progress output
|
||||
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,13 +267,26 @@ CHAIN = "cmd /c " if is_windows() else ""
|
||||
EXE = ".exe" if is_windows() else ""
|
||||
|
||||
|
||||
def make_flags_str(flags: Optional[Union[str, List[str]]]) -> str:
|
||||
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 ""
|
||||
elif isinstance(flags, list):
|
||||
return " ".join(flags)
|
||||
else:
|
||||
return flags
|
||||
return " ".join(flags)
|
||||
|
||||
|
||||
# Load decomp-toolkit generated config.json
|
||||
@ -253,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
|
||||
@ -406,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,
|
||||
@ -426,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,
|
||||
@ -445,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:
|
||||
@ -660,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)
|
||||
@ -725,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})")
|
||||
@ -767,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),
|
||||
@ -789,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
|
||||
|
||||
@ -827,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:
|
||||
@ -1274,37 +1344,27 @@ def generate_objdiff_config(
|
||||
|
||||
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"] = {
|
||||
@ -1388,6 +1448,219 @@ def generate_objdiff_config(
|
||||
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()
|
||||
@ -1450,7 +1723,11 @@ def calculate_progress(config: ProjectConfig) -> None:
|
||||
|
||||
print_category("All", report_data["measures"])
|
||||
for category in report_data["categories"]:
|
||||
print_category(category["name"], category["measures"])
|
||||
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"]
|
||||
|
Loading…
Reference in New Issue
Block a user