|  | # Copyright 2019 The Bazel Authors. All rights reserved. | 
|  | # | 
|  | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | # you may not use this file except in compliance with the License. | 
|  | # You may obtain a copy of the License at | 
|  | # | 
|  | #    http://www.apache.org/licenses/LICENSE-2.0 | 
|  | # | 
|  | # Unless required by applicable law or agreed to in writing, software | 
|  | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | # See the License for the specific language governing permissions and | 
|  | # limitations under the License. | 
|  |  | 
|  | """Configure local Resource Compilers for every available target platform. | 
|  |  | 
|  | Platform support: | 
|  |  | 
|  | - Linux/macOS/non-Windows: this repository rule is almost a no-op. | 
|  | It generates an empty BUILD file, and does not actually discover any | 
|  | toolchains. The register_local_rc_exe_toolchains() method is a no-op. | 
|  |  | 
|  | - Windows: this repository rule discovers the Windows SDK path, the installed | 
|  | rc.exe compilers. The register_local_rc_exe_toolchains() registers a toolchain | 
|  | for each rc.exe compiler. | 
|  |  | 
|  | Usage: | 
|  |  | 
|  | load("//src/main/res:winsdk_configure.bzl", "winsdk_configure") | 
|  |  | 
|  | winsdk_configure(name = "local_config_winsdk") | 
|  |  | 
|  | load("@local_config_winsdk//:toolchains.bzl", "register_local_rc_exe_toolchains") | 
|  |  | 
|  | register_local_rc_exe_toolchains() | 
|  | """ | 
|  |  | 
|  | load("@bazel_tools//tools/cpp:windows_cc_configure.bzl", "find_vc_path", "setup_vc_env_vars") | 
|  | load("@bazel_tools//tools/cpp:cc_configure.bzl", "MSVC_ENVVARS") | 
|  |  | 
|  | # Keys: target architecture, as in <Windows-SDK-path>/<target-architecture>/bin/rc.exe | 
|  | # Values: corresponding Bazel CPU value under @platforms//cpu:* | 
|  | _TARGET_ARCH = { | 
|  | "arm": "arm", | 
|  | "arm64": "aarch64", | 
|  | "x64": "x86_64", | 
|  | "x86": "x86_32", | 
|  | } | 
|  |  | 
|  | def _find_rc_exes(root): | 
|  | result = {} | 
|  | for a in _TARGET_ARCH: | 
|  | exe = root.get_child(a).get_child("rc.exe") | 
|  | if exe.exists: | 
|  | result[a] = str(exe) | 
|  | return result | 
|  |  | 
|  | def _find_all_rc_exe(repository_ctx): | 
|  | if not repository_ctx.os.name.startswith("windows"): | 
|  | return {} | 
|  |  | 
|  | vc = find_vc_path(repository_ctx) | 
|  | if vc: | 
|  | env = setup_vc_env_vars( | 
|  | repository_ctx, | 
|  | vc, | 
|  | envvars = [ | 
|  | "WindowsSdkDir", | 
|  | "WindowsSdkVerBinPath", | 
|  | ], | 
|  | allow_empty = True, | 
|  | escape = False, | 
|  | ) | 
|  |  | 
|  | # Try the versioned directory. | 
|  | sdk = env.get("WindowsSdkVerBinPath") | 
|  | if sdk: | 
|  | archs = _find_rc_exes(repository_ctx.path(sdk)) | 
|  | if archs: | 
|  | return archs | 
|  |  | 
|  | # Try the unversioned directory (typically Windows 8.1 SDK). | 
|  | sdk = env.get("WindowsSdkDir") | 
|  | if sdk: | 
|  | archs = _find_rc_exes(repository_ctx.path(sdk).get_child("bin")) | 
|  | if archs: | 
|  | return archs | 
|  | return {} | 
|  |  | 
|  | def _toolchain_defs(repository_ctx, rc_exes): | 
|  | if not rc_exes: | 
|  | return "" | 
|  |  | 
|  | result = ["""# Auto-generated by winsdk_configure.bzl | 
|  | load( | 
|  | "@io_bazel//src/main/res:winsdk_toolchain.bzl", | 
|  | "WINDOWS_RESOURCE_COMPILER_TOOLCHAIN_TYPE", | 
|  | "windows_resource_compiler_toolchain", | 
|  | )"""] | 
|  |  | 
|  | for arch, rc_path in rc_exes.items(): | 
|  | wrapper = "rc_%s.bat" % arch | 
|  | repository_ctx.file( | 
|  | wrapper, | 
|  | content = "@\"%s\" %%*" % rc_path, | 
|  | executable = True, | 
|  | ) | 
|  |  | 
|  | result.append( | 
|  | """ | 
|  | windows_resource_compiler_toolchain( | 
|  | name = "local_{arch}_tc", | 
|  | rc_exe = "{wrapper}", | 
|  | ) | 
|  |  | 
|  | toolchain( | 
|  | name = "local_{arch}", | 
|  | exec_compatible_with = [ | 
|  | "@platforms//os:windows", | 
|  | "@platforms//cpu:x86_64", | 
|  | ], | 
|  | target_compatible_with = [ | 
|  | "@platforms//os:windows", | 
|  | "@platforms//cpu:{cpu}", | 
|  | ], | 
|  | toolchain = ":local_{arch}_tc", | 
|  | toolchain_type = WINDOWS_RESOURCE_COMPILER_TOOLCHAIN_TYPE, | 
|  | visibility = ["//visibility:public"], | 
|  | ) | 
|  | """.format( | 
|  | arch = arch, | 
|  | wrapper = wrapper, | 
|  | cpu = _TARGET_ARCH[arch], | 
|  | ), | 
|  | ) | 
|  |  | 
|  | return "\n".join(result) | 
|  |  | 
|  | def _toolchain_labels(repository_ctx, rc_exes): | 
|  | tc_labels = [ | 
|  | "\"@{repo}//:local_{arch}\"".format(repo = repository_ctx.name, arch = arch) | 
|  | for arch in rc_exes | 
|  | ] | 
|  | if rc_exes: | 
|  | body = "native.register_toolchains(%s)" % ", ".join(tc_labels) | 
|  | else: | 
|  | body = "pass" | 
|  |  | 
|  | return """# Auto-generated by winsdk_configure.bzl | 
|  |  | 
|  | def register_local_rc_exe_toolchains(): | 
|  | {body} | 
|  | """.format(body = body) | 
|  |  | 
|  | def _impl(repository_ctx): | 
|  | rc_exes = _find_all_rc_exe(repository_ctx) | 
|  | repository_ctx.file( | 
|  | "BUILD", | 
|  | content = _toolchain_defs(repository_ctx, rc_exes), | 
|  | executable = False, | 
|  | ) | 
|  |  | 
|  | repository_ctx.file( | 
|  | "toolchains.bzl", | 
|  | content = _toolchain_labels(repository_ctx, rc_exes), | 
|  | executable = False, | 
|  | ) | 
|  |  | 
|  | winsdk_configure = repository_rule( | 
|  | implementation = _impl, | 
|  | local = True, | 
|  | environ = list(MSVC_ENVVARS), | 
|  | ) |