blob: 06ebb1739becada6203affd4d2b66b3f50d661b6 [file]
BUILD_FILE_CONTENT_TEMPLATE = """
package(default_visibility = ['//visibility:public'])
exports_files(['emscripten_config'])
"""
BUILD_FILE_USE_BUILTIN_CACHE = """
alias(
name = "emscripten_cache",
actual = "{}//:builtin_cache",
)
"""
BUILD_FILE_USE_SECONDARY_CACHE = """
filegroup(
name = "emscripten_cache",
srcs = glob(["cache/**"]),
visibility = ["//visibility:public"],
)
"""
EMBUILDER_CONFIG_TEMPLATE = """
CACHE = '{cache}'
BINARYEN_ROOT = '{binaryen_root}'
LLVM_ROOT = '{llvm_root}'
"""
def get_root_and_script_ext(repository_ctx):
if repository_ctx.os.name.startswith("linux"):
if "amd64" in repository_ctx.os.arch or "x86_64" in repository_ctx.os.arch:
return (repository_ctx.path(Label("@emscripten_bin_linux//:BUILD.bazel")).dirname, "")
elif "aarch64" in repository_ctx.os.arch:
return (repository_ctx.path(Label("@emscripten_bin_linux_arm64//:BUILD.bazel")).dirname, "")
else:
fail("Unsupported architecture for Linux")
elif repository_ctx.os.name.startswith("mac"):
if "amd64" in repository_ctx.os.arch or "x86_64" in repository_ctx.os.arch:
return (repository_ctx.path(Label("@emscripten_bin_mac//:BUILD.bazel")).dirname, "")
elif "aarch64" in repository_ctx.os.arch:
return (repository_ctx.path(Label("@emscripten_bin_mac_arm64//:BUILD.bazel")).dirname, "")
else:
fail("Unsupported architecture for MacOS")
elif repository_ctx.os.name.startswith("windows"):
return (repository_ctx.path(Label("@emscripten_bin_win//:BUILD.bazel")).dirname, ".bat")
else:
fail("Unsupported operating system")
def get_bin_deps_repo_name(repository_ctx):
if repository_ctx.os.name.startswith("linux"):
if "amd64" in repository_ctx.os.arch or "x86_64" in repository_ctx.os.arch:
return "@emscripten_bin_linux"
elif "aarch64" in repository_ctx.os.arch:
return "@emscripten_bin_linux_arm64"
else:
fail("Unsupported architecture for Linux")
elif repository_ctx.os.name.startswith("mac"):
if "amd64" in repository_ctx.os.arch or "x86_64" in repository_ctx.os.arch:
return "@emscripten_bin_mac"
elif "aarch64" in repository_ctx.os.arch:
return "@emscripten_bin_mac_arm64"
else:
fail("Unsupported architecture for MacOS")
elif repository_ctx.os.name.startswith("windows"):
return "@emscripten_bin_win"
else:
fail("Unsupported operating system")
def _emscripten_cache_repository_impl(repository_ctx):
# Read the default emscripten configuration file
default_config = repository_ctx.read(
repository_ctx.path(
Label("@emsdk//emscripten_toolchain:default_config"),
),
)
repo_metadata = None
build_file_content = BUILD_FILE_CONTENT_TEMPLATE
use_builtin_cache = True
if repository_ctx.attr.prebuilt_cache_url:
repository_ctx.download_and_extract(
url = repository_ctx.attr.prebuilt_cache_url,
output = "cache",
sha256 = repository_ctx.attr.prebuilt_cache_sha256,
stripPrefix = repository_ctx.attr.prebuilt_cache_strip_prefix,
)
# Use the prebuilt cache
use_builtin_cache = False
# Bazel 7 does not have the repo_metadata API, so prebuilt cache on Bazel 7 will not be marked as reproducible. This is not ideal, but it is a limitation of Bazel 7.
if hasattr(repository_ctx, "repo_metadata"):
repo_metadata = repository_ctx.repo_metadata(reproducible = True)
elif repository_ctx.attr.targets or repository_ctx.attr.configuration:
root, script_ext = get_root_and_script_ext(repository_ctx)
llvm_root = root.get_child("bin")
cache = repository_ctx.path("cache")
# Create configuration file
embuilder_config_content = EMBUILDER_CONFIG_TEMPLATE.format(
cache = cache,
binaryen_root = root,
llvm_root = llvm_root,
)
repository_ctx.file("embuilder_config", embuilder_config_content)
embuilder_config_path = repository_ctx.path("embuilder_config")
embuilder_path = "{}{}".format(root.get_child("emscripten").get_child("embuilder"), script_ext)
# Prepare the command line
if repository_ctx.attr.targets:
targets = repository_ctx.attr.targets
else:
# If no targets are requested, build everything
targets = ["ALL"]
flags = ["--em-config", embuilder_config_path] + repository_ctx.attr.configuration
embuilder_args = [embuilder_path] + flags + ["build"] + targets
# Run embuilder
repository_ctx.report_progress("Building secondary cache")
result = repository_ctx.execute(
embuilder_args,
quiet = False,
environment = {
"EM_IGNORE_SANITY": "1",
"EM_NODE_JS": "empty",
},
)
if result.return_code != 0:
fail("Embuilder exited with a non-zero return code")
use_builtin_cache = False
if use_builtin_cache:
build_file_content += BUILD_FILE_USE_BUILTIN_CACHE.format(get_bin_deps_repo_name(repository_ctx))
else:
default_config += 'CACHE = os.path.join(os.path.dirname(os.environ["EM_CONFIG_PATH"]), "cache")\n'
build_file_content += BUILD_FILE_USE_SECONDARY_CACHE
# Create the configuration file for the toolchain and export
repository_ctx.file("emscripten_config", default_config)
repository_ctx.file("BUILD.bazel", build_file_content)
return repo_metadata
_emscripten_cache_repository = repository_rule(
implementation = _emscripten_cache_repository_impl,
attrs = {
"configuration": attr.string_list(),
"targets": attr.string_list(),
"prebuilt_cache_url": attr.string(),
"prebuilt_cache_sha256": attr.string(),
"prebuilt_cache_strip_prefix": attr.string(),
},
)
def _emscripten_cache_impl(ctx):
all_configuration = []
all_targets = []
prebuilt_cache_url = ""
prebuilt_cache_sha256 = ""
prebuilt_cache_strip_prefix = ""
prebuilt_cache_seen = False
for mod in ctx.modules:
for configuration in mod.tags.configuration:
all_configuration += configuration.flags
for targets in mod.tags.targets:
all_targets += targets.targets
for prebuilt_cache in mod.tags.prebuilt_cache:
if prebuilt_cache_seen:
fail("Only one prebuilt_cache tag is allowed")
prebuilt_cache_url = prebuilt_cache.http_archive_url
prebuilt_cache_sha256 = prebuilt_cache.sha256
prebuilt_cache_strip_prefix = prebuilt_cache.strip_prefix
prebuilt_cache_seen = True
_emscripten_cache_repository(
name = "emscripten_cache",
configuration = all_configuration,
targets = all_targets,
prebuilt_cache_url = prebuilt_cache_url,
prebuilt_cache_sha256 = prebuilt_cache_sha256,
prebuilt_cache_strip_prefix = prebuilt_cache_strip_prefix,
)
emscripten_cache = module_extension(
tag_classes = {
"configuration": tag_class(attrs = {"flags": attr.string_list()}),
"targets": tag_class(attrs = {"targets": attr.string_list()}),
"prebuilt_cache": tag_class(attrs = {
"http_archive_url": attr.string(mandatory = True),
"sha256": attr.string(mandatory = True),
"strip_prefix": attr.string(),
}),
},
implementation = _emscripten_cache_impl,
)