Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AnkiDroid unit test suite currently not working on arm64 JDKs on macOS #164

Closed
mikehardy opened this issue Mar 16, 2022 · 4 comments · Fixed by ankidroid/Anki-Android#10625 or #246
Assignees

Comments

@mikehardy
Copy link
Member

mikehardy commented Mar 16, 2022

[UPDATE: until solved, we publish rsdroid-arm64.dylib on each release in the list of the artifacts and you can point the robolectric tests to it for use on M1 machines]


Symptom:

    java.lang.UnsatisfiedLinkError: /private/var/folders/5b/1q9_lqrs79ng7n9hjm_xl4cm0000gn/T/librsdroid2032698931526253765.dylib: dlopen(/private/var/folders/5b/1q9_lqrs79ng7n9hjm_xl4cm0000gn/T/librsdroid2032698931526253765.dylib, 0x0001): tried: '/private/var/folders/5b/1q9_lqrs79ng7n9hjm_xl4cm0000gn/T/librsdroid2032698931526253765.dylib' (mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64e')), '/usr/lib/librsdroid2032698931526253765.dylib' (no such file)

@viciousAegis This is a bug on our side. We do not build io.github.david-allison-1:anki-android-backend-testing for M1 Macs.

I have an M1 Mac arriving sometime late March, so I'll be personally invested in testing

As a workaround:

  • Remove @RunWith(AndroidJUnit4::class)
  • Remove :RobolectricTest()
  • This will only work because the test does not depend on the Anki Database

As a workaround, please enable GitHub actions on your GitHub clone of Anki-Android and test there

Properly fixing this

Issue

  • We have a library written in rust: librsdroid. This is compiled for Android
  • Robolectric doesn't run Android, it runs tests via the JVM on your PC
  • Therefore, librsdroid needs to be compiled for native platforms
  • We have a separate library: anki-android-backend-testing which contains the dlls and dylibs needed
  • When this was written, M1 macs didn't exist

Please see: https://github.com/ankidroid/Anki-Android-Backend/tree/main/rsdroid-testing

  • First of all, this isn't well documented. Please submit a PR with better documentation if you want
  • Most of the work is performed via GitHub actions
  • Feel free to submit a pull request to the GitHub actions get this working.
    • Compile the dylib for arm64e (I have no idea how to do this, but it should be possible)
      • The code should be:
        processResources.dependsOn preBuildWindows
        processResources.dependsOn copyWindowsOutput
        // To fix: "toolchain 'nightly-x86_64-unknown-linux-gnu' is not installed"
        // execute in bash: rustup toolchain install nightly-x86_64-unknown-linux-gnu
        // "linker `x86_64-unknown-linux-gnu-gcc` not found"
        // sudo ln -s /usr/bin/cc /usr/local/bin/x86_64-unknown-linux-gnu-gcc
        // rustup target add x86_64-pc-windows-gnu --toolchain nightly
        // brew install mingw-w64 && x86_64-w64-mingw32-gcc -v
        processResources.dependsOn preBuildLinux
        processResources.dependsOn copyLinuxOutput
        if (org.gradle.internal.os.OperatingSystem.current().isMacOsX()) {
        // due to restrictions on downloading the MacOS SDK, we can only build for MacOS on MacOS
        // > Install a reasonable number of copies of the Apple Software on Apple-branded computers
        // https://www.apple.com/legal/sla/docs/xcode.pdf
        processResources.dependsOn preBuildMac
        processResources.dependsOn copyMacOutput
        }
    • Include two dylibs in the jar
    • Fix this code to select the correct dylib based on your architecture:

Originally posted by @david-allison in ankidroid/Anki-Android#10389 (comment)

@mikehardy mikehardy transferred this issue from ankidroid/Anki-Android Mar 16, 2022
@mikehardy mikehardy changed the title Unit test suite currently not working on arm64 JDKs on macOS AnkiDroid unit test suite currently not working on arm64 JDKs on macOS Mar 16, 2022
@david-allison
Copy link
Member

Also:

We should be able to cross-compile Rust for arm64e. This /should/ be doable by adding aarch64-apple-darwin in:

case Platform.LINUX: return toWindowsCommandLine("CC=\$ANKIDROID_LINUX_CC ${mainArg} --target x86_64-unknown-linux-gnu")
case Platform.MACOS:
/// x86_64-apple-darwin14-cc
return toWindowsCommandLine("CC=\$ANKIDROID_MACOS_CC ${mainArg} --target x86_64-apple-darwin")
case Platform.WINDOWS: return toWindowsCommandLine("${mainArg} --target x86_64-pc-windows-gnu")
}

