mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-20 21:14:14 +08:00
Check clang++/g++ version when compiling CUDA extensions (#63230)
Summary: See https://github.com/pytorch/pytorch/issues/55267 Pull Request resolved: https://github.com/pytorch/pytorch/pull/63230 Reviewed By: soulitzer Differential Revision: D34159119 Pulled By: malfet fbshipit-source-id: 6eef7582388bf6a42dcc1d82b6e4b1f40f418dd7 (cherry picked from commit 2056d0a0be7951602de22f8d3b4efc28dd71b6c2)
This commit is contained in:
committed by
PyTorch MergeBot
parent
3ac7828195
commit
86deecd7be
@ -17,7 +17,8 @@ from .file_baton import FileBaton
|
||||
from ._cpp_extension_versioner import ExtensionVersioner
|
||||
from .hipify import hipify_python
|
||||
from .hipify.hipify_python import get_hip_file_path, GeneratedFileCleaner
|
||||
from typing import List, Optional, Union
|
||||
from typing import List, Optional, Union, Tuple
|
||||
from torch.torch_version import TorchVersion
|
||||
|
||||
from setuptools.command.build_ext import build_ext
|
||||
from pkg_resources import packaging # type: ignore[attr-defined]
|
||||
@ -40,6 +41,28 @@ BUILD_SPLIT_CUDA = os.getenv('BUILD_SPLIT_CUDA') or (os.path.exists(os.path.join
|
||||
TORCH_LIB_PATH, f'{CLIB_PREFIX}torch_cuda_cu{CLIB_EXT}')) and os.path.exists(os.path.join(TORCH_LIB_PATH, f'{CLIB_PREFIX}torch_cuda_cpp{CLIB_EXT}')))
|
||||
|
||||
SUBPROCESS_DECODE_ARGS = ('oem',) if IS_WINDOWS else ()
|
||||
MINIMUM_GCC_VERSION = (5, 0, 0)
|
||||
MINIMUM_MSVC_VERSION = (19, 0, 24215)
|
||||
|
||||
# The following values were taken from the following GitHub gist that
|
||||
# summarizes the minimum valid major versions of g++/clang++ for each supported
|
||||
# CUDA version: https://gist.github.com/ax3l/9489132
|
||||
CUDA_GCC_VERSIONS = {
|
||||
'10.2': (MINIMUM_GCC_VERSION, (8, 0, 0)),
|
||||
'11.1': (MINIMUM_GCC_VERSION, (10, 0, 0)),
|
||||
'11.2': (MINIMUM_GCC_VERSION, (10, 0, 0)),
|
||||
'11.3': (MINIMUM_GCC_VERSION, (10, 0, 0)),
|
||||
'11.4': ((6, 0, 0), (10, 0, 0))
|
||||
}
|
||||
|
||||
CUDA_CLANG_VERSIONS = {
|
||||
'10.2': ((3, 3, 0), (8, 0, 0)),
|
||||
'11.1': ((6, 0, 0), (10, 0, 0)),
|
||||
'11.2': ((6, 0, 0), (10, 0, 0)),
|
||||
'11.3': ((6, 0, 0), (10, 0, 0)),
|
||||
'11.4': ((6, 0, 0), (10, 0, 0))
|
||||
}
|
||||
|
||||
|
||||
# Taken directly from python stdlib < 3.9
|
||||
# See https://github.com/pytorch/pytorch/issues/48617
|
||||
@ -123,8 +146,6 @@ def _join_rocm_home(*paths) -> str:
|
||||
return os.path.join(ROCM_HOME, *paths)
|
||||
|
||||
|
||||
MINIMUM_GCC_VERSION = (5, 0, 0)
|
||||
MINIMUM_MSVC_VERSION = (19, 0, 24215)
|
||||
ABI_INCOMPATIBILITY_WARNING = '''
|
||||
|
||||
!! WARNING !!
|
||||
@ -279,22 +300,23 @@ def check_compiler_ok_for_platform(compiler: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def check_compiler_abi_compatibility(compiler) -> bool:
|
||||
def get_compiler_abi_compatibility_and_version(compiler) -> Tuple[bool, TorchVersion]:
|
||||
r'''
|
||||
Verifies that the given compiler is ABI-compatible with PyTorch.
|
||||
Determine if the given compiler is ABI-compatible with PyTorch alongside
|
||||
its version.
|
||||
|
||||
Args:
|
||||
compiler (str): The compiler executable name to check (e.g. ``g++``).
|
||||
Must be executable in a shell process.
|
||||
|
||||
Returns:
|
||||
False if the compiler is (likely) ABI-incompatible with PyTorch,
|
||||
else True.
|
||||
A tuple that contains a boolean that defines if the compiler is (likely) ABI-incompatible with PyTorch,
|
||||
followed by a `TorchVersion` string that contains the compiler version separated by dots.
|
||||
'''
|
||||
if not _is_binary_build():
|
||||
return True
|
||||
return (True, TorchVersion('0.0.0'))
|
||||
if os.environ.get('TORCH_DONT_CHECK_COMPILER_ABI') in ['ON', '1', 'YES', 'TRUE', 'Y']:
|
||||
return True
|
||||
return (True, TorchVersion('0.0.0'))
|
||||
|
||||
# First check if the compiler is one of the expected ones for the particular platform.
|
||||
if not check_compiler_ok_for_platform(compiler):
|
||||
@ -302,11 +324,11 @@ def check_compiler_abi_compatibility(compiler) -> bool:
|
||||
user_compiler=compiler,
|
||||
pytorch_compiler=_accepted_compilers_for_platform()[0],
|
||||
platform=sys.platform))
|
||||
return False
|
||||
return (False, TorchVersion('0.0.0'))
|
||||
|
||||
if IS_MACOS:
|
||||
# There is no particular minimum version we need for clang, so we're good here.
|
||||
return True
|
||||
return (True, TorchVersion('0.0.0'))
|
||||
try:
|
||||
if IS_LINUX:
|
||||
minimum_required_version = MINIMUM_GCC_VERSION
|
||||
@ -320,15 +342,15 @@ def check_compiler_abi_compatibility(compiler) -> bool:
|
||||
except Exception:
|
||||
_, error, _ = sys.exc_info()
|
||||
warnings.warn(f'Error checking compiler version for {compiler}: {error}')
|
||||
return False
|
||||
return (False, TorchVersion('0.0.0'))
|
||||
|
||||
if tuple(map(int, version)) >= minimum_required_version:
|
||||
return True
|
||||
return (True, TorchVersion('.'.join(version)))
|
||||
|
||||
compiler = f'{compiler} {".".join(version)}'
|
||||
warnings.warn(ABI_INCOMPATIBILITY_WARNING.format(compiler))
|
||||
|
||||
return False
|
||||
return (False, TorchVersion('.'.join(version)))
|
||||
|
||||
|
||||
# See below for why we inherit BuildExtension from object.
|
||||
@ -393,7 +415,7 @@ class BuildExtension(build_ext, object):
|
||||
self.force = True
|
||||
|
||||
def build_extensions(self) -> None:
|
||||
self._check_abi()
|
||||
compiler_name, compiler_version = self._check_abi()
|
||||
|
||||
cuda_ext = False
|
||||
extension_iter = iter(self.extensions)
|
||||
@ -407,7 +429,7 @@ class BuildExtension(build_ext, object):
|
||||
extension = next(extension_iter, None)
|
||||
|
||||
if cuda_ext and not IS_HIP_EXTENSION:
|
||||
self._check_cuda_version()
|
||||
self._check_cuda_version(compiler_name, compiler_version)
|
||||
|
||||
for extension in self.extensions:
|
||||
# Ensure at least an empty list of flags for 'cxx' and 'nvcc' when
|
||||
@ -756,7 +778,7 @@ class BuildExtension(build_ext, object):
|
||||
ext_filename = '.'.join(without_abi)
|
||||
return ext_filename
|
||||
|
||||
def _check_abi(self):
|
||||
def _check_abi(self) -> Tuple[str, TorchVersion]:
|
||||
# On some platforms, like Windows, compiler_cxx is not available.
|
||||
if hasattr(self.compiler, 'compiler_cxx'):
|
||||
compiler = self.compiler.compiler_cxx[0]
|
||||
@ -764,15 +786,16 @@ class BuildExtension(build_ext, object):
|
||||
compiler = os.environ.get('CXX', 'cl')
|
||||
else:
|
||||
compiler = os.environ.get('CXX', 'c++')
|
||||
check_compiler_abi_compatibility(compiler)
|
||||
_, version = get_compiler_abi_compatibility_and_version(compiler)
|
||||
# Warn user if VC env is activated but `DISTUILS_USE_SDK` is not set.
|
||||
if IS_WINDOWS and 'VSCMD_ARG_TGT_ARCH' in os.environ and 'DISTUTILS_USE_SDK' not in os.environ:
|
||||
msg = ('It seems that the VC environment is activated but DISTUTILS_USE_SDK is not set.'
|
||||
'This may lead to multiple activations of the VC env.'
|
||||
'Please set `DISTUTILS_USE_SDK=1` and try again.')
|
||||
raise UserWarning(msg)
|
||||
return compiler, version
|
||||
|
||||
def _check_cuda_version(self):
|
||||
def _check_cuda_version(self, compiler_name: str, compiler_version: TorchVersion):
|
||||
if CUDA_HOME:
|
||||
nvcc = os.path.join(CUDA_HOME, 'bin', 'nvcc')
|
||||
cuda_version_str = subprocess.check_output([nvcc, '--version']).strip().decode(*SUBPROCESS_DECODE_ARGS)
|
||||
@ -786,7 +809,33 @@ class BuildExtension(build_ext, object):
|
||||
if getattr(cuda_ver, "major", float("nan")) != getattr(torch_cuda_version, "major", float("nan")):
|
||||
raise RuntimeError(CUDA_MISMATCH_MESSAGE.format(cuda_str_version, torch.version.cuda))
|
||||
warnings.warn(CUDA_MISMATCH_WARN.format(cuda_str_version, torch.version.cuda))
|
||||
if (sys.platform.startswith('linux') and
|
||||
os.environ.get('TORCH_DONT_CHECK_COMPILER_ABI') not in ['ON', '1', 'YES', 'TRUE', 'Y'] and
|
||||
_is_binary_build()):
|
||||
cuda_compiler_bounds = CUDA_CLANG_VERSIONS if compiler_name.startswith('clang') else CUDA_GCC_VERSIONS
|
||||
|
||||
if cuda_str_version not in cuda_compiler_bounds:
|
||||
warnings.warn(f'There are no {compiler_name} version bounds defined for CUDA version {cuda_str_version}')
|
||||
else:
|
||||
min_compiler_version, max_compiler_version = cuda_compiler_bounds[cuda_str_version]
|
||||
min_compiler_version_str = '.'.join(map(str, min_compiler_version))
|
||||
max_compiler_version_str = '.'.join(map(str, max_compiler_version))
|
||||
|
||||
version_bound_str = f'>={min_compiler_version_str}'
|
||||
version_bound_str = f'{version_bound_str}, <={max_compiler_version_str}'
|
||||
|
||||
if compiler_version < TorchVersion(min_compiler_version_str):
|
||||
raise RuntimeError(
|
||||
f'The current installed version of {compiler_name} ({compiler_version}) is less '
|
||||
f'than the minimum required version by CUDA {cuda_str_version} ({min_compiler_version_str}). '
|
||||
f'Please make sure to use an adequate version of {compiler_name} ({version_bound_str}).'
|
||||
)
|
||||
elif compiler_version > TorchVersion(max_compiler_version_str):
|
||||
raise RuntimeError(
|
||||
f'The current installed version of {compiler_name} ({compiler_version}) is greater '
|
||||
f'than the maximum required version by CUDA {cuda_str_version} ({max_compiler_version_str}). '
|
||||
f'Please make sure to use an adequate version of {compiler_name} ({version_bound_str}).'
|
||||
)
|
||||
else:
|
||||
raise RuntimeError(CUDA_NOT_FOUND_MESSAGE)
|
||||
|
||||
@ -1397,7 +1446,7 @@ def _write_ninja_file_and_compile_objects(
|
||||
compiler = os.environ.get('CXX', 'cl')
|
||||
else:
|
||||
compiler = os.environ.get('CXX', 'c++')
|
||||
check_compiler_abi_compatibility(compiler)
|
||||
get_compiler_abi_compatibility_and_version(compiler)
|
||||
if with_cuda is None:
|
||||
with_cuda = any(map(_is_cuda_file, sources))
|
||||
build_file_path = os.path.join(build_directory, 'build.ninja')
|
||||
@ -1440,7 +1489,7 @@ def _write_ninja_file_and_build_library(
|
||||
compiler = os.environ.get('CXX', 'cl')
|
||||
else:
|
||||
compiler = os.environ.get('CXX', 'c++')
|
||||
check_compiler_abi_compatibility(compiler)
|
||||
get_compiler_abi_compatibility_and_version(compiler)
|
||||
if with_cuda is None:
|
||||
with_cuda = any(map(_is_cuda_file, sources))
|
||||
extra_ldflags = _prepare_ldflags(
|
||||
|
Reference in New Issue
Block a user