5

I'm migrating a project from gradle-experimental:0.8.3 to gradle:2.3.3 . Along with it I need to also start using the new cmake which is proving to not be so straight forward. A snippet for the experimental gradle plugin that worked:

repositories {
    libs(PrebuiltLibraries) {
        // Configure one pre-built lib: shared
        crypto {
            // Inform Android Studio where header file dir for this lib
            headers.srcDir "${lib_distribution_root}/openssl/includes"
            // Inform Android Studio where lib is -- each ABI should have a lib file
            binaries.withType(SharedLibraryBinary) {
                sharedLibraryFile = file("${lib_distribution_root}/openssl/lib/armeabi/libcrypto.so")
            }
        }

        openssl {
            // Inform Android Studio where header file dir for this lib
            headers.srcDir "${lib_distribution_root}/openssl/includes"
            // Inform Android Studio where lib is -- each ABI should have a lib file
            binaries.withType(SharedLibraryBinary) {
                sharedLibraryFile = file("${lib_distribution_root}/openssl/lib/armeabi/libssl.so")
            }
        }

        pjsip {
            // Inform Android Studio where header file dir for this lib
            headers.srcDir "${lib_distribution_root}/pjsip/includes"
            // Inform Android Studio where lib is -- each ABI should have a lib file
            binaries.withType(SharedLibraryBinary) {
                sharedLibraryFile = file("${lib_distribution_root}/pjsip/lib/armeabi/libpjsua.so")
            }
        }
    }
}

android {
    def globalConfiguration = rootProject.ext

    compileSdkVersion = globalConfiguration.androidCompileSdkVersion
    buildToolsVersion = globalConfiguration.androidBuildToolsVersion

    defaultConfig.with {
        minSdkVersion.apiLevel = globalConfiguration.androidMinSdkVersion
        targetSdkVersion.apiLevel = globalConfiguration.androidTargetSdkVersion
        multiDexEnabled = true
        testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
    }

    dexOptions.with {
        javaMaxHeapSize = "4g"
    }

    lintOptions.with {
        abortOnError = false
    }

    sources {
        main {
            jni {
                dependencies {
                    library 'crypto' linkage 'shared'
                    library 'openssl' linkage 'shared'
                    library 'pjsip' linkage 'shared'
                }
            }
            jniLibs {
                // for shared lib, lib need to be pushed to the target too
                // Once libs are copied into app/src/main/jniLibs directory,
                // Android Studio will pack them into APK's lib/ directory
                // Here we like to avoid another duplication by pointing
                // to the files that containing our libs' distribution location
                // so the same file is used by compiler at host, also packed
                // into APk to be used at Target (phone/tablet)
                source {
                    srcDir "${lib_distribution_root}/openssl/lib/armeabi"
                    srcDir "${lib_distribution_root}/pjsip/lib/armeabi"
                }
            }
        }
    }

    ndk {
        moduleName = "datanative"
        platformVersion = 19
        stl = "gnustl_static"
        ldLibs.addAll("android", "stdc++", "log", "GLESv2", "EGL", "OpenSLES", "z", "m")
        cppFlags.addAll("-std=c++11", "-frtti", "-fexceptions", "-pthread", "-fpic", "-ffunction-sections", "-funwind-tables")
        cppFlags.add("-DPJ_AUTOCONF")

        abiFilters.add(abiName)
        cppFlags.add("-marm")
    }
}

}

The current work-in-progress has the gradle config:

android {
def globalConfiguration = rootProject.ext

compileSdkVersion globalConfiguration.androidCompileSdkVersion
buildToolsVersion globalConfiguration.androidBuildToolsVersion

defaultConfig {
    minSdkVersion globalConfiguration.androidMinSdkVersion
    targetSdkVersion globalConfiguration.androidTargetSdkVersion
    multiDexEnabled true
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    externalNativeBuild {

        cmake {
            cppFlags "-std=c++11", "-DPJ_AUTOCONF", "-fpic", "-frtti", "-fexceptions", "-pthread", "-ffunction-sections", "-funwind-tables", "-marm"
            arguments '-DANDROID_PLATFORM=android-21', '-DANDROID_STL=gnustl_static'
        }
    }

    ndk {
        moduleName "datanative"
        abiFilters 'armeabi'
    }

}

externalNativeBuild {
    cmake {
        path 'CMakeLists.txt'
    }
}

sourceSets {
    main {
        jniLibs.srcDirs '../distribution/pjsip/lib/armeabi/', '../distribution/openssl/lib/armeabi/', 'src/main/cpp/'
    }
}

dexOptions.with {
    javaMaxHeapSize = "4g"
}

lintOptions.with {
    abortOnError = false
}

}

And the CMakeLists:

cmake_minimum_required(VERSION 3.4.1)

