bazelbuild / bazelbuild/intellij

Android NDK Setup: Stumbling Blocks and Bugs (?)

Open
#2,139 3 comments 3 reactions 0 assignees View on GitHub
lang: c++ not stale product: Android Studio type: bug
Dominant language
Java
Stars
820
Forks
342
Avg merge
2d 16h
Merged PRs (30d)
6

Description

Hello Bazel Plugin Folks,

Foremost: Thanks for releasing this plugin!

I've been enjoying getting it set up for an Android Studio project that makes use of C++ and the NDK. The BUILD file support is a real joy, as were the initial setup, project view configuration and completion, and many other things. Thank you for those gems :)

I'm filing an issue to (1) list some difficulties I worked through that might help others and (2) and to list some things that are still broken for me and might be unintended behavior.

- This first thing I ran into was that the plugin (at least in Android Studio) defaults to having cc_library dependencies of an android_library get completions for the host (i.e. desktop) platform.
- I was pretty surprised to see clangd suggestions for macOS APIs and headers pop up in Android Studio!
- For anyone else having this issue (I think https://github.com/bazelbuild/intellij/issues/1388, for example), you can solve it by adding the following to your .bazelproject. These lines [manually configure the cc_libraries to be compiled for the NDK](https://docs.bazel.build/versions/master/android-ndk.html#building-a-cc_library-for-android-without-using-android_binary). Then you'll get Android standard library completions.
- [There's another issue, #1545, that manifested itself first and tipped me off to the fact that it was trying to compile for an Apple platform.]
```
sync_flags:
--cpu=arm64-v8a
--crosstool_top=@androidndk//:default_crosstool
--host_crosstool_top=@bazel_tools//tools/cpp:toolchain
```
- Even though the above fix does work (for me!), it feels like providing desktop completions in Android Studio is perhaps the wrong default. I would have expected the cc_libraries to pick up NDK configuration from the binary rules that depend upon them, just as they do in Bazel proper.
- I'm guessing the plugin behavior is coming from the following:
- It looks like the plugin uses an aspect to find transitive dependencies of the targets listed in .bazelproject.
- And then compile commands are generated for those dependency rules as though they were being compiled independently, ignoring any transitions that might have occurred in, e.g., an android_binary?
- I'd previously written myself some scripts to get clangd completions in VSCode and initially ran into issues exactly like these. I'd started down the aspect route too, but found I needed to use aquery (or action_listeners) to more easily get things right, since they let you just directly listen to the compile action being invoked. Google Kythe takes the action_listener approach, too (see [interface](https://kythe.io/examples/#extracting-compilations-using-bazel) and [implementation]( https://github.com/kythe/kythe/tree/master/kythe/extractors)). My experience was that aquery solved issues like this pretty well. They also seemed to give flexibility around genrules, etc.
- Separately, I'm not seeing any code completions in the header files of header-only cc_libraries, e.g., templated classes. Is that known/intentional?
- There's (only) one warning listed in the "Bazel Problems" pane and it might be related? It goes:
`Warning: Issues collecting info from C++ compiler (click to see logs)`
The logs then show the plugin trying to compile the empty path, many times over. My shot in the dark is that it might be trying to compile an empty list of files for a header-only cc_library. Here's one as an example--seems like it happens to use Eigen.
```
Compiler exited with error code 1: /T/blaze_compiler.sh -xc++ -gcc-toolchain external/androidndk/ndk/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64 -target aarch64-none-linux-android -fpic -isystem /external/androidndk/ndk/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=29 -no-canonical-prefixes -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -funwind-tables -fstack-protector-strong -fno-addrsig "" -fvisibility=hidden -std=c++17 --sysroot=/external/androidndk/ndk/platforms/android-29/arch-arm64 -isystem /external/androidndk/ndk/sources/cxx-stl/llvm-libc++/include -isystem /external/androidndk/ndk/sources/cxx-stl/llvm-libc++abi/include -isystem /external/androidndk/ndk/sources/android/support/include -isystem /external/androidndk/ndk/sysroot/usr/include -DEIGEN_MPL2_ONLY -DEIGEN_MAX_ALIGN_BYTES=64 -DEIGEN_HAS_TYPE_TRAITS=0 -iquote/. -iquote/bazel-out/arm64-v8a-fastbuild/bin -iquote/external/eigen -I/external/eigen -fpch-preprocess -v -dD -E
Android (6454773 based on r365631c2) clang version 9.0.8 (https://android.googlesource.com/toolchain/llvm-project 98c855489587874b2a325e7a516b99d838599c6f) (based on LLVM 9.0.8svn)
Target: aarch64-none-linux-android
Thread model: posix
InstalledDir: /external/androidndk/ndk/toolchains/llvm/prebuilt/darwin-x86_64/bin
Found candidate GCC installation: /external/androidndk/ndk/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/lib/gcc/aarch64-linux-android/4.9.x
Selected GCC installation: external/androidndk/ndk/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/lib/gcc/aarch64-linux-android/4.9.x
Candidate multilib: .;@m64
Selected multilib: .;@m64
clang: error: no such file or directory: '""'
```
- Seems like something's going wrong in how the plugin provides the headers of c++ deps for inclusion. Headers from the same rule are found fine, but almost all the headers I'm including from a dep are underlined in red. Hovering gives "file not found", but immediately below, the non-code completion part of Android Studio lists the file just fine, and you can jump to it with a click. Am I missing something? I know things are configured right in Bazel, since everything compiles fine. And there's nothing non-standard about the path, since Android Studio is picking it up to jump into the source.
- It looks like one has to manually update the android_sdk_platform in the .bazelproject every time the Android SDK updates? Otherwise the project breaks--is that right? If so, any chance there could be an option (I'd argue maybe as the default) to just pick up the latest installed Android SDK? Bazel's android_sdk_repository defaults to the latest, so maybe the SDK version should just be picked up from the bazel workspace?

Thanks for considering my feedback,
Chris

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the Android NDK cases using the reported .bazelproject settings, android_library/cc_library targets, and header-only dependencies. Inspect the aspect-based dependency collection and generated compile commands, then compare the reported platform, header, and Android SDK behavior with Bazel's android_binary transitions. Done should mean the reported NDK completions, headers, and SDK selection work without manual workarounds.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, cpp
Domain
build-system, devtools, mobile-dev
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.