Skip to content

Commit a9a997c

Browse files
Migrate UniFFI bindings generation off libraryVariants to androidComponents.onVariants (#7430)
The previous migration (#7429) left the UniFFI bindings generation hook in build-scripts/component-common.gradle on the legacy registerJavaGeneratingTask API. Move it to androidComponents.onVariants, registering the generated sources via variant.sources.java.addGeneratedSourceDirectory and converting generateUniffiBindings to typed task classes with a wired output directory. The directory is registered as sources.java (not sources.kotlin) because AGP wires generated java dirs into both javac and kotlinc, while sources.kotlin is only consumed by AGP's built-in Kotlin, not the external Kotlin plugin used here.
1 parent c3af51c commit a9a997c

1 file changed

Lines changed: 72 additions & 38 deletions

File tree

build-scripts/component-common.gradle

Lines changed: 72 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,65 @@
77
// apply from: "$rootDir/build-scripts/component-common.gradle"
88
// ```
99

10+
import javax.inject.Inject
1011

1112
apply plugin: 'com.android.library'
1213
apply plugin: 'kotlin-android'
1314

15+
// Typed Exec subclass used in the moz-central build, where the embedded
16+
// uniffi-bindgen tool and the native megazord library are already built before
17+
// gradle runs. Exposes outputDir as a DirectoryProperty so the generated
18+
// sources can be wired into the variant via addGeneratedSourceDirectory.
19+
abstract class GenerateUniffiBindingsEmbedded extends Exec {
20+
@OutputDirectory
21+
abstract DirectoryProperty getOutputDir()
22+
}
23+
24+
// Typed task used in the standalone app-services build, where the megazord
25+
// dynamic library is produced by a separate gradle task and only exists when
26+
// generateUniffiBindings runs (not at configuration time).
27+
abstract class GenerateUniffiBindingsCargo extends DefaultTask {
28+
@InputFiles
29+
abstract ConfigurableFileCollection getMegazordNativeFiles()
30+
31+
@InputDirectory
32+
abstract DirectoryProperty getBindgenToolDir()
33+
34+
@Input
35+
abstract Property<String> getCrateName()
36+
37+
@Input
38+
abstract Property<String> getNativeRustTarget()
39+
40+
@Internal
41+
abstract DirectoryProperty getWorkingDirectory()
42+
43+
@OutputDirectory
44+
abstract DirectoryProperty getOutputDir()
45+
46+
@Inject
47+
abstract ExecOperations getExecOperations()
48+
49+
@TaskAction
50+
void run() {
51+
def libraryPath = megazordNativeFiles.asFileTree.matching {
52+
include "${nativeRustTarget.get()}/libmegazord.*"
53+
}.singleFile
54+
55+
if (libraryPath == null) {
56+
throw new GradleException("libmegazord dynamic library path not found")
57+
}
58+
59+
execOperations.exec {
60+
workingDir workingDirectory.get().asFile
61+
commandLine '/usr/bin/env', 'cargo', 'uniffi-bindgen', 'generate',
62+
'--crate', crateName.get(), '--language', 'kotlin',
63+
'--out-dir', outputDir.get().asFile,
64+
'--no-format', libraryPath
65+
}
66+
}
67+
}
68+
1469
android {
1570
compileSdk { version = release(config.compileSdkMajorVersion) { minorApiLevel = config.compileSdkMinorVersion } }
1671

@@ -100,62 +155,41 @@ ext.configureUniFFIBindgen = { crateName ->
100155
// This will store the uniffi-bindgen generated files for our component
101156
def uniffiOutDir = layout.buildDirectory.dir("generated/uniffi/")
102157

103-
android {
104-
sourceSets.main.kotlin.srcDirs += uniffiOutDir
105-
}
106-
107158
def generateUniffiBindings
108159
// Call `uniffi-bindgen` to generate the Kotlin bindings
109160
if (gradle.hasProperty("mozconfig")) {
110161
// in moz-central we can use an `Exec` task because we can assume the bindgen tool has already been built.
111-
generateUniffiBindings = tasks.register("generateUniffiBindings", Exec) {
162+
generateUniffiBindings = tasks.register("generateUniffiBindings", GenerateUniffiBindingsEmbedded) {
112163
def libraryPath = "${gradle.mozconfig.topobjdir}/dist/bin/libmegazord.so"
113164
def bindgen = gradle.ext.mozconfig.substs.EMBEDDED_UNIFFI_BINDGEN
114165

166+
outputDir.set(uniffiOutDir)
167+
115168
workingDir project.rootDir
116169
commandLine bindgen
117-
args 'generate', "--crate", crateName, '--language', 'kotlin', '--out-dir', uniffiOutDir.get(), '--no-format', libraryPath
170+
args 'generate', "--crate", crateName, '--language', 'kotlin', '--out-dir', outputDir.get().asFile, '--no-format', libraryPath
118171

119-
outputs.dir uniffiOutDir
120172
// Re-generate when the native megazord library is rebuilt
121173
inputs.files libraryPath
122174
// Re-generate if our uniffi-bindgen tooling changes.
123175
inputs.files bindgen
124176
}
125177
} else {
126-
// In app-services we can't use `Exec` because the megazord target isn't built yet, which we force via `doFirst`
127-
generateUniffiBindings = tasks.register("generateUniffiBindings") {
128-
def megazordNative = configurations.getByName("megazordNative")
129-
doFirst {
130-
def libraryPath = megazordNative.asFileTree.matching {
131-
include "${nativeRustTarget}/libmegazord.*"
132-
}.singleFile
133-
134-
if (libraryPath == null) {
135-
throw new GradleException("libmegazord dynamic library path not found")
136-
}
137-
exec {
138-
workingDir project.rootDir
139-
commandLine '/usr/bin/env', 'cargo', 'uniffi-bindgen', 'generate', "--crate", crateName, '--language', 'kotlin', '--out-dir', uniffiOutDir.get(), '--no-format', libraryPath
140-
}
141-
}
142-
143-
outputs.dir uniffiOutDir
144-
// Re-generate when the native megazord library is rebuilt
145-
inputs.files megazordNative
146-
// Re-generate if our uniffi-bindgen tooling changes.
147-
inputs.dir "${project.appServicesRootDir}/tools/embedded-uniffi-bindgen/"
178+
// In app-services we can't use `Exec` because the megazord target isn't built yet; the task
179+
// resolves the library path from the megazordNative configuration when it runs.
180+
generateUniffiBindings = tasks.register("generateUniffiBindings", GenerateUniffiBindingsCargo) {
181+
// Qualify every property with `it.` because the `crateName` closure parameter shadows the
182+
// task's crateName property; a bare `crateName.set(...)` would target the String, not the task.
183+
it.megazordNativeFiles.from configurations.getByName("megazordNative")
184+
it.bindgenToolDir.set(file("${project.appServicesRootDir}/tools/embedded-uniffi-bindgen/"))
185+
it.crateName.set(crateName)
186+
it.nativeRustTarget.set(rootProject.ext.nativeRustTarget)
187+
it.workingDirectory.set(project.rootDir)
188+
it.outputDir.set(uniffiOutDir)
148189
}
149190
}
150191

151-
afterEvaluate {
152-
def megazordNative = configurations.getByName("megazordNative")
153-
android.libraryVariants.all { variant ->
154-
def compileTask = tasks["compile${variant.name.capitalize()}Kotlin"]
155-
compileTask.dependsOn(generateUniffiBindings)
156-
if (!gradle.hasProperty("mozconfig")) {
157-
variant.registerJavaGeneratingTask(generateUniffiBindings, megazordNative.singleFile)
158-
}
159-
}
192+
androidComponents.onVariants(androidComponents.selector().all()) { variant ->
193+
variant.sources.java.addGeneratedSourceDirectory(generateUniffiBindings) { it.outputDir }
160194
}
161195
}

0 commit comments

Comments
 (0)