[DEV] add a dependency graph generator

lutin dependency:LD ; dot -Tsvg dependency.dot -o dependency.svg ; firefox dependency.svg
This commit is contained in:
Edouard DUPIN 2016-10-28 00:06:05 +02:00
parent f2060d4c97
commit 44dbcdd56d
3 changed files with 160 additions and 19 deletions

View File

@ -69,6 +69,15 @@ def usage(full=False):
print(" clean all (same as previous)") print(" clean all (same as previous)")
print(" " + color['green'] + "dump" + color['default']) print(" " + color['green'] + "dump" + color['default'])
print(" Dump all the module dependency and properties") print(" Dump all the module dependency and properties")
print(" " + color['green'] + "dependency" + color['default'])
print(" generate a file dependency.dot that represent all the dependency link")
print(" Select what in included: 'dependency:LPBDK'")
print(" L: Library")
print(" P: Pre-build")
print(" D: Data")
print(" B: Binary")
print(" K: Package")
print(" eg: lutin dependency:LD ; dot -Tsvg dependency.dot -o dependency.svg ; firefox dependency.svg")
print(" " + color['green'] + "gcov" + color['default']) print(" " + color['green'] + "gcov" + color['default'])
print(" Parse all the code of the library with the gcov resolution") print(" Parse all the code of the library with the gcov resolution")
listOfAllModule = module.list_all_module_with_desc() listOfAllModule = module.list_all_module_with_desc()
@ -169,18 +178,18 @@ def check_boolean(value):
def parseGenericArg(argument, active): def parseGenericArg(argument, active):
debug.extreme_verbose("parse arg : " + argument.get_option_name() + " " + argument.get_arg() + " active=" + str(active)) debug.extreme_verbose("parse arg : " + argument.get_option_name() + " " + argument.get_arg() + " active=" + str(active))
if argument.get_option_name() == "help": if argument.get_option_name() == "help":
if active==False: if active == False:
usage() usage()
return True return True
if argument.get_option_name() == "HELP": if argument.get_option_name() == "HELP":
if active==False: if active == False:
usage(True) usage(True)
return True return True
if argument.get_option_name() == "list-module": if argument.get_option_name() == "list-module":
if active==False: if active == False:
listOfModule = module.list_all_module() list_of_module = module.list_all_module()
retValue = "" retValue = ""
for moduleName in listOfModule: for moduleName in list_of_module:
if retValue != "": if retValue != "":
retValue += " " retValue += " "
retValue += moduleName retValue += moduleName
@ -188,10 +197,10 @@ def parseGenericArg(argument, active):
exit(0) exit(0)
return True return True
if argument.get_option_name() == "list-target": if argument.get_option_name() == "list-target":
if active==False: if active == False:
listOfTarget = target.list_all_target() list_of_target = target.list_all_target()
retValue = "" retValue = ""
for targetName in listOfTarget: for targetName in list_of_target:
if retValue != "": if retValue != "":
retValue += " " retValue += " "
retValue += targetName retValue += targetName
@ -199,61 +208,61 @@ def parseGenericArg(argument, active):
exit(0) exit(0)
return True return True
elif argument.get_option_name()=="jobs": elif argument.get_option_name()=="jobs":
if active==True: if active == True:
multiprocess.set_core_number(int(argument.get_arg())) multiprocess.set_core_number(int(argument.get_arg()))
return True return True
elif argument.get_option_name()=="depth": elif argument.get_option_name()=="depth":
if active==True: if active == True:
env.set_parse_depth(int(argument.get_arg())) env.set_parse_depth(int(argument.get_arg()))
return True return True
elif argument.get_option_name() == "verbose": elif argument.get_option_name() == "verbose":
if active==True: if active == True:
debug.set_level(int(argument.get_arg())) debug.set_level(int(argument.get_arg()))
return True return True
elif argument.get_option_name() == "color": elif argument.get_option_name() == "color":
if active==True: if active == True:
if check_boolean(argument.get_arg()) == True: if check_boolean(argument.get_arg()) == True:
debug.enable_color() debug.enable_color()
else: else:
debug.disable_color() debug.disable_color()
return True return True
elif argument.get_option_name() == "force-build": elif argument.get_option_name() == "force-build":
if active==True: if active == True:
if check_boolean(argument.get_arg()) == True: if check_boolean(argument.get_arg()) == True:
env.set_force_mode(True) env.set_force_mode(True)
else: else:
env.set_force_mode(False) env.set_force_mode(False)
return True return True
elif argument.get_option_name() == "pretty": elif argument.get_option_name() == "pretty":
if active==True: if active == True:
if check_boolean(argument.get_arg()) == True: if check_boolean(argument.get_arg()) == True:
env.set_print_pretty_mode(True) env.set_print_pretty_mode(True)
else: else:
env.set_print_pretty_mode(False) env.set_print_pretty_mode(False)
return True return True
elif argument.get_option_name() == "force-optimisation": elif argument.get_option_name() == "force-optimisation":
if active==True: if active == True:
if check_boolean(argument.get_arg()) == True: if check_boolean(argument.get_arg()) == True:
env.set_force_optimisation(True) env.set_force_optimisation(True)
else: else:
env.set_force_optimisation(False) env.set_force_optimisation(False)
return True return True
elif argument.get_option_name() == "isolate-system": elif argument.get_option_name() == "isolate-system":
if active==True: if active == True:
if check_boolean(argument.get_arg()) == True: if check_boolean(argument.get_arg()) == True:
env.set_isolate_system(True) env.set_isolate_system(True)
else: else:
env.set_isolate_system(False) env.set_isolate_system(False)
return True return True
elif argument.get_option_name() == "force-strip": elif argument.get_option_name() == "force-strip":
if active==True: if active == True:
if check_boolean(argument.get_arg()) == True: if check_boolean(argument.get_arg()) == True:
env.set_force_strip_mode(True) env.set_force_strip_mode(True)
else: else:
env.set_force_strip_mode(False) env.set_force_strip_mode(False)
return True return True
elif argument.get_option_name() == "warning": elif argument.get_option_name() == "warning":
if active==True: if active == True:
if check_boolean(argument.get_arg()) == True: if check_boolean(argument.get_arg()) == True:
env.set_warning_mode(True) env.set_warning_mode(True)
else: else:

