Short version: I have constructed a gradle NDK project where the main project uses ndkBuild and a subproject uses CMake. I want the CMake project to produce a library the ndkBuild project links, but the dependency to the CMake project is not being applied, the library is not found by the main project, and I do not know how to specify to the main project the filename it’s supposed to be extracting from the CMake project.
Context: I have an existing video game which I am porting to the Oculus Mobile SDK 1.16.0
https://developer.oculus.com/downloads/package/oculus-mobile-sdk/ . This SDK contains libraries and sample code, both of which are built using Gradle and ndkBuild. The SDK’s ndkBuild scripts for the sample projects are pretty complicated and I do not know enough about how Oculus works to port them to CMake myself. Meanwhile the project I am porting is based on CMake and would be *very* difficult or impossible to port to ndkBuild, since it includes CMake builds of very complex projects such as Assimp and LuaJIT. For this reason, it is necessary I use both CMake and ndkBuild in this single project.
Currently my project is based on the VrCubeWorld_Framework example from the Oculus Mobile SDK. Its dependencies {} section depends on five projects, four Oculus libraries (:VrAppFramework:Projects:Android, etc) and one mine (“implementation project(':cmakelib’)”). :cmakelib is a project at the top of my repository. Its build.gradle is simple (attached). It includes a CMakeLists.exe which builds a library named “lovr”, created with CMake add_library(lovr SHARED ${SOURCES}). I am using command line gradlew to compile because I could not get Android Studio to create a project without errors.
Some of what is happening makes sense to me:
1. I can build cmakelib by itself with "gradlew installDebug” and it builds and uploads an apk that is (unsurprisingly) not a valid Android program, but if I unzip it, I can see it contains a file in lib/[ARCH] named liblovrd.so.
2. I can build VrCubeWorld_Framework with “gradlew installDebug” and it builds and uploads an apk which is a valid Android program I can execute on my Oculus Go, *and* if I unzip the APK I can see it contains that same lib/[ARCH]/liblovrd.so.
Some of what is happening does *not* make sense to me, and is very bad:
1. Although builds of VrCubeWorld_Framework are triggering builds of cmakelib, as if it were a dependency, the builds of cmakelib are not occurring “before” the build of VrCubeWorld_Framework, as you would expect for a dependency.
What I mean by this: Say that I introduce a failure into cmakelib, for example I add “message(FATAL_ERROR test)” to the CMakeLists.txt. When I installDebug the VRCubeWorld_Framework project, it will fail with the expected message. But let’s say that I introduce failures to cmakelib and VRCubeWorld_Framework at once (I put an error in the source file listed in VRCubeWorld_Framework’s jni/Android.mk). VRCubeWorld_Framework will be built first, and will print its error, and the build will halt, and cmakelib will not be attempted. It appears VRCubeWorld_Framework compiles first and cmakelib after.
This is especially a problem because:
2. VRCubeWorld_Framework, when its jni/Android.mk is being built, cannot find liblovrd.so, and the symbols in liblovrd.so are not visible to its source files. There is a symbol bridgeLovrInit(); in liblovrd.so. If I add “lovr” to LOCAL_SHARED_LIBRARIES in VRCubeWorld_Framework’s jni/Android.mk, and add a call to bridgeLovrInit() in the VRCubeWorld_Framework’s main cpp file, then build, I get these errors at the end of the gradlew output:
/Users/mcc/Library/Android/sdk/ndk-bundle/build/core/
build-binary.mk:688: Android NDK: Module vrcubeworld depends on undefined modules: lovr
[arm64-v8a] Compile++ : vrcubeworld <= VrCubeWorld_Framework.cpp
[arm64-v8a] Prebuilt : libvrapi.so <= /Users/mcc/work/h/ovr_sdk_mobile_1.16.0/VrSamples/VrCubeWorld_Framework/Projects/Android/jni/../../../../../VrApi/Projects/AndroidPrebuilt/jni/../../../Libs/Android/arm64-v8a/Debug/
[arm64-v8a] SharedLibrary : libvrcubeworld.so
/Users/mcc/work/h/ovr_sdk_mobile_1.16.0/VrSamples/VrCubeWorld_Framework/Projects/Android/build/intermediates/ndkBuild/debug/obj/local/arm64-v8a/objs-debug/vrcubeworld/__/__/__/Src/VrCubeWorld_Framework.o: In function `OVR::VrCubeWorld::EnteredVrMode(OVR::ovrIntentType, char const*, char const*, char const*)':
/Users/mcc/work/h/ovr_sdk_mobile_1.16.0/VrSamples/VrCubeWorld_Framework/Projects/Android/jni/../../../Src/VrCubeWorld_Framework.cpp:116: undefined reference to `bridgeLovrInit()'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
Notice the warning on the first line and the error on the final line.
Other things which do not work: If I name lovr in the LOCAL_SHARED_LIBRARIES line to “liblovr”, it fails the same way, with the “undefined module lovr” error; if I say “liblovrd” it gives me an error of “undefined module lovrd”. If I construct “lovr” as a static library (I would actually rather it be static) it can’t find it like that either.
What am I supposed to do here? The other shared libraries included by Android.mk are also coming out of subprojects, but those are all ndkBuild based subprojects. It feels like some kind of magic is allowing the ndkBuild projects to see each other which is not working when the subproject is cmake. How are projects and subprojects in gradle supposed to communicate outputs/inputs to each other?