commit 53617c8f0e4827a93ac2c85420c03e7dfbfcf298
parent 66b603cf145bbb4ade64da622e440daedb4776c8
Author: triesap <tyson@radroots.org>
Date: Sun, 9 Aug 2026 18:24:35 +0000
build: support standalone contributor outputs
- keep extbuild output routing when the tool is available
- fall back to ignored Gradle build and Cargo target directories
- make the checked-in Makefile usable without the extbuild subcommand
- document generated-source and standalone-build ownership
Diffstat:
4 files changed, 36 insertions(+), 36 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
@@ -19,10 +19,9 @@ repository and may depend on the exact public Radroots library revision selected
by the capsule; it must not depend on an implicit sibling checkout.
The repository must remain independently cloneable, buildable, testable, and
-packageable through its checked-in command surfaces. It may materialize the
-exact public source revision into an extbuild-owned cache; it must not depend
-on private parent code, parent-only contracts, unpublished local artifacts,
-absolute host paths, or an enclosing monorepo layout.
+packageable through its checked-in command surfaces with or without extbuild.
+It must not depend on private parent code, parent-only contracts, unpublished
+local artifacts, absolute host paths, or an enclosing monorepo layout.
## Machine authority and generated inputs
@@ -52,8 +51,9 @@ absolute host paths, or an enclosing monorepo layout.
Generated UniFFI Kotlin and native libraries are derived build output. Change
the local canonical Rust producer contract/generator first, regenerate into
-extbuild-owned build locations, and inspect the result. Never hand-edit or
-check in generated bindings or native binaries as a source substitute.
+the active Gradle and Cargo build locations, and inspect the result. Never
+hand-edit or check in generated bindings or native binaries as a source
+substitute.
## Application and security boundaries
@@ -88,20 +88,22 @@ keep implementation, tests, generated outputs, dependency evidence, and public
behavior aligned while preserving unrelated work.
The root `Makefile` is the standalone command surface and its durable behavior
-belongs in Gradle or public producer tools. Gradle intentionally requires
-`EXT_BUILD_GRADLE_BUILD_DIR`, and native Cargo work requires
-`CARGO_TARGET_DIR`; do not bypass extbuild or add repo-local build-output
-fallbacks. Run `make doctor` before the first mutating lane, use `make format`,
-`make lint`, and `make test` while iterating, and run `make check` for the
-complete source checkpoint. Use `make build`, `make bindings`, `make audit`,
-`make licenses`, `make package`, and `make release-check` when their affected
-artifact or release scope requires them.
-
-Source-lock synchronization may fetch the exact public revision and package or
-advisory lanes may require external services. Do not weaken immutable inputs or
-silently switch sources when offline. Never claim a lane passed unless it ran
-successfully; report network, toolchain, platform, advisory-service, package,
-or external-artifact blockers exactly.
+belongs in Gradle or public producer tools. When extbuild is installed, the
+Makefile routes commands through it. Without extbuild, Gradle uses its standard
+ignored `build/` directories and Cargo uses the ignored `core/target/` tree;
+the same checked-in tasks must remain functional. Set `EXTBUILD=` explicitly
+to exercise the standalone lane on a machine that also has extbuild. Run
+`make doctor` before the first mutating lane, use `make format`, `make lint`,
+and `make test` while iterating, and run `make check` for the complete source
+checkpoint. Use `make build`, `make bindings`, `make audit`, `make licenses`,
+`make package`, and `make release-check` when their affected artifact or
+release scope requires them.
+
+Shared public Git dependencies and package or advisory lanes may require
+external services. Do not weaken immutable inputs or silently switch sources
+when offline. Never claim a lane passed unless it ran successfully; report
+network, toolchain, platform, advisory-service, package, or external-artifact
+blockers exactly.
Verify exact manifests/lock agreement, generated binding and native artifact
freshness when affected, compatibility and architecture guards,
diff --git a/Makefile b/Makefile
@@ -3,7 +3,7 @@
GRADLE ?= ./gradlew
CARGO ?= cargo
CARGO_MANIFEST := core/Cargo.toml
-EXTBUILD := cargo extbuild run --
+EXTBUILD ?= $(if $(shell cargo extbuild --version 2>/dev/null),cargo extbuild run --)
.PHONY: help doctor format format-fix lint test check build bindings dev run audit licenses package release-check clean
@@ -11,7 +11,7 @@ help:
@printf '%s\n' doctor format format-fix lint test check build bindings dev run audit licenses package release-check clean
doctor:
- cargo extbuild doctor
+ $(if $(strip $(EXTBUILD)),cargo extbuild doctor,@:)
$(EXTBUILD) java -version
$(EXTBUILD) $(CARGO) --version
$(EXTBUILD) $(GRADLE) --version
diff --git a/app/desktop/build.gradle.kts b/app/desktop/build.gradle.kts
@@ -66,13 +66,16 @@ configure<org.jlleitschuh.gradle.ktlint.KtlintExtension> {
}
}
-val extBuildGradleRoot =
- providers.environmentVariable("EXT_BUILD_GRADLE_BUILD_DIR").orNull
- ?: throw GradleException("EXT_BUILD_GRADLE_BUILD_DIR is required; run Gradle through cargo extbuild")
+val rustCoreSource =
+ rootProject.layout.projectDirectory
+ .dir("core")
+ .asFile
+providers.environmentVariable("EXT_BUILD_GRADLE_BUILD_DIR").orNull?.let { extBuildGradleRoot ->
+ layout.buildDirectory.set(file(extBuildGradleRoot).resolve("app-desktop"))
+}
val cargoTargetRoot =
- providers.environmentVariable("CARGO_TARGET_DIR").orNull
- ?: throw GradleException("CARGO_TARGET_DIR is required; run Gradle through cargo extbuild")
-layout.buildDirectory.set(file(extBuildGradleRoot).resolve("app-desktop"))
+ providers.environmentVariable("CARGO_TARGET_DIR").orNull?.let(::file)
+ ?: rustCoreSource.resolve("target")
val radrootsOffline =
providers
@@ -86,10 +89,6 @@ val immutableCargoArguments =
listOf("--locked")
}
-val rustCoreSource =
- rootProject.layout.projectDirectory
- .dir("core")
- .asFile
val rustManifest = rustCoreSource.resolve("Cargo.toml")
fun workspacePackageValue(key: String): String {
diff --git a/build.gradle.kts b/build.gradle.kts
@@ -4,7 +4,6 @@ plugins {
alias(libs.plugins.compose.compiler) apply false
}
-val extBuildGradleRoot =
- providers.environmentVariable("EXT_BUILD_GRADLE_BUILD_DIR").orNull
- ?: error("EXT_BUILD_GRADLE_BUILD_DIR is required; run Gradle through cargo extbuild")
-layout.buildDirectory.set(file(extBuildGradleRoot).resolve("root"))
+providers.environmentVariable("EXT_BUILD_GRADLE_BUILD_DIR").orNull?.let { extBuildGradleRoot ->
+ layout.buildDirectory.set(file(extBuildGradleRoot).resolve("root"))
+}