decompctx: Automatic includes from cflags, respect #pragma once
Resolves #23, #43
This commit is contained in:
parent
065fc7b715
commit
d34e7c95db
|
@ -18,58 +18,63 @@ from typing import List
|
||||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
root_dir = os.path.abspath(os.path.join(script_dir, ".."))
|
root_dir = os.path.abspath(os.path.join(script_dir, ".."))
|
||||||
src_dir = os.path.join(root_dir, "src")
|
src_dir = os.path.join(root_dir, "src")
|
||||||
include_dirs = [
|
include_dirs: List[str] = [] # Set with -I flag
|
||||||
os.path.join(root_dir, "include"),
|
|
||||||
# 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+(.*)$")
|
guard_pattern = re.compile(r"^#\s*ifndef\s+(.*)$")
|
||||||
|
once_pattern = re.compile(r"^#\s*pragma\s+once$")
|
||||||
|
|
||||||
defines = set()
|
defines = set()
|
||||||
|
deps = []
|
||||||
|
|
||||||
|
|
||||||
def import_h_file(in_file: str, r_path: str, deps: List[str]) -> str:
|
def import_h_file(in_file: str, r_path: str) -> str:
|
||||||
rel_path = os.path.join(root_dir, r_path, in_file)
|
rel_path = os.path.join(root_dir, r_path, in_file)
|
||||||
if os.path.exists(rel_path):
|
if os.path.exists(rel_path):
|
||||||
return import_c_file(rel_path, deps)
|
return import_c_file(rel_path)
|
||||||
for include_dir in include_dirs:
|
for include_dir in include_dirs:
|
||||||
inc_path = os.path.join(include_dir, in_file)
|
inc_path = os.path.join(include_dir, in_file)
|
||||||
if os.path.exists(inc_path):
|
if os.path.exists(inc_path):
|
||||||
return import_c_file(inc_path, deps)
|
return import_c_file(inc_path)
|
||||||
else:
|
else:
|
||||||
print("Failed to locate", in_file)
|
print("Failed to locate", in_file)
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def import_c_file(in_file: str, deps: List[str]) -> str:
|
def import_c_file(in_file: str) -> str:
|
||||||
in_file = os.path.relpath(in_file, root_dir)
|
in_file = os.path.relpath(in_file, root_dir)
|
||||||
deps.append(in_file)
|
deps.append(in_file)
|
||||||
out_text = ""
|
out_text = ""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(in_file, encoding="utf-8") as file:
|
with open(in_file, encoding="utf-8") as file:
|
||||||
out_text += process_file(in_file, list(file), deps)
|
out_text += process_file(in_file, list(file))
|
||||||
except Exception:
|
except Exception:
|
||||||
with open(in_file) as file:
|
with open(in_file) as file:
|
||||||
out_text += process_file(in_file, list(file), deps)
|
out_text += process_file(in_file, list(file))
|
||||||
return out_text
|
return out_text
|
||||||
|
|
||||||
|
|
||||||
def process_file(in_file: str, lines: List[str], deps: List[str]) -> str:
|
def process_file(in_file: str, lines: List[str]) -> str:
|
||||||
out_text = ""
|
out_text = ""
|
||||||
for idx, line in enumerate(lines):
|
for idx, line in enumerate(lines):
|
||||||
guard_match = guard_pattern.match(line.strip())
|
|
||||||
if idx == 0:
|
if idx == 0:
|
||||||
|
guard_match = guard_pattern.match(line.strip())
|
||||||
if guard_match:
|
if guard_match:
|
||||||
if guard_match[1] in defines:
|
if guard_match[1] in defines:
|
||||||
break
|
break
|
||||||
defines.add(guard_match[1])
|
defines.add(guard_match[1])
|
||||||
|
else:
|
||||||
|
once_match = once_pattern.match(line.strip())
|
||||||
|
if once_match:
|
||||||
|
if in_file in defines:
|
||||||
|
break
|
||||||
|
defines.add(in_file)
|
||||||
print("Processing file", in_file)
|
print("Processing file", in_file)
|
||||||
include_match = include_pattern.match(line.strip())
|
include_match = include_pattern.match(line.strip())
|
||||||
if include_match and not include_match[1].endswith(".s"):
|
if include_match and not include_match[1].endswith(".s"):
|
||||||
out_text += f'/* "{in_file}" line {idx} "{include_match[1]}" */\n'
|
out_text += f'/* "{in_file}" line {idx} "{include_match[1]}" */\n'
|
||||||
out_text += import_h_file(include_match[1], os.path.dirname(in_file), deps)
|
out_text += import_h_file(include_match[1], os.path.dirname(in_file))
|
||||||
out_text += f'/* end "{include_match[1]}" */\n'
|
out_text += f'/* end "{include_match[1]}" */\n'
|
||||||
else:
|
else:
|
||||||
out_text += line
|
out_text += line
|
||||||
|
@ -100,10 +105,19 @@ def main():
|
||||||
"--depfile",
|
"--depfile",
|
||||||
help="""Dependency file""",
|
help="""Dependency file""",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-I",
|
||||||
|
"--include",
|
||||||
|
help="""Include directory""",
|
||||||
|
action="append",
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
deps = []
|
if args.include is None:
|
||||||
output = import_c_file(args.c_file, deps)
|
exit("No include directories specified")
|
||||||
|
global include_dirs
|
||||||
|
include_dirs = args.include
|
||||||
|
output = import_c_file(args.c_file)
|
||||||
|
|
||||||
with open(os.path.join(root_dir, args.output), "w", encoding="utf-8") as f:
|
with open(os.path.join(root_dir, args.output), "w", encoding="utf-8") as f:
|
||||||
f.write(output)
|
f.write(output)
|
||||||
|
|
|
@ -176,7 +176,9 @@ class ProjectConfig:
|
||||||
True # Generate compile_commands.json for clangd
|
True # Generate compile_commands.json for clangd
|
||||||
)
|
)
|
||||||
self.extra_clang_flags: List[str] = [] # Extra flags for clangd
|
self.extra_clang_flags: List[str] = [] # Extra flags for clangd
|
||||||
self.scratch_preset_id: Optional[int] = None # Default decomp.me preset ID for scratches
|
self.scratch_preset_id: Optional[int] = (
|
||||||
|
None # Default decomp.me preset ID for scratches
|
||||||
|
)
|
||||||
|
|
||||||
# Progress output, progress.json and report.json config
|
# Progress output, progress.json and report.json config
|
||||||
self.progress = True # Enable report.json generation and CLI progress output
|
self.progress = True # Enable report.json generation and CLI progress output
|
||||||
|
@ -380,7 +382,7 @@ def generate_build_ninja(
|
||||||
decompctx = config.tools_dir / "decompctx.py"
|
decompctx = config.tools_dir / "decompctx.py"
|
||||||
n.rule(
|
n.rule(
|
||||||
name="decompctx",
|
name="decompctx",
|
||||||
command=f"$python {decompctx} $in -o $out -d $out.d",
|
command=f"$python {decompctx} $in -o $out -d $out.d $includes",
|
||||||
description="CTX $in",
|
description="CTX $in",
|
||||||
depfile="$out.d",
|
depfile="$out.d",
|
||||||
deps="gcc",
|
deps="gcc",
|
||||||
|
@ -809,10 +811,8 @@ def generate_build_ninja(
|
||||||
else:
|
else:
|
||||||
extra_cflags.insert(0, "-lang=c")
|
extra_cflags.insert(0, "-lang=c")
|
||||||
|
|
||||||
cflags_str = make_flags_str(cflags)
|
all_cflags = cflags + extra_cflags
|
||||||
if len(extra_cflags) > 0:
|
cflags_str = make_flags_str(all_cflags)
|
||||||
extra_cflags_str = make_flags_str(extra_cflags)
|
|
||||||
cflags_str += " " + extra_cflags_str
|
|
||||||
used_compiler_versions.add(obj.options["mw_version"])
|
used_compiler_versions.add(obj.options["mw_version"])
|
||||||
|
|
||||||
# Add MWCC build rule
|
# Add MWCC build rule
|
||||||
|
@ -836,11 +836,21 @@ def generate_build_ninja(
|
||||||
|
|
||||||
# Add ctx build rule
|
# Add ctx build rule
|
||||||
if obj.ctx_path is not None:
|
if obj.ctx_path is not None:
|
||||||
|
include_dirs = []
|
||||||
|
for flag in all_cflags:
|
||||||
|
if (
|
||||||
|
flag.startswith("-i ")
|
||||||
|
or flag.startswith("-I ")
|
||||||
|
or flag.startswith("-I+")
|
||||||
|
):
|
||||||
|
include_dirs.append(flag[3:])
|
||||||
|
includes = " ".join([f"-I {d}" for d in include_dirs])
|
||||||
n.build(
|
n.build(
|
||||||
outputs=obj.ctx_path,
|
outputs=obj.ctx_path,
|
||||||
rule="decompctx",
|
rule="decompctx",
|
||||||
inputs=src_path,
|
inputs=src_path,
|
||||||
implicit=decompctx,
|
implicit=decompctx,
|
||||||
|
variables={"includes": includes},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add host build rule
|
# Add host build rule
|
||||||
|
@ -1358,9 +1368,21 @@ def generate_objdiff_config(
|
||||||
unit_config["base_path"] = obj.src_obj_path
|
unit_config["base_path"] = obj.src_obj_path
|
||||||
unit_config["metadata"]["source_path"] = obj.src_path
|
unit_config["metadata"]["source_path"] = obj.src_path
|
||||||
|
|
||||||
cflags = obj.options["cflags"]
|
# Filter out include directories
|
||||||
|
def keep_flag(flag):
|
||||||
|
return (
|
||||||
|
not flag.startswith("-i ")
|
||||||
|
and not flag.startswith("-i-")
|
||||||
|
and not flag.startswith("-I ")
|
||||||
|
and not flag.startswith("-I+")
|
||||||
|
and not flag.startswith("-I-")
|
||||||
|
)
|
||||||
|
|
||||||
|
all_cflags = list(
|
||||||
|
filter(keep_flag, obj.options["cflags"] + obj.options["extra_cflags"])
|
||||||
|
)
|
||||||
reverse_fn_order = False
|
reverse_fn_order = False
|
||||||
for flag in cflags:
|
for flag in all_cflags:
|
||||||
if not flag.startswith("-inline "):
|
if not flag.startswith("-inline "):
|
||||||
continue
|
continue
|
||||||
for value in flag.split(" ")[1].split(","):
|
for value in flag.split(" ")[1].split(","):
|
||||||
|
@ -1369,20 +1391,11 @@ def generate_objdiff_config(
|
||||||
elif value == "nodeferred":
|
elif value == "nodeferred":
|
||||||
reverse_fn_order = False
|
reverse_fn_order = False
|
||||||
|
|
||||||
# Filter out include directories
|
|
||||||
def keep_flag(flag):
|
|
||||||
return not flag.startswith("-i ") and not flag.startswith("-I ")
|
|
||||||
|
|
||||||
cflags = list(filter(keep_flag, cflags))
|
|
||||||
|
|
||||||
compiler_version = COMPILER_MAP.get(obj.options["mw_version"])
|
compiler_version = COMPILER_MAP.get(obj.options["mw_version"])
|
||||||
if compiler_version is None:
|
if compiler_version is None:
|
||||||
print(f"Missing scratch compiler mapping for {obj.options['mw_version']}")
|
print(f"Missing scratch compiler mapping for {obj.options['mw_version']}")
|
||||||
else:
|
else:
|
||||||
cflags_str = make_flags_str(cflags)
|
cflags_str = make_flags_str(all_cflags)
|
||||||
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"] = {
|
unit_config["scratch"] = {
|
||||||
"platform": "gc_wii",
|
"platform": "gc_wii",
|
||||||
"compiler": compiler_version,
|
"compiler": compiler_version,
|
||||||
|
|
Loading…
Reference in New Issue