and installing the target platform: https://github.com/ankidroid/Anki-Android-Backend/blob/9302b3f89e09643e95c42166743f8563a3822ddc/.github/scripts/install_rust_robolectric_targets.sh

And then:

Note that aarch64-apple-darwin is a Tier 2 target in Rust.

ankidroid/Anki-Android#10389 (comment)

@david-allison david-allison self-assigned this Mar 25, 2022
@david-allison
Copy link
Member

david-allison commented Mar 25, 2022

Got this working.

But: cross doesn't support aarch64-apple-darwin yet: cross-rs/cross#508, so we won't be able to build a dylib in CI.

I'm open to suggestions, but for now, I'll build a dylib for arm64 and will include it in the releases folder, along with a PR in Anki-Android to get an override working via environment variable

Before this PR: replace

https://github.com/ankidroid/Anki-Android/blob/f0aa92f54dec9475fe23e18c980fb3fe735bcff1/AnkiDroid/src/test/java/com/ichi2/anki/RobolectricTest.kt#L92

with a call to load the dylib

RustBackendLoader.loadRsdroid("/Users/davidallison/StudioProjects/Anki-Android-Backend/rslib-bridge/target/aarch64-apple-darwin/release/librsdroid.dylib")

EDIT: Added to https://github.com/ankidroid/Anki-Android-Backend/releases/tag/0.1.10

@mikehardy
Copy link
Member Author

mikehardy commented Mar 25, 2022

osxcross supports arm64e now, so this triple (aarch64-apple-darwin) is probably supportable
Here's how someone in a related project did it: multiarch/crossbuild#51 (comment)

This is the PR for x86_64-apple-darwin support to cross-r/cross: cross-rs/cross#480
I imagine something based on that would build a Docker image that could then be used with cross-rs/cross via an image tag for the triple

david-allison added a commit to david-allison/Anki-Android that referenced this issue Mar 25, 2022
anki-android-backend-testing contains pre-compiled Rust code so
Robolectric can load it and run natively.

We can't currently include an Apple Silicon (AS) dylib inside
anki-android-backend-testing (`cross` doesn't compile AS code yet)

But, we can compile an AS dylib on an AS Mac and reference it.

So we include the dylib in the releases folder of Anki-Android-Backend
and add functionality to specify an environment variable to load this
dylib from disk, instead of from the .jar

Instructions (for 0.1.10):

Download librsdroid-arm64.dylib from https://github.com/ankidroid/Anki-Android-Backend/releases/tag/0.1.10

And add the following environment variables:
one to the path and one for the version

```
export ANKIDROID_BACKEND_PATH="/Users/davidallison/StudioProjects/Anki-Android-Backend/rslib-bridge/target/aarch64-apple-darwin/release/librsdroid-arm64.dylib"
export ANKIDROID_BACKEND_VERSION="0.1.10"
```

Library generated from:
```
davidallison@Davids-MBP rslib-bridge % pwd
/Users/davidallison/StudioProjects/Anki-Android-Backend/rslib-bridge
cross build --release --features no-android --verbose --target aarch64-apple
```
on an AS MacBook

Fixes ankidroid/Anki-Android-Backend#164
david-allison added a commit to david-allison/Anki-Android that referenced this issue Mar 25, 2022
anki-android-backend-testing contains pre-compiled Rust code so
Robolectric can load it and run natively.

We can't currently include an Apple Silicon (AS) dylib inside
anki-android-backend-testing (`cross` doesn't compile AS code yet)

But, we can compile an AS dylib on an AS Mac and reference it.

So we include the dylib in the releases folder of Anki-Android-Backend
and add functionality to specify an environment variable to load this
dylib from disk, instead of from the .jar

Instructions (for 0.1.10):

Download librsdroid-arm64.dylib from https://github.com/ankidroid/Anki-Android-Backend/releases/tag/0.1.10

And add the following environment variables:
one to the path and one for the version

```
export ANKIDROID_BACKEND_PATH="/Users/davidallison/StudioProjects/Anki-Android-Backend/rslib-bridge/target/aarch64-apple-darwin/release/librsdroid-arm64.dylib"
export ANKIDROID_BACKEND_VERSION="0.1.10"
```

Library generated from:
```
davidallison@Davids-MBP rslib-bridge % pwd
/Users/davidallison/StudioProjects/Anki-Android-Backend/rslib-bridge
cross build --release --features no-android --verbose --target aarch64-apple
```
on an AS MacBook

Fixes ankidroid/Anki-Android-Backend#164
david-allison added a commit to david-allison/Anki-Android that referenced this issue Mar 25, 2022
anki-android-backend-testing contains pre-compiled Rust code so
Robolectric can load it and run natively.

We can't currently include an Apple Silicon (AS) dylib inside
anki-android-backend-testing (`cross` doesn't compile AS code yet)

But, we can compile an AS dylib on an AS Mac and reference it.

So we include the dylib in the releases folder of Anki-Android-Backend
and add functionality to specify an environment variable to load this
dylib from disk, instead of from the .jar

Instructions (for 0.1.10):

Download librsdroid-arm64.dylib from https://github.com/ankidroid/Anki-Android-Backend/releases/tag/0.1.10

And add the following environment variables:
one to the path and one for the version

```
export ANKIDROID_BACKEND_PATH="/Users/davidallison/StudioProjects/Anki-Android-Backend/rslib-bridge/target/aarch64-apple-darwin/release/librsdroid-arm64.dylib"
export ANKIDROID_BACKEND_VERSION="0.1.10"
```

Library generated from:
```
davidallison@Davids-MBP rslib-bridge % pwd
/Users/davidallison/StudioProjects/Anki-Android-Backend/rslib-bridge
rustup install 1.54.0
rustup default 1.54.0
cross build --release --features no-android --verbose --target aarch64-apple
```
on an AS MacBook

Fixes ankidroid/Anki-Android-Backend#164
mikehardy pushed a commit to ankidroid/Anki-Android that referenced this issue Mar 25, 2022
anki-android-backend-testing contains pre-compiled Rust code so
Robolectric can load it and run natively.

We can't currently include an Apple Silicon (AS) dylib inside
anki-android-backend-testing (`cross` doesn't compile AS code yet)

But, we can compile an AS dylib on an AS Mac and reference it.

So we include the dylib in the releases folder of Anki-Android-Backend
and add functionality to specify an environment variable to load this
dylib from disk, instead of from the .jar

Instructions (for 0.1.10):

Download librsdroid-arm64.dylib from https://github.com/ankidroid/Anki-Android-Backend/releases/tag/0.1.10

And add the following environment variables:
one to the path and one for the version

```
export ANKIDROID_BACKEND_PATH="/Users/davidallison/StudioProjects/Anki-Android-Backend/rslib-bridge/target/aarch64-apple-darwin/release/librsdroid-arm64.dylib"
export ANKIDROID_BACKEND_VERSION="0.1.10"
```

Library generated from:
```
davidallison@Davids-MBP rslib-bridge % pwd
/Users/davidallison/StudioProjects/Anki-Android-Backend/rslib-bridge
rustup install 1.54.0
rustup default 1.54.0
cross build --release --features no-android --verbose --target aarch64-apple
```
on an AS MacBook

Fixes ankidroid/Anki-Android-Backend#164
@mikehardy
Copy link
Member Author

mikehardy commented Jun 27, 2022

I want to leave this open for a bit. I just generated the 0.1.11 and 0.1.14-anki2.1.54 artifacts and here was how I did it:

git co 0.1.11 # or your branch name here
git submodule update --recursive
./tools/doctor.sh  # this sets the correct rust version etc, installs targets or should etc
rustup target add aarch64-apple-darwin
cd rslib-bridge
cross build --release --features no-android --verbose --target aarch64-apple-darwin
open target/aarch64-apple-darwin/release/  # now you have a finder window open with rsdroid.dylib there

Open up the tag here on the releases page https://github.com/ankidroid/Anki-Android-Backend/releases
Edit the release
Drop rsdroid.dylib on there and rename it to rsdroid-arm64.dylib

How exactly to integrate it after merging #202 is up in the air - I have not tested - but this should be updated once tested

@mikehardy mikehardy reopened this Jun 27, 2022
dae added a commit to ankitects/Anki-Android-Backend that referenced this issue Nov 29, 2022
The 2.1.55 desktop release switched away from Bazel to a new build system,
which required some changes to this repo. Making the changes was a bit complicated
due to the complexity of the current build system, and I ended up shaving some yaks
to make things simpler while I was working on the changes.

Changes:

- Building for the current architecture instead of all architectures is now the
default, so getting started is easier, and a build in Android Studio no longer
requires special flags.
- The build-current.sh script has been split into build-aar and build-robo
for the Android and Robolectric parts, and can be used for both single-arch
and multi-arch builds.
- On arm64 Macs, the build scripts now create arm binaries
- In a multi-arch build, both x86 and arm64 Mac libs are built, and they're
merged into a single library. This can be done in CI, so there is no manual step
required for M1 machines anymore.
- The build now uses protobuf and python binaries/libs that the desktop build
downloads, so they don't need to be installed separately.
- The pinned Rust version and Rust targets are automatically installed as
required.
- The per-platform CI builds now build in debug mode and are faster.
- Updated the docs to explain how the NDK can be installed via Android Studio,
instead of via separate command-line tools.
- The cross/docker stuff has been stripped out, as it's of limited use as it
can't target macOS legally. Easier to use GH actions for the multi-arch
builds, and keep things simple for local development.
- Fix lint not being run in CI; caught an API 23 reference.

Bumps ankidroid#179 (builds on M1 already work, so this may be simpler than expected?)
Bumps ankidroid#174 (a bunch of the doctor stuff is obsolete; updated HOWTO.md and GH actions should be consulted)
Bumps ankidroid#27 (I recommend closing this; single-platform is the default for local builds, and
CI runners don't have any extra compute available)

Tentatively closes ankidroid#109 (didn't see the flake when I was updating the actions)

Closes ankidroid#235 (translation submodules now automatically synced with anki submodule)
Closes ankidroid#213 (path based on script now)
Closes ankidroid#211 (builds for Arm Mac on Arm Macs)
Closes ankidroid#197 (single arch is the default)
Closes ankidroid#196 (desktop venv is used)
Closes ankidroid#195 (can be done via the GUI, and does not require separate cli download)
Closes ankidroid#168 (latest Rust; easier changing via rust-toolchain.toml)
Closes ankidroid#164 (universal dylib)
Closes ankidroid#127 (no docker)
Closes ankidroid#106 (most of those scripts obsolete; some commands moved into build scripts)
Closes ankidroid#99 (no docker)
Closes ankidroid#98 (no docker)
Closes ankidroid#97 (submodule automatically updated)
Closes ankidroid#96 (build will fail if commit unavailable)
Closes ankidroid#53 (no docker)
Closes ankidroid#40 (DEBUG=1 option documented)
Closes ankidroid#9 (simpler OOTB experience, and updated docs)
dae added a commit to ankitects/Anki-Android-Backend that referenced this issue Nov 29, 2022
The 2.1.55 desktop release switched away from Bazel to a new build system,
which required some changes to this repo. Making the changes was a bit complicated
due to the complexity of the current build system, and I ended up shaving some yaks
to make things simpler while I was working on the changes.

Changes:

- Building for the current architecture instead of all architectures is now the
default, so getting started is easier, and a build in Android Studio no longer
requires special flags.
- The build-current.sh script has been split into build-aar and build-robo
for the Android and Robolectric parts, and can be used for both single-arch
and multi-arch builds.
- On arm64 Macs, the build scripts now create arm binaries
- In a multi-arch build, both x86 and arm64 Mac libs are built, and they're
merged into a single library. This can be done in CI, so there is no manual step
required for M1 machines anymore.
- The build now uses protobuf and python binaries/libs that the desktop build
downloads, so they don't need to be installed separately.
- The pinned Rust version and Rust targets are automatically installed as
required.
- The per-platform CI builds now build in debug mode and are faster.
- Updated the docs to explain how the NDK can be installed via Android Studio,
instead of via separate command-line tools.
- The cross/docker stuff has been stripped out, as it's of limited use as it
can't target macOS legally. Easier to use GH actions for the multi-arch
builds, and keep things simple for local development.
- Fix lint not being run in CI; caught an API 23 reference.

Bumps ankidroid#179 (builds on M1 already work, so this may be simpler than expected?)
Bumps ankidroid#174 (a bunch of the doctor stuff is obsolete; updated HOWTO.md and GH actions should be consulted)
Bumps ankidroid#27 (I recommend closing this; single-platform is the default for local builds, and
CI runners don't have any extra compute available)

Tentatively closes ankidroid#109 (didn't see the flake when I was updating the actions)

Closes ankidroid#235 (translation submodules now automatically synced with anki submodule)
Closes ankidroid#213 (path based on script now)
Closes ankidroid#211 (builds for Arm Mac on Arm Macs)
Closes ankidroid#197 (single arch is the default)
Closes ankidroid#196 (desktop venv is used)
Closes ankidroid#195 (can be done via the GUI, and does not require separate cli download)
Closes ankidroid#168 (latest Rust; easier changing via rust-toolchain.toml)
Closes ankidroid#164 (universal dylib)
Closes ankidroid#127 (no docker)
Closes ankidroid#106 (most of those scripts obsolete; some commands moved into build scripts)
Closes ankidroid#99 (no docker)
Closes ankidroid#98 (no docker)
Closes ankidroid#97 (submodule automatically updated)
Closes ankidroid#96 (build will fail if commit unavailable)
Closes ankidroid#53 (no docker)
Closes ankidroid#40 (DEBUG=1 option documented)
Closes ankidroid#9 (simpler OOTB experience, and updated docs)
dae added a commit to ankitects/Anki-Android-Backend that referenced this issue Nov 29, 2022
The 2.1.55 desktop release switched away from Bazel to a new build system,
which required some changes to this repo. Making the changes was a bit complicated
due to the complexity of the current build system, and I ended up shaving some yaks
to make things simpler while I was working on the changes.

Changes:

- Building for the current architecture instead of all architectures is now the
default, so getting started is easier, and a build in Android Studio no longer
requires special flags.
- The build-current.sh script has been split into build-aar and build-robo
for the Android and Robolectric parts, and can be used for both single-arch
and multi-arch builds.
- On arm64 Macs, the build scripts now create arm binaries
- In a multi-arch build, both x86 and arm64 Mac libs are built, and they're
merged into a single library. This can be done in CI, so there is no manual step
required for M1 machines anymore.
- The build now uses protobuf and python binaries/libs that the desktop build
downloads, so they don't need to be installed separately.
- The pinned Rust version and Rust targets are automatically installed as
required.
- The per-platform CI builds now build in debug mode and are faster.
- Updated the docs to explain how the NDK can be installed via Android Studio,
instead of via separate command-line tools.
- The cross/docker stuff has been stripped out, as it's of limited use as it
can't target macOS legally. Easier to use GH actions for the multi-arch
builds, and keep things simple for local development.
- Fix lint not being run in CI; caught an API 23 reference.

Bumps ankidroid#179 (builds on M1 already work, so this may be simpler than expected?)
Bumps ankidroid#174 (a bunch of the doctor stuff is obsolete; updated HOWTO.md and GH actions should be consulted)
Bumps ankidroid#27 (I recommend closing this; single-platform is the default for local builds, and
CI runners don't have any extra compute available)

Tentatively closes ankidroid#109 (didn't see the flake when I was updating the actions)

Closes ankidroid#235 (translation submodules now automatically synced with anki submodule)
Closes ankidroid#213 (path based on script now)
Closes ankidroid#211 (builds for Arm Mac on Arm Macs)
Closes ankidroid#197 (single arch is the default)
Closes ankidroid#196 (desktop venv is used)
Closes ankidroid#195 (can be done via the GUI, and does not require separate cli download)
Closes ankidroid#168 (latest Rust; easier changing via rust-toolchain.toml)
Closes ankidroid#164 (universal dylib)
Closes ankidroid#127 (no docker)
Closes ankidroid#106 (most of those scripts obsolete; some commands moved into build scripts)
Closes ankidroid#99 (no docker)
Closes ankidroid#98 (no docker)
Closes ankidroid#97 (submodule automatically updated)
Closes ankidroid#96 (build will fail if commit unavailable)
Closes ankidroid#53 (no docker)
Closes ankidroid#40 (DEBUG=1 option documented)
Closes ankidroid#9 (simpler OOTB experience, and updated docs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants