Skip to content

Windows: the project cannot be built or tested — both mandatory PR verification steps fail #104

Description

@yangyws

Impact

On Windows, the project cannot be built or tested at all. Two independent
task failures block it:

  • ./gradlew test — fails. CONTRIBUTING Step 3 makes this a strict requirement
    for Pull Request approval
    .
  • Any APK build (assembleDebug, installDebug, bundleRelease, …) — fails,
    because :mirrorserver:dex is wired into merge*Assets and package*.

So a Windows contributor currently cannot satisfy the mandatory verification
steps in CONTRIBUTING, and cannot produce a build to test on hardware. I'm
flagging this ahead of my localization proposal (#103) because it affects
everyone, not just me.

There is no CI in the repository (.github/ holds only FUNDING.yml and
copilot-instructions.md), so nothing surfaces this automatically — it is
invisible unless someone actually develops on Windows.


Blocker 1 — :mirrorserver:dex looks for d8, Windows ships d8.bat

mirrorserver/build.gradle.kts:

val d8 = newest.resolve("d8")
check(d8.exists()) { "d8 not found at $d8" }

Android SDK build-tools on Windows contains d8.bat only; there is no
extensionless d8. The build fails with:

Execution failed for task ':mirrorserver:dex'.
> d8 not found at C:\Users\<user>\AppData\Local\Android\Sdk\build-tools\36.0.0\d8

The comment a few lines below ("the d8 shell wrapper (macOS)") suggests macOS
was considered here but Windows wasn't.

Suggested fix

val isWindows = System.getProperty("os.name").lowercase().contains("win")
val d8Name = if (isWindows) "d8.bat" else "d8"
val d8 = newest.resolve(d8Name)
check(d8.exists()) { "d8 not found at $d8" }

I've been running this on my own branch for a while and it works. Happy to open
a PR.

Related nit, same block

val newest = buildToolsDir.listFiles()?.filter { it.isDirectory }?.maxByOrNull { it.name }

maxByOrNull { it.name } compares directory names as strings, so a future
single-digit major version would sort above a two-digit one ("9.0.0" >
"36.0.0"). Not currently reachable, but comparing parsed version components
would be safer. Say the word and I'll include it in the same PR, or leave it
out to keep the fix minimal.


Blocker 2 — :app:nativeCTest cannot start on Windows

app/build.gradle.kts:

val nativeCTest = tasks.register<Exec>("nativeCTest") {
    commandLine("./run_native_tests.sh")
}
//
tasks.matching { it.name.contains("UnitTest") || it.name == "test" }.configureEach {
    dependsOn(nativeCTest)
}
Execution failed for task ':app:nativeCTest'.
> A problem occurred starting process 'command './run_native_tests.sh''

Windows cannot exec a .sh file as a process directly. Even under Git Bash the
script additionally requires clang, which is not part of a standard Android
Studio install on Windows.

Because nativeCTest is a dependency of every test / *UnitTest task, fixing
Blocker 1 alone does not make ./gradlew test runnable — both need addressing.

Possible directions

I don't want to presume the design here, so a few options rather than a patch:

  1. Skip the task when no POSIX shell or clang is available
    (onlyIf { … }), so the JVM/Robolectric suites still run and native
    coverage stays a Linux/macOS concern.
  2. Invoke the script through an explicit shell and gate it on clang being
    resolvable.
  3. Keep it mandatory, but document in CONTRIBUTING that Windows contributors
    must run verification under WSL.

Option 3 is legitimate — but it should be stated, because right now CONTRIBUTING
requires a step that silently cannot succeed on Windows.


Reproduction

Windows 11, JDK 21, Android SDK build-tools 36.0.0, Gradle 9.3.1 (wrapper),
clean checkout of main at 92e1081 with only sdk.dir set in
local.properties:

./gradlew test
  -> :app:nativeCTest FAILED           (Blocker 2)
./gradlew test -x :app:nativeCTest
  -> :mirrorserver:dex FAILED          (Blocker 1)
./gradlew test -x :app:nativeCTest -x :mirrorserver:dex
  -> runs; :core 170 passed, :gamefocus 24 passed, :domain 293 tests

For reference, the remaining :domain failures in that last run are 23
Robolectric cases (InstalledAppsManagerTest, RomManagerTest,
IpcParsersTest) failing with UnsatisfiedLinkError: no conscrypt_jni in java.library.path. That looks like a separate local-environment matter and I
have not investigated it further — mentioning it only so the numbers above are
not mistaken for a clean run.


I'm glad to send a PR for Blocker 1 immediately, and to follow your preferred
direction on Blocker 2.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions