我目前正在尝试在Android Studio上的Android原生库中使用boost :: regex库。但是我得到了这两个链接器错误:
F:\Tools\dev\Android\ndks\crystax-ndk-10.3.2/sources/boost/1.64.0/include/boost/regex/v4/regex_search.hpp:56: error: undefined reference to 'boost::re_detail_106400::perl_matcher<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<boost::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::find()'
F:\Tools\dev\Android\ndks\crystax-ndk-10.3.2/sources/boost/1.64.0/include/boost/regex/v4/perl_matcher.hpp:383: error: undefined reference to 'boost::re_detail_106400::perl_matcher<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<boost::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::construct_init(boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > > const&, boost::regex_constants::_match_flags)'
我正在使用crystax-ndk(10.3.2)来编译我的本机c ++代码。 boost库是1.64.0版本,我使用来自here的预编译静态库。
我的build.gradle看起来像这样:
import org.gradle.internal.os.OperatingSystem
apply plugin: 'com.android.model.application'
final APP_ABIS = ["armeabi", "armeabi-v7a", "x86"]
final BOOST_STATIC_LIBS = ["boost_system", "boost_filesystem", "boost_thread", "boost_regex", "boost_iostreams", "boost_log_setup", "boost_log"]
final OPENSSL_SHARED_LIBS = ["ssl", "crypto"]
model {
android {
compileSdkVersion = 23
buildToolsVersion = "25.0.2"
defaultConfig.with {
applicationId = "de.linux13524.youtube_list_downloader"
minSdkVersion.apiLevel = 17
targetSdkVersion.apiLevel = compileSdkVersion as Integer
versionCode = 1
versionName = "1.0"
}
}
android.ndk {
toolchain = "gcc"
toolchainVersion = "5"
moduleName = "native-lib"
cppFlags.add("-std=c++11")
cppFlags.add("-fexceptions")
cppFlags.add("-frtti")
cppFlags.add("-DANDROID")
cppFlags.add("-I" + getBoostIncDir())
cppFlags.add("-I" + getOpenSSLIncDir())
cppFlags.add("-I" + file("../../lib").absolutePath)
cppFlags.add("-I" + file("../../lib/nowide_standalone").absolutePath)
cppFlags.add("-I" + file("../../include").absolutePath)
ldLibs.addAll BOOST_STATIC_LIBS
ldLibs.addAll OPENSSL_SHARED_LIBS
ldLibs.add("log")
stl = "gnustl_shared"
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file('proguard-rules.pro'))
}
}
android.productFlavors {
APP_ABIS.each { abi ->
create(getFlavorName(abi)) {
ndk.with {
abiFilters.add(abi)
getPrebuiltLibPaths(abi).each { path ->
ldFlags.add("-L" + path)
}
}
}
}
}
android.sources {
main {
jni {
source {
srcDirs = ["/src/main/jni".toString(),
"../../src".toString(),
"../../include".toString(),
"../../lib".toString()]
}
}
}
}
}
tasks.all {
task ->
if (task.name.startsWith('link')) {
task.dependsOn copyNativeLibs, stripNativeLibs
}
}
task copyNativeLibs {
["debug", "release"].each { buildType ->
APP_ABIS.each { abi ->
def libs = [:]
BOOST_STATIC_LIBS.each { name ->
libs[name] = "${getBoostLibDir(abi)}/lib${name}.a"
}
OPENSSL_SHARED_LIBS.each { name ->
libs[name] = "${getOpenSSLLibDir(abi)}/lib${name}.so"
}
libs.crystax = getLibCrystax(abi)
libs.each { name, file ->
dependsOn tasks.create(name: "copy-native-library-${name}-${abi}-${buildType}", type: Copy) {
from file
into getTargetLibDir(abi, buildType)
}
}
}
}
}
task stripNativeLibs(dependsOn: copyNativeLibs) {
["debug", "release"].each { buildType ->
APP_ABIS.each { abi ->
def libs_static = []
def libs_dynamic = []
libs_static.addAll(BOOST_STATIC_LIBS)
libs_dynamic.addAll(OPENSSL_SHARED_LIBS)
libs_dynamic.add("crystax")
libs_static.each { name ->
dependsOn tasks.create(name: "strip-native-library-${name}-${abi}-${buildType}", type: Exec) {
commandLine getStripExecutable(abi), "--strip-unneeded", "${getTargetLibDir(abi, buildType)}/lib${name}.a"
}
}
libs_dynamic.each { name ->
dependsOn tasks.create(name: "strip-native-library-${name}-${abi}-${buildType}", type: Exec) {
commandLine getStripExecutable(abi), "--strip-unneeded", "${getTargetLibDir(abi, buildType)}/lib${name}.so"
}
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
}
def getNdkDir() {
if (System.env.ANDROID_NDK_ROOT != null)
return System.env.ANDROID_NDK_ROOT
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def ndkdir = properties.getProperty('ndk.dir', null)
if (ndkdir == null)
throw new GradleException("""\
NDK location not found.
Define location with ndk.dir in the local.properties file
or with an ANDROID_NDK_ROOT environment variable.""")
return ndkdir
}
def getCrystaxNdkDir() {
def ndkDir = getNdkDir()
if (!(new File(ndkDir, "sources/crystax").exists()))
throw new GradleException("""\
'${ndkDir}' is not a CrystaX NDK.
Edit ndk.dir in local.properties or set ANDROID_NDK_ROOT
environment variable pointing to CrystaX NDK""")
return ndkDir
}
static def getFlavorName(abi) {
switch (abi) {
case "armeabi":
return "arm"
case "armeabi-v7a":
return "arm7"
case "arm64-v8a":
return "arm64"
default:
return abi.replaceAll('-', '_')
}
}
static def getToolchainName(abi) {
switch (abi) {
case ~/^armeabi.*/:
return "arm-linux-androideabi"
case ~/^arm64.*/:
return "aarch64-linux-android"
case "mips":
return "mipsel-linux-android"
case "mips64":
return "mips64el-linux-android"
case ["x86", "x86_64"]:
return abi
default:
throw new GradleException("Unsupported ABI: '${abi}'")
}
}
static def getToolchainPrefix(abi) {
switch (abi) {
case ~/^armeabi.*/:
return "arm-linux-androideabi"
case ~/^arm64.*/:
return "aarch64-linux-android"
case "mips":
return "mipsel-linux-android"
case "mips64":
return "mips64el-linux-android"
case "x86":
return "i686-linux-android"
case "x86_64":
return "x86_64-linux-android"
default:
throw new GradleException("Unsupported ABI: '${abi}'")
}
}
static def getHostOS() {
if (OperatingSystem.current().isLinux())
return "linux"
if (OperatingSystem.current().isMacOsX())
return "darwin"
if (OperatingSystem.current().isWindows())
return "windows"
throw new GradleException("Unsupported host OS")
}
static def getHostArch() {
def arch = System.getProperty("os.arch")
switch (arch) {
case ["x86_64", "amd64"]:
return "x86_64"
case ~/^i[3456]86/:
case "x86":
return "x86"
default:
throw new GradleException("Can't detect host's CPU architecture: '${arch}'")
}
}
static def getHostTag() {
def tag = getHostOS()
def arch = getHostArch()
if (tag != "windows" || arch != "x86")
tag += "-${arch}"
return tag
}
def getStripExecutable(abi) {
def ndk = getCrystaxNdkDir()
def toolchainName = getToolchainName(abi)
def toolchainPrefix = getToolchainPrefix(abi)
def hostTag = getHostTag()
def strip = "${ndk}/toolchains/${toolchainName}-5/prebuilt/${hostTag}/bin/${toolchainPrefix}-strip"
if (OperatingSystem.current().isWindows())
strip = strip.replaceAll('/', '\\\\') + '.exe'
return strip
}
def getPrebuiltLibPaths(abi) {
def paths = []
paths += getBoostLibDir(abi)
paths += getOpenSSLLibDir(abi)
paths += getLibCrystaxDir(abi)
return paths
}
def getTargetLibDir(abi, buildType) {
return "${buildDir}/intermediates/binaries/${buildType}/${getFlavorName(abi)}/lib/${abi}"
}
def getLibCrystaxDir(abi) {
return "${getCrystaxNdkDir()}/sources/crystax/libs/${abi}"
}
def getLibCrystax(abi) {
return "${getLibCrystaxDir(abi)}/libcrystax.so"
}
def getBoostDir() {
return "${getCrystaxNdkDir()}/sources/boost/1.64.0"
}
def getBoostIncDir() {
return "${getBoostDir()}/include"
}
def getBoostLibDir(abi) {
return "${getBoostDir()}/${abi}/lib"
}
def getOpenSSLDir() {
return "${getCrystaxNdkDir()}/sources/openssl/1.0.2h"
}
def getOpenSSLIncDir() {
return "${getOpenSSLDir()}/include"
}
def getOpenSSLLibDir(abi) {
return "${getOpenSSLDir()}/libs/${abi}"
}
我将boost_regex
添加到要链接的库列表(BOOST_STATIC_LIBS
)。
除了正则表达式部分(regex_search
)之外,我正在使用http的asio部分,文件系统部分和日志记录部分,没有任何(链接器)问题。
当我用nm --demangle libboost_regex.a | grep perl_matcher | grep regex_traits | grep "find()"
检查libboost_regex.a库时,“未定义的引用”显示在结果列表中。 (另一个参考也在列表中)
那么这里可能出现什么问题?我错过了一些重要的事情吗?
答案 0 :(得分:0)
我通过使用CMake将crystax更改为Android NDK r16b并将c++11
lib设置为build.gradle
来解决我的问题。
在...
externalNativeBuild {
cmake {
cppFlags "-std=c++11 -frtti -fexceptions"
arguments "-DANDROID_STL=c++_static"
}
}
...
:
server.route({
method: 'GET',
path: '/uploads/{file*}',
handler: (req, h) => {
return h.file(`./uploads/${req.params.file}`)
.header('Content-Type', 'application/pdf')
.header('Content-Disposition', 'attachment; filename=' + req.params.file)
},
options: {
auth: false
}
});
现在Boost库(更新到版本1.66)链接没有问题。