bazelbuild / bazelbuild/intellij
Android NDK Setup: Stumbling Blocks and Bugs (?)
- 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
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