[WS] Use tup to build projects

git-svn-id: svn://kolibrios.org@9377 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Magomed Kostoev (mkostoevr) 2021-12-03 21:20:06 +00:00
parent 84837f41d5
commit 4bf8ca235a
5 changed files with 73 additions and 155 deletions

View File

@ -10,6 +10,9 @@ if len(sys.argv) < 2 or sys.argv[1] != "--remove-everything":
# Remove workspace folder # Remove workspace folder
shutil.rmtree("workspace", ignore_errors = True) shutil.rmtree("workspace", ignore_errors = True)
# Remove tup database
shutil.rmtree(".tup", ignore_errors = True)
# TODO: Make build.py remove the stuff it built # TODO: Make build.py remove the stuff it built
# Remove files copied from _tools/workspace # Remove files copied from _tools/workspace

View File

@ -32,3 +32,6 @@ if __name__ == "__main__":
tools_workspace_build_py = os.path.join(tools_workspace, "build.py") tools_workspace_build_py = os.path.join(tools_workspace, "build.py")
create_workspace_script("run.py", tools_workspace_run_py) create_workspace_script("run.py", tools_workspace_run_py)
create_workspace_script("build.py", tools_workspace_build_py) create_workspace_script("build.py", tools_workspace_build_py)
# Initalize tup here
# TODO: Do anything if tup doesn't exist
os.system("tup init")

View File

@ -1,153 +1,74 @@
# Copyright Magomed Kostoev # Copyright Magomed Kostoev
# Published under MIT license # Published under MIT license
class Rule: block_beginner2finisher = {
pass "(": ")",
"{": "}",
"\"": "\"",
}
def get_config(config_name): def get_to(src, ptr, c, backwards = False):
if config_name == "KPACK_CMD": while src[ptr] != c:
# Just never pack the file for now if not backwards:
return "" ptr += 1
else: else:
print(f"Unknown config name: {config_name}") ptr -= 1
exit(-1) return ptr
def skip_whitespaces(src, ptr): # Assuming we are at beginning of some block (string,
while len(src) > ptr and src[ptr] == " ": # parenthesed expression, {}-like thing), get to end
# of the block (also handles the blocks openned in the
# way to the block ending character. So it's not just
# stupid searching for block closing character.
def get_to_block_finisher(src, ptr):
assert(src[ptr] in block_beginner2finisher)
block_beginner = src[ptr]
ptr += 1
while src[ptr] != block_beginner2finisher[block_beginner]:
# If any block starts here - get to its end and then continue
if src[ptr] in block_beginner2finisher:
ptr = get_to_block_finisher(src, ptr)
ptr += 1 ptr += 1
return ptr return ptr
# Returns True if @src has @string starting from @ptr index def get_strnig(src, ptr):
def match_string(src, ptr, string): # Strings starts with "\""
if len(src) <= ptr + len(string): assert(src[ptr] == "\"")
return False
for i in range(len(string)):
if src[ptr + i] != string[i]:
return False
return True
def parse_tup_getconfig(src, ptr): result = ""
# Skip get straight to the argument # Skip first "\"" of the string
ptr += len("tup.getconfig(")
ptr = skip_whitespaces(src, ptr)
if src[ptr] != "\"":
print("Expected \"config name\" as tup.getconfig parameter")
exit()
(config_name, ptr) = parse_string(src, ptr)
ptr = skip_whitespaces(src, ptr)
# Skip closing parenthese of the tup.getconfig call
assert(src[ptr] == ")")
ptr += 1 ptr += 1
return (get_config(config_name), ptr)
def parse_string(src, ptr):
ptr += 1
string = ""
while src[ptr] != "\"": while src[ptr] != "\"":
string += src[ptr] result += src[ptr]
ptr += 1 ptr += 1
# Skip the closing "\""
ptr += 1
ptr = skip_whitespaces(src, ptr)
# Check if we have concatination here
if match_string(src, ptr, ".."):
# Skip the ".."
ptr += 2
# The expression parsing should result in a string
(string_to_add, ptr) = parse_expression(src, ptr)
# Concat our string to the resulting string
string += string_to_add
return (string, ptr)
def parse_expression(src, ptr):
ptr = skip_whitespaces(src, ptr)
result = "WAT?!"
if src[ptr] == "\"":
(result, ptr) = parse_string(src, ptr)
elif match_string(src, ptr, "tup.getconfig("):
(result, ptr) = parse_tup_getconfig(src, ptr)
else:
print(f"Can't handle anything starting with '{src[ptr]}'")
exit(-1)
ptr = skip_whitespaces(src, ptr)
return (result, ptr)
def expect_comma(src, ptr):
comma_skept = False
ptr = skip_whitespaces(src, ptr)
if src[ptr] == ",":
ptr += 1
return (True, ptr)
else:
return (False, ptr)
def parse_arguments(src, ptr):
result = []
# Parse first argument
(argument, ptr) = parse_expression(src, ptr)
result.append(argument)
(comma_encoutered, ptr) = expect_comma(src, ptr)
# Parse the second argument if it's there
if comma_encoutered:
(argument, ptr) = parse_expression(src, ptr)
result.append(argument)
(comma_encoutered, ptr) = expect_comma(src, ptr)
# Parse third argument if it's there
if comma_encoutered:
(argument, ptr) = parse_expression(src, ptr)
result.append(argument)
return result return result
def parse_rule(src, ptr): def parse_rule_output(src, ptr):
# Get straight to the first argument # Get straight to the first argument
ptr += len("tup.rule(") ptr += len("tup.rule")
# Parse the arguments # Get to parenthese
args = parse_arguments(src, ptr) ptr = get_to(src, ptr, "(")
# Build the rule object # Get to the closing parenthese
result = Rule() ptr = get_to_block_finisher(src, ptr)
if len(args) == 3: # We are at closing parenthese of argument list
result.input = args[0] # And the last argument is always output file
result.command = args[1] # Let's get to closing "\"" of the output file name
result.output = args[2] ptr = get_to(src, ptr, "\"", backwards = True)
# Replace %f with input file in rule's command # Get into the string
if type(result.input == str): ptr -= 1
result.command = result.command.replace("%f", result.input) # Then get to the beginning of the string
else: ptr = get_to(src, ptr, "\"", backwards = True)
print("Command building with non-string tup.rule's first argument" # Now we can read the string
+ " isn't implemented") return get_strnig(src, ptr)
exit()
# Replace %o with output file in rule's command
if type(result.output == str):
result.command = result.command.replace("%o", result.output)
else:
print("Command building with non-string tup.rule's first argument"
+ " isn't implemented")
exit()
elif len(args) == 2:
result.input = []
result.command = args[0]
result.output = args[1]
else:
print(f"tup.rule can only take 2 or 3 arguments, not {len(args)}")
exit(-1)
# Unify the API - return arrays as input and output
if type(result.input) == str:
result.input = [ result.input ]
else:
assert(type(result.input) == list)
if type(result.output) == str:
result.output = [ result.output ]
else:
assert(type(result.output) == list)
return result
def parse(file_name): def parse_tupfile_outputs(file_name):
rules = [] outputs = []
with open(file_name) as f: with open(file_name) as f:
tupfile = f.read() tupfile = f.read()
rule_begin_index = tupfile.find("tup.rule(") rule_begin_index = tupfile.find("tup.rule(")
while (rule_begin_index != -1): while (rule_begin_index != -1):
rules.append(parse_rule(tupfile, rule_begin_index)) outputs.append(parse_rule_output(tupfile, rule_begin_index))
# Find the next tup.rule call # Find the next tup.rule call
rule_begin_index = tupfile.find("tup.rule(", rule_begin_index + len("tup.rule(")) rule_begin_index = tupfile.find("tup.rule(", rule_begin_index + len("tup.rule("))
return rules return outputs