View File

@ -1285,6 +1285,107 @@ class Module:
print('-----------------------------------------------') print('-----------------------------------------------')
return True return True
def check_rules(self, type, rules):
if ( ( type == 'LIBRARY' \
or type == 'LIBRARY_DYNAMIC' \
or type == 'LIBRARY_STATIC' ) \
and "L" not in rules ) \
or ( type == 'DATA' \
and "D" not in rules ) \
or ( type == 'PREBUILD'\
and "P" not in rules ) \
or ( type == 'PACKAGE'\
and "K" not in rules) \
or ( ( type == 'BINARY' \
or type == 'BINARY_SHARED' \
or type == 'BINARY_STAND_ALONE')\
and "B" not in rules ) :
return True
return False
# TODO: Add to simplify the display the possibility to check if an element already depend in dependency of an element ???
def dependency_generate(self, target, tmp_file, step, rules):
debug.print_element("dot", "dependency.dot", "<<<", self._name)
if self.check_rules(self._type, rules) == True:
return
if step == 1:
if self._type == 'DATA':
tmp_file.write(' node [\n');
tmp_file.write(' shape=Mdiamond;\n');
tmp_file.write(' style=filled;\n');
tmp_file.write(' color=red;\n');
tmp_file.write(' ];\n');
elif self._type == 'PREBUILD':
tmp_file.write(' node [\n');
tmp_file.write(' shape=square;\n');
tmp_file.write(' style=filled;\n');
tmp_file.write(' color=gray;\n');
tmp_file.write(' ];\n');
elif self._type == 'LIBRARY' \
or self._type == 'LIBRARY_DYNAMIC' \
or self._type == 'LIBRARY_STATIC':
tmp_file.write(' node [\n');
tmp_file.write(' shape=ellipse;\n');
tmp_file.write(' style=filled;\n');
tmp_file.write(' color=lightblue;\n');
tmp_file.write(' ];\n');
elif self._type == 'BINARY' \
or self._type == 'BINARY_SHARED' \
or self._type == 'BINARY_STAND_ALONE':
tmp_file.write(' node [\n');
tmp_file.write(' shape=rectangle;\n');
tmp_file.write(' style=filled;\n');
tmp_file.write(' color=green;\n');
tmp_file.write(' ];\n');
elif self._type == 'PACKAGE':
return
tmp_file.write(' ' + copy.deepcopy(self._name).replace('-','_')+ ';\n');
else:
for elem in self._depends:
debug.verbose("add depend on: " + elem);
tmp_module = None
try:
tmp_module = target.get_module(elem)
except:
target.load_if_needed(elem, optionnal=True)
try:
tmp_module = target.get_module(elem)
except:
debug.verbose(" ==> get error");
if tmp_module == None:
debug.verbose(" ==> notFound");
continue
if self.check_rules(tmp_module._type, rules) == True:
debug.verbose(" ==> not in rules");
continue
tmp_file.write(' ' + copy.deepcopy(self._name).replace('-','_') + ' -> ' + copy.deepcopy(elem).replace('-','_') + ';\n');
for elem in self._depends_optionnal:
elem = elem[0]
debug.verbose("add depend on: " + elem);
tmp_module = None
try:
tmp_module = target.get_module(elem)
except:
target.load_if_needed(elem, optionnal=True)
try:
tmp_module = target.get_module(elem)
except:
debug.verbose(" ==> get error");
if tmp_module == None:
debug.verbose(" ==> notFound");
continue
if self.check_rules(tmp_module._type, rules) == True:
debug.verbose(" ==> not in rules");
continue
tmp_file.write(' ' + copy.deepcopy(self._name).replace('-','_') + ' -> ' + copy.deepcopy(elem).replace('-','_') + ';\n');
"""
tmp_file.write(' module_' + self._name.replace('-','_') + ' {\n');
tmp_file.write(' style=filled;\n');
tmp_file.write(' color=blue;\n');
tmp_file.write(' label="' + self._name + '";\n');
tmp_file.write(' }\n');
"""
## ##
## @brief Get packaging property variable ## @brief Get packaging property variable
## @param[in] self (handle) Class handle ## @param[in] self (handle) Class handle

