Windows: auto-add WGL/SDK as externals (#43752)
Adds a pre-concretization check for the Windows SDK and WGL (Windows GL) packages as non-buildable externals. This is a redo of https://github.com/spack/spack/pull/43459, but makes sure to modify the configuration scope outside of the bootstrap scope: whichever is highest-precedence in the user's environment at the time the concretization runs, which should either be an env scope or the ~ scope. Adds pytest fixture mocking the check for WGL and WSDK as if they were present.
This commit is contained in:
parent
7f4f42894d
commit
7e8415a3a6
5 changed files with 77 additions and 4 deletions
|
@ -1572,6 +1572,8 @@ Microsoft Visual Studio
|
||||||
"""""""""""""""""""""""
|
"""""""""""""""""""""""
|
||||||
|
|
||||||
Microsoft Visual Studio provides the only Windows C/C++ compiler that is currently supported by Spack.
|
Microsoft Visual Studio provides the only Windows C/C++ compiler that is currently supported by Spack.
|
||||||
|
Spack additionally requires that the Windows SDK (including WGL) to be installed as part of your
|
||||||
|
visual studio installation as it is required to build many packages from source.
|
||||||
|
|
||||||
We require several specific components to be included in the Visual Studio installation.
|
We require several specific components to be included in the Visual Studio installation.
|
||||||
One is the C/C++ toolset, which can be selected as "Desktop development with C++" or "C++ build tools,"
|
One is the C/C++ toolset, which can be selected as "Desktop development with C++" or "C++ build tools,"
|
||||||
|
@ -1579,6 +1581,7 @@ depending on installation type (Professional, Build Tools, etc.) The other requ
|
||||||
"C++ CMake tools for Windows," which can be selected from among the optional packages.
|
"C++ CMake tools for Windows," which can be selected from among the optional packages.
|
||||||
This provides CMake and Ninja for use during Spack configuration.
|
This provides CMake and Ninja for use during Spack configuration.
|
||||||
|
|
||||||
|
|
||||||
If you already have Visual Studio installed, you can make sure these components are installed by
|
If you already have Visual Studio installed, you can make sure these components are installed by
|
||||||
rerunning the installer. Next to your installation, select "Modify" and look at the
|
rerunning the installer. Next to your installation, select "Modify" and look at the
|
||||||
"Installation details" pane on the right.
|
"Installation details" pane on the right.
|
||||||
|
|
|
@ -538,6 +538,41 @@ def ensure_patchelf_in_path_or_raise() -> spack.util.executable.Executable:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_winsdk_external_or_raise() -> None:
|
||||||
|
"""Ensure the Windows SDK + WGL are available on system
|
||||||
|
If both of these package are found, the Spack user or bootstrap
|
||||||
|
configuration (depending on where Spack is running)
|
||||||
|
will be updated to include all versions and variants detected.
|
||||||
|
If either the WDK or WSDK are not found, this method will raise
|
||||||
|
a RuntimeError.
|
||||||
|
|
||||||
|
**NOTE:** This modifies the Spack config in the current scope,
|
||||||
|
either user or environment depending on the calling context.
|
||||||
|
This is different from all other current bootstrap dependency
|
||||||
|
checks.
|
||||||
|
"""
|
||||||
|
if set(["win-sdk", "wgl"]).issubset(spack.config.get("packages").keys()):
|
||||||
|
return
|
||||||
|
externals = spack.detection.by_path(["win-sdk", "wgl"])
|
||||||
|
if not set(["win-sdk", "wgl"]) == externals.keys():
|
||||||
|
missing_packages_lst = []
|
||||||
|
if "wgl" not in externals:
|
||||||
|
missing_packages_lst.append("wgl")
|
||||||
|
if "win-sdk" not in externals:
|
||||||
|
missing_packages_lst.append("win-sdk")
|
||||||
|
missing_packages = " & ".join(missing_packages_lst)
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Unable to find the {missing_packages}, please install these packages \
|
||||||
|
via the Visual Studio installer \
|
||||||
|
before proceeding with Spack or provide the path to a non standard install with \
|
||||||
|
'spack external find --path'"
|
||||||
|
)
|
||||||
|
# wgl/sdk are not required for bootstrapping Spack, but
|
||||||
|
# are required for building anything non trivial
|
||||||
|
# add to user config so they can be used by subsequent Spack ops
|
||||||
|
spack.detection.update_configuration(externals, buildable=False)
|
||||||
|
|
||||||
|
|
||||||
def ensure_core_dependencies() -> None:
|
def ensure_core_dependencies() -> None:
|
||||||
"""Ensure the presence of all the core dependencies."""
|
"""Ensure the presence of all the core dependencies."""
|
||||||
if sys.platform.lower() == "linux":
|
if sys.platform.lower() == "linux":
|
||||||
|
|
|
@ -214,8 +214,6 @@ def unit_test(parser, args, unknown_args):
|
||||||
|
|
||||||
# Ensure clingo is available before switching to the
|
# Ensure clingo is available before switching to the
|
||||||
# mock configuration used by unit tests
|
# mock configuration used by unit tests
|
||||||
# Note: skip on windows here because for the moment,
|
|
||||||
# clingo is wholly unsupported from bootstrap
|
|
||||||
with spack.bootstrap.ensure_bootstrap_configuration():
|
with spack.bootstrap.ensure_bootstrap_configuration():
|
||||||
spack.bootstrap.ensure_core_dependencies()
|
spack.bootstrap.ensure_core_dependencies()
|
||||||
if pytest is None:
|
if pytest is None:
|
||||||
|
|
|
@ -809,12 +809,22 @@ def solve(self, setup, specs, reuse=None, output=None, control=None, allow_depre
|
||||||
A tuple of the solve result, the timer for the different phases of the
|
A tuple of the solve result, the timer for the different phases of the
|
||||||
solve, and the internal statistics from clingo.
|
solve, and the internal statistics from clingo.
|
||||||
"""
|
"""
|
||||||
|
# avoid circular import
|
||||||
|
import spack.bootstrap
|
||||||
|
|
||||||
output = output or DEFAULT_OUTPUT_CONFIGURATION
|
output = output or DEFAULT_OUTPUT_CONFIGURATION
|
||||||
timer = spack.util.timer.Timer()
|
timer = spack.util.timer.Timer()
|
||||||
|
|
||||||
# Initialize the control object for the solver
|
# Initialize the control object for the solver
|
||||||
self.control = control or default_clingo_control()
|
self.control = control or default_clingo_control()
|
||||||
|
|
||||||
|
# ensure core deps are present on Windows
|
||||||
|
# needs to modify active config scope, so cannot be run within
|
||||||
|
# bootstrap config scope
|
||||||
|
if sys.platform == "win32":
|
||||||
|
tty.debug("Ensuring basic dependencies {win-sdk, wgl} available")
|
||||||
|
spack.bootstrap.core.ensure_winsdk_external_or_raise()
|
||||||
|
|
||||||
timer.start("setup")
|
timer.start("setup")
|
||||||
asp_problem = setup.setup(specs, reuse=reuse, allow_deprecated=allow_deprecated)
|
asp_problem = setup.setup(specs, reuse=reuse, allow_deprecated=allow_deprecated)
|
||||||
if output.out is not None:
|
if output.out is not None:
|
||||||
|
@ -1403,7 +1413,6 @@ def condition(
|
||||||
raise ValueError(f"Must provide a name for anonymous condition: '{required_spec}'")
|
raise ValueError(f"Must provide a name for anonymous condition: '{required_spec}'")
|
||||||
|
|
||||||
with spec_with_name(required_spec, name):
|
with spec_with_name(required_spec, name):
|
||||||
|
|
||||||
# Check if we can emit the requirements before updating the condition ID counter.
|
# Check if we can emit the requirements before updating the condition ID counter.
|
||||||
# In this way, if a condition can't be emitted but the exception is handled in the
|
# In this way, if a condition can't be emitted but the exception is handled in the
|
||||||
# caller, we won't emit partial facts.
|
# caller, we won't emit partial facts.
|
||||||
|
|
|
@ -763,6 +763,28 @@ def mutable_empty_config(tmpdir_factory, configuration_dir):
|
||||||
yield cfg
|
yield cfg
|
||||||
|
|
||||||
|
|
||||||
|
# From https://github.com/pytest-dev/pytest/issues/363#issuecomment-1335631998
|
||||||
|
# Current suggested implementation from issue compatible with pytest >= 6.2
|
||||||
|
# this may be subject to change as new versions of Pytest are released
|
||||||
|
# and update the suggested solution
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def monkeypatch_session():
|
||||||
|
with pytest.MonkeyPatch.context() as monkeypatch:
|
||||||
|
yield monkeypatch
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session", autouse=True)
|
||||||
|
def mock_wsdk_externals(monkeypatch_session):
|
||||||
|
"""Skip check for required external packages on Windows during testing
|
||||||
|
Note: In general this should cover this behavior for all tests,
|
||||||
|
however any session scoped fixture involving concretization should
|
||||||
|
include this fixture
|
||||||
|
"""
|
||||||
|
monkeypatch_session.setattr(
|
||||||
|
spack.bootstrap.core, "ensure_winsdk_external_or_raise", _return_none
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
def concretize_scope(mutable_config, tmpdir):
|
def concretize_scope(mutable_config, tmpdir):
|
||||||
"""Adds a scope for concretization preferences"""
|
"""Adds a scope for concretization preferences"""
|
||||||
|
@ -842,7 +864,13 @@ def _store_dir_and_cache(tmpdir_factory):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def mock_store(tmpdir_factory, mock_repo_path, mock_configuration_scopes, _store_dir_and_cache):
|
def mock_store(
|
||||||
|
tmpdir_factory,
|
||||||
|
mock_wsdk_externals,
|
||||||
|
mock_repo_path,
|
||||||
|
mock_configuration_scopes,
|
||||||
|
_store_dir_and_cache,
|
||||||
|
):
|
||||||
"""Creates a read-only mock database with some packages installed note
|
"""Creates a read-only mock database with some packages installed note
|
||||||
that the ref count for dyninst here will be 3, as it's recycled
|
that the ref count for dyninst here will be 3, as it's recycled
|
||||||
across each install.
|
across each install.
|
||||||
|
|
Loading…
Reference in a new issue