Automatically find externals (#15158)

Add a `spack external find` command that tries to populate
`packages.yaml` with external packages from the user's `$PATH`. This
focuses on finding build dependencies. Currently, support has only been
added for `cmake`.

For a package to be discoverable with `spack external find`, it must define:
  * an `executables` class attribute containing a list of
    regular expressions that match executable names.
  * a `determine_spec_details(prefix, specs_in_prefix)` method

Spack will call `determine_spec_details()` once for each prefix where
executables are found, passing in the path to the prefix and the path to
all found executables. The package is responsible for invoking the
executables and figuring out what type of installation(s) are in the
prefix, and returning one or more specs (each with version, variants or
whatever else the user decides to include in the spec).

The found specs and prefixes will be added to the user's `packages.yaml`
file. Providing the `--not-buildable` option will mark all generated
entries in `packages.yaml` as `buildable: False`
This commit is contained in:
Peter Scheibel
2020-05-05 17:37:34 -07:00
committed by GitHub
parent 7e5874c250
commit b030a81a5f
7 changed files with 574 additions and 1 deletions

View File

@@ -0,0 +1,34 @@
# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
from spack import *
import os
import re
class FindExternals1(AutotoolsPackage):
executables = ['find-externals1-exe']
url = "http://www.example.com/find-externals-1.0.tar.gz"
version('1.0', 'hash-1.0')
@classmethod
def determine_spec_details(cls, prefix, exes_in_prefix):
exe_to_path = dict(
(os.path.basename(p), p) for p in exes_in_prefix
)
if 'find-externals1-exe' not in exe_to_path:
return None
exe = spack.util.executable.Executable(
exe_to_path['find-externals1-exe'])
output = exe('--version', output=str)
if output:
match = re.search(r'find-externals1.*version\s+(\S+)', output)
if match:
version_str = match.group(1)
return Spec('find-externals1@{0}'.format(version_str))

View File

@@ -5,6 +5,9 @@
from spack import *
import os
import re
class Automake(AutotoolsPackage, GNUMirrorPackage):
"""Automake -- make file builder part of autotools"""
@@ -25,6 +28,24 @@ class Automake(AutotoolsPackage, GNUMirrorPackage):
build_directory = 'spack-build'
executables = ['automake']
@classmethod
def determine_spec_details(cls, prefix, exes_in_prefix):
exe_to_path = dict(
(os.path.basename(p), p) for p in exes_in_prefix
)
if 'automake' not in exe_to_path:
return None
exe = spack.util.executable.Executable(exe_to_path['automake'])
output = exe('--version', output=str)
if output:
match = re.search(r'GNU automake\)\s+(\S+)', output)
if match:
version_str = match.group(1)
return Spec('automake@{0}'.format(version_str))
def patch(self):
# The full perl shebang might be too long
files_to_be_patched_fmt = 'bin/{0}.in'

View File

@@ -5,6 +5,9 @@
from spack import *
import re
import os
class Cmake(Package):
"""A cross-platform, open-source build system. CMake is a family of
@@ -13,6 +16,8 @@ class Cmake(Package):
url = 'https://github.com/Kitware/CMake/releases/download/v3.15.5/cmake-3.15.5.tar.gz'
maintainers = ['chuckatkins']
executables = ['cmake']
version('3.17.1', sha256='3aa9114485da39cbd9665a0bfe986894a282d5f0882b1dea960a739496620727')
version('3.17.0', sha256='b74c05b55115eacc4fa2b77a814981dbda05cdc95a53e279fe16b7b272f00847')
version('3.16.5', sha256='5f760b50b8ecc9c0c37135fae5fbf00a2fef617059aa9d61c1bb91653e5a8bfc')
@@ -146,6 +151,22 @@ class Cmake(Package):
phases = ['bootstrap', 'build', 'install']
@classmethod
def determine_spec_details(cls, prefix, exes_in_prefix):
exe_to_path = dict(
(os.path.basename(p), p) for p in exes_in_prefix
)
if 'cmake' not in exe_to_path:
return None
cmake = spack.util.executable.Executable(exe_to_path['cmake'])
output = cmake('--version', output=str)
if output:
match = re.search(r'cmake.*version\s+(\S+)', output)
if match:
version_str = match.group(1)
return Spec('cmake@{0}'.format(version_str))
def flag_handler(self, name, flags):
if name == 'cxxflags' and self.compiler.name == 'fj':
cxx11plus_flags = (self.compiler.cxx11_flag,