From 59c5965c376ca5a25706046a98271cdbfda9d22f Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Mon, 9 Sep 2019 13:00:08 +0200 Subject: [PATCH] glob --> breadth_first_walk globbing to search for the solib directory can take very long if the current directory contains a large number of files or directories. This can be an issue when executing `haskell_repl` targets. This change uses a breadth first recursive directory walk instead of `glob`. We are looking for the shortest path matching the solib directory, the first match in a breadth first search will be the shortest one. --- haskell/private/cc_wrapper.bzl | 1 + haskell/private/cc_wrapper.py.tpl | 31 ++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/haskell/private/cc_wrapper.bzl b/haskell/private/cc_wrapper.bzl index 10102961..f39c6b5f 100644 --- a/haskell/private/cc_wrapper.bzl +++ b/haskell/private/cc_wrapper.bzl @@ -20,6 +20,7 @@ def _cc_wrapper_impl(ctx): is_executable = True, substitutions = { "{:cc:}": cc, + "{:cpu:}": cc_toolchain.cpu, "{:workspace:}": ctx.workspace_name, "{:platform:}": ctx.attr.platform, }, diff --git a/haskell/private/cc_wrapper.py.tpl b/haskell/private/cc_wrapper.py.tpl index 92edaa15..2fb4ec73 100644 --- a/haskell/private/cc_wrapper.py.tpl +++ b/haskell/private/cc_wrapper.py.tpl @@ -39,6 +39,7 @@ used to avoid command line length limitations. from bazel_tools.tools.python.runfiles import runfiles as bazel_runfiles from contextlib import contextmanager +from collections import deque import glob import itertools import os @@ -599,6 +600,30 @@ def sort_rpaths(rpaths): return sorted(rpaths, key=rpath_priority) +def breadth_first_walk(top): + """Walk the directory tree starting from the given directory + + Returns an iterator that will recursively walk through the directory + similar to `os.walk`. However, contrary to `os.walk` this function iterates + through the directory tree in a breadth first fashion. + + Yields: + (root, dirnames, filenames) + root: The current directory relative to `top`. + dirnames: List of directory names contained in `root`. + filenames: List of file names contained in `root`. + + """ + stack = deque([top]) + while stack: + current = stack.popleft() + # os.walk performs the separation of file and directory entries. But, + # it iterates depth-first. So, we only use os.walk one level deep. + for root, dirs, files in itertools.islice(os.walk(current, followlinks = True), 1): + yield (root, dirs, files) + stack.extend(os.path.join(root, dirname) for dirname in dirs) + + def find_solib_rpath(rpaths, output): """Find the solib directory rpath entry. @@ -618,9 +643,9 @@ def find_solib_rpath(rpaths, output): # GHC generates temporary libraries outside the execroot. In that case # the Bazel generated RPATHs are not forwarded, and the solib directory # is not visible on the command-line. - candidates = glob.glob("**/bin/_solib_*", recursive=True) - if candidates: - return min(candidates) + for (root, dirnames, _) in breadth_first_walk("."): + if "_solib_{:cpu:}" in dirnames: + return os.path.join(root, "_solib_{:cpu:}") return None -- 2.21.0