Supposedly we can now define dependencies on native-only libraries, but I'm having an issue adding multiple dependencies.
apply plugin: 'com.android.model.library'
model {
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
minSdkVersion.apiLevel 11
targetSdkVersion.apiLevel 22
versionCode = 1
versionName = "1.0"
}
sources {
//noinspection GroovyAssignabilityCheck
main {
jni {
dependencies {
project ":libraw"
project ":libjpeg"
}
}
}
}
ndk {
moduleName "rawprocessor"
cppFlags.add("-fexceptions")
ldLibs.add("log")
stl "gnustl_shared"
}
}
}
The two libraries are com.android.model.native and they generate an .so properly.
Headers are loaded from foo, but not bar. If I swap the lines they'll load from bar but not foo. Is there a way to load multiple dependencies?
Update (Actual error messages, complete build.gradle added)
undefined reference to 'jpeg_std_error'
undefined reference to 'jpeg_CreateDecompress'
undefined reference to 'jpeg_mem_src'
These continue for any reference to libjpeg in the aggregate library. If I swap libjpeg to be first I get the same undefined reference to any call in the other library.
undefined reference to `open_file(char const*, long long)'
undefined reference to `recycle()'
Update 2
I just noticed that when I add the aggregate library module (the above build.gradle), the build process does not build the second library. If I comment out that library it builds both native-only libraries. I'm now starting to wonder if there's some issue due to the fact that libraw also depends on libjpeg.
Related
I have an Android Library project which has a part in C/C++ via Android NDK.
The project started half of a year ago so we chose to use Experimental Plugin because of better NDK support.
I'm using gradle-experimental:0.8.2right now. I have a com.android.model.native module and i would like to migrate it to gradle:2.2.0. The only option i see in Gradle Android Plugin DSL is:
AppExtension: android extension for com.android.application projects.
LibraryExtension: android extension for com.android.library projects.
TestExtension: android extension for com.android.test projects.
So the question is how to make a pure native module in gradle with stable gradle plugin?
Here is my current native module:
apply plugin: 'com.android.model.native'
apply from: "../config.gradle"
def config = ext.configuration
model {
android {
compileSdkVersion = config.compileSdkVersion
buildToolsVersion = config.buildToolsVersion
defaultConfig {
minSdkVersion.apiLevel = config.minimumSdkVersion
targetSdkVersion.apiLevel = config.targetSdkVersion
versionCode = 1
versionName = '1.0'
}
ndk {
moduleName = 'apicore'
platformVersion = config.minimumSdkVersion
cppFlags.add("-std=c++11")
cppFlags.add("-pthread")
cppFlags.add("-fexceptions")
cppFlags.add("-frtti")
stl = "gnustl_static"
abiFilters.addAll(config.targetPlatforms)
ldLibs.addAll(['android', 'log'])
}
sources {
main {
jni {
source {
//include "someFile.txt"
// This is ignored.
exclude "main.cpp"
exclude "misc/APITest.cpp"
exclude "misc/APITest.h"
}
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles.add(file('proguard-android.txt'))
}
}
}
}
You will need to create CMakeLists.txt or Android.mk to build your "libapicore.so", if you want to move to stable gradle plugin.
I think you should do next steps:
For easy migration move your .h, .c, .cpp to the
root_folder_of_project\app\src\main\cpp
Also add there CMakeLists.txt. It should look like:
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread")
add_library(apicore SHARED
#here add your cpp sources
mysource1.cpp
mysource2.cpp
#do not include main.cpp misc/APITest.cpp misc/APITest.h
)
#include libraries needed for apicore lib
target_link_libraries(apicore
android
log
)
Now rewrite your app's build.gradle and point it to CMakeLists.txt:
apply plugin: 'com.android.application'
android {
compileSdkVersion = 25
buildToolsVersion = '25.0.2'
defaultConfig {
applicationId = 'com.your.app'
minSdkVersion 16
targetSdkVersion 25
ndk {
abifilters 'armeabi-v7a' /*,'armeabi', etc.*/
}
externalNativeBuild {
cmake {
arguments '-DANDROID_PLATFORM=android-19',
'-DANDROID_TOOLCHAIN=clang', /*or gcc*/
'-DANDROID_CPP_FEATURES=rtti',
'-DANDROID_CPP_FEATURES=exceptions',
'-DANDROID_STL=gnustl_static' /*CMake uses by default*/
}
}
}
buildTypes {...}
externalNativeBuild {
cmake {
path 'src/main/cpp/CMakeLists.txt'
}
}
}
dependencies {...}
With this you will build your android application with your native "libapicore.so" inside.
I just migrated my project from Gradle Experimental Plugin to Gradle plugin for Android. The current Gradle plugin for Android still not provide something what com.android.model.native extension provided from the experimental plugin which is an ability to create a pure native module. I have to realise that i don't even need that. What i did to replace the com.android.model.native module is i made a library module where i handle the native code and building of my native libraries and i just copy the native libraries where i need them. Of course the module generate the .aar but thats not a problem i just don't use it.
I have a project that uses the non-experimental version of the Android Gradle plugin (com.android.tools.build:gradle:2.1.3). I have some native code that I build into a shared library libnative.so.
The problem is that now I want to link libnative.so against a prebuilt library. Let's call this file libfoo.so. If I set the jniLibs.srcDir to the folder containing libfoo.so for the different ABIs I see that it gets bundled into my APK.
However I don't understand how I am supposed to link against it successfully. If I add "foo" to ldLibs I get a linker error saying that it can't find the library. This is probably because the folder containing libfoo.so is not included as a search path to the linker.
How am I supposed to do this? Is it simply not possible without switching to the experimental gradle plugin?
This is my gradle file. I stripped away the part that probably is irrelevant for this problem:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.foo.bar"
minSdkVersion 15
targetSdkVersion 23
versionCode 11
versionName "0.0.11"
def foodir = "${project.buildDir}/../../foo"
ndk {
moduleName "native"
ldLibs "foo"
stl "gnustl_static"
}
sourceSets {
main {
jniLibs.srcDirs = ["${foodir}"]
}
}
}
}
I'm running gradlew to compile an Android app that has a static lib dependency. Somehow, I have an undefined reference to bsd_signal.
I was able to compile this app with gradle 1.X, but I've been obliged to switch to gradle 2.10 and to drop my Android.mk file in favour of putting more build instruction into my gradle.build file, and this is where the trouble arises.
Can anyone tell me whether there is a library that defines bsd_signal, which I should link to my project?
Compiler output
Starting process 'command '/home/myself/Android/Sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++''. Working directory: /home/myself/projects/DroidEar/app Command: /home/myself/Android/Sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++ #/home/myself/projects/DroidEar/app/build/tmp/linkNativeArmeabi-v7aDebugSharedLibrary/options.txt
Successfully started process 'command '/home/myself/Android/Sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++''
/android/ndk/platforms/android-9/arch-arm/usr/include/signal.h:113: error: undefined reference to 'bsd_signal'
/android/ndk/platforms/android-9/arch-arm/usr/include/signal.h:113: error: undefined reference to 'bsd_signal'
collect2: error: ld returned 1 exit status
TMI: Here is my gradle.build file
apply plugin: 'com.android.model.application'
model {
repositories {
libs(PrebuiltLibraries) {
Superpowered {
binaries.withType(StaticLibraryBinary) {
def prefix = "src/main/jniLibs/Superpowered"
headers.srcDir "${prefix}"
if (targetPlatform.getName() == "armeabi-v7a")
staticLibraryFile = file("${prefix}/libSuperpoweredAndroidARM.a")
else if (targetPlatform.getName() == "arm64-v8a")
staticLibraryFile = file("${prefix}/libSuperpoweredAndroidARM64.a")
else if (targetPlatform.getName() == "x86_64")
staticLibraryFile = file("${prefix}/libSuperpoweredAndroidX86_64.a")
else if (targetPlatform.getName() == "X86")
staticLibraryFile = file("${prefix}/libSuperpoweredAndroidX86.a")
}
}
}
}
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.3"
sources {
main {
jni {
dependencies {
library "Superpowered" linkage "static"
}
}
}
}
ndk {
ldLibs.addAll(['log', 'android', 'c'])
}
defaultConfig {
applicationId = "edu.ucdavis.auditoryenhancer"
minSdkVersion.apiLevel = 22
targetSdkVersion.apiLevel = 23
versionCode = 1
versionName = "1.0"
}
}
android.ndk {
moduleName = "native"
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file("proguard-rules.pro"))
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
}
It looks to me like bsd_signal is defined in the signal.o component of platforms/android-9/arch-x86/usr/lib/libc.a, but even with my ldLibs call above including c, I get the error.
Till android-19 inclusive NDK-s signal.h declared bsd_signal extern and signal was an inline calling bsd_signal.
Starting with android-21 signal is an extern and bsd_signal is not declared at all.
What's interesting, bsd_signal was still available as a symbol in NDK r10e android-21 libc.so (so there were no linking errors if using r10e), but is not available in NDK r11 and up.
Removing of bsd_signal from NDK-s android-21+ libc.so results in linking errors if code built with android-21+ is linked with static libs built with lower NDK levels that call signal or bsd_signal. Most popular library which calls signal is OpenSSL.
WARNING: Building those static libs with android-21+ (which would put signal symbol directly) would link fine, but would result in *.so failing to load on older Android OS devices due to signal symbol not found in theirs libc.so.
Therefore it's better to stick with <=android-19 for any code that calls signal or bsd_signal.
To link a library built with <android-21 I ended up declaring a bsd_signal wrapper which would call bsd_signal from libc.so (it's still available in device's libc.so, even up to Android 7.0).
#if (__ANDROID_API__ > 19)
#include <android/api-level.h>
#include <android/log.h>
#include <signal.h>
#include <dlfcn.h>
extern "C" {
typedef __sighandler_t (*bsd_signal_func_t)(int, __sighandler_t);
bsd_signal_func_t bsd_signal_func = NULL;
__sighandler_t bsd_signal(int s, __sighandler_t f) {
if (bsd_signal_func == NULL) {
// For now (up to Android 7.0) this is always available
bsd_signal_func = (bsd_signal_func_t) dlsym(RTLD_DEFAULT, "bsd_signal");
if (bsd_signal_func == NULL) {
// You may try dlsym(RTLD_DEFAULT, "signal") or dlsym(RTLD_NEXT, "signal") here
// Make sure you add a comment here in StackOverflow
// if you find a device that doesn't have "bsd_signal" in its libc.so!!!
__android_log_assert("", "bsd_signal_wrapper", "bsd_signal symbol not found!");
}
}
return bsd_signal_func(s, f);
}
}
#endif
PS. Looks like the bsd_signal symbol will be brought back to libc.so in NDK r13:
https://github.com/android-ndk/ndk/issues/160#issuecomment-236295994
This is ABI breakage in the Android NDK. Libraries/binaries built with a pre-android-21 NDK using signal() won't work with android-21 or newer. And the other way around. This Rust ticket has a more detailed explanation: https://github.com/rust-lang/libc/issues/236#issuecomment-198774409
There is also this ticket for the Android NDK: https://github.com/android-ndk/ndk/issues/48
I built some test c and c++ programs using gradle following these examples
I was also able to setup android studio with the experimental features to build a android project calling native functions with the help of this answer
I know that I can build this project using the android.useDeprecatedNdk=true
and provide my android.mk file for android studio to compile and build the app.
Is it possible with the experimental feature to build this same program? This project is built with CMAKE and there are some compilation steps that output files that needs to link. ndk-build creates these files but I can't find a way to do it with with android experimental features.
I am attempting for testing purposes and to build a non trivial example of building a more complex project. I decided to try to build the zlib library.
Here is my build.gradle
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.1"
defaultConfig.with {
applicationId = "me.test.testnative_exp"
minSdkVersion.apiLevel = 10
targetSdkVersion.apiLevel = 23
versionCode = 1
versionName = "1.0"
buildConfigFields.with {
create() {
type = "int"
name = "VALUE"
value = "1"
}
}
}
}
compileOptions.with {
sourceCompatibility=JavaVersion.VERSION_1_7
targetCompatibility=JavaVersion.VERSION_1_7
}
android.ndk {
moduleName = "hello-jni"
cppFlags += "-I${file("src/main/jni/zlib")}".toString()
stl = "stlport_static"
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles += file('proguard-rules.pro')
}
}
android.sources {
main {
java {
source {
srcDir 'src'
}
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
}
my project structure is
app/
build/
libs/
src/
src/main/testActivity.java
jni/zlib <- the zlib folder is the one that I downloaded from the zlib website.
jni/hello-jni.c
After syncing the build.gradle I get a link error on the header in file:
infbak9.c cannot find #include "zutil.h"
but both files are in the zlib directory under jni.
Is it possible to use the android studio experimental ndk build to compile this project?
there is good project in github that i use its structure in mine, it is nice example for start on "how use experimental(v_0.4.0) plugin in complex project?" :
https://github.com/frogermcs/FlatBuffs
*there are zlib in android NDK, just add appropriate cflag and ldLibs.add("z") in gradle. and in your native code include <zlib.h>
and a good experimental gradle config from google :
https://github.com/googlesamples/android-ndk/blob/229cbe86238d401bb06166b8dfadec8198532589/native-codec/app/build.gradle
you might check this repo for a group of samples:
https://github.com/googlesamples/android-ndk
your issue might be able to fixed by adding something as[from Teapot sample there]:
cppFlags.addAll(['-I' + "${ndkDir}/sources/android/cpufeatures",'-I' + file('src/main/jni/ndk_helper')])
just replace the directory with your own path "zutil.h" etc. you may also use the latest gradle-experimental version to simplify your script -- like removing ".with" for defaultConfig.with, delete java 7 version section( the latest android studio could handle java 8 ), those ".toString()" thing is also wordy so the samples have changed style to use "+" [those is not problem for your build error though]
I am trying to include some native cpp sources in my android app. I'm using Android Studio 1.0 with the gradle build system. I have three modules: my android app, the android opencv libs, the cpp sources (in the jni folder)
The build process gives me the following error:
D:\NVPACK\android-ndk-r10c\sources\cxx-stl\gnu-libstdc++\4.9\include\bits\stl_pair.h
Error:(96, 12) error: redefinition of 'struct std::pair<_T1, _T2>'
Error:(214, 5) error: redefinition of 'template<class _T1, class _T2> bool std::operator==(const std::pair<_T1, _T2>&, const std::pair<_T1, _T2>&)'
... and some other redefinitions with some other errors in other files.
It seems that the include paths are partially wrong or that there are duplicated headers (stl_pair.h) in the NDK This is my build.gradle file:
apply plugin: 'com.android.library'
android {
compileSdkVersion 21
buildToolsVersion "21.1.1"
defaultConfig {
minSdkVersion 15
targetSdkVersion 21
versionCode 1
versionName "1.0"
ndk{
moduleName "Native"
cFlags "-I'D:\\OpenCV-2.4.10-android-sdk\\sdk\\native\\jni\\include' " +
"-I'D:\\NVPACK\\android-ndk-r10c\\sources\\cxx-stl\\gnu-libstdc++\\4.9\\include' " +
"-I'D:\\NVPACK\\android-ndk-r10c\\sources\\cxx-stl\\gnu-libstdc++\\4.9\\libs\\armeabi-v7a\\include'"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
}
In cFlags I point to the openCV sources and to the c++ standard sources as described here. This works all fine until the above error.
I have only a very basic understanding of the whole build process when dealing with cpp sources as I normally work with c# .net or android (without native sources).
From my understanding the ndk-build should give me some .so files that I can use in my app. But the build of the natives failes. Am I missing something in the process?
edit: I switched to eclipse and could build and run the code. Maybe I try to switch back to android studio in the future, but this is not so important.