Skip to content

Commit 445abc6

Browse files
Thom Chiovolonithomcc
Thom Chiovoloni
authored andcommitted
Avoid passing --target to cargo for the default target. Fixes mozilla#10
1 parent 98589fa commit 445abc6

File tree

3 files changed

+75
-7
lines changed

3 files changed

+75
-7
lines changed

README.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,11 @@ Note that if `CARGO_TARGET_DIR` (see https://doc.rust-lang.org/cargo/reference/e
232232
is specified in the environment, it takes precedence over `targetDirectory`, as cargo will output
233233
all build artifacts to it, regardless of what is being built, or where it was invoked.
234234

235+
You may also override `CARGO_TARGET_DIR` variable by setting `rust.cargoTargetDir` in `local.properties`, however it seems very unlikely that this will be useful, as we don't pass this information to cargo itself. That said, it can be used to control where we search for the built library on a per-machine basis.
236+
235237
```groovy
236238
cargo {
237-
// Note: path is relative to the gradle project root.
239+
// Note: path is relative to the gradle project's `projectDir`
238240
targetDirectory = 'path/to/workspace/root/target'
239241
}
240242
```
@@ -331,9 +333,9 @@ rust.targets.library=linux-x86-64
331333
rust.targets=arm,linux-x86-64,darwin
332334
```
333335

334-
## Specifying paths to sub-commands (Python and Cargo)
336+
## Specifying paths to sub-commands (Python, Cargo, and Rustc)
335337

336-
The plugin invokes Python and Cargo. In order of preference, the plugin determines what command to invoke for Python by:
338+
The plugin invokes Python, Cargo and Rustc. In order of preference, the plugin determines what command to invoke for Python by:
337339

338340
1. `rust.pythonCommand` in `${rootDir}/local.properties`
339341
1. the environment variable `RUST_ANDROID_GRADLE_PYTHON_COMMAND`
@@ -345,6 +347,14 @@ In order of preference, the plugin determines what command to invoke for Cargo b
345347
1. the environment variable `RUST_ANDROID_GRADLE_CARGO_COMMAND`
346348
1. the default, `cargo`
347349

350+
In order of preference, the plugin determines what command to invoke for `rustc` by:
351+
352+
1. `rust.rustcCommand` in `${rootDir}/local.properties`
353+
1. the environment variable `RUST_ANDROID_GRADLE_RUSTC_COMMAND`
354+
1. the default, `rustc`
355+
356+
(Note that failure to locate `rustc` is not fatal, however it may result in rebuilding the code more often than is necessary).
357+
348358
Paths must be host operating system specific. For example, on Windows:
349359

350360
```properties

plugin/src/main/kotlin/com/nishtahir/CargoBuildTask.kt

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import org.gradle.api.GradleException
66
import org.gradle.api.Project
77
import org.gradle.api.logging.LogLevel
88
import org.gradle.api.tasks.TaskAction
9+
import java.io.ByteArrayOutputStream
910
import java.io.File
1011

1112
open class CargoBuildTask : DefaultTask() {
1213
var toolchain: Toolchain? = null
1314

15+
1416
@Suppress("unused")
1517
@TaskAction
1618
fun build() = with(project) {
@@ -30,12 +32,24 @@ open class CargoBuildTask : DefaultTask() {
3032
// CARGO_TARGET_DIR can be used to force the use of a global, shared target directory
3133
// across all rust projects on a machine. Use it if it's set, otherwise use the
3234
// configured `targetDirectory` value, and fall back to `${module}/target`.
33-
val targetDirectory = System.getenv("CARGO_TARGET_DIR")
35+
//
36+
// We also allow this to be specified in `local.properties`, not because this is
37+
// something you should ever need to do currently, but we don't want it to ruin anyone's
38+
// day if it turns out we're wrong about that.
39+
val targetDirectory =
40+
getProperty("rust.cargoTargetDir", "CARGO_TARGET_DIR")
3441
?: targetDirectory
3542
?: "${module!!}/target"
3643

44+
val defaultTargetTriple = getDefaultTargetTriple(project, rustcCommand)
45+
46+
val cargoOutputDir = if (toolchain.target == defaultTargetTriple) {
47+
"${targetDirectory}/${profile}"
48+
} else {
49+
"${targetDirectory}/${toolchain.target}/${profile}"
50+
}
3751
copy { spec ->
38-
spec.from(File(project.projectDir, "${targetDirectory}/${toolchain.target}/${profile}"))
52+
spec.from(File(project.projectDir, cargoOutputDir))
3953
spec.into(File(buildDir, "rustJniLibs/${toolchain.folder}"))
4054

4155
// Need to capture the value to dereference smoothly.
@@ -56,6 +70,7 @@ open class CargoBuildTask : DefaultTask() {
5670
inline fun <reified T : BaseExtension> buildProjectForTarget(project: Project, toolchain: Toolchain, cargoExtension: CargoExtension) {
5771
val app = project.extensions[T::class]
5872
val apiLevel = cargoExtension.apiLevel ?: app.defaultConfig.minSdkVersion.apiLevel
73+
val defaultTargetTriple = getDefaultTargetTriple(project, cargoExtension.rustcCommand)
5974

6075
project.exec { spec ->
6176
with(spec) {
@@ -101,8 +116,12 @@ open class CargoBuildTask : DefaultTask() {
101116
// two values.
102117
theCommandLine.add("--${cargoExtension.profile}")
103118
}
104-
105-
theCommandLine.add("--target=${toolchain.target}")
119+
if (toolchain.target != defaultTargetTriple) {
120+
// Only providing --target for the non-default targets means desktop builds
121+
// can share the build cache with `cargo build`/`cargo test`/etc invocations,
122+
// instead of requiring a large amount of redundant work.
123+
theCommandLine.add("--target=${toolchain.target}")
124+
}
106125

107126
// Target-specific environment configuration, passed through to
108127
// the underlying `cargo build` invocation.
@@ -165,3 +184,34 @@ open class CargoBuildTask : DefaultTask() {
165184
}.assertNormalExitValue()
166185
}
167186
}
187+
188+
// This can't be private/internal as it's called from `buildProjectForTarget`.
189+
fun getDefaultTargetTriple(project: Project, rustc: String): String? {
190+
val stdout = ByteArrayOutputStream()
191+
val result = project.exec { spec ->
192+
spec.standardOutput = stdout
193+
spec.commandLine = listOf(rustc, "--version", "--verbose")
194+
}
195+
if (result.exitValue != 0) {
196+
project.logger.warn(
197+
"Failed to get default target triple from rustc (exit code: ${result.exitValue})")
198+
return null
199+
}
200+
val output = stdout.toString()
201+
202+
// The `rustc --version --verbose` output contains a number of lines like `key: value`.
203+
// We're only interested in `host: `, which corresponds to the default target triple.
204+
val triplePrefix = "host: "
205+
206+
val triple = output.split("\n")
207+
.find { it.startsWith(triplePrefix) }
208+
?.let { it.substring(triplePrefix.length).trim() }
209+
210+
if (triple == null) {
211+
project.logger.warn("Failed to parse `rustc -Vv` output! (Please report a rust-android-gradle bug)")
212+
} else {
213+
project.logger.info("Default rust target triple: $triple")
214+
}
215+
return triple
216+
}
217+

plugin/src/main/kotlin/com/nishtahir/CargoExtension.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ open class CargoExtension {
8181
return getProperty("rust.pythonCommand", "RUST_ANDROID_GRADLE_PYTHON_COMMAND") ?: "python"
8282
}
8383

84+
// Required so that we can parse the default triple out of `rustc --version --verbose`. Sadly,
85+
// there seems to be no way to get this information out of cargo directly. Failure to locate
86+
// this isn't fatal, however.
87+
val rustcCommand: String
88+
get() {
89+
return getProperty("rust.rustcCommand", "RUST_ANDROID_GRADLE_RUSTC_COMMAND") ?: "rustc"
90+
}
91+
8492
internal fun getProperty(camelCaseName: String, snakeCaseName: String): String? {
8593
val local: String? = localProperties.getProperty(camelCaseName)
8694
if (local != null) {

0 commit comments

Comments
 (0)