我正在做一个多平台项目,其中支持Linux和Android。代码主要是C语言;Android移植有一个Java包装器用于平台特定的部分,它调用核心功能的本机代码部分。
在Linux上,我们使用CMake,然后是make来构建这个项目。对于Android,我们基本上使用Gradle并通过externalNativeBuild
调用CMake。CMakeFile.txt
可以检测Android构建与一个简单的if (ANDROID)
,允许我们
该项目依赖于一些标准库,我们在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})
# …
当为Android构建时,它要么不拾取任何东西,要么拾取主机操作系统的库(位于/usr/include/
之下),而不是Android的库(位于$NDK/sysroot
之下)。(注意$NDK
只表示NDK路径,不一定是环境变量。)
根据这篇文章,pkg-config
依赖于一堆环境变量来确定在哪里寻找库,即CMAKE_SYSROOT
,PKG_CONFIG_DIR
,PKG_CONFIG_LIBDIR
和PKG_CONFIG_SYSROOT_DIR
。我检查了它们,它们是空的(或未设置)。
使用gradle/NDK/CMake工具链,我如何将正确的变量传递给CMake,或者让它找到NDK提供头的库?
有两个选项:
- 如果预构建库安装在宿主操作系统上(例如,我们使用
docker image
,包括所有编译和安装的预构建和其他先决条件- SDK, NDK, AndroidStudio等),您需要提供CMAKE_FIND_ROOT_PATH
libraries
,includes
和cmake configs
的安装位置:
list(APPEND CMAKE_FIND_ROOT_PATH ${THIRDPARTY_DIR}/${THIRDPARTY_ANDROID_PLATFORM}/${ANDROID_ABI}/boost)
- 如果未安装预构建,则需要提供
Find<module>.cmake
,例如FindBoost.cmake
来服务find_package(Boost)
(这里是如何实现的示例,该项目也使用多平台部件)。
gradle的NDK路径为android.ndkDirectory
。像这样更新build.gradle
:
android {
// ...
defaultConfig {
// ...
externalNativeBuild {
cmake {
// amend existing list of arguments, if you have one
arguments '-DCMAKE_SYSROOT='+android.ndkDirectory+'/sysroot'
}
}
}
}
然后,在CMakeLists.txt
中,第一次使用pkg-config之前,添加:
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)