review changes

This commit is contained in:
kshea21 2025-01-07 15:13:23 -08:00 committed by Gregory Becker
parent 9d0133a771
commit fa088e4975
No known key found for this signature in database
GPG Key ID: 2362541F6D14ED84
2 changed files with 50 additions and 24 deletions

View File

@ -31,6 +31,7 @@
Skimming this module is a nice way to get acquainted with the types of Skimming this module is a nice way to get acquainted with the types of
calls you can make from within the install() function. calls you can make from within the install() function.
""" """
import inspect import inspect
import io import io
import multiprocessing import multiprocessing
@ -453,6 +454,35 @@ def optimization_flags(compiler, target):
return result return result
class FilterDefaultDynamicLinkerSearchPaths:
"""Remove rpaths to directories that are default search paths of the dynamic linker."""
def __init__(self, dynamic_linker: Optional[str]) -> None:
# Identify directories by (inode, device) tuple, which handles symlinks too.
self.default_path_identifiers: Set[Tuple[int, int]] = set()
if not dynamic_linker:
return
for path in spack.util.libc.default_search_paths_from_dynamic_linker(dynamic_linker):
try:
s = os.stat(path)
if stat.S_ISDIR(s.st_mode):
self.default_path_identifiers.add((s.st_ino, s.st_dev))
except OSError:
continue
def is_dynamic_loader_default_path(self, p: str) -> bool:
try:
s = os.stat(p)
return (s.st_ino, s.st_dev) in self.default_path_identifiers
except OSError:
return False
def __call__(self, dirs: List[str]) -> List[str]:
if not self.default_path_identifiers:
return dirs
return [p for p in dirs if not self.is_dynamic_loader_default_path(p)]
def set_wrapper_variables(pkg, env): def set_wrapper_variables(pkg, env):
"""Set environment variables used by the Spack compiler wrapper (which have the prefix """Set environment variables used by the Spack compiler wrapper (which have the prefix
`SPACK_`) and also add the compiler wrappers to PATH. `SPACK_`) and also add the compiler wrappers to PATH.
@ -867,6 +897,7 @@ def effective_deptypes(
root=True, root=True,
all_edges=True, all_edges=True,
) )
traverse.traverse_depth_first_with_visitor(traverse.with_artificial_edges(specs), visitor)
# Dictionary with "no mode" as default value, so it's easy to write modes[x] |= flag. # Dictionary with "no mode" as default value, so it's easy to write modes[x] |= flag.
use_modes = defaultdict(lambda: UseMode(0)) use_modes = defaultdict(lambda: UseMode(0))
@ -1095,10 +1126,7 @@ def load_external_modules(context: SetupContext) -> None:
class ProcessHandle: class ProcessHandle:
""" """Manages and monitors the state of a child process for package installation."""
This class manages and monitors the state of a child process for a task
used for the building and installation of a package.
"""
def __init__( def __init__(
self, self,
@ -1108,7 +1136,7 @@ def __init__(
): ):
""" """
Parameters: Parameters:
pkg: The package to be built and installed through the child process. pkg: The package to be built and installed by the child process.
process: The child process instance being managed/monitored. process: The child process instance being managed/monitored.
read_pipe: The pipe used for receiving information from the child process. read_pipe: The pipe used for receiving information from the child process.
""" """
@ -1117,12 +1145,12 @@ def __init__(
self.read_pipe = read_pipe self.read_pipe = read_pipe
def poll(self) -> bool: def poll(self) -> bool:
"""Checks if there is data available to receive from the read pipe""" """Check if there is data available to receive from the read pipe."""
return self.read_pipe.poll() return self.read_pipe.poll()
def complete(self): def complete(self):
"""Waits (if needed) for the child process to complete """Wait (if needed) for child process to complete
and returns its exit status. and return its exit status.
See ``complete_build_process()``. See ``complete_build_process()``.
""" """
@ -1295,13 +1323,13 @@ def start_build_process(
Args: Args:
pkg: package whose environment we should set up the pkg: package whose environment we should set up the
child process for. child process for.
function: argless function to run in the child function: argless function to run in the child
process. process.
kwargs: additional keyword arguments to pass to ``function()`` kwargs: additional keyword arguments to pass to ``function()``
timeout: maximum time allowed to finish the execution of function timeout: maximum time allowed to finish the execution of function
Usage: Usage::
def child_fun(): def child_fun():
# do stuff # do stuff
@ -1420,7 +1448,7 @@ def exitcode_msg(process):
return child_result return child_result
CONTEXT_BASES = (spack.package_base.PackageBase, spack.builder.Builder) CONTEXT_BASES = (spack.package_base.PackageBase, spack.build_systems._checks.BaseBuilder)
def get_package_context(traceback, context=3): def get_package_context(traceback, context=3):

View File

@ -1337,7 +1337,7 @@ def __init__(
run tests for some run tests for some
use_cache: Install from binary package, if available. use_cache: Install from binary package, if available.
verbose: Display verbose build output (by default, suppresses it) verbose: Display verbose build output (by default, suppresses it)
concurrent_packages: Number of pkgs that could be concurrently built (using n procs) concurrent_packages: Max packages to be built concurrently
""" """
if isinstance(explicit, bool): if isinstance(explicit, bool):
explicit = {pkg.spec.dag_hash() for pkg in packages} if explicit else set() explicit = {pkg.spec.dag_hash() for pkg in packages} if explicit else set()
@ -2113,7 +2113,7 @@ def start_task(task) -> None:
"""Attempts to start a package installation.""" """Attempts to start a package installation."""
pkg, pkg_id, spec = task.pkg, task.pkg_id, task.pkg.spec pkg, pkg_id, spec = task.pkg, task.pkg_id, task.pkg.spec
install_status.next_pkg(pkg) install_status.next_pkg(pkg)
install_status.set_term_title(f"Processing {task.pkg.name}") # install_status.set_term_title(f"Processing {task.pkg.name}")
tty.debug(f"Processing {pkg_id}: task={task}") tty.debug(f"Processing {pkg_id}: task={task}")
# Skip the installation if the spec is not being installed locally # Skip the installation if the spec is not being installed locally
@ -2122,7 +2122,7 @@ def start_task(task) -> None:
if _handle_external_and_upstream(pkg, task.explicit): if _handle_external_and_upstream(pkg, task.explicit):
term_status.clear() term_status.clear()
self._flag_installed(pkg, task.dependents) self._flag_installed(pkg, task.dependents)
return None return
# Flag a failed spec. Do not need an (install) prefix lock since # Flag a failed spec. Do not need an (install) prefix lock since
# assume using a separate (failed) prefix lock file. # assume using a separate (failed) prefix lock file.
@ -2134,7 +2134,7 @@ def start_task(task) -> None:
if self.fail_fast: if self.fail_fast:
raise spack.error.InstallError(fail_fast_err, pkg=pkg) raise spack.error.InstallError(fail_fast_err, pkg=pkg)
return None return
# Attempt to get a write lock. If we can't get the lock then # Attempt to get a write lock. If we can't get the lock then
# another process is likely (un)installing the spec or has # another process is likely (un)installing the spec or has
@ -2153,7 +2153,7 @@ def start_task(task) -> None:
# -- failed, installed, or uninstalled -- on the next pass. # -- failed, installed, or uninstalled -- on the next pass.
if lock is None: if lock is None:
self._requeue_task(task, install_status) self._requeue_task(task, install_status)
return None return
term_status.clear() term_status.clear()
@ -2163,7 +2163,7 @@ def start_task(task) -> None:
task.request.overwrite_time = time.time() task.request.overwrite_time = time.time()
# Determine state of installation artifacts and adjust accordingly. # Determine state of installation artifacts and adjust accordingly.
install_status.set_term_title(f"Preparing {task.pkg.name}") # install_status.set_term_title(f"Preparing {task.pkg.name}")
self._prepare_for_install(task) self._prepare_for_install(task)
# Flag an already installed package # Flag an already installed package
@ -2187,7 +2187,7 @@ def start_task(task) -> None:
# or uninstalled -- on the next pass. # or uninstalled -- on the next pass.
self.installed.remove(pkg_id) self.installed.remove(pkg_id)
self._requeue_task(task, install_status) self._requeue_task(task, install_status)
return None return
# Having a read lock on an uninstalled pkg may mean another # Having a read lock on an uninstalled pkg may mean another
# process completed an uninstall of the software between the # process completed an uninstall of the software between the
@ -2200,16 +2200,15 @@ def start_task(task) -> None:
if ltype == "read": if ltype == "read":
lock.release_read() lock.release_read()
self._requeue_task(task, install_status) self._requeue_task(task, install_status)
return None return
# Proceed with the installation since we have an exclusive write # Proceed with the installation since we have an exclusive write
# lock on the package. # lock on the package.
# Start a child process for a task that's ready to be installed.
install_status.set_term_title(f"Installing {task.pkg.name}") install_status.set_term_title(f"Installing {task.pkg.name}")
action = self._install_action(task) action = self._install_action(task)
if action == InstallAction.INSTALL: if action == InstallAction.INSTALL:
# Start a child process for a task that's ready to be installed.
task.start() task.start()
tty.msg(install_msg(pkg_id, self.pid, install_status)) tty.msg(install_msg(pkg_id, self.pid, install_status))
active_tasks.append(task) active_tasks.append(task)
@ -2321,7 +2320,6 @@ def complete_task(task) -> None:
self._clear_removed_tasks() self._clear_removed_tasks()
if self.build_pq: if self.build_pq:
task = self._pop_task() task = self._pop_task()
pkg, pkg_id = task.pkg, task.pkg_id
assert task.priority != 0, "Found ready task after _peek_ready_task returned None" assert task.priority != 0, "Found ready task after _peek_ready_task returned None"
# If the spec has uninstalled dependencies # If the spec has uninstalled dependencies
# and no active tasks running, then there must be # and no active tasks running, then there must be
@ -2335,11 +2333,11 @@ def complete_task(task) -> None:
) )
left = [dep_id for dep_id in task.uninstalled_deps if dep_id not in self.installed] left = [dep_id for dep_id in task.uninstalled_deps if dep_id not in self.installed]
if not left: if not left:
tty.warn(f"{pkg_id} does NOT actually have any uninstalled deps left") tty.warn(f"{task.pkg_id} does NOT actually have any uninstalled deps left")
dep_str = "dependencies" if task.priority > 1 else "dependency" dep_str = "dependencies" if task.priority > 1 else "dependency"
raise spack.error.InstallError( raise spack.error.InstallError(
f"Cannot proceed with {pkg_id}: {task.priority} uninstalled " f"Cannot proceed with {task.pkg_id}: {task.priority} uninstalled "
f"{dep_str}: {','.join(task.uninstalled_deps)}", f"{dep_str}: {','.join(task.uninstalled_deps)}",
pkg=task.pkg, pkg=task.pkg,
) )