Android NDK with Google Test
Just to add to Alex's excellent answer, you can also deploy and run the resulting test binary using adb
by adding the following to your CMakeLists.txt
:
find_program(ADB adb)
add_custom_command(TARGET footest POST_BUILD
COMMAND ${ADB} shell mkdir -p /data/local/tmp/${ANDROID_ABI}
COMMAND ${ADB} push $<TARGET_FILE:native-lib> /data/local/tmp/${ANDROID_ABI}/
COMMAND ${ADB} push $<TARGET_FILE:footest> /data/local/tmp/${ANDROID_ABI}/
COMMAND ${ADB} shell \"export LD_LIBRARY_PATH=/data/local/tmp/${ANDROID_ABI}\; /data/local/tmp/${ANDROID_ABI}/footest\")
Note that in the above example footest
is dependent on the shared library native-lib
which is why we push that. The path to native-lib
is specified by setting the LD_LIBRARY_PATH
environment variable.
If you choose cmake to drive your externalNativeBuild (and this is the preferred option, according to Android Developers NDK guide), then you can simply add the following lines to your CMakeLists.txt:
set(GOOGLETEST_ROOT ${ANDROID_NDK}/sources/third_party/googletest/googletest)
add_library(gtest STATIC ${GOOGLETEST_ROOT}/src/gtest_main.cc ${GOOGLETEST_ROOT}/src/gtest-all.cc)
target_include_directories(gtest PRIVATE ${GOOGLETEST_ROOT})
target_include_directories(gtest PUBLIC ${GOOGLETEST_ROOT}/include)
add_executable(footest src/main/jni/foo_unittest.cc)
target_link_libraries(footest gtest)
If your build succeeds, you will find app/.externalNativeBuild/cmake/debug/x86/footest
. From here, you can follow the instructions in README.NDK to run it on emulator or device.
Notes:
- make sure that the ABI matches the target you use (the guide is not very clear about this).
- the list of ABI's that are built is controlled by abiFilters in build.gradle. In Android Studio, even ndk-build ignores APP_ABI set in Application.mk.
- the files Android.mk and Application.mk are ignored when you use cmake.
for gradle-3.3, and
classpath 'com.android.tools.build:gradle:2.3.3'
, as in the current Android Studio release 2.3.3, you may need to explicitly specify the unittest target in build.gradle:android { defaultConfig { externalNativeBuild { cmake { targets "foo_unittest" }}}}
with Android Studio 3.0, gradle-4.1, and
classpath 'com.android.tools.build:gradle:3.0.0-beta6'
the executable is easier to find underapp/build/intermediates/cmake/debug/obj
.
To test the foo(int x, int y) function from foo.cpp in a shared library (to make is as close as possible to the NDK instructions), you need some more lines in your CMakeLists.txt script:
# build libfoo.so
add_library(foo SHARED src/main/jni/foo.cpp)
target_link_libraries(footest foo)
You will find libfoo.so to copy manually to your device under app/build/intermediates/cmake/debug/obj
.
To reduce the hassle, you can use STATIC
instead of SHARED
, or simply add foo.cpp to footest executable:
add_executable(footest src/main/jni/foo_unittest.cc src/main/jni/foo.cpp)