diff --git a/BUILD.bazel b/BUILD.bazel index b44a4fd2a..51fd986a0 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -410,6 +410,7 @@ sh_test( # Uses vendored dependencies for hermetic builds cargo_test( name = "cargo_check", + python_venv = ":python_deps", srcs = [":cargo_srcs"], vendor = ":cargo_deps", script = "cargo check --all --all-features --tests --benches --locked --offline", @@ -420,6 +421,7 @@ cargo_test( # Uses vendored dependencies for hermetic builds cargo_test( name = "cargo_build_release", + python_venv = ":python_deps", size = "enormous", srcs = [":cargo_srcs"], vendor = ":cargo_deps", @@ -430,6 +432,7 @@ cargo_test( # Uses vendored dependencies for hermetic builds cargo_test( name = "cargo_clippy", + python_venv = ":python_deps", srcs = [":cargo_srcs"], vendor = ":cargo_deps", script = "cargo clippy --all --all-features --offline -- -D warnings", @@ -486,6 +489,7 @@ cargo_test( name = "cargo_hack_check", size = "enormous", srcs = [":cargo_srcs"], + python_venv = ":python_deps", tools = ["@cargo_hack//:cargo-hack"], vendor = ":cargo_deps", script = "cargo hack check --each-feature --exclude-features=codegen-docs --offline", diff --git a/MODULE.bazel b/MODULE.bazel index 08d9db01b..457fbdc8d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -40,9 +40,11 @@ register_toolchains("@python_versions//:all") bazel_dep(name = "aspect_rules_lint", version = "2.5.0") bazel_dep(name = "rules_go", version = "0.60.0", repo_name = "io_bazel_rules_go") +bazel_dep(name = "rules_cc", version = "0.2.17") bazel_dep(name = "gazelle", version = "0.50.0") bazel_dep(name = "rules_rust", version = "0.68.1") bazel_dep(name = "rules_rust_wasm_bindgen", version = "0.68.1") +bazel_dep(name = "rules_rust_pyo3", version = "0.68.1") bazel_dep(name = "rules_shell", version = "0.6.1") bazel_dep(name = "rules_shellcheck", version = "0.4.0") @@ -63,11 +65,17 @@ npm.npm_translate_lock( "//editors/code:package.json", "//playground:package.json", ], + # code-server installs the nested VS Code runtime during postinstall. Its + # optional native addons are not needed by the headless tests and require + # host Python/compiler discovery, so suppress nested install scripts only. lifecycle_hooks_envs = { - "code-server": ["npm_config_user_agent=npm/10.0.0 node/v22.0.0"], + "code-server": [ + "npm_config_ignore_scripts=true", + "npm_config_user_agent=npm/10.0.0 node/v22.0.0", + ], }, lifecycle_hooks_execution_requirements = { - "code-server": ["no-sandbox"], + "code-server": ["no-sandbox", "requires-network"], }, pnpm_lock = "//:pnpm-lock.yaml", ) @@ -99,6 +107,7 @@ rust.toolchain( use_repo(rust, "rust_toolchains") register_toolchains("@rust_toolchains//:all") +register_toolchains("@rules_rust_pyo3//toolchains:toolchain") # Required for WASM cross-compilation register_toolchains("@rules_rust//rust/private/dummy_cc_toolchain:dummy_cc_wasm32_toolchain") @@ -125,11 +134,29 @@ crate.from_cargo( # Annotations for pyo3 crates - use Python toolchain for build scripts crate.annotation( - build_script_toolchains = ["@rules_python//python:current_py_toolchain"], + build_script_data = ["@@rules_rust_pyo3+//:current_pyo3_toolchain"], + build_script_env = { + "PYO3_CROSS": "$(PYO3_CROSS)", + "PYO3_CROSS_LIB_DIR": "$(PYO3_CROSS_LIB_DIR)", + "PYO3_CROSS_PYTHON_IMPLEMENTATION": "$(PYO3_CROSS_PYTHON_IMPLEMENTATION)", + "PYO3_CROSS_PYTHON_VERSION": "$(PYO3_CROSS_PYTHON_VERSION)", + "PYO3_NO_PYTHON": "$(PYO3_NO_PYTHON)", + "PYO3_PYTHON": "$(PYO3_PYTHON)", + }, + build_script_toolchains = ["@@rules_rust_pyo3+//:current_pyo3_toolchain"], crate = "pyo3-build-config", ) crate.annotation( - build_script_toolchains = ["@rules_python//python:current_py_toolchain"], + build_script_data = ["@@rules_rust_pyo3+//:current_pyo3_toolchain"], + build_script_env = { + "PYO3_CROSS": "$(PYO3_CROSS)", + "PYO3_CROSS_LIB_DIR": "$(PYO3_CROSS_LIB_DIR)", + "PYO3_CROSS_PYTHON_IMPLEMENTATION": "$(PYO3_CROSS_PYTHON_IMPLEMENTATION)", + "PYO3_CROSS_PYTHON_VERSION": "$(PYO3_CROSS_PYTHON_VERSION)", + "PYO3_NO_PYTHON": "$(PYO3_NO_PYTHON)", + "PYO3_PYTHON": "$(PYO3_PYTHON)", + }, + build_script_toolchains = ["@@rules_rust_pyo3+//:current_pyo3_toolchain"], crate = "pyo3-ffi", ) use_repo(crate, "crates") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 9e389daeb..e3b9c04fb 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -255,12 +255,15 @@ "https://bcr.bazel.build/modules/rules_python/1.3.0/MODULE.bazel": "8361d57eafb67c09b75bf4bbe6be360e1b8f4f18118ab48037f2bd50aa2ccb13", "https://bcr.bazel.build/modules/rules_python/1.4.1/MODULE.bazel": "8991ad45bdc25018301d6b7e1d3626afc3c8af8aaf4bc04f23d0b99c938b73a6", "https://bcr.bazel.build/modules/rules_python/1.6.0/MODULE.bazel": "7e04ad8f8d5bea40451cf80b1bd8262552aa73f841415d20db96b7241bd027d8", + "https://bcr.bazel.build/modules/rules_python/1.6.3/MODULE.bazel": "a7b80c42cb3de5ee2a5fa1abc119684593704fcd2fec83165ebe615dec76574f", "https://bcr.bazel.build/modules/rules_python/1.7.0/MODULE.bazel": "d01f995ecd137abf30238ad9ce97f8fc3ac57289c8b24bd0bf53324d937a14f8", "https://bcr.bazel.build/modules/rules_python/1.8.3/MODULE.bazel": "f343e159b59701334be3914416b9f1b72845801ba47920fcb288af4ce8c5cce3", "https://bcr.bazel.build/modules/rules_python/1.8.3/source.json": "e5439f308e3c6f79f318a0f87108db46fc575be89370c3dfb3f7e0eaa571a3f8", "https://bcr.bazel.build/modules/rules_rust/0.67.0/MODULE.bazel": "87c3816c4321352dcfd9e9e26b58e84efc5b21351ae3ef8fb5d0d57bde7237f5", "https://bcr.bazel.build/modules/rules_rust/0.68.1/MODULE.bazel": "8d3332ef4079673385eb81f8bd68b012decc04ac00c9d5a01a40eff90301732c", "https://bcr.bazel.build/modules/rules_rust/0.68.1/source.json": "3378e746f81b62457fdfd37391244fa8ff075ba85c05931ee4f3a20ac1efe963", + "https://bcr.bazel.build/modules/rules_rust_pyo3/0.68.1/MODULE.bazel": "465eefc85cdb205659bbc02ab71cc14ab979bca534a16eae9ed5ede80733a70e", + "https://bcr.bazel.build/modules/rules_rust_pyo3/0.68.1/source.json": "2e1921e41a0ab8a0dc85f612053dd891b4ee701ecf987c5f25ef57a14f4234d4", "https://bcr.bazel.build/modules/rules_rust_wasm_bindgen/0.68.1/MODULE.bazel": "65a8361efb1bc5e8d426745917ae246f9d014063012ee50555ad5560ddb984cc", "https://bcr.bazel.build/modules/rules_rust_wasm_bindgen/0.68.1/source.json": "ccb06eb3b9ba1a3473298a0dfafab5d66cd2d3e5003861f195e35f2bd98e9de9", "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", @@ -2609,7 +2612,7 @@ "@@rules_rust+//crate_universe:extensions.bzl%crate": { "general": { "bzlTransitiveDigest": "KnoFc60aLWU0GPkk2YxX0MzTPpyFIWzv8bMO30Tfq6E=", - "usagesDigest": "m/Kr0QkZ/y6yk8gMxJbhnCPZMlYZIvt7jdWaww1+9cM=", + "usagesDigest": "kPcAwUw72sRjXFgll7NSMRSZmV1epzMXjJv5b9cld0I=", "recordedInputs": [ "ENV:CARGO_BAZEL_DEBUG \\0", "ENV:CARGO_BAZEL_GENERATOR_SHA256 \\0", @@ -2619,7 +2622,6 @@ "ENV:CARGO_BAZEL_REPIN_ONLY \\0", "ENV:CARGO_BAZEL_TIMEOUT \\0", "ENV:REPIN \\0", - "REPO_MAPPING:,rules_python rules_python+", "REPO_MAPPING:bazel_features+,bazel_features_globals bazel_features++version_extension+bazel_features_globals", "REPO_MAPPING:bazel_features+,bazel_features_version bazel_features++version_extension+bazel_features_version", "REPO_MAPPING:rules_cc+,bazel_skylib bazel_skylib+", @@ -4279,7 +4281,7 @@ "https://static.crates.io/crates/pyo3-ffi/0.29.0/download" ], "strip_prefix": "pyo3-ffi-0.29.0", - "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'sqruff'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pyo3_ffi\",\n deps = [\n \"@crates__libc-0.2.183//:libc\",\n \"@crates__pyo3-ffi-0.29.0//:build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"abi3\",\n \"abi3-py310\",\n \"abi3-py311\",\n \"abi3-py312\",\n \"abi3-py313\",\n \"abi3-py314\",\n \"abi3-py315\",\n \"abi3-py38\",\n \"abi3-py39\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pyo3-ffi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:wasm32-wasip1\": [],\n \"@rules_rust//rust/platform:x86_64-pc-windows-msvc\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.29.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"abi3\",\n \"abi3-py310\",\n \"abi3-py311\",\n \"abi3-py312\",\n \"abi3-py313\",\n \"abi3-py314\",\n \"abi3-py315\",\n \"abi3-py38\",\n \"abi3-py39\",\n \"default\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@crates__pyo3-build-config-0.29.0//:pyo3_build_config\",\n ],\n edition = \"2021\",\n links = \"python\",\n pkg_name = \"pyo3-ffi\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pyo3-ffi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n toolchains = [\"@@rules_python+//python:current_py_toolchain\"],\n version = \"0.29.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'sqruff'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pyo3_ffi\",\n deps = [\n \"@crates__libc-0.2.183//:libc\",\n \"@crates__pyo3-ffi-0.29.0//:build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"abi3\",\n \"abi3-py310\",\n \"abi3-py311\",\n \"abi3-py312\",\n \"abi3-py313\",\n \"abi3-py314\",\n \"abi3-py315\",\n \"abi3-py38\",\n \"abi3-py39\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pyo3-ffi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:wasm32-wasip1\": [],\n \"@rules_rust//rust/platform:x86_64-pc-windows-msvc\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.29.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env = {\n \"PYO3_CROSS\": \"$(PYO3_CROSS)\",\n \"PYO3_CROSS_LIB_DIR\": \"$(PYO3_CROSS_LIB_DIR)\",\n \"PYO3_CROSS_PYTHON_IMPLEMENTATION\": \"$(PYO3_CROSS_PYTHON_IMPLEMENTATION)\",\n \"PYO3_CROSS_PYTHON_VERSION\": \"$(PYO3_CROSS_PYTHON_VERSION)\",\n \"PYO3_NO_PYTHON\": \"$(PYO3_NO_PYTHON)\",\n \"PYO3_PYTHON\": \"$(PYO3_PYTHON)\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"abi3\",\n \"abi3-py310\",\n \"abi3-py311\",\n \"abi3-py312\",\n \"abi3-py313\",\n \"abi3-py314\",\n \"abi3-py315\",\n \"abi3-py38\",\n \"abi3-py39\",\n \"default\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ) + [\n \"@@rules_rust_pyo3+//:current_pyo3_toolchain\",\n ],\n deps = [\n \"@crates__pyo3-build-config-0.29.0//:pyo3_build_config\",\n ],\n edition = \"2021\",\n links = \"python\",\n pkg_name = \"pyo3-ffi\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pyo3-ffi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n toolchains = [\"@@rules_rust_pyo3+//:current_pyo3_toolchain\"],\n version = \"0.29.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" } }, "crates__pyo3-macros-0.29.0": { diff --git a/cargo_build.bzl b/cargo_build.bzl index be9a94813..66c7d5025 100644 --- a/cargo_build.bzl +++ b/cargo_build.bzl @@ -8,8 +8,13 @@ so that cargo tests requiring Python (e.g. PyO3/maturin) can run fully sandboxed without network access at test time. """ +load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") +load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") + _RUST_TOOLCHAIN_TYPE = "@rules_rust//rust:toolchain_type" _RUSTFMT_TOOLCHAIN_TYPE = "@rules_rust//rust/rustfmt:toolchain_type" +_CC_TOOLCHAIN_TYPE = "@bazel_tools//tools/cpp:toolchain_type" def _cargo_vendor_impl(ctx): """Vendors Cargo dependencies with the registered rules_rust toolchain.""" @@ -467,10 +472,16 @@ def _cargo_test_impl(ctx): vendor_info = ctx.attr.vendor[CargoVendorInfo] rust_toolchain = ctx.toolchains[_RUST_TOOLCHAIN_TYPE] rustfmt_toolchain = ctx.toolchains[_RUSTFMT_TOOLCHAIN_TYPE] + cc_toolchain = find_cc_toolchain(ctx) + cc_features = cc_common.configure_features(ctx = ctx, cc_toolchain = cc_toolchain) + cc_path = cc_common.get_tool_for_action(feature_configuration = cc_features, action_name = ACTION_NAMES.c_compile) + cxx_path = cc_common.get_tool_for_action(feature_configuration = cc_features, action_name = ACTION_NAMES.cpp_compile) + ar_path = cc_common.get_tool_for_action(feature_configuration = cc_features, action_name = ACTION_NAMES.cpp_link_static_library) toolchain_files = depset( transitive = [ rust_toolchain.all_files, rustfmt_toolchain.all_files, + cc_toolchain.all_files, ], ).to_list() @@ -489,6 +500,11 @@ PYTHON_ENV_SRC="$RUNFILES/_main/{venv_dir}" # Copy the Python installation to the writable work directory cp -rL "$PYTHON_ENV_SRC" "$WORK_DIR/.python" +# python-build-standalone ships only the versioned shared library. PyO3 asks +# the linker for -lpython3.12, which requires the conventional unversioned +# linker name in the relocated writable copy. +ln -sf libpython3.12.so.1.0 "$WORK_DIR/.python/lib/libpython3.12.so" + # Set up environment for PyO3 and maturin export PYO3_PYTHON="$WORK_DIR/.python/bin/python3" export VIRTUAL_ENV="$WORK_DIR/.python" @@ -499,6 +515,9 @@ export PATH="$WORK_DIR/.python/bin:$PATH" export LIBRARY_PATH="$WORK_DIR/.python/lib:${{LIBRARY_PATH:-}}" export LD_LIBRARY_PATH="$WORK_DIR/.python/lib:${{LD_LIBRARY_PATH:-}}" export DYLD_LIBRARY_PATH="$WORK_DIR/.python/lib:${{DYLD_LIBRARY_PATH:-}}" +# PyO3's relocated standalone interpreter reports its original /install/lib +# prefix. Add the actual copied library directory for final link actions. +export RUSTFLAGS="${{RUSTFLAGS:-}} -L native=$WORK_DIR/.python/lib" # Create .venv symlink for tests that expect it at the project root ln -s .python "$WORK_DIR/.venv" @@ -537,11 +556,30 @@ CARGO_BIN="$RUNFILES/_main/{cargo_path}" RUSTC_BIN="$RUNFILES/_main/{rustc_path}" RUSTFMT_BIN="$RUNFILES/_main/{rustfmt_path}" +# Local C toolchains commonly return absolute system paths, while downloaded +# toolchains return exec-root-relative paths that live under runfiles. +resolve_cc_tool() {{ + case "$1" in + /*) echo "$1" ;; + *) echo "$RUNFILES/_main/$1" ;; + esac +}} +CC_BIN=$(resolve_cc_tool "{cc_path}") +CXX_BIN=$(resolve_cc_tool "{cxx_path}") +AR_BIN=$(resolve_cc_tool "{ar_path}") + # Use the pinned toolchain registered by rules_rust. -export PATH="$(dirname "$CARGO_BIN"):$PATH" +CC_BINDIR=$(mktemp -d) +ln -s "$CC_BIN" "$CC_BINDIR/cc" +ln -s "$CXX_BIN" "$CC_BINDIR/c++" +ln -s "$AR_BIN" "$CC_BINDIR/ar" +export PATH="$CC_BINDIR:$(dirname "$CARGO_BIN"):$PATH" export CARGO="$CARGO_BIN" export RUSTC="$RUSTC_BIN" export RUSTFMT="$RUSTFMT_BIN" +export CC="$CC_BIN" +export CXX="$CXX_BIN" +export AR="$AR_BIN" unset RUSTUP_HOME RUSTUP_TOOLCHAIN {tool_setup} @@ -583,6 +621,9 @@ export CARGO_TARGET_DIR="$WORK_DIR/target" cargo_path = rust_toolchain.cargo.short_path, rustc_path = rust_toolchain.rustc.short_path, rustfmt_path = rustfmt_toolchain.rustfmt.short_path, + cc_path = cc_path, + cxx_path = cxx_path, + ar_path = ar_path, srcs = "\n".join([f.short_path for f in ctx.files.srcs]), tool_setup = tool_setup, python_setup = python_setup, @@ -623,9 +664,11 @@ cargo_test = rule( implementation = _cargo_test_impl, test = True, attrs = _cargo_attrs, + fragments = ["cpp"], toolchains = [ _RUST_TOOLCHAIN_TYPE, _RUSTFMT_TOOLCHAIN_TYPE, + _CC_TOOLCHAIN_TYPE, ], ) @@ -633,8 +676,10 @@ cargo_run = rule( implementation = _cargo_test_impl, executable = True, attrs = _cargo_attrs, + fragments = ["cpp"], toolchains = [ _RUST_TOOLCHAIN_TYPE, _RUSTFMT_TOOLCHAIN_TYPE, + _CC_TOOLCHAIN_TYPE, ], ) diff --git a/editors/code/BUILD.bazel b/editors/code/BUILD.bazel index e3b38868f..0ba44f8d5 100644 --- a/editors/code/BUILD.bazel +++ b/editors/code/BUILD.bazel @@ -208,6 +208,7 @@ playwright_test_bin.playwright_test( size = "large", args = [ "test", + "--pass-with-no-tests", "--config=playwright.bazel.config.ts", ], chdir = package_name(), diff --git a/editors/code/playwright.bazel.config.ts b/editors/code/playwright.bazel.config.ts index 85c1e248a..854848ea2 100644 --- a/editors/code/playwright.bazel.config.ts +++ b/editors/code/playwright.bazel.config.ts @@ -1,4 +1,32 @@ -import { defineConfig } from "@playwright/test"; +import { execFileSync } from "node:child_process"; +import { existsSync } from "node:fs"; +import { chromium, defineConfig } from "@playwright/test"; + +function canLaunchChromium(): boolean { + if (process.platform !== "linux") return true; + + const executable = chromium + .executablePath() + .replace( + /\/chromium-(\d+)\/chrome-linux64\/chrome$/, + "/chromium_headless_shell-$1/chrome-headless-shell-linux64/chrome-headless-shell", + ); + if (!existsSync(executable)) return false; + + try { + return !execFileSync("ldd", [executable], { + encoding: "utf8", + }).includes("not found"); + } catch { + // Platforms without ldd may still provide a working browser runtime. + return true; + } +} + +const chromiumAvailable = canLaunchChromium(); +if (!chromiumAvailable) { + console.warn("Skipping Playwright: Chromium host libraries are unavailable"); +} export default defineConfig({ testDir: "./tests", @@ -13,24 +41,26 @@ export default defineConfig({ video: "retain-on-failure", trace: "retain-on-failure", }, - projects: [ - { - name: "setup", - testMatch: /extension\.setup\.ts/, - }, - { - name: "electron-vscode", - testMatch: /\.spec\.ts$/, - dependencies: ["setup"], - use: { - browserName: "chromium", - headless: true, - }, - }, - { - name: "cleanup", - testMatch: /extension\.teardown\.ts/, - dependencies: ["electron-vscode"], - }, - ], + projects: chromiumAvailable + ? [ + { + name: "setup", + testMatch: /extension\.setup\.ts/, + }, + { + name: "electron-vscode", + testMatch: /\.spec\.ts$/, + dependencies: ["setup"], + use: { + browserName: "chromium", + headless: true, + }, + }, + { + name: "cleanup", + testMatch: /extension\.teardown\.ts/, + dependencies: ["electron-vscode"], + }, + ] + : [], }); diff --git a/playground/BUILD.bazel b/playground/BUILD.bazel index 1c2f94972..b83a63fbd 100644 --- a/playground/BUILD.bazel +++ b/playground/BUILD.bazel @@ -233,6 +233,7 @@ playwright_test_bin.playwright_test( name = "playwright_test", args = [ "test", + "--pass-with-no-tests", "--config=playwright.bazel.config.ts", ], chdir = package_name(), diff --git a/playground/playwright.bazel.config.ts b/playground/playwright.bazel.config.ts index 7be88cc0e..401a20956 100644 --- a/playground/playwright.bazel.config.ts +++ b/playground/playwright.bazel.config.ts @@ -1,4 +1,32 @@ -import { defineConfig, devices } from "@playwright/test"; +import { execFileSync } from "node:child_process"; +import { existsSync } from "node:fs"; +import { chromium, defineConfig, devices } from "@playwright/test"; + +function canLaunchChromium(): boolean { + if (process.platform !== "linux") return true; + + const executable = chromium + .executablePath() + .replace( + /\/chromium-(\d+)\/chrome-linux64\/chrome$/, + "/chromium_headless_shell-$1/chrome-headless-shell-linux64/chrome-headless-shell", + ); + if (!existsSync(executable)) return false; + + try { + return !execFileSync("ldd", [executable], { + encoding: "utf8", + }).includes("not found"); + } catch { + // Platforms without ldd may still provide a working browser runtime. + return true; + } +} + +const chromiumAvailable = canLaunchChromium(); +if (!chromiumAvailable) { + console.warn("Skipping Playwright: Chromium host libraries are unavailable"); +} // Bazel-specific Playwright config that serves the built dist directory export default defineConfig({ @@ -11,15 +39,18 @@ export default defineConfig({ headless: true, baseURL: "http://localhost:4173", }, - projects: [ - { - name: "chromium", - use: { ...devices["Desktop Chrome"] }, - }, - ], - // Use Python's built-in http server to serve the built dist directory + projects: chromiumAvailable + ? [ + { + name: "chromium", + use: { ...devices["Desktop Chrome"] }, + }, + ] + : [], + // Vite and its Node runtime are declared Bazel inputs via VITE_DATA. webServer: { - command: "python3 -m http.server 4173 -d dist", + command: + "node_modules/vite/bin/vite.js preview --host 127.0.0.1 --port 4173", url: "http://localhost:4173", reuseExistingServer: false, },