← Files LimrunARCHIVED FILE
skills/limrun-xcode-bazel/references/project-compatibility.md
6.06 KB · Oct 5, 2026 · 18:22 UTC
# Making an arbitrary Bazel Apple project build on Limrun RBE The generated `--config=limrun` is the whole happy path for an idiomatic rules_apple / rules_swift project. When a build doesn't go green, it's almost always one of the patterns below — each is a property of *the project's* Bazel setup, not a Limrun bug. Symptom → cause → what to do. ## What the generated config / fleet already handle (don't re-derive these) - **apple_support rule `load`s on Bazel 9** — the `.limrun/BUILD` loads `xcode_version` / `available_xcodes` / `xcode_config` from apple_support on Bazel 9 (where they're no longer native globals) and omits them on Bazel 8 (where loading them fails). Driven off the workspace `.bazelversion`. - **Xcode pinned to the sandbox's, both remote and local** — the `.limrun/BUILD` declares the sandbox's Xcode (the fleet default, or the major picked with `lim xcode rbe --xcode-version`) as both the remote AND local version and sets `--xcode_version` to it, so the build uses only that Xcode and resolves cleanly (no apple_support "…not available locally" notice). This is the "everything runs remotely" stance — see the local-Apple-actions pattern below if a project genuinely needs a Mac-local Apple action. - **`--strategy=SwiftCompile=remote` / `--strategy=Genrule=remote`** — overrides the common local pins (rules_swift's worker, standalone genrules). - **rules_apple `no-remote` / `no-remote-exec` stripped** (`--modify_execution_info=.*=-no-remote,.*=-no-remote-exec`): bundling, linking, and signing actions that rules_apple (or a repo's recommended `+no-remote` bazelrc) pins local are stripped so they run on the worker. Without this they fail on a thin (e.g. Linux) client with `cannot be executed with any of the available strategies: [remote]`. - **A workspace `--remote_cache` is cleared** (`--remote_cache=`): a repo pointing `--remote_cache` at a separate backend (BuildBuddy, EngFlow) would split the CAS against Limrun's executor and fail with `Lost inputs no longer available remotely`. The generated config empties it under `--config=limrun`, and the repo's non-limrun builds keep their own cache. - **Darwin exec platform on non-mac clients**, and `PATH` including `/usr/sbin`. - **CoreSimulator IB utility devices** (actool/ibtool) — provisioned by the fleet. ## Patterns that require a project-side change ### A pinned Xcode version via a Starlark transition A repo may lock the Xcode version for a sub-build with a `transition` outputting `//command_line_option:xcode_version`. **A transition output overrides `--xcode_version`** — no flag or bazelrc can win against it. If the pinned version isn't the sandbox's, analysis fails in `host_xcodes`. Fix: pick the matching major with `lim xcode rbe --xcode-version <major>` when the fleet has it, otherwise edit the transition to drop the `xcode_version` output (or set it to the sandbox's). ### Custom `remote_default_exec_properties` Limrun's worker matches actions by an **exact** platform-property set (`OSFamily=Darwin`). A project bazelrc that adds extra/mismatched properties (a lowercase `OSFamily=darwin`, `Arch=arm64`, a `cache_bust=…`) makes the action platform no longer match any worker → the build stalls or reports no usable worker. Fix: neutralize those base `build --remote_default_exec_properties=…` lines for the limrun path (the generated config sets the one the worker needs). ### Per-mnemonic strategy pins beyond Swift/Genrule If a repo pins other mnemonics local (e.g. `--strategy=ObjcCompile=local`), those actions run on the client and then need a local Xcode / can't run on a thin Linux client. Symptom: an action runs `local`/`worker` and fails resolving a local toolchain. Fix: override the offending mnemonic to `remote`. ### Foreign-build genrules (a host tool compiled from source) A genrule that downloads a C/C++ tool's source and shells out to `cmake`/`make` (probing `sysctl` for `-j`, etc.) is **not** sandbox/RBE-friendly: the cage lacks those tools. Symptom: `sysctl: command not found` / `Exit 127` in a `[for tool]` genrule once forced remote. Idiomatic host tools built as a normal `cc_binary` compile fine remotely. Treat the genrule form as a project smell. ### codesign digest algorithm A target that sets `codesignopts = ["--digest-algorithm=sha1"]` fails under recent Xcode's codesign: `signing with only SHA1 not allowed`. Use `sha256`. ### A Mac-local Apple action that must use the client's own Xcode The generated config pins Xcode to the fleet's version for **both** the remote and local sets, and forces every action remote (`--spawn_strategy=remote`, `--noremote_local_fallback`). That's deliberate: it makes the build identical on a Mac and a Linux client and silences the "Xcode not available locally" notice. The trade-off: if a project *forces* an Apple/Swift action to run on the Mac client (e.g. a `--strategy=…=local` pin, or a rule that runs `xcode-locator` against the host), it will look for the fleet's Xcode build locally and fail (`xcode-locator … not available`) instead of using the Mac's own Xcode. This is intended — under Limrun RBE everything is meant to run remotely. If you genuinely need that local action: either drop the local strategy pin so it runs remote like everything else (preferred), or, if you must keep it local, hand-edit `.limrun/BUILD` to declare the client's *real* local Xcode as a distinct `local_xcode` (a different major.minor from the fleet's, so its alias doesn't collide) under `local_versions` — accepting the "not available locally" notice back. Re-running `lim xcode rbe` regenerates `.limrun/`, so make the edit durable elsewhere if you keep it. ## Expected, benign - **A local sub-build before the remote build** — some example repos consume the ruleset via a *built release archive*, so the first thing you see is a local build of that archive, then the real target builds remote. Not an error. - `compatibility_level` and `bazel_features` version mismatch **warnings**. --- Append new patterns here as they're hit — keep them at the pattern level (symptom → cause → fix), not as one-off patches for a specific app.
SHA-256: fbba8cf146d35bcb192c09df0b6f47a007801eacc9ee47b26863c285e0fadbe8