From: SangYoun Kwak Date: Mon, 4 Nov 2024 10:44:09 +0000 (+0900) Subject: Refactor modify_pc.py to be modulized X-Git-Tag: accepted/tizen/9.0/unified/20241107.020129~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a9fb1fc6c12f99fa31a22e6981f27ebc246d9aa7;p=platform%2Fhal%2Fbackend%2Frootstrap.git Refactor modify_pc.py to be modulized A class PkgConfig that manages the contents of .pc file is used to increase readability and maintainability. Also, parsing part and modification parts are separated to make them more maintainable. As parsing part is separated, some datas are moved to the .pc.in files to make the module more data-independent. Change-Id: I2855a862d8dfb7d4dc2af8af1d22addc02785f5c Signed-off-by: SangYoun Kwak --- diff --git a/modify_pc.py b/modify_pc.py index b659456..c1ea980 100755 --- a/modify_pc.py +++ b/modify_pc.py @@ -2,67 +2,141 @@ 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() diff --git a/packaging/hal-rootstrap-headed.pc.in b/packaging/hal-rootstrap-headed.pc.in index eb84c3c..6dfcc06 100644 --- a/packaging/hal-rootstrap-headed.pc.in +++ b/packaging/hal-rootstrap-headed.pc.in @@ -3,6 +3,7 @@ package_name=hal-rootstrap prefix=/opt/data/hal-rootstrap@PREFIX@ exec_prefix=/opt/data/hal-rootstrap@EXEC_PREFIX@ +hal_rootstrap_dir_symbol=hal_rootstrap_dir hal_rootstrap_dir=/opt/data/hal-rootstrap/headed hal_rootstrap_libdir=${hal_rootstrap_dir}@LIBDIR@ hal_rootstrap_include_dir=${hal_rootstrap_dir}@INCLUDEDIR@ @@ -12,3 +13,7 @@ Description: ${package_name} interface Version: @VERSION@ Requires: + +Libs: -L${hal_rootstrap_dir} +Cflags: -I${hal_rootstrap_dir} +CXXflags: -I${hal_rootstrap_dir} diff --git a/packaging/hal-rootstrap.pc.in b/packaging/hal-rootstrap.pc.in index 5ce9317..b6f06a1 100644 --- a/packaging/hal-rootstrap.pc.in +++ b/packaging/hal-rootstrap.pc.in @@ -3,6 +3,7 @@ package_name=hal-rootstrap prefix=/opt/data/hal-rootstrap@PREFIX@ exec_prefix=/opt/data/hal-rootstrap@EXEC_PREFIX@ +hal_rootstrap_dir_symbol=hal_rootstrap_dir hal_rootstrap_dir=/opt/data/hal-rootstrap/common hal_rootstrap_libdir=${hal_rootstrap_dir}@LIBDIR@ hal_rootstrap_include_dir=${hal_rootstrap_dir}@INCLUDEDIR@ @@ -12,3 +13,7 @@ Description: ${package_name} interface Version: @VERSION@ Requires: + +Libs: -L${hal_rootstrap_dir} +Cflags: -I${hal_rootstrap_dir} +CXXflags: -I${hal_rootstrap_dir}