Errores de "referencia indefinida a" durante el enlace de la biblioteca nativa por el complemento gradle "experimental"

Traté de crear una aplicación JNI simple con un nuevo sistema de compilación basado en com.android "experimental".modelo.application (com.android.tools.build:gradle-experimental:0.9.2).

./gradle/wrapper/gradle-wrapper.properties:


    distributionBase=GRADLE_USER_HOME
    distributionPath=wrapper/dists
    zipStoreBase=GRADLE_USER_HOME
    zipStorePath=wrapper/dists
    distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip

./build.gradle:


    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle-experimental:0.9.2'
        }
    }
    allprojects {
        repositories {
            jcenter()
        }
    }
    task clean(type: Delete) {
        delete rootProject.buildDir
    }

./app/build.gradle:


    apply plugin: 'com.android.model.application'

    Properties properties = new Properties()
    properties.load(project.rootProject.file('local.properties').newDataInputStream())
    def project_src_main = project.getRootDir().absolutePath + '/app/src/main'

    model {
        android {
            compileSdkVersion 25
            buildToolsVersion "25.0.3"
            ndk {
                moduleName = 'android-cpp-sandbox'
                toolchainVersion "4.9"
                platformVersion 16
                stl 'gnustl_static'
                abiFilters.addAll(['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'])
            }
            defaultConfig {
                applicationId 'com.lamersoft.androidcppsandbox'
                minSdkVersion.apiLevel 23
                targetSdkVersion.apiLevel 25
            }
            sources {
                main {
                    manifest {
                        source.srcDir project_src_main
                    }
                    java {
                        source.srcDir project_src_main + '/java'
                    }
                    res {
                        source.srcDir project_src_main + '/res'
                    }
                    jni {
                        source.srcDir project_src_main + '/jni'
                    }
                }
            }
            productFlavors {
                create("arm7") {
                    ndk.abiFilters.add('armeabi-v7a')
                }
                create("arm8") {
                    ndk.abiFilters.add('arm64-v8a')
                }
                create("x86") {
                    ndk.abiFilters.add('x86')
                }
                create("x86-64") {
                    ndk.abiFilters.add('x86_64')
                }
                create("all") {
                }
            }
            buildTypes {
                release {
                    minifyEnabled false
                    proguardFiles.add(file('proguard-android.txt'))
                }
            }
        }
    }
    dependencies {
        compile fileTree(include: ['*.jar'], dir: 'libs')
        androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
            exclude group: 'com.android.support', module: 'support-annotations'
        })
        compile 'com.android.support:appcompat-v7:25.3.1'
        compile 'com.android.support.constraint:constraint-layout:1.0.2'
        compile 'com.android.support:design:25.3.1'
    }

./app/src/main/res/layout/activity_main.xml:


    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.lamersoft.androidcppsandbox.MainActivity">
        <android.support.design.widget.AppBarLayout
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:theme="@style/AppTheme.AppBarOverlay">
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:popupTheme="@style/AppTheme.PopupOverlay" />
        </android.support.design.widget.AppBarLayout>
        <include layout="@layout/content_main"/>
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_margin="@dimen/fab_margin"
            app:srcCompat="@android:drawable/ic_dialog_email" />
    </android.support.design.widget.CoordinatorLayout>

./app/src/main/res/layout/content_main.xml:


    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:showIn="@layout/activity_main"
        tools:context="com.lamersoft.androidcppsandbox.MainActivity">
        <TextView
            android:id="@+id/sample_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </android.support.constraint.ConstraintLayout>

./app/src/main/java/com/lamersoft/androidcppsandbox/MainActivity.java:


    package com.lamersoft.androidcppsandbox;

    import android.os.Bundle;
    import android.support.design.widget.FloatingActionButton;
    import android.support.design.widget.Snackbar;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.Toolbar;
    import android.view.View;

    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);

           FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
            fab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Snackbar.make(view, stringFromJNI(), Snackbar.LENGTH_LONG).setAction("Action", null).show();
                }
            });

        }

        private native String stringFromJNI();

        static {
            System.loadLibrary("android-cpp-sandbox");
        }
    }

./app/src/main/jni/main.cpp:


    #include <jni.h>
    #include <string>
    int counter = 1;
    extern "C"
    JNIEXPORT jstring JNICALL
    Java_com_lamersoft_androidcppsandbox_MainActivity_stringFromJNI(
            JNIEnv* env,
            jobject /* this */) {
        char s[100];
        snprintf(s, sizeof(s), "Hello  from C++ #%d", counter++);
        return env->NewStringUTF(s);
    }

El resultado

Modificaciones

Para reproducir el problema, crearé una clase C ++ en una carpeta separada y la incluiré en el proyecto agregando la ruta con un cppFlag "-I".

./app/src/main/externalCPP/SampleClass.h:


    #ifndef ANDROIDCPPSANDBOX_SAMPLECLASS_H
    #define ANDROIDCPPSANDBOX_SAMPLECLASS_H

    class SampleClass {
    public:
        SampleClass(int start);
        int count();
    private:
        int counter = 0;
    };

    #endif //ANDROIDCPPSANDBOX_SAMPLECLASS_H

./app/src/main/externalCPP/SampleClass.cpp:


    #include "SampleClass.h"
    SampleClass::SampleClass(int start) {
        counter = start;
    }

    int SampleClass::count() {
        return counter++;
    }

./app/src/main/jni/main.cpp:


    #include <jni.h>
    #include <string>
    #include <SampleClass.h>

    SampleClass *counter = new SampleClass(1);

    extern "C"
    JNIEXPORT jstring JNICALL
    Java_com_lamersoft_androidcppsandbox_MainActivity_stringFromJNI(
            JNIEnv* env,
            jobject /* this */) {
        char s[100];
        snprintf(s, sizeof(s), "Hello  from C++ #%d", counter->count());
        return env->NewStringUTF(s);
    }

./app/build.gradle:

solo una línea agregada:



    ...
    model {
        android {
            ...
            ndk {
                ...
                cppFlags.add('-I' + project_src_main + '/externalCPP')
                ...

El resultado

Como puede ver, el proyecto no se compila. Falla conerror: referencia indefinida a 'SampleClass :: count ()' yerror: referencia indefinida a 'SampleClass :: SampleClass (int)'.

Lo mismo sucede cuando trato de usar un terceropreconstruido biblioteca estática en el proyecto definiéndola de esta manera:



    ...
    model {
        repositories {
            libs(PrebuiltLibraries) {
                ThirdPartyLibrary {
                    headers.srcDir project_src_main + '/externalCPP'
                    binaries.withType(StaticLibraryBinary) {
                        staticLibraryFile = file(project_src_main + '/externalCPP/lib/libSomeThirdPartyLibrary' + targetPlatform.getName() + '.a')
                    }
                }
            }
        }
        android {
            ...
            sources {
                main {
                    ...
                    jni {
                        source.srcDir project_src_main + '/jni'
                        dependencies {
                            library 'ThirdPartyLibrary' linkage 'static'
                        }
                    }
                }
            }
            ...

¿Alguien cómo resolver esto con elexperimental plugin de gradle?

Respuestas a la pregunta(0)

Su respuesta a la pregunta