Improve LDF and Circular dependencies

This commit is contained in:
Ivan Kravets
2016-11-23 23:47:09 +02:00
parent 5bcd7c574d
commit e2de7b05b9

View File

@ -32,7 +32,7 @@ from platformio.managers.lib import LibraryManager
class LibBuilderFactory(object): class LibBuilderFactory(object):
@staticmethod @staticmethod
def new(env, path): def new(env, path, verbose=False):
clsname = "UnknownLibBuilder" clsname = "UnknownLibBuilder"
if isfile(join(path, "library.json")): if isfile(join(path, "library.json")):
clsname = "PlatformIOLibBuilder" clsname = "PlatformIOLibBuilder"
@ -45,7 +45,9 @@ class LibBuilderFactory(object):
elif used_frameworks: elif used_frameworks:
clsname = "%sLibBuilder" % used_frameworks[0].title() clsname = "%sLibBuilder" % used_frameworks[0].title()
obj = getattr(sys.modules[__name__], clsname)(env, path) obj = getattr(sys.modules[__name__], clsname)(env,
path,
verbose=verbose)
assert isinstance(obj, LibBuilderBase) assert isinstance(obj, LibBuilderBase)
return obj return obj
@ -82,15 +84,17 @@ class LibBuilderBase(object):
INC_SCANNER = SCons.Scanner.C.CScanner() INC_SCANNER = SCons.Scanner.C.CScanner()
INC_DIRS_CACHE = None INC_DIRS_CACHE = None
def __init__(self, env, path, manifest=None): def __init__(self, env, path, manifest=None, verbose=False):
self.env = env.Clone() self.env = env.Clone()
self.envorigin = env.Clone() self.envorigin = env.Clone()
self.path = realpath(env.subst(path)) self.path = realpath(env.subst(path))
self.verbose = verbose
self._manifest = manifest if manifest else self.load_manifest() self._manifest = manifest if manifest else self.load_manifest()
self._is_dependent = False self._is_dependent = False
self._is_built = False
self._depbuilders = list() self._depbuilders = list()
self._circular_deps = list()
self._scanned_paths = list() self._scanned_paths = list()
self._built_node = None
# process extra options and append to build environment # process extra options and append to build environment
self.process_extra_options() self.process_extra_options()
@ -209,8 +213,6 @@ class LibBuilderBase(object):
def _process_dependencies(self, lib_builders): def _process_dependencies(self, lib_builders):
if not self.dependencies: if not self.dependencies:
return return
verbose = (int(ARGUMENTS.get("PIOVERBOSE", 0)) and
not self.env.GetOption('clean'))
for item in self.dependencies: for item in self.dependencies:
skip = False skip = False
for key in ("platforms", "frameworks"): for key in ("platforms", "frameworks"):
@ -219,7 +221,7 @@ class LibBuilderBase(object):
continue continue
if (key in item and if (key in item and
not self.items_in_list(self.env[env_key], item[key])): not self.items_in_list(self.env[env_key], item[key])):
if verbose: if self.verbose:
sys.stderr.write("Skip %s incompatible dependency %s\n" sys.stderr.write("Skip %s incompatible dependency %s\n"
% (key[:-1], item)) % (key[:-1], item))
skip = True skip = True
@ -285,12 +287,23 @@ class LibBuilderBase(object):
return result return result
def depend_recursive(self, lb, lib_builders, search_paths=None): def depend_recursive(self, lb, lib_builders, search_paths=None):
def _already_depends(_lb):
if self in _lb.depbuilders:
return True
for __lb in _lb.depbuilders:
if _already_depends(__lb):
return True
return False
# assert isinstance(lb, LibBuilderBase) # assert isinstance(lb, LibBuilderBase)
if self != lb: if self != lb:
if self in lb.depbuilders: if _already_depends(lb):
sys.stderr.write("Warning! Circular dependencies detected " if self.verbose:
"between `%s` and `%s`\n" % sys.stderr.write("Warning! Circular dependencies detected "
(self.path, lb.path)) "between `%s` and `%s`\n" %
(self.path, lb.path))
self._circular_deps.append(lb)
elif lb not in self._depbuilders: elif lb not in self._depbuilders:
self._depbuilders.append(lb) self._depbuilders.append(lb)
LibBuilderBase.INC_DIRS_CACHE = None LibBuilderBase.INC_DIRS_CACHE = None
@ -322,21 +335,25 @@ class LibBuilderBase(object):
def build(self): def build(self):
libs = [] libs = []
for lb in self.depbuilders: for lb in self._depbuilders:
libs.extend(lb.build()) libs.extend(lb.build())
# copy shared information to self env # copy shared information to self env
for key in ("CPPPATH", "LIBPATH", "LIBS", "LINKFLAGS"): for key in ("CPPPATH", "LIBPATH", "LIBS", "LINKFLAGS"):
self.env.AppendUnique(**{key: lb.env.get(key)}) self.env.AppendUnique(**{key: lb.env.get(key)})
if not self._built_node: for lb in self._circular_deps:
self.env.AppendUnique(CPPPATH=lb.get_inc_dirs())
if not self._is_built:
self.env.AppendUnique(CPPPATH=self.get_inc_dirs()) self.env.AppendUnique(CPPPATH=self.get_inc_dirs())
if self.lib_archive: if self.lib_archive:
self._built_node = self.env.BuildLibrary( libs.append(
self.build_dir, self.src_dir, self.src_filter) self.env.BuildLibrary(self.build_dir, self.src_dir,
self.src_filter))
else: else:
self._built_node = self.env.BuildSources( self.env.BuildSources(self.build_dir, self.src_dir,
self.build_dir, self.src_dir, self.src_filter) self.src_filter)
libs.append(self._built_node) self._is_built = True
return libs return libs
@ -346,6 +363,10 @@ class UnknownLibBuilder(LibBuilderBase):
class ProjectAsLibBuilder(LibBuilderBase): class ProjectAsLibBuilder(LibBuilderBase):
def __init__(self, *args, **kwargs):
LibBuilderBase.__init__(self, *args, **kwargs)
self._is_built = True
@property @property
def lib_ldf_mode(self): def lib_ldf_mode(self):
return 2 # parse all project files return 2 # parse all project files
@ -371,11 +392,6 @@ class ProjectAsLibBuilder(LibBuilderBase):
return LibBuilderBase.search_deps_recursive(self, lib_builders, return LibBuilderBase.search_deps_recursive(self, lib_builders,
search_paths) search_paths)
def build(self):
# dummy mark that project is built
self._built_node = "dummy"
return [l for l in LibBuilderBase.build(self) if l != "dummy"]
class ArduinoLibBuilder(LibBuilderBase): class ArduinoLibBuilder(LibBuilderBase):
@ -550,7 +566,9 @@ def GetLibBuilders(env):
if item == "__cores__" or not isdir(join(libs_dir, item)): if item == "__cores__" or not isdir(join(libs_dir, item)):
continue continue
try: try:
lb = LibBuilderFactory.new(env, join(libs_dir, item)) lb = LibBuilderFactory.new(env,
join(libs_dir, item),
verbose=verbose)
except ValueError: except ValueError:
if verbose: if verbose:
sys.stderr.write("Skip library with broken manifest: %s\n" sys.stderr.write("Skip library with broken manifest: %s\n"