Possible Bug in cmake-file-api related to relative paths

I know the following is going to sound Android Studio / Gradle specific, but please hear me out as I think this is a bug in file api, not in Gradle / Android. Also, apologies in advance for the long message, but there’s a lot of setup here, and I don’t think I can shorten it without losing important information.

I have a large application for one of the supported platforms is Android. We use CMake via the Android Studio Gradle CMake Plugin. As of CMake 3.18 and Android Studio 4.2, this invokes cmake-file-api so that Gradle can get a detailed description of the build.

I believe I’m hitting a bug in cmake-file-api that is preventing Gradle from working, but I am hoping someone could help me narrow this down further. Here are the key points distilled down:

  1. Android Studio generates my cmake ninja build into the folder D:\src\game-engine\Client\AndroidClient\engine\.cxx\cmake\release\armeabi-v7a.
  2. Before doing so, it creates file api requests in the form of:
D:
 |_ src
    |_ game-engine
       |_ Client
          |_ AndroidClient
             |_ engine
                |_ .cxx
                   |_ cmake
                      |_ release
                         |_ armeabi-v7a       # This is the build directory / CMakeCache.txt location
                            |_ .cmake
                               |_ api
                                  |_ v1
                                     |_ query
                                        |_ client-agp
                                           |_ cache-v2
                                           |_ cmakeFiles-v1
                                           |_ codemodel-v2
  1. Gradle runs cmake configure step with the following command line:
cmake.exe 
    -HD:\src\game-engine\Client 
    "-DCMAKE_CXX_FLAGS=-fexceptions -frtti" 
    -DCMAKE_FIND_ROOT_PATH=D:\src\game-engine\Client\AndroidClient\engine\.cxx\cmake\release\prefab\armeabi-v7a\prefab 
    -DCMAKE_BUILD_TYPE=Release 
    -DCMAKE_TOOLCHAIN_FILE=C:\Users\divis\AppData\Local\Android\Sdk\ndk\21.3.6528147\build\cmake\android.toolchain.cmake 
    -DANDROID_ABI=armeabi-v7a 
    -DANDROID_NDK=C:\Users\divis\AppData\Local\Android\Sdk\ndk\21.3.6528147 
    -DANDROID_PLATFORM=android-19 
    -DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a 
    -DCMAKE_ANDROID_NDK=C:\Users\divis\AppData\Local\Android\Sdk\ndk\21.3.6528147 
    -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 
    -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=D:\src\game-engine\Client\AndroidClient\engine\build\intermediates\cmake\release\obj\armeabi-v7a 
    -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=D:\src\game-engine\Client\AndroidClient\engine\build\intermediates\cmake\release\obj\armeabi-v7a 
    -DCMAKE_SYSTEM_NAME=Android 
    -DCMAKE_SYSTEM_VERSION=19 
    -DANDROID_TOOLCHAIN=clang 
    -DANDROID_STL=c++_static 
    -DANDROID_ARM_NEON=TRUE 
    -DANDROID_PIE=TRUE 
    -DCMAKE_VERBOSE_MAKEFILE=FALSE 
    -DBUILD_TESTS=OFF 
    -BD:\src\game-engine\Client\AndroidClient\engine\.cxx\cmake\release\armeabi-v7a 
    -GNinja
  1. One of the outputs of this build is libfmod.so, and if I print the target properties of this target, I see the following:
fmod LIBRARY_OUTPUT_DIRECTORY = D:\src\game-engine\Client\AndroidClient\engine\build\intermediates\cmake\release\obj\armeabi-v7a
fmod RUNTIME_OUTPUT_DIRECTORY = D:\src\game-engine\Client\AndroidClient\engine\build\intermediates\cmake\release\obj\armeabi-v7a

Just to confirm, If I add some debugging to print the value of $<TARGET_FILE:fmod>, I see this:

$ ninja genexdebug
[12.320 235/235]cmd.exe /C "cd /D D:\src\game-engine\Client\AndroidClient\engine\.cxx\cmake\release\armeabi-v7a\ThirdParty\f...ake.exe -E echo D:/src/game-engine/Client/AndroidClient/engine/build/intermediates/cmake/release/obj/armeabi-v7a/libfmod.so"
D:/src/game-engine/Client/AndroidClient/engine/build/intermediates/cmake/release/obj/armeabi-v7a/libfmod.so

Clearly at this point we can establish that CMake (correctly) believes this file belongs in D:/src/game-engine/Client/AndroidClient/engine/build/intermediates/cmake/release/obj/armeabi-v7a/libfmod.so.

  1. Moving along, let’s look at the reply from the cmake file api.
# target-fmod-Release-<hash>.json
{
	"artifacts" : 
	[
		{
			"path" : "D:/src/game-engine/Client/AndroidClient/engine/build/intermediates/cmake/release/obj/armeabi-v7a/libfmod.so"
		}
	],
        ...

Looks correct. Now for engine, which depends on libfmod.so.

# target-engine-Release-<hash>.json
{
	"artifacts" : 
	[
		{
			"path" : "D:/src/game-engine/Client/AndroidClient/engine/build/intermediates/cmake/release/obj/armeabi-v7a/libengine.so"
		}
	],

	...
	"link" : 
	{
		"commandFragments" : 
		[
			{
				"fragment" : "-Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -Wl,--no-undefined -Qunused-arguments   -Xlinker --no-map-whole-files",
				"role" : "flags"
			},
			...
			{
				"backtrace" : 2,
				"fragment" : "..\\..\\..\\..\\..\\build\\intermediates\\cmake\\release\\obj\\armeabi-v7a\\libfmod.so",
				"role" : "libraries"
			},

The Problem
Ok… Finally I can demonstrate the problem. There are 5 ..\'s in the fragment above. Starting from the folder containing the CMakeCache.txt / build.ninja and resolving the aforementioned relative path we end up with

# Reply from file api
D:\src\game-engine\Client\AndroidClient\build\intermediates\cmake\release\obj\armeabi-v7a\libfmod.so
# What CMake believes the path to be at configure time.
D:\src\game-engine\Client\AndroidClient\engine\build\intermediates\cmake\release\obj\armeabi-v7a\libfmod.so

I tried creating a minimal reproducer of this, but in all of my attempts, the fragment gets output with an absolute path, not a relative path. So it isn’t clear to me how to force it to generate an absolute path, or why it might be generating an incorrect relative path.

Any suggestions on whether this is a valid bug and if there’s anything I can do to help create a smaller reproducer?

@brad.king Looks like a potential file-api issue.

Yes. I’ve reproduced the problem and opened CMake Issue 22301 to track it.

Thanks for the quick response and action :slight_smile: