我正在尝试将庞大的跨平台C ++ 11(iOS + Android)应用程序项目迁移到Android Studio 14.我使用CrystaX NDK进行boost和C ++ 14。在他们网站的博客here上有一个官方的Android Studio + CrystaX教程,但它已经过时了。
我已下载官方hello-jni示例,该示例旨在与Android Studio 1.4配合使用,并尝试使其适用于与CrystaX NDK配合使用。这些是我的Gradle 2.5设置:
项目build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle-experimental:0.2.0'
}
}
allprojects {
repositories {
jcenter()
}
}
module build.gradle
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.1"
defaultConfig.with {
applicationId = "com.tableair.app"
minSdkVersion.apiLevel = 4
targetSdkVersion.apiLevel = 23
}
}
compileOptions.with {
sourceCompatibility=JavaVersion.VERSION_1_7
targetCompatibility=JavaVersion.VERSION_1_7
}
/*
* native build settings
*/
android.ndk {
moduleName = "tableair-framework"
cppFlags += "-std=c++11"
cppFlags += "-Werror"
ldLibs = ["android", "log", "GLESv2", "crystax"]
stl = "gnustl_static"
/*
* Other ndk flags configurable here are
* cppFlags += "-fno-rtti"
* cppFlags += "-fno-exceptions"
* ldLibs = ["android", "log"]
* stl = "system"
*/
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles += file('proguard-rules.txt')
}
}
android.productFlavors {
// for detailed abiFilter descriptions, refer to "Supported ABIs" @
// https://developer.android.com/ndk/guides/abis.html#sa
create("arm") {
ndk.abiFilters += "armeabi"
}
create("arm7") {
ndk.abiFilters += "armeabi-v7a"
}
create("arm8") {
ndk.abiFilters += "arm64-v8a"
}
create("x86") {
ndk.abiFilters += "x86"
}
create("x86-64") {
ndk.abiFilters += "x86_64"
}
create("mips") {
ndk.abiFilters += "mips"
}
create("mips-64") {
ndk.abiFilters += "mips64"
}
// To include all cpu architectures, leaves abiFilters empty
create("all")
}
}
local.properties
ndk.dir=/Users/vilius/Software/Android/crystax-ndk-10.2.1
sdk.dir=/Users/vilius/Library/Android/sdk
当我尝试运行该应用时。我收到这个错误:
....
:app:generateAllDebugAndroidTestSources UP-TO-DATE
:app:copyArm64-v8aDebugAllTableair-frameworkSharedLibraryGdbServer UP-TO-DATE
:app:createArm64-v8aDebugAllTableair-frameworkSharedLibraryGdbsetup
:app:compileArm64-v8aDebugAllTableair-frameworkSharedLibraryTableair-frameworkMainC UP-TO-DATE
:app:linkArm64-v8aDebugAllTableair-frameworkSharedLibrary
/Users/vilius/Software/Android/crystax-ndk-10.2.1/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/../lib/gcc/aarch64-linux-android/4.9/../../../../aarch64-linux-android/bin/ld: cannot find -lcrystax
/Users/vilius/Software/Android/crystax-ndk-10.2.1/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/../lib/gcc/aarch64-linux-android/4.9/../../../../aarch64-linux-android/bin/ld: cannot find -lcrystax
Error:error: ld returned 1 exit status
Error:Execution failed for task ':app:linkArm64-v8aDebugAllTableair-frameworkSharedLibrary'.
> A build operation failed.
Linker failed while linking libtableair-framework.so.
See the complete log at: file:///Users/vilius/TableAir/Mobile/app/android-studio-project/app/build/tmp/linkArm64-v8aDebugAllTableair-frameworkSharedLibrary/output.txt
... / output.txt显示与消息窗口中完全相同的信息。
有没有人对此问题有任何想法?
答案 0 :(得分:8)
是的,示例here有点过时,所以我们计划尽快发布新文章,并提供有关如何使用CrystaX NDK和新实验性Gradle插件的更新说明。在此期间,您可以查看example我已经推送到github。该示例中最有趣的部分是app的build.gradle,因此为方便起见,我将其复制到此处:
public class BMIprogram {
public static void main(String[] args) {
double BMI;
double weight;
double height;
Scanner bodymassScan = new Scanner(System.in);
System.out.println("Enter weight in pounds: ");
weight = bodymassScan.nextInt();
System.out.println("Enter height in inches: ");
height = bodymassScan.nextInt();
BMI = ((weight/Math.pow(height, 2)) * 703);
System.out.println(BMI + " is the BMI");
}
}
我已经使用Android Studio 1.4和gradle实验插件0.2.0进行了测试。
实际上,自定义import org.gradle.internal.os.OperatingSystem;
apply plugin: 'com.android.model.application'
final APP_ABIS = ["armeabi", "armeabi-v7a", "x86"]
final BOOST_SHARED_LIBS = ["boost_serialization"]
model {
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.1"
defaultConfig.with {
applicationId = "net.crystax.testboost2"
minSdkVersion.apiLevel = 15
targetSdkVersion.apiLevel = compileSdkVersion.asType(Integer)
versionCode = 1
versionName = "1.0"
}
}
compileOptions.with {
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
}
android.ndk {
moduleName = "test-boost2"
cppFlags += "-std=c++11"
cppFlags += "-fexceptions"
cppFlags += "-frtti"
cppFlags += "-Werror"
cppFlags += "-I" + getBoostIncDir()
ldLibs.addAll BOOST_SHARED_LIBS
ldLibs += "log"
stl = "gnustl_shared"
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles += file('proguard-rules.pro')
}
}
android.productFlavors {
APP_ABIS.each { abi ->
create(getFlavorName(abi)) {
ndk.with {
abiFilters += abi
getPrebuiltLibPaths(abi).each { path ->
ldFlags += "-L" + path
}
}
}
}
}
}
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_SHARED_LIBS.each { name ->
libs[name] = "${getBoostLibDir(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 = []
libs.addAll(BOOST_SHARED_LIBS)
libs += "crystax"
libs.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.0.1'
compile 'com.android.support:design:23.0.1'
}
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
}
def getFlavorName(abi) {
switch (abi) {
case "armeabi":
return "arm";
case "armeabi-v7a":
return "arm7"
case "arm64-v8a":
return "arm64"
default:
return abi.replaceAll('-', '_')
}
}
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}'")
}
}
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}'")
}
}
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")
}
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}'")
}
}
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}-4.9/prebuilt/${hostTag}/bin/${toolchainPrefix}-strip"
if (OperatingSystem.current().isWindows())
strip = strip.replaceAll('/', '\\\\') + '.exe'
return strip
}
def getPrebuiltLibPaths(abi) {
def paths = []
paths += getBoostLibDir(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.58.0"
}
def getBoostIncDir() {
return "${getBoostDir()}/include"
}
def getBoostLibDir(abi) {
return "${getBoostDir()}/libs/${abi}"
}
任务只需要将共享库包含到apk中;如果您与静态库链接,则根本不需要copyNativeLibs
。
更新:我添加了copyNativeLibs
任务只是因为我意识到APK包含了带有调试信息的未经剥离的库,使其大小太大而没有任何实际需要。
答案 1 :(得分:0)
@ dmitry-moskalchuk你好Dmitry我用你的代码编译build.gradle并在local.properties中定义了crystax-ndk-10.2.1 ndk.dir = /选择/ Android的SDK-LINUX / crystax-NDK-10.2.1
我总是收到错误: 错误:配置项目':app'。
时出现问题android.compileSdkVersion丢失!
但它在android部分以及androidmanifest.xml中定义
谢谢。