# 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 //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), )