blob: de885f71d1873f9bbdb5287d59121cbc62f490f9 [file] [log] [blame]
"""Repository rule for ROCm autoconfiguration.
`rocm_configure` depends on the following environment variables:
* `TF_NEED_ROCM`: Whether to enable building with ROCm.
* `GCC_HOST_COMPILER_PATH`: The GCC host compiler path
* `ROCM_TOOLKIT_PATH`: The path to the ROCm toolkit. Default is
`/opt/rocm`.
* `TF_ROCM_VERSION`: The version of the ROCm toolkit. If this is blank, then
use the system default.
* `TF_MIOPEN_VERSION`: The version of the MIOpen library.
* `TF_ROCM_AMDGPU_TARGETS`: The AMDGPU targets. Default is
`gfx803,gfx900`.
"""
load(
":cuda_configure.bzl",
"make_copy_dir_rule",
"make_copy_files_rule",
"to_list_of_strings",
)
load(
"//third_party/remote_config:common.bzl",
"err_out",
"execute",
"files_exist",
"get_bash_bin",
"get_cpu_value",
"raw_exec",
"realpath",
"which",
)
_GCC_HOST_COMPILER_PATH = "GCC_HOST_COMPILER_PATH"
_GCC_HOST_COMPILER_PREFIX = "GCC_HOST_COMPILER_PREFIX"
_ROCM_TOOLKIT_PATH = "ROCM_TOOLKIT_PATH"
_TF_ROCM_VERSION = "TF_ROCM_VERSION"
_TF_MIOPEN_VERSION = "TF_MIOPEN_VERSION"
_TF_ROCM_AMDGPU_TARGETS = "TF_ROCM_AMDGPU_TARGETS"
_TF_ROCM_CONFIG_REPO = "TF_ROCM_CONFIG_REPO"
_DEFAULT_ROCM_VERSION = ""
_DEFAULT_MIOPEN_VERSION = ""
_DEFAULT_ROCM_TOOLKIT_PATH = "/opt/rocm"
_DEFAULT_ROCM_AMDGPU_TARGETS = ["gfx803", "gfx900"]
def verify_build_defines(params):
"""Verify all variables that crosstool/BUILD.rocm.tpl expects are substituted.
Args:
params: dict of variables that will be passed to the BUILD.tpl template.
"""
missing = []
for param in [
"cxx_builtin_include_directories",
"extra_no_canonical_prefixes_flags",
"host_compiler_path",
"host_compiler_prefix",
"linker_bin_path",
"unfiltered_compile_flags",
]:
if ("%{" + param + "}") not in params:
missing.append(param)
if missing:
auto_configure_fail(
"BUILD.rocm.tpl template is missing these variables: " +
str(missing) +
".\nWe only got: " +
str(params) +
".",
)
def find_cc(repository_ctx):
"""Find the C++ compiler."""
# Return a dummy value for GCC detection here to avoid error
target_cc_name = "gcc"
cc_path_envvar = _GCC_HOST_COMPILER_PATH
cc_name = target_cc_name
if cc_path_envvar in repository_ctx.os.environ:
cc_name_from_env = repository_ctx.os.environ[cc_path_envvar].strip()
if cc_name_from_env:
cc_name = cc_name_from_env
if cc_name.startswith("/"):
# Absolute path, maybe we should make this supported by our which function.
return cc_name
cc = which(repository_ctx, cc_name)
if cc == None:
fail(("Cannot find {}, either correct your path or set the {}" +
" environment variable").format(target_cc_name, cc_path_envvar))
return cc
_INC_DIR_MARKER_BEGIN = "#include <...>"
def _cxx_inc_convert(path):
"""Convert path returned by cc -E xc++ in a complete path."""
path = path.strip()
return path
def _get_cxx_inc_directories_impl(repository_ctx, cc, lang_is_cpp):
"""Compute the list of default C or C++ include directories."""
if lang_is_cpp:
lang = "c++"
else:
lang = "c"
# TODO: We pass -no-canonical-prefixes here to match the compiler flags,
# but in rocm_clang CROSSTOOL file that is a `feature` and we should
# handle the case when it's disabled and no flag is passed
result = raw_exec(repository_ctx, [
cc,
"-no-canonical-prefixes",
"-E",
"-x" + lang,
"-",
"-v",
])
stderr = err_out(result)
index1 = stderr.find(_INC_DIR_MARKER_BEGIN)
if index1 == -1:
return []
index1 = stderr.find("\n", index1)
if index1 == -1:
return []
index2 = stderr.rfind("\n ")
if index2 == -1 or index2 < index1:
return []
index2 = stderr.find("\n", index2 + 1)
if index2 == -1:
inc_dirs = stderr[index1 + 1:]
else:
inc_dirs = stderr[index1 + 1:index2].strip()
return [
str(repository_ctx.path(_cxx_inc_convert(p)))
for p in inc_dirs.split("\n")
]
def get_cxx_inc_directories(repository_ctx, cc):
"""Compute the list of default C and C++ include directories."""
# For some reason `clang -xc` sometimes returns include paths that are
# different from the ones from `clang -xc++`. (Symlink and a dir)
# So we run the compiler with both `-xc` and `-xc++` and merge resulting lists
includes_cpp = _get_cxx_inc_directories_impl(repository_ctx, cc, True)
includes_c = _get_cxx_inc_directories_impl(repository_ctx, cc, False)
includes_cpp_set = depset(includes_cpp)
return includes_cpp + [
inc
for inc in includes_c
if inc not in includes_cpp_set.to_list()
]
def auto_configure_fail(msg):
"""Output failure message when rocm configuration fails."""
red = "\033[0;31m"
no_color = "\033[0m"
fail("\n%sROCm Configuration Error:%s %s\n" % (red, no_color, msg))
def auto_configure_warning(msg):
"""Output warning message during auto configuration."""
yellow = "\033[1;33m"
no_color = "\033[0m"
print("\n%sAuto-Configuration Warning:%s %s\n" % (yellow, no_color, msg))
# END cc_configure common functions (see TODO above).
def _host_compiler_includes(repository_ctx, cc):
"""Computed the list of gcc include directories.
Args:
repository_ctx: The repository context.
cc: The path to the gcc host compiler.
Returns:
A list of gcc include directories.
"""
inc_dirs = get_cxx_inc_directories(repository_ctx, cc)
# Add numpy headers
inc_dirs.append("/usr/lib/python2.7/dist-packages/numpy/core/include")
return inc_dirs
def _rocm_include_path(repository_ctx, rocm_config):
"""Generates the cxx_builtin_include_directory entries for rocm inc dirs.
Args:
repository_ctx: The repository context.
rocm_config: The path to the gcc host compiler.
Returns:
A string containing the Starlark string for each of the gcc
host compiler include directories, which can be added to the CROSSTOOL
file.
"""
inc_dirs = []
# general ROCm include path
inc_dirs.append(rocm_config.rocm_toolkit_path + "/include")
# Add HSA headers
inc_dirs.append(rocm_config.rocm_toolkit_path + "/hsa/include")
# Add HIP headers
inc_dirs.append(rocm_config.rocm_toolkit_path + "/include/hip")
inc_dirs.append(rocm_config.rocm_toolkit_path + "/include/hip/hcc_detail")
inc_dirs.append(rocm_config.rocm_toolkit_path + "/hip/include")
# Add HIP-Clang headers
inc_dirs.append(rocm_config.rocm_toolkit_path + "/llvm/lib/clang/8.0/include")
inc_dirs.append(rocm_config.rocm_toolkit_path + "/llvm/lib/clang/9.0.0/include")
inc_dirs.append(rocm_config.rocm_toolkit_path + "/llvm/lib/clang/10.0.0/include")
inc_dirs.append(rocm_config.rocm_toolkit_path + "/llvm/lib/clang/11.0.0/include")
# Add rocrand and hiprand headers
inc_dirs.append(rocm_config.rocm_toolkit_path + "/rocrand/include")
inc_dirs.append(rocm_config.rocm_toolkit_path + "/hiprand/include")
# Add rocfft headers
inc_dirs.append(rocm_config.rocm_toolkit_path + "/rocfft/include")
# Add rocBLAS headers
inc_dirs.append(rocm_config.rocm_toolkit_path + "/rocblas/include")
# Add MIOpen headers
inc_dirs.append(rocm_config.rocm_toolkit_path + "/miopen/include")
# Add RCCL headers
inc_dirs.append(rocm_config.rocm_toolkit_path + "/rccl/include")
# Add hcc headers
inc_dirs.append(rocm_config.rocm_toolkit_path + "/hcc/include")
inc_dirs.append(rocm_config.rocm_toolkit_path + "/hcc/compiler/lib/clang/7.0.0/include/")
inc_dirs.append(rocm_config.rocm_toolkit_path + "/hcc/lib/clang/7.0.0/include")
# Newer hcc builds use/are based off of clang 8.0.0.
inc_dirs.append(rocm_config.rocm_toolkit_path + "/hcc/compiler/lib/clang/8.0.0/include/")
inc_dirs.append(rocm_config.rocm_toolkit_path + "/hcc/lib/clang/8.0.0/include")
# Support hcc based off clang 9.0.0, included in ROCm2.2
inc_dirs.append(rocm_config.rocm_toolkit_path + "/hcc/compiler/lib/clang/9.0.0/include/")
inc_dirs.append(rocm_config.rocm_toolkit_path + "/hcc/lib/clang/9.0.0/include")
# Support hcc based off clang 10.0.0, included in ROCm2.8
inc_dirs.append(rocm_config.rocm_toolkit_path + "/hcc/compiler/lib/clang/10.0.0/include/")
inc_dirs.append(rocm_config.rocm_toolkit_path + "/hcc/lib/clang/10.0.0/include")
return inc_dirs
def _enable_rocm(repository_ctx):
if "TF_NEED_ROCM" in repository_ctx.os.environ:
enable_rocm = repository_ctx.os.environ["TF_NEED_ROCM"].strip()
if enable_rocm == "1":
if get_cpu_value(repository_ctx) != "Linux":
auto_configure_warning("ROCm configure is only supported on Linux")
return False
return True
return False
def _rocm_toolkit_path(repository_ctx, bash_bin):
"""Finds the rocm toolkit directory.
Args:
repository_ctx: The repository context.
Returns:
A speculative real path of the rocm toolkit install directory.
"""
rocm_toolkit_path = _DEFAULT_ROCM_TOOLKIT_PATH
if _ROCM_TOOLKIT_PATH in repository_ctx.os.environ:
rocm_toolkit_path = repository_ctx.os.environ[_ROCM_TOOLKIT_PATH].strip()
if files_exist(repository_ctx, [rocm_toolkit_path], bash_bin) != [True]:
auto_configure_fail("Cannot find rocm toolkit path.")
return realpath(repository_ctx, rocm_toolkit_path, bash_bin)
def _amdgpu_targets(repository_ctx):
"""Returns a list of strings representing AMDGPU targets."""
if _TF_ROCM_AMDGPU_TARGETS not in repository_ctx.os.environ:
return _DEFAULT_ROCM_AMDGPU_TARGETS
amdgpu_targets_str = repository_ctx.os.environ[_TF_ROCM_AMDGPU_TARGETS]
amdgpu_targets = amdgpu_targets_str.split(",")
for amdgpu_target in amdgpu_targets:
if amdgpu_target[:3] != "gfx" or not amdgpu_target[3:].isdigit():
auto_configure_fail("Invalid AMDGPU target: %s" % amdgpu_target)
return amdgpu_targets
def _hipcc_env(repository_ctx):
"""Returns the environment variable string for hipcc.
Args:
repository_ctx: The repository context.
Returns:
A string containing environment variables for hipcc.
"""
hipcc_env = ""
for name in [
"HIP_CLANG_PATH",
"DEVICE_LIB_PATH",
"HIP_VDI_HOME",
"HIPCC_VERBOSE",
"HIPCC_COMPILE_FLAGS_APPEND",
"HIPPCC_LINK_FLAGS_APPEND",
"HCC_AMDGPU_TARGET",
"HIP_PLATFORM",
]:
if name in repository_ctx.os.environ:
hipcc_env = (hipcc_env + " " + name + "=\"" +
repository_ctx.os.environ[name].strip() + "\";")
return hipcc_env.strip()
def _hipcc_is_hipclang(repository_ctx, rocm_config, bash_bin):
"""Returns if hipcc is based on hip-clang toolchain.
Args:
repository_ctx: The repository context.
rocm_config: The path to the hip compiler.
bash_bin: the path to the bash interpreter
Returns:
A string "True" if hipcc is based on hip-clang toolchain.
The functions returns "False" if not (ie: based on HIP/HCC toolchain).
"""
# check user-defined hip-clang environment variables
for name in ["HIP_CLANG_PATH", "HIP_VDI_HOME"]:
if name in repository_ctx.os.environ:
return "True"
# grep for "HIP_COMPILER=clang" in /opt/rocm/hip/lib/.hipInfo
cmd = "grep HIP_COMPILER=clang %s/hip/lib/.hipInfo || true" % rocm_config.rocm_toolkit_path
grep_result = execute(repository_ctx, [bash_bin, "-c", cmd], empty_stdout_fine = True)
result = grep_result.stdout.strip()
if result == "HIP_COMPILER=clang":
return "True"
return "False"
def _if_hipcc_is_hipclang(repository_ctx, rocm_config, bash_bin, if_true, if_false = []):
"""
Returns either the if_true or if_false arg based on whether hipcc
is based on the hip-clang toolchain
Args :
repository_ctx: The repository context.
rocm_config: The path to the hip compiler.
if_true : value to return if hipcc is hip-clang based
if_false : value to return if hipcc is not hip-clang based
(optional, defaults to empty list)
Returns :
either the if_true arg or the of_False arg
"""
if _hipcc_is_hipclang(repository_ctx, rocm_config, bash_bin) == "True":
return if_true
return if_false
def _crosstool_verbose(repository_ctx):
"""Returns the environment variable value CROSSTOOL_VERBOSE.
Args:
repository_ctx: The repository context.
Returns:
A string containing value of environment variable CROSSTOOL_VERBOSE.
"""
name = "CROSSTOOL_VERBOSE"
if name in repository_ctx.os.environ:
return repository_ctx.os.environ[name].strip()
return "0"
def _lib_name(lib, version = "", static = False):
"""Constructs the name of a library on Linux.
Args:
lib: The name of the library, such as "hip"
version: The version of the library.
static: True the library is static or False if it is a shared object.
Returns:
The platform-specific name of the library.
"""
if static:
return "lib%s.a" % lib
else:
if version:
version = ".%s" % version
return "lib%s.so%s" % (lib, version)
def _rocm_lib_paths(repository_ctx, lib, basedir):
file_name = _lib_name(lib, version = "", static = False)
return [
repository_ctx.path("%s/lib64/%s" % (basedir, file_name)),
repository_ctx.path("%s/lib64/stubs/%s" % (basedir, file_name)),
repository_ctx.path("%s/lib/x86_64-linux-gnu/%s" % (basedir, file_name)),
repository_ctx.path("%s/lib/%s" % (basedir, file_name)),
repository_ctx.path("%s/%s" % (basedir, file_name)),
]
def _batch_files_exist(repository_ctx, libs_paths, bash_bin):
all_paths = []
for _, lib_paths in libs_paths:
for lib_path in lib_paths:
all_paths.append(lib_path)
return files_exist(repository_ctx, all_paths, bash_bin)
def _select_rocm_lib_paths(repository_ctx, libs_paths, bash_bin):
test_results = _batch_files_exist(repository_ctx, libs_paths, bash_bin)
libs = {}
i = 0
for name, lib_paths in libs_paths:
selected_path = None
for path in lib_paths:
if test_results[i] and selected_path == None:
# For each lib select the first path that exists.
selected_path = path
i = i + 1
if selected_path == None:
auto_configure_fail("Cannot find rocm library %s" % name)
libs[name] = struct(file_name = selected_path.basename, path = realpath(repository_ctx, selected_path, bash_bin))
return libs
def _find_libs(repository_ctx, rocm_config, bash_bin):
"""Returns the ROCm libraries on the system.
Args:
repository_ctx: The repository context.
rocm_config: The ROCm config as returned by _get_rocm_config
bash_bin: the path to the bash interpreter
Returns:
Map of library names to structs of filename and path
"""
libs_paths = [
(name, _rocm_lib_paths(repository_ctx, name, path))
for name, path in [
("hip_hcc", rocm_config.rocm_toolkit_path),
("rocblas", rocm_config.rocm_toolkit_path + "/rocblas"),
("rocfft", rocm_config.rocm_toolkit_path + "/rocfft"),
("hiprand", rocm_config.rocm_toolkit_path + "/hiprand"),
("MIOpen", rocm_config.rocm_toolkit_path + "/miopen"),
("rccl", rocm_config.rocm_toolkit_path + "/rccl"),
("hipsparse", rocm_config.rocm_toolkit_path + "/hipsparse"),
]
]
return _select_rocm_lib_paths(repository_ctx, libs_paths, bash_bin)
def _get_rocm_config(repository_ctx, bash_bin):
"""Detects and returns information about the ROCm installation on the system.
Args:
repository_ctx: The repository context.
bash_bin: the path to the path interpreter
Returns:
A struct containing the following fields:
rocm_toolkit_path: The ROCm toolkit installation directory.
amdgpu_targets: A list of the system's AMDGPU targets.
"""
rocm_toolkit_path = _rocm_toolkit_path(repository_ctx, bash_bin)
return struct(
rocm_toolkit_path = rocm_toolkit_path,
amdgpu_targets = _amdgpu_targets(repository_ctx),
)
def _tpl_path(repository_ctx, labelname):
return repository_ctx.path(Label("//third_party/gpus/%s.tpl" % labelname))
def _tpl(repository_ctx, tpl, substitutions = {}, out = None):
if not out:
out = tpl.replace(":", "/")
repository_ctx.template(
out,
_tpl_path(repository_ctx, tpl),
substitutions,
)
_DUMMY_CROSSTOOL_BZL_FILE = """
def error_gpu_disabled():
fail("ERROR: Building with --config=rocm but TensorFlow is not configured " +
"to build with GPU support. Please re-run ./configure and enter 'Y' " +
"at the prompt to build with GPU support.")
native.genrule(
name = "error_gen_crosstool",
outs = ["CROSSTOOL"],
cmd = "echo 'Should not be run.' && exit 1",
)
native.filegroup(
name = "crosstool",
srcs = [":CROSSTOOL"],
output_licenses = ["unencumbered"],
)
"""
_DUMMY_CROSSTOOL_BUILD_FILE = """
load("//crosstool:error_gpu_disabled.bzl", "error_gpu_disabled")
error_gpu_disabled()
"""
def _create_dummy_repository(repository_ctx):
# Set up BUILD file for rocm/.
_tpl(
repository_ctx,
"rocm:build_defs.bzl",
{
"%{rocm_is_configured}": "False",
"%{rocm_extra_copts}": "[]",
},
)
_tpl(
repository_ctx,
"rocm:BUILD",
{
"%{hip_lib}": _lib_name("hip"),
"%{rocblas_lib}": _lib_name("rocblas"),
"%{miopen_lib}": _lib_name("miopen"),
"%{rccl_lib}": _lib_name("rccl"),
"%{rocfft_lib}": _lib_name("rocfft"),
"%{hiprand_lib}": _lib_name("hiprand"),
"%{hipsparse_lib}": _lib_name("hipsparse"),
"%{copy_rules}": "",
"%{rocm_headers}": "",
},
)
# Create dummy files for the ROCm toolkit since they are still required by
# tensorflow/core/platform/default/build_config:rocm.
repository_ctx.file("rocm/hip/include/hip/hip_runtime.h", "")
# Set up rocm_config.h, which is used by
# tensorflow/stream_executor/dso_loader.cc.
_tpl(
repository_ctx,
"rocm:rocm_config.h",
{
"%{rocm_toolkit_path}": _DEFAULT_ROCM_TOOLKIT_PATH,
},
"rocm/rocm/rocm_config.h",
)
# If rocm_configure is not configured to build with GPU support, and the user
# attempts to build with --config=rocm, add a dummy build rule to intercept
# this and fail with an actionable error message.
repository_ctx.file(
"crosstool/error_gpu_disabled.bzl",
_DUMMY_CROSSTOOL_BZL_FILE,
)
repository_ctx.file("crosstool/BUILD", _DUMMY_CROSSTOOL_BUILD_FILE)
def _norm_path(path):
"""Returns a path with '/' and remove the trailing slash."""
path = path.replace("\\", "/")
if path[-1] == "/":
path = path[:-1]
return path
def _genrule(src_dir, genrule_name, command, outs):
"""Returns a string with a genrule.
Genrule executes the given command and produces the given outputs.
"""
return (
"genrule(\n" +
' name = "' +
genrule_name + '",\n' +
" outs = [\n" +
outs +
"\n ],\n" +
' cmd = """\n' +
command +
'\n """,\n' +
")\n"
)
def _compute_rocm_extra_copts(repository_ctx, amdgpu_targets):
if False:
amdgpu_target_flags = ["--amdgpu-target=" +
amdgpu_target for amdgpu_target in amdgpu_targets]
else:
# AMDGPU targets are handled in the "crosstool_wrapper_driver_is_not_gcc"
amdgpu_target_flags = []
return str(amdgpu_target_flags)
def _create_local_rocm_repository(repository_ctx):
"""Creates the repository containing files set up to build with ROCm."""
tpl_paths = {labelname: _tpl_path(repository_ctx, labelname) for labelname in [
"rocm:build_defs.bzl",
"rocm:BUILD",
"crosstool:BUILD.rocm",
"crosstool:hipcc_cc_toolchain_config.bzl",
"crosstool:clang/bin/crosstool_wrapper_driver_rocm",
"rocm:rocm_config.h",
]}
bash_bin = get_bash_bin(repository_ctx)
rocm_config = _get_rocm_config(repository_ctx, bash_bin)
# Copy header and library files to execroot.
# rocm_toolkit_path
rocm_toolkit_path = rocm_config.rocm_toolkit_path
copy_rules = [
make_copy_dir_rule(
repository_ctx,
name = "rocm-include",
src_dir = rocm_toolkit_path + "/include",
out_dir = "rocm/include",
),
make_copy_dir_rule(
repository_ctx,
name = "rocfft-include",
src_dir = rocm_toolkit_path + "/rocfft/include",
out_dir = "rocm/include/rocfft",
),
make_copy_dir_rule(
repository_ctx,
name = "rocblas-include",
src_dir = rocm_toolkit_path + "/rocblas/include",
out_dir = "rocm/include/rocblas",
),
make_copy_dir_rule(
repository_ctx,
name = "miopen-include",
src_dir = rocm_toolkit_path + "/miopen/include",
out_dir = "rocm/include/miopen",
),
make_copy_dir_rule(
repository_ctx,
name = "rccl-include",
src_dir = rocm_toolkit_path + "/rccl/include",
out_dir = "rocm/include/rccl",
),
make_copy_dir_rule(
repository_ctx,
name = "hipsparse-include",
src_dir = rocm_toolkit_path + "/hipsparse/include",
out_dir = "rocm/include/hipsparse",
),
]
rocm_libs = _find_libs(repository_ctx, rocm_config, bash_bin)
rocm_lib_srcs = []
rocm_lib_outs = []
for lib in rocm_libs.values():
rocm_lib_srcs.append(lib.path)
rocm_lib_outs.append("rocm/lib/" + lib.file_name)
copy_rules.append(make_copy_files_rule(
repository_ctx,
name = "rocm-lib",
srcs = rocm_lib_srcs,
outs = rocm_lib_outs,
))
# Set up BUILD file for rocm/
repository_ctx.template(
"rocm/build_defs.bzl",
tpl_paths["rocm:build_defs.bzl"],
{
"%{rocm_is_configured}": "True",
"%{rocm_extra_copts}": _compute_rocm_extra_copts(
repository_ctx,
rocm_config.amdgpu_targets,
),
},
)
repository_ctx.template(
"rocm/BUILD",
tpl_paths["rocm:BUILD"],
{
"%{hip_lib}": rocm_libs["hip_hcc"].file_name,
"%{rocblas_lib}": rocm_libs["rocblas"].file_name,
"%{rocfft_lib}": rocm_libs["rocfft"].file_name,
"%{hiprand_lib}": rocm_libs["hiprand"].file_name,
"%{miopen_lib}": rocm_libs["MIOpen"].file_name,
"%{rccl_lib}": rocm_libs["rccl"].file_name,
"%{hipsparse_lib}": rocm_libs["hipsparse"].file_name,
"%{copy_rules}": "\n".join(copy_rules),
"%{rocm_headers}": ('":rocm-include",\n' +
'":rocfft-include",\n' +
'":rocblas-include",\n' +
'":miopen-include",\n' +
'":rccl-include",\n' +
'":hipsparse-include",'),
},
)
# Set up crosstool/
cc = find_cc(repository_ctx)
host_compiler_includes = get_cxx_inc_directories(repository_ctx, cc)
host_compiler_prefix = "/usr/bin"
if _GCC_HOST_COMPILER_PREFIX in repository_ctx.os.environ:
host_compiler_prefix = repository_ctx.os.environ[_GCC_HOST_COMPILER_PREFIX].strip()
rocm_defines = {}
rocm_defines["%{host_compiler_prefix}"] = host_compiler_prefix
rocm_defines["%{linker_bin_path}"] = rocm_config.rocm_toolkit_path + "/hcc/compiler/bin"
# For gcc, do not canonicalize system header paths; some versions of gcc
# pick the shortest possible path for system includes when creating the
# .d file - given that includes that are prefixed with "../" multiple
# time quickly grow longer than the root of the tree, this can lead to
# bazel's header check failing.
rocm_defines["%{extra_no_canonical_prefixes_flags}"] = "\"-fno-canonical-system-headers\""
rocm_defines["%{unfiltered_compile_flags}"] = to_list_of_strings([
"-DTENSORFLOW_USE_ROCM=1",
"-D__HIP_PLATFORM_HCC__",
"-DEIGEN_USE_HIP",
] + _if_hipcc_is_hipclang(repository_ctx, rocm_config, bash_bin, [
#
# define "TENSORFLOW_COMPILER_IS_HIP_CLANG" when we are using clang
# based hipcc to compile/build tensorflow
#
# Note that this #define should not be used to check whether or not
# tensorflow is being built with ROCm support
# (only TENSORFLOW_USE_ROCM should be used for that purpose)
#
"-DTENSORFLOW_COMPILER_IS_HIP_CLANG=1",
]))
rocm_defines["%{host_compiler_path}"] = "clang/bin/crosstool_wrapper_driver_is_not_gcc"
rocm_defines["%{cxx_builtin_include_directories}"] = to_list_of_strings(host_compiler_includes +
_rocm_include_path(repository_ctx, rocm_config))
verify_build_defines(rocm_defines)
# Only expand template variables in the BUILD file
repository_ctx.template(
"crosstool/BUILD",
tpl_paths["crosstool:BUILD.rocm"],
rocm_defines,
)
# No templating of cc_toolchain_config - use attributes and templatize the
# BUILD file.
repository_ctx.template(
"crosstool/cc_toolchain_config.bzl",
tpl_paths["crosstool:hipcc_cc_toolchain_config.bzl"],
)
repository_ctx.template(
"crosstool/clang/bin/crosstool_wrapper_driver_is_not_gcc",
tpl_paths["crosstool:clang/bin/crosstool_wrapper_driver_rocm"],
{
"%{cpu_compiler}": str(cc),
"%{hipcc_path}": rocm_config.rocm_toolkit_path + "/bin/hipcc",
"%{hipcc_env}": _hipcc_env(repository_ctx),
"%{hipcc_is_hipclang}": _hipcc_is_hipclang(repository_ctx, rocm_config, bash_bin),
"%{rocr_runtime_path}": rocm_config.rocm_toolkit_path + "/lib",
"%{rocr_runtime_library}": "hsa-runtime64",
"%{hip_runtime_path}": rocm_config.rocm_toolkit_path + "/hip/lib",
"%{hip_runtime_library}": "hip_hcc",
"%{hcc_runtime_path}": rocm_config.rocm_toolkit_path + "/hcc/lib",
"%{hcc_runtime_library}": "mcwamp",
"%{crosstool_verbose}": _crosstool_verbose(repository_ctx),
"%{gcc_host_compiler_path}": str(cc),
"%{rocm_amdgpu_targets}": ",".join(
["\"%s\"" % c for c in rocm_config.amdgpu_targets],
),
},
)
# Set up rocm_config.h, which is used by
# tensorflow/stream_executor/dso_loader.cc.
repository_ctx.template(
"rocm/rocm/rocm_config.h",
tpl_paths["rocm:rocm_config.h"],
{
"%{rocm_amdgpu_targets}": ",".join(
["\"%s\"" % c for c in rocm_config.amdgpu_targets],
),
"%{rocm_toolkit_path}": rocm_config.rocm_toolkit_path,
},
)
def _create_remote_rocm_repository(repository_ctx, remote_config_repo):
"""Creates pointers to a remotely configured repo set up to build with ROCm."""
_tpl(
repository_ctx,
"rocm:build_defs.bzl",
{
"%{rocm_is_configured}": "True",
"%{rocm_extra_copts}": _compute_rocm_extra_copts(
repository_ctx,
[], #_compute_capabilities(repository_ctx)
),
},
)
repository_ctx.template(
"rocm/BUILD",
Label(remote_config_repo + "/rocm:BUILD"),
{},
)
repository_ctx.template(
"rocm/build_defs.bzl",
Label(remote_config_repo + "/rocm:build_defs.bzl"),
{},
)
repository_ctx.template(
"rocm/rocm/rocm_config.h",
Label(remote_config_repo + "/rocm:rocm/rocm_config.h"),
{},
)
def _rocm_autoconf_impl(repository_ctx):
"""Implementation of the rocm_autoconf repository rule."""
if not _enable_rocm(repository_ctx):
_create_dummy_repository(repository_ctx)
elif _TF_ROCM_CONFIG_REPO in repository_ctx.os.environ:
_create_remote_rocm_repository(
repository_ctx,
repository_ctx.os.environ[_TF_ROCM_CONFIG_REPO],
)
else:
_create_local_rocm_repository(repository_ctx)
rocm_configure = repository_rule(
implementation = _rocm_autoconf_impl,
environ = [
_GCC_HOST_COMPILER_PATH,
_GCC_HOST_COMPILER_PREFIX,
"TF_NEED_ROCM",
_ROCM_TOOLKIT_PATH,
_TF_ROCM_VERSION,
_TF_MIOPEN_VERSION,
_TF_ROCM_AMDGPU_TARGETS,
_TF_ROCM_CONFIG_REPO,
],
)
"""Detects and configures the local ROCm toolchain.
Add the following to your WORKSPACE FILE:
```python
rocm_configure(name = "local_config_rocm")
```
Args:
name: A unique name for this workspace rule.
"""