View File

@ -5,21 +5,15 @@ path_to_tools_workspace = os.path.dirname(os.path.abspath(__file__))
path_to_tools = os.path.dirname(path_to_tools_workspace) path_to_tools = os.path.dirname(path_to_tools_workspace)
sys.path.append(path_to_tools) sys.path.append(path_to_tools)
from lib.tupfile_parser import parse as parse_tupfile from lib.tupfile_parser import parse_tupfile_outputs
def build(): def build():
if not os.path.exists("Tupfile.lua"): os.system("tup")
print("No Tupfile.lua, can't build anything") outputs = parse_tupfile_outputs("Tupfile.lua")
exit() for name in outputs:
if name.endswith(".inc"):
tup_rules = parse_tupfile("Tupfile.lua") continue
program_files = [] return name
for rule in tup_rules:
# TODO: Manage source dependencies
# TODO: Inform about tools required for the build
os.system(rule.command)
program_files += rule.output
return program_files
if __name__ == "__main__": if __name__ == "__main__":
build() build()

View File

@ -51,7 +51,7 @@ def run_qemu(start_dir = "workspace"):
return subprocess.Popen(a, bufsize = 0, stdout = qemu_stdout, stderr = qemu_stderr, stdin = subprocess.DEVNULL, start_new_session = True) return subprocess.Popen(a, bufsize = 0, stdout = qemu_stdout, stderr = qemu_stderr, stdin = subprocess.DEVNULL, start_new_session = True)
if __name__ == "__main__": if __name__ == "__main__":
program_files = build() program_name = build()
os.makedirs("workspace", exist_ok = True) os.makedirs("workspace", exist_ok = True)
@ -72,19 +72,16 @@ if __name__ == "__main__":
img.delete_path("DEMOS") img.delete_path("DEMOS")
img.delete_path("3D") img.delete_path("3D")
log("Moving program files into kolibri image... ", end = "") log("Moving program into kolibri image... ", end = "")
for file_name in program_files: with open(program_name, "rb") as file:
with open(file_name, "rb") as file: file_data = file.read()
file_data = file.read() if not img.add_file_path(program_name.upper(), file_data):
if not img.add_file_path(file_name.upper(), file_data): print(f"Coudn't move {program_name} into IMG")
print(f"Coudn't move {file_name} into IMG")
log("Done") log("Done")
# TODO: Figure out which of compiled files is a program executable and only run it # TODO: Figure out which of compiled files is a program executable and only run it
log("Adding program to autorun.dat", end = "") log("Adding program to autorun.dat... ", end = "")
lines_to_add = b"" lines_to_add = bytes(f"\r\n/SYS/{program_name.upper()}\t\t""\t0\t# Your program", "ascii")
for file_name in program_files:
lines_to_add += bytes(f"\r\n/SYS/{file_name.upper()}\t\t""\t0\t# Your program", "ascii")
autorun_dat = img.extract_file_path("SETTINGS\AUTORUN.DAT") autorun_dat = img.extract_file_path("SETTINGS\AUTORUN.DAT")
place_for_new_lines = autorun_dat.index(b"\r\n/SYS/@TASKBAR")# b"\r\n### Hello, ASM World! ###") place_for_new_lines = autorun_dat.index(b"\r\n/SYS/@TASKBAR")# b"\r\n### Hello, ASM World! ###")
autorun_dat = autorun_dat[:place_for_new_lines] + lines_to_add + autorun_dat[place_for_new_lines:] autorun_dat = autorun_dat[:place_for_new_lines] + lines_to_add + autorun_dat[place_for_new_lines:]