msvcdeps: Faster case correction

Visual Studio returns paths to dependencies with incorrect case.
ant_glob() is very slow for this use case (40~50% impact to overall
build time). This patch uses os.listdir() to find the correct case
of each path component.
This commit is contained in:
Michael Vincent 2021-04-12 16:06:54 -05:00
parent 80ffb62e4d
commit 2d14817f1f
1 changed files with 29 additions and 10 deletions

View File

@ -50,23 +50,42 @@ def apply_msvcdeps_flags(taskgen):
if taskgen.env.get_flat(flag).find(PREPROCESSOR_FLAG) < 0: if taskgen.env.get_flat(flag).find(PREPROCESSOR_FLAG) < 0:
taskgen.env.append_value(flag, PREPROCESSOR_FLAG) taskgen.env.append_value(flag, PREPROCESSOR_FLAG)
def get_correct_path_case(base_path, path):
'''
Return a case-corrected version of ``path`` by searching the filesystem for
``path``, relative to ``base_path``, using the case returned by the filesystem.
'''
components = Utils.split_path(path)
corrected_path = ''
if os.path.isabs(path):
corrected_path = components.pop(0).upper() + os.sep
for part in components:
part = part.lower()
search_path = os.path.join(base_path, corrected_path)
for item in os.listdir(search_path):
if item.lower() == part:
corrected_path = os.path.join(corrected_path, item)
break
else:
raise ValueError("Can't find %r in %r" % (part, search_path))
return corrected_path
def path_to_node(base_node, path, cached_nodes): def path_to_node(base_node, path, cached_nodes):
''' '''
Take the base node and the path and return a node Take the base node and the path and return a node
Results are cached because searching the node tree is expensive Results are cached because searching the node tree is expensive
The following code is executed by threads, it is not safe, so a lock is needed... The following code is executed by threads, it is not safe, so a lock is needed...
''' '''
# normalize the path because ant_glob() does not understand # normalize the path to remove parent path components (..)
# parent path components (..)
path = os.path.normpath(path) path = os.path.normpath(path)
# normalize the path case to increase likelihood of a cache hit # normalize the path case to increase likelihood of a cache hit
path = os.path.normcase(path) node_lookup_key = (base_node, os.path.normcase(path))
# ant_glob interprets [] and () characters, so those must be replaced
path = path.replace('[', '?').replace(']', '?').replace('(', '[(]').replace(')', '[)]')
node_lookup_key = (base_node, path)
try: try:
node = cached_nodes[node_lookup_key] node = cached_nodes[node_lookup_key]
@ -76,8 +95,8 @@ def path_to_node(base_node, path, cached_nodes):
try: try:
node = cached_nodes[node_lookup_key] node = cached_nodes[node_lookup_key]
except KeyError: except KeyError:
node_list = base_node.ant_glob([path], ignorecase=True, remove=False, quiet=True, regex=False) path = get_correct_path_case(base_node.abspath(), path)
node = cached_nodes[node_lookup_key] = node_list[0] if node_list else None node = cached_nodes[node_lookup_key] = base_node.find_node(path)
return node return node