| 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, ".exe") | |
| 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 | |
| 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, | |
| ) |