View File

@ -653,11 +653,42 @@ class Target:
for mod in self.module_list: for mod in self.module_list:
mod.display() mod.display()
return return
if name[:10] == "dependency":
if len(name) > 10:
rules = name.split(":")[1]
else:
rules = "LBDPK"
# L for library
# B for binary
# D for Data
# P for prebuild
# K for package
debug.print_element("dot", "", "---", "dependency.dot")
self.load_all()
tmp_file = open("dependency.dot", 'w')
tmp_file.write('digraph G {\n')
tmp_file.write(' rankdir=\"LR\";\n')
for mod in self.module_list:
mod.dependency_generate(self, tmp_file, 1, rules)
# TODO : do it better ==> system library hook (do a oad of all avillable system library)
tmp_file.write(' node [\n');
tmp_file.write(' shape=square;\n');
tmp_file.write(' style=filled;\n');
tmp_file.write(' color=gray;\n');
tmp_file.write(' ];\n');
# TODO : End hook
for mod in self.module_list:
mod.dependency_generate(self, tmp_file, 2, rules)
tmp_file.write('}\n')
tmp_file.flush()
tmp_file.close()
debug.print_element("dot", "", "---", "dependency.dot")
return
if name == "all": if name == "all":
debug.info("build all") debug.info("build all")
self.load_all() self.load_all()
for mod in self.module_list: for mod in self.module_list:
if self._name=="Android": if self._name == "Android":
if mod.get_type() == "PACKAGE": if mod.get_type() == "PACKAGE":
mod.build(self, None) mod.build(self, None)
else: else: