2021-04-13 09:47:52 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
2023-06-29 14:06:23 +02:00
|
|
|
from functools import lru_cache
|
2023-02-22 09:22:31 +01:00
|
|
|
import os
|
|
|
|
import shutil
|
2023-07-19 11:01:28 +02:00
|
|
|
from typing import List, Dict, Set, Union
|
2021-04-13 09:47:52 +02:00
|
|
|
from pathlib import Path
|
2021-08-22 23:55:26 +02:00
|
|
|
import subprocess
|
2021-04-13 09:47:52 +02:00
|
|
|
import sys
|
|
|
|
import ninja_syntax
|
|
|
|
from glob import glob
|
|
|
|
|
2021-04-18 15:26:00 +02:00
|
|
|
# Configuration:
|
2023-03-13 00:08:06 +01:00
|
|
|
VERSIONS = ["us", "jp", "ique", "pal"]
|
2021-04-18 15:26:00 +02:00
|
|
|
DO_SHA1_CHECK = True
|
2021-06-21 06:30:57 +02:00
|
|
|
|
2021-04-18 15:26:00 +02:00
|
|
|
# Paths:
|
2021-04-13 09:47:52 +02:00
|
|
|
ROOT = Path(__file__).parent.parent.parent
|
2023-07-13 10:56:16 +02:00
|
|
|
if ROOT.is_absolute():
|
|
|
|
ROOT = ROOT.relative_to(Path.cwd())
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
BUILD_TOOLS = Path("tools/build")
|
2021-04-13 09:47:52 +02:00
|
|
|
YAY0_COMPRESS_TOOL = f"{BUILD_TOOLS}/yay0/Yay0compress"
|
|
|
|
CRC_TOOL = f"{BUILD_TOOLS}/rom/n64crc"
|
|
|
|
|
2023-07-18 10:53:53 +02:00
|
|
|
PIGMENT = "pigment64"
|
2023-07-20 08:18:25 +02:00
|
|
|
PIGMENT_REQ_VERSION = "0.3.0"
|
2023-07-18 10:53:53 +02:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
|
|
|
|
def exec_shell(command: List[str]) -> str:
|
2023-07-18 10:53:53 +02:00
|
|
|
ret = subprocess.run(
|
|
|
|
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
|
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
return ret.stdout
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
|
|
|
|
def write_ninja_rules(
|
|
|
|
ninja: ninja_syntax.Writer,
|
|
|
|
cpp: str,
|
|
|
|
extra_cppflags: str,
|
|
|
|
extra_cflags: str,
|
|
|
|
use_ccache: bool,
|
|
|
|
shift: bool,
|
|
|
|
debug: bool,
|
|
|
|
):
|
2021-04-13 09:47:52 +02:00
|
|
|
# platform-specific
|
|
|
|
|
2021-08-25 20:08:35 +02:00
|
|
|
ccache = ""
|
2021-08-22 23:55:26 +02:00
|
|
|
|
2021-08-25 20:08:35 +02:00
|
|
|
if use_ccache:
|
|
|
|
ccache = "ccache "
|
|
|
|
try:
|
2023-06-26 12:27:37 +02:00
|
|
|
subprocess.call(
|
|
|
|
["ccache"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
|
|
|
|
)
|
2021-08-25 20:08:35 +02:00
|
|
|
except FileNotFoundError:
|
|
|
|
ccache = ""
|
2021-08-22 23:55:26 +02:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
cross = "mips-linux-gnu-"
|
2021-08-24 19:11:05 +02:00
|
|
|
cc = f"{BUILD_TOOLS}/cc/gcc/gcc"
|
2023-06-26 12:27:37 +02:00
|
|
|
cc_modern = f"{cross}gcc"
|
2021-09-25 09:31:44 +02:00
|
|
|
cc_ido = f"{BUILD_TOOLS}/cc/ido5.3/cc"
|
2022-01-29 02:01:26 +01:00
|
|
|
cc_272_dir = f"{BUILD_TOOLS}/cc/gcc2.7.2/"
|
|
|
|
cc_272 = f"{cc_272_dir}/gcc"
|
2021-08-24 19:11:05 +02:00
|
|
|
cxx = f"{BUILD_TOOLS}/cc/gcc/g++"
|
2021-04-13 09:47:52 +02:00
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ICONV = "iconv --from UTF-8 --to $encoding"
|
2021-09-25 09:31:44 +02:00
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
CPPFLAGS_COMMON = (
|
|
|
|
"-Iver/$version/include -Iver/$version/build/include -Iinclude -Isrc -Iassets/$version -D_LANGUAGE_C -D_FINALROM "
|
|
|
|
"-DVERSION=$version -DF3DEX_GBI_2 -D_MIPS_SZLONG=32"
|
|
|
|
)
|
2021-10-22 16:01:27 +02:00
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
CPPFLAGS_272 = CPPFLAGS_COMMON + " -nostdinc"
|
|
|
|
|
|
|
|
CPPFLAGS = "-w " + CPPFLAGS_COMMON + " -nostdinc"
|
2021-06-21 06:30:57 +02:00
|
|
|
|
2022-10-18 13:43:04 +02:00
|
|
|
cflags = f"-c -G0 -O2 -gdwarf-2 -x c -B {BUILD_TOOLS}/cc/gcc/ {extra_cflags}"
|
2023-02-24 05:02:57 +01:00
|
|
|
|
2023-02-22 09:22:31 +01:00
|
|
|
cflags_modern = f"-c -G0 -O2 -gdwarf-2 -fno-builtin-bcopy -fno-tree-loop-distribute-patterns -funsigned-char -mgp32 -mfp32 -mabi=32 -mfix4300 -march=vr4300 -mno-gpopt -fno-toplevel-reorder -mno-abicalls -fno-pic -fno-exceptions -fno-stack-protector -fno-zero-initialized-in-bss -Wno-builtin-declaration-mismatch -x c {extra_cflags}"
|
2023-02-24 05:02:57 +01:00
|
|
|
|
2022-01-29 02:01:26 +01:00
|
|
|
cflags_272 = f"-c -G0 -mgp32 -mfp32 -mips3 {extra_cflags}"
|
2023-06-26 12:27:37 +02:00
|
|
|
cflags_272 = cflags_272.replace("-ggdb3", "-g1")
|
2021-07-28 13:47:05 +02:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
ninja.variable("python", sys.executable)
|
|
|
|
|
2023-02-14 14:14:14 +01:00
|
|
|
ld_args = f"-T ver/$version/build/undefined_syms.txt -T ver/$version/undefined_syms_auto.txt -T ver/$version/undefined_funcs_auto.txt -Map $mapfile --no-check-sections -T $in -o $out"
|
|
|
|
|
|
|
|
if shift:
|
2023-02-22 09:22:31 +01:00
|
|
|
# For the shiftable build, we link twice to resolve some addresses that gnu ld can't figure out all in one go.
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"ld",
|
2023-02-14 14:14:14 +01:00
|
|
|
description="link($version) $out",
|
|
|
|
command=f"{cross}ld $$(tools/build/ld/multilink_calc.py $version hardcode) {ld_args} && \
|
|
|
|
{cross}ld $$(tools/build/ld/multilink_calc.py $version calc) {ld_args}",
|
|
|
|
)
|
|
|
|
else:
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"ld",
|
2023-02-14 14:14:14 +01:00
|
|
|
description="link($version) $out",
|
|
|
|
command=f"{cross}ld {ld_args}",
|
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
|
2023-07-18 11:07:58 +02:00
|
|
|
ninja.rule(
|
|
|
|
"shape_ld",
|
|
|
|
description="link($version) shape $out",
|
|
|
|
command=f"{cross}ld -T src/map_shape.ld $in -o $out",
|
|
|
|
)
|
|
|
|
|
|
|
|
ninja.rule(
|
|
|
|
"shape_objcopy",
|
|
|
|
description="objcopy($version) shape $out",
|
|
|
|
command=f"{cross}objcopy $in $out -O binary",
|
|
|
|
)
|
|
|
|
|
2022-10-28 03:42:27 +02:00
|
|
|
Z64_DEBUG = ""
|
|
|
|
if debug:
|
2023-07-18 11:07:58 +02:00
|
|
|
Z64_DEBUG = " -gS -R .data -R .note -R .eh_frame -R .gnu.attributes -R .comment -R .options"
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"z64",
|
2021-04-13 09:47:52 +02:00
|
|
|
description="rom $out",
|
2023-07-18 11:07:58 +02:00
|
|
|
command=f"{cross}objcopy $in $out -O binary{Z64_DEBUG} && {BUILD_TOOLS}/rom/n64crc $out",
|
2021-04-13 09:47:52 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"z64_ique",
|
2023-02-21 15:37:27 +01:00
|
|
|
description="rom $out",
|
2023-07-18 11:07:58 +02:00
|
|
|
command=f"{cross}objcopy $in $out -O binary{Z64_DEBUG}",
|
2023-02-21 15:37:27 +01:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"sha1sum",
|
2021-06-21 06:30:57 +02:00
|
|
|
description="check $in",
|
2021-08-25 07:08:42 +02:00
|
|
|
command="sha1sum -c $in && touch $out" if DO_SHA1_CHECK else "touch $out",
|
2021-06-21 06:30:57 +02:00
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"cpp", description="cpp $in", command=f"{cpp} $in {extra_cppflags} -P -o $out"
|
2021-08-22 15:10:06 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"cc",
|
2021-10-25 13:44:55 +02:00
|
|
|
description="gcc $in",
|
2023-06-26 12:27:37 +02:00
|
|
|
command=f"bash -o pipefail -c '{cpp} {CPPFLAGS} {extra_cppflags} -DOLD_GCC $cppflags -MD -MF $out.d $in -o - | {ICONV} | {ccache}{cc} {cflags} $cflags - -o $out'",
|
2021-04-13 09:47:52 +02:00
|
|
|
depfile="$out.d",
|
|
|
|
deps="gcc",
|
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"cc_modern",
|
2023-01-31 17:12:03 +01:00
|
|
|
description="gcc $in",
|
2023-06-26 12:27:37 +02:00
|
|
|
command=f"bash -o pipefail -c '{cpp} {CPPFLAGS} {extra_cppflags} $cppflags -MD -MF $out.d $in -o - | {ICONV} | {ccache}{cc_modern} {cflags_modern} $cflags - -o $out'",
|
2023-01-31 17:12:03 +01:00
|
|
|
depfile="$out.d",
|
|
|
|
deps="gcc",
|
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"cc_ido",
|
2021-10-25 13:44:55 +02:00
|
|
|
description="ido $in",
|
2023-02-22 09:22:31 +01:00
|
|
|
command=f"{ccache}{cc_ido} -w {CPPFLAGS_COMMON} {extra_cppflags} $cppflags -c -mips1 -O0 -G0 -non_shared -Xfullwarn -Xcpluscomm -o $out $in",
|
2021-10-22 16:01:27 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"cc_272",
|
2022-01-29 02:01:26 +01:00
|
|
|
description="cc_272 $in",
|
2023-02-22 09:22:31 +01:00
|
|
|
command=f"bash -o pipefail -c 'COMPILER_PATH={cc_272_dir} {cc_272} {CPPFLAGS_272} {extra_cppflags} $cppflags {cflags_272} $cflags $in -o $out && mips-linux-gnu-objcopy -N $in $out'",
|
2021-09-25 09:31:44 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"cxx",
|
2021-08-22 23:55:26 +02:00
|
|
|
description="cxx $in",
|
2023-06-26 12:27:37 +02:00
|
|
|
command=f"bash -o pipefail -c '{cpp} {CPPFLAGS} {extra_cppflags} $cppflags -MD -MF $out.d $in -o - | {ICONV} | {ccache}{cxx} {cflags} $cflags - -o $out'",
|
2021-04-13 09:47:52 +02:00
|
|
|
depfile="$out.d",
|
|
|
|
deps="gcc",
|
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"dead_cc_fix",
|
|
|
|
description="dead_cc_fix $in",
|
2022-09-28 22:52:12 +02:00
|
|
|
command=f"mips-linux-gnu-objcopy --redefine-sym sqrtf=dead_sqrtf $in $out",
|
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"bin",
|
2021-04-13 09:47:52 +02:00
|
|
|
description="bin $in",
|
|
|
|
command=f"{cross}ld -r -b binary $in -o $out",
|
|
|
|
)
|
|
|
|
|
2023-07-18 11:07:58 +02:00
|
|
|
ninja.rule(
|
|
|
|
"cp",
|
|
|
|
description="cp $in $out",
|
|
|
|
command=f"cp $in $out",
|
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"as",
|
2021-04-13 09:47:52 +02:00
|
|
|
description="as $in",
|
2023-07-21 18:53:09 +02:00
|
|
|
command=f"{cpp} {CPPFLAGS} {extra_cppflags} $cppflags $in -o - | {cross}as -EB -march=vr4300 -mtune=vr4300 -Iinclude -o $out",
|
2021-04-13 09:47:52 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"img",
|
2021-04-13 09:47:52 +02:00
|
|
|
description="img($img_type) $in",
|
|
|
|
command=f"$python {BUILD_TOOLS}/img/build.py $img_type $in $out $img_flags",
|
|
|
|
)
|
|
|
|
|
2023-07-18 10:53:53 +02:00
|
|
|
ninja.rule(
|
|
|
|
"pigment",
|
|
|
|
description="img($img_type) $in",
|
2023-07-20 08:18:25 +02:00
|
|
|
command=f"{PIGMENT} to-bin $img_flags -f $img_type -o $out $in",
|
2023-07-18 10:53:53 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"img_header",
|
2021-04-13 09:47:52 +02:00
|
|
|
description="img_header $in",
|
2023-06-26 12:27:37 +02:00
|
|
|
command=f'$python {BUILD_TOOLS}/img/header.py $in $out "$c_name"',
|
2021-04-13 09:47:52 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"bin_inc_c",
|
2021-07-12 11:15:00 +02:00
|
|
|
description="bin_inc_c $out",
|
2023-06-26 12:27:37 +02:00
|
|
|
command=f'$python {BUILD_TOOLS}/bin_inc_c.py $in $out "$c_name"',
|
2021-07-12 11:15:00 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"pal_inc_c",
|
2022-08-10 15:36:38 +02:00
|
|
|
description="pal_inc_c $out",
|
2023-06-26 12:27:37 +02:00
|
|
|
command=f'$python {BUILD_TOOLS}/pal_inc_c.py $in $out "$c_name"',
|
2022-08-10 15:36:38 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"yay0",
|
2021-04-13 09:47:52 +02:00
|
|
|
description="yay0 $in",
|
|
|
|
command=f"{BUILD_TOOLS}/yay0/Yay0compress $in $out",
|
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"npc_sprite",
|
2021-04-13 09:47:52 +02:00
|
|
|
description="sprite $sprite_name",
|
2023-07-10 07:57:27 +02:00
|
|
|
command=f"$python {BUILD_TOOLS}/sprite/npc_sprite.py $out $sprite_name $asset_stack",
|
2021-04-13 09:47:52 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"sprites",
|
|
|
|
description="sprites $out $header_out",
|
|
|
|
command=f"$python {BUILD_TOOLS}/sprite/sprites.py $out $header_out $build_dir $asset_stack",
|
2021-04-13 09:47:52 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"sprite_header",
|
2021-04-13 09:47:52 +02:00
|
|
|
description="sprite_header $sprite_name",
|
2023-07-10 07:57:27 +02:00
|
|
|
command=f"$python {BUILD_TOOLS}/sprite/header.py $out $sprite_name $sprite_id $asset_stack",
|
2021-04-13 09:47:52 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"msg",
|
2021-04-13 09:47:52 +02:00
|
|
|
description="msg $in",
|
|
|
|
command=f"$python {BUILD_TOOLS}/msg/parse_compile.py $in $out",
|
|
|
|
)
|
|
|
|
|
2023-07-22 19:20:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"icons",
|
|
|
|
command=f"$python {BUILD_TOOLS}/pm_icons.py $out $list_path $header_path $asset_stack",
|
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"msg_combine",
|
2021-04-13 09:47:52 +02:00
|
|
|
description="msg_combine $out",
|
|
|
|
command=f"$python {BUILD_TOOLS}/msg/combine.py $out $in",
|
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"mapfs",
|
2021-04-13 09:47:52 +02:00
|
|
|
description="mapfs $out",
|
2021-07-16 13:08:22 +02:00
|
|
|
command=f"$python {BUILD_TOOLS}/mapfs/combine.py $version $out $in",
|
2021-04-13 09:47:52 +02:00
|
|
|
)
|
|
|
|
|
2023-06-29 14:06:23 +02:00
|
|
|
ninja.rule(
|
|
|
|
"tex",
|
|
|
|
description="tex $out",
|
2023-07-13 10:56:16 +02:00
|
|
|
command=f"$python {BUILD_TOOLS}/mapfs/tex.py $out $tex_name $asset_stack",
|
2023-06-29 14:06:23 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"pack_title_data",
|
2021-05-08 08:54:34 +02:00
|
|
|
description="pack_title_data $out",
|
|
|
|
command=f"$python {BUILD_TOOLS}/mapfs/pack_title_data.py $out $in",
|
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"map_header", command=f"$python {BUILD_TOOLS}/mapfs/map_header.py $in > $out"
|
|
|
|
)
|
2021-04-18 15:26:00 +02:00
|
|
|
|
2023-07-18 11:07:58 +02:00
|
|
|
ninja.rule("charset", command=f"$python {BUILD_TOOLS}/pm_charset.py $out $in")
|
2021-07-16 11:28:37 +02:00
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
2023-07-18 11:07:58 +02:00
|
|
|
"charset_palettes",
|
2023-06-26 12:27:37 +02:00
|
|
|
command=f"$python {BUILD_TOOLS}/pm_charset_palettes.py $out $in",
|
|
|
|
)
|
2021-07-16 11:28:37 +02:00
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
2023-07-18 11:07:58 +02:00
|
|
|
"sprite_shading_profiles",
|
2023-06-26 12:27:37 +02:00
|
|
|
command=f"$python {BUILD_TOOLS}/sprite/sprite_shading_profiles.py $in $out $header_path",
|
|
|
|
)
|
2022-11-15 15:55:59 +01:00
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
2023-07-18 11:07:58 +02:00
|
|
|
"imgfx_data", command=f"$python {BUILD_TOOLS}/imgfx/imgfx_data.py $in $out"
|
2023-06-26 12:27:37 +02:00
|
|
|
)
|
2023-04-25 06:55:14 +02:00
|
|
|
|
2023-07-18 11:07:58 +02:00
|
|
|
ninja.rule("shape", command=f"$python {BUILD_TOOLS}/mapfs/shape.py $in $out")
|
|
|
|
|
2021-08-18 18:28:32 +02:00
|
|
|
with Path("tools/permuter_settings.toml").open("w") as f:
|
|
|
|
f.write(
|
2023-07-03 11:35:05 +02:00
|
|
|
f"compiler_command = \"{cc} {CPPFLAGS.replace('$version', 'pal')} {cflags} -DPERMUTER -fforce-addr\"\n"
|
2023-06-26 12:27:37 +02:00
|
|
|
)
|
|
|
|
f.write(
|
|
|
|
f'assembler_command = "{cross}as -EB -march=vr4300 -mtune=vr4300 -Iinclude"\n'
|
|
|
|
)
|
|
|
|
f.write(f'compiler_type = "gcc"\n')
|
|
|
|
f.write(
|
|
|
|
"""
|
2021-08-18 18:28:32 +02:00
|
|
|
[preserve_macros]
|
|
|
|
"gs?[DS]P.*" = "void"
|
|
|
|
OVERRIDE_FLAG_CHECK = "int"
|
|
|
|
OS_K0_TO_PHYSICAL = "int"
|
|
|
|
"G_.*" = "int"
|
|
|
|
"TEXEL.*" = "int"
|
|
|
|
PRIMITIVE = "int"
|
2021-09-22 13:17:46 +02:00
|
|
|
|
|
|
|
[decompme.compilers]
|
|
|
|
"tools/build/cc/gcc/gcc" = "gcc2.8.1"
|
2023-06-26 12:27:37 +02:00
|
|
|
"""
|
|
|
|
)
|
|
|
|
|
2021-08-18 18:28:32 +02:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
def write_ninja_for_tools(ninja: ninja_syntax.Writer):
|
2023-06-26 12:27:37 +02:00
|
|
|
ninja.rule(
|
|
|
|
"cc_tool",
|
2021-04-13 09:47:52 +02:00
|
|
|
description="cc_tool $in",
|
|
|
|
command=f"cc -w $in -O3 -o $out",
|
|
|
|
)
|
|
|
|
|
|
|
|
ninja.build(YAY0_COMPRESS_TOOL, "cc_tool", f"{BUILD_TOOLS}/yay0/Yay0compress.c")
|
|
|
|
ninja.build(CRC_TOOL, "cc_tool", f"{BUILD_TOOLS}/rom/n64crc.c")
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
class Configure:
|
|
|
|
def __init__(self, version: str):
|
|
|
|
self.version = version
|
|
|
|
self.version_path = ROOT / f"ver/{version}"
|
|
|
|
self.linker_entries = None
|
|
|
|
|
2023-02-14 14:14:14 +01:00
|
|
|
def split(self, assets: bool, code: bool, shift: bool, debug: bool):
|
2021-04-13 09:47:52 +02:00
|
|
|
import split
|
|
|
|
|
|
|
|
modes = ["ld"]
|
|
|
|
if assets:
|
2023-06-26 12:27:37 +02:00
|
|
|
modes.extend(
|
|
|
|
[
|
|
|
|
"bin",
|
|
|
|
"yay0",
|
|
|
|
"img",
|
|
|
|
"vtx",
|
|
|
|
"vtx_common",
|
|
|
|
"gfx",
|
|
|
|
"gfx_common",
|
|
|
|
"pm_map_data",
|
2023-07-22 19:20:37 +02:00
|
|
|
"pm_icons",
|
2023-06-26 12:27:37 +02:00
|
|
|
"pm_msg",
|
|
|
|
"pm_sprites",
|
|
|
|
"pm_charset",
|
|
|
|
"pm_charset_palettes",
|
|
|
|
"pm_effect_loads",
|
|
|
|
"pm_effect_shims",
|
|
|
|
"pm_sprite_shading_profiles",
|
|
|
|
"pm_imgfx_data",
|
|
|
|
]
|
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
if code:
|
|
|
|
modes.extend(["code", "c", "data", "rodata"])
|
|
|
|
|
2023-02-22 09:22:31 +01:00
|
|
|
splat_files = [str(self.version_path / "splat.yaml")]
|
2021-10-26 05:26:38 +02:00
|
|
|
if debug:
|
2023-02-22 09:22:31 +01:00
|
|
|
splat_files += [str(self.version_path / "splat-debug.yaml")]
|
2021-10-26 05:26:38 +02:00
|
|
|
|
2023-02-14 14:14:14 +01:00
|
|
|
if shift:
|
2023-02-22 09:22:31 +01:00
|
|
|
splat_files += [str(self.version_path / "splat-shift.yaml")]
|
2023-02-14 14:14:14 +01:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
split.main(
|
2023-02-22 09:22:31 +01:00
|
|
|
splat_files,
|
2021-04-13 09:47:52 +02:00
|
|
|
modes,
|
2021-10-29 19:57:15 +02:00
|
|
|
verbose=False,
|
2021-04-13 09:47:52 +02:00
|
|
|
)
|
2023-02-22 09:22:31 +01:00
|
|
|
self.linker_entries = split.linker_writer.entries
|
2023-06-26 12:27:37 +02:00
|
|
|
self.asset_stack: List[str] = split.config["asset_stack"]
|
2021-04-13 09:47:52 +02:00
|
|
|
|
|
|
|
def build_path(self) -> Path:
|
|
|
|
return Path(f"ver/{self.version}/build")
|
|
|
|
|
2021-08-22 15:10:06 +02:00
|
|
|
def undefined_syms_path(self) -> Path:
|
|
|
|
return self.build_path() / "undefined_syms.txt"
|
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
def elf_path(self) -> Path:
|
|
|
|
# TODO: read basename and build_path from splat.yaml
|
|
|
|
return Path(f"ver/{self.version}/build/papermario.elf")
|
|
|
|
|
|
|
|
def rom_path(self) -> Path:
|
|
|
|
return self.elf_path().with_suffix(".z64")
|
|
|
|
|
|
|
|
def rom_ok_path(self) -> Path:
|
|
|
|
return self.elf_path().with_suffix(".ok")
|
|
|
|
|
|
|
|
def linker_script_path(self) -> Path:
|
|
|
|
# TODO: read from splat.yaml
|
|
|
|
return Path(f"ver/{self.version}/papermario.ld")
|
|
|
|
|
|
|
|
def map_path(self) -> Path:
|
|
|
|
return self.elf_path().with_suffix(".map")
|
|
|
|
|
|
|
|
def resolve_src_paths(self, src_paths: List[Path]) -> List[str]:
|
|
|
|
out = []
|
|
|
|
|
|
|
|
for path in src_paths:
|
2021-04-18 15:26:00 +02:00
|
|
|
path = self.resolve_asset_path(path)
|
2021-04-13 09:47:52 +02:00
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
if path is not None:
|
|
|
|
if path.is_dir():
|
|
|
|
out.extend(glob(str(path) + "/**/*", recursive=True))
|
|
|
|
else:
|
|
|
|
out.append(str(path))
|
2021-04-13 09:47:52 +02:00
|
|
|
|
|
|
|
return out
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
# Given a directory relative to assets/, return a list of all assets in the directory
|
|
|
|
# for all layers of the asset stack
|
|
|
|
def get_asset_list(self, asset_dir: str) -> List[str]:
|
|
|
|
ret: Dict[Path, Path] = {}
|
|
|
|
|
|
|
|
for stack_dir in self.asset_stack:
|
|
|
|
path_stem = f"assets/{stack_dir}/{asset_dir}"
|
|
|
|
|
|
|
|
for p in Path(path_stem).glob("**/*"):
|
|
|
|
glob_part = p.relative_to(path_stem)
|
|
|
|
if glob_part not in ret:
|
|
|
|
ret[glob_part] = p
|
|
|
|
|
|
|
|
return [str(v) for v in ret.values()]
|
|
|
|
|
2023-06-29 14:06:23 +02:00
|
|
|
@lru_cache(maxsize=None)
|
2021-04-18 15:26:00 +02:00
|
|
|
def resolve_asset_path(self, path: Path) -> Path:
|
2023-07-13 10:56:16 +02:00
|
|
|
# Remove nonsense
|
|
|
|
path = Path(os.path.normpath(path))
|
|
|
|
|
2021-04-18 15:26:00 +02:00
|
|
|
parts = list(path.parts)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
if parts[0] != "assets":
|
|
|
|
return path
|
|
|
|
|
|
|
|
for asset_dir in self.asset_stack:
|
|
|
|
parts[1] = asset_dir
|
|
|
|
new_path = Path("/".join(parts))
|
|
|
|
if new_path.exists():
|
|
|
|
return new_path
|
2021-04-18 15:26:00 +02:00
|
|
|
|
|
|
|
return path
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
def write_ninja(
|
|
|
|
self,
|
|
|
|
ninja: ninja_syntax.Writer,
|
|
|
|
skip_outputs: Set[str],
|
|
|
|
non_matching: bool,
|
|
|
|
modern_gcc: bool,
|
2023-07-18 11:07:58 +02:00
|
|
|
c_maps: bool = False,
|
2023-06-26 12:27:37 +02:00
|
|
|
):
|
2021-04-13 09:47:52 +02:00
|
|
|
import segtypes
|
2023-06-26 12:27:37 +02:00
|
|
|
import segtypes.common.c
|
|
|
|
import segtypes.common.bin
|
2021-09-30 11:48:03 +02:00
|
|
|
import segtypes.common.data
|
2023-06-26 12:27:37 +02:00
|
|
|
import segtypes.common.group
|
2023-03-13 00:08:06 +01:00
|
|
|
import segtypes.common.asm
|
2023-06-26 12:27:37 +02:00
|
|
|
import segtypes.n64.header
|
|
|
|
import segtypes.n64.img
|
|
|
|
import segtypes.n64.palette
|
2022-12-11 08:43:29 +01:00
|
|
|
import segtypes.n64.yay0
|
2021-04-13 09:47:52 +02:00
|
|
|
|
|
|
|
assert self.linker_entries is not None
|
|
|
|
|
|
|
|
built_objects = set()
|
|
|
|
generated_headers = []
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
def build(
|
|
|
|
object_paths: Union[Path, List[Path]],
|
|
|
|
src_paths: List[Path],
|
|
|
|
task: str,
|
|
|
|
variables: Dict[str, str] = {},
|
|
|
|
implicit_outputs: List[str] = [],
|
|
|
|
asset_deps: List[str] = [],
|
|
|
|
):
|
2021-04-13 09:47:52 +02:00
|
|
|
if not isinstance(object_paths, list):
|
|
|
|
object_paths = [object_paths]
|
|
|
|
|
|
|
|
object_strs = [str(obj) for obj in object_paths]
|
|
|
|
needs_build = False
|
|
|
|
|
|
|
|
for object_path in object_paths:
|
|
|
|
if object_path.suffixes[-1] == ".o":
|
|
|
|
built_objects.add(str(object_path))
|
2023-06-26 12:27:37 +02:00
|
|
|
elif (
|
|
|
|
object_path.suffixes[-1] == ".h"
|
|
|
|
or task == "bin_inc_c"
|
|
|
|
or task == "pal_inc_c"
|
|
|
|
):
|
2021-04-13 09:47:52 +02:00
|
|
|
generated_headers.append(str(object_path))
|
|
|
|
|
|
|
|
# don't rebuild objects if we've already seen all of them
|
|
|
|
if not str(object_path) in skip_outputs:
|
|
|
|
needs_build = True
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
for i_output in implicit_outputs:
|
|
|
|
if i_output.endswith(".h"):
|
|
|
|
generated_headers.append(i_output)
|
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
if needs_build:
|
|
|
|
skip_outputs.update(object_strs)
|
|
|
|
|
|
|
|
implicit = []
|
|
|
|
order_only = []
|
|
|
|
|
|
|
|
if task == "yay0":
|
|
|
|
implicit.append(YAY0_COMPRESS_TOOL)
|
2023-01-31 17:12:03 +01:00
|
|
|
elif task in ["cc", "cxx", "cc_modern"]:
|
2021-04-13 09:47:52 +02:00
|
|
|
order_only.append("generated_headers_" + self.version)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
inputs = self.resolve_src_paths(src_paths)
|
|
|
|
for dir in asset_deps:
|
|
|
|
inputs.extend(self.get_asset_list(dir))
|
2021-04-13 09:47:52 +02:00
|
|
|
ninja.build(
|
2023-06-26 12:27:37 +02:00
|
|
|
outputs=object_strs, # $out
|
2023-04-25 06:55:14 +02:00
|
|
|
rule=task,
|
2023-07-13 10:56:16 +02:00
|
|
|
inputs=inputs, # $in
|
2021-04-13 09:47:52 +02:00
|
|
|
implicit=implicit,
|
|
|
|
order_only=order_only,
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={"version": self.version, **variables},
|
|
|
|
implicit_outputs=implicit_outputs,
|
2021-04-13 09:47:52 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
# Build objects
|
|
|
|
for entry in self.linker_entries:
|
|
|
|
seg = entry.segment
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
if seg.type == "linker" or seg.type == "linker_offset":
|
|
|
|
continue
|
|
|
|
|
|
|
|
assert entry.object_path is not None
|
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
if isinstance(seg, segtypes.n64.header.N64SegHeader):
|
|
|
|
build(entry.object_path, entry.src_paths, "as")
|
2023-06-26 12:27:37 +02:00
|
|
|
elif isinstance(seg, segtypes.common.asm.CommonSegAsm) or (
|
|
|
|
isinstance(seg, segtypes.common.data.CommonSegData)
|
|
|
|
and not seg.type[0] == "."
|
|
|
|
):
|
|
|
|
build(entry.object_path, entry.src_paths, "as")
|
|
|
|
elif seg.type in ["pm_effect_loads", "pm_effect_shims"]:
|
2021-04-13 09:47:52 +02:00
|
|
|
build(entry.object_path, entry.src_paths, "as")
|
2023-06-26 12:27:37 +02:00
|
|
|
elif isinstance(seg, segtypes.common.c.CommonSegC) or (
|
|
|
|
isinstance(seg, segtypes.common.data.CommonSegData)
|
|
|
|
and seg.type[0] == "."
|
|
|
|
):
|
2021-07-28 13:47:05 +02:00
|
|
|
cflags = None
|
|
|
|
if isinstance(seg.yaml, dict):
|
|
|
|
cflags = seg.yaml.get("cflags")
|
|
|
|
elif len(seg.yaml) >= 4:
|
|
|
|
cflags = seg.yaml[3]
|
|
|
|
|
|
|
|
# default cflags where not specified
|
|
|
|
if cflags is None:
|
|
|
|
if "nusys" in entry.src_paths[0].parts:
|
|
|
|
cflags = ""
|
2023-06-26 12:27:37 +02:00
|
|
|
elif "os" in entry.src_paths[0].parts: # libultra
|
2021-07-28 13:47:05 +02:00
|
|
|
cflags = ""
|
2023-06-26 12:27:37 +02:00
|
|
|
else: # papermario
|
2021-07-28 13:47:05 +02:00
|
|
|
cflags = "-fforce-addr"
|
|
|
|
|
2022-05-27 15:00:53 +02:00
|
|
|
# c
|
2021-04-13 09:47:52 +02:00
|
|
|
task = "cc"
|
2021-08-22 23:55:26 +02:00
|
|
|
if entry.src_paths[0].suffixes[-1] == ".cpp":
|
|
|
|
task = "cxx"
|
2021-10-22 16:01:27 +02:00
|
|
|
|
2023-02-14 14:14:14 +01:00
|
|
|
if modern_gcc:
|
|
|
|
task = "cc_modern"
|
2023-01-31 17:12:03 +01:00
|
|
|
|
2021-09-25 09:31:44 +02:00
|
|
|
if seg.name.endswith("osFlash"):
|
|
|
|
task = "cc_ido"
|
2022-01-29 02:01:26 +01:00
|
|
|
elif "gcc_272" in cflags:
|
|
|
|
task = "cc_272"
|
2023-02-22 09:22:31 +01:00
|
|
|
cflags = cflags.replace("gcc_272", "")
|
2021-07-28 13:47:05 +02:00
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
encoding = (
|
|
|
|
"CP932" # similar to SHIFT-JIS, but includes backslash and tilde
|
|
|
|
)
|
2023-03-08 16:40:22 +01:00
|
|
|
if version == "ique":
|
2023-02-21 15:37:27 +01:00
|
|
|
encoding = "EUC-JP"
|
|
|
|
|
2022-09-28 22:52:12 +02:00
|
|
|
# Dead cod
|
2023-07-20 08:18:25 +02:00
|
|
|
if isinstance(seg.parent.yaml, dict) and seg.parent.yaml.get(
|
|
|
|
"dead_code", False
|
|
|
|
):
|
2022-09-28 22:52:12 +02:00
|
|
|
obj_path = str(entry.object_path)
|
|
|
|
init_obj_path = Path(obj_path + ".dead")
|
2023-06-26 12:27:37 +02:00
|
|
|
build(
|
|
|
|
init_obj_path,
|
|
|
|
entry.src_paths,
|
|
|
|
task,
|
|
|
|
variables={
|
|
|
|
"cflags": cflags,
|
|
|
|
"cppflags": f"-DVERSION_{self.version.upper()}",
|
|
|
|
"encoding": encoding,
|
|
|
|
},
|
|
|
|
)
|
2022-09-28 22:52:12 +02:00
|
|
|
build(
|
|
|
|
entry.object_path,
|
|
|
|
[init_obj_path],
|
2023-06-26 12:27:37 +02:00
|
|
|
"dead_cc_fix",
|
2022-09-28 22:52:12 +02:00
|
|
|
)
|
|
|
|
# Not dead cod
|
|
|
|
else:
|
2023-07-24 17:37:23 +02:00
|
|
|
if non_matching or seg.get_most_parent().name not in [
|
|
|
|
"main",
|
|
|
|
"engine1",
|
|
|
|
"engine2",
|
|
|
|
]:
|
2022-10-16 00:24:05 +02:00
|
|
|
cflags += " -fno-common"
|
2023-06-26 12:27:37 +02:00
|
|
|
build(
|
|
|
|
entry.object_path,
|
|
|
|
entry.src_paths,
|
|
|
|
task,
|
|
|
|
variables={
|
|
|
|
"cflags": cflags,
|
|
|
|
"cppflags": f"-DVERSION_{self.version.upper()}",
|
|
|
|
"encoding": encoding,
|
|
|
|
},
|
|
|
|
)
|
2021-07-12 11:15:00 +02:00
|
|
|
|
|
|
|
# images embedded inside data aren't linked, but they do need to be built into .inc.c files
|
2021-09-30 11:48:03 +02:00
|
|
|
if isinstance(seg, segtypes.common.group.CommonSegGroup):
|
2021-07-12 11:15:00 +02:00
|
|
|
for seg in seg.subsegments:
|
|
|
|
if isinstance(seg, segtypes.n64.img.N64SegImg):
|
|
|
|
flags = ""
|
2022-09-28 22:52:12 +02:00
|
|
|
if seg.n64img.flip_h:
|
2021-07-12 11:15:00 +02:00
|
|
|
flags += "--flip-x "
|
2022-09-28 22:52:12 +02:00
|
|
|
if seg.n64img.flip_v:
|
2021-07-12 11:15:00 +02:00
|
|
|
flags += "--flip-y "
|
|
|
|
|
2022-05-05 16:08:16 +02:00
|
|
|
src_paths = [seg.out_path().relative_to(ROOT)]
|
2021-07-12 11:15:00 +02:00
|
|
|
inc_dir = self.build_path() / "include" / seg.dir
|
2023-06-26 12:27:37 +02:00
|
|
|
bin_path = (
|
|
|
|
self.build_path() / seg.dir / (seg.name + ".png.bin")
|
|
|
|
)
|
2021-07-12 11:15:00 +02:00
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
build(
|
|
|
|
bin_path,
|
|
|
|
src_paths,
|
2023-07-18 10:53:53 +02:00
|
|
|
"pigment",
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={
|
|
|
|
"img_type": seg.type,
|
|
|
|
"img_flags": flags,
|
|
|
|
},
|
|
|
|
)
|
2021-07-12 11:15:00 +02:00
|
|
|
|
2023-07-19 11:01:28 +02:00
|
|
|
assert seg.vram_start is not None, (
|
|
|
|
"img with vram_start unset: " + seg.name
|
|
|
|
)
|
|
|
|
|
2022-06-12 17:33:32 +02:00
|
|
|
c_sym = seg.create_symbol(
|
2023-06-26 12:27:37 +02:00
|
|
|
addr=seg.vram_start,
|
|
|
|
in_segment=True,
|
|
|
|
type="data",
|
|
|
|
define=True,
|
2022-06-12 17:33:32 +02:00
|
|
|
)
|
2022-12-12 13:31:29 +01:00
|
|
|
name = c_sym.name
|
|
|
|
if "namespaced" in seg.args:
|
|
|
|
name = f"N({name[7:]})"
|
|
|
|
vars = {"c_name": name}
|
2023-06-26 12:27:37 +02:00
|
|
|
build(
|
|
|
|
inc_dir / (seg.name + ".png.h"),
|
|
|
|
src_paths,
|
|
|
|
"img_header",
|
|
|
|
vars,
|
|
|
|
)
|
|
|
|
build(
|
|
|
|
inc_dir / (seg.name + ".png.inc.c"),
|
|
|
|
[bin_path],
|
|
|
|
"bin_inc_c",
|
|
|
|
vars,
|
|
|
|
)
|
2021-07-12 11:15:00 +02:00
|
|
|
elif isinstance(seg, segtypes.n64.palette.N64SegPalette):
|
2022-05-05 16:08:16 +02:00
|
|
|
src_paths = [seg.out_path().relative_to(ROOT)]
|
2021-07-12 11:15:00 +02:00
|
|
|
inc_dir = self.build_path() / "include" / seg.dir
|
2023-06-26 12:27:37 +02:00
|
|
|
bin_path = (
|
|
|
|
self.build_path() / seg.dir / (seg.name + ".pal.bin")
|
|
|
|
)
|
2021-07-12 11:15:00 +02:00
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
build(
|
|
|
|
bin_path,
|
|
|
|
src_paths,
|
2023-07-18 10:53:53 +02:00
|
|
|
"pigment",
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={
|
|
|
|
"img_type": seg.type,
|
|
|
|
"img_flags": "",
|
|
|
|
},
|
|
|
|
)
|
2022-06-12 17:33:32 +02:00
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
assert seg.vram_start is not None
|
2022-06-12 17:33:32 +02:00
|
|
|
c_sym = seg.create_symbol(
|
2023-06-26 12:27:37 +02:00
|
|
|
addr=seg.vram_start,
|
|
|
|
in_segment=True,
|
|
|
|
type="data",
|
|
|
|
define=True,
|
2022-06-12 17:33:32 +02:00
|
|
|
)
|
|
|
|
vars = {"c_name": c_sym.name}
|
2023-06-26 12:27:37 +02:00
|
|
|
build(
|
|
|
|
inc_dir / (seg.name + ".pal.inc.c"),
|
|
|
|
[bin_path],
|
|
|
|
"pal_inc_c",
|
|
|
|
vars,
|
|
|
|
)
|
2021-09-30 11:48:03 +02:00
|
|
|
elif isinstance(seg, segtypes.common.bin.CommonSegBin):
|
2021-04-13 09:47:52 +02:00
|
|
|
build(entry.object_path, entry.src_paths, "bin")
|
2022-12-11 08:43:29 +01:00
|
|
|
elif isinstance(seg, segtypes.n64.yay0.N64SegYay0):
|
2023-06-26 12:27:37 +02:00
|
|
|
compressed_path = entry.object_path.with_suffix("") # remove .o
|
2021-04-13 09:47:52 +02:00
|
|
|
build(compressed_path, entry.src_paths, "yay0")
|
|
|
|
build(entry.object_path, [compressed_path], "bin")
|
|
|
|
elif isinstance(seg, segtypes.n64.img.N64SegImg):
|
|
|
|
flags = ""
|
2022-09-28 22:52:12 +02:00
|
|
|
if seg.n64img.flip_h:
|
2021-04-13 09:47:52 +02:00
|
|
|
flags += "--flip-x "
|
2022-09-28 22:52:12 +02:00
|
|
|
if seg.n64img.flip_v:
|
2021-04-13 09:47:52 +02:00
|
|
|
flags += "--flip-y "
|
|
|
|
|
2021-07-12 11:15:00 +02:00
|
|
|
bin_path = entry.object_path.with_suffix(".bin")
|
|
|
|
inc_dir = self.build_path() / "include" / seg.dir
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
build(
|
|
|
|
bin_path,
|
|
|
|
entry.src_paths,
|
2023-07-18 10:53:53 +02:00
|
|
|
"pigment",
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={
|
|
|
|
"img_type": seg.type,
|
|
|
|
"img_flags": flags,
|
|
|
|
},
|
|
|
|
)
|
2021-07-12 11:15:00 +02:00
|
|
|
build(entry.object_path, [bin_path], "bin")
|
2021-04-13 09:47:52 +02:00
|
|
|
|
2022-06-12 17:33:32 +02:00
|
|
|
# c_sym = seg.create_symbol(
|
|
|
|
# addr=seg.vram_start, in_segment=True, type="data", define=True
|
|
|
|
# )
|
|
|
|
# vars = {"c_name": c_sym.name}
|
2021-07-12 11:15:00 +02:00
|
|
|
build(inc_dir / (seg.name + ".png.h"), entry.src_paths, "img_header")
|
2021-04-13 09:47:52 +02:00
|
|
|
elif isinstance(seg, segtypes.n64.palette.N64SegPalette):
|
2021-07-12 11:15:00 +02:00
|
|
|
bin_path = entry.object_path.with_suffix(".bin")
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
build(
|
|
|
|
bin_path,
|
|
|
|
entry.src_paths,
|
2023-07-18 10:53:53 +02:00
|
|
|
"pigment",
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={
|
|
|
|
"img_type": seg.type,
|
|
|
|
"img_flags": "",
|
|
|
|
},
|
|
|
|
)
|
2021-07-12 11:15:00 +02:00
|
|
|
build(entry.object_path, [bin_path], "bin")
|
2023-06-26 12:27:37 +02:00
|
|
|
elif seg.type == "pm_sprites":
|
|
|
|
assert entry.object_path is not None
|
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
sprite_yay0s = []
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
npc_obj_path = entry.object_path.parent / "npc"
|
|
|
|
|
|
|
|
# NPC sprite headers
|
|
|
|
for sprite_id, sprite_dir in enumerate(entry.src_paths[1:], 1):
|
2021-04-13 09:47:52 +02:00
|
|
|
sprite_name = sprite_dir.name
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
bin_path = npc_obj_path / (sprite_name + ".bin")
|
2021-04-13 09:47:52 +02:00
|
|
|
yay0_path = bin_path.with_suffix(".Yay0")
|
|
|
|
sprite_yay0s.append(yay0_path)
|
|
|
|
|
2023-07-10 07:57:27 +02:00
|
|
|
build(
|
|
|
|
bin_path,
|
|
|
|
[sprite_dir],
|
|
|
|
"npc_sprite",
|
|
|
|
variables={
|
|
|
|
"sprite_name": sprite_name,
|
|
|
|
"asset_stack": ",".join(self.asset_stack),
|
|
|
|
},
|
2023-07-13 10:56:16 +02:00
|
|
|
asset_deps=[str(sprite_dir)],
|
2023-07-10 07:57:27 +02:00
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
build(yay0_path, [bin_path], "yay0")
|
2023-07-10 07:57:27 +02:00
|
|
|
|
|
|
|
# NPC sprite header
|
2021-04-13 09:47:52 +02:00
|
|
|
build(
|
2023-06-26 12:27:37 +02:00
|
|
|
self.build_path() / "include/sprite/npc" / (sprite_name + ".h"),
|
|
|
|
[sprite_dir, yay0_path],
|
2021-04-13 09:47:52 +02:00
|
|
|
"sprite_header",
|
2023-07-10 07:57:27 +02:00
|
|
|
variables={
|
|
|
|
"sprite_name": sprite_name,
|
|
|
|
"sprite_id": str(sprite_id),
|
|
|
|
"asset_stack": ",".join(self.asset_stack),
|
|
|
|
},
|
2021-04-13 09:47:52 +02:00
|
|
|
)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
# Sprites .bin
|
|
|
|
sprite_player_header_path = str(
|
|
|
|
self.build_path() / "include/sprite/player.h"
|
|
|
|
)
|
|
|
|
|
|
|
|
build(
|
|
|
|
entry.object_path.with_suffix(".bin"),
|
|
|
|
[entry.src_paths[0], *sprite_yay0s],
|
|
|
|
"sprites",
|
|
|
|
variables={
|
|
|
|
"header_out": sprite_player_header_path,
|
|
|
|
"build_dir": str(
|
|
|
|
self.build_path() / "assets" / self.version / "sprite"
|
|
|
|
),
|
|
|
|
"asset_stack": ",".join(self.asset_stack),
|
|
|
|
},
|
|
|
|
implicit_outputs=[sprite_player_header_path],
|
|
|
|
asset_deps=["sprite/player"],
|
|
|
|
)
|
|
|
|
|
|
|
|
# Sprites .o
|
2021-04-13 09:47:52 +02:00
|
|
|
build(entry.object_path, [entry.object_path.with_suffix(".bin")], "bin")
|
2023-06-26 12:27:37 +02:00
|
|
|
|
2021-07-16 11:28:37 +02:00
|
|
|
elif seg.type == "pm_msg":
|
2021-04-13 09:47:52 +02:00
|
|
|
msg_bins = []
|
|
|
|
|
|
|
|
for section_idx, msg_path in enumerate(entry.src_paths):
|
2023-06-26 12:27:37 +02:00
|
|
|
bin_path = (
|
|
|
|
entry.object_path.with_suffix("") / f"{section_idx:02X}.bin"
|
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
msg_bins.append(bin_path)
|
|
|
|
build(bin_path, [msg_path], "msg")
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
build(
|
|
|
|
[
|
|
|
|
entry.object_path.with_suffix(".bin"),
|
|
|
|
self.build_path() / "include" / "message_ids.h",
|
|
|
|
],
|
|
|
|
msg_bins,
|
|
|
|
"msg_combine",
|
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
build(entry.object_path, [entry.object_path.with_suffix(".bin")], "bin")
|
2023-07-24 17:37:23 +02:00
|
|
|
|
2023-07-22 19:20:37 +02:00
|
|
|
elif seg.type == "pm_icons":
|
|
|
|
# make icons.bin
|
|
|
|
header_path = str(self.build_path() / "include" / "icon_offsets.h")
|
|
|
|
build(
|
|
|
|
entry.object_path.with_suffix(""),
|
|
|
|
entry.src_paths,
|
|
|
|
"icons",
|
|
|
|
variables={
|
|
|
|
"list_path": entry.src_paths[0],
|
|
|
|
"header_path": header_path,
|
|
|
|
"asset_stack": ",".join(self.asset_stack),
|
|
|
|
},
|
|
|
|
implicit_outputs=[header_path],
|
|
|
|
asset_deps=["icon"],
|
|
|
|
)
|
|
|
|
# make icons.bin.o
|
|
|
|
build(entry.object_path, [entry.object_path.with_suffix("")], "bin")
|
|
|
|
|
2021-07-16 11:28:37 +02:00
|
|
|
elif seg.type == "pm_map_data":
|
2023-07-13 10:56:16 +02:00
|
|
|
# flat list of (uncompressed path, compressed? path) pairs
|
|
|
|
bin_yay0s: List[Path] = []
|
2021-05-08 08:54:34 +02:00
|
|
|
src_dir = Path("assets/x") / seg.name
|
2021-04-13 09:47:52 +02:00
|
|
|
|
|
|
|
for path in entry.src_paths:
|
|
|
|
name = path.stem
|
2021-05-08 08:54:34 +02:00
|
|
|
out_dir = entry.object_path.with_suffix("").with_suffix("")
|
|
|
|
bin_path = out_dir / f"{name}.bin"
|
2021-04-13 09:47:52 +02:00
|
|
|
|
|
|
|
if name.startswith("party_"):
|
|
|
|
compress = True
|
2023-06-26 12:27:37 +02:00
|
|
|
build(
|
|
|
|
bin_path,
|
|
|
|
[path],
|
|
|
|
"img",
|
|
|
|
variables={
|
|
|
|
"img_type": "party",
|
|
|
|
"img_flags": "",
|
|
|
|
},
|
|
|
|
)
|
2021-05-08 08:54:34 +02:00
|
|
|
elif name == "title_data":
|
|
|
|
compress = True
|
|
|
|
|
|
|
|
logotype_path = out_dir / "title_logotype.bin"
|
|
|
|
copyright_path = out_dir / "title_copyright.bin"
|
2023-06-26 12:27:37 +02:00
|
|
|
copyright_pal_path = out_dir / "title_copyright.pal" # jp only
|
2021-05-08 08:54:34 +02:00
|
|
|
press_start_path = out_dir / "title_press_start.bin"
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
build(
|
|
|
|
logotype_path,
|
|
|
|
[src_dir / "title/logotype.png"],
|
2023-07-18 10:53:53 +02:00
|
|
|
"pigment",
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={
|
|
|
|
"img_type": "rgba32",
|
2021-07-16 13:08:22 +02:00
|
|
|
"img_flags": "",
|
2023-06-26 12:27:37 +02:00
|
|
|
},
|
|
|
|
)
|
|
|
|
build(
|
|
|
|
press_start_path,
|
|
|
|
[src_dir / "title/press_start.png"],
|
2023-07-18 10:53:53 +02:00
|
|
|
"pigment",
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={
|
2021-07-16 13:08:22 +02:00
|
|
|
"img_type": "ia8",
|
|
|
|
"img_flags": "",
|
2023-06-26 12:27:37 +02:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
if self.version == "jp":
|
|
|
|
build(
|
|
|
|
copyright_path,
|
|
|
|
[src_dir / "title/copyright.png"],
|
2023-07-18 10:53:53 +02:00
|
|
|
"pigment",
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={
|
|
|
|
"img_type": "ci4",
|
|
|
|
"img_flags": "",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
build(
|
|
|
|
copyright_pal_path,
|
|
|
|
[src_dir / "title/copyright.png"],
|
2023-07-18 10:53:53 +02:00
|
|
|
"pigment",
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={
|
|
|
|
"img_type": "palette",
|
|
|
|
"img_flags": "",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
imgs = [
|
|
|
|
logotype_path,
|
|
|
|
copyright_path,
|
|
|
|
press_start_path,
|
|
|
|
copyright_pal_path,
|
|
|
|
]
|
|
|
|
else:
|
|
|
|
build(
|
|
|
|
copyright_path,
|
|
|
|
[src_dir / "title/copyright.png"],
|
2023-07-18 10:53:53 +02:00
|
|
|
"pigment",
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={
|
|
|
|
"img_type": "ia8",
|
|
|
|
"img_flags": "",
|
|
|
|
},
|
|
|
|
)
|
2021-07-16 13:08:22 +02:00
|
|
|
imgs = [logotype_path, copyright_path, press_start_path]
|
|
|
|
|
|
|
|
build(bin_path, imgs, "pack_title_data")
|
2021-04-13 09:47:52 +02:00
|
|
|
elif name.endswith("_bg"):
|
|
|
|
compress = True
|
2023-06-26 12:27:37 +02:00
|
|
|
build(
|
|
|
|
bin_path,
|
|
|
|
[path],
|
|
|
|
"img",
|
|
|
|
variables={
|
|
|
|
"img_type": "bg",
|
|
|
|
"img_flags": "",
|
|
|
|
},
|
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
elif name.endswith("_tex"):
|
|
|
|
compress = False
|
2023-06-29 14:06:23 +02:00
|
|
|
tex_dir = path.parent / name
|
|
|
|
build(
|
|
|
|
bin_path,
|
2023-07-03 11:35:05 +02:00
|
|
|
[tex_dir, path.parent / (name + ".json")],
|
2023-06-29 14:06:23 +02:00
|
|
|
"tex",
|
2023-07-13 10:56:16 +02:00
|
|
|
variables={
|
|
|
|
"tex_name": name,
|
|
|
|
"asset_stack": ",".join(self.asset_stack),
|
|
|
|
},
|
|
|
|
asset_deps=[f"mapfs/tex/{name}"],
|
2023-06-29 14:06:23 +02:00
|
|
|
)
|
2023-07-18 11:07:58 +02:00
|
|
|
elif name.endswith("_shape_built"):
|
|
|
|
base_name = name[:-6]
|
|
|
|
raw_bin_path = self.resolve_asset_path(
|
|
|
|
f"assets/x/mapfs/geom/{base_name}.bin"
|
2023-06-26 12:27:37 +02:00
|
|
|
)
|
2023-07-18 11:07:58 +02:00
|
|
|
bin_path = bin_path.parent / "geom" / (base_name + ".bin")
|
|
|
|
|
|
|
|
if c_maps:
|
|
|
|
# raw bin -> c -> o -> elf -> objcopy -> final bin file
|
|
|
|
c_file_path = (
|
|
|
|
bin_path.parent / "geom" / base_name
|
|
|
|
).with_suffix(".c")
|
|
|
|
o_path = bin_path.parent / "geom" / (base_name + ".o")
|
|
|
|
elf_path = bin_path.parent / "geom" / (base_name + ".elf")
|
|
|
|
|
|
|
|
build(c_file_path, [raw_bin_path], "shape")
|
2021-04-18 15:26:00 +02:00
|
|
|
build(
|
2023-07-18 11:07:58 +02:00
|
|
|
o_path,
|
|
|
|
[c_file_path],
|
|
|
|
"cc" if not modern_gcc else "cc_modern",
|
|
|
|
variables={
|
|
|
|
"cflags": "",
|
|
|
|
"cppflags": f"-DVERSION_{self.version.upper()}",
|
|
|
|
"encoding": "CP932", # similar to SHIFT-JIS, but includes backslash and tilde
|
|
|
|
},
|
2021-04-18 15:26:00 +02:00
|
|
|
)
|
2023-07-18 11:07:58 +02:00
|
|
|
build(elf_path, [o_path], "shape_ld")
|
|
|
|
build(bin_path, [elf_path], "shape_objcopy")
|
|
|
|
else:
|
|
|
|
build(bin_path, [raw_bin_path], "cp")
|
2021-04-18 15:26:00 +02:00
|
|
|
|
|
|
|
compress = True
|
2023-07-18 11:07:58 +02:00
|
|
|
out_dir = out_dir / "geom"
|
2021-04-13 09:47:52 +02:00
|
|
|
else:
|
|
|
|
compress = True
|
|
|
|
bin_path = path
|
|
|
|
|
|
|
|
if compress:
|
2021-07-16 13:08:22 +02:00
|
|
|
yay0_path = out_dir / f"{name}.Yay0"
|
2021-04-13 09:47:52 +02:00
|
|
|
build(yay0_path, [bin_path], "yay0")
|
|
|
|
else:
|
|
|
|
yay0_path = bin_path
|
|
|
|
|
|
|
|
bin_yay0s.append(bin_path)
|
|
|
|
bin_yay0s.append(yay0_path)
|
|
|
|
|
|
|
|
# combine
|
|
|
|
build(entry.object_path.with_suffix(""), bin_yay0s, "mapfs")
|
|
|
|
build(entry.object_path, [entry.object_path.with_suffix("")], "bin")
|
2021-07-16 11:28:37 +02:00
|
|
|
elif seg.type == "pm_charset":
|
|
|
|
rasters = []
|
|
|
|
|
|
|
|
for src_path in entry.src_paths:
|
2023-06-26 12:27:37 +02:00
|
|
|
out_path = (
|
|
|
|
self.build_path()
|
|
|
|
/ seg.dir
|
|
|
|
/ seg.name
|
|
|
|
/ (src_path.stem + ".bin")
|
|
|
|
)
|
|
|
|
build(
|
|
|
|
out_path,
|
|
|
|
[src_path],
|
2023-07-18 10:53:53 +02:00
|
|
|
"pigment",
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={
|
|
|
|
"img_type": "ci4",
|
|
|
|
"img_flags": "",
|
|
|
|
},
|
|
|
|
)
|
2021-07-16 11:28:37 +02:00
|
|
|
rasters.append(out_path)
|
|
|
|
|
2023-07-18 11:07:58 +02:00
|
|
|
build(entry.object_path.with_suffix(""), rasters, "charset")
|
2021-07-16 11:28:37 +02:00
|
|
|
build(entry.object_path, [entry.object_path.with_suffix("")], "bin")
|
|
|
|
elif seg.type == "pm_charset_palettes":
|
|
|
|
palettes = []
|
|
|
|
|
|
|
|
for src_path in entry.src_paths:
|
2023-06-26 12:27:37 +02:00
|
|
|
out_path = (
|
|
|
|
self.build_path()
|
|
|
|
/ seg.dir
|
|
|
|
/ seg.name
|
|
|
|
/ "palette"
|
|
|
|
/ (src_path.stem + ".bin")
|
|
|
|
)
|
|
|
|
build(
|
|
|
|
out_path,
|
|
|
|
[src_path],
|
2023-07-18 10:53:53 +02:00
|
|
|
"pigment",
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={
|
|
|
|
"img_type": "palette",
|
|
|
|
"img_flags": "",
|
|
|
|
},
|
|
|
|
)
|
2021-07-16 11:28:37 +02:00
|
|
|
palettes.append(out_path)
|
|
|
|
|
2023-07-18 11:07:58 +02:00
|
|
|
build(entry.object_path.with_suffix(""), palettes, "charset_palettes")
|
2021-07-16 11:28:37 +02:00
|
|
|
build(entry.object_path, [entry.object_path.with_suffix("")], "bin")
|
2022-11-15 15:55:59 +01:00
|
|
|
elif seg.type == "pm_sprite_shading_profiles":
|
2023-06-26 12:27:37 +02:00
|
|
|
header_path = str(
|
|
|
|
self.build_path() / "include/sprite/sprite_shading_profiles.h"
|
|
|
|
)
|
|
|
|
build(
|
|
|
|
entry.object_path.with_suffix(""),
|
|
|
|
entry.src_paths,
|
2023-07-18 11:07:58 +02:00
|
|
|
"sprite_shading_profiles",
|
2023-06-26 12:27:37 +02:00
|
|
|
implicit_outputs=[header_path],
|
|
|
|
variables={
|
|
|
|
"header_path": header_path,
|
|
|
|
},
|
|
|
|
)
|
2022-11-15 15:55:59 +01:00
|
|
|
build(entry.object_path, [entry.object_path.with_suffix("")], "bin")
|
2023-04-25 06:55:14 +02:00
|
|
|
elif seg.type == "pm_imgfx_data":
|
2023-06-26 12:27:37 +02:00
|
|
|
c_file_path = (
|
|
|
|
Path(f"assets/{self.version}") / "imgfx" / (seg.name + ".c")
|
|
|
|
)
|
2023-07-18 11:07:58 +02:00
|
|
|
build(c_file_path, entry.src_paths, "imgfx_data")
|
2023-04-25 06:55:14 +02:00
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
build(
|
|
|
|
entry.object_path,
|
|
|
|
[c_file_path],
|
|
|
|
"cc" if not modern_gcc else "cc_modern",
|
|
|
|
variables={
|
|
|
|
"cflags": "",
|
|
|
|
"cppflags": f"-DVERSION_{self.version.upper()}",
|
|
|
|
"encoding": "CP932", # similar to SHIFT-JIS, but includes backslash and tilde
|
|
|
|
},
|
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
else:
|
2023-06-26 12:27:37 +02:00
|
|
|
raise Exception(
|
|
|
|
f"don't know how to build {seg.__class__.__name__} '{seg.name}'"
|
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
|
2021-08-22 15:10:06 +02:00
|
|
|
# Run undefined_syms through cpp
|
|
|
|
ninja.build(
|
|
|
|
str(self.undefined_syms_path()),
|
|
|
|
"cpp",
|
2023-06-26 12:27:37 +02:00
|
|
|
str(self.version_path / "undefined_syms.txt"),
|
2021-08-22 15:10:06 +02:00
|
|
|
)
|
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
# Build elf, z64, ok
|
2021-10-26 05:26:38 +02:00
|
|
|
additional_objects = [str(self.undefined_syms_path())]
|
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
ninja.build(
|
|
|
|
str(self.elf_path()),
|
|
|
|
"ld",
|
|
|
|
str(self.linker_script_path()),
|
2023-06-26 12:27:37 +02:00
|
|
|
implicit=[str(obj) for obj in built_objects] + additional_objects,
|
|
|
|
variables={"version": self.version, "mapfile": str(self.map_path())},
|
2021-04-13 09:47:52 +02:00
|
|
|
)
|
2023-02-21 15:37:27 +01:00
|
|
|
|
2023-03-08 16:40:22 +01:00
|
|
|
if self.version == "ique":
|
2023-02-21 15:37:27 +01:00
|
|
|
ninja.build(
|
|
|
|
str(self.rom_path()),
|
|
|
|
"z64_ique",
|
|
|
|
str(self.elf_path()),
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={"version": self.version},
|
2023-02-21 15:37:27 +01:00
|
|
|
)
|
|
|
|
else:
|
|
|
|
ninja.build(
|
|
|
|
str(self.rom_path()),
|
|
|
|
"z64",
|
|
|
|
str(self.elf_path()),
|
|
|
|
implicit=[CRC_TOOL],
|
2023-06-26 12:27:37 +02:00
|
|
|
variables={"version": self.version},
|
2023-02-21 15:37:27 +01:00
|
|
|
)
|
2023-02-14 14:14:14 +01:00
|
|
|
|
|
|
|
if not non_matching:
|
|
|
|
ninja.build(
|
|
|
|
str(self.rom_ok_path()),
|
|
|
|
"sha1sum",
|
|
|
|
f"ver/{self.version}/checksum.sha1",
|
|
|
|
implicit=[str(self.rom_path())],
|
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
|
|
|
|
ninja.build("generated_headers_" + self.version, "phony", generated_headers)
|
|
|
|
|
|
|
|
def make_current(self, ninja: ninja_syntax.Writer):
|
|
|
|
current = Path("ver/current")
|
|
|
|
|
|
|
|
try:
|
|
|
|
current.unlink()
|
|
|
|
except Exception:
|
|
|
|
pass
|
|
|
|
|
|
|
|
current.symlink_to(self.version)
|
|
|
|
|
|
|
|
ninja.build("ver/current/build/papermario.z64", "phony", str(self.rom_path()))
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
if __name__ == "__main__":
|
|
|
|
from argparse import ArgumentParser
|
|
|
|
|
|
|
|
parser = ArgumentParser(description="Paper Mario build.ninja generator")
|
2023-06-26 12:27:37 +02:00
|
|
|
parser.add_argument(
|
|
|
|
"version",
|
|
|
|
nargs="*",
|
|
|
|
default=[],
|
2023-07-24 17:37:23 +02:00
|
|
|
choices=[*VERSIONS, []],
|
2023-06-26 12:27:37 +02:00
|
|
|
help="Version(s) to configure for. Most tools will operate on the first-provided only. Supported versions: "
|
|
|
|
+ ",".join(VERSIONS),
|
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
parser.add_argument("--cpp", help="GNU C preprocessor command")
|
2023-06-26 12:27:37 +02:00
|
|
|
parser.add_argument(
|
|
|
|
"-c",
|
|
|
|
"--clean",
|
|
|
|
action="store_true",
|
|
|
|
help="Delete assets and previously-built files",
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--splat", default="tools/splat", help="Path to splat tool to use"
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--split-code", action="store_true", help="Re-split code segments to asm files"
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--no-split-assets",
|
|
|
|
action="store_true",
|
|
|
|
help="Don't split assets from the baserom(s)",
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"-d", "--debug", action="store_true", help="Generate debugging information"
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"-n",
|
|
|
|
"--non-matching",
|
|
|
|
action="store_true",
|
|
|
|
help="Compile nonmatching code. Combine with --debug for more detailed debug info",
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--shift",
|
|
|
|
action="store_true",
|
|
|
|
help="Build a shiftable version of the game (non-matching)",
|
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--modern-gcc",
|
|
|
|
action="store_true",
|
|
|
|
help="Use modern GCC instead of the original compiler",
|
|
|
|
)
|
2021-08-29 18:48:23 +02:00
|
|
|
parser.add_argument("--ccache", action="store_true", help="Use ccache")
|
2023-07-18 11:07:58 +02:00
|
|
|
parser.add_argument(
|
|
|
|
"--c-maps",
|
|
|
|
action="store_true",
|
|
|
|
help="Convert map binaries to C as part of the build process",
|
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
exec_shell(["make", "-C", str(ROOT / args.splat)])
|
|
|
|
|
|
|
|
# on macOS, /usr/bin/cpp defaults to clang rather than gcc (but we need gcc's)
|
2023-06-26 12:27:37 +02:00
|
|
|
if (
|
|
|
|
args.cpp is None
|
|
|
|
and sys.platform == "darwin"
|
|
|
|
and "Free Software Foundation" not in exec_shell(["cpp", "--version"])
|
|
|
|
):
|
|
|
|
gcc_cpps = ("cpp-14", "cpp-13", "cpp-12", "cpp-11")
|
|
|
|
for ver in gcc_cpps:
|
2023-06-27 01:00:58 +02:00
|
|
|
try:
|
|
|
|
if "Free Software Foundation" in exec_shell([ver, "--version"]):
|
|
|
|
args.cpp = ver
|
|
|
|
break
|
|
|
|
except FileNotFoundError:
|
|
|
|
pass
|
2023-06-26 12:27:37 +02:00
|
|
|
if args.cpp is None:
|
2021-08-09 17:59:05 +02:00
|
|
|
print("error: system C preprocessor is not GNU!")
|
2023-06-26 12:27:37 +02:00
|
|
|
print(
|
|
|
|
"This is a known issue on macOS - only clang's cpp is installed by default."
|
|
|
|
)
|
|
|
|
print(
|
|
|
|
"Use 'brew' to obtain GNU cpp, then run this script again with the --cpp option, e.g."
|
|
|
|
)
|
|
|
|
print(f" ./configure --cpp {gcc_cpps[0]}")
|
2021-08-09 17:59:05 +02:00
|
|
|
exit(1)
|
2021-04-13 09:47:52 +02:00
|
|
|
|
2023-07-18 10:53:53 +02:00
|
|
|
try:
|
|
|
|
version = exec_shell([PIGMENT, "--version"]).split(" ")[1].strip()
|
|
|
|
|
|
|
|
if version < PIGMENT_REQ_VERSION:
|
|
|
|
print(
|
|
|
|
f"error: {PIGMENT} version {PIGMENT_REQ_VERSION} or newer is required, system version is {version}\n"
|
|
|
|
)
|
|
|
|
exit(1)
|
|
|
|
except FileNotFoundError:
|
|
|
|
print(f"error: {PIGMENT} is not installed\n")
|
|
|
|
print(
|
|
|
|
"To build and install it, obtain cargo:\n\tcurl https://sh.rustup.rs -sSf | sh"
|
|
|
|
)
|
|
|
|
print(f"and then run:\n\tcargo install {PIGMENT}")
|
|
|
|
exit(1)
|
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
# default version behaviour is to only do those that exist
|
|
|
|
if len(args.version) > 0:
|
|
|
|
versions = args.version
|
|
|
|
else:
|
|
|
|
versions = []
|
|
|
|
|
|
|
|
for version in VERSIONS:
|
|
|
|
rom = ROOT / f"ver/{version}/baserom.z64"
|
|
|
|
|
2021-08-18 19:10:11 +02:00
|
|
|
print(f"configure: looking for baserom {rom.relative_to(ROOT)}", end="")
|
2021-04-13 09:47:52 +02:00
|
|
|
|
|
|
|
if rom.exists():
|
|
|
|
print("...found")
|
|
|
|
versions.append(version)
|
|
|
|
else:
|
|
|
|
print("...missing")
|
|
|
|
|
|
|
|
if len(versions) == 0:
|
|
|
|
print("error: no baseroms found")
|
|
|
|
exit(1)
|
|
|
|
|
|
|
|
if args.clean:
|
|
|
|
print("configure: cleaning...")
|
|
|
|
|
|
|
|
exec_shell(["ninja", "-t", "clean"])
|
|
|
|
|
|
|
|
for version in versions:
|
2023-02-22 09:22:31 +01:00
|
|
|
shutil.rmtree(ROOT / f"assets/{version}", ignore_errors=True)
|
|
|
|
shutil.rmtree(ROOT / f"ver/{version}/assets", ignore_errors=True)
|
|
|
|
shutil.rmtree(ROOT / f"ver/{version}/build", ignore_errors=True)
|
2023-03-06 08:44:48 +01:00
|
|
|
try:
|
|
|
|
os.remove(ROOT / f"ver/{version}/.splat_cache")
|
|
|
|
except OSError:
|
|
|
|
pass
|
2021-04-13 09:47:52 +02:00
|
|
|
|
2023-02-22 09:22:31 +01:00
|
|
|
extra_cflags = ""
|
|
|
|
extra_cppflags = ""
|
2021-07-28 13:47:05 +02:00
|
|
|
if args.non_matching:
|
2023-02-22 09:22:31 +01:00
|
|
|
extra_cppflags += " -DNON_MATCHING"
|
2021-07-28 13:47:05 +02:00
|
|
|
|
|
|
|
if args.debug:
|
2023-06-26 12:27:37 +02:00
|
|
|
extra_cflags += " -ggdb3" # we can generate more accurate debug info in non-matching mode
|
|
|
|
extra_cppflags += " -DDEBUG" # e.g. affects ASSERT macro
|
2021-07-28 13:47:05 +02:00
|
|
|
elif args.debug:
|
|
|
|
# g1 doesn't affect codegen
|
2023-02-22 09:22:31 +01:00
|
|
|
extra_cflags += " -ggdb3"
|
2021-07-28 13:47:05 +02:00
|
|
|
|
2023-01-17 00:03:23 +01:00
|
|
|
if args.shift:
|
2023-02-22 09:22:31 +01:00
|
|
|
extra_cppflags += " -DSHIFT"
|
2023-02-14 14:14:14 +01:00
|
|
|
|
2023-07-21 18:53:09 +02:00
|
|
|
extra_cflags += " -Wmissing-braces -Wimplicit -Wredundant-decls -Wstrict-prototypes -Wno-redundant-decls"
|
2021-08-25 14:34:03 +02:00
|
|
|
|
2021-04-13 09:47:52 +02:00
|
|
|
# add splat to python import path
|
2023-05-09 05:48:11 +02:00
|
|
|
sys.path.insert(0, str((ROOT / args.splat).resolve()))
|
2021-04-13 09:47:52 +02:00
|
|
|
|
|
|
|
ninja = ninja_syntax.Writer(open(str(ROOT / "build.ninja"), "w"), width=9999)
|
|
|
|
|
2023-02-14 14:14:14 +01:00
|
|
|
non_matching = args.non_matching or args.modern_gcc or args.shift
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
write_ninja_rules(
|
|
|
|
ninja,
|
|
|
|
args.cpp or "cpp",
|
|
|
|
extra_cppflags,
|
|
|
|
extra_cflags,
|
|
|
|
args.ccache,
|
|
|
|
args.shift,
|
|
|
|
args.debug,
|
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
write_ninja_for_tools(ninja)
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
skip_files: Set[str] = set()
|
2021-04-13 09:47:52 +02:00
|
|
|
all_rom_oks: List[str] = []
|
|
|
|
first_configure = None
|
|
|
|
|
|
|
|
for version in versions:
|
|
|
|
print(f"configure: configuring version {version}")
|
|
|
|
|
|
|
|
configure = Configure(version)
|
|
|
|
|
|
|
|
if not first_configure:
|
|
|
|
first_configure = configure
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
# include tools/splat_ext in the python path
|
|
|
|
sys.path.append(str((ROOT / "tools/splat_ext").resolve()))
|
|
|
|
|
|
|
|
configure.split(
|
|
|
|
not args.no_split_assets, args.split_code, args.shift, args.debug
|
|
|
|
)
|
2023-07-18 11:07:58 +02:00
|
|
|
configure.write_ninja(
|
|
|
|
ninja, skip_files, non_matching, args.modern_gcc, args.c_maps
|
|
|
|
)
|
2021-04-13 09:47:52 +02:00
|
|
|
|
|
|
|
all_rom_oks.append(str(configure.rom_ok_path()))
|
|
|
|
|
2023-06-26 12:27:37 +02:00
|
|
|
assert first_configure
|
2021-04-13 09:47:52 +02:00
|
|
|
first_configure.make_current(ninja)
|
|
|
|
|
2023-02-14 14:14:14 +01:00
|
|
|
if non_matching:
|
|
|
|
ninja.build("all", "phony", [str(first_configure.rom_path())])
|
|
|
|
else:
|
|
|
|
ninja.build("all", "phony", all_rom_oks)
|
2021-04-13 09:47:52 +02:00
|
|
|
ninja.default("all")
|