user149408
user149408

Reputation: 5901

How to tell CMake (invoked through externalNativeBuild) where to look for libraries?

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?

Upvotes: 1

Views: 964

Answers (2)

user149408
user149408

Reputation: 5901

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)

Upvotes: 0

Mykola Khyliuk
Mykola Khyliuk

Reputation: 1423

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).

Upvotes: 1

Related Questions