Android Studio 14本机开发+ CrystaX NDK [英] Android Studio 14 Native Development + CrystaX NDK

查看:1117
本文介绍了Android Studio 14本机开发+ CrystaX NDK的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将一个巨大的交叉平台C ++ 11(iOS + Android)应用程序项目迁移到Android Studio 14.我使用CrystaX NDK的boost和C ++ 14。有一个官方的Android Studio + CrystaX教程在他们的网站的博客这里,但它已过时。



我已经下载了官方hello-jni示例,该示例旨在与Android Studio 1.4配合使用,并尝试使其适用于CrystaX NDK。这是我的Gradle 2.5设置:



项目build.gradle



  //顶层构建文件,您可以在其中添加所有子项目/模块共有的配置选项。 
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
}

/ *
*本机构建设置
* /
android.ndk {
moduleName =tableair-framework
cppFlags + =-std = c ++ 11
cppFlags + =-Werror
ldLibs = [android,log,GLESv2,crystax]
stl =gnustl_static
/ *
*其他ndk标志可配置在这里是
* cppFlags + =-fno-rtti
* cppFlags + =-fno-exceptions
* ldLibs = ,log]
* stl =system
* /
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles + = file('proguard-rules.txt')
}
}
android.productFlavors {
//详细的abiFilter描述,请参阅支持的ABI @
// 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 -64){
ndk.abiFilters + =x86_64
}
create(mips){
ndk.abiFilters + =mips
}
create(mips-64){
ndk.abiFilters + =mips64
}
//包括所有cpu架构,留下abiFilters空
create (all)
}
}

local.properties

  ndk.dir = / Users / vilius / Software / Android / crystax-ndk-10.2.1 
sdk.dir = / Users / vilius / Library / Android / sdk

应用程序。我收到此错误:

  .... 
:app:generateAllDebugAndroidTestSources最新日期
: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:找不到-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:找不到-lcrystax
错误:错误:ld返回1退出状态
错误:任务':app:linkArm64-v8aDebugAllTableair-frameworkSharedLibrary'的执行失败。
>构建操作失败。
链接器失败,而链接libtableair-framework.so。
查看完整日志:file:///Users/vilius/TableAir/Mobile/app/android-studio-project/app/build/tmp/linkArm64-v8aDebugAllTableair-frameworkSharedLibrary/output.txt

... / output.txt显示与消息窗口中完全相同的信息。



有没有人对这个问题有想法?

解决方案

https://www.crystax.net/en/blog/3\">这里有点过时,所以我们计划很快发布新文章,更新了如何使用CrystaX NDK与新的实验Gradle插件的描述。在此期间,您可以查看示例我推送到github。这个例子中最有趣的部分是应用程序的build.gradle,所以为了方便在这里复制它:

  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 b $ b proguardFiles + = file('proguard-rules.pro')
}
}

android.productFlavors {
APP_ABIS.each {abi - >
create(getFlavorName(abi)){
ndk.with {
abiFilters + = abi
getPrebuiltLibPaths(abi).each {path - >
ldFlags + =-L+路径
}
}
}
}
}

}

tasks.all {
task - >
if(task.name.startsWith('link')){
task.dependsOn copyNativeLibs,stripNativeLibs
}
}

task copyNativeLibs {
[debug,release]。每个{buildType - >
APP_ABIS.each {abi - >
def libs = [:]
BOOST_SHARED_LIBS.each {name - >
libs [name] =$ {getBoostLibDir(abi)} / lib $ {name} .so
}
libs.crystax = getLibCrystax(abi)
$ b b libs.each {name,file - >
dependsOn tasks.create(name:copy-native-library - $ {name} - $ {abi} - $ {buildType},type:Copy){
from file
into getTargetLibDir(abi,buildType)
}
}
}
}
}

任务stripNativeLibs(dependsOn:copyNativeLibs){
[debug,release]。每个{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'c​​om.android.support: appcompat-v7:23.0.1'
compile'c​​om.android.support:design:23.0.1'
}

def getNdkDir(){
if System.env.ANDROID_NDK_ROOT!= null)
return System.env.ANDROID_NDK_ROOT

属性属性= new属性()
properties.load(project.rootProject.file .properties')。newDataInputStream())
def ndkdir = properties.getProperty('ndk.dir',null)
if(ndkdir == null)
throw new GradleException( \
找不到NDK位置
在local.properties文件
中或使用ANDROID_NDK_ROOT环境变量定义ndk.dir的位置)

return ndkdir
}

def getCrystaxNdkDir(){
def ndkDir = getNdkDir()
if(!新文件(ndkDir,sources / crystax)。 exists()))
throw new GradleException(\
'$ {ndkDir}'不是CrystaX NDK。
在local.properties中编辑ndk.dir或设置ANDROID_NDK_ROOT
指向CrystaX NDK的环境变量)

return ndkDir
}