file(GLOB SOURCES
    src/main/cpp/*.h
    src/main/cpp/*.cpp
)

set(distribution_DIR ${path})

include_directories(src/main/cpp/)
include_directories(../distribution/openssl/includes/)
include_directories(../distribution/pjsip/includes/)

add_library( crypto  SHARED IMPORTED )
set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
                       # Provides the path to the library you want to import.
                       absolute_path_cause_gradle_has_error_otherwise/distribution/openssl/lib/armeabi/libcrypto.so )

add_library( ssl  SHARED IMPORTED )
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
                       # Provides the path to the library you want to import.
                       absolute_path_cause_gradle_has_error_otherwise/distribution/openssl/lib/armeabi/libssl.so )

add_library( pjsip  SHARED IMPORTED )
set_target_properties(pjsip PROPERTIES IMPORTED_LOCATION
                       # Provides the path to the library you want to import.
                       absolute_path_cause_gradle_has_error_otherwise/distribution/pjsip/lib/armeabi/libpjsua.so )

add_library( data SHARED ${SOURCES} )

target_link_libraries(data crypto ssl pjsip)

The linking error that I'm facing and maybe not the root cause:

/src/main/cpp/sthread.cpp

Error:(73) undefined reference to '__emutls_v._ZN6STrace12pLocalStreamE'

Error:(73) undefined reference to '__emutls_v._ZN6STrace12pLocalStreamE'

/Library/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/basic_string.h

Error:(547) undefined reference to '__emutls_v._ZN6STrace12pLocalStreamE'

Error:(547) undefined reference to '__emutls_v._ZN6STrace12pLocalStreamE'

Any clue will be apreciated. Thank you!

Misca
  • 459
  • 2
  • 11
  • 31
  • What version of the NDK are you using? – Dan Albert Aug 25 '17 at 16:43
  • It's 15.1, latest one – Misca Aug 26 '17 at 17:05
  • I believe that this problem has nothing to do with the prebuilt libraries you use. But to verify this step towards a [MCVE](https://stackoverflow.com/help/mcve), try to remove `target_link_libraries` entirely. I expect much more undefined references, but the question is will the same `__emutils_…` stay. – Alex Cohn Aug 28 '17 at 05:47
  • 1
    The second step could be to turn on [`"-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON"`](https://stackoverflow.com/a/43442227/192373) to see what actual commands fail. – Alex Cohn Aug 28 '17 at 05:48
  • After removing target_link_libraries, indeed there are lots of other undefined references but that one still shows up, last in the list. Using the Verbose argument does not make any difference in the messages for the build, it shows up in the cmake_build_command.txt: -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON . Trying to check how I can use that argument. Thanks Alex! – Misca Aug 28 '17 at 06:52
  • 1
    The link I gave above explains how the verbose flag and other means can be used to reveal the actual compile/link commands that are performed by CMake. You can actually copy/paste such command to your terminal and check manually how different flags and arguments effect the outcome. In this specific case, I suspect that not all **cppFlags** are accepted from gradle, at least not the way you expect them to be accepted. You can even check how the same compile/link commands look like when commanded by the *experimental* plugin. – Alex Cohn Aug 28 '17 at 18:14
  • 1
    I am surprised that you don't see much more undefined references (with the original **CMakeLists.txt** file) because you don't have `"android", "stdc++", "log", "GLESv2", "EGL", "OpenSLES", "z", "m"` libraries listed in **`target_link_libraries`**. – Alex Cohn Aug 28 '17 at 18:16
  • By adding the above to the target, it says "Cannot specify link libraries for target "android" which is not built by this project". Still experimenting with those flags. – Misca Aug 29 '17 at 07:32
  • 1
    Oh, you must specify sources for these libs, see for example https://stackoverflow.com/a/40857689/192373 – Alex Cohn Aug 29 '17 at 14:53
  • Ok, so after linking the libs and there were also some code fixes, I got to runtime errors: java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib/libcrypto.so" needed or dlopened by "/system/lib/libnativeloader.so" is not accessible for the namespace "classloader-namespace" . This seems pretty common and it's covered by the Nougat Changelist. Trying to figure out what happens there. – Misca Aug 31 '17 at 06:58
  • Or wait, the libcrypto.so is not a system lib – Misca Aug 31 '17 at 07:25
  • **libcrypto.so** does exist in `/system/lib`; you add your version, which is fine. Maybe you should explicitly load it from Java before you load `libdata.so` or whatever is the name of your main **.so** – Alex Cohn Aug 31 '17 at 11:09
  • Actually there are 4 libs loaded in a static initialised in java, that previously worked: System.loadLibrary("crypto"); System.loadLibrary("ssl"); System.loadLibrary("pjsua"); System.loadLibrary("datanative-lib"); These should correspond to the libraries that i'm adding in the make file – Misca Aug 31 '17 at 11:48
  • the last one is actually System.loadLibrary("data") – Misca Aug 31 '17 at 11:59
  • Try to use **System.load(getContext().getApplicationInfo().nativeLibraryDir + "libcrypto.so")**, *etc.* – Alex Cohn Aug 31 '17 at 14:23
  • Sorry for the late reply. The stack goes into this message "/vendor/lib, /system/lib]]] couldn't find "libpjsua.so" ", don't have the getContext for that static call. – Misca Oct 16 '17 at 12:41

0 Answers0