1

I am working on a multi-platform project which, among others, supports Linux and Android. The code is mostly C; the Android port has a Java wrapper for the platform-specific parts, which calls the native code parts for the core functionality.

On Linux we build this project with CMake, followed by make. For Android we essentially use Gradle and call CMake through externalNativeBuild. The CMakeFile.txt can detect an Android build with a simple if (ANDROID), allowing us to

The project relies on some standard libraries, which we detect with the following in our CMakeLists.txt:

find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
    pkg_check_modules ( FOO foo-42.0 )
    if (FOO_FOUND)
        set(HAVE_FOO 1)
        include_directories(${FOO_INCLUDE_DIRS})
        # …

When building for Android, this picks up either nothing or libraries for the host OS (somewhere underneath /usr/include/) rather than those for Android (which would reside somewhere underneath $NDK/sysroot). (Note $NDK just denotes the NDK path, not necessarily an environment variable.)

According to this post, pkg-config relies on a bunch of environment variables to determine where to look for libraries, namely CMAKE_SYSROOT, PKG_CONFIG_DIR, PKG_CONFIG_LIBDIR and PKG_CONFIG_SYSROOT_DIR. I checked them and they are empty (or unset).

Using the gradle/NDK/CMake toolchain, how can I either pass the correct variables to CMake, or otherwise have it find the libraries for which NDK supplies headers?

user149408
  • 5,385
  • 4
  • 33
  • 69

2 Answers2

1

There are two options:

  1. If the prebuilts libraries are installed on a hosted OS (for example, we are using docker image that includes all compiled and installed prebuilts and other prerequisites - SDK, NDK, AndroidStudio, etc.), you need to provide CMAKE_FIND_ROOT_PATH where libraries, includes and cmake configs are installed:
list(APPEND CMAKE_FIND_ROOT_PATH ${THIRDPARTY_DIR}/${THIRDPARTY_ANDROID_PLATFORM}/${ANDROID_ABI}/boost)
  1. If the prebuilts are not installed, you need to provide Find<module>.cmake, for example FindBoost.cmake to serve find_package(Boost) (here's an example of how it could be, also this project uses multi-platform parts).
Mykola Khyliuk
  • 1,234
  • 1
  • 9
  • 16
  • Thanks, but the question is not about bundling prebuilt libraries, but about using libraries that ship with Android (such as the standard C library) and ensuring CMake finds the correct header files. – user149408 Feb 28 '21 at 13:31
  • It doesn't matter, algorithm is the same, so libraries shipped by Android (NDK) don't provide ```*config.cmake``` therefore to support ```find_package()``` you need to provide ```Find<>.cmake``` if it is unnneded to support you can use ```find_library``` which works with NDK stuff or simmply directly link required libraries, e.g.: ```target_link_libraries(native-lib log)```. – Mykola Khyliuk Feb 28 '21 at 15:45
0

The NDK path is available to gradle as android.ndkDirectory. Update build.gradle like this:

android {
    // ...
    defaultConfig {
        // ...
        externalNativeBuild {
            cmake {
                // amend existing list of arguments, if you have one
                arguments '-DCMAKE_SYSROOT='+android.ndkDirectory+'/sysroot'
            }
        }
    }
}

Then, in CMakeLists.txt, before the first use pf pkg-config, add:

if(ANDROID)
    set(ENV{PKG_CONFIG_DIR} "")
    set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_SYSROOT}/usr/lib/pkgconfig:${CMAKE_SYSROOT}/usr/share/pkgconfig")
    set(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_SYSROOT})
endif(ANDROID)
user149408
  • 5,385
  • 4
  • 33
  • 69