def getFlavorName(abi){
switch(abi){
casearmeabi:
returnarm;
casearmeabi-v7a:
returnarm7
casearm64-v8a:
returnarm64
默认值:
return abi.replaceAll(' - ','_')
}
}

def getToolchainName(abi){
switch(abi){
case〜/ ^ armeabi。* /:
returnarm- linux-androideabi
case〜/ ^ arm64。* /:
returnaarch64-linux-android
casemips:
returnmipsel-linux-android
casemips64:
returnmips64el-linux-android
case [x86,x86_64]:
return abi
默认值:
throw new GradleException(Unsupported ABI:'$ {abi}')
}
}

def getToolchainPrefix(abi){
switch {
case〜/ ^ armeabi。* /:
returnarm-linux-androideabi
case〜/ ^ arm64。* /:
returnaarch64-linux-android
casemips:
returnmipsel-linux-android
casemips64:
returnmips64el-linux-android
casex86 :
returni686-linux-android
casex86_64:
returnx86_64-linux-android
默认:
throw new GradleException不支持的ABI:'$ {abi}')
}
}

def getHostOS(){
if(OperatingSystem.current()。isLinux
return(linux)
if(OperatingSystem.current()。isMacOsX())
returndarwin
if(OperatingSystem.current()。isWindows $ b returnwindows
抛出新的GradleException(不支持的主机操作系统)
}

def getHostArch(){
def arch = System.getProperty os.arch)
switch(arch){
case [x86_64,amd64]:
returnx86_64
case〜/ ^ i [3456] 86 /:
casex86:
returnx86
default:
throw new GradleException(无法检测主机的CPU架构:'$ {arch}'
}
}

def getHostTag(){
def tag = getHostOS()
def arch = getHostArch()
if !=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)
路径+ = getLibCrystaxDir(abi)
返回路径
}

def getTargetLibDir abi,buildType){
return$ {buildDir} / intermediateates / binaries / $ {buildType} / $ {getFlavorName(abi)} / lib / $ {abi}
}
b $ b def getLibCrystaxDir(abi){
return$ {getCrystaxNdkDir()} / sources / crystax / libs / $ {abi}
}

def getLibCrystax ){
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}
}

我已经用Android Studio 1.4和gradle实验性插件0.2.0测试过了。



自定义 copyNativeLibs 任务仅需要将共享库包含在apk中;如果你链接到静态库,根本不需要 copyNativeLibs



UPDATE:我已经添加了 stripNativeLibs 任务只是因为我意识到APK包含未上架的库与调试信息,使其尺寸太大,没有任何真正的需要。 p>

I am trying to migrate a huge crossplatform C++11 (iOS+Android) app project into Android Studio 14. I am using CrystaX NDK for boost and C++14. There's an official Android Studio + CrystaX tutorial on their website's blog here but it's outdated.

I've downloaded the official hello-jni example that is meant to work with Android Studio 1.4 and tried to adapt it to work with CrystaX NDK. These are my Gradle 2.5 settings:

project 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

When I try to run the app. I get this error:

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

The .../output.txt displays exactly the same information as in the message window.

Does anyone have ideas about this problem?

解决方案

Yes, example here is bit outdated, so we plan to publish new article soon, with updated description of how to use CrystaX NDK with new experimental Gradle plugin. In the meantime, you can look on example I've pushed to github. The most interesting part of that example is app's build.gradle, so I copy it here for convenience:

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}"
}

I've tested it with Android Studio 1.4 and gradle experimental plugin 0.2.0.

In fact, custom copyNativeLibs task needed only for including shared libraries into apk; if you link with static libraries, copyNativeLibs is not needed at all.

UPDATE: I've added stripNativeLibs task just because I've realized that APK got included unstripped libraries with debug information, making its size too big without any real need in that.

这篇关于Android Studio 14本机开发+ CrystaX NDK的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