MarkaRagnos0815
MarkaRagnos0815

Reputation: 211

how to build cc_test for android using bazel

I am trying to use bazel as build system. My project looks like this:

bazel build //unit:unit --crosstool_top=@androidndk//:default_crosstool --cpu=armeabi-v7a

INFO: Invocation ID: b7c88128-3448-4eb7-bf25-ce8269895956 ERROR: ../yg32wcuz/external/androidndk/BUILD.bazel:39:1: in cc_toolchain_suite rule @androidndk//:toolchain-gnu-libstdcpp: cc_toolchain_suite '@androidndk//:toolchain-gnu-libstdcpp' does not contain a toolchain for cpu 'x64_windows' ERROR: Analysis of target '//unit:unit' failed; build aborted: Analysis of target '@androidndk//:toolchain-gnu-libstdcpp' failed; build aborted

It looks like that bazel seems to have problem with cc_test and android toolchain

Is there any way to build and run an executable for android using bazel? Maybe I missed some command line arguments

Edit:

tried the solution below and added a sh_test rule but it fails again using @androidsdk//:adb and leads to the following error

ERROR: missing input file '@androidsdk//:platform-tools/adb' 
ERROR: unit/BUILD:61:1: //unit:unit_android: missing input file '@androidsdk//:platform-tools/adb' Target //unit:unit_android failed to build 
ERROR: unit/BUILD:61:1 1 input file(s) do not exist

I also need to use $ANDROID_HOME/platform-tools/adb to get the adb binary. external/androidsdk/platform-tools/adb does not work. my BUILD file is in a sub folder of the workspace, maybe this is the issue.

removing @androidsdk//:adb fixes this error. there are some adjustments needed in sh_test rule like:

sh_test(
    name = "unit_android",
    srcs = ["unit_android.sh"],
    data = [
        ":unit",
        #"@androidsdk//:adb",
    ],
    deps = [
        "@bazel_tools//tools/bash/runfiles", # to access the manifest
    ],
)

using runfiles dependency allows me to access the binary via $(rlocation ..) in shell script. but now there seems to be another issue:

when using 'bazel run': It looks like that bazel is trying to upload the file to msys shell (i am using windows) and not to the device:

adb: error: failed to copy '.../_bazel_exb_a/yg32wcuz/execroot/test/bazel-out/armeabi-v7a-fastbuild/bin/unit/unit' to 'C:/Development/msys2/data/local/tmp/unit'

when using 'bazel test': it just states an error and the content of test log is

unknown parameter - /users

Edit 2: WORKSPACE file about android sdk/ndk

android_ndk_repository(
    name = "androidndk", # Required. Name *must* be "androidndk".
    api_level = 26
)

android_sdk_repository(
    name = "androidsdk", # Required. Name *must* be "androidsdk".
    api_level = 26
)

In both case I assume env var ANDROID_NDK_HOME (points to ndk), ANDROID_SDK_HOME (points to sdk) and ANDROID_HOME (points to sdk) are set. I also checked the external dir, sdk is in there. Removing "@androidsdk//:adb" seem to work but the bazel shell environment now tries to add a prefix before "/data/local/tmp" and tries to upload to a non existing folder. forget about the issue with "/users" (windows path issue ...)

Upvotes: 0

Views: 1745

Answers (1)

ahumesky
ahumesky

Reputation: 5016

--crosstool_top by itself sets both the target and host crosstool, so you may just need to set --host_crosstool_top back to the default: --host_crosstool_top=@bazel_tools//tools/cpp:toolchain

Edit:

Running the test on a device is unfortunately not supported out of the box by bazel test. There needs to be some test runner that knows how to put the test on the device, run it, and collect the results. A very simple version of that might look like:

test.cc:

int main(int argc, char** argv) {
  // Test always passes.
  // Return non-zero for test failure.
  return 0;
}

example_android_cc_test.sh:

adb=external/androidsdk/platform-tools/adb

# The test requires a running emulator or connected device.
# The name of the cc_test binary can be passed in using the
# args attribute of sh_test to make this script generic.
$adb push example_test /data/local/tmp

# adb shell returns the exit code of the command
# that was executed, and the exit code of the
# test shell script determines if the sh_test target
# passes or fails.
$adb shell "/data/local/tmp/example_test"

BUILD:

cc_test(
  name = "example_test",
  srcs = ["test.cc"],
  linkopts = ["-pie"],
  linkstatic = 1,
)

sh_test(
  name = "example_android_cc_test",
  srcs = ["example_android_cc_test.sh"],
  data = [
      ":example_test",
      "@androidsdk//:adb",
  ],
)

Note that this approach is not hermetic because it relies on an emulator to already be running, or a device to be already connected. It's possible to start an emulator as part of the test, but that's more involved.

Upvotes: 1

Related Questions