solDOOM/external/pure_doom/PureDOOM/tools/gen_single_header.py

104 lines
3.4 KiB
Python
Raw Normal View History

# This scripts generates single header doom.
import glob
import re
import os
files = []
code_files = []
done_files = []
final:str = ""
class File:
def __init__(self, filename) -> None:
with open(filename, "r") as file:
self.content = file.read()
# Find headers
self.headers = re.findall(r'#include \"(\w+\.h)\"', self.content)
# Comment out includes
# Special handling is needed for DOOM.c. It includes system headers, and
# we can't comment those out. For DOOM.c, only comment out quoted
# includes. Otherwise, comment all of them.
if os.path.basename(filename) == "DOOM.c":
self.content = re.sub(r'#include[ \t]+\"', '//#include "', self.content)
else:
self.content = re.sub(r'#include', '//#include', self.content)
# Remove copyrighted block of text at the top (We include copyright at the top of the PureDOOM.h)
# This is done by finding the first non-empty line that doesn't start with `//`
# Note the use of `:=`: https://docs.python.org/3/whatsnew/3.8.html#assignment-expressions
if (match := re.search(r'(^|\n)(?!//|\n)', self.content)) is not None:
# Get rid of everything up to and including the first match
# This works because the match is for the character preceeding where
# we should start - either `^` or the preceeding newline.
self.content = self.content[match.end():]
# Clean up some "logs" at the end of the file
self.content = re.sub(r'\/\/-----------------------------------------------------------------------------\n\/\/\n\/\/ \$Log\:\$\n\/\/\n\/\/-----------------------------------------------------------------------------', '', self.content)
self.name = os.path.basename(filename)
def __repr__(self) -> str:
return self.name + " -> " + str(self.headers)
# Collect headers
headers = glob.glob(r'../src/DOOM/*.h')
headers.sort() # To make it predictable
for header in headers:
if header.endswith("DOOM.h") or header.endswith("d_french.h"):
continue # We'll do that one manually later, and first
files.append(File(header))
# Collect code files
codes = glob.glob(r'../src/DOOM/*.c')
codes.sort() # To make it predictable
for code in codes:
code_files.append(File(code))
# Start with DOOM.h
with open("../src/DOOM/DOOM.h", "r") as header:
final += header.read()
print("Concat: DOOM.h")
done_files.append("DOOM.h")
# Concat files as long as there are to concat
while len(files) > 0:
# Find the first file where it's dependencies have been done
found = False
for file in files:
has_dependencies = False
for header in file.headers:
if header not in done_files:
has_dependencies = True
break
if has_dependencies:
continue # Pick a different file
found = True
print("Concat: " + file.name)
final += file.content
done_files.append(file.name)
files.remove(file)
break
if not found:
print("Cycling includes: " + str(files))
exit(1)
final += "\n#if defined(DOOM_IMPLEMENTATION)\n"
# Append all code files after
for file in code_files:
print("Concat: " + file.name)
final += file.content
final += "\n#endif // DOOM_IMPLEMENTATION\n"
# Output single header
with open("../PureDOOM.h", "w") as file:
file.write(final)