Windows: reenable unit tests (#33385)

Unit tests on Windows are supposed to pass for any PR to pass CI.
However, the return code for the unit test command was not being
checked, which meant this check was always passing (effectively
disabled). This PR

* Properly checks the result of the unit tests and fails if the
  unit tests fail
* Fixes (or disables on Windows) a number of tests which have
  "drifted" out of support on Windows since this check was
  effectively disabled
This commit is contained in:
John W. Parent 2022-12-09 08:27:46 -05:00 committed by GitHub
parent ec62150ed7
commit 0e69710f41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 190 additions and 135 deletions

View file

@ -1,6 +1,4 @@
# (c) 2021 Lawrence Livermore National Laboratory
Set-Location spack
# (c) 2022 Lawrence Livermore National Laboratory
git config --global user.email "spack@example.com"
git config --global user.name "Test User"

View file

@ -10,7 +10,7 @@ concurrency:
defaults:
run:
shell:
powershell Invoke-Expression -Command ".\share\spack\qa\windows_test_setup.ps1"; {0}
powershell Invoke-Expression -Command "./share/spack/qa/windows_test_setup.ps1"; {0}
jobs:
unit-tests:
runs-on: windows-latest
@ -26,13 +26,11 @@ jobs:
python -m pip install --upgrade pip six pywin32 setuptools codecov pytest-cov clingo
- name: Create local develop
run: |
.\spack\.github\workflows\setup_git.ps1
./.github/workflows/setup_git.ps1
- name: Unit Test
run: |
echo F|xcopy .\spack\share\spack\qa\configuration\windows_config.yaml $env:USERPROFILE\.spack\windows\config.yaml
cd spack
dir
spack unit-test -x --verbose --cov --cov-config=pyproject.toml --ignore=lib/spack/spack/test/cmd
./share/spack/qa/validate_last_exit.ps1
coverage combine -a
coverage xml
- uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70
@ -52,12 +50,11 @@ jobs:
python -m pip install --upgrade pip six pywin32 setuptools codecov coverage pytest-cov clingo
- name: Create local develop
run: |
.\spack\.github\workflows\setup_git.ps1
./.github/workflows/setup_git.ps1
- name: Command Unit Test
run: |
echo F|xcopy .\spack\share\spack\qa\configuration\windows_config.yaml $env:USERPROFILE\.spack\windows\config.yaml
cd spack
spack unit-test -x --verbose --cov --cov-config=pyproject.toml lib/spack/spack/test/cmd
./share/spack/qa/validate_last_exit.ps1
coverage combine -a
coverage xml
- uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70
@ -78,81 +75,81 @@ jobs:
- name: Build Test
run: |
spack compiler find
echo F|xcopy .\spack\share\spack\qa\configuration\windows_config.yaml $env:USERPROFILE\.spack\windows\config.yaml
spack external find cmake
spack external find ninja
spack -d install abseil-cpp
make-installer:
runs-on: windows-latest
steps:
- name: Disable Windows Symlinks
run: |
git config --global core.symlinks false
shell:
powershell
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
fetch-depth: 0
- uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984
with:
python-version: 3.9
- name: Install Python packages
run: |
python -m pip install --upgrade pip six pywin32 setuptools
- name: Add Light and Candle to Path
run: |
$env:WIX >> $GITHUB_PATH
- name: Run Installer
run: |
.\spack\share\spack\qa\setup_spack.ps1
spack make-installer -s spack -g SILENT pkg
echo "installer_root=$((pwd).Path)" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
env:
ProgressPreference: SilentlyContinue
- uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb
with:
name: Windows Spack Installer Bundle
path: ${{ env.installer_root }}\pkg\Spack.exe
- uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb
with:
name: Windows Spack Installer
path: ${{ env.installer_root}}\pkg\Spack.msi
execute-installer:
needs: make-installer
runs-on: windows-latest
defaults:
run:
shell: pwsh
steps:
- uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984
with:
python-version: 3.9
- name: Install Python packages
run: |
python -m pip install --upgrade pip six pywin32 setuptools
- name: Setup installer directory
run: |
mkdir -p spack_installer
echo "spack_installer=$((pwd).Path)\spack_installer" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
- uses: actions/download-artifact@v3
with:
name: Windows Spack Installer Bundle
path: ${{ env.spack_installer }}
- name: Execute Bundled Installer
run: |
$proc = Start-Process ${{ env.spack_installer }}\spack.exe "/install /quiet" -Passthru
$handle = $proc.Handle # cache proc.Handle
$proc.WaitForExit();
$LASTEXITCODE
env:
ProgressPreference: SilentlyContinue
- uses: actions/download-artifact@v3
with:
name: Windows Spack Installer
path: ${{ env.spack_installer }}
- name: Execute MSI
run: |
$proc = Start-Process ${{ env.spack_installer }}\spack.msi "/quiet" -Passthru
$handle = $proc.Handle # cache proc.Handle
$proc.WaitForExit();
$LASTEXITCODE
# TODO: johnwparent - reduce the size of the installer operations
# make-installer:
# runs-on: windows-latest
# steps:
# - name: Disable Windows Symlinks
# run: |
# git config --global core.symlinks false
# shell:
# powershell
# - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
# with:
# fetch-depth: 0
# - uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984
# with:
# python-version: 3.9
# - name: Install Python packages
# run: |
# python -m pip install --upgrade pip six pywin32 setuptools
# - name: Add Light and Candle to Path
# run: |
# $env:WIX >> $GITHUB_PATH
# - name: Run Installer
# run: |
# ./share/spack/qa/setup_spack_installer.ps1
# spack make-installer -s . -g SILENT pkg
# echo "installer_root=$((pwd).Path)" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
# env:
# ProgressPreference: SilentlyContinue
# - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb
# with:
# name: Windows Spack Installer Bundle
# path: ${{ env.installer_root }}\pkg\Spack.exe
# - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb
# with:
# name: Windows Spack Installer
# path: ${{ env.installer_root}}\pkg\Spack.msi
# execute-installer:
# needs: make-installer
# runs-on: windows-latest
# defaults:
# run:
# shell: pwsh
# steps:
# - uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984
# with:
# python-version: 3.9
# - name: Install Python packages
# run: |
# python -m pip install --upgrade pip six pywin32 setuptools
# - name: Setup installer directory
# run: |
# mkdir -p spack_installer
# echo "spack_installer=$((pwd).Path)\spack_installer" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
# - uses: actions/download-artifact@v3
# with:
# name: Windows Spack Installer Bundle
# path: ${{ env.spack_installer }}
# - name: Execute Bundled Installer
# run: |
# $proc = Start-Process ${{ env.spack_installer }}\spack.exe "/install /quiet" -Passthru
# $handle = $proc.Handle # cache proc.Handle
# $proc.WaitForExit();
# $LASTEXITCODE
# env:
# ProgressPreference: SilentlyContinue
# - uses: actions/download-artifact@v3
# with:
# name: Windows Spack Installer
# path: ${{ env.spack_installer }}
# - name: Execute MSI
# run: |
# $proc = Start-Process ${{ env.spack_installer }}\spack.msi "/quiet" -Passthru
# $handle = $proc.Handle # cache proc.Handle
# $proc.WaitForExit();
# $LASTEXITCODE

View file

@ -99,7 +99,9 @@ def getuid():
def rename(src, dst):
# On Windows, os.rename will fail if the destination file already exists
if is_windows:
if os.path.exists(dst):
# Windows path existence checks will sometimes fail on junctions/links/symlinks
# so check for that case
if os.path.exists(dst) or os.path.islink(dst):
os.remove(dst)
os.rename(src, dst)
@ -288,7 +290,10 @@ def groupid_to_group(x):
shutil.copy(filename, tmp_filename)
try:
extra_kwargs = {"errors": "surrogateescape"}
# To avoid translating line endings (\n to \r\n and vis versa)
# we force os.open to ignore translations and use the line endings
# the file comes with
extra_kwargs = {"errors": "surrogateescape", "newline": ""}
# Open as a text file and filter until the end of the file is
# reached or we found a marker in the line if it was specified

View file

@ -545,8 +545,9 @@ def ensure_core_dependencies():
"""Ensure the presence of all the core dependencies."""
if sys.platform.lower() == "linux":
ensure_patchelf_in_path_or_raise()
if not IS_WINDOWS:
ensure_gpg_in_path_or_raise()
ensure_clingo_importable_or_raise()
ensure_gpg_in_path_or_raise()
def all_core_root_specs():

View file

@ -9,6 +9,7 @@
import platform
import re
import shutil
import sys
import tempfile
from typing import List, Optional, Sequence
@ -27,6 +28,8 @@
__all__ = ["Compiler"]
is_windows = sys.platform == "win32"
@llnl.util.lang.memoized
def _get_compiler_version_output(compiler_path, version_arg, ignore_errors=()):
@ -592,7 +595,16 @@ def search_regexps(cls, language):
# defined for the compiler
compiler_names = getattr(cls, "{0}_names".format(language))
prefixes = [""] + cls.prefixes
suffixes = [""] + cls.suffixes
suffixes = [""]
# Windows compilers generally have an extension of some sort
# as do most files on Windows, handle that case here
if is_windows:
ext = r"\.(?:exe|bat)"
cls_suf = [suf + ext for suf in cls.suffixes]
ext_suf = [ext]
suffixes = suffixes + cls.suffixes + cls_suf + ext_suf
else:
suffixes = suffixes + cls.suffixes
regexp_fmt = r"^({0}){1}({2})$"
return [
re.compile(regexp_fmt.format(prefix, re.escape(name), suffix))

View file

@ -722,6 +722,8 @@ def _default_make_compilers(cmp_id, paths):
compiler_cls = spack.compilers.class_for_compiler_name(compiler_name)
spec = spack.spec.CompilerSpec(compiler_cls.name, version)
paths = [paths.get(x, None) for x in ("cc", "cxx", "f77", "fc")]
# TODO: johnwparent - revist the following line as per discussion at:
# https://github.com/spack/spack/pull/33385/files#r1040036318
target = archspec.cpu.host()
compiler = compiler_cls(spec, operating_system, str(target.family), paths)
return [compiler]

View file

@ -42,16 +42,16 @@ def get_valid_fortran_pth(comp_ver):
class Msvc(Compiler):
# Subclasses use possible names of C compiler
cc_names: List[str] = ["cl.exe"]
cc_names: List[str] = ["cl"]
# Subclasses use possible names of C++ compiler
cxx_names: List[str] = ["cl.exe"]
cxx_names: List[str] = ["cl"]
# Subclasses use possible names of Fortran 77 compiler
f77_names: List[str] = ["ifx.exe"]
f77_names: List[str] = ["ifx"]
# Subclasses use possible names of Fortran 90 compiler
fc_names: List[str] = ["ifx.exe"]
fc_names: List[str] = ["ifx"]
# Named wrapper links within build_env_path
# Due to the challenges of supporting compiler wrappers

View file

@ -1289,7 +1289,7 @@ def __init__(
# have package.py files for.
self._normal = normal
self._concrete = concrete
self.external_path = external_path
self._external_path = external_path
self.external_modules = Spec._format_module_list(external_modules)
# This attribute is used to store custom information for
@ -1326,6 +1326,14 @@ def _format_module_list(modules):
modules = list(modules)
return modules
@property
def external_path(self):
return pth.path_to_os_path(self._external_path)[0]
@external_path.setter
def external_path(self, ext_path):
self._external_path = ext_path
@property
def external(self):
return bool(self.external_path) or bool(self.external_modules)

View file

@ -3,6 +3,7 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os.path
import sys
import pytest
@ -123,6 +124,10 @@ def test_old_style_compatibility_with_super(spec_str, method_name, expected):
assert value == expected
@pytest.mark.skipif(
sys.platform == "win32",
reason="log_ouput cannot currently be used outside of subprocess on Windows",
)
@pytest.mark.regression("33928")
@pytest.mark.usefixtures("builder_test_repository", "config", "working_env")
@pytest.mark.disable_clean_stage_check

View file

@ -347,7 +347,7 @@ def _determine_variants(cls, exes, version_str):
assert "externals" in packages_yaml["gcc"]
externals = packages_yaml["gcc"]["externals"]
assert len(externals) == 1
assert externals[0]["prefix"] == "/opt/gcc/bin"
assert externals[0]["prefix"] == os.path.sep + os.path.join("opt", "gcc", "bin")
def test_new_entries_are_reported_correctly(

View file

@ -3,6 +3,7 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import sys
from textwrap import dedent
from spack.main import SpackCommand
@ -18,12 +19,24 @@ def test_list():
def test_list_cli_output_format(mock_tty_stdout):
out = list("mpileaks")
assert out == dedent(
"""\
# Currently logging on Windows detaches stdout
# from the terminal so we miss some output during tests
# TODO: (johnwparent): Once logging is amended on Windows,
# restore this test
if not sys.platform == "win32":
out_str = dedent(
"""\
mpileaks
==> 1 packages
"""
)
)
else:
out_str = dedent(
"""\
mpileaks
"""
)
assert out == out_str
def test_list_filter(mock_packages):

View file

@ -208,9 +208,7 @@ def _warn(*args, **kwargs):
# Note: I want to use https://docs.pytest.org/en/7.1.x/how-to/skipping.html#skip-all-test-functions-of-a-class-or-module
# the style formatter insists on separating these two lines.
pytest.mark.skipif(sys.platform == "win32", reason="Envs unsupported on Windows")
@pytest.mark.skipif(sys.platform == "win32", reason="Envs unsupported on Windows")
class TestUninstallFromEnv(object):
"""Tests an installation with two environments e1 and e2, which each have
shared package installations:

View file

@ -3,7 +3,6 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os
import posixpath
import sys
import jinja2
@ -339,7 +338,7 @@ def test_concretize_compiler_flag_propagate(self):
assert spec.satisfies("^openblas cflags='-g'")
@pytest.mark.skipif(
os.environ.get("SPACK_TEST_SOLVER") == "original" or sys.platform == "win32",
os.environ.get("SPACK_TEST_SOLVER") == "original",
reason="Optional compiler propagation isn't deprecated for original concretizer",
)
def test_concretize_compiler_flag_does_not_propagate(self):
@ -349,7 +348,7 @@ def test_concretize_compiler_flag_does_not_propagate(self):
assert not spec.satisfies("^openblas cflags='-g'")
@pytest.mark.skipif(
os.environ.get("SPACK_TEST_SOLVER") == "original" or sys.platform == "win32",
os.environ.get("SPACK_TEST_SOLVER") == "original",
reason="Optional compiler propagation isn't deprecated for original concretizer",
)
def test_concretize_propagate_compiler_flag_not_passed_to_dependent(self):
@ -449,7 +448,7 @@ def test_concretize_two_virtuals_with_dual_provider_and_a_conflict(self):
s.concretize()
@pytest.mark.skipif(
os.environ.get("SPACK_TEST_SOLVER") == "original" or sys.platform == "win32",
os.environ.get("SPACK_TEST_SOLVER") == "original",
reason="Optional compiler propagation isn't deprecated for original concretizer",
)
def test_concretize_propagate_disabled_variant(self):
@ -466,7 +465,6 @@ def test_concretize_propagated_variant_is_not_passed_to_dependent(self):
assert spec.satisfies("^openblas+shared")
@pytest.mark.skipif(sys.platform == "win32", reason="No Compiler for Arch on Win")
def test_no_matching_compiler_specs(self, mock_low_high_config):
# only relevant when not building compilers as needed
with spack.concretize.enable_compiler_existence_check():
@ -527,7 +525,7 @@ def test_compiler_inheritance(self, compiler_str):
def test_external_package(self):
spec = Spec("externaltool%gcc")
spec.concretize()
assert spec["externaltool"].external_path == posixpath.sep + posixpath.join(
assert spec["externaltool"].external_path == os.path.sep + os.path.join(
"path", "to", "external_tool"
)
assert "externalprereq" not in spec
@ -558,10 +556,10 @@ def test_nobuild_package(self):
def test_external_and_virtual(self):
spec = Spec("externaltest")
spec.concretize()
assert spec["externaltool"].external_path == posixpath.sep + posixpath.join(
assert spec["externaltool"].external_path == os.path.sep + os.path.join(
"path", "to", "external_tool"
)
assert spec["stuff"].external_path == posixpath.sep + posixpath.join(
assert spec["stuff"].external_path == os.path.sep + os.path.join(
"path", "to", "external_virtual_gcc"
)
assert spec["externaltool"].compiler.satisfies("gcc")
@ -1815,7 +1813,6 @@ def test_git_hash_assigned_version_is_preferred(self):
c = s.concretized()
assert hash in str(c)
@pytest.mark.skipif(sys.platform == "win32", reason="Not supported on Windows (yet)")
@pytest.mark.parametrize("git_ref", ("a" * 40, "0.2.15", "main"))
def test_git_ref_version_is_equivalent_to_specified_version(self, git_ref):
if spack.config.get("config:concretizer") == "original":
@ -1827,7 +1824,6 @@ def test_git_ref_version_is_equivalent_to_specified_version(self, git_ref):
assert s.satisfies("@develop")
assert s.satisfies("@0.1:")
@pytest.mark.skipif(sys.platform == "win32", reason="Not supported on Windows (yet)")
@pytest.mark.parametrize("git_ref", ("a" * 40, "0.2.15", "fbranch"))
def test_git_ref_version_errors_if_unknown_version(self, git_ref):
if spack.config.get("config:concretizer") == "original":

View file

@ -270,7 +270,7 @@ def test_external_mpi(self):
# ensure that once config is in place, external is used
spec = Spec("mpi")
spec.concretize()
assert spec["mpich"].external_path == os.sep + os.path.join("dummy", "path")
assert spec["mpich"].external_path == os.path.sep + os.path.join("dummy", "path")
def test_external_module(self, monkeypatch):
"""Test that packages can find externals specified by module
@ -305,7 +305,7 @@ def mock_module(cmd, module):
# ensure that once config is in place, external is used
spec = Spec("mpi")
spec.concretize()
assert spec["mpich"].external_path == "/dummy/path"
assert spec["mpich"].external_path == os.path.sep + os.path.join("dummy", "path")
def test_buildable_false(self):
conf = syaml.load_config(

View file

@ -259,6 +259,17 @@ def _verify_executables_noop(*args):
return None
def _host():
"""Mock archspec host so there is no inconsistency on the Windows platform
This function cannot be local as it needs to be pickleable"""
return archspec.cpu.Microarchitecture("x86_64", [], "generic", [], {}, 0)
@pytest.fixture(scope="function")
def archspec_host_is_spack_test_host(monkeypatch):
monkeypatch.setattr(archspec.cpu, "host", _host)
#
# Disable checks on compiler executable existence
#

View file

@ -719,13 +719,13 @@ def test_external_entries_in_db(mutable_database):
assert not rec.spec.external_modules
rec = mutable_database.get_record("externaltool")
assert rec.spec.external_path == os.sep + os.path.join("path", "to", "external_tool")
assert rec.spec.external_path == os.path.sep + os.path.join("path", "to", "external_tool")
assert not rec.spec.external_modules
assert rec.explicit is False
rec.spec.package.do_install(fake=True, explicit=True)
rec = mutable_database.get_record("externaltool")
assert rec.spec.external_path == os.sep + os.path.join("path", "to", "external_tool")
assert rec.spec.external_path == os.path.sep + os.path.join("path", "to", "external_tool")
assert not rec.spec.external_modules
assert rec.explicit is True

View file

@ -488,7 +488,7 @@ def fake_package_list(compiler, architecture, pkgs):
def test_bootstrapping_compilers_with_different_names_from_spec(
install_mockery, mutable_config, mock_fetch
install_mockery, mutable_config, mock_fetch, archspec_host_is_spack_test_host
):
with spack.config.override("config:install_missing_compilers", True):
with spack.concretize.disable_compiler_existence_check():

View file

@ -3,6 +3,7 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import itertools
import sys
import pytest
@ -11,6 +12,8 @@
import spack.variant
from spack.parser import SpecParser, SpecTokenizationError, Token, TokenType
is_windows = sys.platform == "win32"
def simple_package_name(name):
"""A simple package name in canonical form"""
@ -834,6 +837,7 @@ def test_error_conditions(text, exc_cls):
SpecParser(text).next_spec()
@pytest.mark.skipif(is_windows, reason="Spec parsing does not currently support Windows paths")
def test_parse_specfile_simple(specfile_for, tmpdir):
specfile = tmpdir.join("libdwarf.json")
s = specfile_for("libdwarf", specfile)
@ -879,6 +883,7 @@ def test_parse_filename_missing_slash_as_spec(specfile_for, tmpdir, filename):
)
@pytest.mark.skipif(is_windows, reason="Spec parsing does not currently support Windows paths")
def test_parse_specfile_dependency(default_mock_concretization, tmpdir):
"""Ensure we can use a specfile as a dependency"""
s = default_mock_concretization("libdwarf")

View file

@ -122,7 +122,7 @@ def path_to_os_path(*pths):
"""
ret_pths = []
for pth in pths:
if type(pth) is str and not is_path_url(pth):
if isinstance(pth, str) and not is_path_url(pth):
pth = convert_to_platform_path(pth)
ret_pths.append(pth)
return ret_pths

View file

@ -1,3 +0,0 @@
spack compiler find
echo F|xcopy .\spack\share\spack\qa\configuration\windows_config.yaml $env:USERPROFILE\.spack\windows\config.yaml
spack external find cmake

View file

@ -0,0 +1,2 @@
spack compiler find
spack external find cmake

View file

@ -0,0 +1,3 @@
if ($LASTEXITCODE -ne 0){
throw "Unit Tests have failed"
}

View file

@ -1,11 +1,5 @@
Set-Location ../
$env:python_pf_ver="C:\hostedtoolcache\windows\Python\3.9.5\x64\python.exe"
cmd /c "`"spack\bin\spack_cmd.bat`" print " |
foreach {
if ($_ -match "=") {
$v = $_.split("=")
[Environment]::SetEnvironmentVariable($v[0], $v[1])
}
}
$ErrorActionPreference = "SilentlyContinue"
Write-Output F|xcopy .\share\spack\qa\configuration\windows_config.yaml $env:USERPROFILE\.spack\windows\config.yaml
# The line below prevents the _spack_root symlink from causing issues with cyclic symlinks on Windows
(Get-Item '.\lib\spack\docs\_spack_root').Delete()
./share/spack/setup-env.ps1

View file

@ -3,6 +3,8 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import sys
from spack.package import *
@ -23,6 +25,12 @@ def compiler_search_prefix(self):
def install(self, spec, prefix):
# Create the minimal compiler that will fool `spack compiler find`
mkdirp(self.compiler_search_prefix)
with open(self.compiler_search_prefix.icx, "w") as f:
f.write('#!/bin/bash\necho "oneAPI DPC++ Compiler %s"' % str(spec.version))
set_executable(self.compiler_search_prefix.icx)
comp = self.compiler_search_prefix.icx
if sys.platform == "win32":
comp = comp + ".bat"
comp_string = "@echo off\necho oneAPI DPC++ Compiler %s" % str(spec.version)
else:
comp_string = '#!/bin/bash\necho "oneAPI DPC++ Compiler %s"' % str(spec.version)
with open(comp, "w") as f:
f.write(comp_string)
set_executable(comp)