Android NDK and dropping in new shared libraries - android

I have a question regarding why I cannot simply drop in new shared libraries in Android without recompiling via NDK-build. Heres what i do:
Using Android Studio and the recent release of the Android NDK, I have been able to compile an app that uses a C code, which refers to a shared library. I compile the shared library with:
GCC := /xxx/AndroidStudioProjects/android-ndk-r10d/toolchains/x86-4.6/prebuilt/windows/bin/i686-linux-android-gcc.exe
GPP :=/xxx/AndroidStudioProjects/android-ndk-r10d/toolchains/x86-4.6/prebuilt/windows/bin/i686-linux-android-g++.exe
AR := /xxx/AndroidStudioProjects/android-ndk-r10d/toolchains/x86-4.6/prebuilt/windows/bin/i686-linux-android-ar.exe
OPTIONS :=\
-ffunction-sections \
-funwind-tables \
-DANDROID
default: all
all: obj
$(AR) r libmathadd.so mathadd.o
obj:
$(GCC) $(OPTIONS) -c mathadd.c
This gives me my .so file. I now run my ndk-build with the Android.mk makefile:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mathadd
LOCAL_SRC_FILES :=./libmathadd.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
LOCAL_MODULE := ndk1
LOCAL_SRC_FILES := native.c
LOCAL_SHARED_LIBRARIES := mathadd
include $(BUILD_SHARED_LIBRARY)
Following this, I have my ndk1 .so file and my mathadd .so which i then place in a folder directory:
app -> src -> jniLibs -> x86 -> libmathadd.so
and
app -> src -> jniLibs -> x86 -> libndk1.so
I compile and run on my emulator, and boom everything works!
Now heres my problem.
I slightly modify my shared library source (mathadd.c). I recompile it using the first make file and drop it straight into the app tree (without rebuilding the native c code) . I rebuild the app in Studio, and run on my emulator, and notice that my modifications did not occur.
I am not changing my native source, nor the api between native and my shared library.
If I rebuild the native with the ndk-build script, and drag the new native ndk1 in, everything works again, including the new modifcations. It seems I need to rebuild source via ndk everytime I tweak a shared library...??
Any ideas?
UPDATE:
I opened up my libndk .so library with a RE tool. Turns out the ndk compiler is statically adding the libmathadd code into the libndk, despite it being listed as a local shared library. Im curious if this is because the optimization is by default set for fastest speed, and the libmathadd code is simplistic math.

So libndk1.so has a dependency on libmath.so ? That would then be logical to rebuild it when you touch to libmath source.

Related

skip prebuilt-library.mk on gradle sync android studio

My project app depends on a library module alib. both app and alib build a c++ library with ndk. the app c++ lib, called app.so, depends on alib.so, which is the c++ lib for the library module. Inside the android.mk of app, i have:
LOCAL_PATH := $(the_right_alib_path)
include $(CLEAR_VARS)
LOCAL_MODULE := alibsdk
LOCAL_SRC_FILES := libalib.so
include $(PREBUILT_SHARED_LIBRARY)
Gradle sync fails on prebuilt-library.mk, with message Android NDK: Check that /the_right_alib_path/libalib.so exists or that its path is correct.
the file would be there if i build the module with gradle, it's naturally not there when I do gradle sync.
How can I skip the execution of prebuilt-library.mk?
Alternatively there is a way to tell ndk that the alib.so will be built by another gradle module?
Ps. This is more annoying cause in reality it checks all the libraries for different versions/flavor/dimensions, and i don't need to build all those libraries to work on the dev version on the app.
You can avoid the error by small modification of the Android.mk:
include $(CLEAR_VARS)
LOCAL_MODULE := alibsdk
LOCAL_SRC_FILES := libalib.so
ifeq ($(findstring n,$(MAKEFLAGS)),n)
include $(BUILD_SHARED_LIBRARY)
else
include $(PREBUILT_SHARED_LIBRARY)
endif
This takes advantage of the -n flag that is passed to ndk-build during sync. You can create a custom define for that, if you wish. build-shared-library.mk will generate a warning about strange SRC, but won't fail.
Same can be achieved without touching the Android.mk files: in your build.gradle, use
if (project.gradle.startParameter.taskNames.isEmpty()
|| project.gradle.startParameter.taskNames[0].contains(":generate")) {
android.defaultConfig.externalNativeBuild.ndkBuild.arguments += 'PREBUILT_SHARED_LIBRARY=$(BUILD_SHARED_LIBRARY)'
}
Android Studio runs ndk-build many times: with no tasks (the Sync step), within a :generate[flavor][Debug|Release]Sources, and within :externalNativeBuild[flavor][Debug|Release].
To retrieve the current task, I followed https://stackoverflow.com/a/21603707/192373.
Maybe the easiest fix is to rely on an obscure implementation detail of prebuilt-library.mk*). Early in your main Android.mk, add the line
override prebuilt=$(if $(strip $(wildcard $(prebuilt_path))),$(prebuilt_path),.)
This can be done in gradle, if necessary:
android.defaultConfig.externalNativeBuild.ndkBuild {
arguments 'prebuilt=$(if $(strip $(wildcard $(prebuilt_path))),$(prebuilt_path),.)'
}
*) verified for NDK r19b and earlier.

