-
Notifications
You must be signed in to change notification settings - Fork 810
[Bazel] Support for a custom prebuilt emscripten cache #1620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
cc59466
53341a8
961b27e
77eb9cd
bd51eec
55f3e37
8ade2ca
0a46a54
a34996d
6ebf8b2
a5b8e2a
a633036
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,21 @@ 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}' | ||
|
|
@@ -29,6 +44,26 @@ def get_root_and_script_ext(repository_ctx): | |
| 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( | ||
|
|
@@ -37,7 +72,26 @@ def _emscripten_cache_repository_impl(repository_ctx): | |
| ), | ||
| ) | ||
|
|
||
| if repository_ctx.attr.targets or repository_ctx.attr.configuration: | ||
| 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") | ||
|
|
@@ -72,42 +126,72 @@ def _emscripten_cache_repository_impl(repository_ctx): | |
| }, | ||
| ) | ||
| if result.return_code != 0: | ||
| fail("Embuilder exited with a non-zero return code") | ||
| fail("Embuilder exited with a non-zero return code\nstdout: {}\nstderr: {}".format(result.stdout, result.stderr)) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we should avoid capturing the stdout/stderr of embuilder? Is it problem to simpy pass it through. By default its not very verbose.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added it to debug why embuilder was failing when I was creating prebuilt cache for the test. For some reason I thought that the default for I agree it's better to be passed through. |
||
|
|
||
| # Override Emscripten's cache with the secondary cache | ||
| default_config += "CACHE = '{}'\n".format(cache) | ||
| 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_TEMPLATE) | ||
| 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 | ||
|
DoDoENT marked this conversation as resolved.
|
||
| 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, | ||
|
DoDoENT marked this conversation as resolved.
|
||
| ) | ||
|
|
||
| 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, | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| build --incompatible_enable_cc_toolchain_resolution | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know if we still need this
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought this was needed for Bazel 7, but I see now that in Bazel 7 this got enabled by default. Since we don't support older bazel versions, it's safe to remove it. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| bazel-bin | ||
| bazel-out | ||
| bazel-test_prebuilt_cache | ||
| bazel-testlogs |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| load("@emsdk//emscripten_toolchain:wasm_rules.bzl", "wasm_cc_binary") | ||
| load("@rules_cc//cc:defs.bzl", "cc_binary") | ||
|
|
||
| cc_binary( | ||
| name = "hello-world", | ||
| srcs = ["hello-world.cc"], | ||
| copts = [ | ||
| "-flto=thin", | ||
| ], | ||
| linkopts = [ | ||
| "-sAUTO_NATIVE_LIBRARIES=0", | ||
| "-flto=thin", | ||
| ], | ||
| ) | ||
|
|
||
| wasm_cc_binary( | ||
| name = "hello-world-wasm", | ||
| cc_target = ":hello-world", | ||
| outputs = [ | ||
| "hello-world.js", | ||
| "hello-world.wasm", | ||
| ], | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| bazel_dep(name = "rules_cc", version = "0.2.16") | ||
| bazel_dep(name = "emsdk") | ||
| local_path_override( | ||
| module_name = "emsdk", | ||
| path = "..", | ||
| ) | ||
|
|
||
| emscripten_deps = use_extension( | ||
| "@emsdk//:emscripten_deps.bzl", | ||
| "emscripten_deps", | ||
| ) | ||
|
|
||
| # Need to use the same version of Emscripten as the prebuilt cache was built with to ensure compatibility even when future versions of Emscripten are released. | ||
| emscripten_deps.config( | ||
| version = "5.0.7", | ||
| ) | ||
|
|
||
| emscripten_cache = use_extension( | ||
| "@emsdk//:emscripten_cache.bzl", | ||
| "emscripten_cache", | ||
| ) | ||
|
|
||
| # This cache was built with Emscripten 5.0.7, and contains opt-thinlto build. | ||
| # It has been build according to these instructions: https://github.com/DoDoENT/bazel-playground/blob/master/tools/emsdk-cache-builder/README.md | ||
|
DoDoENT marked this conversation as resolved.
Outdated
|
||
| emscripten_cache.prebuilt_cache( | ||
| http_archive_url = "https://github.com/DoDoENT/bazel-playground/releases/download/emsdk-cache/emsdk-cache-5.0.7.tar.gz", | ||
| sha256 = "bbfdab09ae64769c4aa977b1d88f776490c459c87e7ed7e31fe00190cd56b14a", | ||
| strip_prefix = "emsdk-cache", | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| #include <iostream> | ||
|
|
||
| int main(int argc, char** argv) { | ||
| std::cout << "hello world!" << std::endl; | ||
| return 0; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent suggestion! Thank you. I added tests that uncovered incompatibilities with Bazel 7, which I now fixed.