github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/gpus/rocm_configure.bzl (about) 1 # -*- Python -*- 2 """Repository rule for ROCm autoconfiguration. 3 4 `rocm_configure` depends on the following environment variables: 5 6 * `TF_NEED_ROCM`: Whether to enable building with ROCm. 7 * `GCC_HOST_COMPILER_PATH`: The GCC host compiler path 8 * `ROCM_TOOLKIT_PATH`: The path to the ROCm toolkit. Default is 9 `/opt/rocm`. 10 * `TF_ROCM_VERSION`: The version of the ROCm toolkit. If this is blank, then 11 use the system default. 12 * `TF_MIOPEN_VERSION`: The version of the MIOpen library. 13 * `TF_ROCM_AMDGPU_TARGETS`: The AMDGPU targets. Default is 14 `gfx803,gfx900`. 15 """ 16 17 load( 18 ":cuda_configure.bzl", 19 "make_copy_dir_rule", 20 "make_copy_files_rule", 21 "to_list_of_strings", 22 "verify_build_defines", 23 ) 24 25 _GCC_HOST_COMPILER_PATH = "GCC_HOST_COMPILER_PATH" 26 _GCC_HOST_COMPILER_PREFIX = "GCC_HOST_COMPILER_PREFIX" 27 _ROCM_TOOLKIT_PATH = "ROCM_TOOLKIT_PATH" 28 _TF_ROCM_VERSION = "TF_ROCM_VERSION" 29 _TF_MIOPEN_VERSION = "TF_MIOPEN_VERSION" 30 _TF_ROCM_AMDGPU_TARGETS = "TF_ROCM_AMDGPU_TARGETS" 31 _TF_ROCM_CONFIG_REPO = "TF_ROCM_CONFIG_REPO" 32 33 _DEFAULT_ROCM_VERSION = "" 34 _DEFAULT_MIOPEN_VERSION = "" 35 _DEFAULT_ROCM_TOOLKIT_PATH = "/opt/rocm" 36 _DEFAULT_ROCM_AMDGPU_TARGETS = ["gfx803", "gfx900"] 37 38 def _get_win_rocm_defines(repository_ctx): 39 """Return CROSSTOOL defines for Windows""" 40 41 # Return fake vaules for Windows specific fields. 42 # This ensures the CROSSTOOL file parser is happy. 43 return { 44 "%{msvc_env_tmp}": "msvc_not_used", 45 "%{msvc_env_path}": "msvc_not_used", 46 "%{msvc_env_include}": "msvc_not_used", 47 "%{msvc_env_lib}": "msvc_not_used", 48 "%{msvc_cl_path}": "msvc_not_used", 49 "%{msvc_ml_path}": "msvc_not_used", 50 "%{msvc_link_path}": "msvc_not_used", 51 "%{msvc_lib_path}": "msvc_not_used", 52 } 53 54 def find_cc(repository_ctx): 55 """Find the C++ compiler.""" 56 57 # Return a dummy value for GCC detection here to avoid error 58 target_cc_name = "gcc" 59 cc_path_envvar = _GCC_HOST_COMPILER_PATH 60 cc_name = target_cc_name 61 62 if cc_path_envvar in repository_ctx.os.environ: 63 cc_name_from_env = repository_ctx.os.environ[cc_path_envvar].strip() 64 if cc_name_from_env: 65 cc_name = cc_name_from_env 66 if cc_name.startswith("/"): 67 # Absolute path, maybe we should make this supported by our which function. 68 return cc_name 69 cc = repository_ctx.which(cc_name) 70 if cc == None: 71 fail(("Cannot find {}, either correct your path or set the {}" + 72 " environment variable").format(target_cc_name, cc_path_envvar)) 73 return cc 74 75 _INC_DIR_MARKER_BEGIN = "#include <...>" 76 77 def _cxx_inc_convert(path): 78 """Convert path returned by cc -E xc++ in a complete path.""" 79 path = path.strip() 80 return path 81 82 def _get_cxx_inc_directories_impl(repository_ctx, cc, lang_is_cpp): 83 """Compute the list of default C or C++ include directories.""" 84 if lang_is_cpp: 85 lang = "c++" 86 else: 87 lang = "c" 88 89 # TODO: We pass -no-canonical-prefixes here to match the compiler flags, 90 # but in rocm_clang CROSSTOOL file that is a `feature` and we should 91 # handle the case when it's disabled and no flag is passed 92 result = repository_ctx.execute([ 93 cc, 94 "-no-canonical-prefixes", 95 "-E", 96 "-x" + lang, 97 "-", 98 "-v", 99 ]) 100 index1 = result.stderr.find(_INC_DIR_MARKER_BEGIN) 101 if index1 == -1: 102 return [] 103 index1 = result.stderr.find("\n", index1) 104 if index1 == -1: 105 return [] 106 index2 = result.stderr.rfind("\n ") 107 if index2 == -1 or index2 < index1: 108 return [] 109 index2 = result.stderr.find("\n", index2 + 1) 110 if index2 == -1: 111 inc_dirs = result.stderr[index1 + 1:] 112 else: 113 inc_dirs = result.stderr[index1 + 1:index2].strip() 114 115 return [ 116 str(repository_ctx.path(_cxx_inc_convert(p))) 117 for p in inc_dirs.split("\n") 118 ] 119 120 def get_cxx_inc_directories(repository_ctx, cc): 121 """Compute the list of default C and C++ include directories.""" 122 123 # For some reason `clang -xc` sometimes returns include paths that are 124 # different from the ones from `clang -xc++`. (Symlink and a dir) 125 # So we run the compiler with both `-xc` and `-xc++` and merge resulting lists 126 includes_cpp = _get_cxx_inc_directories_impl(repository_ctx, cc, True) 127 includes_c = _get_cxx_inc_directories_impl(repository_ctx, cc, False) 128 129 includes_cpp_set = depset(includes_cpp) 130 return includes_cpp + [ 131 inc 132 for inc in includes_c 133 if inc not in includes_cpp_set.to_list() 134 ] 135 136 def auto_configure_fail(msg): 137 """Output failure message when rocm configuration fails.""" 138 red = "\033[0;31m" 139 no_color = "\033[0m" 140 fail("\n%sROCm Configuration Error:%s %s\n" % (red, no_color, msg)) 141 142 # END cc_configure common functions (see TODO above). 143 144 def _host_compiler_includes(repository_ctx, cc): 145 """Computed the list of gcc include directories. 146 147 Args: 148 repository_ctx: The repository context. 149 cc: The path to the gcc host compiler. 150 151 Returns: 152 A list of gcc include directories. 153 """ 154 inc_dirs = get_cxx_inc_directories(repository_ctx, cc) 155 156 # Add numpy headers 157 inc_dirs.append("/usr/lib/python2.7/dist-packages/numpy/core/include") 158 159 return inc_dirs 160 161 def _rocm_include_path(repository_ctx, rocm_config): 162 """Generates the cxx_builtin_include_directory entries for rocm inc dirs. 163 164 Args: 165 repository_ctx: The repository context. 166 rocm_config: The path to the gcc host compiler. 167 168 Returns: 169 A string containing the Starlark string for each of the gcc 170 host compiler include directories, which can be added to the CROSSTOOL 171 file. 172 """ 173 inc_dirs = [] 174 175 # general ROCm include path 176 inc_dirs.append(rocm_config.rocm_toolkit_path + "/include") 177 178 # Add HSA headers 179 inc_dirs.append("/opt/rocm/hsa/include") 180 181 # Add HIP headers 182 inc_dirs.append("/opt/rocm/include/hip") 183 inc_dirs.append("/opt/rocm/include/hip/hcc_detail") 184 inc_dirs.append("/opt/rocm/hip/include") 185 186 # Add HIP-Clang headers 187 inc_dirs.append("/opt/rocm/llvm/lib/clang/8.0/include") 188 inc_dirs.append("/opt/rocm/llvm/lib/clang/9.0.0/include") 189 inc_dirs.append("/opt/rocm/llvm/lib/clang/10.0.0/include") 190 191 # Add rocrand and hiprand headers 192 inc_dirs.append("/opt/rocm/rocrand/include") 193 inc_dirs.append("/opt/rocm/hiprand/include") 194 195 # Add rocfft headers 196 inc_dirs.append("/opt/rocm/rocfft/include") 197 198 # Add rocBLAS headers 199 inc_dirs.append("/opt/rocm/rocblas/include") 200 201 # Add MIOpen headers 202 inc_dirs.append("/opt/rocm/miopen/include") 203 204 # Add RCCL headers 205 inc_dirs.append("/opt/rocm/rccl/include") 206 207 # Add hcc headers 208 inc_dirs.append("/opt/rocm/hcc/include") 209 inc_dirs.append("/opt/rocm/hcc/compiler/lib/clang/7.0.0/include/") 210 inc_dirs.append("/opt/rocm/hcc/lib/clang/7.0.0/include") 211 212 # Newer hcc builds use/are based off of clang 8.0.0. 213 inc_dirs.append("/opt/rocm/hcc/compiler/lib/clang/8.0.0/include/") 214 inc_dirs.append("/opt/rocm/hcc/lib/clang/8.0.0/include") 215 216 # Support hcc based off clang 9.0.0, included in ROCm2.2 217 inc_dirs.append("/opt/rocm/hcc/compiler/lib/clang/9.0.0/include/") 218 inc_dirs.append("/opt/rocm/hcc/lib/clang/9.0.0/include") 219 220 # Support hcc based off clang 10.0.0, included in ROCm2.8 221 inc_dirs.append("/opt/rocm/hcc/compiler/lib/clang/10.0.0/include/") 222 inc_dirs.append("/opt/rocm/hcc/lib/clang/10.0.0/include") 223 224 return inc_dirs 225 226 def _enable_rocm(repository_ctx): 227 if "TF_NEED_ROCM" in repository_ctx.os.environ: 228 enable_rocm = repository_ctx.os.environ["TF_NEED_ROCM"].strip() 229 return enable_rocm == "1" 230 return False 231 232 def _rocm_toolkit_path(repository_ctx): 233 """Finds the rocm toolkit directory. 234 235 Args: 236 repository_ctx: The repository context. 237 238 Returns: 239 A speculative real path of the rocm toolkit install directory. 240 """ 241 rocm_toolkit_path = _DEFAULT_ROCM_TOOLKIT_PATH 242 if _ROCM_TOOLKIT_PATH in repository_ctx.os.environ: 243 rocm_toolkit_path = repository_ctx.os.environ[_ROCM_TOOLKIT_PATH].strip() 244 if not repository_ctx.path(rocm_toolkit_path).exists: 245 auto_configure_fail("Cannot find rocm toolkit path.") 246 return str(repository_ctx.path(rocm_toolkit_path).realpath) 247 248 def _amdgpu_targets(repository_ctx): 249 """Returns a list of strings representing AMDGPU targets.""" 250 if _TF_ROCM_AMDGPU_TARGETS not in repository_ctx.os.environ: 251 return _DEFAULT_ROCM_AMDGPU_TARGETS 252 amdgpu_targets_str = repository_ctx.os.environ[_TF_ROCM_AMDGPU_TARGETS] 253 amdgpu_targets = amdgpu_targets_str.split(",") 254 for amdgpu_target in amdgpu_targets: 255 if amdgpu_target[:3] != "gfx" or not amdgpu_target[3:].isdigit(): 256 auto_configure_fail("Invalid AMDGPU target: %s" % amdgpu_target) 257 return amdgpu_targets 258 259 def _hipcc_env(repository_ctx): 260 """Returns the environment variable string for hipcc. 261 262 Args: 263 repository_ctx: The repository context. 264 265 Returns: 266 A string containing environment variables for hipcc. 267 """ 268 hipcc_env = "" 269 for name in [ 270 "HIP_CLANG_PATH", 271 "DEVICE_LIB_PATH", 272 "HIP_VDI_HOME", 273 "HIPCC_VERBOSE", 274 "HIPCC_COMPILE_FLAGS_APPEND", 275 "HIPPCC_LINK_FLAGS_APPEND", 276 "HCC_AMDGPU_TARGET", 277 "HIP_PLATFORM", 278 ]: 279 if name in repository_ctx.os.environ: 280 hipcc_env = (hipcc_env + " " + name + "=\"" + 281 repository_ctx.os.environ[name].strip() + "\";") 282 return hipcc_env.strip() 283 284 def _hipcc_is_hipclang(repository_ctx): 285 """Returns if hipcc is based on hip-clang toolchain. 286 287 Args: 288 repository_ctx: The repository context. 289 290 Returns: 291 A string "True" if hipcc is based on hip-clang toolchain. 292 The functions returns "False" if not (ie: based on HIP/HCC toolchain). 293 """ 294 295 # check user-defined hip-clang environment variables 296 for name in ["HIP_CLANG_PATH", "HIP_VDI_HOME"]: 297 if name in repository_ctx.os.environ: 298 return "True" 299 300 # grep for "HIP_COMPILER=clang" in /opt/rocm/hip/lib/.hipInfo 301 grep_result = _execute( 302 repository_ctx, 303 ["grep", "HIP_COMPILER=clang", "/opt/rocm/hip/lib/.hipInfo"], 304 empty_stdout_fine = True, 305 ) 306 result = grep_result.stdout 307 if result == "HIP_COMPILER=clang": 308 return "True" 309 return "False" 310 311 def _if_hipcc_is_hipclang(repository_ctx, if_true, if_false = []): 312 """ 313 Returns either the if_true or if_false arg based on whether hipcc 314 is based on the hip-clang toolchain 315 316 Args : 317 repository_ctx: The repository context. 318 if_true : value to return if hipcc is hip-clang based 319 if_false : value to return if hipcc is not hip-clang based 320 (optional, defaults to empty list) 321 322 Returns : 323 either the if_true arg or the of_False arg 324 """ 325 if _hipcc_is_hipclang(repository_ctx) == "True": 326 return if_true 327 return if_false 328 329 def _crosstool_verbose(repository_ctx): 330 """Returns the environment variable value CROSSTOOL_VERBOSE. 331 332 Args: 333 repository_ctx: The repository context. 334 335 Returns: 336 A string containing value of environment variable CROSSTOOL_VERBOSE. 337 """ 338 name = "CROSSTOOL_VERBOSE" 339 if name in repository_ctx.os.environ: 340 return repository_ctx.os.environ[name].strip() 341 return "0" 342 343 def _cpu_value(repository_ctx): 344 """Returns the name of the host operating system. 345 346 Args: 347 repository_ctx: The repository context. 348 349 Returns: 350 A string containing the name of the host operating system. 351 """ 352 os_name = repository_ctx.os.name.lower() 353 if os_name.startswith("mac os"): 354 return "Darwin" 355 if os_name.find("windows") != -1: 356 return "Windows" 357 result = repository_ctx.execute(["uname", "-s"]) 358 return result.stdout.strip() 359 360 def _lib_name(lib, cpu_value, version = "", static = False): 361 """Constructs the platform-specific name of a library. 362 363 Args: 364 lib: The name of the library, such as "hip" 365 cpu_value: The name of the host operating system. 366 version: The version of the library. 367 static: True the library is static or False if it is a shared object. 368 369 Returns: 370 The platform-specific name of the library. 371 """ 372 if cpu_value in ("Linux", "FreeBSD"): 373 if static: 374 return "lib%s.a" % lib 375 else: 376 if version: 377 version = ".%s" % version 378 return "lib%s.so%s" % (lib, version) 379 elif cpu_value == "Windows": 380 return "%s.lib" % lib 381 elif cpu_value == "Darwin": 382 if static: 383 return "lib%s.a" % lib 384 elif version: 385 version = ".%s" % version 386 return "lib%s%s.dylib" % (lib, version) 387 else: 388 auto_configure_fail("Invalid cpu_value: %s" % cpu_value) 389 390 def _find_rocm_lib( 391 lib, 392 repository_ctx, 393 cpu_value, 394 basedir, 395 version = "", 396 static = False): 397 """Finds the given ROCm libraries on the system. 398 399 Args: 400 lib: The name of the library, such as "hip" 401 repository_ctx: The repository context. 402 cpu_value: The name of the host operating system. 403 basedir: The install directory of ROCm. 404 version: The version of the library. 405 static: True if static library, False if shared object. 406 407 Returns: 408 Returns a struct with the following fields: 409 file_name: The basename of the library found on the system. 410 path: The full path to the library. 411 """ 412 file_name = _lib_name(lib, cpu_value, version, static) 413 if cpu_value == "Linux": 414 path = repository_ctx.path("%s/lib64/%s" % (basedir, file_name)) 415 if path.exists: 416 return struct(file_name = file_name, path = str(path.realpath)) 417 path = repository_ctx.path("%s/lib64/stubs/%s" % (basedir, file_name)) 418 if path.exists: 419 return struct(file_name = file_name, path = str(path.realpath)) 420 path = repository_ctx.path( 421 "%s/lib/x86_64-linux-gnu/%s" % (basedir, file_name), 422 ) 423 if path.exists: 424 return struct(file_name = file_name, path = str(path.realpath)) 425 426 path = repository_ctx.path("%s/lib/%s" % (basedir, file_name)) 427 if path.exists: 428 return struct(file_name = file_name, path = str(path.realpath)) 429 path = repository_ctx.path("%s/%s" % (basedir, file_name)) 430 if path.exists: 431 return struct(file_name = file_name, path = str(path.realpath)) 432 433 auto_configure_fail("Cannot find rocm library %s" % file_name) 434 435 def _find_libs(repository_ctx, rocm_config): 436 """Returns the ROCm libraries on the system. 437 438 Args: 439 repository_ctx: The repository context. 440 rocm_config: The ROCm config as returned by _get_rocm_config 441 442 Returns: 443 Map of library names to structs of filename and path as returned by 444 _find_rocm_lib. 445 """ 446 cpu_value = rocm_config.cpu_value 447 return { 448 "hip": _find_rocm_lib( 449 "hip_hcc", 450 repository_ctx, 451 cpu_value, 452 rocm_config.rocm_toolkit_path, 453 ), 454 "rocblas": _find_rocm_lib( 455 "rocblas", 456 repository_ctx, 457 cpu_value, 458 rocm_config.rocm_toolkit_path + "/rocblas", 459 ), 460 "rocfft": _find_rocm_lib( 461 "rocfft", 462 repository_ctx, 463 cpu_value, 464 rocm_config.rocm_toolkit_path + "/rocfft", 465 ), 466 "hiprand": _find_rocm_lib( 467 "hiprand", 468 repository_ctx, 469 cpu_value, 470 rocm_config.rocm_toolkit_path + "/hiprand", 471 ), 472 "miopen": _find_rocm_lib( 473 "MIOpen", 474 repository_ctx, 475 cpu_value, 476 rocm_config.rocm_toolkit_path + "/miopen", 477 ), 478 "rccl": _find_rocm_lib( 479 "rccl", 480 repository_ctx, 481 cpu_value, 482 rocm_config.rocm_toolkit_path + "/rccl", 483 ), 484 } 485 486 def _get_rocm_config(repository_ctx): 487 """Detects and returns information about the ROCm installation on the system. 488 489 Args: 490 repository_ctx: The repository context. 491 492 Returns: 493 A struct containing the following fields: 494 rocm_toolkit_path: The ROCm toolkit installation directory. 495 amdgpu_targets: A list of the system's AMDGPU targets. 496 cpu_value: The name of the host operating system. 497 """ 498 cpu_value = _cpu_value(repository_ctx) 499 rocm_toolkit_path = _rocm_toolkit_path(repository_ctx) 500 return struct( 501 rocm_toolkit_path = rocm_toolkit_path, 502 amdgpu_targets = _amdgpu_targets(repository_ctx), 503 cpu_value = cpu_value, 504 ) 505 506 def _tpl(repository_ctx, tpl, substitutions = {}, out = None): 507 if not out: 508 out = tpl.replace(":", "/") 509 repository_ctx.template( 510 out, 511 Label("//third_party/gpus/%s.tpl" % tpl), 512 substitutions, 513 ) 514 515 def _file(repository_ctx, label): 516 repository_ctx.template( 517 label.replace(":", "/"), 518 Label("//third_party/gpus/%s.tpl" % label), 519 {}, 520 ) 521 522 _DUMMY_CROSSTOOL_BZL_FILE = """ 523 def error_gpu_disabled(): 524 fail("ERROR: Building with --config=rocm but TensorFlow is not configured " + 525 "to build with GPU support. Please re-run ./configure and enter 'Y' " + 526 "at the prompt to build with GPU support.") 527 528 native.genrule( 529 name = "error_gen_crosstool", 530 outs = ["CROSSTOOL"], 531 cmd = "echo 'Should not be run.' && exit 1", 532 ) 533 534 native.filegroup( 535 name = "crosstool", 536 srcs = [":CROSSTOOL"], 537 output_licenses = ["unencumbered"], 538 ) 539 """ 540 541 _DUMMY_CROSSTOOL_BUILD_FILE = """ 542 load("//crosstool:error_gpu_disabled.bzl", "error_gpu_disabled") 543 544 error_gpu_disabled() 545 """ 546 547 def _create_dummy_repository(repository_ctx): 548 cpu_value = _cpu_value(repository_ctx) 549 550 # Set up BUILD file for rocm/. 551 _tpl( 552 repository_ctx, 553 "rocm:build_defs.bzl", 554 { 555 "%{rocm_is_configured}": "False", 556 "%{rocm_extra_copts}": "[]", 557 }, 558 ) 559 _tpl( 560 repository_ctx, 561 "rocm:BUILD", 562 { 563 "%{hip_lib}": _lib_name("hip", cpu_value), 564 "%{rocblas_lib}": _lib_name("rocblas", cpu_value), 565 "%{miopen_lib}": _lib_name("miopen", cpu_value), 566 "%{rccl_lib}": _lib_name("rccl", cpu_value), 567 "%{rocfft_lib}": _lib_name("rocfft", cpu_value), 568 "%{hiprand_lib}": _lib_name("hiprand", cpu_value), 569 "%{copy_rules}": "", 570 "%{rocm_headers}": "", 571 }, 572 ) 573 574 # Create dummy files for the ROCm toolkit since they are still required by 575 # tensorflow/core/platform/default/build_config:rocm. 576 repository_ctx.file("rocm/hip/include/hip/hip_runtime.h", "") 577 578 # Set up rocm_config.h, which is used by 579 # tensorflow/stream_executor/dso_loader.cc. 580 _tpl( 581 repository_ctx, 582 "rocm:rocm_config.h", 583 { 584 "%{rocm_toolkit_path}": _DEFAULT_ROCM_TOOLKIT_PATH, 585 }, 586 "rocm/rocm/rocm_config.h", 587 ) 588 589 # If rocm_configure is not configured to build with GPU support, and the user 590 # attempts to build with --config=rocm, add a dummy build rule to intercept 591 # this and fail with an actionable error message. 592 repository_ctx.file( 593 "crosstool/error_gpu_disabled.bzl", 594 _DUMMY_CROSSTOOL_BZL_FILE, 595 ) 596 repository_ctx.file("crosstool/BUILD", _DUMMY_CROSSTOOL_BUILD_FILE) 597 598 def _execute( 599 repository_ctx, 600 cmdline, 601 error_msg = None, 602 error_details = None, 603 empty_stdout_fine = False): 604 """Executes an arbitrary shell command. 605 606 Args: 607 repository_ctx: the repository_ctx object 608 cmdline: list of strings, the command to execute 609 error_msg: string, a summary of the error if the command fails 610 error_details: string, details about the error or steps to fix it 611 empty_stdout_fine: bool, if True, an empty stdout result is fine, otherwise 612 it's an error 613 Return: 614 the result of repository_ctx.execute(cmdline) 615 """ 616 result = repository_ctx.execute(cmdline) 617 if result.stderr or not (empty_stdout_fine or result.stdout): 618 auto_configure_fail( 619 "\n".join([ 620 error_msg.strip() if error_msg else "Repository command failed", 621 result.stderr.strip(), 622 error_details if error_details else "", 623 ]), 624 ) 625 return result 626 627 def _norm_path(path): 628 """Returns a path with '/' and remove the trailing slash.""" 629 path = path.replace("\\", "/") 630 if path[-1] == "/": 631 path = path[:-1] 632 return path 633 634 def _genrule(src_dir, genrule_name, command, outs): 635 """Returns a string with a genrule. 636 637 Genrule executes the given command and produces the given outputs. 638 """ 639 return ( 640 "genrule(\n" + 641 ' name = "' + 642 genrule_name + '",\n' + 643 " outs = [\n" + 644 outs + 645 "\n ],\n" + 646 ' cmd = """\n' + 647 command + 648 '\n """,\n' + 649 ")\n" 650 ) 651 652 def _read_dir(repository_ctx, src_dir): 653 """Returns a string with all files in a directory. 654 655 Finds all files inside a directory, traversing subfolders and following 656 symlinks. The returned string contains the full path of all files 657 separated by line breaks. 658 """ 659 find_result = _execute( 660 repository_ctx, 661 ["find", src_dir, "-follow", "-type", "f"], 662 empty_stdout_fine = True, 663 ) 664 result = find_result.stdout 665 return result 666 667 def _compute_rocm_extra_copts(repository_ctx, amdgpu_targets): 668 if False: 669 amdgpu_target_flags = ["--amdgpu-target=" + 670 amdgpu_target for amdgpu_target in amdgpu_targets] 671 else: 672 # AMDGPU targets are handled in the "crosstool_wrapper_driver_is_not_gcc" 673 amdgpu_target_flags = [] 674 return str(amdgpu_target_flags) 675 676 def _create_local_rocm_repository(repository_ctx): 677 """Creates the repository containing files set up to build with ROCm.""" 678 rocm_config = _get_rocm_config(repository_ctx) 679 680 # Copy header and library files to execroot. 681 # rocm_toolkit_path 682 rocm_toolkit_path = rocm_config.rocm_toolkit_path 683 copy_rules = [ 684 make_copy_dir_rule( 685 repository_ctx, 686 name = "rocm-include", 687 src_dir = rocm_toolkit_path + "/include", 688 out_dir = "rocm/include", 689 ), 690 make_copy_dir_rule( 691 repository_ctx, 692 name = "rocfft-include", 693 src_dir = rocm_toolkit_path + "/rocfft/include", 694 out_dir = "rocm/include/rocfft", 695 ), 696 make_copy_dir_rule( 697 repository_ctx, 698 name = "rocblas-include", 699 src_dir = rocm_toolkit_path + "/rocblas/include", 700 out_dir = "rocm/include/rocblas", 701 ), 702 make_copy_dir_rule( 703 repository_ctx, 704 name = "miopen-include", 705 src_dir = rocm_toolkit_path + "/miopen/include", 706 out_dir = "rocm/include/miopen", 707 ), 708 make_copy_dir_rule( 709 repository_ctx, 710 name = "rccl-include", 711 src_dir = rocm_toolkit_path + "/rccl/include", 712 out_dir = "rocm/include/rccl", 713 ), 714 ] 715 716 rocm_libs = _find_libs(repository_ctx, rocm_config) 717 rocm_lib_srcs = [] 718 rocm_lib_outs = [] 719 for lib in rocm_libs.values(): 720 rocm_lib_srcs.append(lib.path) 721 rocm_lib_outs.append("rocm/lib/" + lib.file_name) 722 copy_rules.append(make_copy_files_rule( 723 repository_ctx, 724 name = "rocm-lib", 725 srcs = rocm_lib_srcs, 726 outs = rocm_lib_outs, 727 )) 728 729 # Set up BUILD file for rocm/ 730 _tpl( 731 repository_ctx, 732 "rocm:build_defs.bzl", 733 { 734 "%{rocm_is_configured}": "True", 735 "%{rocm_extra_copts}": _compute_rocm_extra_copts( 736 repository_ctx, 737 rocm_config.amdgpu_targets, 738 ), 739 }, 740 ) 741 _tpl( 742 repository_ctx, 743 "rocm:BUILD", 744 { 745 "%{hip_lib}": rocm_libs["hip"].file_name, 746 "%{rocblas_lib}": rocm_libs["rocblas"].file_name, 747 "%{rocfft_lib}": rocm_libs["rocfft"].file_name, 748 "%{hiprand_lib}": rocm_libs["hiprand"].file_name, 749 "%{miopen_lib}": rocm_libs["miopen"].file_name, 750 "%{rccl_lib}": rocm_libs["rccl"].file_name, 751 "%{copy_rules}": "\n".join(copy_rules), 752 "%{rocm_headers}": ('":rocm-include",\n' + 753 '":rocfft-include",\n' + 754 '":rocblas-include",\n' + 755 '":miopen-include",\n' + 756 '":rccl-include",'), 757 }, 758 ) 759 760 # Set up crosstool/ 761 cc = find_cc(repository_ctx) 762 763 host_compiler_includes = get_cxx_inc_directories(repository_ctx, cc) 764 765 host_compiler_prefix = "/usr/bin" 766 if _GCC_HOST_COMPILER_PREFIX in repository_ctx.os.environ: 767 host_compiler_prefix = repository_ctx.os.environ[_GCC_HOST_COMPILER_PREFIX].strip() 768 769 rocm_defines = {} 770 771 rocm_defines["%{host_compiler_prefix}"] = host_compiler_prefix 772 773 rocm_defines["%{linker_bin_path}"] = "/opt/rocm/hcc/compiler/bin" 774 775 # For gcc, do not canonicalize system header paths; some versions of gcc 776 # pick the shortest possible path for system includes when creating the 777 # .d file - given that includes that are prefixed with "../" multiple 778 # time quickly grow longer than the root of the tree, this can lead to 779 # bazel's header check failing. 780 rocm_defines["%{extra_no_canonical_prefixes_flags}"] = "\"-fno-canonical-system-headers\"" 781 782 rocm_defines["%{unfiltered_compile_flags}"] = to_list_of_strings([ 783 "-DTENSORFLOW_USE_ROCM=1", 784 "-D__HIP_PLATFORM_HCC__", 785 "-DEIGEN_USE_HIP", 786 ] + _if_hipcc_is_hipclang(repository_ctx, [ 787 # 788 # define "TENSORFLOW_COMPILER_IS_HIP_CLANG" when we are using clang 789 # based hipcc to compile/build tensorflow 790 # 791 # Note that this #define should not be used to check whether or not 792 # tensorflow is being built with ROCm support 793 # (only TENSORFLOW_USE_ROCM should be used for that purpose) 794 # 795 "-DTENSORFLOW_COMPILER_IS_HIP_CLANG=1", 796 ])) 797 798 rocm_defines["%{host_compiler_path}"] = "clang/bin/crosstool_wrapper_driver_is_not_gcc" 799 800 # # Enable a few more warnings that aren't part of -Wall. 801 # compiler_flag: "-Wunused-but-set-parameter" 802 803 # # But disable some that are problematic. 804 # compiler_flag: "-Wno-free-nonheap-object" # has false positives 805 806 rocm_defines["%{host_compiler_warnings}"] = to_list_of_strings(["-Wunused-but-set-parameter", "-Wno-free-nonheap-object"]) 807 808 rocm_defines["%{cxx_builtin_include_directories}"] = to_list_of_strings(host_compiler_includes + 809 _rocm_include_path(repository_ctx, rocm_config)) 810 811 rocm_defines["%{linker_files}"] = "clang/bin/crosstool_wrapper_driver_is_not_gcc" 812 813 rocm_defines["%{win_linker_files}"] = ":empty" 814 815 # Add the dummy defines for windows...requried to pass the "verify_build_defines" check 816 rocm_defines.update(_get_win_rocm_defines(repository_ctx)) 817 818 verify_build_defines(rocm_defines) 819 820 # Only expand template variables in the BUILD file 821 _tpl(repository_ctx, "crosstool:BUILD", rocm_defines) 822 823 # No templating of cc_toolchain_config - use attributes and templatize the 824 # BUILD file. 825 _tpl( 826 repository_ctx, 827 "crosstool:hipcc_cc_toolchain_config.bzl", 828 out = "crosstool/cc_toolchain_config.bzl", 829 ) 830 831 _tpl( 832 repository_ctx, 833 "crosstool:clang/bin/crosstool_wrapper_driver_rocm", 834 { 835 "%{cpu_compiler}": str(cc), 836 "%{hipcc_path}": "/opt/rocm/bin/hipcc", 837 "%{hipcc_env}": _hipcc_env(repository_ctx), 838 "%{hipcc_is_hipclang}": _hipcc_is_hipclang(repository_ctx), 839 "%{rocr_runtime_path}": "/opt/rocm/lib", 840 "%{rocr_runtime_library}": "hsa-runtime64", 841 "%{hip_runtime_path}": "/opt/rocm/hip/lib", 842 "%{hip_runtime_library}": "hip_hcc", 843 "%{hcc_runtime_path}": "/opt/rocm/hcc/lib", 844 "%{hcc_runtime_library}": "mcwamp", 845 "%{crosstool_verbose}": _crosstool_verbose(repository_ctx), 846 "%{gcc_host_compiler_path}": str(cc), 847 "%{rocm_amdgpu_targets}": ",".join( 848 ["\"%s\"" % c for c in rocm_config.amdgpu_targets], 849 ), 850 }, 851 out = "crosstool/clang/bin/crosstool_wrapper_driver_is_not_gcc", 852 ) 853 854 # Set up rocm_config.h, which is used by 855 # tensorflow/stream_executor/dso_loader.cc. 856 _tpl( 857 repository_ctx, 858 "rocm:rocm_config.h", 859 { 860 "%{rocm_amdgpu_targets}": ",".join( 861 ["\"%s\"" % c for c in rocm_config.amdgpu_targets], 862 ), 863 "%{rocm_toolkit_path}": rocm_config.rocm_toolkit_path, 864 }, 865 "rocm/rocm/rocm_config.h", 866 ) 867 868 def _create_remote_rocm_repository(repository_ctx, remote_config_repo): 869 """Creates pointers to a remotely configured repo set up to build with ROCm.""" 870 _tpl( 871 repository_ctx, 872 "rocm:build_defs.bzl", 873 { 874 "%{rocm_is_configured}": "True", 875 "%{rocm_extra_copts}": _compute_rocm_extra_copts( 876 repository_ctx, 877 [], #_compute_capabilities(repository_ctx) 878 ), 879 }, 880 ) 881 repository_ctx.template( 882 "rocm/BUILD", 883 Label(remote_config_repo + "/rocm:BUILD"), 884 {}, 885 ) 886 repository_ctx.template( 887 "rocm/build_defs.bzl", 888 Label(remote_config_repo + "/rocm:build_defs.bzl"), 889 {}, 890 ) 891 repository_ctx.template( 892 "rocm/rocm/rocm_config.h", 893 Label(remote_config_repo + "/rocm:rocm/rocm_config.h"), 894 {}, 895 ) 896 897 def _rocm_autoconf_impl(repository_ctx): 898 """Implementation of the rocm_autoconf repository rule.""" 899 if not _enable_rocm(repository_ctx): 900 _create_dummy_repository(repository_ctx) 901 elif _TF_ROCM_CONFIG_REPO in repository_ctx.os.environ: 902 _create_remote_rocm_repository( 903 repository_ctx, 904 repository_ctx.os.environ[_TF_ROCM_CONFIG_REPO], 905 ) 906 else: 907 _create_local_rocm_repository(repository_ctx) 908 909 rocm_configure = repository_rule( 910 implementation = _rocm_autoconf_impl, 911 environ = [ 912 _GCC_HOST_COMPILER_PATH, 913 _GCC_HOST_COMPILER_PREFIX, 914 "TF_NEED_ROCM", 915 _ROCM_TOOLKIT_PATH, 916 _TF_ROCM_VERSION, 917 _TF_MIOPEN_VERSION, 918 _TF_ROCM_AMDGPU_TARGETS, 919 _TF_ROCM_CONFIG_REPO, 920 ], 921 ) 922 923 """Detects and configures the local ROCm toolchain. 924 925 Add the following to your WORKSPACE FILE: 926 927 ```python 928 rocm_configure(name = "local_config_rocm") 929 ``` 930 931 Args: 932 name: A unique name for this workspace rule. 933 """