from sys import argv
from os import listdir
-from re import compile as regex_compile
-
-include_dir_root_path = "hal_rootstrap_dir"
-
-regex_comment = regex_compile("([^#]*)(#.*)?")
-regex_assignment = regex_compile("\\s*([-_a-zA-Z0-9]+)\\s*=\\s*([^\\s]*)")
-regex_declaration = regex_compile("\\s*([-_a-zA-Z0-9]+)\\s*:\\s*(.+)\\s*")
-regex_substitution = regex_compile("\\${([-_a-zA-Z0-9]+)}")
-
-libs = { "-L${" + include_dir_root_path + "}" }
-cflags = { "-I${" + include_dir_root_path + "}" }
-cxxflags = { "-I${" + include_dir_root_path + "}" }
-
-def remove_comment(line):
- matches = regex_comment.findall(line)
- line, _ = matches[0][0], matches[0][1]
- return line
-
-def parse_pc(fname):
- variables = dict()
-
- f = open(fname, "r")
- for line in f:
- line = remove_comment(line)
- if matches := regex_assignment.findall(line):
- symbol, value = matches[0][0], matches[0][1]
- matched_symbols = regex_substitution.findall(value)
- for matched_symbol in matched_symbols:
- value = value.replace("${{{}}}".format(matched_symbol), "{}".format(variables[matched_symbol]))
- variables[symbol] = value
- continue
- if matches := regex_declaration.findall(line):
- symbol, value = matches[0][0], matches[0][1]
- matched_symbols = regex_substitution.findall(value)
- for matched_symbol in matched_symbols:
- value = value.replace("${{{}}}".format(matched_symbol), "{}".format(variables[matched_symbol]))
- if symbol == "Libs":
- libs.update(set(map(lambda value: value[:2] + "${" + include_dir_root_path + "}" + value[2:] if value[2] == '/' else value, value.split())))
- continue
- if symbol == "Cflags":
- cflags.update((map(lambda value: value[:2] + "${" + include_dir_root_path + "}" + value[2:] if value[2] == '/' else value, value.split())))
- continue
- if symbol == "CXXflags":
- cxxflags.update(list(map(lambda value: value[:2] + "${" + include_dir_root_path + "}" + value[2:] if value[2] == '/' else value, value.split())))
- continue
-
- f.close()
-
-def write_to_pc(fname):
- f = open(fname, "a")
- f.write("\n")
- f.write("Libs: {}\n".format(' '.join(libs)))
- f.write("Cflags: {}\n".format(' '.join(cflags)))
- f.write("CXXflags: {}\n".format(' '.join(cxxflags)))
- f.close()
-
-rootstrap_pc_path = argv[1]
-pc_dir = argv[2]
-pc_files = listdir(pc_dir)
-
-for pc_file in pc_files:
- parse_pc("{}/{}".format(pc_dir, pc_file))
-
-write_to_pc(rootstrap_pc_path)
+from re import compile as compile_regex
+
+class FileLineReadGenerator:
+ def __init__(self, fname):
+ self.fname = fname
+ def readline(self):
+ with open(self.fname, "r") as f:
+ for line in f:
+ yield line
+ return None
+
+class RecursiveReferenceException(Exception):
+ pass
+
+class UnknownVariableException(Exception):
+ pass
+
+class PkgConfig:
+ regex_comment = compile_regex("([^#]*)(#.*)?")
+ regex_assignment = compile_regex("\\s*([-_a-zA-Z0-9]+)\\s*=\\s*([^\\s]*)")
+ regex_declaration = compile_regex("\\s*([-_a-zA-Z0-9]+)\\s*:\\s*(.*)\\s*")
+ regex_substitution = compile_regex("\\${([-_a-zA-Z0-9]+)}")
+ regex_root_substitution = compile_regex("^-([a-zA-Z])/(.*)$")
+
+ def __init__(self):
+ self.variables = dict()
+ self.declarations = dict()
+
+ def remove_comment(self, line):
+ matches = self.regex_comment.findall(line)
+ line, _ = matches[0][0], matches[0][1]
+ return line
+
+ def substitute_value(self, sub_value, symbol, value):
+ return sub_value.replace(f"${{{symbol}}}", str(value))
+
+ def substitute_symbols(self, target_dict):
+ for symbol, value in self.variables.items():
+ for sub_symbol, sub_value in target_dict.items():
+ target_dict[sub_symbol] = self.substitute_value(sub_value, symbol, value)
+
+ def substitute_variables(self):
+ self.substitute_symbols(self.variables)
+
+ for symbol, value in self.variables.items():
+ if matched := self.regex_substitution.findall(value):
+ if any(map(lambda symbol: symbol in self.variables, matched)):
+ raise RecursiveReferenceException(f"Variable is referenced recursively: {symbol}")
+ raise UnknownVariableException(f"Unknown variable(s): {matched}")
+
+ def substitute_declarations(self):
+ self.substitute_symbols(self.declarations)
+
+ for symbol, value in self.declarations.items():
+ if matched := self.regex_substitution.findall(value):
+ raise UnknownVariableException(f"Unknown variable(s): {matched}")
+
+ def substitute_declaration_root(self, value, root):
+ substituted_values = list()
+ value_entities = value.split()
+
+ for value_entity in value_entities:
+ if matched := self.regex_root_substitution.findall(value_entity):
+ substituted_values.append(f"-{matched[0][0]}${{{root}}}/{matched[0][1]}")
+ continue
+ substituted_values.append(value_entity)
+
+ return ' '.join(substituted_values)
+
+ def substitute_declarations_root(self, root):
+ target_declaration_symbols = ( "Libs", "Cflags", "CXXflags" )
+ for target_declaration_symbol in target_declaration_symbols:
+ if target_declaration_symbol not in self.declarations:
+ continue
+ self.declarations[target_declaration_symbol] = self.substitute_declaration_root(self.declarations[target_declaration_symbol], root)
+
+ def parse(self, fname):
+ linegen = FileLineReadGenerator(fname)
+ for line in linegen.readline():
+ line = self.remove_comment(line.strip())
+ if not line:
+ continue
+ if matches := self.regex_assignment.findall(line):
+ symbol, value = matches[0][0], matches[0][1]
+ self.variables[symbol] = value
+ continue
+ if matches := self.regex_declaration.findall(line):
+ symbol, value = matches[0][0], matches[0][1]
+ self.declarations[symbol] = value
+ continue
+
+ def merge_declarations(self, other_pkgconfig):
+ symbols_to_merge = ( "Libs", "Cflags", "CXXflags" )
+ for symbol in symbols_to_merge:
+ if symbol not in other_pkgconfig.declarations:
+ continue
+ value = other_pkgconfig.declarations[symbol]
+ if symbol not in self.declarations:
+ self.declarations[symbol] = value
+ continue
+ new_values = set(self.declarations[symbol].split())
+ new_values.update(value.split())
+ self.declarations[symbol] = ' '.join(new_values)
+
+ def export_file(self, fname):
+ with open(fname, "w") as f:
+ for symbol, value in self.variables.items():
+ f.write("{}={}\n".format(symbol, value))
+
+ f.write("\n")
+
+ for symbol, value in self.declarations.items():
+ f.write("{}: {}\n".format(symbol, value))
+
+def main():
+ rootstrap_pc_path = argv[1]
+ pc_dir = argv[2]
+ pc_files = listdir(pc_dir)
+
+ hal_pkgconfig = PkgConfig()
+ hal_pkgconfig.parse(rootstrap_pc_path)
+
+ include_dir_root_path = hal_pkgconfig.variables["hal_rootstrap_dir_symbol"]
+
+ for pc_file in pc_files:
+ pc_file_path = "{}/{}".format(pc_dir, pc_file)
+ pkgconfig = PkgConfig()
+ pkgconfig.parse(pc_file_path)
+ pkgconfig.substitute_variables()
+ pkgconfig.substitute_declarations()
+ hal_pkgconfig.merge_declarations(pkgconfig)
+
+ hal_pkgconfig.substitute_declarations_root(include_dir_root_path)
+
+ hal_pkgconfig.export_file(rootstrap_pc_path)
+
+if __name__ == "__main__":
+ main()