How to tell toolchain for a Device? In order to build native application in C

I have a shared library in C. I want to compile and run a test application on my android device.
As for as my understanding goes, here is what I think I have to do:
Cross compile the library for the arm device using its tool chain
Make an android.mk file and compile using NDK (I followed this link : build-cc-executables-for-android-using-ndk)
I modified the android.mk file to add a shared library,
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# give module name
LOCAL_MODULE := depend1
LOCAL_SRC_FILES := libdepend1.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
# give module name
LOCAL_MODULE := depend2
LOCAL_SRC_FILES := libdepend2.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
# give module name
LOCAL_MODULE := test
# list your C files to compile
LOCAL_SRC_FILES := test.c
# this option will build executables instead of building library
include $(BUILD_EXECUTABLE)
The project compiles. I get my executable in the libs folder.
On running the executable on android shell using adb I get the following error:
Init: Error opening /data/local/project/depend1.so: dlopen failed: could not load library "depend2.so" needed by "depend1.so"; caused by could not load library "libgcc_s.so.1" needed by "depend2.so"; caused by library "libgcc_s.so.1" not found
(NOTE: dlopen is part of my code)
It is not able find a library that is part of the toolchain, I didnt find this library in /system/lib of the device, which leads me to my first question - Am i using the right toolchain (the one I used is arm-none-linux-gnueabi)
Secondly am I building it correctly for android?
This library use Cmake or automake?
For Cmake you just need to properly confugure it (how to)
Example: cmake -DANDROID_NDK=path/to/ndk -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake --DANDROID_ABI=armeabi-v7a -DANDROID_PLATFORM=android-21 ..
For automake you should use prebuilt GCC toolchains (but GCC deprecated in NDK) or create new own standalone toolchain (how to)
This toolchains are 100% valid for cross-compiling for Android
If you still want use ndk-build you can read this link (I don't use it, so I can help further only with Cmake and automake)

Android.mk PREBUILT_SHARED_LIBRARY how to generate LOCAL_SRC_FILES file from script?

I have an NDK project where I build the shared libraries using the cross-compiler and standard gnu make utils. That is done with a separate script. But for the purpose of using the libraries in my project, I would like my Android.mk process to call my script to generate the shared library if it hasn't already been built, and then have Android.mk wrap it using the PREBUILT_SHARED_LIBRARY process.
Currently, if I run my script offline to generate libmy_so.so, then the following makefile will work. However, if I don't run the script explicitly first, I get the following error:
Android NDK: ERROR:/path_to_project/Android.mk:my_module: LOCAL_SRC_FILES points to a missing file
and my script is never called, so the make process is failing before even trying to resolve the dependency.
include $(CLEAR_VARS)
LOCAL_MODULE := my_module
LOCAL_SRC_FILES := libmy_so.so
LOCAL_EXPORT_CFLAGS := # some stuff
LOCAL_EXPORT_LDLIBS := # some stuff
$(LOCAL_PATH)/libmy_so.so:
echo "generate file"
$(shell run_script_that_creates_libmy_so.so)
include $(PREBUILT_SHARED_LIBRARY)
Is there a clean solution to this? I am even ok with running the script automatically as a preprocessing step (I can always have my script quietly exit if the file exists already), but I have not found an incantation that allows the LOCAL_SRC_FILES variable to point to a non-existent file. I have considered placing a dummy libmy_so.so to start, but that is an ugly hack.
Found a hack -- better way?
I found a hack. The makefile prebuilt-library.mk in the NDK contains the following lines:
ifndef prebuilt
$(call __ndk_info,ERROR:$(LOCAL_MAKEFILE):$(LOCAL_MODULE): LOCAL_SRC_FILES points to a missing file)
$(call __ndk_info,Check that $(prebuilt_path) exists, or that its path is correct)
$(call __ndk_error,Aborting)
#endif
I created a copy of this file (and prebuilt-shared-library.mk to which I reference my copy of prebuilt-library.mk) and commented those lines out to stop the error. Then the trick is to make some target that is evaluated first depend on the file I want to generate. After digging through the .mk scripts in the NDK, I found that libraries serves the purpose. By adding libraries: $(LOCAL_PATH)/libmy_so.so to Android.mk, it will finally do what I want.
include $(CLEAR_VARS)
LOCAL_MODULE := my_module
LOCAL_SRC_FILES := libmy_so.so
LOCAL_EXPORT_CFLAGS := # some stuff
LOCAL_EXPORT_LDLIBS := # some stuff
$(LOCAL_PATH)/libmy_so.so:
echo "generate file"
$(shell run_script_that_creates_libmy_so.so)
libraries: $(LOCAL_PATH)/libmy_so.so
include /path/to/my/mk/files/prebuilt-shared-library.mk
This is obviously less than ideal as I would like to make sure my makefiles mature with newer versions of the NDK, but it does the trick. Still interested in more elegant solutions.

Android library project with native code packages library twice in the APK

I have two Android projects, one is a shared library and one is my application's project. Both projects contain some Java and some native code. When I try and run my APK I receive the following error:
Error generating final archive: Found duplicate file for APK: lib/armeabi/libOEShared.so
My shared library is marked as a library project (Properties->Android->'Is Library') so that I am able to use it's Java code. This presumably copies libOEShared.so for me once.
In order to link my Applications native code with libOEShared I use the NDK Prebuilds feature. Here is my Android.mk:
#include shared library
include $(CLEAR_VARS)
LOCAL_MODULE := OEShared
LOCAL_SRC_FILES := ../../../Shared/OEShared/libs/armeabi/libOEShared.so
include $(PREBUILT_SHARED_LIBRARY)
#build App library
include $(CLEAR_VARS)
LOCAL_MODULE := OEApp
LOCAL_SRC_FILES := OEApp.cpp
LOCAL_LDLIBS := -llog -lGLESv2 -lz
LOCAL_SHARED_LIBRARIES := OEShared
include $(BUILD_SHARED_LIBRARY)
However, the NDK also copies libOEShared into my Application project's lib folder, resulting in two copies being present in the final APK.
How can I link my Application's native code to libOEShared without it being automatically duplicated?
Thank you for you time, this has caused me a lot of frustration so far.
Only linking is required here, instead of build. Linking can be done by using LOCAL_LD_LIBS flag. You can try this.
LOCAL_LDLIBS := -L$(LOCAL_PATH)/../../../Shared/OEShared/libs/$(TARGET_ARCH_ABI)/ \
-lOEShared

Eclipse Android Native debugging fails

I have a problem getting the native debugging support to work for my Eclipse project under Windows for Android.
Google unfortunately didn't help after more than 1 day of research.
I am pretty much a beginner with eclipse, so the solution might be easy because I do also some non-standard things I guess.
My android project is already functioning and running fine on my devices (Acer Iconia A500 Android 3.2.1, HTC Incredible S Android 4.0.4 etc.).
I created the project with the ADT Plugin Wizard and then added native support by using the project context menu entry added by ADT.
I then added the java files I already had (previously I used to compile with CMake and the Android stand-alone toolchain, though I never tried to remote debug this way). I created a new package for that "com.x.y" where I dropped them on to (I don't want to reveal the real package name as the project will be part of a commercial product).
Then I added my Sources by dragging them into the jni folder. The sources are not located inside the jni folder but are linked to a location "../../" below the project (Its part of a cross platform application so I can reuse the source files accross different toolchains).
I also link against 4 static libraries that will be shipped with the product by adjusting the Android.mk the following way:
LOCAL_PATH := $(call my-dir)
MY_PATH := $(LOCAL_PATH)
LOCAL_PATH := $(MY_SDK)/lib/Android/armeabi-v7aD
include $(CLEAR_VARS)
LOCAL_MODULE := A
LOCAL_SRC_FILES := libA.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := B
LOCAL_SRC_FILES := libB.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := C
LOCAL_SRC_FILES := libC.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := D
LOCAL_SRC_FILES := libD.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES += $(my_SDK)/include/
LOCAL_PATH := $(MY_PATH)/../../..
LOCAL_CFLAGS += -Wno-format -DANDROID -fno-rtti -fno-exceptions #And many other flags If they are important I will post them later, too
LOCAL_CPPFLAGS += -fno-rtti -fno-exceptions
LOCAL_MODULE := MY_PROJECT
LOCAL_SRC_FILES := Android/Main.cpp # Some other sources..
LOCAL_LDLIBS := -lstdc++ -lEGL -lGLESv2 -llog -Wl,--allow-multiple-definition -Wl,--no-undefined
LOCAL_STATIC_LIBRARIES := A B C D
include $(BUILD_SHARED_LIBRARY)
I also have a Application.mk:
APP_ABI := armeabi-v7a
APP_PLATFORM := android-9
APP_STL := stlport_static
APP_CFLAGS += -fno-rtti -fno-exceptions
Then I added under Debug Configurations a new "Android Native Application" launching the default Activity and using
Debugger "${NdkGdb}"
Command File "${NdkProject}\libs\${NdkCompatAbi}\gdb.setup"
Shared Libraries (Added automatically) ${NdkProject}/obj/local/$NdkCompatAbi}/
The rest is also added automatically and I think should work this way.
One thing that I think is odd is that I get the console Output
[2013-03-08 10:50:36 - Unable to launch cygpath. Is Cygwin on the path?] java.io.IOException: Cannot run program "cygpath": CreateProcess error=2, The system cannot find the file specified
But I can build the project fine this way and later I don't get any warnings trying to attach gdb (I am using Msys, I also have cygwin installed so I don't know why Eclipse is complaining here).
When I launch the application, it starts up on the device and then I get the following Console output([Android Native Application] gdb):
(no debugging symbols found)
Error while mapping shared library sections:
/system/bin/linker: No such file or directory.
Error while mapping shared library sections:
libstdc++.so: No such file or directory.
... And alot more of that type
(no debugging symbols found)
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
warning: shared library handler failed to enable breakpoint
No line 219 in file "jni/../../../MySourceFile.cpp".
I definitely build with NDK_DEBUG=1, my static .a Libraries are build with -g
AndroidManifest.xml has an entry android:debuggable="true".
When I run "sh /ndk-gdb --verbose" in the eclipse project directory (using Msys) I get the following output:
Android NDK installation path: /c/SDK/android-ndk-r7
Using default adb command: /c/SDK/android-sdks/platform-tools/adb.exe
ADB version found: Android Debug Bridge version 1.0.31
Using final ADB command: '/c/SDK/android-sdks/platform-tools/adb.exe'
Using auto-detected project path: .
Found package name: com.x.y
ABIs targetted by application: armeabi-v7a
Device API Level: 13
Device CPU ABIs: armeabi-v7a armeabi
Compatible device ABI: armeabi-v7a
Found debuggable flag: true
ERROR: Non-debuggable application installed on the target device.
Please re-install the debuggable version!
I really want to have native debugging support for this project. So I really appreciate any help.
Is it true that I have to use cygwin? I don't get any reasonable error message for that while trying to attach the debugger.

Categories

Resources