3030
3131from platformio import exception , fs
3232from platformio .builder .tools import platformio as piotool
33- from platformio .compat import IS_WINDOWS , hashlib_encode_data , string_types
33+ from platformio .compat import IS_WINDOWS , MISSING , hashlib_encode_data , string_types
3434from platformio .http import HTTPClientError , InternetIsOffline
3535from platformio .package .exception import (
3636 MissingPackageManifestError ,
@@ -143,7 +143,7 @@ def __init__(self, env, path, manifest=None, verbose=False):
143143
144144 self ._deps_are_processed = False
145145 self ._circular_deps = []
146- self ._processed_files = []
146+ self ._processed_search_files = []
147147
148148 # reset source filter, could be overridden with extra script
149149 self .env ["SRC_FILTER" ] = ""
@@ -154,20 +154,27 @@ def __init__(self, env, path, manifest=None, verbose=False):
154154 def __repr__ (self ):
155155 return "%s(%r)" % (self .__class__ , self .path )
156156
157- def __contains__ (self , path ):
158- p1 = self .path
159- p2 = path
157+ def __contains__ (self , child_path ):
158+ return self .is_common_builder (self .path , child_path )
159+
160+ def is_common_builder (self , root_path , child_path ):
160161 if IS_WINDOWS :
161- p1 = p1 .lower ()
162- p2 = p2 .lower ()
163- if p1 == p2 :
162+ root_path = root_path .lower ()
163+ child_path = child_path .lower ()
164+ if root_path == child_path :
164165 return True
165- if os .path .commonprefix ([p1 + os .path .sep , p2 ]) == p1 + os .path .sep :
166+ if (
167+ os .path .commonprefix ([root_path + os .path .sep , child_path ])
168+ == root_path + os .path .sep
169+ ):
166170 return True
167171 # try to resolve paths
168- p1 = os .path .os .path .realpath (p1 )
169- p2 = os .path .os .path .realpath (p2 )
170- return os .path .commonprefix ([p1 + os .path .sep , p2 ]) == p1 + os .path .sep
172+ root_path = os .path .realpath (root_path )
173+ child_path = os .path .realpath (child_path )
174+ return (
175+ os .path .commonprefix ([root_path + os .path .sep , child_path ])
176+ == root_path + os .path .sep
177+ )
171178
172179 @property
173180 def name (self ):
@@ -324,7 +331,7 @@ def get_search_files(self):
324331 )
325332 ]
326333
327- def _get_found_includes ( # pylint: disable=too-many-branches
334+ def get_implicit_includes ( # pylint: disable=too-many-branches
328335 self , search_files = None
329336 ):
330337 # all include directories
@@ -345,15 +352,17 @@ def _get_found_includes( # pylint: disable=too-many-branches
345352 include_dirs .extend (LibBuilderBase ._INCLUDE_DIRS_CACHE )
346353
347354 result = []
348- for path in search_files or []:
349- if path in self ._processed_files :
355+ search_files = search_files or []
356+ while search_files :
357+ node = self .env .File (search_files .pop (0 ))
358+ if node .get_abspath () in self ._processed_search_files :
350359 continue
351- self ._processed_files .append (path )
360+ self ._processed_search_files .append (node . get_abspath () )
352361
353362 try :
354363 assert "+" in self .lib_ldf_mode
355364 candidates = LibBuilderBase .CCONDITIONAL_SCANNER (
356- self . env . File ( path ) ,
365+ node ,
357366 self .env ,
358367 tuple (include_dirs ),
359368 depth = self .CCONDITIONAL_SCANNER_DEPTH ,
@@ -363,39 +372,35 @@ def _get_found_includes( # pylint: disable=too-many-branches
363372 if self .verbose and "+" in self .lib_ldf_mode :
364373 sys .stderr .write (
365374 "Warning! Classic Pre Processor is used for `%s`, "
366- "advanced has failed with `%s`\n " % (path , exc )
375+ "advanced has failed with `%s`\n " % (node . get_abspath () , exc )
367376 )
368- candidates = self .env .File (path ).get_implicit_deps (
369- self .env ,
370- LibBuilderBase .CLASSIC_SCANNER ,
371- lambda _ : tuple (include_dirs ),
377+ candidates = LibBuilderBase .CLASSIC_SCANNER (
378+ node , self .env , tuple (include_dirs )
372379 )
373380
374- # mark candidates already processed
375- self ._processed_files .extend (
376- [
377- c .get_abspath ()
378- for c in candidates
379- if c .get_abspath () not in self ._processed_files
380- ]
381- )
382-
383- # print(path, [c.get_abspath() for c in candidates])
381+ # print(node.get_abspath(), [c.get_abspath() for c in candidates])
384382 for item in candidates :
383+ item_path = item .get_abspath ()
384+ # process internal files recursively
385+ if (
386+ item_path not in self ._processed_search_files
387+ and item_path not in search_files
388+ and item_path in self
389+ ):
390+ search_files .append (item_path )
385391 if item not in result :
386392 result .append (item )
387393 if not self .PARSE_SRC_BY_H_NAME :
388394 continue
389- _h_path = item .get_abspath ()
390- if not fs .path_endswith_ext (_h_path , piotool .SRC_HEADER_EXT ):
395+ if not fs .path_endswith_ext (item_path , piotool .SRC_HEADER_EXT ):
391396 continue
392- _f_part = _h_path [: _h_path .rindex ("." )]
397+ item_fname = item_path [: item_path .rindex ("." )]
393398 for ext in piotool .SRC_C_EXT + piotool .SRC_CXX_EXT :
394- if not os .path .isfile ("%s.%s" % (_f_part , ext )):
399+ if not os .path .isfile ("%s.%s" % (item_fname , ext )):
395400 continue
396- _c_path = self .env .File ("%s.%s" % (_f_part , ext ))
397- if _c_path not in result :
398- result .append (_c_path )
401+ item_c_node = self .env .File ("%s.%s" % (item_fname , ext ))
402+ if item_c_node not in result :
403+ result .append (item_c_node )
399404
400405 return result
401406
@@ -410,7 +415,7 @@ def search_deps_recursive(self, search_files=None):
410415 search_files = self .get_search_files ()
411416
412417 lib_inc_map = {}
413- for inc in self ._get_found_includes (search_files ):
418+ for inc in self .get_implicit_includes (search_files ):
414419 inc_path = inc .get_abspath ()
415420 for lb in self .env .GetLibBuilders ():
416421 if inc_path in lb :
@@ -571,11 +576,10 @@ def lib_ldf_mode(self):
571576 # pylint: disable=no-member
572577 if not self ._manifest .get ("dependencies" ):
573578 return LibBuilderBase .lib_ldf_mode .fget (self )
574- missing = object ()
575579 global_value = self .env .GetProjectConfig ().getraw (
576- "env:" + self .env ["PIOENV" ], "lib_ldf_mode" , missing
580+ "env:" + self .env ["PIOENV" ], "lib_ldf_mode" , MISSING
577581 )
578- if global_value != missing :
582+ if global_value != MISSING :
579583 return LibBuilderBase .lib_ldf_mode .fget (self )
580584 # automatically enable C++ Preprocessing in runtime
581585 # (Arduino IDE has this behavior)
@@ -827,11 +831,10 @@ def extra_script(self):
827831
828832 @property
829833 def lib_archive (self ):
830- missing = object ()
831834 global_value = self .env .GetProjectConfig ().getraw (
832- "env:" + self .env ["PIOENV" ], "lib_archive" , missing
835+ "env:" + self .env ["PIOENV" ], "lib_archive" , MISSING
833836 )
834- if global_value != missing :
837+ if global_value != MISSING :
835838 return self .env .GetProjectConfig ().get (
836839 "env:" + self .env ["PIOENV" ], "lib_archive"
837840 )
@@ -881,6 +884,12 @@ def __init__(self, env, *args, **kwargs):
881884 if export_projenv :
882885 env .Export (dict (projenv = self .env ))
883886
887+ def __contains__ (self , child_path ):
888+ for root_path in (self .include_dir , self .src_dir , self .test_dir ):
889+ if root_path and self .is_common_builder (root_path , child_path ):
890+ return True
891+ return False
892+
884893 @property
885894 def include_dir (self ):
886895 include_dir = self .env .subst ("$PROJECT_INCLUDE_DIR" )
@@ -890,6 +899,10 @@ def include_dir(self):
890899 def src_dir (self ):
891900 return self .env .subst ("$PROJECT_SRC_DIR" )
892901
902+ @property
903+ def test_dir (self ):
904+ return self .env .subst ("$PROJECT_TEST_DIR" )
905+
893906 def get_search_files (self ):
894907 items = []
895908 build_type = self .env .GetBuildType ()
@@ -1035,7 +1048,7 @@ def IsCompatibleLibBuilder(env, lb, verbose=int(ARGUMENTS.get("PIOVERBOSE", 0)))
10351048 sys .stderr .write ("Platform incompatible library %s\n " % lb .path )
10361049 return False
10371050 if compat_mode in ("soft" , "strict" ) and not lb .is_frameworks_compatible (
1038- env .get ("PIOFRAMEWORK" , [] )
1051+ env .get ("PIOFRAMEWORK" , "__noframework__" )
10391052 ):
10401053 if verbose :
10411054 sys .stderr .write ("Framework incompatible library %s\n " % lb .path )
0 commit comments